feat(skills): offer the agent skill install during onboarding - #161
Conversation
- bunny login makes a one-time offer after authenticating: interactive runs only, marker in the XDG cache dir, skipped when any global root already has the skill; failures never break login - install.sh outro points AI-tool users at bunny skills install --global - new isGlobalSkillInstalled() in core/agent-skill.ts backs the already-installed check
🦋 Changeset detectedLatest commit: 9bc8635 The changes in this PR will be included in the next version bump. This PR includes changesets to release 6 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…lled-check test - offer.ts reuses CACHE_DIR from core/update-check.ts instead of rebuilding the XDG path - the three offer guards collapse into one condition - isGlobalSkillInstalled assertions fold into the existing global-install test
|
@codex review |
Greptile SummaryThe PR adds agent-skill discovery to onboarding while making interrupted or failed installations retryable.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| packages/cli/src/commands/skills/offer.ts | Implements guarded login offers and passive hints, marking completion only after a decline or successful installation. |
| packages/cli/src/core/agent-skill.ts | Writes each root's SKILL.md sentinel last and requires completed sentinels in both global roots. |
| packages/cli/src/commands/auth/login.ts | Adds explicit skill-install flags and invokes onboarding after profile persistence and best-effort credential verification. |
| packages/cli/src/index.ts | Runs the passive skill hint after normal command execution while excluding skill-management commands. |
| packages/cli/src/core/ui.ts | Adds a confirmation helper that distinguishes cancellation from an explicit decline. |
| packages/cli/src/core/agent-skill.test.ts | Covers all-root completion checks and failed-refresh sentinel removal. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[CLI command completes] --> B{Login handled offer?}
B -->|Yes| Z[No passive hint]
B -->|No| C{Interactive and authenticated?}
C -->|No| Z
C -->|Yes| D{Marker absent and global install incomplete?}
D -->|No| Z
D -->|Yes| E[Show passive installation hint]
E --> F[Write shared offer marker]
L[Successful bunny login] --> G{install-skill flag}
G -->|true| H[Install both global roots]
G -->|false| Z
G -->|unset| I{Interactive and not previously offered?}
I -->|No| Z
I -->|Yes| J[Prompt user]
J -->|Decline| F
J -->|Accept| H
J -->|Cancel| K[Leave marker absent for retry]
H --> M{Installation succeeds?}
M -->|Yes| F
M -->|No| N[Warn and leave marker absent]
Reviews (4): Last reviewed commit: "fix(skills): clear the SKILL.md sentinel..." | Re-trigger Greptile
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1a568be929
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| logger.success( | ||
| "Agent skill installed to ~/.agents/skills and ~/.claude/skills.", | ||
| ); | ||
| } catch {} |
There was a problem hiding this comment.
Allow retrying after a failed skill installation
If the marker is written successfully but installGlobalSkill() then fails—for example because one of the home-directory skill roots is not writable—this empty catch suppresses the error while leaving skills-offered in place. Every later login returns at the marker check even though the skill is not installed, and the user receives neither an error nor another offer. Clear or defer the marker on installation failure and report a non-fatal warning.
Useful? React with 👍 / 👎.
…age reaches the browser
…n --install-skill
| function installAndReport(): void { | ||
| try { | ||
| installGlobalSkill(BUNNY_CLI_SKILL); | ||
| markOffered(); |
There was a problem hiding this comment.
Partial installs suppress retries
If writing a later skill file or the second global root fails after SKILL.md has been written, installGlobalSkill leaves that partial output while skipping markOffered. The any-root installed check then suppresses subsequent offers, leaving the global skill incomplete instead of retrying the failed installation.
…updates read as incomplete
What
Two onboarding hooks for the agent skill that shipped in #160, so users actually find it:
bunny loginnow makes a one-time offer to install the skill globally after authenticating (packages/cli/src/commands/skills/offer.ts). Guards, in order: interactive runs only (non-TTY and--output jsonnever see a prompt), a marker file in the XDG cache dir (bunnynet/skills-offered, same state dir as the update check) so it fires at most once, and an already-installed check via the newisGlobalSkillInstalled()incore/agent-skill.ts. Declining prints thebunny skills install --globalhint; the whole offer is wrapped so no failure can break login.install.shoutro now mentionsbunny skills install --globalnext to the "Run 'bunny --help'" line. Text only: the script never runs the install itself, since it may execute under sudo with a different HOME.Why
The skill is only useful if people know it exists. Nothing offered it before: no postinstall (hostile in CI), no first-run hook. Login is the natural moment; the user is authenticated, interactive, and has just committed to using the CLI.
Notes for review
login.tsimporting from../skills/offer.tsfollows existing lateral command imports (e.g.storage/docs.ts->../docs.ts).isGlobalSkillInstalled),bash -n install.sh, and a headless run confirming the non-TTY guard returns silently without writing the marker.