From ffe53b4e4bd6f1590ed0e1d45a45b0c23d08d343 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 13:52:57 +0000 Subject: [PATCH 1/5] Initial plan From ecb301d1df07a9021da90006d0000b1d98b5883a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 14:00:56 +0000 Subject: [PATCH 2/5] Add update_ai wrapper with overwrite TRUE default Agent-Logs-Url: https://github.com/api2r/pkgskills/sessions/24beabbb-a9b0-4804-885f-a4ead3b28f41 Co-authored-by: jonthegeek <33983824+jonthegeek@users.noreply.github.com> --- NAMESPACE | 1 + NEWS.md | 2 ++ R/update_ai.R | 39 ++++++++++++++++++++++ man/update_ai.Rd | 57 +++++++++++++++++++++++++++++++++ tests/testthat/test-update_ai.R | 51 +++++++++++++++++++++++++++++ 5 files changed, 150 insertions(+) create mode 100644 R/update_ai.R create mode 100644 man/update_ai.Rd create mode 100644 tests/testthat/test-update_ai.R diff --git a/NAMESPACE b/NAMESPACE index bbf88e6..1bf36d4 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(default_allowlist) +export(update_ai) export(use_agent) export(use_ai) export(use_github_copilot) diff --git a/NEWS.md b/NEWS.md index 30db357..185500f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # pkgskills (development version) +* `update_ai()` now wraps `use_ai()` with `overwrite = TRUE` by default (#noissue). + * `use_github_copilot_code_review()` now installs `.github/copilot-instructions.md` to skip `man/*.Rd` files during Copilot code review, and `use_github_copilot()` now calls it (#89). * `use_github_copilot()` now uses the external, stable `api2r/actions/install@v1` composite workflow instead of the local `install` action (#84). diff --git a/R/update_ai.R b/R/update_ai.R new file mode 100644 index 0000000..39d794e --- /dev/null +++ b/R/update_ai.R @@ -0,0 +1,39 @@ +#' Update the full AI agent suite for a project +#' +#' Thin wrapper around [use_ai()] with `overwrite = TRUE` by default. +#' +#' @inheritParams use_ai +#' @returns A named list of paths returned by [use_ai()], invisibly. +#' @export +#' @examplesIf interactive() +#' +#' update_ai() +update_ai <- function( + save_agent_as = "AGENTS.md", + target_skills_dir = ".github", + use_skills_subdir = TRUE, + overwrite = TRUE, + open = rlang::is_interactive(), + gh_token = gh::gh_token(), + allowlist = default_allowlist(), + skills = c( + "create-issue", + "document", + "github", + "implement-issue", + "r-code", + "search-code", + "tdd-workflow" + ) +) { + use_ai( + save_agent_as = save_agent_as, + target_skills_dir = target_skills_dir, + use_skills_subdir = use_skills_subdir, + overwrite = overwrite, + open = open, + gh_token = gh_token, + allowlist = allowlist, + skills = skills + ) +} diff --git a/man/update_ai.Rd b/man/update_ai.Rd new file mode 100644 index 0000000..9200d43 --- /dev/null +++ b/man/update_ai.Rd @@ -0,0 +1,57 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/update_ai.R +\name{update_ai} +\alias{update_ai} +\title{Update the full AI agent suite for a project} +\usage{ +update_ai( + save_agent_as = "AGENTS.md", + target_skills_dir = ".github", + use_skills_subdir = TRUE, + overwrite = TRUE, + open = rlang::is_interactive(), + gh_token = gh::gh_token(), + allowlist = default_allowlist(), + skills = c("create-issue", "document", "github", "implement-issue", "r-code", + "search-code", "tdd-workflow") +) +} +\arguments{ +\item{save_agent_as}{(\code{character(1)}) Output path for \code{AGENTS.md}, relative +to the project root. Passed to \code{\link[=use_agent]{use_agent()}} as \code{save_as}.} + +\item{target_skills_dir}{(\code{character(1)}) Directory where skills will be +installed. Passed to all \verb{use_skill_*()} functions as \code{target_dir}.} + +\item{use_skills_subdir}{(\code{logical(1)}) Whether to place the skill folder +under a \code{skills} subdirectory of \code{target_dir}. Defaults to \code{TRUE}, +producing \code{.github/skills/{skill}/SKILL.md}.} + +\item{overwrite}{(\code{logical(1)}) Whether to overwrite existing file(s). +Defaults to \code{FALSE}.} + +\item{open}{(\code{logical(1)}) Whether to open the file after creation.} + +\item{gh_token}{(\code{character(1)}) A GitHub personal access token. Defaults to +\code{gh::gh_token()}.} + +\item{allowlist}{(\code{character}) Hostnames to add to the GitHub Copilot coding +agent firewall allowlist. Defaults to \code{\link[=default_allowlist]{default_allowlist()}}, a curated set +of R and GitHub domains.} + +\item{skills}{(\code{character}) Which skills to install. Defaults to all known +skills. Pass a subset to install only specific skills, or \code{character(0)} +for none.} +} +\value{ +A named list of paths returned by \code{\link[=use_ai]{use_ai()}}, invisibly. +} +\description{ +Thin wrapper around \code{\link[=use_ai]{use_ai()}} with \code{overwrite = TRUE} by default. +} +\examples{ +\dontshow{if (interactive()) withAutoprint(\{ # examplesIf} + + update_ai() +\dontshow{\}) # examplesIf} +} diff --git a/tests/testthat/test-update_ai.R b/tests/testthat/test-update_ai.R new file mode 100644 index 0000000..cf5cbec --- /dev/null +++ b/tests/testthat/test-update_ai.R @@ -0,0 +1,51 @@ +test_that("update_ai() defaults overwrite to TRUE (#noissue)", { + local_pkg() + local_gh_mock() + local_mocked_bindings( + use_ai = function( + save_agent_as, + target_skills_dir, + use_skills_subdir, + overwrite, + open, + gh_token, + allowlist, + skills + ) { + expect_true(overwrite) + invisible("ok") + } + ) + + result <- withVisible(update_ai(open = FALSE, skills = "r-code")) + expect_false(result$visible) + expect_identical(result$value, "ok") +}) + +test_that("update_ai() still allows explicit overwrite = FALSE (#noissue)", { + local_pkg() + local_gh_mock() + local_mocked_bindings( + use_ai = function( + save_agent_as, + target_skills_dir, + use_skills_subdir, + overwrite, + open, + gh_token, + allowlist, + skills + ) { + expect_false(overwrite) + invisible("ok") + } + ) + + result <- withVisible(update_ai( + overwrite = FALSE, + open = FALSE, + skills = "r-code" + )) + expect_false(result$visible) + expect_identical(result$value, "ok") +}) From 8f9f9a4e72b1cf554a7b5b7be65617dd3f741faf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 15 May 2026 14:03:16 +0000 Subject: [PATCH 3/5] Fix update_ai documentation overwrite default Agent-Logs-Url: https://github.com/api2r/pkgskills/sessions/24beabbb-a9b0-4804-885f-a4ead3b28f41 Co-authored-by: jonthegeek <33983824+jonthegeek@users.noreply.github.com> --- R/update_ai.R | 2 ++ man/update_ai.Rd | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/R/update_ai.R b/R/update_ai.R index 39d794e..de67ff3 100644 --- a/R/update_ai.R +++ b/R/update_ai.R @@ -3,6 +3,8 @@ #' Thin wrapper around [use_ai()] with `overwrite = TRUE` by default. #' #' @inheritParams use_ai +#' @param overwrite (`logical(1)`) Whether to overwrite existing file(s). +#' Defaults to `TRUE`. #' @returns A named list of paths returned by [use_ai()], invisibly. #' @export #' @examplesIf interactive() diff --git a/man/update_ai.Rd b/man/update_ai.Rd index 9200d43..fdaa6de 100644 --- a/man/update_ai.Rd +++ b/man/update_ai.Rd @@ -28,7 +28,7 @@ under a \code{skills} subdirectory of \code{target_dir}. Defaults to \code{TRUE} producing \code{.github/skills/{skill}/SKILL.md}.} \item{overwrite}{(\code{logical(1)}) Whether to overwrite existing file(s). -Defaults to \code{FALSE}.} +Defaults to \code{TRUE}.} \item{open}{(\code{logical(1)}) Whether to open the file after creation.} From 023866e0faaf5618b8781579347525a41846e7cf Mon Sep 17 00:00:00 2001 From: Jon Harmon Date: Fri, 15 May 2026 09:18:13 -0500 Subject: [PATCH 4/5] Apply suggestions from code review /document Co-authored-by: Jon Harmon --- NEWS.md | 2 +- R/update_ai.R | 2 +- tests/testthat/test-update_ai.R | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 185500f..d5030b2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,6 @@ # pkgskills (development version) -* `update_ai()` now wraps `use_ai()` with `overwrite = TRUE` by default (#noissue). +* `update_ai()` now wraps `use_ai()` with `overwrite = TRUE` by default (#94). * `use_github_copilot_code_review()` now installs `.github/copilot-instructions.md` to skip `man/*.Rd` files during Copilot code review, and `use_github_copilot()` now calls it (#89). diff --git a/R/update_ai.R b/R/update_ai.R index de67ff3..3fe4876 100644 --- a/R/update_ai.R +++ b/R/update_ai.R @@ -1,6 +1,6 @@ #' Update the full AI agent suite for a project #' -#' Thin wrapper around [use_ai()] with `overwrite = TRUE` by default. +#' Update all files generated by [use_ai()]. Equivalent to `use_ai(overwrite = TRUE)`. #' #' @inheritParams use_ai #' @param overwrite (`logical(1)`) Whether to overwrite existing file(s). diff --git a/tests/testthat/test-update_ai.R b/tests/testthat/test-update_ai.R index cf5cbec..ec202b1 100644 --- a/tests/testthat/test-update_ai.R +++ b/tests/testthat/test-update_ai.R @@ -1,4 +1,4 @@ -test_that("update_ai() defaults overwrite to TRUE (#noissue)", { +test_that("update_ai() defaults overwrite to TRUE (#94)", { local_pkg() local_gh_mock() local_mocked_bindings( @@ -22,7 +22,7 @@ test_that("update_ai() defaults overwrite to TRUE (#noissue)", { expect_identical(result$value, "ok") }) -test_that("update_ai() still allows explicit overwrite = FALSE (#noissue)", { +test_that("update_ai() still allows explicit overwrite = FALSE (#94)", { local_pkg() local_gh_mock() local_mocked_bindings( From 141b9201b6a4333194f99286b90ae4d4efe6f1f3 Mon Sep 17 00:00:00 2001 From: Jon Harmon Date: Fri, 15 May 2026 09:22:28 -0500 Subject: [PATCH 5/5] Document --- man/update_ai.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/update_ai.Rd b/man/update_ai.Rd index fdaa6de..477cab4 100644 --- a/man/update_ai.Rd +++ b/man/update_ai.Rd @@ -47,7 +47,7 @@ for none.} A named list of paths returned by \code{\link[=use_ai]{use_ai()}}, invisibly. } \description{ -Thin wrapper around \code{\link[=use_ai]{use_ai()}} with \code{overwrite = TRUE} by default. +Update all files generated by \code{\link[=use_ai]{use_ai()}}. Equivalent to \code{use_ai(overwrite = TRUE)}. } \examples{ \dontshow{if (interactive()) withAutoprint(\{ # examplesIf}