Skip to content

fix(cli): runner-aware help banners + wizard reference#384

Merged
coderdan merged 2 commits intomainfrom
dan/runner-aware-help-banners
May 4, 2026
Merged

fix(cli): runner-aware help banners + wizard reference#384
coderdan merged 2 commits intomainfrom
dan/runner-aware-help-banners

Conversation

@coderdan
Copy link
Copy Markdown
Contributor

@coderdan coderdan commented May 1, 2026

Closes #385.

Follow-up to #377 addressing Lindsay's feedback that the --help banners and the wizard suggestion in db install's "Next steps" panel still hard-coded npx @cipherstash/cli regardless of how the user invoked the CLI.

#379 already shipped runnerCommand(pm, ref) + detectPackageManager(). This applies them to the remaining places.

Before / after

$ bunx @cipherstash/cli --help

# Before
Usage: npx @cipherstash/cli <command> [options]
Examples:
  npx @cipherstash/cli init
  npx @cipherstash/cli db install
  ...

# After
Usage: bunx @cipherstash/cli <command> [options]
Examples:
  bunx @cipherstash/cli init
  bunx @cipherstash/cli db install
  ...

Same for pnpm dlx, yarn dlx, default npx.

Touches

  • bin/stash.tsHELP interpolates a STASH constant (runnerCommand(PM, '@cipherstash/cli')) for the usage line, six examples, and the requireStack hint shown when @cipherstash/stack isn't installed.
  • commands/auth/index.ts — same pattern for the auth HELP (usage line + two examples).
  • commands/db/install.ts — the wizard line in printNextSteps uses runnerCommand(pm, '@cipherstash/wizard').

Messages

messages.cli.usagePrefix and messages.auth.usagePrefix become stable leaders ('Usage: ') — the runner+package portion is appended at render time. The smoke E2E tests already use toContain against these constants, so they stay runner-agnostic without test changes.

Out of scope

messages.db.migrateNotImplemented keeps its hard-coded npx form. db migrate is a not-yet-implemented stub; the inconsistency only surfaces when someone runs a command that doesn't exist yet. Not worth plumbing.

Manual test plan

I ran each of the below locally; would appreciate reviewers running them too.

git checkout dan/runner-aware-help-banners
pnpm install
pnpm --filter @cipherstash/cli build
STASH=$PWD/packages/cli/dist/bin/stash.js

Detection prefers npm_config_user_agent over lockfile; overriding it directly is the easiest way to test each runner without installing them.

1. Top-level --help — Usage line and the six Examples should all use the runner:

```sh
node $STASH --help # → npx (default)
npm_config_user_agent='bun/1.x' node $STASH --help # → bunx
npm_config_user_agent='pnpm/9.x' node $STASH --help # → pnpm dlx
npm_config_user_agent='yarn/4.x' node $STASH --help # → yarn dlx
```

2. auth --help (or just auth with no subcommand):

```sh
npm_config_user_agent='bun/1.x' node $STASH auth

Expected: "Usage: bunx @cipherstash/cli auth [options]"

Examples: "bunx @cipherstash/cli auth login" / "...auth login --supabase"

```

3. db install "Next steps" panel — the wizard line should match the runner:

```sh
mkdir /tmp/runner-test && cd /tmp/runner-test
DATABASE_URL=postgresql://test/x npm_config_user_agent='bun/1.x' \
node $STASH db install --dry-run

When the panel prints, the wizard line should read:

bunx @cipherstash/wizard

(You'll also see "bunx @cipherstash/cli db install" as the intro — covered by #377.)

```

4. requireStack hint — surfaces when running db push/validate/schema build without @cipherstash/stack installed:

```sh
cd /tmp/runner-test
DATABASE_URL=postgresql://test/x npm_config_user_agent='pnpm/9.x' \
node $STASH db push

Expected error:

@cipherstash/stack is required for this command.

Install it with: pnpm add @cipherstash/stack

Or run: pnpm dlx @cipherstash/cli init

```

5. Lockfile fallback — without npm_config_user_agent, detection falls back to lockfile:

```sh
cd /tmp/runner-test
touch bun.lock
node $STASH --help # without npm_config_user_agent override

Expected: bunx-flavoured output

rm bun.lock && touch pnpm-lock.yaml
node $STASH --help

Expected: pnpm dlx

rm pnpm-lock.yaml
```

Automated coverage

