Skip to content

Releases: cipherstash/stack

stash@0.13.0

06 May 16:43
1175e86

Choose a tag to compare

Minor Changes

  • e16b282: Split agent handoff out of stash init into a new stash impl command. init now owns scaffolding only (auth, database, encryption client, EQL extension) and exits at a clean checkpoint pointing at stash impl. stash impl derives plan-vs-implement mode from disk state — if .cipherstash/plan.md is missing it asks the agent to draft a plan; if it exists, the agent executes the plan as the source of truth. --continue-without-plan skips the planning checkpoint after an interactive confirmation. The earlier in-init Plan first / Go straight to implementation picker is removed in favour of the new command boundary.

  • db163e1: stash impl now renders a plan summary panel and asks the user to confirm before launching the implementation agent. When a plan exists, the CLI parses a machine-readable <!-- cipherstash:plan-summary {...} --> block (the planning agent is instructed to emit one at the top of .cipherstash/plan.md) and prints column counts, per-column paths, and whether the work is single-deploy or staged across 4 deploys. Default-yes on the confirm so the path of least resistance is to proceed; saying No exits cleanly. Older plans without the summary block fall back to a soft "open in your editor" panel — never an error. Non-TTY runs (CI, pipes) skip the confirm and proceed.

  • 59b138b: Extract planning into its own stash plan command. Three commands now own the setup lifecycle:

    • stash init — scaffold (auth, db, deps, EQL). Ends with a chain prompt to stash plan.
    • stash plan — draft a reviewable plan at .cipherstash/plan.md. Ends with a chain prompt to stash impl.
    • stash impl — execute. With a plan, shows the summary panel and confirms. Without one, presents a Draft a plan first / Continue without a plan picker (the second option goes through a security confirm). --continue-without-plan skips the picker.

    stash status reflects the new flow — its "Plan written" stage and Next: line route to stash plan when init is done but no plan exists. Non-TTY runs of stash impl without a plan now error out with a clear next-action rather than guessing intent.

  • db163e1: Add stash status — a top-level lifecycle map for the project. Reads .cipherstash/context.json, .cipherstash/plan.md, and .cipherstash/setup-prompt.md from disk to render a panel showing whether init is done, whether a plan has been written, and whether an agent has been engaged. Points at stash db status for EQL install info and stash encrypt status for per-column migration phase. Runs in milliseconds — no auth, no database connection required. The existing stash db status is unchanged.

stash@0.12.1

04 May 22:32
f66ca99

Choose a tag to compare

Patch Changes

  • 439c63e: Fix backfill CLI wrapper to resolve schema column metadata correctly and surface configuration errors with author-controlled messages while keeping generic diagnostics for unexpected failures.

stash@0.12.0

04 May 17:04
2a669d9

Choose a tag to compare

