Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions .github/skills/create-issue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ If `gh` is not authenticated, stop and ask the user to authenticate before conti

## Looking up IDs

The hardcoded IDs below are correct for this repo as of 2026-03-11. If they ever change, or if you're working in a fork, re-run these queries to get fresh values:
The hardcoded IDs below are correct for this repo as of 2026-05-15 12:52:35 UTC. If they ever change, or if you're working in a fork, re-run these queries to get fresh values:

```bash
# Repository node ID
Expand All @@ -29,11 +29,11 @@ Choose the type that best fits the issue:

| Type | ID | Use for |
|---|---|---|
| Feature | `IT_kwDOCPuMJs4BPtRe` | New exported functions or capabilities |
| Bug | `IT_kwDOCPuMJs4BPtRc` | Something broken or incorrect |
| Documentation | `IT_kwDOCPuMJs4B5OL_` | Docs-only changes |
| Task | `IT_kwDOCPuMJs4BPtRZ` | Maintenance, refactoring, chores |
| Infrastructure | `IT_kwDOCPuMJs4B5OMn` | CI, tooling, repo configuration |
| Task | `IT_kwDOCPuMJs4BPtRZ` | A specific piece of work |
| Bug | `IT_kwDOCPuMJs4BPtRc` | An unexpected problem or behavior |
| Feature | `IT_kwDOCPuMJs4BPtRe` | A request, idea, or new functionality |
| Documentation | `IT_kwDOCPuMJs4B5OL_` | Explanations of how or why to do things |
| Infrastructure | `IT_kwDOCPuMJs4B5OMn` | Infrastructure of a project, like GitHub Actions |

## Issue title

Expand Down
6 changes: 3 additions & 3 deletions .github/skills/r-code/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: Guide for writing R code. Use when writing new functions, designing

# R code

This skill covers how to design and write R functions — including naming conventions, signatures, API conventions, input validation, error handling, and common pitfalls. For documenting functions, use the `document` skill. For tests, use the `tdd-workflow` skill.
This skill covers how to design and write R functions — including naming conventions, signatures, API conventions, input validation, condition handling, and common pitfalls. For documenting functions, use the `document` skill. For tests, use the `tdd-workflow` skill.

## Naming conventions

Expand Down Expand Up @@ -184,9 +184,9 @@ Keep a function internal when:

Internal helpers use a dot prefix (e.g. `.parse_response()`).

## Error handling
## Condition handling

Use `.pkg_abort()` (defined in `R/aaa-conditions.R`) rather than calling `cli::cli_abort()` directly. This wraps `stbl::pkg_abort()` and ensures consistent error class formatting:
Use `.pkg_abort()`, `.pkg_warn()`, and `.pkg_inform()` (defined in `R/aaa-conditions.R`) rather than calling `cli::cli_abort()`, `cli::cli_warn()`, or `cli::cli_inform()` directly. These wrap `stbl` condition helpers and ensure consistent class formatting:

```r
.pkg_abort(
Expand Down
26 changes: 26 additions & 0 deletions .github/skills/tdd-workflow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,32 @@ test_that("process_data() errors on empty input (#42)", {
Pass `transform = .transform_path(path)` to scrub volatile values (e.g. temp
paths) from the snapshot before comparison.

**Warnings thrown by this package** (via `.pkg_warn()`) should be tested with
`stbl::expect_pkg_warning_snapshot()`:

```r
test_that("process_data() warns on dropped rows (#42)", {
stbl::expect_pkg_warning_snapshot(
process_data(data.frame(value = c(1, NA))),
"pkgskills",
"dropped_rows"
)
})
```

**Messages thrown by this package** (via `.pkg_inform()`) should be tested with
`stbl::expect_pkg_message_snapshot()`:

```r
test_that("process_data() informs on defaults used (#42)", {
stbl::expect_pkg_message_snapshot(
process_data(data.frame(value = 1)),
"pkgskills",
"used_defaults"
)
})
```

**Errors thrown by `stbl`** (via `stbl::to_*()` / `stbl::stabilize_*()`)
should be tested with `stbl::expect_pkg_error_classes()`. Since the message
text is controlled by `stbl`, only the class hierarchy needs to be asserted:
Expand Down
11 changes: 7 additions & 4 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,30 @@ BugReports: https://github.com/api2r/pkgskills/issues
Depends:
R (>= 4.1.0)
Imports:
cli,
desc,
fs,
gert,
gh,
glue,
purrr,
rlang,
stbl (>= 0.3.0),
stbl (>= 0.3.0.9000),
stringr,
usethis
Suggests:
astgrepr,
callr,
cli,
knitr,
rmarkdown,
testthat (>= 3.0.0),
withr
VignetteBuilder:
knitr
Remotes:
stbl=wranglezone/stbl
Config/testthat/edition: 3
Encoding: UTF-8
Language: en-US
Roxygen: list(markdown = TRUE)
RoxygenNote: 7.3.3
VignetteBuilder: knitr
Config/roxygen2/version: 8.0.0
60 changes: 57 additions & 3 deletions R/aaa-conditions.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#' Raise a package-scoped error
#' Signal a package-scoped error
#'
#' @inheritParams .shared-params
#' @inheritParams stbl::pkg_abort
Expand All @@ -7,14 +7,68 @@
.pkg_abort <- function(
message,
subclass,
parent = NULL,
call = caller_env(),
message_env = caller_env()
message_env = caller_env(),
...
) {
stbl::pkg_abort(
"pkgskills",
message,
subclass,
call = call,
message_env = message_env
message_env = message_env,
parent = parent,
...
)
}

#' Signal a package-scoped warning
#'
#' @inheritParams .shared-params
#' @inheritParams stbl::pkg_warn
#' @returns Does not return.
#' @keywords internal
.pkg_warn <- function(
message,
subclass,
parent = NULL,
call = caller_env(),
message_env = caller_env(),
...
) {
stbl::pkg_warn(
"pkgskills",
message,
subclass,
call = call,
message_env = message_env,
parent = parent,
...
)
}

#' Signal a package-scoped message
#'
#' @inheritParams .shared-params
#' @inheritParams stbl::pkg_inform
#' @returns Does not return.
#' @keywords internal
.pkg_inform <- function(
message,
subclass,
parent = NULL,
call = caller_env(),
message_env = caller_env(),
...
) {
stbl::pkg_inform(
"pkgskills",
message,
subclass,
call = call,
message_env = message_env,
parent = parent,
...
)
}
19 changes: 11 additions & 8 deletions R/use_agent.R
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ use_agent <- function(
data <- .get_desc_fields(c("Package", "Title", "Description", "URL"))
.use_template("AGENTS.md", save_as, data = data, open = open)
usethis::use_build_ignore(save_as)
cli::cli_inform(c(
"{.file AGENTS.md} created.",
"i" = paste0(
"To tailor it to your project, tell your AI agent this: ",
"\"Tailor @AGENTS.md to reflect this repository's actual structure. ",
"Focus on the **Repository overview** and the **Key files** table.\""
)
))
.pkg_inform(
c(
"{.file AGENTS.md} created.",
"i" = paste0(
"To tailor it to your project, tell your AI agent this: ",
"\"Tailor @AGENTS.md to reflect this repository's actual structure. ",
"Focus on the **Repository overview** and the **Key files** table.\""
)
),
c("ai_implementation", "agent")
)
invisible(usethis::proj_path(save_as))
}
28 changes: 21 additions & 7 deletions R/use_github_copilot_whitelist.R
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@ use_github_copilot_whitelist <- function(
repo_parts <- .extract_repo_from_desc()
owner <- repo_parts[["owner"]]
repo <- repo_parts[["repo"]]
call <- rlang::current_env()

rlang::try_fetch(
.set_copilot_allowlist(owner, repo, allowlist, gh_token),
error = function(cnd) {
cli::cli_warn(rlang::cnd_message(cnd))
.inform_copilot_allowlist(owner, repo, allowlist)
.pkg_warn(
rlang::cnd_message(cnd),
c("allowlist_api_error"),
call = call
)
.inform_copilot_allowlist(owner, repo, allowlist, call = call)
}
)

Expand Down Expand Up @@ -81,13 +86,22 @@ default_allowlist <- function() {
#' @inheritParams .shared-params
#' @returns `NULL`, invisibly.
#' @keywords internal
.inform_copilot_allowlist <- function(owner, repo, allowlist) {
.inform_copilot_allowlist <- function(
owner,
repo,
allowlist,
call = caller_env()
) {
url <- glue::glue(
"https://github.com/{owner}/{repo}/settings/copilot/coding_agent/allowlist"
)
cli::cli_inform(c(
"Add the following hosts to the Copilot coding agent firewall allowlist at {.url {url}}:",
allowlist
))
.pkg_inform(
c(
"Add the following hosts to the Copilot coding agent firewall allowlist at {.url {url}}:",
allowlist
),
c("ai_implementation", "github_copilot", "whitelist"),
call = call
)
invisible(NULL)
}
5 changes: 4 additions & 1 deletion R/use_skill.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
call = call
)
.upsert_agents_skill_from_template(skill_path_relative, save_as, call = call)
cli::cli_inform("Skill {.file {save_as}} installed.")
.pkg_inform(
"Skill {.file {save_as}} installed.",
c("ai_implementation", "skill")
)
invisible(save_as_absolute)
}

Expand Down
5 changes: 3 additions & 2 deletions R/use_skill_create_issue.R
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,9 @@ use_skill_create_issue <- function(
repo <- url_match[[3L]]
bug_reports_url <- glue::glue("https://github.com/{owner}/{repo}/issues")
desc::desc_set(BugReports = bug_reports_url, normalize = TRUE)
cli::cli_inform(
"Added {.field BugReports} to {.file DESCRIPTION}: {.url {bug_reports_url}}"
.pkg_inform(
"Added {.field BugReports} to {.file DESCRIPTION}: {.url {bug_reports_url}}",
c("description_update", "bugreports")
)
bug_reports_url
}
Expand Down
17 changes: 10 additions & 7 deletions R/use_skill_document.R
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,16 @@ use_skill_document <- function(
shared_params_path <- usethis::proj_path("R/aaa-shared_params.R")
if (!fs::file_exists(shared_params_path)) {
.use_template("aaa-shared_params.R", "R/aaa-shared_params.R")
cli::cli_inform(c(
"{.file R/aaa-shared_params.R} created.",
"i" = paste(
"Add shared parameters to it as your package grows.",
"Functions can inherit shared parameters with {.code @inheritParams .shared-params}."
)
))
.pkg_inform(
c(
"{.file R/aaa-shared_params.R} created.",
"i" = paste(
"Add shared parameters to it as your package grows.",
"Functions can inherit shared parameters with {.code @inheritParams .shared-params}."
)
),
c("shared_file", "params")
)
}

invisible(skill_path)
Expand Down
17 changes: 10 additions & 7 deletions R/use_skill_r_code.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,16 @@ use_skill_r_code <- function(
data <- .get_desc_fields("Package")
.use_template("aaa-conditions.R", "R/aaa-conditions.R", data = data)
usethis::use_package("stbl", min_version = "0.3.0")
cli::cli_inform(c(
"{.file R/aaa-conditions.R} created.",
"i" = paste(
"Use {.fn .pkg_abort} for package errors.",
"Add more error helpers here as your package grows."
)
))
.pkg_inform(
c(
"{.file R/aaa-conditions.R} created.",
"i" = paste(
"Use {.fn .pkg_abort} for package errors.",
"Add more error helpers here as your package grows."
)
),
c("shared_file", "conditions")
)
}

invisible(skill_path)
Expand Down
Loading
Loading