-
Notifications
You must be signed in to change notification settings - Fork 3
feat: split the wizard into a seperate package #368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| --- | ||
| '@cipherstash/cli': minor | ||
| --- | ||
|
|
||
| Reduce friction in `stash init`. | ||
|
|
||
| - **No more "How will you connect to your database?" prompt.** Init now auto-detects Drizzle (from `drizzle.config.*` or `drizzle-orm`/`drizzle-kit` in `package.json`) and Supabase (from the host in `DATABASE_URL`), and silently picks the matching encryption client template. Falls back to a generic Postgres template otherwise. | ||
| - **No more "Where should we create your encryption client?" prompt.** Init writes to `./src/encryption/index.ts` by default. The "file already exists, what would you like to do?" prompt still appears so existing client files aren't silently overwritten. | ||
| - **Single combined dependency-install prompt.** Previously init asked twice (once for `@cipherstash/stack`, once for `@cipherstash/cli`). It now asks once, listing both, and runs the installs in sequence. When both packages are already in `node_modules`, no prompt appears at all. | ||
| - **Already-authenticated users skip the "Continue with workspace X?" prompt.** Init logs `Using workspace X` and proceeds. Run `stash auth login` directly to switch workspaces. | ||
|
|
||
| `stash db install` now also calls into the same encryption-client scaffolder as a safety net — users who run `db install` without `init` first still get a working client file generated at the path their `stash.config.ts` points to. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| --- | ||
| '@cipherstash/cli': minor | ||
| --- | ||
|
|
||
| **Breaking:** the `stash wizard` command has been removed. The AI-guided encryption setup is now its own package — run it via `npx @cipherstash/wizard` (or `pnpm dlx`, `bunx`, `yarn dlx`). | ||
|
|
||
| The wizard was pulling `@anthropic-ai/claude-agent-sdk` (47MB unpacked) into every `npx @cipherstash/cli` invocation, even for fast commands like `init`, `auth`, and `db install`. Splitting it out keeps cli's dependency tree small and lets each package manager handle the wizard's install natively — no more shelling out to `npm` from inside the cli, no Yarn PnP / Bun-only failure modes. | ||
|
|
||
| The next-steps output from `init` and `db install` still recommends `npx @cipherstash/wizard` as the automated path. The `schema build` command no longer offers a wizard/builder selection prompt — it goes straight to the schema builder. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| --- | ||
| '@cipherstash/wizard': minor | ||
| --- | ||
|
|
||
| Initial release of `@cipherstash/wizard` — AI-powered encryption setup for CipherStash, extracted from `@cipherstash/cli`. | ||
|
|
||
| Run it once per project, after `stash init`: | ||
|
|
||
| ```bash | ||
| npx @cipherstash/wizard | ||
| pnpm dlx @cipherstash/wizard | ||
| yarn dlx @cipherstash/wizard | ||
| bunx @cipherstash/wizard | ||
| ``` | ||
|
|
||
| The wizard reads your codebase, asks which columns to encrypt, hands a surgical prompt to the Claude Agent SDK against the CipherStash-hosted LLM gateway, and runs deterministic post-agent steps (package install, `db install`, `db push`, framework migrations). Same behavior as the previous `stash wizard` command — just shipped as its own package so it doesn't bloat the cli's dependency tree. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| import { existsSync, mkdirSync, writeFileSync } from 'node:fs' | ||
| import { dirname, resolve } from 'node:path' | ||
| import * as p from '@clack/prompts' | ||
| import type { Integration } from '../init/types.js' | ||
| import { generatePlaceholderClient } from '../init/utils.js' | ||
| import { detectDrizzle, detectSupabase } from './detect.js' | ||
|
|
||
| /** | ||
| * Pick a placeholder template using the same signals `db install` already | ||
| * detects. Drizzle wins over Supabase when both look present (a Drizzle-on- | ||
| * Supabase project is more naturally scaffolded as Drizzle). | ||
| */ | ||
| function detectIntegration( | ||
| cwd: string, | ||
| databaseUrl: string | undefined, | ||
| ): Integration { | ||
| if (detectDrizzle(cwd)) return 'drizzle' | ||
| if (detectSupabase(databaseUrl)) return 'supabase' | ||
| return 'postgresql' | ||
| } | ||
|
|
||
| /** | ||
| * Scaffold an encryption client file at `clientPath` if one doesn't exist. | ||
| * No-op when the file is already present. Silent — never prompts. | ||
| * | ||
| * `init`'s `buildSchemaStep` is the primary path that creates this file | ||
| * (and handles the "file already exists" case interactively). This function | ||
| * exists as a safety net for users who run `db install` directly without | ||
| * `init` first — they still get a working client file rather than failing | ||
| * later when the config tries to load a non-existent path. | ||
| */ | ||
| export function ensureEncryptionClient( | ||
| clientPath: string, | ||
| cwd: string = process.cwd(), | ||
| databaseUrl: string | undefined = process.env.DATABASE_URL, | ||
| ): void { | ||
| const resolved = resolve(cwd, clientPath) | ||
| if (existsSync(resolved)) return | ||
|
|
||
| const integration = detectIntegration(cwd, databaseUrl) | ||
| const contents = generatePlaceholderClient(integration) | ||
|
|
||
| const dir = dirname(resolved) | ||
| if (!existsSync(dir)) { | ||
| mkdirSync(dir, { recursive: true }) | ||
| } | ||
| writeFileSync(resolved, contents, 'utf-8') | ||
|
|
||
| p.log.success( | ||
| `Scaffolded encryption client at ${clientPath} (${integration} template)`, | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -9,6 +9,7 @@ import { | |||||||||||||||||||||
| loadBundledEqlSql, | ||||||||||||||||||||||
| } from '@/installer/index.js' | ||||||||||||||||||||||
| import * as p from '@clack/prompts' | ||||||||||||||||||||||
| import { ensureEncryptionClient } from './client-scaffold.js' | ||||||||||||||||||||||
| import { ensureStashConfig } from './config-scaffold.js' | ||||||||||||||||||||||
| import { | ||||||||||||||||||||||
| type SupabaseProjectInfo, | ||||||||||||||||||||||
|
|
@@ -86,6 +87,11 @@ export async function installCommand(options: InstallOptions) { | |||||||||||||||||||||
| const config = await loadStashConfig() | ||||||||||||||||||||||
| s.stop('Configuration loaded.') | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Safety net: if the user ran `db install` without first running `init`, | ||||||||||||||||||||||
| // scaffold the encryption client file so config.client points somewhere | ||||||||||||||||||||||
| // real. No-op when the file already exists. | ||||||||||||||||||||||
| ensureEncryptionClient(config.client, process.cwd(), config.databaseUrl) | ||||||||||||||||||||||
|
Comment on lines
+90
to
+93
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Line 93 runs Proposed fix- ensureEncryptionClient(config.client, process.cwd(), config.databaseUrl)
+ if (!options.dryRun) {
+ ensureEncryptionClient(config.client, process.cwd(), config.databaseUrl)
+ }📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // Auto-detect provider hints when the user didn't explicitly pass flags. | ||||||||||||||||||||||
| // CIP-2985. | ||||||||||||||||||||||
| const resolved = resolveProviderOptions(options, config.databaseUrl) | ||||||||||||||||||||||
|
|
@@ -258,8 +264,8 @@ function printNextSteps(): void { | |||||||||||||||||||||
| [ | ||||||||||||||||||||||
| 'Next steps:', | ||||||||||||||||||||||
| '', | ||||||||||||||||||||||
| ' 1. Wire up encrypt/decrypt with the wizard:', | ||||||||||||||||||||||
| ' npx @cipherstash/cli wizard', | ||||||||||||||||||||||
| ' 1. Wire up encrypt/decrypt with the wizard (AI-guided, automated):', | ||||||||||||||||||||||
| ' npx @cipherstash/wizard', | ||||||||||||||||||||||
| '', | ||||||||||||||||||||||
| ' 2. Or use the client directly from @cipherstash/stack:', | ||||||||||||||||||||||
| " import { Encryption } from '@cipherstash/stack'", | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a language to the flow-diagram fence.
The unlabeled fence on Line 31 triggers MD040. Mark it as
textso docs lint stays clean.Suggested fix
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 31-31: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents