feat(cli): hand off init to local coding agents (Claude / Codex / AGENTS.md / wizard)#395
feat(cli): hand off init to local coding agents (Claude / Codex / AGENTS.md / wizard)#395coderdan wants to merge 6 commits intodan/stash-wizard-wrapperfrom
Conversation
🦋 Changeset detectedLatest commit: dad8a3f The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 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 |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
4ab8e16 to
ce70b4d
Compare
39e8420 to
b392b38
Compare
After authentication, schema generation, and Forge install, init now offers to hand off the rest of setup to Claude Code. Choosing the handoff installs a project-local skill at .claude/skills/cipherstash-setup/SKILL.md and writes .cipherstash/context.json describing the integration, encryption client path, columns, env keys, and package manager — then spawns claude interactively. The skill body comes from a versioned rulebook (core + integration partials) that ships bundled with the CLI. When wizard.getstash.sh is reachable, the CLI prefers the gateway-served version so content updates between releases land without a CLI bump; network failures fall through to the bundled copy silently. CIPHERSTASH_WIZARD_URL overrides the gateway endpoint for local testing. Re-running init upserts the managed region of SKILL.md via sentinel markers (<!-- cipherstash:rulebook start/end -->) so user edits outside the block are preserved. Three completion modes are available at the new "how to proceed" step: - Hand off to Claude Code (default when claude detected) - Just write the rules files (no spawn — drive your own agent) - Use the CipherStash Agent (run stash wizard later) Phase 1 only targets Claude Code; Codex (AGENTS.md), Cursor, and Copilot writers are scoped for follow-up phases.
…S.md) Phase 2 of the init agent handoff. Replaces the three-mode "how to proceed" prompt with a four-option menu so users can pick the agent that matches their workflow: - Hand off to Claude Code (default when claude on PATH) - Hand off to Codex (default when codex on PATH and claude is not) - Use the CipherStash Agent (fallback — runs `stash wizard`) - Write AGENTS.md (default when neither CLI agent is detected) Detection is non-blocking: a missing CLI doesn't hide the option, the handoff step still writes the rules files and prints install + manual-launch instructions. The user's progress is never wasted. Adds renderAgentsMd to @cipherstash/cli's bundled rulebook (plain markdown, no YAML frontmatter — sentinel-marker friendly). Extends fetchRulebook to take an `agent` parameter so the gateway can serve SKILL.md or AGENTS.md from the same endpoint and the bundled fallback picks the right renderer. Refactors the shared writer logic (context.json + sentinel-upserted artifact files + CLI version walker) into lib/write-context.ts so all four handoff steps share one implementation.
b392b38 to
581831d
Compare
…n prompt Three changes that turn the agent handoff from "here are the rules, figure it out" into "here's exactly what to do": 1. **Resolve DATABASE_URL upfront and require it.** New resolve-database step wraps the existing resolveDatabaseUrl resolver (--flag → env → supabase status → interactive prompt → hard fail). The URL is threaded through state so downstream steps don't re-prompt. 2. **Introspect the database and let the user pick columns.** build-schema now connects, lists tables in the public schema, and runs the same multi-select UX as `stash schema build` (lifted into a shared lib). Empty databases still fall back to the placeholder users/email/name client; the action prompt notes that and asks the agent to reshape it. 3. **Install EQL during init.** New install-eql step runs `stash db install` programmatically after a y/N confirm, using the URL we already resolved. No second credential prompt. Skipping isn't a dead end — the action prompt's first TODO becomes "run stash db install". 4. **Write `.cipherstash/setup-prompt.md`** — a per-project action plan generated from init state. Lists what init already did and what's left with exact commands and paths (drizzle-kit generate / migrate, supabase migration new, etc.) tailored to the detected integration and package manager. Claude / Codex launch prompts now point the agent at this file first; the skill / AGENTS.md provides the reusable rulebook the prompt references. For IDE users, it's ready to paste into the first chat. Renames install-forge → install-deps. "Forge" was the legacy name for the CLI itself (renamed to `stash` in #383); the step installs `@cipherstash/stack` and `stash`, so install-deps says what it actually does. Refactor: introspectDatabase + selectTableColumns lifted from schema/build.ts into init/lib/introspect.ts so both the standalone command and the new init step share one codepath. generateClientFromSchemas similarly consolidated into init/utils.ts.
A leftover `node_modules/<pkg>/` directory with no `package.json` (from a prior aborted install, a stale workspace symlink, or npm pruning a package mid-install) was previously treated as installed. install-deps would skip the install — and then install-eql's call to installCommand would scaffold `stash.config.ts`, try to load it via jiti, and crash with `Cannot find module 'stash'` deep inside jiti's resolver. Two changes: 1. `isPackageInstalled` now requires both the directory AND a `package.json` inside it. Matches what Node's resolver actually needs to load the module. 2. install-eql double-checks that `stash` is loadable before calling `installCommand`. If install-deps was skipped or rolled back, we exit the step with a clear error pointing the user at the right manual command, instead of letting the failure surface as an opaque jiti trace mid-flow. Adds tests covering the directory-without-manifest case so this can't regress silently.
Before this, `.cipherstash/context.json` was only written inside the
handoff step. If init aborted between build-schema and the handoff —
install-eql crashing, Ctrl+C, anything — the previous run's context.json
would still be on disk, and a user manually launching `claude` against
the stale file would see a placeholder schema instead of what was just
introspected.
The fix writes a baseline context.json at the end of build-schema using
the bundled rulebook version. Handoff steps still refresh it with the
gateway-served rulebook version (when reachable), but the file is no
longer dependent on the handoff completing — it tracks the encryption
client at the moment that client is generated.
This was the root cause of a tester seeing claude reading
`{"tableName":"users","columns":[...]}` after they had selected
`transactions` during the (working) introspection prompt.
…lti-table schemas) Pre-review pass over the init agent handoff: - Use `fileURLToPath` instead of `new URL(...).pathname` in `rulebook/partials.ts` — the latter breaks on Windows (`/C:/...`) and on paths with spaces. - Replace the POSIX-only `/bin/sh -c command -v` with a pure-Node PATH walk in `detect-agents.ts`. Honours `PATHEXT`-style suffixes (`.cmd`, `.exe`, `.bat`) on Windows so `claude.cmd` is detected. - Split `wizardCommand` into `runWizardSpawn` (returns exit code) and `wizardCommand` (calls `process.exit`). The init handoff path uses `runWizardSpawn` so init can finish its outro and run `next-steps` instead of aborting on a non-zero wizard exit. - Single-quote the launch-prompt examples printed to the user when `claude`/`codex` aren't on PATH — robust against any future shell-special characters in the prompt. - Store env-key names on `InitState` once (in `build-schema`) rather than scanning `.env*` files three times across `gather-context`, the baseline write, and the chosen handoff. Drops the awkward "side channel" comment in gather-context. - Change `state.schema: SchemaDef` to `state.schemas: SchemaDef[]` (and same in `ContextFile`) so multi-table introspection runs are represented faithfully. Drop the unused `schema` field from `SetupPromptContext` (the renderer never read it). - Drop the stale "Renamed from `forgeInstalled`" comment from `InitState`. The rename is in git history. - Inline the `buildFromIntrospection` one-line forwarder. README updated with the new init flow, the four-option handoff menu, and a `stash wizard` reference section. Outdated "edit your encryption client by hand" guidance removed in favour of the action-prompt-driven workflow. 154 stack CLI tests pass (no behaviour change in the test suite). 17 suite rulebook tests pass.
Summary
Stacked on #394.
stash initnow runs the whole CipherStash setup as one flow — auth, resolveDATABASE_URL, introspect the database and let the user pick columns, install dependencies, install EQL, then hand off the rest to the user's local coding agent.A four-option menu at the end picks where to go from there:
.claude/skills/cipherstash-setup/SKILL.md, writes.cipherstash/context.jsonand.cipherstash/setup-prompt.md, spawnsclaudeinteractively. Default whenclaudeis on PATH.AGENTS.md(sentinel-upserted), the same context + setup-prompt files, spawnscodexinteractively. Default whencodexis on PATH (andclaudeisn't)..cipherstash/context.jsonand runsstash wizard. Fallback for users without a local CLI agent.AGENTS.md+.cipherstash/context.json+.cipherstash/setup-prompt.mdand stops. For Cursor / Windsurf / Cline / any tool that follows the AGENTS.md convention.If a chosen CLI agent isn't installed, init still writes the rules files and prints install + manual-launch instructions. Progress is never wasted.
The three artifacts
.cipherstash/context.json— pure facts: integration, encryption client path, every selected schema, env-key names (never values), package manager, install command, rulebook + CLI versions, generation timestamp. Written immediately afterbuild-schema(with the bundled rulebook version) so it always tracks the encryption client; handoff steps refresh it with the gateway-served version when reachable. The early baseline means a mid-flow failure leavescontext.jsonconsistent with the encryption client, not stale from a previous run..cipherstash/setup-prompt.md— project-specific action plan generated from init state. "Init has done X and Y; here's exactly what to do next, with these commands and paths." Tailored per integration + package manager (e.g. drizzle-kit / Supabase / Prisma / generic). The launch prompt for Claude / Codex points the agent at this file first.SKILL.md/AGENTS.md— reusable rulebook with the never-do-this list, column-type rules, ORM-specific patterns. Sentinel-marker upserted (<!-- cipherstash:rulebook start/end -->) so re-runs replace only the managed region; user edits outside survive.Rulebook source
Versioned content lives in a new
@cipherstash/rulebookpackage (see suite PR #506). The CLI ships with the bundled partials and renderers but prefers the gateway-served version whenwizard.getstash.sh/v1/wizard/rulebookis reachable — so content updates land between CLI releases. Network failures fall through to the bundled copy silently.CIPHERSTASH_WIZARD_URLoverrides the gateway endpoint for local-dev against a wizard gateway running onlocalhost.Init pipeline
Smoke-test status
claudespawn launched correctlycodexspawn path not yet exercised end-to-endstash wizardwrapper is exercised by feat(cli): stash wizard thin-wrapper subcommand #394's smoke tests but the init→wizard chain hasn't been run end-to-end/etc/hostsblock ofwizard.getstash.shTest plan for reviewer
pnpm --filter stash test(154 tests)pnpm --filter stash buildcleanmkdir demo && cd demo && pnpm init -y && pnpm add drizzle-orm→node /path/to/dist/bin/stash.js init→ step through the four optionswizard.getstash.sh(e.g./etc/hosts) and confirm the bundled fallback message + valid SKILL.md outputArchitectural notes
introspectDatabase+selectTableColumnslifted fromcommands/schema/build.tsintocommands/init/lib/introspect.tsso bothstash schema buildandstash initshare one introspection codepath.generateClientFromSchemas— moved intocommands/init/utils.ts.packages/cli/src/rulebook/holds the bundled markdown partials + renderers (core + drizzle / supabase / postgresql).commands/init/lib/sentinel-upsert.tsis the managed-block writer used by bothSKILL.mdandAGENTS.md.isPackageInstallednow requires both the directory AND apackage.jsoninside it (matches what Node's resolver actually needs to load the module). The earlier "directory exists" check was treating leftover/broken installs as valid.Related