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..d5030b2 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 (#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). * `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..3fe4876 --- /dev/null +++ b/R/update_ai.R @@ -0,0 +1,41 @@ +#' Update the full AI agent suite for a project +#' +#' 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). +#' Defaults to `TRUE`. +#' @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..477cab4 --- /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{TRUE}.} + +\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{ +Update all files generated by \code{\link[=use_ai]{use_ai()}}. Equivalent to \code{use_ai(overwrite = TRUE)}. +} +\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..ec202b1 --- /dev/null +++ b/tests/testthat/test-update_ai.R @@ -0,0 +1,51 @@ +test_that("update_ai() defaults overwrite to TRUE (#94)", { + 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 (#94)", { + 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") +})