Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
docs
.claude/settings.local.json
_dev
.claude/skills/r-cli-app
.agents/skills/r-cli-app
skills-lock.json
3 changes: 3 additions & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,9 @@ Suggests:
htmltools,
pandoc,
pkgload,
processx,
ragg,
Rapp (>= 0.3.0),
roxygen2,
shiny,
shinychat (>= 0.3.0),
Expand All @@ -90,6 +92,7 @@ Collate:
'btw_client_app.R'
'btw_task.R'
'btw_this.R'
'cli.R'
'clipboard.R'
'deprecated.R'
'edit_btw_md.R'
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export(btw_tool_skill)
export(btw_tool_web_read_url)
export(btw_tools)
export(edit_btw_md)
export(install_btw_cli)
export(use_btw_md)
if (getRversion() < "4.3.0") importFrom("S7", "@")
import(rlang)
Expand Down
8 changes: 8 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# btw (development version)

* New `btw` CLI provides command-line access to btw's tool groups — **docs**,
**pkg**, **info**, and **cran** — powered by
[Rapp](https://github.com/r-lib/Rapp). Install with `install_btw_cli()` and
run commands like `btw docs help dplyr::mutate` or `btw cran search
"tidyverse"`. Output is designed for humans and LLMs: colored and formatted
for terminals, plain markdown when piped, with a `--json` flag to return
pipable JSON in select commands (#176).

* `btw` now supports [Agent Skills](https://agentskills.io) via
`btw_tool_skill()`. Skills are modular, on-demand capabilities that provide
specialized instructions, bundled scripts, reference docs, and asset
Expand Down
118 changes: 118 additions & 0 deletions R/cli.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
#' Install the btw CLI
#'
#' Installs the `btw` CLI launcher using [Rapp::install_pkg_cli_apps()].
#' [Rapp](https://github.com/r-lib/Rapp) is required to build and install the
#' CLI. See [Rapp::install_pkg_cli_apps()] for details on where the launcher is
#' installed and how to manage it.
#'
#' After installing the CLI, you will be offered the option to install the
#' `r-btw-cli` skill, which helps AI coding assistants discover and use the
#' `btw` CLI. If you decline or are in a non-interactive session, the skill
#' instructions are copied to the clipboard (or printed) so you can add them
#' to your `CLAUDE.md`, `AGENTS.md`, or other context file manually.
#'
#' @param destdir Directory where the CLI launcher will be installed. If `NULL`,
#' the default location used by [Rapp::install_pkg_cli_apps()] is used.
#' @inheritDotParams Rapp::install_pkg_cli_apps -package -destdir
#'
#' @returns The result of [Rapp::install_pkg_cli_apps()], invisibly.
#'
#' @export
install_btw_cli <- function(destdir = NULL, ...) {
rlang::check_installed(c(
"Rapp (>= 0.3.0)",
"devtools",
"pkgload",
"callr",
"covr",
"testthat",
"rmarkdown",
"pkgsearch"
))

result <- Rapp::install_pkg_cli_apps(package = "btw", destdir = destdir, ...)

for (path in result) {
cli::cli_alert_success("Installed {.code btw} CLI to {.path {path}}")
}

install_btw_cli_skill()

invisible(result)
}

install_btw_cli_skill <- function() {
if (!is_interactive()) {
install_btw_cli_skill_clipboard()
return(invisible())
}

cli::cli_h2("Install btw CLI skill")
cli::cli_text(
"The {.field r-btw-cli} skill helps AI coding assistants discover and use
the {.code btw} CLI."
)

scope_choices <- c(
"~/.agents/skills (Recommended)",
"~/.claude/skills",
"Custom path",
"Skip (copy to clipboard instead)"
)

choice <- utils::menu(
choices = scope_choices,
graphics = FALSE,
title = "\u276F Where should the skill be installed?"
)

if (choice == 0 || choice == 4) {
install_btw_cli_skill_clipboard()
return(invisible())
}

scope <- switch(
as.character(choice),
"1" = "~/.agents/skills",
"2" = "~/.claude/skills",
"3" = readline("Enter path: ")
)

skill_dir <- system.file("cli-skill", "r-btw-cli", package = "btw")
tryCatch(
install_skill_from_dir(skill_dir, scope = scope),
error = function(e) {
cli::cli_warn(
"Failed to install skill: {conditionMessage(e)}"
)
install_btw_cli_skill_clipboard()
}
)

invisible()
}

install_btw_cli_skill_clipboard <- function() {
skill_path <- system.file(
"cli-skill",
"r-btw-cli",
"SKILL.md",
package = "btw"
)

if (!nzchar(skill_path) || !file.exists(skill_path)) {
cli::cli_warn("Could not find the {.field r-btw-cli} skill file.")
return(invisible())
}

fm <- frontmatter::read_front_matter(skill_path)
body <- fm$body %||% ""

write_to_clipboard(body, what = "{.strong r-btw-cli} skill instructions")

cli::cli_alert_info(
"Add the copied instructions to your {.file CLAUDE.md}, {.file AGENTS.md}, or other coding agent's context file."
)

invisible()
}
4 changes: 2 additions & 2 deletions R/clipboard.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
write_to_clipboard <- function(x) {
write_to_clipboard <- function(x, what = "{.pkg btw}") {
if (!is_interactive() || !clipr::clipr_available()) {
if (is_interactive()) {
cli::cli_alert_warning(
Expand All @@ -13,7 +13,7 @@ write_to_clipboard <- function(x) {
tryCatch(
{
clipr::write_clip(x)
cli::cli_alert_success("{.pkg btw} copied to the clipboard!")
cli::cli_alert_success(sprintf("%s copied to the clipboard!", what))
},
error = function(e) e
)
Expand Down
Loading
Loading