Surface Coverage
runnerCommand / detectPackageManager themselves Unit-tested in src/commands/init/__tests__/utils.test.ts (from #379)
Top-level --help Usage line + Examples New E2E in tests/e2e/runner-aware-help.e2e.test.ts — 4 cases (npx / bunx / pnpm dlx / yarn dlx) asserting the right runner appears
auth --help Usage line + Examples Same file, 4 more cases
db install "Next steps" panel (wizard line) Not covered — would need a successful install (real DB). Manual only.
requireStack hint Not covered — workspace has @cipherstash/stack installed so the path doesn't fire in CI. Manual only.
messages.cli.usagePrefix no longer hardcoded with npx Smoke E2E (existing) already passes regardless of runner thanks to the leader-only assertion

The two gaps (Next-steps panel and requireStack hint) are awkward to E2E without standing up a real DB or surgically removing @cipherstash/stack from the test environment. If a future PR adds either of those harnesses, both would be cheap to cover then.

Test plan

  • pnpm --filter @cipherstash/cli build clean
  • pnpm --filter @cipherstash/cli test — unit tests pass
  • pnpm --filter @cipherstash/cli test:e2e — 18 E2E tests pass (was 10; +8 from new runner-aware-help.e2e.test.ts)
  • biome check clean on changed files
  • Manual: ran node dist/bin/stash.js --help with npm_config_user_agent cleared / set to pnpm/9 / set to bun/1 and confirmed the rendered Usage line + Examples match the runner.
  • Rebased onto post-feat(cli): layered DATABASE_URL resolution for db / schema commands #377 main

Summary by CodeRabbit

  • New Features

    • CLI help output and post-install instructions now dynamically adapt to match the package manager runner you used (e.g., bunx, pnpm dlx, yarn dlx instead of always showing npx).
  • Tests

    • Added E2E tests for runner-aware help output verification.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 1, 2026

🦋 Changeset detected

Latest commit: 0560049

The changes in this PR will be included in the next version bump.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

📝 Walkthrough

Walkthrough

This PR makes CLI help banners and "Next steps" output dynamically use the package manager runner the user invoked (bunx, pnpm dlx, yarn dlx, or npx fallback) instead of hardcoding npx. Changes span message constants, detection/rendering logic, and integration points across help text and wizard output.

Changes

Runner-Aware Help & Next Steps

Layer / File(s) Summary
Message Constants
packages/cli/src/messages.ts
messages.cli.usagePrefix and messages.auth.usagePrefix changed from hardcoded 'Usage: npx stash' patterns to runner-agnostic 'Usage: ' leaders; runner/package portion is appended at render time.
Package Manager Detection & Helpers
packages/cli/src/bin/stash.ts
Detects package manager via detectPackageManager(), computes STASH runner command once at module level, adds isModuleNotFound() helper for error handling, and updates requireStack() to output package-manager-specific install/init guidance.
Help Text Integration
packages/cli/src/commands/auth/index.ts
Computes STASH_AUTH from detected package manager and uses it in the auth command's usage prefix and example commands instead of hardcoded npx stash auth.
Wizard Next Steps
packages/cli/src/commands/db/install.ts
printNextSteps() detects package manager and renders the wizard invocation using runnerCommand(pm, 'stash') instead of hardcoded stash wizard.
Tests & Documentation
.changeset/cli-runner-aware-help-banners.md, packages/cli/tests/e2e/runner-aware-help.e2e.test.ts
Changeset describes runner-aware rendering across help/next-steps; E2E test verifies --help and auth commands render the correct runner (npx, bunx, pnpm dlx, yarn dlx) from npm_config_user_agent environment variable.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant CLI as CLI Entry
    participant Detect as Package Manager<br/>Detection
    participant Render as Help Renderer
    participant Output as Terminal Output

    User->>CLI: bunx `@cipherstash/cli` --help<br/>(npm_config_user_agent=bunx)
    CLI->>Detect: detectPackageManager()
    Detect->>Detect: Check npm_config_user_agent
    Detect-->>CLI: 'bunx'
    CLI->>CLI: Compute runnerCommand('bunx', 'stash')
    CLI->>Render: Build help with 'bunx stash'
    Render->>Render: Inject 'bunx' into Usage:<br/>and Examples
    Render-->>Output: Usage: bunx stash ...<br/>Examples: bunx stash init ...
    Output-->>User: Display runner-aware help
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • auxesis

🐰 A rabbit hops through the CLI with glee,
No more npx hardcoded, plain to see!
bunx, pnpm dlx, yarn dlx shine bright,
Each runner now shown, oh what a delight! ✨
The help banners dance with the user's own call.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: runner-aware help banners and wizard reference updates across multiple CLI files.
Linked Issues check ✅ Passed The PR fully addresses issue #385 by using runnerCommand and detectPackageManager helpers to make help banners, examples, and wizard references runner-aware across all specified locations.
Out of Scope Changes check ✅ Passed All changes are directly scoped to issue #385; the PR only touches help/wizard references and includes a documented out-of-scope note for db migrate.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dan/runner-aware-help-banners

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 60 minutes.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderdan coderdan force-pushed the dan/runner-aware-help-banners branch from 3a708f9 to 03d845e Compare May 1, 2026 06:09
coderdan added 2 commits May 4, 2026 10:38
Follow-up to PR #377 addressing Lindsay's feedback that the HELP
banners and the wizard reference in `db install`'s "Next steps"
panel still hard-coded `npx`. #379 already added
`runnerCommand(pm, ref)` + `detectPackageManager()`; this sweep
applies it to the remaining places.

User-visible: a user who runs `bunx @cipherstash/cli --help` now
sees `bunx @cipherstash/cli` in the Usage line and Examples, and
the wizard suggestion at the end of `db install` matches the user's
runner. Same for `pnpm dlx`, `yarn dlx`, default `npx`.

Touches:
- `bin/stash.ts` — `HELP` template now interpolates a `STASH`
  constant (`runnerCommand(PM, '@cipherstash/cli')`) for the
  Usage line, the six Examples, and the `requireStack` hint.
- `commands/auth/index.ts` — same pattern for the auth HELP, with
  a `STASH_AUTH` constant for the Usage line + two examples.
- `commands/db/install.ts` — the wizard line in `printNextSteps`
  uses `runnerCommand(pm, '@cipherstash/wizard')`. Also brings
  the `p.intro('npx @cipherstash/cli db install')` line in line
  with the runner-aware pattern (was already pinned for the same
  reason in PR #377; this branch is off main, so it lands here too).

Messages: `messages.cli.usagePrefix` and `messages.auth.usagePrefix`
become stable leaders (`'Usage: '`) — the runner+package suffix
is appended at render time. E2E assertions stay runner-agnostic
because they `toContain('Usage: ')` rather than the full prefix.

Out of scope (still): the migrate stub message in
`messages.db.migrateNotImplemented` keeps its hard-coded `npx`
form. The stub is a placeholder and the inconsistency only shows
when someone runs a not-yet-implemented command — not worth
plumbing for.
Adds 8 new E2E tests in `tests/e2e/runner-aware-help.e2e.test.ts`
asserting that `--help` and `auth --help` surface the right runner
(`npx` / `bunx` / `pnpm dlx` / `yarn dlx`) based on
`npm_config_user_agent`. Covers the gap between the existing unit
tests for `detectPackageManager` / `runnerCommand` (which prove the
helpers work in isolation) and the user-visible HELP rendering
(which the smoke suite checks for existence but not runner-correctness).

The Next-steps panel in `db install` and the `requireStack` hint
are still uncovered by automation — they require either a real DB
or a fixture without `@cipherstash/stack`. Documented as known gaps
in the PR description.
@coderdan coderdan force-pushed the dan/runner-aware-help-banners branch from 03d845e to 0560049 Compare May 4, 2026 00:39
@coderdan coderdan requested a review from a team as a code owner May 4, 2026 00:39
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/cli/tests/e2e/runner-aware-help.e2e.test.ts (1)

35-36: ⚡ Quick win

Use message constants for asserted user-facing strings.

These assertions hard-code usage text; prefer constants from src/messages.ts to keep E2E aligned with copy changes.

♻️ Proposed refactor
 import { describe, expect, it } from 'vitest'
 import { render } from '../helpers/pty.js'
+import { messages } from '../../src/messages.js'
@@
-      expect(r.output).toContain(`Usage: ${label} stash`)
+      expect(r.output).toContain(`${messages.cli.usagePrefix}${label} stash`)
@@
-      expect(r.output).toContain(`Usage: ${label} stash auth`)
+      expect(r.output).toContain(`${messages.auth.usagePrefix}${label} stash auth`)

As per coding guidelines, "Extract user-facing strings that E2E tests assert on into src/messages.ts as constants rather than hard-coding them in tests".

Also applies to: 51-52

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/cli/tests/e2e/runner-aware-help.e2e.test.ts` around lines 35 - 36,
Replace hard-coded usage and example strings in the assertions that inspect
r.output (e.g., the expect(r.output).toContain(`Usage: ${label} stash`) and the
similar assertions around lines 51-52) with constants exported from
src/messages.ts: import the appropriate message constants (e.g., USAGE_STASH or
analogous names) and use those constants in the expect(...).toContain(...)
checks; update the test to reference the message constant(s) for both the Usage
and Examples assertions so E2E stays in sync with copy changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.changeset/cli-runner-aware-help-banners.md:
- Around line 9-16: The fenced code block containing the CLI usage examples (the
block starting with "Usage: bunx `@cipherstash/cli` <command> [options]") is
missing a language identifier and fails markdown linting; update the opening
fence to include a language (e.g., add "text" after the three backticks) so it
reads ```text and leave the block contents unchanged.

In `@packages/cli/tests/e2e/runner-aware-help.e2e.test.ts`:
- Around line 19-20: The test data in
packages/cli/tests/e2e/runner-aware-help.e2e.test.ts currently includes an entry
{ ua: '', label: 'npx' } which is brittle because an empty npm_config_user_agent
can resolve via lockfile fallback; update the test by removing the hard-coded
'npx' expectation for the empty-ua case and instead either (A) add a separate
e2e test that sets up a controlled cwd with no lockfile and asserts the fallback
is 'npx', or (B) change the empty-ua case to assert a more flexible outcome
(e.g., expect no forced label or check that detection falls back to lockfile
resolution) so the test no longer assumes 'npx' unconditionally; locate the
array of UA test vectors in the runner-aware-help.e2e.test.ts file to apply the
change.

---

Nitpick comments:
In `@packages/cli/tests/e2e/runner-aware-help.e2e.test.ts`:
- Around line 35-36: Replace hard-coded usage and example strings in the
assertions that inspect r.output (e.g., the expect(r.output).toContain(`Usage:
${label} stash`) and the similar assertions around lines 51-52) with constants
exported from src/messages.ts: import the appropriate message constants (e.g.,
USAGE_STASH or analogous names) and use those constants in the
expect(...).toContain(...) checks; update the test to reference the message
constant(s) for both the Usage and Examples assertions so E2E stays in sync with
copy changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 99d22c1e-578e-4629-bfdd-2e9c84bb19fa

📥 Commits

Reviewing files that changed from the base of the PR and between b108560 and 0560049.

📒 Files selected for processing (6)
  • .changeset/cli-runner-aware-help-banners.md
  • packages/cli/src/bin/stash.ts
  • packages/cli/src/commands/auth/index.ts
  • packages/cli/src/commands/db/install.ts
  • packages/cli/src/messages.ts
  • packages/cli/tests/e2e/runner-aware-help.e2e.test.ts

Comment thread .changeset/cli-runner-aware-help-banners.md
Comment thread packages/cli/tests/e2e/runner-aware-help.e2e.test.ts
@coderdan coderdan merged commit e64f1d8 into main May 4, 2026
8 checks passed
@coderdan coderdan deleted the dan/runner-aware-help-banners branch May 4, 2026 00:45
auxesis added a commit that referenced this pull request May 4, 2026
Reconciles the rebased branch with main's PR #384 (runner-aware help
banners) and the @cipherstash/cli → stash rename.

Changes:
- Replace remaining `npx drizzle-kit` hardcodings in db/install.ts
  with the detected runner (Task 8 work that conflicted during
  rebase and was skipped — these spots weren't covered by main).
- Make messages.db.migrateNotImplemented runner-aware. Main's
  hardcoded literal `"npx stash db migrate"` was caught by the lint;
  the factory takes a `stashRef` matching the existing `STASH`
  constant in bin/stash.ts.
- Allowlist packages/cli/src/commands/init/lib/setup-prompt.ts
  in the lint script — its `case 'npm': return 'npx --no-install'`
  is the same canonical pattern we already allowlist in
  init/utils.ts.
- Update supabase-migration.test.ts assertions to reference `stash`
  instead of `@cipherstash/cli`.
- Revert the stale post-review fix to `printNextSteps`/
  `writeSupabaseMigrationFile` — main's `printNextSteps()` is
  self-contained and doesn't need a runner threaded through.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

stash CLI help banners and "Next steps" panel hard-code npx regardless of runner

2 participants