Minor Changes

  • f315334: stash init can now hand off the rest of setup to whichever coding agent the user is set up with — and it leaves them with a project-specific action plan and the right reference material, not just generic rules.

    The new pipeline:

    1. Authenticate (unchanged).
    2. Resolve DATABASE_URL — uses the same resolver as stash db install (flag → env → supabase status → interactive prompt). Hard-fails with an actionable message if nothing resolves.
    3. Build the encryption client. When the database has tables, init introspects them and generates a real client from the user's selection. When the database is empty, it falls back to a placeholder so fresh projects still work — and the action prompt notes the placeholder so the agent reshapes it later.
    4. Install dependencies@cipherstash/stack (runtime) + stash (CLI dev dep).
    5. Install EQL into the database — y/N confirm, then runs stash db install programmatically against the URL we already resolved. No second prompt for credentials.
    6. Pick a handoff from the four-option menu. Each handoff installs the right artifacts for the chosen tool:
      • Hand off to Claude Code — copies the per-integration set of authored skills (stash-encryption + stash-<integration> + stash-cli) into .claude/skills/, writes .cipherstash/context.json and .cipherstash/setup-prompt.md, spawns claude. Default when claude is on PATH.
      • Hand off to Codex — writes a sentinel-managed AGENTS.md (durable doctrine) + copies the same skills into .codex/skills/ (procedural workflows), writes context.json + setup-prompt.md, spawns codex. Default when codex is on PATH and claude is not. Follows OpenAI's Codex guidance: AGENTS.md for repo doctrine, skills for repeatable workflows.
      • Use the CipherStash Agent — writes context.json and runs stash wizard. Fallback for users without a local CLI agent. The wizard installs its own skills.
      • Write AGENTS.md — for editor agents (Cursor, Windsurf, Cline) that don't auto-load skill directories. Writes a single AGENTS.md with the doctrine plus the relevant skill content inlined under a sentinel block, so the agent has the API details without needing to follow file references. Plus context.json + setup-prompt.md. No spawn.

    Detection is non-blocking: if the chosen CLI agent (claude or codex) isn't installed, init still writes the artifacts and prints install + manual-launch instructions. Progress is never wasted.

    .cipherstash/setup-prompt.md is the headline artifact. It's the project-specific action plan — "init has done X and Y; you need to do Z next, with these exact commands and paths" — generated from the current init state. The launch prompt for Claude / Codex points the agent at this file first; the installed skills provide the reusable rulebook the prompt references. For IDE users, it's ready to paste into the first chat.

    Per-integration skill subset:

    drizzle    → stash-encryption + stash-drizzle  + stash-cli
    supabase   → stash-encryption + stash-supabase + stash-cli
    postgresql → stash-encryption + stash-cli
    

    The skills themselves are the authored ones at the repo root (/skills/); they ship inside the CLI tarball via tsup so init can copy them locally without a network round-trip. The AGENTS.md doctrine fragment ships the same way.

    Re-running init is safe — AGENTS.md uses sentinel-marker upsert (<!-- cipherstash:rulebook start/end -->), so the managed region is replaced in place and any user edits outside it are preserved. Skill directories are overwritten so the user always gets the latest content. setup-prompt.md is regenerated wholesale each run since it's meant to reflect the current state.

    .cipherstash/context.json is the universal "what shape is this project" payload — integration, encryption client path, schema, env key names (never values), package manager, install command, CLI version, names of installed skills, generation timestamp.

  • ce70b4d: Add stash wizard as a thin wrapper subcommand around @cipherstash/wizard.

    The wizard ships as a separate npm package so the heavy agent SDK stays out of the stash CLI bundle. Until now, users had to remember a second tool name (npx @cipherstash/wizard); the wrapper exposes the same capability under the existing stash surface so the user only has to think about one CLI.

    stash wizard detects the project's package manager and spawns the wizard via the matching one-shot runner — npx, pnpm dlx, yarn dlx, or bunx — with stdio: 'inherit' so the wizard owns the terminal cleanly. Any flags after wizard are forwarded verbatim, so stash wizard --debug works.

    On a cold cache (the wizard package isn't installed in the project) the runner downloads it before launching — a few seconds. The wrapper prints an explicit "first run downloads ~5s" line in that case so the CLI doesn't appear hung. On a warm cache, just a "Launching the CipherStash wizard…" line, then the wizard takes over.

    Existing copy that pointed at npx @cipherstash/wizard (init's next-steps for base / Drizzle / Supabase, db install's post-install note) now uses stash wizard.

  • add4357: Add stash encrypt command group and @cipherstash/migrate library for plaintext → encrypted column migrations.

    New CLI commands:

    • stash encrypt status — per-column migration status (phase, backfill progress, drift between intent and state, EQL registration).
    • stash encrypt plan — diff .cipherstash/migrations.json (intent) vs observed state.
    • stash encrypt backfill --table <t> --column <c> — resumable, idempotent, chunked encryption of plaintext into <col>_encrypted. Uses the user's encryption client (Protect/Stack). SIGINT-safe; re-run to resume. The first run on a column prompts to confirm dual-writes are deployed (or accept --confirm-dual-writes-deployed for non-interactive contexts), records the dual_writing transition in cs_migrations, then runs the chunked encryption loop. --force re-encrypts every plaintext row regardless of current state — recovery path for drift caused by an earlier backfill running before dual-writes were actually live.
    • stash encrypt cutover --table <t> --column <c> — runs eql_v2.rename_encrypted_columns() inside a transaction; optionally forces Proxy config refresh via CIPHERSTASH_PROXY_URL. After cutover, apps reading <col> transparently receive the encrypted column.
    • stash encrypt drop --table <t> --column <c> — generates a migration file that drops the old plaintext column.

    stash db install now also installs a cipherstash.cs_migrations table used to track per-column migration runtime state (current phase, backfill cursor, rows processed). The table is append-only (event-log shape) and kept separate from eql_v2_configuration which remains the authoritative EQL intent store used by Proxy.

    The new @cipherstash/migrate package exposes the same primitives as a library for users who want to embed backfill in their own workers or cron jobs — all commands are thin wrappers around its exports (runBackfill, appendEvent, latestByColumn, progress, renameEncryptedColumns, reloadConfig, readManifest, writeManifest).

Patch Changes

  • 39af183: Make --help banners and the post-install "Next steps" panel show commands using the package manager the user actually invoked the CLI with, instead of always emitting npx.

    A user who runs bunx @cipherstash/cli --help now sees:

    Usage: bunx @cipherstash/cli <command> [options]
    …
    Examples:
      bunx @cipherstash/cli init
      bunx @cipherstash/cli auth login
      bunx @cipherstash/cli db install
    

    instead of npx @cipherstash/cli … regardless of how they invoked it. Same for pnpm dlx, yarn dlx, and the default npx path.

    Concretely:

    • --help (top-level) — usage line and all six examples in bin/stash.ts.
    • --help (auth) — usage line and the two auth login examples in commands/auth/index.ts.
    • db install's "Next steps" note — the wizard invocation now matches the user's runner.
    • The @cipherstash/stack is required for this command hint shown by requireStack (when db push/validate/schema build are run before the runtime SDK is installed) now suggests the package manager's install command and the user's runner for the follow-up init invocation.

    No public-API change. Detection sources unchanged from #379: npm_config_user_agent first, then lockfile, then npx fallback.

  • a8dbb65: Render every user-facing CLI string and execute every shell-out under the detected package manager (npx / bunx / pnpm dlx / yarn dlx), completing the work started in #379. Affected surfaces: @cipherstash/cli top-level + auth + env help, db install Drizzle migration steps, db migrate not-implemented warning, the Supabase migration SQL header, the Supabase status fallback exec, the @cipherstash/protect stash Stricli help (set/get/list/delete), the @cipherstash/wizard usage line and agent command allowlist, and the @cipherstash/drizzle generate-eql-migration help + drizzle-kit invocation. A new pnpm run lint:runners lint runs in CI and fails on any reintroduction of a hardcoded runner literal.

  • Updated dependencies [add4357]

    • @cipherstash/migrate@0.2.0

@cipherstash/wizard@0.1.3

04 May 17:04
2a669d9

Choose a tag to compare

Patch Changes

  • a8dbb65: Render every user-facing CLI string and execute every shell-out under the detected package manager (npx / bunx / pnpm dlx / yarn dlx), completing the work started in #379. Affected surfaces: @cipherstash/cli top-level + auth + env help, db install Drizzle migration steps, db migrate not-implemented warning, the Supabase migration SQL header, the Supabase status fallback exec, the @cipherstash/protect stash Stricli help (set/get/list/delete), the @cipherstash/wizard usage line and agent command allowlist, and the @cipherstash/drizzle generate-eql-migration help + drizzle-kit invocation. A new pnpm run lint:runners lint runs in CI and fails on any reintroduction of a hardcoded runner literal.

@cipherstash/protect@11.1.2

04 May 17:04
2a669d9

Choose a tag to compare

Patch Changes

  • a8dbb65: Render every user-facing CLI string and execute every shell-out under the detected package manager (npx / bunx / pnpm dlx / yarn dlx), completing the work started in #379. Affected surfaces: @cipherstash/cli top-level + auth + env help, db install Drizzle migration steps, db migrate not-implemented warning, the Supabase migration SQL header, the Supabase status fallback exec, the @cipherstash/protect stash Stricli help (set/get/list/delete), the @cipherstash/wizard usage line and agent command allowlist, and the @cipherstash/drizzle generate-eql-migration help + drizzle-kit invocation. A new pnpm run lint:runners lint runs in CI and fails on any reintroduction of a hardcoded runner literal.

@cipherstash/protect-dynamodb@11.0.2

04 May 17:04
2a669d9

Choose a tag to compare

Patch Changes

  • Updated dependencies [a8dbb65]
    • @cipherstash/protect@11.1.2

@cipherstash/migrate@0.2.0

04 May 17:04
2a669d9

Choose a tag to compare

Minor Changes

  • add4357: Add stash encrypt command group and @cipherstash/migrate library for plaintext → encrypted column migrations.

    New CLI commands:

    • stash encrypt status — per-column migration status (phase, backfill progress, drift between intent and state, EQL registration).
    • stash encrypt plan — diff .cipherstash/migrations.json (intent) vs observed state.
    • stash encrypt backfill --table <t> --column <c> — resumable, idempotent, chunked encryption of plaintext into <col>_encrypted. Uses the user's encryption client (Protect/Stack). SIGINT-safe; re-run to resume. The first run on a column prompts to confirm dual-writes are deployed (or accept --confirm-dual-writes-deployed for non-interactive contexts), records the dual_writing transition in cs_migrations, then runs the chunked encryption loop. --force re-encrypts every plaintext row regardless of current state — recovery path for drift caused by an earlier backfill running before dual-writes were actually live.
    • stash encrypt cutover --table <t> --column <c> — runs eql_v2.rename_encrypted_columns() inside a transaction; optionally forces Proxy config refresh via CIPHERSTASH_PROXY_URL. After cutover, apps reading <col> transparently receive the encrypted column.
    • stash encrypt drop --table <t> --column <c> — generates a migration file that drops the old plaintext column.

    stash db install now also installs a cipherstash.cs_migrations table used to track per-column migration runtime state (current phase, backfill cursor, rows processed). The table is append-only (event-log shape) and kept separate from eql_v2_configuration which remains the authoritative EQL intent store used by Proxy.

    The new @cipherstash/migrate package exposes the same primitives as a library for users who want to embed backfill in their own workers or cron jobs — all commands are thin wrappers around its exports (runBackfill, appendEvent, latestByColumn, progress, renameEncryptedColumns, reloadConfig, readManifest, writeManifest).

@cipherstash/drizzle@3.0.2

04 May 17:04
2a669d9

Choose a tag to compare

Patch Changes

  • a8dbb65: Render every user-facing CLI string and execute every shell-out under the detected package manager (npx / bunx / pnpm dlx / yarn dlx), completing the work started in #379. Affected surfaces: @cipherstash/cli top-level + auth + env help, db install Drizzle migration steps, db migrate not-implemented warning, the Supabase migration SQL header, the Supabase status fallback exec, the @cipherstash/protect stash Stricli help (set/get/list/delete), the @cipherstash/wizard usage line and agent command allowlist, and the @cipherstash/drizzle generate-eql-migration help + drizzle-kit invocation. A new pnpm run lint:runners lint runs in CI and fails on any reintroduction of a hardcoded runner literal.

stash@0.11.0

01 May 18:06
af78001

Choose a tag to compare

Minor Changes

  • de9c02c: Rename the CLI package from @cipherstash/cli to stash. The published code, commands, and flags are unchanged — this is a pure rename so the day-to-day invocation drops from npx @cipherstash/cli ... to npx stash ....

    Migration

    1. Update your package.json devDependencies:

      -  "@cipherstash/cli": "^0.10.0"
      +  "stash": "^0.10.1"
    2. Update the defineConfig import in stash.config.ts:

      - import { defineConfig } from '@cipherstash/cli'
      + import { defineConfig } from 'stash'
    3. Update any npx @cipherstash/cli ... / bunx @cipherstash/cli ... / pnpm dlx @cipherstash/cli ... / yarn dlx @cipherstash/cli ... invocations in scripts, CI, READMEs, and team docs to use stash instead. Programmatic exports (defineConfig, loadStashConfig, EQLInstaller, loadBundledEqlSql, downloadEqlSql, PermissionCheckResult) are re-exported from stash with the same shapes.

    Wizard impact (@cipherstash/wizard)

    The wizard's post-agent step and its prerequisite / agent-error hints now reference stash (e.g. Run: bunx stash auth login, Running bunx stash db install...) rather than @cipherstash/cli. The wizard package name and stash-wizard binary are unchanged — only the strings the wizard prints and the commands it shells out to are affected.

  • 8ee11fd: Layered DATABASE_URL resolution for DB / schema commands.

    Previously, any DB-touching command (db install, db push, db upgrade, db status, db validate, db test-connection, schema build) failed with the cryptic Zod error:

    Error: Invalid stash.config.ts
      - databaseUrl: Invalid input: expected nonoptional, received undefined
    

    if DATABASE_URL wasn't already in the environment. The CLI auto-loaded .env.local / .env.development.local / .env.development / .env, but had no story for --database-url flags, local Supabase, or pasted-once values.

    The scaffolded stash.config.ts now calls a resolver directly:

    import { defineConfig, resolveDatabaseUrl } from "stash";
    
    export default defineConfig({
      databaseUrl: await resolveDatabaseUrl(),
      client: "./src/encryption/index.ts",
    });

    resolveDatabaseUrl() walks sources in order; first hit wins:

    1. --database-url <url> flag — new, accepted on all seven DB / schema commands. Used for this run only; never written to disk.
    2. process.env.DATABASE_URL — covers shell exports, mise, direnv, dotenv-cli, the existing dotenv loads.
    3. supabase status --output envDB_URL — auto-engaged when --supabase is set or a supabase/config.toml is detected. Useful for local Supabase users who haven't exported the URL yet.
    4. Interactive prompt — opens with a tip listing the alternatives (flag, env, the user's actual dotenv file). Skipped under CI=true or non-TTY stdin.
    5. Hard fail with a source-naming error message.

    The connection string is never persisted to diskstash.config.ts only contains the await resolveDatabaseUrl() call, never a literal URL. The resolver also doesn't mutate process.env; CLI flag context is threaded into the config evaluation via AsyncLocalStorage so concurrent loads stay isolated. Source labels are logged on non-env paths (Using DATABASE_URL from --database-url flag / from supabase status / from prompt) but the URL itself is never echoed.

    db test-connection's connection-failure hint is now source-aware: it points users at --database-url, the env var, and the actual dotenv file in their project (.env.local if present, .env otherwise) — not the misleading stash.config.ts it used to suggest.

@cipherstash/wizard@0.1.2

01 May 18:06
af78001

Choose a tag to compare

Patch Changes

  • de9c02c: Rename the CLI package from @cipherstash/cli to stash. The published code, commands, and flags are unchanged — this is a pure rename so the day-to-day invocation drops from npx @cipherstash/cli ... to npx stash ....

    Migration

    1. Update your package.json devDependencies:

      -  "@cipherstash/cli": "^0.10.0"
      +  "stash": "^0.10.1"
    2. Update the defineConfig import in stash.config.ts:

      - import { defineConfig } from '@cipherstash/cli'
      + import { defineConfig } from 'stash'
    3. Update any npx @cipherstash/cli ... / bunx @cipherstash/cli ... / pnpm dlx @cipherstash/cli ... / yarn dlx @cipherstash/cli ... invocations in scripts, CI, READMEs, and team docs to use stash instead. Programmatic exports (defineConfig, loadStashConfig, EQLInstaller, loadBundledEqlSql, downloadEqlSql, PermissionCheckResult) are re-exported from stash with the same shapes.

    Wizard impact (@cipherstash/wizard)

    The wizard's post-agent step and its prerequisite / agent-error hints now reference stash (e.g. Run: bunx stash auth login, Running bunx stash db install...) rather than @cipherstash/cli. The wizard package name and stash-wizard binary are unchanged — only the strings the wizard prints and the commands it shells out to are affected.