@posthog/wizard 2.29.0 → 2.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +35 -1
  2. package/dist/README.md +33 -0
  3. package/dist/{add-mcp-server-to-clients-B6Pj4IKt.js → add-mcp-server-to-clients-BPBRx_Nz.js} +4 -4
  4. package/dist/{add-mcp-server-to-clients-B6Pj4IKt.js.map → add-mcp-server-to-clients-BPBRx_Nz.js.map} +1 -1
  5. package/dist/{agent-interface-CVW8H9eF.js → agent-interface-DT_uyR45.js} +504 -425
  6. package/dist/agent-interface-DT_uyR45.js.map +1 -0
  7. package/dist/{agent-runner-VzTpPaVT.js → agent-runner-DfRka7f7.js} +41 -24
  8. package/dist/agent-runner-DfRka7f7.js.map +1 -0
  9. package/dist/{analytics-DvDjbNmK.js → analytics-3GR9OyE9.js} +14 -6
  10. package/dist/analytics-3GR9OyE9.js.map +1 -0
  11. package/dist/{api-DfpSG5xU.js → api-Dmc76exl.js} +3 -3
  12. package/dist/{api-DfpSG5xU.js.map → api-Dmc76exl.js.map} +1 -1
  13. package/dist/bin.js +33 -33
  14. package/dist/bin.js.map +1 -1
  15. package/dist/{ci-install-Bzfo3nON.js → ci-install-QWrT_cW8.js} +4 -4
  16. package/dist/{ci-install-Bzfo3nON.js.map → ci-install-QWrT_cW8.js.map} +1 -1
  17. package/dist/{debug-HQ0NrBA2.js → debug-aqoKImO6.js} +1 -1
  18. package/dist/{debug-CMZ7kqW1.js → debug-n42RObru.js} +9 -10
  19. package/dist/debug-n42RObru.js.map +1 -0
  20. package/dist/{environment-cVP7bGnh.js → environment-BKPsjOXk.js} +3 -3
  21. package/dist/{environment-cVP7bGnh.js.map → environment-BKPsjOXk.js.map} +1 -1
  22. package/dist/{file-utils-D1632P4x.js → file-utils-ALRqLr0x.js} +2 -2
  23. package/dist/{file-utils-D1632P4x.js.map → file-utils-ALRqLr0x.js.map} +1 -1
  24. package/dist/{interactive-DCIL3NcQ.js → interactive-ChaxKwhe.js} +2 -2
  25. package/dist/{interactive-DCIL3NcQ.js.map → interactive-ChaxKwhe.js.map} +1 -1
  26. package/dist/{mcp-prompt-streaming-BRoVSf3N.js → mcp-prompt-streaming-CNmYvvmk.js} +4 -4
  27. package/dist/{mcp-prompt-streaming-BRoVSf3N.js.map → mcp-prompt-streaming-CNmYvvmk.js.map} +1 -1
  28. package/dist/{non-interactive-u4VG76Vi.js → non-interactive-BM4hUmlI.js} +2 -2
  29. package/dist/{non-interactive-u4VG76Vi.js.map → non-interactive-BM4hUmlI.js.map} +1 -1
  30. package/dist/{package-manager-0M_uIOP0.js → package-manager-l8N6VCPX.js} +2 -2
  31. package/dist/{package-manager-0M_uIOP0.js.map → package-manager-l8N6VCPX.js.map} +1 -1
  32. package/dist/{playground-B6wgUvH-.js → playground-C7SbDVI4.js} +4 -4
  33. package/dist/{playground-B6wgUvH-.js.map → playground-C7SbDVI4.js.map} +1 -1
  34. package/dist/{posthog-integration-C_9G_kTS.js → posthog-integration-YDzQBfhq.js} +13 -14
  35. package/dist/{posthog-integration-C_9G_kTS.js.map → posthog-integration-YDzQBfhq.js.map} +1 -1
  36. package/dist/{provisioning-CgCxuoe6.js → provisioning-ql6mjOVq.js} +3 -3
  37. package/dist/{provisioning-CgCxuoe6.js.map → provisioning-ql6mjOVq.js.map} +1 -1
  38. package/dist/{registry-BgsYtCkS.js → registry-5SphnyxS.js} +4 -4
  39. package/dist/{registry-BgsYtCkS.js.map → registry-5SphnyxS.js.map} +1 -1
  40. package/dist/{setup-utils-DF6EKEeA.js → setup-utils-CoblNeRY.js} +8 -8
  41. package/dist/{setup-utils-DF6EKEeA.js.map → setup-utils-CoblNeRY.js.map} +1 -1
  42. package/dist/{start-tui-Deaj99It.js → start-tui-D_woOYMc.js} +13 -13
  43. package/dist/{start-tui-Deaj99It.js.map → start-tui-D_woOYMc.js.map} +1 -1
  44. package/dist/{steps-AF3ulYYe.js → steps-2gR__rtG.js} +7 -7
  45. package/dist/{steps-AF3ulYYe.js.map → steps-2gR__rtG.js.map} +1 -1
  46. package/dist/{telemetry-DPVvKu5X.js → telemetry-CqysQT5U.js} +3 -3
  47. package/dist/{telemetry-DPVvKu5X.js.map → telemetry-CqysQT5U.js.map} +1 -1
  48. package/dist/{terminal-BVKeWPb3.js → terminal-CeokeMGP.js} +9 -9
  49. package/dist/{terminal-BVKeWPb3.js.map → terminal-CeokeMGP.js.map} +1 -1
  50. package/dist/{urls-Bur7Zb7A.js → urls-BOcViDhS.js} +2 -2
  51. package/dist/{urls-Bur7Zb7A.js.map → urls-BOcViDhS.js.map} +1 -1
  52. package/dist/{wizard-abort-D3vY7K9a.js → wizard-abort-C0siBgn5.js} +1 -1
  53. package/dist/{wizard-abort-D0UMhCP5.js → wizard-abort-DFL5Um-M.js} +3 -3
  54. package/dist/{wizard-abort-D0UMhCP5.js.map → wizard-abort-DFL5Um-M.js.map} +1 -1
  55. package/package.json +16 -52
  56. package/dist/agent-interface-CVW8H9eF.js.map +0 -1
  57. package/dist/agent-runner-VzTpPaVT.js.map +0 -1
  58. package/dist/analytics-DvDjbNmK.js.map +0 -1
  59. package/dist/debug-CMZ7kqW1.js.map +0 -1
package/dist/bin.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"bin.js","names":["getContentBlocks","DOCS_URL","REPORT_FILE","DOCS_URL","getContentBlocks","REPORT_FILE","DOCS_URL","agentSkillContentBlocks","agentSkillContentBlocks","fs","path","path"],"sources":["../src/commands/command.ts","../src/wizard.ts","../src/commands/provision.ts","../src/commands/basic-integration/index.ts","../src/lib/programs/shared/package-scanning.ts","../src/lib/programs/revenue-analytics/detect.ts","../src/lib/programs/revenue-analytics/steps.ts","../src/lib/programs/agent-skill/content/index.tsx","../src/lib/programs/revenue-analytics/index.ts","../src/lib/warehouse-sources/registry.ts","../src/lib/warehouse-sources/detect.ts","../src/lib/programs/warehouse-source/detect.ts","../src/lib/programs/warehouse-source/steps.ts","../src/lib/programs/warehouse-source/index.ts","../src/lib/programs/agent-skill/steps.ts","../src/lib/programs/agent-skill/index.ts","../src/lib/programs/audit/detect.ts","../src/lib/programs/audit/seed.ts","../src/lib/programs/audit/index.ts","../src/lib/programs/events-audit/steps.ts","../src/lib/programs/events-audit/seed.ts","../src/lib/programs/events-audit/index.ts","../src/lib/programs/posthog-doctor/steps.ts","../src/lib/programs/posthog-doctor/types.ts","../src/lib/programs/posthog-doctor/fetch.ts","../src/lib/programs/posthog-doctor/kind-metadata.ts","../src/lib/programs/posthog-doctor/index.ts","../src/lib/programs/web-analytics-doctor/detect.ts","../src/lib/programs/web-analytics-doctor/steps.ts","../src/lib/programs/web-analytics-doctor/index.ts","../src/lib/programs/migration/steps.ts","../src/lib/programs/migration/content/vendor-stack.tsx","../src/lib/programs/migration/content/free-tier.tsx","../src/lib/programs/migration/content/pricing-structure.tsx","../src/lib/programs/migration/content/index.tsx","../src/lib/programs/migration/index.ts","../src/lib/programs/error-tracking-upload-source-maps/detect.ts","../src/lib/programs/error-tracking-upload-source-maps/steps.ts","../src/lib/programs/error-tracking-upload-source-maps/prompt.ts","../src/lib/programs/error-tracking-upload-source-maps/content/index.tsx","../src/lib/programs/error-tracking-upload-source-maps/index.ts","../src/lib/programs/self-driving/detect.ts","../src/lib/programs/self-driving/steps.ts","../src/lib/programs/self-driving/prompt.ts","../src/lib/programs/self-driving/content/tips.ts","../src/lib/programs/self-driving/index.ts","../src/lib/programs/mcp/index.ts","../src/lib/programs/slack/index.ts","../src/lib/programs/program-registry.ts","../src/commands/mcp/add.ts","../src/commands/mcp/remove.ts","../src/commands/mcp/tutorial.ts","../src/commands/mcp/index.ts","../src/lib/runners/resolve-no-telemetry.ts","../src/lib/runners/run-wizard.ts","../src/lib/runners/run-wizard-ci.ts","../src/commands/skill-program-options.ts","../src/commands/factories/shared.ts","../src/lib/programs/dispatch-family.ts","../src/ui/tui/primitives/PromptLabel.tsx","../src/ui/tui/primitives/ConfirmButton.tsx","../src/ui/tui/hooks/keyboard-hints-utils.ts","../src/ui/tui/hooks/useKeyboardHints.tsx","../src/ui/tui/hooks/useKeyBindings.ts","../src/ui/tui/primitives/PickerMenu.tsx","../src/commands/factories/family-picker.tsx","../src/commands/factories/family-command-factory.ts","../src/commands/audit.ts","../src/commands/doctor.ts","../src/commands/factories/native-command-factory.ts","../src/commands/migrate.ts","../src/commands/revenue.ts","../src/commands/warehouse.ts","../src/commands/self-driving.ts","../src/commands/slack.ts","../src/commands/upload-sourcemaps.ts","../src/commands/basic-integration/skill.ts","../src/commands/skill.ts","../src/steps/install-cli-steering/index.ts","../src/commands/cli/add.ts","../src/commands/cli/index.ts","../bin.ts"],"sourcesContent":["import type {\n Arguments,\n Argv,\n CommandModule,\n Options,\n PositionalOptions,\n} from 'yargs';\nimport { setEntryCommand } from '@utils/links';\n\nexport interface Command {\n /** Yargs command name. Use `['$0']` for the default command. */\n name: string | readonly string[];\n description: string;\n /** Flags exposed by this command. Same shape as yargs `.options()`. */\n options?: Record<string, Options>;\n /**\n * Positional arguments declared in `name` (e.g. the `id` in `skill [id]`).\n * Under `.strictOptions()`, yargs only treats a positional as a known\n * argument once it's registered via `.positional()` — a command-string\n * positional alone is rejected as `Unknown argument`. Declare each one here\n * so an optional positional like `skill [id]` actually accepts its value.\n */\n positionals?: Record<string, PositionalOptions>;\n /** Nested subcommands. */\n children?: readonly Command[];\n /** `--help` examples shown for this command. */\n examples?: ReadonlyArray<readonly [string, string]>;\n /**\n * Called synchronously by yargs when the command matches. Wrap async work in\n * `void (async () => { ... })()`. Optional only when `children` is set — in\n * that case yargs requires the user to pick a subcommand (or to set\n * `interactiveDefault` for an in-process picker).\n */\n handler?: (argv: Arguments) => void;\n /**\n * Cross-flag validation run by yargs after parsing. Throw to reject (yargs\n * prints the message and exits non-zero); return `true` to accept. Prefer\n * this over per-option `conflicts` for mutually exclusive flags: yargs\n * counts a `default`-valued flag as \"present\", so `conflicts` misfires on\n * boolean flags that default to `false` — a hand-written predicate only\n * sees what you test for (e.g. truthiness).\n */\n check?: (argv: Arguments) => boolean;\n /**\n * Optional handler invoked when this command has `children` but the user\n * supplied no subcommand. Use it to mount an interactive picker over the\n * children so `wizard audit` (no leaf) opens a TUI menu instead of yargs\n * help. When set, suppresses the implicit `demandCommand(1)`.\n *\n * May return a Promise — yargs awaits the result before exiting.\n */\n interactiveDefault?: (argv: Arguments) => void | Promise<void>;\n /**\n * When true, this child is the \"default\" leaf in its family: the\n * family picker pre-highlights it so a single Enter runs it. The picker\n * still always opens — this never auto-runs the child. At most one child\n * per parent should be marked. Propagated from the context-mill manifest\n * entry's `default` flag through `skillCommandFactory`.\n */\n default?: boolean;\n}\n\n/** Extract the bare command word(s) from a yargs name spec, dropping positionals and aliases' arg syntax. */\nexport function commandKeys(name: string | readonly string[]): string[] {\n const list: readonly string[] = typeof name === 'string' ? [name] : name;\n return list.map((n) => n.trim().split(/\\s+/)[0]);\n}\n\nexport function toCommandModule(\n cmd: Command,\n parentPath: readonly string[],\n): CommandModule {\n // `wizard slack` → 'slack', `wizard mcp add` → 'mcp-add'. The default\n // `$0` resolves to '' and is skipped — its handler reports itself.\n const entryCommand = [...parentPath, commandKeys(cmd.name)[0]]\n .filter((key) => key !== '$0')\n .join('-');\n return {\n command: cmd.name,\n describe: cmd.description,\n builder: (y: Argv) => {\n let next = cmd.options ? y.options(cmd.options) : y;\n for (const [key, opts] of Object.entries(cmd.positionals ?? {})) {\n next = next.positional(key, opts);\n }\n if (cmd.check) next = next.check(cmd.check);\n for (const [usage, description] of cmd.examples ?? []) {\n next = next.example(usage, description);\n }\n const ownPath = [...parentPath, commandKeys(cmd.name)[0]];\n for (const child of cmd.children ?? []) {\n next = next.command(toCommandModule(child, ownPath));\n }\n if (cmd.children?.length && !cmd.handler && !cmd.interactiveDefault) {\n next = next.demandCommand(1);\n }\n return next;\n },\n handler: (argv: Arguments) => {\n if (entryCommand) setEntryCommand(entryCommand);\n const run = cmd.handler ?? cmd.interactiveDefault ?? (() => undefined);\n run(argv);\n },\n };\n}\n","import yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport type { Argv } from 'yargs';\nimport { IS_PRODUCTION_BUILD } from '@env';\nimport { toCommandModule, type Command } from './commands/command';\n\n/**\n * Global yargs options applied to every command. These are read from the\n * `POSTHOG_WIZARD` env prefix as well as flags.\n *\n * Options with `hidden: true` are \"internal modes\" — they don't show up in\n * `--help` but are still accepted on every command. The catalog of internal\n * flags and what each one does lives in CONTRIBUTING.md.\n */\nexport const GLOBAL_OPTIONS = {\n debug: {\n default: false,\n describe: 'Enable verbose logging\\nenv: POSTHOG_WIZARD_DEBUG',\n type: 'boolean' as const,\n },\n region: {\n describe: 'PostHog cloud region\\nenv: POSTHOG_WIZARD_REGION',\n choices: ['us', 'eu'] as const,\n type: 'string' as const,\n },\n signup: {\n default: false,\n describe:\n 'Create a new PostHog account during setup\\nenv: POSTHOG_WIZARD_SIGNUP',\n type: 'boolean' as const,\n },\n telemetry: {\n default: true,\n describe:\n 'Send wizard run state to PostHog (pass --no-telemetry to disable)\\nenv: POSTHOG_WIZARD_TELEMETRY',\n type: 'boolean' as const,\n },\n 'api-key': {\n describe:\n 'PostHog personal API key (phx_xxx) for authentication\\nenv: POSTHOG_WIZARD_API_KEY',\n type: 'string' as const,\n },\n 'project-id': {\n describe:\n 'PostHog project ID to use (optional; when not set, uses default from API key or OAuth)\\nenv: POSTHOG_WIZARD_PROJECT_ID',\n type: 'string' as const,\n },\n email: {\n describe:\n 'Email address for signup (used with --signup)\\nenv: POSTHOG_WIZARD_EMAIL',\n type: 'string' as const,\n },\n // ── Internal modes ─────────────────────────────────────────────────\n // Hidden from `--help`. See CONTRIBUTING.md for what each one does.\n 'local-mcp': {\n default: false,\n describe:\n 'Use local MCP server at http://localhost:8787/mcp\\nenv: POSTHOG_WIZARD_LOCAL_MCP',\n type: 'boolean' as const,\n hidden: true,\n },\n benchmark: {\n default: false,\n describe:\n 'Run in benchmark mode with per-phase token tracking\\nenv: POSTHOG_WIZARD_BENCHMARK',\n type: 'boolean' as const,\n hidden: true,\n },\n 'yara-report': {\n default: false,\n describe:\n 'Print YARA scanner summary after the agent run\\nenv: POSTHOG_WIZARD_YARA_REPORT',\n type: 'boolean' as const,\n hidden: true,\n },\n};\n\nexport class Wizard {\n private cli: Argv;\n\n private constructor() {\n let cli = yargs(hideBin(process.argv))\n .env('POSTHOG_WIZARD')\n .options(GLOBAL_OPTIONS);\n\n // CI mode (--ci) is only supported in dev/test. It is left undeclared in\n // published builds (NODE_ENV==='production'), so .strictOptions() rejects\n // it there as an unknown argument — exactly like any other unrecognized\n // flag. init() additionally detects it up front to print a clearer message.\n if (!IS_PRODUCTION_BUILD) {\n cli = cli.option('ci', {\n default: false,\n describe:\n 'Enable CI mode for non-interactive execution\\nenv: POSTHOG_WIZARD_CI',\n type: 'boolean',\n hidden: true,\n });\n }\n\n this.cli = cli\n .strictOptions()\n // Reject unrecognized commands (e.g. `wizard bogus`) instead of letting\n // them fall through to the default `$0` integration flow.\n .strictCommands()\n // Print a concise error and point to `--help`, instead of yargs' default\n // of dumping the entire usage screen under every failure.\n .fail((msg, err) => {\n const text = msg || (err && err.message) || 'Invalid arguments';\n process.stderr.write(\n `\\n\\x1b[1;91m✖ ${text}\\x1b[0m\\n` +\n ` Run \\`wizard --help\\` to see available commands and options.\\n\\n`,\n );\n process.exit(1);\n })\n .help()\n .alias('help', 'h')\n .version()\n .alias('version', 'v');\n }\n\n /** Start a chain; equivalent to `new Wizard().use(...cmds)`. */\n static use(...cmds: Command[]): Wizard {\n return new Wizard().use(...cmds);\n }\n\n /** Register one or more commands with yargs. */\n use(...cmds: Command[]): this {\n for (const cmd of cmds) {\n this.cli = this.cli.command(toCommandModule(cmd, []));\n }\n return this;\n }\n\n /** Parse argv and dispatch to the matching registered command. */\n init(): void {\n // In published builds, `--ci` is undeclared, so yargs would reject it as\n // an unknown argument — accurate but unhelpful, since --help doesn't list\n // --ci either and the user has no path forward. POSTHOG_WIZARD_CI silently\n // no-ops for the same reason (yargs only resolves env vars for declared\n // options). Detect both up front and exit with a message that explains why.\n if (IS_PRODUCTION_BUILD) {\n const args = process.argv.slice(2);\n const argvHasCI = args.some(\n (a) => a === '--ci' || a === '--no-ci' || a.startsWith('--ci='),\n );\n const envHasCI =\n process.env.POSTHOG_WIZARD_CI != null &&\n process.env.POSTHOG_WIZARD_CI !== '';\n if (argvHasCI || envHasCI) {\n process.stderr.write(\n `\\n\\x1b[1;91m✖ CI mode is not currently supported in published builds.\\x1b[0m\\n\\n`,\n );\n process.exit(1);\n }\n }\n void this.cli.wrap(process.stdout.isTTY ? this.cli.terminalWidth() : 80)\n .argv;\n }\n}\n","import type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport type { ProvisioningResult } from '@utils/provisioning';\nimport type { Command } from './command';\n\nexport const provisionCommand: Command = {\n name: 'provision',\n description: 'Create a new PostHog account (headless, no TUI)',\n options: {\n email: {\n describe: 'Email address for the new account',\n type: 'string',\n demandOption: true,\n },\n region: {\n describe: 'Cloud region (us or eu)',\n choices: ['us', 'eu'] as const,\n default: 'us',\n },\n name: {\n describe: 'Name for the new account',\n type: 'string',\n default: '',\n },\n json: {\n describe:\n 'Emit JSON result to stdout (defaults to true when stdout is not a TTY)',\n type: 'boolean',\n },\n },\n examples: [\n ['wizard provision --email matt+test@posthog.com --region us', ''],\n ['wizard provision --email user@example.com --region eu --json', ''],\n ],\n handler: runProvision,\n};\n\nfunction runProvision(argv: Arguments): void {\n const jsonMode =\n argv.json === undefined ? !process.stdout.isTTY : Boolean(argv.json);\n if (!jsonMode) setUI(new LoggingUI());\n\n void provision({\n email: argv.email as string,\n region: (argv.region as string).toUpperCase() as 'US' | 'EU',\n name: (argv.name as string) ?? '',\n jsonMode,\n });\n}\n\ntype ProvisionArgs = {\n email: string;\n region: 'US' | 'EU';\n name: string;\n jsonMode: boolean;\n};\n\nasync function provision({\n email,\n region,\n name,\n jsonMode,\n}: ProvisionArgs): Promise<void> {\n try {\n const { provisionNewAccount } = await import('@utils/provisioning');\n if (!jsonMode) {\n getUI().log.info(`Provisioning account for ${email} in ${region}...`);\n }\n const result = await provisionNewAccount(email, name, region);\n emitResult(result, jsonMode);\n process.exit(0);\n } catch (error) {\n emitError(error, jsonMode);\n process.exit(1);\n }\n}\n\nfunction emitResult(result: ProvisioningResult, jsonMode: boolean): void {\n if (jsonMode) {\n process.stdout.write(`${JSON.stringify(result)}\\n`);\n return;\n }\n getUI().log.success('Account provisioned successfully:');\n getUI().log.info(` API Key: ${result.projectApiKey}`);\n getUI().log.info(` Host: ${result.host}`);\n getUI().log.info(` Project ID: ${result.projectId}`);\n getUI().log.info(` Account ID: ${result.accountId}`);\n getUI().log.info(` Access Token: ${result.accessToken}`);\n getUI().log.info(` Refresh Token: ${result.refreshToken}`);\n if (result.personalApiKey) {\n getUI().log.info(` Personal API Key: ${result.personalApiKey}`);\n }\n}\n\nfunction emitError(error: unknown, jsonMode: boolean): void {\n const msg = error instanceof Error ? error.message : String(error);\n const code = msg.includes('already associated')\n ? 'email_exists'\n : 'provisioning_failed';\n if (jsonMode) {\n process.stderr.write(`${JSON.stringify({ error: msg, code })}\\n`);\n return;\n }\n getUI().log.error(`Provisioning failed: ${msg}`);\n}\n","import { isNonInteractiveEnvironment } from '@utils/environment';\nimport { setEntryCommand } from '@utils/links';\nimport { provisionCommand } from '../provision';\nimport type { Command } from '../command';\n\nexport const basicIntegrationCommand: Command = {\n name: ['$0'],\n description: 'Run the PostHog setup wizard',\n // provision is a one-shot HTTP call tied to the base flow, not a wizard\n // program — it rides under the base command rather than as a peer.\n children: [provisionCommand],\n options: {\n 'install-dir': {\n describe:\n 'Directory to install PostHog in\\nenv: POSTHOG_WIZARD_INSTALL_DIR',\n type: 'string',\n },\n name: {\n describe:\n 'Name for account creation with --ci --signup\\nenv: POSTHOG_WIZARD_NAME',\n type: 'string',\n },\n // ── Internal modes ───────────────────────────────────────────────\n // Hidden from `--help`. See CONTRIBUTING.md for what each one does.\n playground: {\n default: false,\n describe: 'Launch the TUI primitives playground',\n type: 'boolean',\n hidden: true,\n },\n },\n check: (argv) => {\n // --playground is the standalone TUI demo; it can't combine with --ci.\n if (argv.playground && argv.ci) {\n throw new Error('--playground cannot be combined with --ci.');\n }\n return true;\n },\n handler: (argv) => {\n // The bare run is the integrate flow.\n setEntryCommand('integrate');\n // Each mode file is loaded only when its branch is taken, so a plain\n // `npx @posthog/wizard` never pulls in the CI or playground paths.\n void (async () => {\n if (argv.ci) {\n const { runCIInstall } = await import('./ci-install');\n return runCIInstall(argv);\n }\n if (isNonInteractiveEnvironment()) {\n const { failNonInteractive } = await import('./non-interactive');\n return failNonInteractive();\n }\n if (argv.playground) {\n const { runPlayground } = await import('./playground');\n return runPlayground();\n }\n const { runInteractive } = await import('./interactive');\n runInteractive(argv);\n })();\n },\n};\n","import type { Dirent } from 'fs';\nimport { readFileSync, readdirSync } from 'fs';\nimport { join, relative } from 'path';\nimport { IGNORED_DIRS } from '@utils/file-utils';\n\nexport const POSTHOG_SDKS = [\n 'posthog-js',\n 'posthog-node',\n 'posthog-react-native',\n 'posthog-android',\n 'posthog-ios',\n];\n\nexport const STRIPE_SDKS = [\n 'stripe',\n '@stripe/stripe-js',\n '@stripe/react-stripe-js',\n];\n\nexport interface PackageMatch {\n /** Path to the package.json relative to installDir */\n path: string;\n posthogSdks: string[];\n stripeSdks: string[];\n}\n\n/**\n * Recursively find all package.json files under installDir (max depth 3),\n * skipping common ignored directories. Returns matches with detected SDKs.\n */\nexport function findPackageJsons(\n installDir: string,\n maxDepth = 3,\n): PackageMatch[] {\n const matches: PackageMatch[] = [];\n\n function scan(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') && entry.name !== '.') continue;\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = join(dir, entry.name);\n\n if (entry.isFile() && entry.name === 'package.json') {\n try {\n const pkg = JSON.parse(readFileSync(fullPath, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const depNames = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n const posthogSdks = depNames.filter((d) => POSTHOG_SDKS.includes(d));\n const stripeSdks = depNames.filter((d) => STRIPE_SDKS.includes(d));\n matches.push({\n path: relative(installDir, fullPath) || 'package.json',\n posthogSdks,\n stripeSdks,\n });\n } catch {\n // Skip malformed package.json\n }\n } else if (entry.isDirectory()) {\n scan(fullPath, depth + 1);\n }\n }\n }\n\n scan(installDir, 0);\n return matches;\n}\n","/**\n * Revenue analytics prerequisite detection.\n *\n * Scans the project for PostHog + Stripe SDKs and writes results\n * into frameworkContext for the intro screen to render.\n */\n\nimport { existsSync, statSync } from 'fs';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\nimport { findPackageJsons } from '@lib/programs/shared/package-scanning';\n\nexport {\n findPackageJsons,\n POSTHOG_SDKS,\n STRIPE_SDKS,\n type PackageMatch,\n} from '@lib/programs/shared/package-scanning';\n\n/**\n * Structured detection errors. The screen renders each kind into JSX\n * with proper formatting — keeps error data separate from presentation.\n */\nexport type RevenueDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-package-json' }\n | { kind: 'no-sdks'; scannedCount: number }\n | { kind: 'missing-posthog'; foundStripe: string[] }\n | { kind: 'missing-stripe'; foundPosthog: string[] };\n\n/** `[ABORT] <reason>` cases the revenue analytics skill can emit. */\nexport const REVENUE_ABORT_CASES: AbortCase[] = [\n {\n // Skill emits: [ABORT] Could not find a PostHog distinct_id\n match: /^could not find a posthog distinct_id$/i,\n message: 'Could not find a PostHog distinct_id',\n body:\n 'The agent could not find PostHog distinct_id usage in your codebase. ' +\n 'Your users must be identified in PostHog before they can be tagged in Stripe. ' +\n 'Please identify your users and try again.',\n docsUrl: 'https://posthog.com/docs/product-analytics/identify',\n },\n {\n // Skill emits: [ABORT] Could not find a Stripe integration\n match: /^could not find a stripe integration$/i,\n message: 'Could not find a Stripe integration',\n body:\n 'The Wizard could not find an existing Stripe customer, charge, ' +\n 'subscription, or other Stripe operations. Please run the Revenue ' +\n 'Analytics Wizard on a project with an existing Stripe integration.',\n docsUrl: 'https://posthog.com/docs/revenue-analytics',\n },\n];\n\n/**\n * Scan `session.installDir` for PostHog + Stripe SDKs. Writes detection\n * results into frameworkContext via the callback — either the detected\n * SDK lists (for the intro screen) or a `RevenueDetectError` on failure.\n *\n * The skill install happens later in the bootstrap runner, not here.\n */\nexport function detectRevenuePrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: RevenueDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n // Verify the install directory exists and is readable\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n // Find all package.json files (root + monorepo subpackages)\n const matches = findPackageJsons(installDir);\n\n if (matches.length === 0) {\n fail({ kind: 'no-package-json' });\n return;\n }\n\n // Aggregate detected SDKs across all package.json files\n const allPosthogSdks = new Set<string>();\n const allStripeSdks = new Set<string>();\n for (const match of matches) {\n for (const sdk of match.posthogSdks) allPosthogSdks.add(sdk);\n for (const sdk of match.stripeSdks) allStripeSdks.add(sdk);\n }\n\n const detectedPosthogSdks = [...allPosthogSdks];\n const detectedStripeSdks = [...allStripeSdks];\n\n if (detectedPosthogSdks.length === 0 && detectedStripeSdks.length === 0) {\n fail({ kind: 'no-sdks', scannedCount: matches.length });\n return;\n }\n\n if (detectedPosthogSdks.length === 0) {\n fail({ kind: 'missing-posthog', foundStripe: detectedStripeSdks });\n return;\n }\n\n if (detectedStripeSdks.length === 0) {\n fail({ kind: 'missing-stripe', foundPosthog: detectedPosthogSdks });\n return;\n }\n\n setFrameworkContext('detectedPosthogSdks', detectedPosthogSdks);\n setFrameworkContext('detectedStripeSdks', detectedStripeSdks);\n setFrameworkContext(\n 'detectedPackagePaths',\n matches\n .filter((m) => m.posthogSdks.length > 0 || m.stripeSdks.length > 0)\n .map((m) => m.path),\n );\n}\n","/**\n * Revenue analytics program step list.\n *\n * The detect step checks for PostHog + Stripe SDKs. The skill install\n * and agent run live in the program runner (see agent-runner.ts).\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\nimport { detectRevenuePrerequisites } from './detect.js';\n\nexport const REVENUE_ANALYTICS_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting prerequisites',\n // Headless step: no screen, no gate. onReady fires after bin.ts\n // assigns the session — the hook scans for PostHog + Stripe SDKs\n // and writes the results (or a detectError) to frameworkContext\n // for the intro screen to render.\n onReady: (ctx) =>\n detectRevenuePrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'revenue-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Revenue analytics',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","/**\n * Agent-skill learn-deck — the short three-line sequence shown while a\n * skill-based program (audit, revenue-analytics, agent-skill, etc.)\n * runs. Skill programs don't need the full PostHog onboarding narrative.\n */\n\nimport { Text } from 'ink';\nimport type { WizardStore } from '@ui/tui/store';\nimport { TextRevealMode } from '@ui/tui/primitives/TextBlock';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const getContentBlocks = (store?: WizardStore): ContentBlock[] => {\n const skillId = store?.session.skillId ?? 'unknown';\n return [\n {\n content: 'Welcome.',\n pause: 3000,\n mode: TextRevealMode.Typewriter,\n animationInterval: 160,\n },\n { content: 'The Wizard is an agent.', pause: 4000 },\n {\n pause: 60000,\n content: (\n <Text>\n Running the <Text color=\"cyan\">{skillId}</Text> skill...\n </Text>\n ),\n },\n ];\n};\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { REVENUE_ANALYTICS_PROGRAM } from './steps.js';\nimport { REVENUE_ABORT_CASES } from './detect.js';\nimport { getContentBlocks } from './content/index.js';\n\nexport const revenueAnalyticsConfig: ProgramConfig = {\n command: 'revenue-analytics',\n description: 'Set up PostHog revenue analytics (e.g. Stripe integration)',\n id: 'revenue-analytics-setup',\n skillId: 'revenue-analytics-setup',\n steps: REVENUE_ANALYTICS_PROGRAM,\n getContentBlocks,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n run: {\n skillId: 'revenue-analytics-setup',\n integrationLabel: 'revenue-analytics-setup',\n customPrompt: () => 'Set up revenue analytics for this project.',\n successMessage: 'Revenue analytics configured!',\n reportFile: 'posthog-revenue-report.md',\n docsUrl: 'https://posthog.com/docs/revenue-analytics',\n spinnerMessage: 'Setting up revenue analytics...',\n estimatedDurationMinutes: 5,\n abortCases: REVENUE_ABORT_CASES,\n },\n requires: ['posthog-integration'],\n};\n\nexport { REVENUE_ANALYTICS_PROGRAM } from './steps.js';\nexport {\n detectRevenuePrerequisites,\n POSTHOG_SDKS,\n STRIPE_SDKS,\n type RevenueDetectError,\n} from './detect.js';\n","/**\n * Registry of data warehouse source detectors.\n *\n * Each entry maps a codebase footprint to a PostHog source `kind`. The `kind`\n * strings are validated against the MCP `external-data-sources-wizard` tool —\n * keep them in sync with PostHog's released source types.\n *\n * `in-cli` sources are created from the terminal (databases + API-key SaaS).\n * `deep-link` sources have no safe terminal credential path (OAuth) but a\n * codebase footprint worth nudging the user about — we open the app instead.\n */\n\nimport type { SourceDetector } from './types.js';\n\nexport const SOURCE_DETECTORS: SourceDetector[] = [\n {\n kind: 'Postgres',\n label: 'PostgreSQL',\n mode: 'in-cli',\n signals: {\n npm: ['pg', 'postgres', 'postgres.js', 'knex', 'sequelize'],\n python: ['psycopg', 'psycopg2', 'psycopg2-binary', 'asyncpg'],\n ruby: ['pg'],\n envKeys: [\n // NOTE: DATABASE_URL is ambiguous — MySQL/SQLite projects (Prisma,\n // Rails) use it too. We only read key NAMES, not the scheme, so this\n // is a deliberate precision/recall tradeoff biased toward the most\n // common convention (DATABASE_URL → Postgres).\n /^DATABASE_URL$/,\n /^POSTGRES_/,\n /^PG(HOST|DATABASE|USER|PORT)$/,\n ],\n },\n },\n {\n kind: 'MySQL',\n label: 'MySQL',\n mode: 'in-cli',\n signals: {\n npm: ['mysql', 'mysql2'],\n python: ['pymysql', 'mysqlclient', 'mysql-connector-python'],\n ruby: ['mysql2'],\n envKeys: [/^MYSQL_/],\n },\n },\n {\n kind: 'MongoDB',\n label: 'MongoDB',\n mode: 'in-cli',\n signals: {\n npm: ['mongodb', 'mongoose'],\n python: ['pymongo', 'motor'],\n ruby: ['mongo', 'mongoid'],\n // Matches both MONGO_* and MONGODB_* prefixes (e.g. MONGO_HOST,\n // MONGODB_URI) in one pattern.\n envKeys: [/^MONGO(DB)?_/],\n },\n },\n {\n kind: 'Snowflake',\n label: 'Snowflake',\n mode: 'in-cli',\n signals: {\n npm: ['snowflake-sdk'],\n python: ['snowflake-connector-python', 'snowflake-sqlalchemy'],\n envKeys: [/^SNOWFLAKE_/],\n },\n },\n {\n kind: 'BigQuery',\n label: 'BigQuery',\n mode: 'in-cli',\n signals: {\n npm: ['@google-cloud/bigquery'],\n python: ['google-cloud-bigquery'],\n envKeys: [/^BIGQUERY_/],\n },\n },\n {\n kind: 'Redshift',\n label: 'Redshift',\n mode: 'in-cli',\n signals: {\n npm: ['node-redshift'],\n python: ['redshift-connector'],\n envKeys: [/^REDSHIFT_/],\n },\n },\n {\n kind: 'MSSQL',\n label: 'SQL Server',\n mode: 'in-cli',\n signals: {\n npm: ['mssql', 'tedious'],\n python: ['pyodbc', 'pymssql'],\n envKeys: [/^MSSQL_/],\n },\n },\n {\n kind: 'Supabase',\n label: 'Supabase',\n mode: 'in-cli',\n signals: {\n npm: ['@supabase/supabase-js'],\n python: ['supabase'],\n envKeys: [/^SUPABASE_/],\n },\n },\n {\n kind: 'ClickHouse',\n label: 'ClickHouse',\n mode: 'in-cli',\n signals: {\n npm: ['@clickhouse/client'],\n python: ['clickhouse-connect', 'clickhouse-driver'],\n envKeys: [/^CLICKHOUSE_/],\n },\n },\n {\n kind: 'Convex',\n label: 'Convex',\n mode: 'in-cli',\n signals: {\n npm: ['convex'],\n python: ['convex'],\n envKeys: [/^CONVEX_/, /^NEXT_PUBLIC_CONVEX_URL$/],\n },\n },\n {\n kind: 'Stripe',\n label: 'Stripe',\n mode: 'in-cli',\n signals: {\n npm: ['stripe', '@stripe/stripe-js', '@stripe/react-stripe-js'],\n python: ['stripe'],\n ruby: ['stripe'],\n envKeys: [/^STRIPE_(SECRET|API)_KEY$/],\n },\n },\n {\n kind: 'Clerk',\n label: 'Clerk',\n mode: 'in-cli',\n signals: {\n npm: [\n '@clerk/nextjs',\n '@clerk/clerk-react',\n '@clerk/backend',\n '@clerk/express',\n '@clerk/fastify',\n '@clerk/remix',\n ],\n envKeys: [/^CLERK_SECRET_KEY$/, /^NEXT_PUBLIC_CLERK_/],\n },\n },\n {\n kind: 'Resend',\n label: 'Resend',\n mode: 'in-cli',\n signals: {\n npm: ['resend'],\n python: ['resend'],\n envKeys: [/^RESEND_API_KEY$/],\n },\n },\n {\n kind: 'Shopify',\n label: 'Shopify',\n mode: 'in-cli',\n signals: {\n npm: ['@shopify/shopify-api', 'shopify-api-node'],\n python: ['shopifyapi'],\n envKeys: [/^SHOPIFY_/],\n },\n },\n {\n kind: 'Klaviyo',\n label: 'Klaviyo',\n mode: 'in-cli',\n signals: {\n npm: ['klaviyo-api'],\n python: ['klaviyo-api'],\n envKeys: [/^KLAVIYO_/],\n },\n },\n {\n kind: 'Chargebee',\n label: 'Chargebee',\n mode: 'in-cli',\n signals: {\n npm: ['chargebee'],\n python: ['chargebee'],\n envKeys: [/^CHARGEBEE_/],\n },\n },\n {\n kind: 'Paddle',\n label: 'Paddle',\n mode: 'in-cli',\n signals: {\n npm: ['@paddle/paddle-node-sdk', '@paddle/paddle-js'],\n envKeys: [/^PADDLE_/],\n },\n },\n {\n kind: 'Polar',\n label: 'Polar',\n mode: 'in-cli',\n signals: {\n npm: ['@polar-sh/sdk', '@polar-sh/nextjs'],\n envKeys: [/^POLAR_/],\n },\n },\n {\n kind: 'Mailchimp',\n label: 'Mailchimp',\n mode: 'in-cli',\n signals: {\n npm: ['@mailchimp/mailchimp_marketing'],\n python: ['mailchimp-marketing'],\n envKeys: [/^MAILCHIMP_/],\n },\n },\n {\n kind: 'CustomerIO',\n label: 'Customer.io',\n mode: 'in-cli',\n signals: {\n npm: ['customerio-node'],\n python: ['customerio'],\n envKeys: [/^CUSTOMER_?IO_/],\n },\n },\n {\n kind: 'Typeform',\n label: 'Typeform',\n mode: 'in-cli',\n signals: {\n npm: ['@typeform/api-client'],\n envKeys: [/^TYPEFORM_/],\n },\n },\n {\n kind: 'Sentry',\n label: 'Sentry',\n mode: 'in-cli',\n signals: {\n npm: [\n '@sentry/node',\n '@sentry/browser',\n '@sentry/react',\n '@sentry/nextjs',\n ],\n python: ['sentry-sdk'],\n ruby: ['sentry-ruby'],\n },\n },\n {\n kind: 'Plaid',\n label: 'Plaid',\n mode: 'in-cli',\n signals: {\n npm: ['plaid'],\n python: ['plaid-python', 'plaid'],\n ruby: ['plaid'],\n envKeys: [/^PLAID_/],\n },\n },\n {\n kind: 'Braintree',\n label: 'Braintree',\n mode: 'in-cli',\n signals: {\n npm: ['braintree'],\n python: ['braintree'],\n ruby: ['braintree'],\n envKeys: [/^BRAINTREE_/],\n },\n },\n {\n kind: 'Square',\n label: 'Square',\n mode: 'in-cli',\n signals: {\n npm: ['square'],\n python: ['squareup'],\n ruby: ['square'],\n envKeys: [/^SQUARE_/],\n },\n },\n {\n kind: 'GoCardless',\n label: 'GoCardless',\n mode: 'in-cli',\n signals: {\n npm: ['gocardless-nodejs'],\n python: ['gocardless-pro'],\n ruby: ['gocardless_pro'],\n envKeys: [/^GOCARDLESS_/],\n },\n },\n {\n kind: 'Mollie',\n label: 'Mollie',\n mode: 'in-cli',\n signals: {\n npm: ['@mollie/api-client'],\n python: ['mollie-api-python'],\n envKeys: [/^MOLLIE_/],\n },\n },\n {\n kind: 'CheckoutCom',\n label: 'Checkout.com',\n mode: 'in-cli',\n signals: {\n npm: ['checkout-sdk-node'],\n python: ['checkout-sdk'],\n // Checkout.com's own convention is the CKO_ prefix.\n envKeys: [/^CKO_/, /^CHECKOUT_COM_/],\n },\n },\n {\n kind: 'Recurly',\n label: 'Recurly',\n mode: 'in-cli',\n signals: {\n npm: ['recurly'],\n python: ['recurly'],\n ruby: ['recurly'],\n envKeys: [/^RECURLY_/],\n },\n },\n {\n kind: 'RevenueCat',\n label: 'RevenueCat',\n mode: 'in-cli',\n signals: {\n npm: [\n '@revenuecat/purchases-js',\n 'react-native-purchases',\n '@revenuecat/purchases-capacitor',\n ],\n envKeys: [/^REVENUE_?CAT_/],\n },\n },\n {\n kind: 'Twilio',\n label: 'Twilio',\n mode: 'in-cli',\n signals: {\n npm: ['twilio'],\n python: ['twilio'],\n ruby: ['twilio-ruby'],\n envKeys: [/^TWILIO_/],\n },\n },\n {\n kind: 'SendGrid',\n label: 'SendGrid',\n mode: 'in-cli',\n signals: {\n npm: ['@sendgrid/mail', '@sendgrid/client'],\n python: ['sendgrid'],\n ruby: ['sendgrid-ruby'],\n envKeys: [/^SENDGRID_/],\n },\n },\n {\n kind: 'Mailgun',\n label: 'Mailgun',\n mode: 'in-cli',\n signals: {\n npm: ['mailgun.js', 'mailgun-js'],\n python: ['mailgun'],\n ruby: ['mailgun-ruby'],\n envKeys: [/^MAILGUN_/],\n },\n },\n {\n kind: 'Postmark',\n label: 'Postmark',\n mode: 'in-cli',\n signals: {\n npm: ['postmark'],\n python: ['postmarker'],\n ruby: ['postmark'],\n envKeys: [/^POSTMARK_/],\n },\n },\n {\n kind: 'Brevo',\n label: 'Brevo',\n mode: 'in-cli',\n signals: {\n npm: ['@getbrevo/brevo', 'sib-api-v3-sdk'],\n python: ['sib-api-v3-sdk'],\n envKeys: [/^BREVO_/],\n },\n },\n {\n kind: 'MailerLite',\n label: 'MailerLite',\n mode: 'in-cli',\n signals: {\n npm: ['@mailerlite/mailerlite-nodejs'],\n python: ['mailerlite'],\n envKeys: [/^MAILERLITE_/],\n },\n },\n {\n kind: 'Mailjet',\n label: 'Mailjet',\n mode: 'in-cli',\n signals: {\n npm: ['node-mailjet'],\n python: ['mailjet-rest'],\n // Mailjet's documented env convention is MJ_APIKEY_PUBLIC / *_PRIVATE.\n envKeys: [/^MAILJET_/, /^MJ_APIKEY_/],\n },\n },\n {\n kind: 'LaunchDarkly',\n label: 'LaunchDarkly',\n mode: 'in-cli',\n signals: {\n npm: [\n 'launchdarkly-node-server-sdk',\n '@launchdarkly/node-server-sdk',\n 'launchdarkly-js-client-sdk',\n 'launchdarkly-react-client-sdk',\n ],\n python: ['launchdarkly-server-sdk'],\n ruby: ['launchdarkly-server-sdk'],\n envKeys: [/^LAUNCHDARKLY_/, /^LD_SDK_KEY$/],\n },\n },\n {\n kind: 'Optimizely',\n label: 'Optimizely',\n mode: 'in-cli',\n signals: {\n npm: ['@optimizely/optimizely-sdk'],\n python: ['optimizely-sdk'],\n envKeys: [/^OPTIMIZELY_/],\n },\n },\n {\n kind: 'Braze',\n label: 'Braze',\n mode: 'in-cli',\n signals: {\n npm: ['@braze/web-sdk', '@braze/react-native-sdk'],\n python: ['braze-client'],\n envKeys: [/^BRAZE_/],\n },\n },\n {\n kind: 'Rollbar',\n label: 'Rollbar',\n mode: 'in-cli',\n signals: {\n npm: ['rollbar'],\n python: ['rollbar', 'pyrollbar'],\n ruby: ['rollbar'],\n envKeys: [/^ROLLBAR_/],\n },\n },\n {\n kind: 'Okta',\n label: 'Okta',\n mode: 'in-cli',\n signals: {\n npm: ['@okta/okta-sdk-nodejs', '@okta/okta-auth-js', '@okta/okta-react'],\n python: ['okta'],\n envKeys: [/^OKTA_/],\n },\n },\n {\n kind: 'WorkOS',\n label: 'WorkOS',\n mode: 'in-cli',\n signals: {\n npm: ['@workos-inc/node'],\n python: ['workos'],\n envKeys: [/^WORKOS_/],\n },\n },\n {\n kind: 'Notion',\n label: 'Notion',\n mode: 'in-cli',\n signals: {\n npm: ['@notionhq/client'],\n python: ['notion-client'],\n envKeys: [/^NOTION_/],\n },\n },\n {\n kind: 'FullStory',\n label: 'FullStory',\n mode: 'in-cli',\n signals: {\n npm: ['@fullstory/browser', '@fullstory/react-native'],\n envKeys: [/^FULLSTORY_/],\n },\n },\n {\n kind: 'Amplitude',\n label: 'Amplitude',\n mode: 'in-cli',\n signals: {\n npm: [\n '@amplitude/analytics-browser',\n '@amplitude/analytics-node',\n '@amplitude/analytics-react-native',\n 'amplitude-js',\n ],\n python: ['amplitude-analytics'],\n envKeys: [/^AMPLITUDE_/],\n },\n },\n {\n kind: 'Mixpanel',\n label: 'Mixpanel',\n mode: 'in-cli',\n signals: {\n npm: ['mixpanel', 'mixpanel-browser'],\n python: ['mixpanel'],\n ruby: ['mixpanel-ruby'],\n envKeys: [/^MIXPANEL_/],\n },\n },\n {\n kind: 'Pendo',\n label: 'Pendo',\n mode: 'in-cli',\n signals: {\n npm: ['@pendo/agent'],\n envKeys: [/^PENDO_/],\n },\n },\n {\n kind: 'Salesforce',\n label: 'Salesforce',\n mode: 'deep-link',\n signals: {\n npm: ['jsforce'],\n python: ['simple-salesforce'],\n envKeys: [/^SALESFORCE_/],\n },\n },\n {\n kind: 'Hubspot',\n label: 'HubSpot',\n mode: 'deep-link',\n signals: {\n npm: ['@hubspot/api-client'],\n python: ['hubspot-api-client'],\n envKeys: [/^HUBSPOT_/],\n },\n },\n {\n kind: 'Zendesk',\n label: 'Zendesk',\n mode: 'deep-link',\n signals: {\n npm: ['node-zendesk'],\n python: ['zenpy'],\n envKeys: [/^ZENDESK_/],\n },\n },\n {\n kind: 'Intercom',\n label: 'Intercom',\n mode: 'deep-link',\n signals: {\n npm: ['intercom-client', '@intercom/messenger-js-sdk'],\n python: ['python-intercom'],\n envKeys: [/^INTERCOM_/],\n },\n },\n {\n kind: 'Linear',\n label: 'Linear',\n mode: 'deep-link',\n signals: {\n npm: ['@linear/sdk'],\n envKeys: [/^LINEAR_API_KEY$/],\n },\n },\n {\n // OAuth-only in PostHog (Slack app integration), so deep-link.\n kind: 'Slack',\n label: 'Slack',\n mode: 'deep-link',\n signals: {\n npm: ['@slack/web-api', '@slack/bolt'],\n python: ['slack-sdk', 'slack-bolt'],\n envKeys: [/^SLACK_(BOT|APP|SIGNING|CLIENT)_/],\n },\n },\n {\n // 'Github' (not 'GitHub') — matches the ExternalDataSourceType value.\n // Default auth is the GitHub App integration (OAuth), so deep-link.\n kind: 'Github',\n label: 'GitHub',\n mode: 'deep-link',\n signals: {\n npm: ['@octokit/rest', '@octokit/core', '@octokit/graphql', 'octokit'],\n python: ['pygithub'],\n ruby: ['octokit'],\n },\n },\n];\n","/**\n * Data warehouse source detection.\n *\n * Scans a project for codebase signals (npm/python/ruby deps, `.env` key\n * names) and matches them against the `SOURCE_DETECTORS` registry. Pure\n * function: no store mutations, no UI calls. Reads files locally — only the\n * wizard process does this; the agent never sees secret values.\n *\n * Note we only read `.env` KEY NAMES, never values.\n */\n\nimport { analytics } from '@utils/analytics';\nimport { walkProjectFiles, safeReadFile } from '@utils/file-utils';\nimport type { PackageJson } from '@utils/package-json';\nimport {\n parseRequirementsTxt,\n parsePyprojectToml,\n parsePipfile,\n} from '@lib/detection/features';\nimport { SOURCE_DETECTORS } from './registry.js';\nimport type { DetectedSource, SourceDetector } from './types.js';\n\ninterface ProjectSignals {\n npm: Set<string>;\n python: Set<string>;\n ruby: Set<string>;\n envKeys: Set<string>;\n}\n\nconst MAX_DEPTH = 3;\n\n/**\n * Detect which warehouse sources the project at `installDir` appears to use.\n * Returns one `DetectedSource` per matched registry entry (kinds are unique,\n * so the result is naturally deduped).\n */\nexport function detectWarehouseSources(installDir: string): DetectedSource[] {\n // No directory guard here: walkProjectFiles is best-effort and yields no\n // signals for a missing/unreadable dir (→ []). The program-level detect\n // step is responsible for surfacing a structured `bad-directory` error.\n const signals = collectSignals(installDir);\n\n const detected: DetectedSource[] = [];\n for (const detector of SOURCE_DETECTORS) {\n const match = matchDetector(detector, signals);\n if (match) {\n detected.push({\n kind: detector.kind,\n label: detector.label,\n mode: detector.mode,\n matchedSignal: match,\n });\n }\n }\n return detected;\n}\n\n/** Returns a human-readable description of the first matching signal, or null. */\nfunction matchDetector(\n detector: SourceDetector,\n signals: ProjectSignals,\n): string | null {\n const { npm, python, ruby, envKeys } = detector.signals;\n\n const npmHit = npm?.find((dep) => signals.npm.has(dep));\n if (npmHit) return `found \\`${npmHit}\\` in package.json`;\n\n const pyHit = python?.find((dep) => signals.python.has(dep));\n if (pyHit) return `found \\`${pyHit}\\` in Python dependencies`;\n\n const rubyHit = ruby?.find((gem) => signals.ruby.has(gem));\n if (rubyHit) return `found \\`${rubyHit}\\` in Gemfile`;\n\n if (envKeys) {\n for (const key of signals.envKeys) {\n if (envKeys.some((re) => re.test(key))) {\n return `found \\`${key}\\` in .env`;\n }\n }\n }\n\n return null;\n}\n\nfunction collectSignals(installDir: string): ProjectSignals {\n const signals: ProjectSignals = {\n npm: new Set(),\n python: new Set(),\n ruby: new Set(),\n envKeys: new Set(),\n };\n\n walkProjectFiles(\n installDir,\n (name, fullPath) => ingestFile(name, fullPath, signals),\n MAX_DEPTH,\n );\n\n return signals;\n}\n\n/**\n * Route a file to the right parser BY NAME, reading its contents only when the\n * name matches one of the ~6 manifests we care about. Checking the name first\n * avoids slurping every file in the tree (lockfiles, binaries, assets) into\n * memory just to discard it.\n */\nfunction ingestFile(\n name: string,\n fullPath: string,\n signals: ProjectSignals,\n): void {\n const ingest = ingestorFor(name);\n if (!ingest) return;\n\n const content = safeReadFile(fullPath);\n if (content === null) return;\n\n ingest(content, signals);\n}\n\ntype Ingestor = (content: string, signals: ProjectSignals) => void;\n\n/** Pick the parser for a manifest filename, or null if it's not one we read. */\nfunction ingestorFor(name: string): Ingestor | null {\n if (name === 'package.json') return addNpmDeps;\n if (name === 'requirements.txt')\n return (c, s) => parseRequirementsTxt(c).forEach((d) => s.python.add(d));\n if (name === 'pyproject.toml')\n return (c, s) => parsePyprojectToml(c).forEach((d) => s.python.add(d));\n if (name === 'Pipfile')\n return (c, s) => parsePipfile(c).forEach((d) => s.python.add(d));\n if (name === 'Gemfile')\n return (c, s) => parseGemfile(c).forEach((g) => s.ruby.add(g));\n if (name.startsWith('.env'))\n return (c, s) => parseEnvKeys(c).forEach((k) => s.envKeys.add(k));\n return null;\n}\n\nfunction addNpmDeps(content: string, signals: ProjectSignals): void {\n try {\n const pkg = JSON.parse(content) as PackageJson;\n for (const dep of Object.keys({\n ...pkg.dependencies,\n ...pkg.devDependencies,\n })) {\n signals.npm.add(dep);\n }\n } catch (error) {\n // Malformed package.json — skip it, but record that we hit it.\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'detectWarehouseSources.parsePackageJson' },\n );\n }\n}\n\n/** Extract gem names from `gem 'name'` declarations. */\nexport function parseGemfile(content: string): string[] {\n const gems: string[] = [];\n for (const match of content.matchAll(/^\\s*gem\\s+['\"]([^'\"]+)['\"]/gm)) {\n gems.push(match[1]);\n }\n return gems;\n}\n\n/** Extract KEY NAMES from a dotenv file. Values are intentionally discarded. */\nexport function parseEnvKeys(content: string): string[] {\n const keys: string[] = [];\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const match = trimmed.match(/^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=/);\n if (match) keys.push(match[1]);\n }\n return keys;\n}\n","/**\n * Warehouse-source program detection step.\n *\n * Thin adapter over `detectWarehouseSources` that writes results into\n * frameworkContext for the intro screen, plus the `[ABORT]` cases the\n * data-warehouse-source-setup skill can emit.\n */\n\nimport { existsSync, statSync } from 'fs';\nimport { analytics } from '@utils/analytics';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\nimport { detectWarehouseSources } from '@lib/warehouse-sources/detect';\nimport type { DetectedSource } from '@lib/warehouse-sources/types';\n\n/** Structured detection errors rendered by the intro screen. */\nexport type WarehouseDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-sources' };\n\n/** frameworkContext key holding the detected sources (set on success). */\nexport const DETECTED_WAREHOUSE_SOURCES_KEY = 'detectedWarehouseSources';\n\n/**\n * Read the detected sources out of frameworkContext. Single accessor shared by\n * the intro screen and the prompt builder so the key + cast live in one place.\n */\nexport function getDetectedWarehouseSources(\n session: WizardSession,\n): DetectedSource[] {\n return (\n (session.frameworkContext[DETECTED_WAREHOUSE_SOURCES_KEY] as\n | DetectedSource[]\n | undefined) ?? []\n );\n}\n\n/** `[ABORT] <reason>` cases the skill can emit. */\nexport const WAREHOUSE_ABORT_CASES: AbortCase[] = [\n {\n // Skill emits: [ABORT] No data source detected\n // Tolerant of plural (\"sources\") and a trailing period.\n match: /^no data sources? detected\\.?$/i,\n message: 'No data source detected',\n body:\n 'The agent could not confirm a data warehouse source to connect. ' +\n 'Run this command from a project that uses a supported source ' +\n '(a database, Stripe, etc.).',\n docsUrl: 'https://posthog.com/docs/data-warehouse',\n },\n {\n // Skill emits: [ABORT] Source creation failed\n match: /^source creation failed\\.?$/i,\n message: 'Source creation failed',\n body:\n 'PostHog could not create the data warehouse source with the ' +\n 'credentials provided. Double-check the connection details and try ' +\n 'again, or set the source up directly in the PostHog app.',\n docsUrl: 'https://posthog.com/docs/data-warehouse',\n },\n];\n\n/**\n * Scan `session.installDir` for warehouse-source signals. Writes the detected\n * sources (or a `detectError`) into frameworkContext for the intro screen.\n */\nexport function detectWarehousePrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: WarehouseDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch (error) {\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'detectWarehousePrerequisites.stat', path: installDir },\n );\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n const sources = detectWarehouseSources(installDir);\n\n if (sources.length === 0) {\n fail({ kind: 'no-sources' });\n return;\n }\n\n setFrameworkContext(DETECTED_WAREHOUSE_SOURCES_KEY, sources);\n}\n","/**\n * Warehouse-source program step list.\n *\n * The detect step scans for warehouse-source signals. The skill install and\n * agent run live in the program runner (see agent-runner.ts). The skill drives\n * both in-CLI source creation and deep-link emission per detected source.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { detectWarehousePrerequisites } from './detect.js';\n\nexport const WAREHOUSE_SOURCE_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting data sources',\n // Headless step: no screen. onReady scans installDir and writes the\n // detected sources (or a detectError) to frameworkContext for the\n // intro screen to render.\n onReady: (ctx) =>\n detectWarehousePrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'warehouse-intro',\n gate: (session) => session.setupConfirmed,\n },\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Data warehouse',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { WAREHOUSE_SOURCE_PROGRAM } from './steps.js';\nimport {\n WAREHOUSE_ABORT_CASES,\n getDetectedWarehouseSources,\n} from './detect.js';\nimport { getContentBlocks } from './content/index.js';\n\n/**\n * Inject the detected sources (and their creation mode) into the prompt so the\n * skill knows what to set up. The *how* — in-CLI creation vs deep-link, field\n * collection, validation — lives in the skill, not here.\n */\nfunction buildPrompt(session: WizardSession): string {\n const sources = getDetectedWarehouseSources(session);\n if (sources.length === 0) {\n return 'Set up a data warehouse source for this project.';\n }\n\n const lines = sources.map(\n (s) =>\n `- ${s.label} (kind: ${s.kind}, mode: ${s.mode}) — ${s.matchedSignal}`,\n );\n\n return [\n 'The wizard detected the following data warehouse sources in this project:',\n ...lines,\n '',\n 'Set these up in PostHog following the skill instructions: create `in-cli` ' +\n 'sources directly via the PostHog MCP after collecting credentials; for ' +\n '`deep-link` sources, provide the user the pre-filled new-source URL.',\n ].join('\\n');\n}\n\nexport const warehouseSourceConfig: ProgramConfig = {\n command: 'warehouse',\n description:\n 'Detect and connect a data warehouse source (Postgres, Stripe, …)',\n id: 'warehouse-source',\n skillId: 'data-warehouse-source-setup',\n steps: WAREHOUSE_SOURCE_PROGRAM,\n getContentBlocks,\n reportFile: 'posthog-warehouse-report.md',\n allowedTools: ['Agent'],\n run: (session: WizardSession): Promise<ProgramRun> =>\n Promise.resolve({\n skillId: 'data-warehouse-source-setup',\n integrationLabel: 'data-warehouse-source-setup',\n customPrompt: () => buildPrompt(session),\n successMessage: 'Data warehouse source connected!',\n reportFile: 'posthog-warehouse-report.md',\n docsUrl: 'https://posthog.com/docs/data-warehouse',\n spinnerMessage: 'Connecting your data source...',\n estimatedDurationMinutes: 5,\n abortCases: WAREHOUSE_ABORT_CASES,\n }),\n requires: ['posthog-integration'],\n};\n\nexport { WAREHOUSE_SOURCE_PROGRAM } from './steps.js';\nexport {\n detectWarehousePrerequisites,\n getDetectedWarehouseSources,\n DETECTED_WAREHOUSE_SOURCES_KEY,\n WAREHOUSE_ABORT_CASES,\n type WarehouseDetectError,\n} from './detect.js';\n","/**\n * Generic agent skill step list.\n *\n * Minimal flow: intro → health-check → auth → run → outro → skills.\n * No detection, no setup, no MCP.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\n\nexport const AGENT_SKILL_STEPS: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'agent-skill-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Running',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","/**\n * Generic agent skill program factory.\n *\n * Creates a ProgramConfig for any context-mill skill. Provide a\n * skill ID and basic UI config — the factory handles the rest.\n *\n * Usage:\n * createSkillProgram({\n * skillId: 'error-tracking-setup',\n * command: 'errors',\n * id: 'error-tracking',\n * description: 'Set up PostHog error tracking',\n * integrationLabel: 'error-tracking',\n * successMessage: 'Error tracking configured!',\n * reportFile: 'posthog-error-tracking-report.md',\n * docsUrl: 'https://posthog.com/docs/error-tracking',\n * spinnerMessage: 'Setting up error tracking...',\n * estimatedDurationMinutes: 5,\n * })\n */\n\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun, AbortCase } from '@lib/agent/agent-runner';\nimport { AGENT_SKILL_STEPS } from './steps.js';\nimport { getContentBlocks } from './content/index.js';\n\nexport interface SkillProgramOptions {\n /** Context-mill skill ID to install */\n skillId: string;\n /** CLI subcommand name */\n command: string;\n /** Unique flow key — must match a Program enum entry */\n id: string;\n /** CLI description shown in --help */\n description: string;\n /** Analytics integration label */\n integrationLabel: string;\n /** Custom prompt instruction. Appended after default project prompt. */\n customPrompt?: string;\n successMessage: string;\n reportFile: string;\n docsUrl: string;\n spinnerMessage: string;\n estimatedDurationMinutes: number;\n /** Other program ids that must be satisfied first */\n requires?: string[];\n /** Override the default outro. Receives the same args as ProgramRun.buildOutroData. */\n buildOutroData?: ProgramRun['buildOutroData'];\n /** Known `[ABORT] <reason>` cases the skill can emit. */\n abortCases?: AbortCase[];\n}\n\nexport function createSkillProgram(opts: SkillProgramOptions): ProgramConfig {\n return {\n command: opts.command,\n description: opts.description,\n id: opts.id,\n skillId: opts.skillId,\n steps: AGENT_SKILL_STEPS,\n reportFile: opts.reportFile,\n getContentBlocks,\n run: {\n skillId: opts.skillId,\n integrationLabel: opts.integrationLabel,\n customPrompt: opts.customPrompt ? () => opts.customPrompt! : undefined,\n successMessage: opts.successMessage,\n reportFile: opts.reportFile,\n docsUrl: opts.docsUrl,\n spinnerMessage: opts.spinnerMessage,\n estimatedDurationMinutes: opts.estimatedDurationMinutes,\n buildOutroData: opts.buildOutroData,\n abortCases: opts.abortCases,\n },\n requires: opts.requires,\n };\n}\n\nexport { AGENT_SKILL_STEPS } from './steps.js';\n","import type { AbortCase } from '@lib/agent/agent-runner';\n\n/** `[ABORT] <reason>` cases the audit skill can emit. Reason strings are\n * defined in the skill's `Abort statuses` section. */\nexport const AUDIT_ABORT_CASES: AbortCase[] = [\n {\n match: /^no posthog sdk found$/i,\n message: 'No PostHog SDK found',\n body:\n 'The audit needs an existing PostHog integration to review. No PostHog ' +\n 'SDK appears in this project’s dependency manifests. Run the basic ' +\n 'integration program to install PostHog first, then re-run the audit.',\n docsUrl: 'https://posthog.com/docs/getting-started/install',\n },\n];\n","import fs from 'fs';\nimport path from 'path';\nimport { logToFile } from '@utils/debug';\nimport { AUDIT_CHECKS_FILE, type AuditCheck } from './types.js';\n\n/**\n * The 10 data-integrity checks the audit runs, plus one workflow row for the\n * notebook upload at the end (so the skill's `audit_resolve_checks` call for\n * `upload-notebook` succeeds — the skill writes the report to a PostHog\n * notebook as its final step).\n */\nexport const AUDIT_SEED_CHECKS: AuditCheck[] = [\n {\n id: 'sdk-installed',\n area: 'Installation',\n label: 'PostHog SDK installed',\n status: 'pending',\n },\n {\n id: 'sdk-up-to-date',\n area: 'Installation',\n label: 'SDK version up to date',\n status: 'pending',\n },\n {\n id: 'init-correct',\n area: 'Installation',\n label: 'Initialization is correct',\n status: 'pending',\n },\n {\n id: 'identify-stable-distinct-id',\n area: 'Identification',\n label: 'Stable distinct_id (not session UUID)',\n status: 'pending',\n },\n {\n id: 'identify-not-late',\n area: 'Identification',\n label: 'identify() called before captures / flag evals',\n status: 'pending',\n },\n {\n id: 'cross-runtime-distinct-id',\n area: 'Identification',\n label: 'Same distinct_id across client and server',\n status: 'pending',\n },\n {\n id: 'identify-reset-on-logout',\n area: 'Identification',\n label: 'reset() called on logout / account switch',\n status: 'pending',\n },\n {\n id: 'capture-event-names-static',\n area: 'Event Capture',\n label: 'Event names are static and consistent',\n status: 'pending',\n },\n {\n id: 'capture-uses-proxy',\n area: 'Event Capture',\n label: 'Captures route through a reverse proxy',\n status: 'pending',\n },\n {\n id: 'capture-growth-events',\n area: 'Event Capture',\n label: 'Key activation events captured',\n status: 'pending',\n },\n {\n id: 'write-report',\n area: 'Write report',\n label: 'Create posthog-audit-report.md',\n status: 'pending',\n },\n {\n id: 'upload-notebook',\n area: 'Upload notebook',\n label: 'Write the report into a PostHog notebook',\n status: 'pending',\n },\n];\n\n/**\n * Atomically write a seeded ledger to the project's audit checks file.\n *\n * Each audit-flavored program (doctor, events-audit) owns its own seed\n * shape — pass the seed in so this writer stays program-agnostic.\n */\nexport function seedAuditLedger(\n installDir: string,\n checks: AuditCheck[] = AUDIT_SEED_CHECKS,\n): void {\n const target = path.join(installDir, AUDIT_CHECKS_FILE);\n const tmp = `${target}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify(checks, null, 2), 'utf8');\n fs.renameSync(tmp, target);\n logToFile(`seedAuditLedger: wrote ${checks.length} entries to ${target}`);\n}\n","import {\n AGENT_SKILL_STEPS,\n createSkillProgram,\n} from '@lib/programs/agent-skill/index';\nimport type { ProgramStep, ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { OutroKind } from '@lib/wizard-session';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { getCloudUrlFromRegion } from '@utils/urls';\nimport { AUDIT_ABORT_CASES } from './detect.js';\nimport { AUDIT_CHECKS_KEY, AUDIT_REPORT_FILE } from './types.js';\nimport { AUDIT_SEED_CHECKS, seedAuditLedger } from './seed.js';\n\n/** Audit-specific screens for the shared agent-skill pipeline. */\nconst AUDIT_SCREEN_BY_STEP: Record<string, string> = {\n intro: 'audit-intro',\n run: 'audit-run',\n outro: 'audit-outro',\n};\n\nconst seedBeforeAuditRun = (session: WizardSession): void => {\n seedAuditLedger(session.installDir);\n session.frameworkContext[AUDIT_CHECKS_KEY] = AUDIT_SEED_CHECKS;\n};\n\nconst withAuditScreens = (steps: ProgramStep[]): ProgramStep[] =>\n steps.map((step) => {\n const override = AUDIT_SCREEN_BY_STEP[step.id];\n return override ? { ...step, screenId: override } : step;\n });\n\nconst auditSteps: ProgramStep[] = withAuditScreens(AGENT_SKILL_STEPS);\n\nconst baseConfig = createSkillProgram({\n skillId: 'audit',\n command: 'audit',\n id: 'audit',\n description:\n 'Audit an existing PostHog integration for correctness and best practices',\n integrationLabel: 'audit',\n customPrompt:\n 'Run a comprehensive audit of the existing PostHog integration. Follow the skill program steps in order. Do not modify any project files — only create the final audit report.',\n successMessage:\n 'Audit complete! You can view the audit report at ./posthog-audit-report.md',\n reportFile: AUDIT_REPORT_FILE,\n docsUrl: 'https://posthog.com/docs/product-analytics/best-practices',\n spinnerMessage: 'Auditing PostHog integration...',\n estimatedDurationMinutes: 5,\n requires: ['posthog-integration'],\n abortCases: AUDIT_ABORT_CASES,\n});\n\nconst auditRun = async (session: WizardSession): Promise<ProgramRun> => {\n seedBeforeAuditRun(session);\n\n if (!baseConfig.run) {\n throw new Error('Audit program has no run configuration.');\n }\n\n const baseRun =\n typeof baseConfig.run === 'function'\n ? await baseConfig.run(session)\n : baseConfig.run;\n\n return {\n ...baseRun,\n // Override the default outro so the dashboard + notebook URLs the\n // agent emits via `[DASHBOARD_URL]` / `[NOTEBOOK_URL]` are surfaced\n // on the post-run screen.\n buildOutroData: (sess, _credentials, cloudRegion) => {\n const cloudUrl = cloudRegion\n ? getCloudUrlFromRegion(cloudRegion)\n : undefined;\n const continueUrl =\n sess.signup && cloudUrl\n ? `${cloudUrl}/products?source=wizard`\n : undefined;\n\n // Note: `sess` here is the agent-runner's snapshot of session at\n // runAgent() invocation time. Any URL emissions during the run land\n // on the live store, NOT on this snapshot. The UI layer\n // (InkUI.setOutroData) merges live URLs in on top of this return\n // value, so it's safe to leave dashboardUrl/notebookUrl as undefined\n // here when the snapshot doesn't have them.\n return {\n kind: OutroKind.Success as const,\n message: baseRun.successMessage,\n reportFile: baseRun.reportFile,\n docsUrl: baseRun.docsUrl,\n continueUrl,\n dashboardUrl: sess.dashboardUrl ?? undefined,\n notebookUrl: sess.notebookUrl ?? undefined,\n };\n },\n };\n};\n\nexport const auditConfig: ProgramConfig = {\n ...baseConfig,\n steps: auditSteps,\n run: auditRun,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n};\n","/**\n * Events-audit program.\n *\n * Mirrors the posthog-integration step list, except:\n * - The initial framework detection step is omitted — the events-audit\n * skill handles detection at agent run time.\n * - The intro step uses the audit intro screen (no framework selection\n * logic) instead of the integration intro.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\n\nfunction needsSetup(session: WizardSession): boolean {\n const config = session.frameworkConfig;\n if (!config?.metadata.setup?.questions) return false;\n\n return config.metadata.setup.questions.some(\n (q: { key: string }) => !(q.key in session.frameworkContext),\n );\n}\n\nexport const EVENTS_AUDIT_PROGRAM: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'audit-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'setup',\n label: 'Setup',\n screenId: 'setup',\n show: needsSetup,\n isComplete: (session) => !needsSetup(session),\n },\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Events audit',\n screenId: 'audit-run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'mcp',\n label: 'MCP servers',\n screenId: 'mcp',\n isComplete: (session) => session.mcpComplete,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'audit-outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'keep-skills',\n label: 'Keep Skills',\n screenId: 'keep-skills',\n },\n];\n","import type { AuditCheck } from '@lib/programs/audit/types';\n\n/**\n * The 7 phases the events-audit skill marches through. One check per area\n * so PendingChecksList renders a clean linear pipeline (area = bold header,\n * single row = the active spinner).\n *\n * Phase ids match what the skill's step files resolve via\n * `mcp__wizard-tools__audit_resolve_checks` as each phase completes. The\n * skill's step 1 also seeds these same ids — keep both in sync so the\n * wizard pre-seed and the skill's MCP seed agree.\n */\nexport const EVENTS_AUDIT_SEED_CHECKS: AuditCheck[] = [\n {\n id: 'detect-sdk',\n area: 'Detect SDK',\n label: 'Identify PostHog SDK(s) in dependencies',\n status: 'pending',\n },\n {\n id: 'scan-sites',\n area: 'Scan capture sites',\n label: 'Grep capture/identify/group call sites',\n status: 'pending',\n },\n {\n id: 'enrich-sites',\n area: 'Enrich',\n label: 'Subagent fan-out to read capture files',\n status: 'pending',\n },\n {\n id: 'query-volume',\n area: 'Query PostHog',\n label: '30-day volume + last_seen via MCP',\n status: 'pending',\n },\n {\n id: 'write-report',\n area: 'Write report',\n label: 'Create posthog-events-audit-report.md',\n status: 'pending',\n },\n {\n id: 'create-dashboard',\n area: 'Create dashboard',\n label: 'Optional: dashboard for resolved events',\n status: 'pending',\n },\n {\n id: 'upload-notebook',\n area: 'Upload notebook',\n label: 'Write the report into a PostHog notebook',\n status: 'pending',\n },\n];\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { OutroKind } from '@lib/wizard-session';\nimport { SPINNER_MESSAGE } from '@lib/framework-config';\nimport { isUsingTypeScript } from '@utils/setup-utils';\nimport { getCloudUrlFromRegion } from '@utils/urls';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { EVENTS_AUDIT_PROGRAM } from './steps.js';\nimport { AUDIT_CHECKS_KEY } from '@lib/programs/audit/types';\nimport { seedAuditLedger } from '@lib/programs/audit/seed';\nimport { EVENTS_AUDIT_SEED_CHECKS } from './seed.js';\n\nexport const SETUP_REPORT_FILE = 'posthog-events-audit-report.md';\n\nconst DOCS_URL = 'https://posthog.com/docs/product-analytics/best-practices';\n\nexport const eventsAuditConfig: ProgramConfig = {\n command: 'events-audit',\n description: 'Audit PostHog event tracking in this project',\n id: 'events-audit',\n skillId: 'events-audit',\n steps: EVENTS_AUDIT_PROGRAM,\n // Top-level reportFile so AuditRunScreen can resolve the report path\n // synchronously without unwrapping the deferred `run` function.\n reportFile: SETUP_REPORT_FILE,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n\n run: (session: WizardSession): Promise<ProgramRun> => {\n const typeScriptDetected = isUsingTypeScript({\n installDir: session.installDir,\n });\n session.typescript = typeScriptDetected;\n\n // Seed the audit ledger so AuditRunScreen has something to render\n // before the agent emits its first check update. The events-audit\n // ledger is the 6-phase pipeline, not the doctor's 10 integrity checks.\n seedAuditLedger(session.installDir, EVENTS_AUDIT_SEED_CHECKS);\n session.frameworkContext[AUDIT_CHECKS_KEY] = EVENTS_AUDIT_SEED_CHECKS;\n\n return Promise.resolve({\n skillId: 'events-audit',\n integrationLabel: 'events-audit',\n spinnerMessage: SPINNER_MESSAGE,\n successMessage:\n 'Events audit complete! You can view the report at ./posthog-events-audit-report.md',\n estimatedDurationMinutes: 5,\n reportFile: SETUP_REPORT_FILE,\n docsUrl: DOCS_URL,\n errorMessage: 'Events audit failed',\n additionalFeatureQueue: session.additionalFeatureQueue,\n\n customPrompt: (ctx) =>\n `Audit PostHog event capture in this project. Do not modify any project files — produce a read-only report only.\n\nProject context:\n- PostHog Project ID: ${ctx.projectId}\n- TypeScript: ${typeScriptDetected ? 'Yes' : 'No'}\n- PostHog public token: ${ctx.projectApiKey}\n- PostHog Host: ${ctx.host}\n`,\n\n buildOutroData: (sess, _credentials, cloudRegion) => {\n const cloudUrl = cloudRegion\n ? getCloudUrlFromRegion(cloudRegion)\n : undefined;\n const continueUrl =\n sess.signup && cloudUrl\n ? `${cloudUrl}/products?source=wizard`\n : undefined;\n // The agent emits `[DASHBOARD_URL] <url>` once it creates the\n // dashboard; the SDK-message interceptor stores it on the session.\n // Fall back to the dashboards index if nothing was emitted.\n const dashboardUrl =\n sess.dashboardUrl ?? (cloudUrl ? `${cloudUrl}/dashboard` : undefined);\n\n // The agent emits `[NOTEBOOK_URL] <url>` once it uploads the report\n // to a PostHog notebook. No fallback: if the notebook upload was\n // skipped (e.g. MCP unavailable) we just don't show a link.\n const notebookUrl = sess.notebookUrl ?? undefined;\n\n return {\n kind: OutroKind.Success as const,\n message: 'Your events audit was successful',\n reportFile: SETUP_REPORT_FILE,\n changes: [],\n docsUrl: DOCS_URL,\n continueUrl,\n dashboardUrl,\n notebookUrl,\n };\n },\n });\n },\n};\n\nexport { EVENTS_AUDIT_PROGRAM } from './steps.js';\n","import type { ProgramStep } from '@lib/programs/program-step';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\n\nexport const POSTHOG_DOCTOR_PROGRAM: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'doctor-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'report',\n label: 'Doctor report',\n screenId: 'doctor-report',\n isComplete: (session) => session.outroData !== null,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n];\n","import { z } from 'zod';\n\nexport const HealthIssueSeveritySchema = z.enum([\n 'critical',\n 'warning',\n 'info',\n]);\nexport type HealthIssueSeverity = z.infer<typeof HealthIssueSeveritySchema>;\n\nexport const HealthIssueStatusSchema = z.enum(['active', 'resolved']);\n\nexport const HealthIssueSchema = z.object({\n id: z.string(),\n kind: z.string(),\n severity: HealthIssueSeveritySchema,\n status: HealthIssueStatusSchema,\n dismissed: z.boolean(),\n created_at: z.string(),\n updated_at: z.string(),\n resolved_at: z.string().nullable().optional(),\n});\nexport type HealthIssue = z.infer<typeof HealthIssueSchema>;\n\nexport const HealthIssueListResponseSchema = z.object({\n results: z.array(HealthIssueSchema),\n count: z.number().optional(),\n next: z.string().nullable().optional(),\n previous: z.string().nullable().optional(),\n});\nexport type HealthIssueListResponse = z.infer<\n typeof HealthIssueListResponseSchema\n>;\n\nexport interface HealthIssueSummary {\n total: number;\n by_severity: Record<HealthIssueSeverity, number>;\n}\n","import axios from 'axios';\nimport { analytics } from '@utils/analytics';\nimport { handleApiError } from '@lib/api';\nimport { WIZARD_USER_AGENT } from '@lib/constants';\nimport { HealthIssueListResponseSchema, type HealthIssue } from './types';\n\nexport async function fetchHealthIssues(\n accessToken: string,\n baseUrl: string,\n projectId: number,\n): Promise<HealthIssue[]> {\n const endpoint = `/api/environments/${projectId}/health_issues/`;\n const url = `${baseUrl}${endpoint}?status=active&dismissed=false&limit=250`;\n try {\n const response = await axios.get(url, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n return HealthIssueListResponseSchema.parse(response.data).results;\n } catch (error) {\n const apiError = handleApiError(error, 'fetch health issues');\n analytics.captureException(apiError, { endpoint, baseUrl, projectId });\n throw apiError;\n }\n}\n","import { POSTHOG_DOCS_URL } from '@lib/constants';\n\nexport interface KindMeta {\n title: string;\n description: string;\n docsUrl: string;\n}\n\nexport const KIND_METADATA: Record<string, KindMeta> = {\n ingestion_lag: {\n title: 'Ingestion is delayed',\n description:\n 'Events are being received but are taking longer than usual to appear.',\n docsUrl: `${POSTHOG_DOCS_URL}/support/troubleshooting`,\n },\n ingestion_warning: {\n title: 'Ingestion warnings on recent events',\n description:\n 'Some recent events were rejected or flagged by the ingestion pipeline.',\n docsUrl: `${POSTHOG_DOCS_URL}/support/troubleshooting`,\n },\n sdk_outdated: {\n title: 'SDK version is out of date',\n description:\n 'One or more SDKs are running an old version. Upgrade to get the latest fixes.',\n docsUrl: `${POSTHOG_DOCS_URL}/libraries`,\n },\n no_live_events: {\n title: 'No $pageview or $screen events in the last 30 days',\n description:\n 'PostHog is not receiving page or screen events from this project.',\n docsUrl: `${POSTHOG_DOCS_URL}/getting-started/install`,\n },\n no_pageleave_events: {\n title: '$pageleave events not being sent',\n description:\n 'Enable pageleave tracking to power bounce rate and session duration.',\n docsUrl: `${POSTHOG_DOCS_URL}/libraries/js#config`,\n },\n scroll_depth: {\n title: 'Scroll depth tracking disabled',\n description:\n 'Turn on scroll depth to capture how far users read each page.',\n docsUrl: `${POSTHOG_DOCS_URL}/libraries/js#config`,\n },\n authorized_urls: {\n title: 'No authorized URLs configured',\n description:\n 'Some web analytics filters require at least one authorized URL to work.',\n docsUrl: `${POSTHOG_DOCS_URL}/web-analytics/faq`,\n },\n reverse_proxy: {\n title: 'No reverse proxy detected',\n description: 'A reverse proxy reduces data loss from ad blockers.',\n docsUrl: `${POSTHOG_DOCS_URL}/advanced/proxy`,\n },\n web_vitals: {\n title: 'Web Vitals tracking disabled',\n description:\n 'Enable Web Vitals to capture LCP, CLS and other performance metrics.',\n docsUrl: `${POSTHOG_DOCS_URL}/web-analytics/web-vitals`,\n },\n materialized_view_failure: {\n title: 'A materialized view is failing',\n description: 'A data modeling pipeline failed its most recent run.',\n docsUrl: `${POSTHOG_DOCS_URL}/data-warehouse`,\n },\n external_data_failure: {\n title: 'External data source is failing',\n description: 'An external data source sync failed and data may be stale.',\n docsUrl: `${POSTHOG_DOCS_URL}/data-warehouse/sources`,\n },\n};\n\nexport const UNKNOWN_KIND_META: KindMeta = {\n title: 'Unknown issue',\n description:\n 'PostHog reported an issue kind the wizard does not yet recognize.',\n docsUrl: POSTHOG_DOCS_URL,\n};\n\nexport function getKindMeta(kind: string): KindMeta {\n return KIND_METADATA[kind] ?? { ...UNKNOWN_KIND_META, title: kind };\n}\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { POSTHOG_DOCTOR_PROGRAM } from './steps.js';\n\nexport const posthogDoctorConfig: ProgramConfig = {\n command: 'doctor',\n description:\n 'Diagnose your PostHog project for configuration issues and setup warnings',\n id: 'posthog-doctor',\n requiresAi: false,\n steps: POSTHOG_DOCTOR_PROGRAM,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n};\n\nexport { POSTHOG_DOCTOR_PROGRAM } from './steps.js';\nexport { fetchHealthIssues } from './fetch.js';\nexport { getKindMeta, KIND_METADATA } from './kind-metadata.js';\nexport type { KindMeta } from './kind-metadata.js';\nexport type {\n HealthIssue,\n HealthIssueSeverity,\n HealthIssueSummary,\n} from './types.js';\n","import { existsSync, statSync } from 'fs';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\nimport { findPackageJsons } from '@lib/programs/shared/package-scanning';\n\nexport type WebAnalyticsDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-package-json' }\n | { kind: 'no-posthog'; scannedCount: number };\n\nexport const WEB_ANALYTICS_ABORT_CASES: AbortCase[] = [\n {\n match: /^no web analytics events$/i,\n message: 'No web analytics events',\n body:\n 'The doctor found no $pageview events in the last 30 days, so there is ' +\n 'nothing to audit yet. Make sure PostHog is initialized and capturing ' +\n 'pageviews, then run the doctor again.',\n docsUrl: 'https://posthog.com/docs/web-analytics/getting-started',\n },\n {\n match: /^insufficient permissions$/i,\n message: 'Insufficient permissions',\n body:\n 'The doctor could not query your project — the authenticated token is ' +\n 'missing query access. Re-run the wizard to sign in again, or use a key ' +\n 'with read access to your events.',\n docsUrl: 'https://posthog.com/docs/web-analytics',\n },\n {\n match: /^posthog sdk not installed$/i,\n message: 'PostHog SDK not installed',\n body:\n 'The doctor could not find a PostHog SDK in this project. Install and ' +\n 'configure PostHog first (run `npx @posthog/wizard`), then run the ' +\n 'doctor to check your web analytics setup.',\n docsUrl: 'https://posthog.com/docs/libraries/js',\n },\n];\n\nexport function detectWebAnalyticsPrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: WebAnalyticsDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n const matches = findPackageJsons(installDir);\n\n if (matches.length === 0) {\n fail({ kind: 'no-package-json' });\n return;\n }\n\n const sdks = [...new Set(matches.flatMap((m) => m.posthogSdks))];\n\n if (sdks.length === 0) {\n fail({ kind: 'no-posthog', scannedCount: matches.length });\n return;\n }\n\n setFrameworkContext('detectedPosthogSdks', sdks);\n}\n","import type { ProgramStep } from '@lib/programs/program-step';\nimport { AGENT_SKILL_STEPS } from '@lib/programs/agent-skill/steps';\nimport { detectWebAnalyticsPrerequisites } from './detect.js';\n\nexport const WEB_ANALYTICS_DOCTOR_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting prerequisites',\n onReady: (ctx) =>\n detectWebAnalyticsPrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n ...AGENT_SKILL_STEPS,\n];\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport { createSkillProgram } from '../agent-skill/index.js';\nimport { WEB_ANALYTICS_DOCTOR_PROGRAM } from './steps.js';\nimport { WEB_ANALYTICS_ABORT_CASES } from './detect.js';\n\nconst REPORT_FILE = 'posthog-web-analytics-report.md';\nconst DOCS_URL = 'https://posthog.com/docs/web-analytics';\n\nexport const webAnalyticsDoctorConfig: ProgramConfig = {\n ...createSkillProgram({\n skillId: 'web-analytics-doctor',\n command: 'web-analytics',\n id: 'web-analytics-doctor',\n description: 'Audit and fix your PostHog web analytics setup',\n integrationLabel: 'web-analytics-doctor',\n customPrompt:\n \"Run the web-analytics-doctor skill to check this project's PostHog web \" +\n 'analytics setup. Audit read-only first, then present the findings to the ' +\n 'user with a single wizard_ask multi-select and apply only the fixes they ' +\n 'choose — editing project code and/or PostHog project settings via the ' +\n 'MCP — before writing the report.',\n successMessage:\n 'Web analytics check complete! You can view the report at ./posthog-web-analytics-report.md',\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n spinnerMessage: 'Checking your web analytics setup...',\n estimatedDurationMinutes: 5,\n requires: ['posthog-integration'],\n abortCases: WEB_ANALYTICS_ABORT_CASES,\n }),\n steps: WEB_ANALYTICS_DOCTOR_PROGRAM,\n parentCommand: 'audit',\n};\n\nexport { WEB_ANALYTICS_DOCTOR_PROGRAM } from './steps.js';\nexport {\n detectWebAnalyticsPrerequisites,\n WEB_ANALYTICS_ABORT_CASES,\n type WebAnalyticsDetectError,\n} from './detect.js';\n","import type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\n\nexport const MIGRATION_PROGRAM: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'migration-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Migration',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","/**\n * Vendor cost stack — the multi-tool baseline a typical migration target has\n * before consolidating onto PostHog. Numbers from each vendor's published\n * starter pricing.\n */\n\nimport { Text } from 'ink';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const VENDOR_STACK_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 600,\n pause: 9000,\n lines: [\n <Text bold>{' Typical pre-migration stack'}</Text>,\n <Text> </Text>,\n <Text>\n <Text color=\"gray\">{' Sentry'}</Text>\n <Text>{' error tracking '}</Text>\n <Text color=\"red\">{'$26/mo+'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' LaunchDarkly'}</Text>\n <Text>{' feature flags '}</Text>\n <Text color=\"red\">{'$8.33/mo+'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' Amplitude'}</Text>\n <Text>{' product analytics '}</Text>\n <Text color=\"red\">{'$49/mo+'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' Braintrust'}</Text>\n <Text>{' LLM analytics '}</Text>\n <Text color=\"red\">{'$50/mo+'}</Text>\n </Text>,\n <Text color=\"gray\">{' ─────────────────────────────────────'}</Text>,\n <Text>\n <Text>{' Total'}</Text>\n <Text>{' '}</Text>\n <Text bold color=\"red\">\n {'$133/mo+'}\n </Text>\n </Text>,\n <Text dimColor>{' plus ~450KB of JavaScript SDKs'}</Text>,\n ],\n};\n","/**\n * PostHog free-tier highlights — the numbers a migrating team gets back when\n * they consolidate. Sourced from posthog.com/pricing.md.\n */\n\nimport { Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const FREE_TIER_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 400,\n pause: 9000,\n lines: [\n <Text bold>{' Free every month, on every product'}</Text>,\n <Text> </Text>,\n <Text>\n <Text color={Colors.accent}>{' 1,000,000 '}</Text>\n <Text>events </Text>\n <Text dimColor>product analytics</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 1,000,000 '}</Text>\n <Text>requests </Text>\n <Text dimColor>feature flags + experiments</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 5,000 '}</Text>\n <Text>recordings </Text>\n <Text dimColor>session replay</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 100,000 '}</Text>\n <Text>exceptions </Text>\n <Text dimColor>error tracking</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 100,000 '}</Text>\n <Text>events </Text>\n <Text dimColor>LLM analytics</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 50 GB '}</Text>\n <Text>logs </Text>\n <Text dimColor>logs</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 1,500 '}</Text>\n <Text>responses </Text>\n <Text dimColor>surveys</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 1,000,000 '}</Text>\n <Text>rows </Text>\n <Text dimColor>data warehouse</Text>\n </Text>,\n ],\n};\n","/**\n * Pricing structure block — what happens after the free tier.\n */\n\nimport { Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const PRICING_STRUCTURE_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 500,\n pause: 8000,\n lines: [\n <Text bold>{' After the free tier'}</Text>,\n <Text> </Text>,\n <Text>\n <Text color={Colors.accent}>{' $0 '}</Text>\n <Text>base price · pay only for what you use</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>per-event prices decrease with volume</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>no per-seat charges — your whole team is included</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>web analytics bundled with product analytics</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>experiments bundled with feature flags</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>revenue analytics bundled with data warehouse</Text>\n </Text>,\n ],\n};\n","/**\n * Migration learn deck (statsig variant). Statsig is the only `migrate`\n * variant today, so this deck plays as-is when the wizard runs\n * `migrate --product=statsig`. Three movements:\n *\n * 1. Welcome and reassure.\n * 2. What to expect — the migration is replacement-only, takes a few\n * minutes, leaves the build green.\n * 3. What's a little different — how flags and experiments work in\n * PostHog, presented as right-way guidance rather than gotchas.\n *\n * FF/experiments guidance paraphrased from PostHog public docs:\n * - posthog.com/docs/feature-flags/best-practices\n * - posthog.com/docs/feature-flags/common-questions\n * - posthog.com/docs/experiments/best-practices\n */\n\nimport { Text } from 'ink';\nimport type { WizardStore } from '@ui/tui/store';\nimport { Colors } from '@ui/tui/styles';\nimport { TextRevealMode } from '@ui/tui/primitives/TextBlock';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\nimport { StatusPeekTrigger } from '@ui/tui/components/StatusPeekTrigger';\nimport { PRODUCT_SUITE_BLOCK } from '@lib/programs/posthog-integration/content/product-suite';\nimport { LINE_CHART_BLOCK } from '@lib/programs/posthog-integration/content/line-chart';\nimport { FUNNEL_BLOCK } from '@lib/programs/posthog-integration/content/funnel';\nimport { VENDOR_STACK_BLOCK } from './vendor-stack.js';\nimport { FREE_TIER_BLOCK } from './free-tier.js';\nimport { PRICING_STRUCTURE_BLOCK } from './pricing-structure.js';\n\nexport const getContentBlocks = (store?: WizardStore): ContentBlock[] => [\n // ── Welcome ────────────────────────────────────────────────────────────\n {\n content: 'Hello.',\n pause: 3000,\n mode: TextRevealMode.Typewriter,\n animationInterval: 160,\n },\n\n { content: 'The Wizard is an agent.', pause: 4000 },\n\n {\n content:\n 'As we speak, it’s making a plan to migrate from Statsig to PostHog.',\n pause: 6000,\n },\n\n {\n content: 'PostHog covers the cost of running this agent.',\n pause: 4000,\n },\n\n { type: 'clear', pause: 2000 },\n\n {\n pause: 5000,\n persist: true,\n content: <StatusPeekTrigger store={store} />,\n },\n\n {\n pause: 6000,\n persist: true,\n content: (\n <Text>\n Press{' '}\n <Text color={Colors.accent} bold>\n S\n </Text>{' '}\n to expand or collapse the status.\n </Text>\n ),\n },\n\n { type: 'clear', pause: 2000 },\n\n // ── What to expect ─────────────────────────────────────────────────────\n { content: 'Here’s what to expect.', pause: 3000 },\n\n { content: 'The migration takes about ten minutes.', pause: 3000 },\n\n {\n content:\n 'Every Statsig call gets replaced in place with its PostHog equivalent.',\n pause: 5500,\n },\n\n {\n content:\n 'Nothing new gets added. No extra captures, no surprise instrumentation.',\n pause: 5500,\n },\n\n {\n content:\n 'The Statsig package gets removed at the end. We’ll run build and lint to clean up after ourselves.',\n pause: 6500,\n },\n\n { type: 'clear', pause: 2000 },\n\n // ── What's a little different ─────────────────────────────────────────\n {\n content: 'A few things work a little differently in PostHog.',\n pause: 4500,\n },\n\n {\n content: (\n <Text>\n Flags evaluate against a stable user. Call{' '}\n <Text bold color={Colors.accent}>\n identify()\n </Text>{' '}\n first, then check the flag.\n </Text>\n ),\n pause: 6000,\n persist: true,\n },\n\n {\n content:\n 'For anything in the first paint, evaluate server-side and bootstrap the values into the client.',\n pause: 6500,\n },\n\n {\n content: (\n <Text>\n In production, route requests through a reverse proxy to avoid ad\n blockers breaking your flags.{'\\n'}\n <Text dimColor>https://posthog.com/docs/advanced/proxy</Text>\n </Text>\n ),\n pause: 6500,\n persist: true,\n },\n\n {\n content:\n 'When a flag reaches 100% rollout, retire it. Flags are signals, not switches.',\n pause: 5500,\n },\n\n {\n content: (\n <Text>\n Name flags descriptively. No double negatives. Reflect the return type.{' '}\n <Text dimColor>For example </Text>\n <Text bold>show-new-checkout</Text>\n <Text dimColor>.</Text>\n </Text>\n ),\n pause: 6500,\n persist: true,\n },\n\n { type: 'clear', pause: 1500 },\n\n // ── Experiments ────────────────────────────────────────────────────────\n {\n content: (\n <Text bold color={Colors.accent}>\n Experiments\n </Text>\n ),\n pause: 2500,\n persist: true,\n },\n\n {\n content:\n 'Change one thing per variant. Multiple changes in one variant blur the result.',\n pause: 5500,\n },\n\n {\n content:\n 'Decide the running time up front. PostHog includes a sample-size and duration calculator in the setup flow.',\n pause: 6500,\n },\n\n {\n content: 'Roll out to 5–10% first. Watch the metrics. Then increase.',\n pause: 5000,\n },\n\n {\n content:\n 'Exclude users who already completed the flow. They can’t be affected by the test.',\n pause: 5500,\n },\n\n { type: 'clear', pause: 1500 },\n\n // ── Close ──────────────────────────────────────────────────────────────\n {\n content: 'Flags and experiments live alongside the rest of your data.',\n pause: 4500,\n },\n\n {\n content: 'Ship behind a flag, watch replays, check analytics for impact.',\n pause: 4500,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n content:\n 'PostHog also provides every other analytics and AI tool to build your product.',\n pause: 4500,\n },\n\n PRODUCT_SUITE_BLOCK,\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'And consolidating onto one platform saves real money.',\n pause: 4500,\n },\n\n { content: 'Here’s the math.', pause: 1500 },\n\n VENDOR_STACK_BLOCK,\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'Pricing is usage-based, with a generous free tier.',\n pause: 4000,\n },\n\n FREE_TIER_BLOCK,\n\n { type: 'clear', pause: 1500 },\n\n PRICING_STRUCTURE_BLOCK,\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'Gain clarity and really understand your users.',\n pause: 4000,\n },\n\n { content: 'Use trends to measure growth.', pause: 2500 },\n\n LINE_CHART_BLOCK,\n\n { type: 'clear', pause: 500 },\n\n { content: 'Use funnels to reveal bottlenecks.', pause: 2500 },\n\n FUNNEL_BLOCK,\n];\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport type { AbortCase } from '@lib/agent/agent-runner';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { MIGRATION_PROGRAM } from './steps.js';\nimport { getContentBlocks } from './content/index.js';\n\nconst MIGRATION_REPORT_FILE = 'migration-report.md';\n\nconst MIGRATION_ABORT_CASES: AbortCase[] = [\n {\n match: /^no source-sdk calls found$/i,\n message: 'No source-SDK calls found',\n body:\n 'The migration needs an existing third-party SDK to migrate from. No ' +\n 'calls to the source SDK appear anywhere in this project. If you ' +\n \"haven't installed PostHog yet, you don't need this command — run \" +\n '`npx @posthog/wizard@latest` to add PostHog from scratch.',\n },\n];\n\n// Default skill id when nothing else picks one. The `wizard migrate <vendor>`\n// subcommands override this via skillCommandFactory using each manifest\n// entry's skillId, so this default only kicks in for legacy callers (e.g.\n// programmatic uses of migrationConfig directly).\nconst DEFAULT_MIGRATE_SKILL_ID = 'migrate-statsig';\n\nexport const migrationConfig: ProgramConfig = {\n command: 'migrate',\n description: 'Migrate to PostHog from another analytics provider',\n id: 'migration',\n skillId: DEFAULT_MIGRATE_SKILL_ID,\n steps: MIGRATION_PROGRAM,\n reportFile: MIGRATION_REPORT_FILE,\n getContentBlocks,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n run: {\n skillId: DEFAULT_MIGRATE_SKILL_ID,\n integrationLabel: 'migration',\n customPrompt: () =>\n 'Migrate this project from its existing third-party analytics, ' +\n 'feature-flag, and observability tools to PostHog. Run the `migrate` ' +\n 'skill end-to-end: follow the step chain starting at ' +\n 'references/1-presence.md. Only replace existing source-SDK call sites ' +\n 'with PostHog equivalents — make zero unrelated changes and no ' +\n `net-new instrumentation. The final report is written to ./${MIGRATION_REPORT_FILE}.`,\n successMessage: `Migration complete! View the report at ./${MIGRATION_REPORT_FILE}`,\n reportFile: MIGRATION_REPORT_FILE,\n docsUrl: '',\n spinnerMessage: 'Migrating to PostHog...',\n estimatedDurationMinutes: 8,\n abortCases: MIGRATION_ABORT_CASES,\n },\n requires: ['posthog-integration'],\n};\n\nexport { MIGRATION_PROGRAM } from './steps.js';\n","/**\n * Source maps upload prerequisite detection.\n *\n * Scans the project for signals that identify the platform and build system,\n * then maps to one of the context-mill `error-tracking-upload-source-maps-*`\n * skill variants. Results are written to frameworkContext for the intro\n * screen to render and for the agent prompt to consume.\n */\n\nimport type { Dirent } from 'fs';\nimport { readFileSync, readdirSync, existsSync, statSync } from 'fs';\nimport { join, relative } from 'path';\nimport { IGNORED_DIRS } from '@utils/file-utils';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\n\n/**\n * Skill variants published under the `error-tracking-upload-source-maps`\n * category in context-mill. The agent loads\n * `error-tracking-upload-source-maps-<variant>`.\n */\nexport type SkillVariant =\n | 'web'\n | 'nextjs'\n | 'node'\n | 'react'\n | 'angular'\n | 'nuxt'\n | 'react-native'\n | 'android'\n | 'flutter'\n | 'ios'\n | 'vite'\n | 'webpack'\n | 'rollup';\n\nconst DISPLAY_NAME: Record<SkillVariant, string> = {\n web: 'Web (JavaScript)',\n nextjs: 'Next.js',\n node: 'Node.js',\n react: 'React',\n angular: 'Angular',\n nuxt: 'Nuxt',\n 'react-native': 'React Native',\n android: 'Android',\n flutter: 'Flutter',\n ios: 'iOS',\n vite: 'Vite',\n webpack: 'Webpack',\n rollup: 'Rollup',\n};\n\n/**\n * Variants the wizard can wire up source-map upload for automatically. The\n * native variants (react-native, android, flutter, ios) are recognised but not\n * yet automatable, so the agentic picker treats them as non-instrumentable.\n */\nexport const AUTOMATABLE_VARIANTS: readonly SkillVariant[] = [\n 'web',\n 'nextjs',\n 'node',\n 'react',\n 'angular',\n 'nuxt',\n 'vite',\n 'webpack',\n 'rollup',\n];\n\nconst POSTHOG_SDKS = [\n 'posthog-js',\n 'posthog-node',\n 'posthog-react-native',\n 'posthog-android',\n 'posthog-ios',\n];\n\n/**\n * Structured detection errors. The screen renders each kind into JSX\n * with proper formatting — keeps error data separate from presentation.\n */\nexport type SourceMapsDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-project-files' }\n | { kind: 'unsupported-platform'; detected: string }\n | { kind: 'no-posthog-sdk'; platform: SkillVariant };\n\n/** `[ABORT] <reason>` cases the source maps skill can emit. */\nexport const SOURCE_MAPS_ABORT_CASES: AbortCase[] = [\n {\n match: /^no posthog sdk detected$/i,\n message: 'No PostHog SDK detected',\n body:\n 'The agent could not find a PostHog SDK in your project. ' +\n 'Source map upload requires the SDK to already be installed so it can ' +\n 'report errors. Run `npx @posthog/wizard` first to install the SDK.',\n docsUrl: 'https://posthog.com/docs/error-tracking',\n },\n {\n match: /^build command not found$/i,\n message: 'Build command not found',\n body:\n 'The agent could not identify how to build your project. Source map ' +\n 'upload runs as part of the production build. Add a build script to ' +\n 'your project and run this wizard again.',\n docsUrl: 'https://posthog.com/docs/error-tracking/upload-source-maps',\n },\n];\n\n// ── File / dependency probes ─────────────────────────────────────────\n\ninterface ProjectSignals {\n packageJsons: Array<{ path: string; deps: Set<string> }>;\n hasXcodeProject: boolean;\n hasPodfile: boolean;\n hasSwiftPackage: boolean;\n hasGradle: boolean;\n hasPubspec: boolean;\n scannedFileCount: number;\n}\n\nfunction collectSignals(installDir: string, maxDepth = 3): ProjectSignals {\n const signals: ProjectSignals = {\n packageJsons: [],\n hasXcodeProject: false,\n hasPodfile: false,\n hasSwiftPackage: false,\n hasGradle: false,\n hasPubspec: false,\n scannedFileCount: 0,\n };\n\n function scan(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') && entry.name !== '.') continue;\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = join(dir, entry.name);\n\n if (entry.isFile()) {\n signals.scannedFileCount += 1;\n if (entry.name === 'package.json') {\n try {\n const pkg = JSON.parse(readFileSync(fullPath, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = new Set([\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ]);\n signals.packageJsons.push({\n path: relative(installDir, fullPath) || 'package.json',\n deps,\n });\n } catch {\n // skip malformed package.json\n }\n } else if (entry.name === 'Podfile') {\n signals.hasPodfile = true;\n } else if (entry.name === 'Package.swift') {\n signals.hasSwiftPackage = true;\n } else if (entry.name === 'pubspec.yaml') {\n signals.hasPubspec = true;\n } else if (\n entry.name === 'build.gradle' ||\n entry.name === 'build.gradle.kts' ||\n entry.name === 'settings.gradle' ||\n entry.name === 'settings.gradle.kts'\n ) {\n signals.hasGradle = true;\n }\n } else if (entry.isDirectory()) {\n if (entry.name.endsWith('.xcodeproj')) {\n signals.hasXcodeProject = true;\n } else {\n scan(fullPath, depth + 1);\n }\n }\n }\n }\n\n scan(installDir, 0);\n return signals;\n}\n\n// ── Skill selection ──────────────────────────────────────────────────\n\nfunction pickJsVariant(deps: Set<string>): SkillVariant {\n // Opinionated full-stack frameworks first — they own their build pipeline\n // and have dedicated skill variants, so bundler detection underneath\n // them is irrelevant.\n if (deps.has('react-native')) return 'react-native';\n if (deps.has('nuxt')) return 'nuxt';\n if (deps.has('next')) return 'nextjs';\n if (deps.has('@angular/core')) return 'angular';\n // Bundlers next — prefer these over the bare `react` variant because\n // their skills are simpler (one bundler-plugin config) than wiring\n // posthog-cli into an arbitrary React setup.\n if (deps.has('vite')) return 'vite';\n if (deps.has('webpack')) return 'webpack';\n if (deps.has('rollup')) return 'rollup';\n // Plain React with no recognised bundler.\n if (deps.has('react')) return 'react';\n // Server-only Node project\n if (deps.has('posthog-node')) return 'node';\n // Fallback: generic web\n return 'web';\n}\n\nfunction selectVariant(signals: ProjectSignals): SkillVariant | null {\n // Mobile / native first — they don't coexist with JS bundlers in the\n // detection signals we look at.\n if (signals.hasPubspec) return 'flutter';\n if (signals.hasXcodeProject || signals.hasPodfile || signals.hasSwiftPackage)\n return 'ios';\n if (signals.hasGradle) return 'android';\n\n if (signals.packageJsons.length > 0) {\n // Union all deps across package.json files (covers monorepos)\n const allDeps = new Set<string>();\n for (const pkg of signals.packageJsons) {\n for (const dep of pkg.deps) allDeps.add(dep);\n }\n return pickJsVariant(allDeps);\n }\n\n return null;\n}\n\nfunction hasPostHogSdk(signals: ProjectSignals): boolean {\n for (const pkg of signals.packageJsons) {\n for (const sdk of POSTHOG_SDKS) {\n if (pkg.deps.has(sdk)) return true;\n }\n }\n // For native platforms the PostHog SDK lives outside package.json and\n // is detected by the agent during the skill run. Assume present here.\n return (\n signals.hasXcodeProject ||\n signals.hasPodfile ||\n signals.hasSwiftPackage ||\n signals.hasGradle ||\n signals.hasPubspec\n );\n}\n\n// ── Entry point ──────────────────────────────────────────────────────\n\nexport const SOURCE_MAPS_CONTEXT_KEYS = {\n skillVariant: 'sourceMapsSkillVariant',\n displayName: 'sourceMapsDisplayName',\n packagePaths: 'sourceMapsPackagePaths',\n detectError: 'detectError',\n // Set by the agentic picker once the user chooses a project to instrument.\n selectedVariant: 'sourceMapsSelectedVariant',\n selectedDisplayName: 'sourceMapsSelectedDisplayName',\n selectedPath: 'sourceMapsSelectedPath',\n} as const;\n\n/**\n * Scan `session.installDir` for platform / build-system signals. Writes\n * detection results into frameworkContext via the callback — either the\n * picked skill variant + display name, or a `SourceMapsDetectError`.\n *\n * The skill install happens later in the agent run, not here. This step\n * only picks which variant the prompt should ask the agent to load.\n */\nexport function detectSourceMapsPrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: SourceMapsDetectError) =>\n setFrameworkContext(SOURCE_MAPS_CONTEXT_KEYS.detectError, error);\n\n const installDir = session.installDir;\n\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n const signals = collectSignals(installDir);\n const variant = selectVariant(signals);\n\n // This program currently targets JS-like stacks only. Avoid selecting native\n // platforms until dedicated skill variants are available.\n if (\n variant &&\n ['react-native', 'flutter', 'ios', 'android'].includes(variant)\n ) {\n fail({ kind: 'unsupported-platform', detected: variant });\n return;\n }\n\n if (!variant) {\n if (signals.scannedFileCount === 0) {\n fail({ kind: 'no-project-files' });\n } else {\n fail({ kind: 'unsupported-platform', detected: 'unknown' });\n }\n return;\n }\n\n if (!hasPostHogSdk(signals)) {\n fail({ kind: 'no-posthog-sdk', platform: variant });\n return;\n }\n\n setFrameworkContext(SOURCE_MAPS_CONTEXT_KEYS.skillVariant, variant);\n setFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.displayName,\n DISPLAY_NAME[variant],\n );\n setFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.packagePaths,\n signals.packageJsons.map((p) => p.path),\n );\n}\n\nexport { DISPLAY_NAME as VARIANT_DISPLAY_NAME };\n","/**\n * Error tracking source maps upload program step list.\n *\n * Flow: a static intro (no detection yet) → login → an agentic detect+pick\n * screen that scans the repo on Haiku and lets the user choose a project →\n * agent run → outro. Detection runs after auth because the detection agent\n * needs credentials.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { RunPhase } from '@lib/wizard-session';\nimport { SOURCE_MAPS_CONTEXT_KEYS } from './detect.js';\n\nfunction projectSelected(session: WizardSession): boolean {\n return (\n session.frameworkContext[SOURCE_MAPS_CONTEXT_KEYS.selectedVariant] != null\n );\n}\n\nexport const ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'source-maps-intro',\n gate: (session) => session.setupConfirmed,\n },\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'detect',\n label: 'Detecting projects',\n // The Haiku agent scans the repo, surfaces an instrumentable / not-yet map,\n // and the user picks the project to wire up. Advances once a project is\n // chosen (its variant is written to frameworkContext). The gate lets the\n // agent runner park after auth until the pick lands, so the run prompt sees\n // the chosen variant.\n screenId: 'source-maps-detect',\n isComplete: projectSelected,\n gate: projectSelected,\n },\n {\n id: 'run',\n label: 'Upload source maps',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'source-maps-outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","import { AgentSignals } from '@lib/agent/agent-interface';\nimport type { SkillVariant } from './detect.js';\n\nexport type SourceMapsUploadPromptParams = {\n displayName: string | undefined;\n variant: SkillVariant;\n skillId: string;\n /** Project to instrument, relative to the repo root (\".\" or undefined = root). */\n projectPath?: string;\n projectId: number;\n host: string;\n settingsUrl: string;\n uiHost: string;\n};\n\nexport const SOURCE_MAPS_DETECTION_FAILED_PROMPT = `Detection did not pick a source maps skill variant for this project.\nEmit: ${AgentSignals.ABORT} unsupported-platform\nThen halt.`;\n\nexport function buildSourceMapsUploadPrompt(\n params: SourceMapsUploadPromptParams,\n): string {\n const {\n displayName,\n variant,\n skillId,\n projectPath,\n projectId,\n host,\n settingsUrl,\n uiHost,\n } = params;\n const platformLabel = displayName ?? variant;\n const inSubproject = projectPath != null && projectPath !== '.';\n const projectLine = inSubproject\n ? `- Project directory (relative to repo root): ${projectPath}`\n : '- Project directory: the repo root';\n\n return `You are wiring up PostHog Error Tracking source map upload for this ${platformLabel} project.\n\nProject context:\n- PostHog Project ID: ${projectId}\n- PostHog Host: ${host}\n- Detected platform: ${platformLabel}\n- Skill to use: ${skillId}\n${projectLine}\n- Personal API keys settings page: ${settingsUrl}\n\nAll file changes, build/run commands, and config edits target the project directory above${\n inSubproject\n ? ` — this is a monorepo, so scope your work to \\`${projectPath}\\` and do not touch other packages`\n : ''\n }.\n\nThe skill you install in STEP 2 is the source of truth for the HOW of every\nstep: its \"## Steps\" section has an overview, tips and per-technology\nexamples for each named step, and its reference files carry the exact\nper-framework API. The STEPS below give the order, the conditionals, and the\nwizard-specific mechanics (which MCP tool to call, signals to emit) — read\nthe matching skill step (named in parentheses) before doing the work, and do\nnot invent steps the skill doesn't describe.\n\nFollow these steps IN ORDER. Do not skip or reorder.\n\nYour FIRST message must contain ONLY parallel tool calls, in this order:\n - the STEP 1 wizard_ask call FIRST — tool calls execute as they stream,\n so this puts the API-key prompt in front of the user within seconds —\n then\n - one TaskCreate call PER task below, all in this same message (the tool\n takes a single task per call). The TUI shows only the subject, so keep\n every description to a few words — never a sentence.\nDo not read files, explore the project, or write any text first, and keep\nany thinking before the calls to a single short sentence.\n\nUse exactly these tasks, in this order — do not collapse, rename, or omit\nany of them. Getting the API key is NOT a task — its prompt is already on\nscreen by the time the list renders:\n 1. Install source maps skill\n 2. Apply build-config changes (per skill)\n 3. Make credentials readable at build time\n 4. Write keys to .env\n 5. Identify build & run commands\n 6. Set up CI for auto-upload\n 7. Test the local setup\n 8. Summarise & hand off\nDrive the list with TaskUpdate — mark a task in_progress when you start it\nand completed when done. ALWAYS keep task 7 (\"Test the local setup\") in the\nlist even if the user declines it in STEP 8: mark it completed rather than\ndeleting it, so the user can see it was offered.\n\nSTEP 1 — Get a personal API key from the user. (skill: \"Get a personal API key\")\n This wizard_ask call ships in your FIRST message, per the rule above.\n The wizard cannot mint keys — never call the PostHog API or any tool to\n create one. Ask the user with the wizard_ask MCP tool; you receive the\n answer as a vaulted secretRef (never the raw value), which you reuse in\n STEP 5:\n {\n id: \"api-key\",\n prompt: \"Paste your PostHog personal API key below.\\\\n\\\\nDon't have one yet? Create one here:\\\\n${settingsUrl}\\\\n\\\\nWhen creating the key, choose the 'Source map upload' preset, then come back and paste it here.\",\n kind: \"text\",\n sensitive: true\n }\n Keep the \\\\n line breaks exactly as written — Ink's <Text> renders them\n as separate lines. The answer is { secretRef: \"secret:...\" }.\n If wizard_ask is unavailable (CI / non-interactive), emit\n ${AgentSignals.ABORT} requires-interactive-mode and halt.\n\nSTEP 2 — Install the skill.\n Call install_skill (wizard-tools MCP server) with skillId \"${skillId}\".\n Do NOT run shell commands to install skills. Then read the installed\n SKILL.md and its reference files — they drive STEPS 3-9.\n If install fails, emit ${\n AgentSignals.ERROR_RESOURCE_MISSING\n } skill ${skillId} could not be installed.\n\nSTEP 3 — Apply build-config changes. (skill: \"Apply build-config changes\")\n Make the bundler / build-config changes the skill's step instructs. The\n skill and its reference are the source of truth for this platform.\n\nSTEP 4 — Make the credentials readable at build time. (skill: \"Make credentials available at build time\")\n Follow the skill's step. Wizard-specific: if it calls for a loader (e.g.\n \\`dotenv\\`), install it SILENTLY — do NOT ask the user or call wizard_ask.\n Skip this step entirely if the platform already auto-loads .env.\n\nSTEP 5 — Write the credentials to the env file. (skill: \"Write credentials to the env file\")\n Use the wizard-tools MCP server. Reuse the env file the skill tells you to\n pick — the prerequisite PostHog integration usually already wrote\n POSTHOG_* vars to one, so seed your keys alongside them.\n - First call check_env_keys on that file (returns present/absent, never\n values — don't read the file directly).\n - Then call set_env_values, passing the STEP 1 secretRef as a value\n object, not a literal string:\n values: {\n \"POSTHOG_CLI_API_KEY\": { secretRef: \"<the ref from STEP 1>\" },\n \"POSTHOG_CLI_PROJECT_ID\": \"${projectId}\",\n \"POSTHOG_CLI_HOST\": \"${host}\"\n }\n Variable names follow the skill's per-uploader conventions. The wizard\n resolves the ref locally before writing, so you never see the key value.\n\nSTEP 6 — Identify the build AND run commands. (skill: \"Identify the build and run commands\")\n Per the skill, resolve the production BUILD command and the RUN command\n for THIS project (use detect_package_manager for the package manager). Do\n NOT run either yourself — the user runs them. If you cannot identify a\n build command, emit ${AgentSignals.ABORT} build command not found.\n\nSTEP 7 — Set up CI for automatic uploads. (skill: \"Set up CI for automatic uploads\")\n Source maps only upload when the production build runs, so the build's\n CI/CD must carry the same upload credentials you wrote in STEP 5. Do this\n step without asking — there is no opt-in question for it. Follow the\n skill's \"Set up CI for automatic uploads\" step — it is the source of\n truth for tracing where the production build runs and wiring the\n credentials through every layer, whatever the CI provider.\n Wizard-specific rules on top:\n - Trace the deploy path by reading the project's files — do NOT ask the\n user, and do NOT invent config that isn't there.\n - Carry every manual follow-up the skill has you hand off (secrets the\n user must create, an untraceable build path) into STEP 9.\n\nSTEP 8 — Offer to test the local setup. (skill: \"Test the local setup\")\n Call wizard_ask:\n {\n id: \"test-affordance\",\n prompt: \"Want me to help you test your local setup? I'll add a temporary test button (or route) to your app so you can confirm errors show up in Error Tracking with readable stack traces after your next build. I'll remove it once you've confirmed it works.\",\n kind: \"single\",\n options: [\n { label: \"Yes, help me test it\", value: \"yes\" },\n { label: \"No, I'll test on my own later\", value: \"no\" }\n ]\n }\n\n If \"no\", skip to STEP 9.\n\n If \"yes\", follow the skill's \"Test the local setup\" step for the\n platform-appropriate affordance, the captureException shape, the\n placement, and the read-before-edit / always-revert rules. Then pause for\n the user with wizard_ask, baking the EXACT build and run commands from\n STEP 6 (and the exact button label / route) into the prompt as literal,\n copy-pasteable steps. Separate each numbered step with \\\\n\\\\n so the TUI\n renders them as distinct lines:\n {\n id: \"test-done\",\n prompt: \"1) Run \\`<your detected build command>\\` to upload source maps and build the app with the test affordance.\\\\n\\\\n2) Start the app with \\`<your detected run command>\\`, then click the \\\\\"<your test button label>\\\\\" button (or hit \\`<your test route>\\`).\\\\n\\\\n3) Open Error Tracking in PostHog (${uiHost}/project/${projectId}/error_tracking) and confirm the test error appears with a source-resolved stack trace pointing at real source files (not minified bundle paths).\\\\n\\\\nWhen you're done, select Continue and I'll revert the test code.\",\n kind: \"single\",\n options: [{ label: \"Continue (revert test code)\", value: \"continue\" }]\n }\n After the user continues, revert the test code per the skill's rules and\n surface any failure in STEP 9.\n\nSTEP 9 — Summarise and hand off. (skill: \"Verify and hand off\")\n Follow the skill's \"Verify and hand off\" step. The Symbol sets page for\n this project — where the user confirms the upload landed — is:\n ${uiHost}/project/${projectId}/error_tracking/configuration\n`;\n}\n","/**\n * Source-maps learn-deck — the narrative played in the run screen's left\n * pane (LearnCard) while the agent wires source-map upload into the build.\n *\n * It educates the user on what source maps are and why uploading them\n * matters, built around a before/after stack-trace contrast: a minified\n * production trace nobody can read, then the same trace resolved back to\n * real source. Program-owned; wired onto the program's getContentBlocks.\n *\n * Lines stay narrow (~36 cols) because this renders in the left half of a\n * split pane — see LearnCard's paneWidth math.\n */\n\nimport { Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { WizardStore } from '@ui/tui/store';\nimport { TextRevealMode } from '@ui/tui/primitives/TextBlock';\nimport {\n isClearBlock,\n type ContentBlock,\n} from '@ui/tui/primitives/content-types';\nimport { StatusPeekTrigger } from '@ui/tui/components/StatusPeekTrigger';\n\n/**\n * Per-slide dwell multiplier. Each block stays on screen for `pause * SLIDE_PACE`\n * ms after it finishes animating, before the deck advances. Bump this single\n * knob to give every slide more reading time. Clear (page-break) blocks are\n * left untouched so the blank gap between slides stays snappy.\n */\nconst SLIDE_PACE = 1.5;\n\nconst withPace = (block: ContentBlock): ContentBlock => {\n if (typeof block === 'string' || isClearBlock(block) || block.pause == null) {\n return block;\n }\n return { ...block, pause: Math.round(block.pause * SLIDE_PACE) };\n};\n\n/** Apply the dwell multiplier to every block in a deck. */\nconst pace = (blocks: ContentBlock[]): ContentBlock[] => blocks.map(withPace);\n\n/**\n * A minified production stack trace — the problem source maps solve. Framed as\n * a labelled, muted example (no error-red ✘) so a glance reads it as\n * illustrative content, not as the wizard itself having errored mid-run.\n */\nconst MINIFIED_TRACE: ContentBlock = {\n type: 'lines',\n interval: 400,\n pause: 7000,\n lines: [\n <Text dimColor>{'example — minified production trace'}</Text>,\n <Text color={Colors.muted}>{' TypeError: cart is undefined'}</Text>,\n <Text dimColor>{' at t.min.js:1:48213'}</Text>,\n <Text dimColor>{' at t.min.js:1:9402'}</Text>,\n <Text dimColor>{' at t.min.js:1:71150'}</Text>,\n ],\n};\n\n/** The same trace, resolved through uploaded source maps. */\nconst RESOLVED_TRACE: ContentBlock = {\n type: 'lines',\n interval: 400,\n pause: 8000,\n lines: [\n <Text dimColor>{'example — resolved with source maps'}</Text>,\n <Text color={Colors.success}>{' ✔ TypeError: cart is undefined'}</Text>,\n <Text>\n <Text dimColor>{' at '}</Text>\n <Text color=\"cyan\">Cart.tsx:42</Text>\n <Text dimColor>{' loadCart'}</Text>\n </Text>,\n <Text>\n <Text dimColor>{' at '}</Text>\n <Text color=\"cyan\">App.tsx:88</Text>\n <Text dimColor>{' render'}</Text>\n </Text>,\n <Text>\n <Text dimColor>{' at '}</Text>\n <Text color=\"cyan\">index.tsx:5</Text>\n <Text dimColor>{' main'}</Text>\n </Text>,\n ],\n};\n\n/**\n * How a bundle is tied to its map: PostHog injects a chunk-ID marker into the\n * built JS and stamps the matching source map with the same ID.\n */\nconst CHUNK_ID_LINK: ContentBlock = {\n type: 'lines',\n interval: 450,\n pause: 7500,\n lines: [\n <Text dimColor>app.min.js</Text>,\n <Text dimColor>{' …minified code…'}</Text>,\n <Text>\n <Text color=\"cyan\">{' //# chunkId=a1b2c3d4'}</Text>\n <Text dimColor>{' ← injected'}</Text>\n </Text>,\n <Text dimColor>{' ↕ matched by id'}</Text>,\n <Text>\n <Text dimColor>app.min.js.map</Text>\n <Text dimColor>{' ← uploaded'}</Text>\n </Text>,\n ],\n};\n\n/** Many similar exceptions collapse into a single issue. */\nconst GROUPING: ContentBlock = {\n type: 'lines',\n interval: 450,\n pause: 7000,\n lines: [\n <Text dimColor>{'exception ─┐'}</Text>,\n <Text>\n <Text dimColor>{'exception ─┼──→ '}</Text>\n <Text color={Colors.accent} bold>\n 1 issue\n </Text>\n </Text>,\n <Text dimColor>{'exception ─┘'}</Text>,\n ],\n};\n\nexport const getContentBlocks = (store?: WizardStore): ContentBlock[] =>\n pace([\n {\n content: 'Welcome.',\n pause: 3000,\n mode: TextRevealMode.Typewriter,\n animationInterval: 160,\n },\n\n {\n content: \"I'm wiring PostHog Error Tracking into your build.\",\n pause: 5000,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'When you ship to production, your code gets minified.',\n pause: 5000,\n },\n {\n content: 'Thousands of readable lines collapse into one dense bundle.',\n pause: 5000,\n },\n {\n content: 'So a thrown error gives you a stack trace like this:',\n pause: 2000,\n },\n\n MINIFIED_TRACE,\n\n { content: 'Just offsets into a file no human can read.', pause: 5000 },\n\n { type: 'clear', pause: 1500 },\n\n { content: 'Source maps are the key.', pause: 3500 },\n {\n content:\n 'They map every position in that bundle back to your original source — the real file, line, and function.',\n pause: 6000,\n },\n {\n content:\n \"Right now I'm hooking source-map generation and upload into your build, tied to each release you ship.\",\n pause: 6000,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'But how does PostHog know which map belongs to which build?',\n pause: 4500,\n },\n {\n content:\n 'During the build, it injects a unique chunk ID into each bundle:',\n pause: 2500,\n },\n\n CHUNK_ID_LINK,\n\n {\n content:\n 'The matching source map is stamped with that same ID before it ships to PostHog.',\n pause: 6000,\n },\n {\n content:\n 'When an error comes in, PostHog reads the chunk ID off the bundle, finds the map with the exact same ID, and uses it to map each frame back to your source — even for a release you shipped weeks ago.',\n pause: 8000,\n },\n\n { type: 'clear', pause: 1500 },\n\n { content: 'So that same error becomes:', pause: 2000 },\n\n RESOLVED_TRACE,\n\n {\n content: 'Readable stack traces, straight from production.',\n pause: 5000,\n },\n {\n content: 'You debug a live error like it happened on your own machine.',\n pause: 6000,\n },\n\n { type: 'clear', pause: 1500 },\n\n { content: 'Zooming out — this is how Error Tracking works.', pause: 4000 },\n {\n content: 'Every error your app throws is captured as an exception.',\n pause: 5000,\n },\n {\n content: 'PostHog groups similar exceptions into a single issue:',\n pause: 2500,\n },\n\n GROUPING,\n\n {\n content:\n 'So a bug that fires ten thousand times is one issue to triage — not ten thousand alerts.',\n pause: 6500,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'And this is where source maps earn their keep again.',\n pause: 4500,\n },\n {\n content:\n 'Grouping reads the stack trace. Minified frames all look alike — so unrelated crashes get merged, and one real bug scatters across many issues.',\n pause: 8000,\n },\n {\n content:\n 'With source maps, PostHog groups on your real frames — so each distinct bug lands as one clean issue.',\n pause: 7000,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n pause: 5000,\n persist: true,\n content: <StatusPeekTrigger store={store} />,\n },\n {\n pause: 90000,\n content: (\n <Text>\n Press{' '}\n <Text color={Colors.accent} bold>\n S\n </Text>{' '}\n to follow along — or sit tight, I'll let you know when it's done.\n </Text>\n ),\n },\n ]);\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { OutroKind } from '@lib/wizard-session';\nimport { ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM } from './steps.js';\nimport {\n buildSourceMapsUploadPrompt,\n SOURCE_MAPS_DETECTION_FAILED_PROMPT,\n} from './prompt.js';\nimport {\n SOURCE_MAPS_ABORT_CASES,\n SOURCE_MAPS_CONTEXT_KEYS,\n type SkillVariant,\n} from './detect.js';\nimport { getContentBlocks } from './content/index.js';\nimport { getUiHostFromHost } from '@utils/urls';\nimport { getUI } from '@ui';\n\nconst REPORT_FILE = 'posthog-source-maps-report.md';\nconst DOCS_URL = 'https://posthog.com/docs/error-tracking/upload-source-maps';\n\nexport const errorTrackingUploadSourceMapsConfig: ProgramConfig = {\n command: 'upload-source-maps',\n description: 'Upload source maps to PostHog Error Tracking',\n id: 'error-tracking-upload-source-maps',\n requiresAi: true,\n steps: ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM,\n reportFile: REPORT_FILE,\n getContentBlocks,\n requires: ['posthog-integration'],\n\n run: (_session: WizardSession): Promise<ProgramRun> => {\n // Read the picked project LIVE at prompt-build time, not here: the picker\n // screen runs AFTER this run config is resolved (post-auth), and the store\n // forks the session reference, so the `session` passed in never sees the\n // choice. getUI().getFrameworkContext reads the live store session.\n const readSelection = () => {\n const variant = getUI().getFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.selectedVariant,\n ) as SkillVariant | undefined;\n const displayName = getUI().getFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.selectedDisplayName,\n ) as string | undefined;\n const projectPath = getUI().getFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.selectedPath,\n ) as string | undefined;\n const skillId = variant\n ? `error-tracking-upload-source-maps-${variant}`\n : undefined;\n return { variant, displayName, projectPath, skillId };\n };\n\n return Promise.resolve({\n integrationLabel: 'error-tracking-upload-source-maps',\n // Skill is installed by the agent (after the API-key choice is made)\n // rather than pre-installed by the runner, so leave skillId unset.\n successMessage: 'Source maps wired up!',\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n spinnerMessage: 'Wiring up source maps...',\n estimatedDurationMinutes: 3,\n abortCases: SOURCE_MAPS_ABORT_CASES,\n // The flow parks on wizard_ask while the user does slow work — create\n // a personal API key in the browser (STEP 1), or run a production\n // build, trigger the test error, and check Error Tracking (STEP 8).\n // The 5-minute default cancels the question mid-task and the agent\n // wraps up to the outro, so give these answers half an hour.\n askTimeoutMs: 30 * 60 * 1000,\n\n customPrompt: (ctx) => {\n const { variant, displayName, projectPath, skillId } = readSelection();\n if (!skillId || !variant) {\n // No project was selected — abort with a structured signal so the\n // runner renders a friendly outro.\n return SOURCE_MAPS_DETECTION_FAILED_PROMPT;\n }\n\n const uiHost = getUiHostFromHost(ctx.host).replace(/\\/$/, '');\n\n return buildSourceMapsUploadPrompt({\n displayName,\n variant,\n skillId,\n projectPath,\n projectId: ctx.projectId,\n host: ctx.host,\n settingsUrl: `${uiHost}/project/${ctx.projectId}/settings/user-api-keys`,\n uiHost,\n });\n },\n\n postRun: () => {\n // Stash a hint for the outro about what variant we shipped.\n const { variant } = readSelection();\n if (variant) {\n getUI().setFrameworkContext('sourceMapsCompletedVariant', variant);\n }\n return Promise.resolve();\n },\n\n buildOutroData: () => {\n // SourceMapsOutroScreen renders static \"what we did + how it works\"\n // guidance, so no per-run `changes` list is needed here.\n return {\n kind: OutroKind.Success as const,\n message: 'Source maps wired up!',\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n };\n },\n });\n },\n};\n\nexport { ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM } from './steps.js';\nexport {\n detectSourceMapsPrerequisites,\n SOURCE_MAPS_ABORT_CASES,\n SOURCE_MAPS_CONTEXT_KEYS,\n VARIANT_DISPLAY_NAME,\n type SkillVariant,\n type SourceMapsDetectError,\n} from './detect.js';\n","/**\n * Self-driving prerequisite detection + abort vocabulary.\n *\n * The only thing worth verifying before auth is local and cheap: that\n * `session.installDir` is a real, readable directory. We deliberately do\n * NOT require the base posthog-integration report to be present — it is a\n * report many users never commit, and `requires: ['posthog-integration']`\n * is metadata, not a hard runtime gate. Real readiness (integration state\n * + beta access) is established by the agent's STEP 1 Signals API probe at\n * the start of the run. The beta gates (the `product-autonomy` access flag\n * and `signals-scout` enrollment — PostHog-side flag names, unchanged by\n * the wizard-side \"self-driving\" rename) are PostHog-internal flags with no\n * customer-facing read API, which is why that probe lives in the run and\n * emits a structured `[ABORT]` when the product is not available.\n */\n\nimport { existsSync, statSync } from 'fs';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\n\n/**\n * Structured detection errors. The intro screen renders each kind into\n * JSX — keeps error data separate from presentation.\n */\nexport type SelfDrivingDetectError = {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n};\n\n/**\n * `[ABORT] <reason>` cases the self-driving skill can emit. The\n * reason strings are part of the skill contract — the context-mill\n * `self-driving-setup` skill emits these exact strings.\n */\nexport const SELF_DRIVING_ABORT_CASES: AbortCase[] = [\n {\n // Skill emits: [ABORT] self-driving is not available for this project\n match: /^self-driving is not available for this project$/i,\n message: 'PostHog Self-driving is not available for this project',\n body:\n 'Self-driving is in beta and is enabled per ' +\n 'team by PostHog. This project does not appear to have access yet. ' +\n 'Reach out to your PostHog contact (or wizard@posthog.com) to join ' +\n 'the beta, then run the wizard again.',\n },\n {\n // Skill emits: [ABORT] github connection declined\n match: /^github connection declined$/i,\n message: 'GitHub connection required',\n body:\n 'Self-driving needs GitHub access to research issues in your code and ' +\n 'open fixes, so setup cannot finish without it. Nothing was left ' +\n 'half-configured. When you are ready to install the PostHog GitHub ' +\n 'App, run the wizard again.',\n },\n {\n // Skill emits: [ABORT] requires-interactive-mode\n match: /^requires-interactive-mode$/i,\n message: 'Interactive terminal required',\n body:\n 'Self-driving setup asks questions along the way (GitHub and ' +\n 'issue trackers), so it needs an interactive terminal. Run ' +\n 'the wizard outside CI / non-interactive mode.',\n },\n {\n // The wizard_ask tool's own error texts (non-interactive host, ask cap\n // reached) instruct the agent to emit this reason — cover it so those\n // paths render a friendly screen instead of the generic abort outro.\n match: /^requirements-incomplete$/i,\n message: 'Setup needs your input',\n body:\n 'The wizard could not collect the answers this setup needs (the ' +\n 'environment was non-interactive, or the question budget ran out). ' +\n 'Nothing was left half-configured. Run the wizard again in an ' +\n 'interactive terminal.',\n },\n];\n\n/**\n * Verify `session.installDir` is a readable directory. Writes a\n * `SelfDrivingDetectError` to frameworkContext on failure — the intro\n * screen renders it and blocks.\n */\nexport function detectSelfDrivingPrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: SelfDrivingDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n}\n","/**\n * Self-driving program step list.\n *\n * detect → intro → health-check → auth → run → outro. No keep-skills\n * step: the setup skill is transient orchestration knowledge the user\n * won't reuse, so postRun removes it instead of prompting.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\nimport { detectSelfDrivingPrerequisites } from './detect.js';\n\nexport const SELF_DRIVING_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting prerequisites',\n // Headless step: no screen, no gate. onReady fires after bin.ts\n // assigns the session — verifies the PostHog setup report exists\n // and writes a detectError to frameworkContext for the intro\n // screen to render when it doesn't.\n onReady: (ctx) =>\n detectSelfDrivingPrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'self-driving-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Self-driving',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n];\n","import { AgentSignals } from '@lib/agent/agent-interface';\nimport type { PromptContext } from '@lib/agent/agent-runner';\nimport { getUiHostFromHost } from '@utils/urls';\n\n/**\n * Build the self-driving run prompt. The installed\n * `self-driving-setup` skill is the source of truth for the HOW of\n * every step (which MCP tools to call, which sources/scouts apply, how\n * to verify); this prompt carries the order, the wizard-specific\n * mechanics (wizard_ask, abort signals), and the project URLs.\n */\nexport function buildSelfDrivingPrompt(ctx: PromptContext): string {\n const uiHost = getUiHostFromHost(ctx.host).replace(/\\/$/, '');\n const projectBase = `${uiHost}/project/${ctx.projectId}`;\n const integrationsSettingsUrl = `${projectBase}/settings/environment-integrations`;\n const orgAiSettingsUrl = `${uiHost}/settings/organization#organization-ai-consent`;\n const newWarehouseSourceUrl = `${projectBase}/pipeline/new/source`;\n const inboxUrl = `${projectBase}/inbox`;\n const optIn = (value: boolean | null | undefined): string =>\n value === true ? 'ON' : value === false ? 'OFF' : 'unknown';\n const optIns = ctx.teamProductOptIns;\n\n return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources, make sure GitHub is connected, tune the scout troop, design custom scouts for what this product uniquely needs, and hand the user a configured inbox.\n\nProject URLs:\n- Integrations settings: ${integrationsSettingsUrl}\n- Organization AI settings: ${orgAiSettingsUrl}\n- New data warehouse source (Linear / Zendesk / GitHub issues / pganalyze): ${newWarehouseSourceUrl}\n- Self-driving inbox: ${inboxUrl}\n\nProject state read at auth time (PostHog project settings — authoritative\nfor whether a product is enabled, regardless of what this repo\ninstruments; products are often instrumented from other repos or the\nsnippet, so repo evidence may rule a product IN but never OUT):\n- Session replay recording: ${optIn(optIns?.sessionReplay)}\n- Exception autocapture (error tracking): ${optIn(optIns?.exceptionAutocapture)}\n- Surveys: ${optIn(optIns?.surveys)}\n\nThe installed skill is the source of truth for the HOW of every step:\nwhich MCP tools to call, which sources and scouts apply to this product,\nand how to verify each change. The STEPS below give the order and the\nwizard-specific mechanics — read the matching skill reference before\ndoing the work, and do not invent steps the skill doesn't describe.\n\nBefore doing any work, create your FULL task list in a single TaskCreate\ncall so the user can follow your progress in the TUI. Use exactly these\ntasks, in this order:\n 1. Check Self-driving access\n 2. Read project and current Self-driving state\n 3. Connect GitHub (required)\n 4. Enable signal sources\n 5. Offer issue-tracker integrations\n 6. Configure the scout troop\n 7. Design custom scouts\n 8. Write report and hand off\nDrive the list with TaskUpdate — mark a task in_progress when you start\nit and completed when done. If a step turns out to be a no-op (e.g.\nGitHub is already connected), still mark its task completed.\n\nWizard mechanics:\n- Ask the user things ONLY with the wizard_ask MCP tool, and batch\n related questions (e.g. one multi-select for all issue trackers, not\n one ask per tool). The per-run ask budget is limited.\n- If wizard_ask is unavailable (CI / non-interactive), emit\n ${AgentSignals.ABORT} requires-interactive-mode and halt.\n- When a step requires the user to do something in the browser, give\n them the exact URL inside the wizard_ask prompt text — do not try to\n open a browser yourself.\n- Emit ${AgentSignals.STATUS} lines as you complete each step so the\n user sees progress.\n\nFollow these steps IN ORDER. Do not skip or reorder.\n\nSTEP 1 — Check Self-driving access. (skill: \"Check access\")\n Probe the Signals API as the skill describes. If the API is not\n available for this project (permission or not-found errors), emit\n ${AgentSignals.ABORT} self-driving is not available for this project\n and halt.\n\nSTEP 2 — Read project and current Signals state. (skill: \"Read context\")\n If ./posthog-setup-report.md exists, read it as a strong hint for what\n THIS repo instruments — but it is often absent (users frequently don't\n commit it), so do NOT depend on it. Combine whatever you find with the\n project-state block above and the skill's server-side usage probes —\n repo evidence rules products in, never out. Do a light scan ONLY for\n what neither covers. List the currently enabled signal sources so every\n later write is idempotent.\n\nSTEP 3 — Connect GitHub. REQUIRED. (skill: \"Connect GitHub\")\n Signals cannot research or fix issues without code access. Check for\n an existing GitHub integration first; if absent, send the user\n through the GitHub App connection via wizard_ask exactly as the skill\n describes (it builds the one-click authorize link), and verify the\n connection after they confirm. If the user cannot connect now, emit\n ${AgentSignals.ABORT} github connection declined\n and halt — never finish setup without GitHub.\n\nSTEP 4 — Enable signal sources. (skill: \"Enable sources\")\n Enable the sources that match what this product actually uses, per\n the skill. Never enable a source for a tool the user hasn't\n confirmed they use.\n\nSTEP 5 — Offer issue-tracker integrations. (skill: \"Connected tools\")\n One batched multi-select wizard_ask for the external tools the skill\n lists. The run auto-connects the ones it can (GitHub Issues, and\n Linear via a one-click OAuth link), verifying each with a single\n silent check — never nudge. It arms the rest as dormant responders to\n finish later: for tools it can't auto-connect (Zendesk, pganalyze) it\n never sends the user to paste credentials and never re-prompts. Enable\n a source only for a tool the user picked.\n\nSTEP 6 — Configure the scout troop. (skill: \"Scouts\")\n Materialize the troop, then enable only a small set — the \"general\"\n scout plus the one or two specialists for the products this project\n uses most — and disable the rest, per the skill.\n\nSTEP 7 — Design custom scouts for this product. (skill: \"Custom scouts\")\n You are the only actor that has read this repo — turn that into\n coverage per the skill: a real gap analysis of the project's\n watchable surfaces against what the built-in troop already covers,\n then custom scouts for the uncovered ones. Keep scout bodies\n high-level: describe the behavior and signal conditions to watch,\n referencing repo evidence by file/function name — never paste raw\n source, secrets, env values, or customer data into a scout body.\n Never edit built-in scout bodies. Propose all candidates in ONE\n batched wizard_ask\n before creating anything; the user declining everything (or finding\n no gap at all) is a valid outcome, not an abort. Mark the task\n completed either way.\n\nSTEP 8 — Write the report and hand off. (skill: \"Report\")\n Write the report per the skill, including follow-ups for anything\n deferred. Tell the user findings will start appearing in their inbox\n at ${inboxUrl} within about 30 minutes.`;\n}\n","/**\n * Sidebar tips for the self-driving run. Unlike the generic\n * onboarding tips (`DEFAULT_TIPS`), these explain Signals' core nouns —\n * signal sources and scouts — in plain language, so the agent's\n * questions during the run land with a user who's never seen the terms.\n *\n * Product knowledge lives here in the program, not in the generic\n * `TipsCard`. Wired onto the program's `getTips`.\n */\n\nimport type { Tip } from '@ui/tui/components/TipsCard';\n\nexport const SELF_DRIVING_TIPS: Tip[] = [\n {\n id: 'what-is-a-signal-source',\n title: \"What's a signal source?\",\n description:\n 'A signal source is one of the streams PostHog plugs straight into — your errors, session replays, support, GitHub or Linear issues. Each one watches its own stream and speaks up the moment something specific goes wrong there.',\n },\n {\n id: 'what-is-a-scout',\n title: \"What's a scout?\",\n description:\n 'A scout is like an analyst PostHog runs for you on a schedule: rather than watching one stream, it ranges freely across your product data, looking for the bigger trends and surprises — a spike in errors, a funnel quietly dropping — that no single stream would catch.',\n },\n {\n id: 'findings-in-inbox',\n title: 'Findings land in your inbox',\n description:\n 'Once setup finishes, PostHog starts scanning within ~30 minutes and surfaces what it finds in your Self-driving inbox — grouped, researched, and ready to act on.',\n },\n];\n\nexport const getTips = (): Tip[] => SELF_DRIVING_TIPS;\n","import { join } from 'path';\nimport { access, rm } from 'node:fs/promises';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport { OutroKind } from '@lib/wizard-session';\nimport { getUiHostFromHost } from '@utils/urls';\nimport { createSkillProgram } from '../agent-skill/index.js';\nimport { getContentBlocks as agentSkillContentBlocks } from '../agent-skill/content/index.js';\nimport { SELF_DRIVING_PROGRAM } from './steps.js';\nimport { SELF_DRIVING_ABORT_CASES } from './detect.js';\nimport { buildSelfDrivingPrompt } from './prompt.js';\nimport { getTips } from './content/tips.js';\n\nexport const SELF_DRIVING_SKILL_ID = 'self-driving-setup';\nconst REPORT_FILE = 'posthog-self-driving-report.md';\nconst DOCS_URL = 'https://posthog.com/docs';\nconst SUCCESS_MESSAGE =\n 'Self-driving is on! PostHog will start scanning within ~30 minutes ' +\n 'and surface findings in your inbox.';\nconst WIZARD_MARKER = '.posthog-wizard';\n\n/**\n * Remove the installed setup skill. It is transient orchestration\n * knowledge (unlike integration skills such as the Next.js one, which\n * are worth keeping for the user's coding agents), so the program\n * cleans it up instead of showing the keep-skills prompt. Marker-\n * guarded: only directories the wizard installed are touched.\n */\nasync function removeInstalledSkill(installDir: string): Promise<void> {\n const skillDir = join(installDir, '.claude', 'skills', SELF_DRIVING_SKILL_ID);\n try {\n await access(join(skillDir, WIZARD_MARKER));\n } catch {\n return;\n }\n await rm(skillDir, { recursive: true, force: true }).catch(() => undefined);\n}\n\nconst run: ProgramRun = {\n skillId: SELF_DRIVING_SKILL_ID,\n integrationLabel: SELF_DRIVING_SKILL_ID,\n customPrompt: buildSelfDrivingPrompt,\n successMessage: SUCCESS_MESSAGE,\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n spinnerMessage: 'Setting up PostHog Self-driving...',\n estimatedDurationMinutes: 10,\n abortCases: SELF_DRIVING_ABORT_CASES,\n // The flow legitimately needs several interactions (GitHub connect +\n // verify, issue-tracker picks, the scout-tailoring proposal), so raise\n // the wizard_ask budget a little above the default 10.\n maxQuestions: 13,\n // This flow hands the user long OAuth/authorize URLs (Linear, GitHub\n // fallback, Zendesk) in wizard_ask prompts. Render them as OSC 8\n // hyperlinks + clipboard copy so the overlay's line wrapping can't break\n // the click target. Scoped to this program only.\n richLinks: true,\n // STEP 3 (GitHub App install) and STEP 5 (Linear OAuth) park on wizard_ask\n // while the user does slow browser work; a first-time GitHub App install\n // routinely exceeds the 5-min default, and a timeout is indistinguishable\n // from a decline (both resolve to __cancelled__). Match upload-source-maps.\n askTimeoutMs: 30 * 60 * 1000,\n\n postRun: async (session) => {\n await removeInstalledSkill(session.installDir);\n },\n\n buildOutroData: (_session, credentials) => {\n const uiHost = getUiHostFromHost(credentials.host).replace(/\\/$/, '');\n const inboxUrl = `${uiHost}/project/${credentials.projectId}/inbox`;\n return {\n kind: OutroKind.Success as const,\n message:\n 'Self-driving is on. PostHog is scanning your project — ' +\n 'first findings hit your inbox within ~30 minutes.',\n primaryLink: { label: 'Your Self-driving inbox', url: inboxUrl },\n nextSteps: {\n heading: 'In your inbox you can:',\n items: [\n 'Review the findings PostHog surfaces',\n 'Triage what matters and dismiss the noise',\n 'Kick off fixes and open issues',\n ],\n },\n reportFile: REPORT_FILE,\n };\n },\n};\n\nexport const selfDrivingConfig: ProgramConfig = {\n ...createSkillProgram({\n skillId: SELF_DRIVING_SKILL_ID,\n command: 'self-driving',\n id: 'self-driving',\n description: 'Set up PostHog Self-driving for this project',\n integrationLabel: SELF_DRIVING_SKILL_ID,\n successMessage: SUCCESS_MESSAGE,\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n spinnerMessage: 'Setting up PostHog Self-driving...',\n estimatedDurationMinutes: 10,\n requires: ['posthog-integration'],\n abortCases: SELF_DRIVING_ABORT_CASES,\n }),\n steps: SELF_DRIVING_PROGRAM,\n run,\n getTips,\n // The shared agent-skill Learn deck lingers ~60s on its last block before\n // RunScreen flips to the Self-driving Tips pane; shorten that final pause\n // so the scout/source/inbox tips appear promptly (the Tasks pane already\n // shows progress). Same deck, just a quicker hand-off.\n getContentBlocks: (store) => {\n const blocks = agentSkillContentBlocks(store);\n return blocks.map((b, i) =>\n i === blocks.length - 1 && typeof b === 'object'\n ? { ...b, pause: 5000 }\n : b,\n );\n },\n};\n\nexport { SELF_DRIVING_PROGRAM } from './steps.js';\nexport {\n detectSelfDrivingPrerequisites,\n SELF_DRIVING_ABORT_CASES,\n type SelfDrivingDetectError,\n} from './detect.js';\n","/**\n * MCP add / remove / tutorial programs.\n *\n * None of these run the agent pipeline — they're TUI-only flows invoked\n * by the `mcp add` / `mcp remove` / `mcp tutorial` subcommands in\n * bin.ts. They live in the program registry so the screen sequence is\n * derived alongside every other program (no special-cases in\n * screen-sequences.ts).\n */\n\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport { McpOutcome } from '@lib/wizard-session';\n\nexport const mcpAddConfig: ProgramConfig = {\n id: 'mcp-add',\n requiresAi: false,\n description: 'Add PostHog MCP server to supported clients',\n // Order: install → Slack → tutorial. Slack runs before the tutorial\n // because it renders gracefully without credentials (no surprise\n // OAuth on the loginless install path). The tutorial is last so its\n // explicit \"Start tutorial\" opt-in is the moment OAuth fires — and\n // skipping the tutorial doesn't bury Slack discovery behind a\n // dismissal screen.\n steps: [\n {\n id: 'mcp-add',\n label: 'Add MCP server',\n screenId: 'mcp-add',\n isComplete: (s) => s.mcpComplete,\n },\n {\n id: 'slack-connect',\n label: 'Connect Slack',\n screenId: 'slack-connect',\n // Gate on a successful install so no-clients / skipped / failed\n // outcomes go straight to program end without a \"what's next\" prompt.\n show: (s) => s.mcpOutcome === McpOutcome.Installed,\n isComplete: (s) => s.slackStepDismissed,\n },\n {\n id: 'mcp-suggested-prompts',\n label: 'Suggested prompts',\n screenId: 'mcp-suggested-prompts',\n // Same install gate — without a working MCP there's nothing to\n // talk to from the tutorial.\n show: (s) => s.mcpOutcome === McpOutcome.Installed,\n isComplete: (s) => s.mcpSuggestedPromptsDismissed,\n },\n ],\n};\n\n/**\n * `wizard mcp remove` — single-step uninstall flow.\n *\n * DO NOT append `mcp-suggested-prompts` (or any other tutorial-shaped\n * step) here. A user who just removed MCP is opting OUT of the agent having\n * access to PostHog; immediately pivoting into a tutorial that asks\n * them to log in and try prompts is wrong on intent and confusing on\n * UX. The screen also reads `session.mcpInstalledClients` for its\n * Choose-phase copy (\"MCP is installed for X\") — that array is empty\n * post-remove, so the copy would be a lie.\n *\n * If you want a \"did you mean to keep it?\" confirmation, build that as\n * a screen earlier in this program — don't reuse the tutorial.\n */\nexport const mcpRemoveConfig: ProgramConfig = {\n id: 'mcp-remove',\n requiresAi: false,\n description: 'Remove PostHog MCP server from supported clients',\n steps: [\n {\n id: 'mcp-remove',\n label: 'Remove MCP server',\n screenId: 'mcp-remove',\n isComplete: (s) => s.mcpComplete,\n },\n ],\n};\n\n/**\n * Standalone tutorial flow — boots directly into the Choose phase of\n * McpSuggestedPromptsScreen without going through MCP install first.\n * Useful for users who already installed MCP and want to revisit the\n * tutorial, or anyone who just wants to try the agent against PostHog\n * without touching their IDE config.\n *\n * The screen handles its own OAuth (via services.performLogin) so this\n * program doesn't pre-populate credentials.\n */\nexport const mcpTutorialConfig: ProgramConfig = {\n id: 'mcp-tutorial',\n requiresAi: false,\n description: 'Try the PostHog MCP with your agent — no install needed',\n steps: [\n {\n id: 'mcp-suggested-prompts',\n label: 'MCP tutorial',\n screenId: 'mcp-suggested-prompts',\n isComplete: (s) => s.mcpSuggestedPromptsDismissed,\n },\n {\n id: 'slack-connect',\n label: 'Connect Slack',\n screenId: 'slack-connect',\n isComplete: (s) => s.slackStepDismissed,\n },\n ],\n};\n","/**\n * Slack connect program — TUI-only flow invoked by `wizard slack`. One\n * step: the same Connect Slack screen the MCP flows end on. The screen\n * renders the no-creds nudge (marketing copy + \"Open Slack setup\" link);\n * we deliberately don't force OAuth here because connecting Slack itself\n * happens in the browser, so a wizard login adds nothing for the user.\n */\n\nimport type { ProgramConfig } from '@lib/programs/program-step';\n\nexport const slackConnectConfig: ProgramConfig = {\n id: 'slack',\n description: 'Connect PostHog to your Slack',\n steps: [\n {\n id: 'slack-connect',\n label: 'Connect Slack',\n screenId: 'slack-connect',\n isComplete: (s) => s.slackStepDismissed,\n },\n ],\n};\n","/**\n * Central registry of all wizard programs.\n *\n * Adding a new program:\n * 1. Create src/lib/programs/<name>/ with index.ts exporting a ProgramConfig\n * 2. Import and add it to PROGRAM_REGISTRY below\n * 3. (If custom intro screen) add to src/ui/tui/screen-registry.tsx\n *\n * screen-sequences.ts, store.ts, and bin.ts all derive their wiring from\n * this array — no need to touch those files when adding a program.\n */\n\nimport type { ProgramConfig } from './program-step.js';\nimport { POSTHOG_DOCS_URL } from '../constants.js';\nimport { posthogIntegrationConfig } from './posthog-integration/index.js';\nimport { revenueAnalyticsConfig } from './revenue-analytics/index.js';\nimport { warehouseSourceConfig } from './warehouse-source/index.js';\nimport { auditConfig } from './audit/index.js';\nimport { eventsAuditConfig } from './events-audit/index.js';\nimport { posthogDoctorConfig } from './posthog-doctor/index.js';\nimport { webAnalyticsDoctorConfig } from './web-analytics-doctor/index.js';\nimport { migrationConfig } from './migration/index.js';\nimport { errorTrackingUploadSourceMapsConfig } from './error-tracking-upload-source-maps/index.js';\nimport { selfDrivingConfig } from './self-driving/index.js';\nimport { AGENT_SKILL_STEPS } from './agent-skill/index.js';\nimport { getContentBlocks as agentSkillContentBlocks } from './agent-skill/content/index.js';\nimport {\n mcpAddConfig,\n mcpRemoveConfig,\n mcpTutorialConfig,\n} from './mcp/index.js';\nimport { slackConnectConfig } from './slack/index.js';\n\n// Generic skill program — runs an arbitrary context-mill skill chosen at\n// dispatch time (session.skillId) rather than a registered named program.\n// Backs `wizard skill <name>` and the narrow `audit` leaves (events,\n// feature-flags, identify, session-replay, autocapture); each injects its\n// skillId onto the config, which lands on session.skillId before the run.\n//\n// The `run` recipe is a function rather than a static block because the\n// skillId isn't known until dispatch. Without a `run` recipe the runner's\n// `skipAgent` guard (run-wizard.ts) fires and the skill never executes — so we\n// derive generic run metadata from the resolved skill id at run time.\nexport const agentSkillConfig: ProgramConfig = {\n id: 'agent-skill',\n description: 'Run an arbitrary context-mill skill',\n steps: AGENT_SKILL_STEPS,\n getContentBlocks: agentSkillContentBlocks,\n allowedTools: ['Agent'],\n run: (session) => {\n const skillId = session.skillId ?? 'agent-skill';\n return Promise.resolve({\n skillId,\n integrationLabel: skillId,\n spinnerMessage: `Running ${skillId}...`,\n successMessage: `${skillId} complete!`,\n estimatedDurationMinutes: 5,\n reportFile: `posthog-${skillId}-report.md`,\n docsUrl: POSTHOG_DOCS_URL,\n });\n },\n};\n\nexport const PROGRAM_REGISTRY = [\n posthogIntegrationConfig,\n revenueAnalyticsConfig,\n warehouseSourceConfig,\n errorTrackingUploadSourceMapsConfig,\n auditConfig,\n eventsAuditConfig,\n posthogDoctorConfig,\n webAnalyticsDoctorConfig,\n migrationConfig,\n selfDrivingConfig,\n agentSkillConfig,\n mcpAddConfig,\n mcpRemoveConfig,\n mcpTutorialConfig,\n slackConnectConfig,\n] as const satisfies readonly ProgramConfig[];\n\n/**\n * Typed program names. Values come from each config's `id`, so there's\n * no parallel string list to keep in sync — adding `Program.Foo` here is\n * just exposing `fooConfig.id` under a friendly name for call sites.\n */\nexport const Program = {\n PostHogIntegration: posthogIntegrationConfig.id,\n RevenueAnalyticsSetup: revenueAnalyticsConfig.id,\n WarehouseSource: warehouseSourceConfig.id,\n ErrorTrackingUploadSourceMaps: errorTrackingUploadSourceMapsConfig.id,\n Migration: migrationConfig.id,\n Audit: auditConfig.id,\n EventsAudit: eventsAuditConfig.id,\n PosthogDoctor: posthogDoctorConfig.id,\n WebAnalyticsDoctor: webAnalyticsDoctorConfig.id,\n SelfDriving: selfDrivingConfig.id,\n AgentSkill: agentSkillConfig.id,\n McpAdd: mcpAddConfig.id,\n McpRemove: mcpRemoveConfig.id,\n McpTutorial: mcpTutorialConfig.id,\n SlackConnect: slackConnectConfig.id,\n} as const;\n\n/** Compile-time union of every registered program id. */\nexport type ProgramId = (typeof PROGRAM_REGISTRY)[number]['id'];\n\n/**\n * Look up a program config by its id. `ProgramId` is a union of every\n * registered id, so the lookup is statically guaranteed to find a match\n * — the `!` is a load-bearing assertion of that invariant, not a hope.\n */\nexport function getProgramConfig(id: ProgramId): ProgramConfig {\n return PROGRAM_REGISTRY.find((c) => c.id === id)!;\n}\n\n/** A program config that is exposed as a CLI subcommand. */\nexport type SubcommandProgram = ProgramConfig & { command: string };\n\n/** All program configs that are exposed as CLI subcommands. */\nexport function getSubcommandPrograms(): SubcommandProgram[] {\n return PROGRAM_REGISTRY.filter(\n (c): c is SubcommandProgram => c.command != null,\n );\n}\n","import type { Arguments } from 'yargs';\nimport { setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { Program } from '@lib/programs/program-registry';\nimport { VERSION } from '@lib/version';\nimport type { Command } from '../command';\n\nexport const mcpAddCommand: Command = {\n name: 'add',\n description: 'Install PostHog MCP server to supported clients',\n options: {\n local: {\n default: false,\n describe: 'Add local development MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n features: {\n describe: 'Comma-separated list of features to enable (default: all)',\n type: 'string',\n },\n 'api-key': {\n describe: 'PostHog personal API key (phx_xxx) for MCP authentication',\n type: 'string',\n },\n },\n handler: runMcpAdd,\n};\n\nfunction runMcpAdd(argv: Arguments): void {\n const features = parseFeatures(argv.features);\n void (async () => {\n const { readApiKeyFromEnv } = await import('@utils/env-api-key');\n const apiKey = (argv.apiKey as string | undefined) || readApiKeyFromEnv();\n const debug = argv.debug as boolean | undefined;\n const localMcp = argv.local as boolean | undefined;\n\n try {\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession } = await import('@lib/wizard-session');\n const tui = startTUI(VERSION, Program.McpAdd);\n tui.store.session = buildSession({\n debug,\n localMcp,\n mcpFeatures: features,\n apiKey,\n });\n } catch (error) {\n if (!isTUIUnavailable(error)) throw error;\n setUI(new LoggingUI());\n const { addMCPServerToClientsStep } = await import(\n '@steps/add-mcp-server-to-clients/index'\n );\n await addMCPServerToClientsStep({ local: localMcp, features, apiKey });\n }\n })();\n}\n\n/**\n * Ink throws \"Raw mode is not supported\" when stdin has no TTY (piped input,\n * CI, some IDE terminals). That is the only TUI failure we degrade to\n * LoggingUI for — any other error from the TUI path is a real bug and must\n * surface rather than be silently swallowed.\n */\nfunction isTUIUnavailable(error: unknown): boolean {\n return (\n error instanceof Error && /raw mode is not supported/i.test(error.message)\n );\n}\n\nfunction parseFeatures(raw: unknown): string[] | undefined {\n if (typeof raw !== 'string') return undefined;\n return raw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n}\n","import type { Arguments } from 'yargs';\nimport { setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { Program } from '@lib/programs/program-registry';\nimport { VERSION } from '@lib/version';\nimport type { Command } from '../command';\n\nexport const mcpRemoveCommand: Command = {\n name: 'remove',\n description: 'Remove PostHog MCP server from supported clients',\n options: {\n local: {\n default: false,\n describe: 'Remove local development MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n },\n handler: runMcpRemove,\n};\n\nfunction runMcpRemove(argv: Arguments): void {\n void (async () => {\n const debug = argv.debug as boolean | undefined;\n const localMcp = argv.local as boolean | undefined;\n\n try {\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession } = await import('@lib/wizard-session');\n const tui = startTUI(VERSION, Program.McpRemove);\n tui.store.session = buildSession({ debug, localMcp });\n } catch {\n setUI(new LoggingUI());\n const { removeMCPServerFromClientsStep } = await import(\n '@steps/add-mcp-server-to-clients/index'\n );\n await removeMCPServerFromClientsStep({ local: localMcp });\n }\n })();\n}\n","import type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { Program } from '@lib/programs/program-registry';\nimport { VERSION } from '@lib/version';\nimport type { Command } from '../command';\n\nexport const mcpTutorialCommand: Command = {\n name: 'tutorial',\n description: 'Try the PostHog MCP with your agent (no install needed)',\n options: {\n local: {\n default: false,\n describe:\n 'Point the tutorial at the local MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n },\n handler: runMcpTutorial,\n};\n\nfunction runMcpTutorial(argv: Arguments): void {\n void (async () => {\n const debug = argv.debug as boolean | undefined;\n const localMcp = argv.local as boolean | undefined;\n\n try {\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession } = await import('@lib/wizard-session');\n const tui = startTUI(VERSION, Program.McpTutorial);\n tui.store.session = buildSession({ debug, localMcp });\n } catch (err) {\n // TUI unavailable — the tutorial has no headless fallback.\n setUI(new LoggingUI());\n getUI().log.error(\n `The MCP tutorial requires an interactive terminal. ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n process.exit(1);\n }\n })();\n}\n","import { mcpAddCommand } from './add';\nimport { mcpRemoveCommand } from './remove';\nimport { mcpTutorialCommand } from './tutorial';\nimport type { Command } from '../command';\n\nexport const mcpCommand: Command = {\n name: 'mcp',\n description: 'MCP server management commands',\n children: [mcpAddCommand, mcpRemoveCommand, mcpTutorialCommand],\n};\n","/**\n * `--no-telemetry` flips `telemetry: false` via yargs negation;\n * `POSTHOG_WIZARD_NO_TELEMETRY` is honoured separately so the env-var\n * form documented in the README keeps working.\n */\nexport function resolveNoTelemetry(options: Record<string, unknown>): boolean {\n if (options.telemetry === false) return true;\n const env = process.env.POSTHOG_WIZARD_NO_TELEMETRY;\n if (env == null || env === '') return false;\n const norm = env.toLowerCase();\n return norm !== '0' && norm !== 'false';\n}\n","import { VERSION } from '@lib/version';\nimport { logToFile, getLogFilePath } from '@utils/debug';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport type { startTUI as StartTUIFn } from '@ui/tui/start-tui';\nimport type { TaskStreamPush as TaskStreamPushClass } from '@lib/task-stream/task-stream-push';\nimport { resolveNoTelemetry } from './resolve-no-telemetry';\nimport { runCleanups } from '@utils/wizard-abort';\n\nconst WIZARD_VERSION = VERSION;\n\n/**\n * Run a full wizard program in the TUI. Handles the full lifecycle: start TUI,\n * build session, run detection, wait for intro gate, execute the\n * agent pipeline, wait for outro dismissal, then exit.\n */\nexport function runWizard(\n config: ProgramConfig,\n options: Record<string, unknown>,\n): void {\n let tui: ReturnType<typeof StartTUIFn> | null = null;\n let taskStream: TaskStreamPushClass | null = null;\n let onSignal: (() => void) | null = null;\n let exitInProgress = false;\n\n void (async () => {\n try {\n const installDir = (options.installDir as string) || process.cwd();\n\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession, RunPhase } = await import('@lib/wizard-session');\n const { TaskStreamPush } = await import('@lib/task-stream/index');\n const { PostHogDestination } = await import(\n '@lib/task-stream/destinations/posthog'\n );\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n tui = startTUI(WIZARD_VERSION, config.id as any);\n const activeTui = tui;\n\n const session = buildSession({\n debug: options.debug as boolean | undefined,\n localMcp: options.localMcp as boolean | undefined,\n installDir,\n ci: false,\n signup: options.signup as boolean | undefined,\n apiKey: options.apiKey as string | undefined,\n projectId: options.projectId as string | undefined,\n email: options.email as string | undefined,\n benchmark: options.benchmark as boolean | undefined,\n yaraReport: options.yaraReport as boolean | undefined,\n noTelemetry: resolveNoTelemetry(options),\n });\n session.programLabel = config.id;\n if (options.skillId) {\n session.skillId = options.skillId as string;\n } else if (config.skillId) {\n session.skillId = config.skillId;\n }\n\n activeTui.store.session = session;\n\n const taskStreamEnabled = !session.noTelemetry;\n taskStream = new TaskStreamPush({\n store: activeTui.store,\n programId: config.id,\n destinations: [\n new PostHogDestination({\n getCredentials: () => activeTui.store.session.credentials,\n onError: (err) => logToFile('[task-stream-push]', err.message),\n }),\n ],\n enabled: taskStreamEnabled,\n });\n const activeStream = taskStream;\n activeStream.attach();\n\n // Flush a terminal-phase push on Ctrl-C so the web app sees the\n // run ended in error rather than hanging on the last \"running\"\n // snapshot.\n let signalled = false;\n onSignal = (): void => {\n if (signalled || exitInProgress) return;\n signalled = true;\n logToFile('[run-wizard] signal received, flushing task stream');\n // Run cleanups synchronously first — settings restore is sync fs work\n // and must complete even if the stream shutdown below times out.\n runCleanups();\n if (activeTui.store.session.runPhase === RunPhase.Running) {\n activeTui.store.setRunPhase(RunPhase.Error);\n }\n void activeStream\n .shutdown(2000)\n .catch((e) =>\n logToFile('[run-wizard] task stream shutdown error on signal:', e),\n )\n .finally(() => {\n try {\n activeTui.unmount();\n } catch {\n // terminal may already be torn down\n }\n process.exit(130);\n });\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n\n await activeTui.store.runReadyHooks();\n await activeTui.store.getGate('intro');\n await activeTui.store.getGate('health-check');\n\n const skipAgent = config.run == null;\n\n if (skipAgent) {\n const { getOrAskForProjectData } = await import('@utils/setup-utils');\n const { projectApiKey, host, accessToken, projectId } =\n await getOrAskForProjectData({\n signup: session.signup,\n ci: session.ci,\n apiKey: session.apiKey,\n projectId: session.projectId,\n programId: config.id,\n });\n activeTui.store.setCredentials({\n accessToken,\n projectApiKey,\n host,\n projectId,\n });\n } else {\n const { runAgent } = await import('@lib/agent/agent-runner');\n await runAgent(config, activeTui.store.session);\n }\n\n const isDone = (): boolean =>\n skipAgent\n ? activeTui.store.session.outroDismissed\n : activeTui.store.session.skillsComplete;\n\n await new Promise<void>((resolve) => {\n const unsub = activeTui.store.subscribe(() => {\n if (isDone()) {\n unsub();\n resolve();\n }\n });\n if (isDone()) {\n unsub();\n resolve();\n }\n });\n\n exitInProgress = true;\n await activeStream.shutdown(2000);\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n activeTui.unmount();\n process.exit(0);\n } catch (err) {\n // File-log first — the cleanup below can throw or exit.\n logToFile('[run-wizard] FATAL:', err);\n // Run cleanups before anything async so settings are restored even if\n // the stream shutdown hangs.\n runCleanups();\n // The task-stream debounce timer keeps the event loop alive, so\n // we have to drain it before exiting on the error path.\n exitInProgress = true;\n if (onSignal) {\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n }\n if (taskStream) {\n try {\n await taskStream.shutdown(2000);\n } catch {\n // ignore\n }\n }\n if (tui) {\n try {\n tui.unmount();\n } catch {\n // ignore\n }\n }\n // Print after unmount — anything printed into the alt screen is wiped.\n // eslint-disable-next-line no-console\n console.error('Wizard run failed:', err);\n // eslint-disable-next-line no-console\n console.error(`Full logs: ${getLogFilePath()}`);\n process.exit(1);\n }\n })();\n}\n","import { POSTHOG_DOCS_URL } from '@lib/constants';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport { analytics } from '@utils/analytics';\nimport { resolveNoTelemetry } from './resolve-no-telemetry';\n\n/**\n * The single CI validation layer: defaults region and requires api-key and\n * install-dir. Every CI entry point routes through `runWizardCI`, so this is\n * the one place these checks live. UI must be initialized before calling.\n */\nexport function validateCiOptions(options: Record<string, unknown>): void {\n if (!options.region) options.region = 'us';\n if (!options.apiKey) {\n getUI().intro('PostHog Wizard');\n getUI().log.error('CI mode requires --api-key (personal API key phx_xxx)');\n process.exit(1);\n }\n if (!options.installDir) {\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'CI mode requires --install-dir (directory to install in)',\n );\n process.exit(1);\n }\n}\n\n/**\n * CI-mode pipeline shared by every non-interactive entry point.\n *\n * Validates flags, builds a `ci:true` session, runs `config.ciPreRun` (or the\n * program's `onReady` hooks by default), executes `runAgent`, and routes any\n * failure through `wizardAbort`. `wizardAbort` owns all exits — never add a\n * raw `process.exit` here.\n */\nexport function runWizardCI(\n config: ProgramConfig,\n options: Record<string, unknown>,\n): void {\n setUI(new LoggingUI());\n validateCiOptions(options);\n // Every CI entry point routes through here — upgrade the non-prod\n // build tag from 'dev' to 'ci'.\n analytics.setTag('build', 'ci');\n\n void (async () => {\n const path = await import('path');\n const { buildSession } = await import('@lib/wizard-session');\n const { readEnvironment } = await import('@utils/environment');\n const { readApiKeyFromEnv } = await import('@utils/env-api-key');\n const { configureLogFileFromEnvironment, logToFile } = await import(\n '@utils/debug'\n );\n const { wizardAbort, WizardError } = await import('@utils/wizard-abort');\n\n configureLogFileFromEnvironment();\n\n const env = readEnvironment();\n const apiKey =\n (options.apiKey as string) ?? readApiKeyFromEnv() ?? undefined;\n const installDir = path.isAbsolute(options.installDir as string)\n ? (options.installDir as string)\n : path.join(process.cwd(), options.installDir as string);\n\n const session = buildSession({\n debug: options.debug as boolean | undefined,\n installDir,\n ci: true,\n signup: options.signup as boolean | undefined,\n localMcp: options.localMcp as boolean | undefined,\n apiKey,\n email: options.email as string | undefined,\n projectId: options.projectId as string | undefined,\n benchmark: options.benchmark as boolean | undefined,\n yaraReport: options.yaraReport as boolean | undefined,\n noTelemetry: resolveNoTelemetry(options),\n ...env,\n });\n session.programLabel = config.id;\n if (config.skillId) {\n session.skillId = config.skillId;\n }\n const runDef = typeof config.run === 'object' ? config.run : null;\n\n getUI().intro('Welcome to the PostHog setup wizard');\n getUI().log.info(`Running ${config.id} in CI mode`);\n\n try {\n if (config.ciPreRun) {\n await config.ciPreRun(session);\n } else {\n const readyCtx = {\n session,\n setFrameworkContext: (key: string, value: unknown) => {\n session.frameworkContext[key] = value;\n },\n setFrameworkConfig: () => undefined,\n setDetectedFramework: () => undefined,\n // CI session is a plain object (no nanostore copy-on-write),\n // so direct assignment is safe here.\n setSkillId: (skillId: string | null) => {\n session.skillId = skillId;\n },\n setUnsupportedVersion: () => undefined,\n addDiscoveredFeature: () => undefined,\n setDetectionComplete: () => undefined,\n };\n for (const step of config.steps) {\n if (step.onReady) {\n await step.onReady(readyCtx);\n }\n }\n\n const detectError = session.frameworkContext.detectError as\n | { kind: string; [k: string]: unknown }\n | undefined;\n if (detectError) {\n await wizardAbort({\n message: `Prerequisites not met: ${detectError.kind}\\n\\nSee ${\n runDef?.docsUrl ?? POSTHOG_DOCS_URL\n }`,\n error: new WizardError(`${config.id} prerequisites failed`, {\n integration: config.id,\n detect_error_kind: detectError.kind,\n }),\n });\n }\n }\n\n const { runAgent } = await import('@lib/agent/agent-runner');\n await runAgent(config, session);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n const errorStack =\n error instanceof Error && error.stack ? error.stack : undefined;\n\n logToFile(`[bin.ts CI] ERROR: ${errorMessage}`);\n if (errorStack) logToFile(`[bin.ts CI] STACK: ${errorStack}`);\n\n const debugInfo = session.debug && errorStack ? `\\n\\n${errorStack}` : '';\n const docsUrl =\n session.frameworkConfig?.metadata.docsUrl ??\n runDef?.docsUrl ??\n POSTHOG_DOCS_URL;\n await wizardAbort({\n message: `Something went wrong: ${errorMessage}\\n\\nYou can read the documentation at ${docsUrl} to set up manually.${debugInfo}`,\n error: error as Error,\n });\n }\n })().catch(() => {\n process.exit(1);\n });\n}\n","/**\n * Per-command options shared by every skill-based program command\n * (`audit events`, `migrate statsig`, `revenue`, `source-maps`, …).\n *\n * Only flags that are unique to skill commands live here. Global flags\n * (`--debug`, `--local-mcp`, `--benchmark`, `--yara-report`, `--ci`) are\n * declared once in `wizard.ts::GLOBAL_OPTIONS` and apply automatically\n * across every command — no need to repeat them per subcommand.\n */\nexport const skillProgramOptions = {\n 'install-dir': {\n describe: 'Directory to install in',\n type: 'string' as const,\n },\n};\n","import type { Arguments, Options } from 'yargs';\n\nimport { runWizard, runWizardCI } from '@lib/runners';\nimport type { ProgramConfig } from '@lib/programs/program-step';\n\nimport { skillProgramOptions } from '../skill-program-options';\n\n/**\n * Dispatch a parsed yargs invocation to the wizard runner. Applies the\n * program's `mapCliOptions` transform, then routes to `runWizard` or\n * `runWizardCI` based on the `--ci` flag.\n *\n * Every command file used to inline this; the factories call it instead.\n */\n/**\n * Run a command's async body as fire-and-forget while still surfacing failures.\n * yargs handlers are synchronous, so async work kicks off a detached promise —\n * without this, a rejection becomes an unhandled promise rejection (no message,\n * wrong exit code). This awaits the work and turns any error into a clean\n * message + non-zero exit.\n */\nexport function runCommandHandler(work: () => void | Promise<void>): void {\n void (async () => {\n try {\n await work();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`\\n\\x1b[1;91m✖ ${msg}\\x1b[0m\\n\\n`);\n process.exit(1);\n }\n })();\n}\n\nexport function dispatchProgram(config: ProgramConfig, argv: Arguments): void {\n const argvRecord = argv as unknown as Record<string, unknown>;\n const extras = config.mapCliOptions?.(argvRecord) ?? {};\n const options = { ...argvRecord, ...extras };\n if (options.ci) {\n runWizardCI(config, options);\n } else {\n runWizard(config, options);\n }\n}\n\n/**\n * Merge the standard skill-program flags (`--debug`, `--install-dir`, etc.)\n * with any program-specific options declared on `cliOptions`.\n *\n * Program-specific options shadow the standard ones — that's intentional, so\n * a program can override a default flag if it ever needs to.\n */\nexport function mergeCommandOptions(\n config: ProgramConfig,\n): Record<string, Options> {\n return {\n ...skillProgramOptions,\n ...((config.cliOptions ?? {}) as Record<string, Options>),\n };\n}\n","import type { Arguments } from 'yargs';\n\nimport { auditConfig } from '@lib/programs/audit/index';\nimport { agentSkillConfig } from '@lib/programs/program-registry';\nimport { webAnalyticsDoctorConfig } from '@lib/programs/web-analytics-doctor/index';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport { getSkillsBaseUrl } from '@lib/constants';\nimport { fetchSkillMenu, type CliEntry } from '@lib/wizard-tools';\nimport { analytics } from '@utils/analytics';\n\nimport { dispatchProgram } from '../../commands/factories/shared';\nimport type { Command } from '../../commands/command';\n\n/**\n * Capture a CLI dispatch error, flush analytics, and exit. The wizard never\n * starts a run from these paths — use flush() (not shutdown()) so we don't\n * fire a \"setup wizard finished\" event for a parse error that didn't run.\n */\nasync function exitDispatchError(\n reason: string,\n properties: Record<string, unknown>,\n message: string,\n code = 1,\n): Promise<never> {\n analytics.wizardCapture('cli dispatch error', { reason, ...properties });\n try {\n await analytics.flush();\n } catch {\n /* flush is best-effort; never block the exit */\n }\n process.stderr.write(message);\n return process.exit(code);\n}\n\n/**\n * Family commands (`wizard audit`, `wizard migrate`, ...) resolve their\n * subcommands at runtime against the published `cliEntries` inside\n * `skill-menu.json`. Adding a subcommand is a context-mill release — no\n * wizard release needed.\n *\n * Wizard-native subcommands (programs that aren't backed by a single skill,\n * e.g. `wizard audit web-analytics`) live here in code, dispatched directly\n * without touching the registry. Adding a native is a wizard PR.\n */\n\n/** Wizard-native subcommands keyed by family. */\nconst NATIVE_HANDLERS: Record<string, Record<string, ProgramConfig>> = {\n audit: { 'web-analytics': webAnalyticsDoctorConfig },\n};\n\n/**\n * Resolve a fetched CliEntry to the ProgramConfig that actually runs it.\n * Most entries run via the generic agent-skill program with the entry's\n * `skillId` injected. The comprehensive `audit all` is the one exception —\n * skillId 'audit' triggers the specialized auditConfig (custom hooks,\n * content blocks, screens).\n */\nfunction configForCliEntry(entry: CliEntry): ProgramConfig {\n if (entry.skillId === 'audit') return auditConfig;\n return { ...agentSkillConfig, skillId: entry.skillId };\n}\n\nfunction familyEntries(family: string, entries: CliEntry[]): CliEntry[] {\n return entries.filter(\n (e) =>\n e.role === 'command' && e.parentCommand === family && Boolean(e.command),\n );\n}\n\n/**\n * Dispatch `wizard <family> <sub>` to the right program.\n *\n * Order:\n * 1. Native handler for (family, sub) — runs immediately, no network.\n * 2. Fetched CliEntry — runs the resolved skill.\n * 3. Unknown — prints the available list and exits non-zero.\n */\nexport async function dispatchFamily(\n family: string,\n argv: Arguments,\n): Promise<void> {\n const sub = (argv.skill as string | undefined)?.trim();\n if (!sub) {\n // Reached only in non-TTY/CI — an interactive terminal routes the no-sub\n // case to the picker before this runs, so don't suggest opening it here.\n return exitDispatchError(\n 'missing subcommand',\n { family },\n `\\n\\x1b[1;91m✖ \\`wizard ${family}\\` requires a subcommand.\\x1b[0m\\n` +\n ` Pass one (e.g. \\`wizard ${family} <subcommand>\\`), or run it in an interactive terminal to pick from a menu.\\n\\n`,\n );\n }\n\n const native = NATIVE_HANDLERS[family]?.[sub];\n if (native) {\n dispatchProgram(native, argv);\n return;\n }\n\n const skillsBaseUrl = getSkillsBaseUrl(Boolean(argv['local-mcp']));\n const menu = await fetchSkillMenu(skillsBaseUrl);\n if (!menu) {\n return exitDispatchError(\n 'registry unreachable',\n { family, sub, skillsBaseUrl },\n `\\n\\x1b[1;91m✖ Couldn't reach the skill registry at ${skillsBaseUrl}.\\x1b[0m\\n` +\n ` Check your network connection and try again.\\n\\n`,\n );\n }\n\n const entries = menu.cliEntries ?? [];\n const entry = familyEntries(family, entries).find((e) => e.command === sub);\n if (entry) {\n dispatchProgram(configForCliEntry(entry), argv);\n return;\n }\n\n const available = [\n ...Object.keys(NATIVE_HANDLERS[family] ?? {}),\n ...familyEntries(family, entries).map((e) => e.command!),\n ].sort();\n return exitDispatchError(\n 'unknown subcommand',\n { family, sub, available },\n `\\n\\x1b[1;91m✖ Unknown subcommand \"${sub}\" under \\`${family}\\`.\\x1b[0m\\n` +\n (available.length\n ? ` Available: ${available.join(', ')}\\n\\n`\n : ` No subcommands published for \"${family}\" yet.\\n\\n`),\n );\n}\n\n/**\n * Build the children list shown in the family's interactive picker.\n * Combines native handlers with skill-backed entries from the live registry.\n * Used by `familyCommandFactory`'s `interactiveDefault`.\n */\nexport function buildFamilyPickerChildren(\n family: string,\n entries: CliEntry[],\n): Command[] {\n const natives: Command[] = Object.entries(NATIVE_HANDLERS[family] ?? {}).map(\n ([cmd, program]) => ({\n name: cmd,\n description: program.description,\n handler: (argv: Arguments) => dispatchProgram(program, argv),\n }),\n );\n const live: Command[] = familyEntries(family, entries).map((entry) => ({\n name: entry.command!,\n description: entry.description,\n handler: (argv: Arguments) => {\n void dispatchFamily(family, {\n ...argv,\n skill: entry.command,\n } as Arguments);\n },\n default: entry.default,\n }));\n return [...natives, ...live];\n}\n\n/**\n * The children the family picker shows **today**: only the leaf marked\n * `default` (e.g. `audit events`). Every other subcommand stays runnable\n * directly (`wizard audit <name>`) — they just aren't listed in the picker yet.\n * Falls back to all children when nothing is marked `default`.\n *\n * Temporary: when we're ready to surface the full menu, return `children`\n * unchanged (and delete this note).\n */\nexport function pickerChildrenToShow(children: readonly Command[]): Command[] {\n const defaults = children.filter((c) => c.default);\n return defaults.length > 0 ? [...defaults] : [...children];\n}\n","/**\n * PromptLabel — Compact inline label for input prompts.\n *\n * Renders: [!] message\n * where [!] is black text on accent background.\n */\n\nimport { Box, Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\n\ninterface PromptLabelProps {\n message?: string;\n}\n\nexport const PromptLabel = ({ message }: PromptLabelProps) => {\n return (\n <Box>\n <Text bold color={Colors.accent}>\n {' '}\n {message}\n </Text>\n </Box>\n );\n};\n","/**\n * ConfirmButton — the confirm row used to submit a selection.\n *\n * Pure render. Multi-select menus (PickerMenu mode=\"multi\", GroupedPickerMenu)\n * append this below their options as the final focusable row: the user toggles\n * options with enter, then arrows down onto this row and presses enter to\n * submit. This replaces the older \"enter anywhere submits\" pattern, which\n * confused people who expected enter to toggle the focused item.\n *\n * Renders flat, mirroring the option rows — a focus triangle and the label,\n * accent and bold when focused, dimmed otherwise — so it lines up under the\n * options instead of sitting in a separate boxed target.\n */\n\nimport { Text } from 'ink';\nimport { Icons, Colors } from '@ui/tui/styles';\n\ninterface ConfirmButtonProps {\n /** Button text. Defaults to \"Confirm\". */\n label?: string;\n /** Whether the cursor is currently on the button. */\n focused: boolean;\n /** Optional selected-item count, rendered as \"Label (n)\" when > 0. */\n count?: number;\n}\n\nexport const ConfirmButton = ({\n label = 'Confirm',\n focused,\n count,\n}: ConfirmButtonProps) => {\n const text = count && count > 0 ? `${label} (${count})` : label;\n return (\n <Text\n color={focused ? Colors.accent : undefined}\n bold={focused}\n dimColor={!focused}\n >\n {focused ? Icons.triangleSmallRight : ' '} {text}\n </Text>\n );\n};\n","/**\n * Pure utility functions for keyboard hints — no React or Ink dependencies.\n * Extracted for testability in a node Jest environment.\n */\n\nexport interface KeyboardHint {\n label: string;\n action: string;\n priority: number;\n}\n\n/** Well-known key matches corresponding to Ink's key.* properties. */\nexport enum KeyMatch {\n UpArrow = 'upArrow',\n DownArrow = 'downArrow',\n LeftArrow = 'leftArrow',\n RightArrow = 'rightArrow',\n Return = 'return',\n Escape = 'escape',\n Space = 'space',\n}\n\n/** A key match: either a KeyMatch enum value or a literal character string (e.g. 'a', 's'). */\nexport type KeyMatchOrChar = KeyMatch | (string & NonNullable<unknown>);\n\n/** Default priorities by key type. */\nconst DEFAULT_PRIORITY: Record<string, number> = {\n [KeyMatch.UpArrow]: 0,\n [KeyMatch.DownArrow]: 0,\n [KeyMatch.LeftArrow]: 1,\n [KeyMatch.RightArrow]: 1,\n [KeyMatch.Space]: 10,\n [KeyMatch.Escape]: 20,\n [KeyMatch.Return]: 21,\n};\n\n/** Get the default display priority for a key match. */\nexport function getDefaultPriority(\n match: KeyMatchOrChar | KeyMatchOrChar[],\n): number {\n const first = Array.isArray(match) ? match[0] : match;\n return DEFAULT_PRIORITY[first] ?? 15;\n}\n\n/** Check if a KeyMatchOrChar matches the given input string and key flags. */\nexport function matchesKey(\n m: KeyMatchOrChar,\n input: string,\n key: { [k: string]: unknown },\n): boolean {\n switch (m) {\n case KeyMatch.UpArrow:\n return !!key.upArrow;\n case KeyMatch.DownArrow:\n return !!key.downArrow;\n case KeyMatch.LeftArrow:\n return !!key.leftArrow;\n case KeyMatch.RightArrow:\n return !!key.rightArrow;\n case KeyMatch.Return:\n return !!key.return;\n case KeyMatch.Escape:\n return !!key.escape;\n case KeyMatch.Space:\n return input === ' ';\n default:\n return input === m;\n }\n}\n\n/** Serialize hints for comparison. */\nexport function hintsKey(hints: KeyboardHint[]): string {\n return hints.map((h) => `${h.label}:${h.action}`).join('|');\n}\n\n/** Deduplicate hints by label+action and sort by priority. */\nexport function deduplicateAndSort(hints: KeyboardHint[]): KeyboardHint[] {\n const seen = new Set<string>();\n const deduped: KeyboardHint[] = [];\n for (const hint of hints) {\n const k = `${hint.label}:${hint.action}`;\n if (!seen.has(k)) {\n seen.add(k);\n deduped.push(hint);\n }\n }\n deduped.sort((a, b) => a.priority - b.priority);\n return deduped;\n}\n","/**\n * KeyboardHintsProvider — Context for collecting and displaying keyboard hints.\n *\n * Input components register their hints via useKeyBindings. The provider\n * flattens, deduplicates, and sorts them. The hints bar stays visible for as\n * long as a screen has registered hints — it never auto-dismisses.\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n hintsKey,\n deduplicateAndSort,\n type KeyboardHint,\n} from './keyboard-hints-utils.js';\n\nexport type { KeyboardHint } from './keyboard-hints-utils.js';\n\ninterface KeyboardHintsContextValue {\n register(id: string, hints: KeyboardHint[]): void;\n unregister(id: string): void;\n hints: KeyboardHint[];\n}\n\nconst KeyboardHintsContext = createContext<KeyboardHintsContextValue>({\n register: () => undefined,\n unregister: () => undefined,\n hints: [],\n});\n\nexport const useKeyboardHintsContext = () => useContext(KeyboardHintsContext);\n\nexport const KeyboardHintsProvider = ({\n children,\n}: {\n children: ReactNode;\n}) => {\n const registrationsRef = useRef(new Map<string, KeyboardHint[]>());\n const [hints, setHints] = useState<KeyboardHint[]>([]);\n const prevHintsKeyRef = useRef('');\n\n const recompute = useCallback(() => {\n const all: KeyboardHint[] = [];\n for (const h of registrationsRef.current.values()) {\n all.push(...h);\n }\n const deduped = deduplicateAndSort(all);\n\n const newKey = hintsKey(deduped);\n if (newKey !== prevHintsKeyRef.current) {\n prevHintsKeyRef.current = newKey;\n setHints(deduped);\n }\n }, []);\n\n const register = useCallback(\n (id: string, h: KeyboardHint[]) => {\n registrationsRef.current.set(id, h);\n recompute();\n },\n [recompute],\n );\n\n const unregister = useCallback(\n (id: string) => {\n registrationsRef.current.delete(id);\n recompute();\n },\n [recompute],\n );\n\n return (\n <KeyboardHintsContext.Provider value={{ register, unregister, hints }}>\n {children}\n </KeyboardHintsContext.Provider>\n );\n};\n","/**\n * useKeyBindings — Declarative keyboard input + automatic hint registration.\n *\n * Replaces raw `useInput` in input components. Define bindings as data;\n * the hook wires up the Ink input handler AND registers hints in the\n * KeyboardHintsProvider. One source of truth for keys and their labels.\n */\n\nimport { useInput, type Key } from 'ink';\nimport { useEffect, useRef } from 'react';\nimport { useKeyboardHintsContext } from './useKeyboardHints.js';\nimport {\n matchesKey,\n getDefaultPriority,\n KeyMatch,\n type KeyboardHint,\n type KeyMatchOrChar,\n} from './keyboard-hints-utils.js';\n\nexport { KeyMatch };\nexport type { KeyMatchOrChar } from './keyboard-hints-utils.js';\n\nexport interface KeyBinding {\n /** Which key(s) trigger this binding. Array = multiple keys, one hint. */\n match: KeyMatchOrChar | KeyMatchOrChar[];\n /** Display label in hints bar (e.g. \"↑↓\", \"space\", \"enter\") */\n label: string;\n /** Description in hints bar (e.g. \"navigate\", \"toggle\") */\n action: string;\n /** Ordering priority (lower = further left). Defaults based on key type. */\n priority?: number;\n /** Handler called when the key matches. */\n handler: (input: string, key: Key) => void;\n}\n\n/**\n * Declarative key bindings hook. Replaces `useInput` in input components.\n * Registers hints automatically with the KeyboardHintsProvider.\n *\n * @param id Unique identifier for this component's hints registration\n * @param bindings Array of key binding definitions\n */\nexport function useKeyBindings(id: string, bindings: KeyBinding[]): void {\n const ctx = useKeyboardHintsContext();\n\n // Extract hints and register. Use a serialized key to avoid unnecessary updates.\n const hintsRef = useRef<string>('');\n const hints: KeyboardHint[] = bindings.map((b) => ({\n label: b.label,\n action: b.action,\n priority: b.priority ?? getDefaultPriority(b.match),\n }));\n const serialized = hints\n .map((h) => `${h.label}:${h.action}:${h.priority}`)\n .join('|');\n\n useEffect(() => {\n if (serialized !== hintsRef.current) {\n hintsRef.current = serialized;\n ctx.register(id, hints);\n }\n return () => ctx.unregister(id);\n // eslint-disable-next-line\n }, [id, serialized]);\n\n // Wire up input handling\n useInput((input, key) => {\n for (const binding of bindings) {\n const matches = Array.isArray(binding.match)\n ? binding.match\n : [binding.match];\n if (matches.some((m) => matchesKey(m, input, key))) {\n binding.handler(input, key);\n return;\n }\n }\n });\n}\n","/**\n * PickerMenu — Single and multi select.\n * Single mode: custom renderer with small triangle indicator; enter selects.\n * Multi mode: checkbox glyphs toggled with enter, plus a focusable\n * Confirm button below the options. The cursor moves onto the button and\n * enter submits — see MultiPickerMenu for the rationale.\n *\n * Key bindings are declared via useKeyBindings, which auto-registers\n * hints in the KeyboardHintsBar.\n */\n\nimport { Box, Text } from 'ink';\nimport { useEffect, useState } from 'react';\nimport { Icons, Colors } from '@ui/tui/styles';\nimport { PromptLabel } from './PromptLabel.js';\nimport { ConfirmButton } from './ConfirmButton.js';\nimport {\n useKeyBindings,\n KeyMatch,\n type KeyBinding,\n} from '@ui/tui/hooks/useKeyBindings';\n\ninterface PickerOption<T> {\n label: string;\n value: T;\n hint?: string;\n /**\n * Multi-select only: a secondary explanation rendered dimmed and wrapped on\n * its own line(s) beneath the label, for choices that need more than a title.\n * When unset, the row renders exactly as a label-only row.\n */\n description?: string;\n /** Glyph rendered before the label, in its own color — unaffected by\n * focus and disabled styling. */\n icon?: { glyph: string; color?: string };\n /** Dimmed and unselectable; navigation skips over it. */\n disabled?: boolean;\n /**\n * Multi-select only: marks this option mutually exclusive with every other\n * option. Selecting it clears all other picks; selecting any non-exclusive\n * option clears it. Used e.g. for a browser connector that can't be\n * installed alongside local editors.\n */\n exclusive?: boolean;\n}\n\n/**\n * Step through a column's options in `dir`, wrapping, until an enabled\n * option is found. Returns `from` unchanged if the column is entirely\n * disabled.\n */\nfunction stepEnabled<T>(\n options: PickerOption<T>[],\n rows: number,\n from: number,\n dir: 1 | -1,\n): number {\n const col = Math.floor(from / rows);\n const colStart = col * rows;\n const colLen = Math.min(rows, options.length - colStart);\n let row = from % rows;\n for (let i = 0; i < colLen; i++) {\n row = (row + dir + colLen) % colLen;\n const idx = colStart + row;\n if (!options[idx]?.disabled) return idx;\n }\n return from;\n}\n\n/** Index of the first enabled option, for the initial focus. */\nfunction firstEnabled<T>(options: PickerOption<T>[]): number {\n const idx = options.findIndex((o) => !o.disabled);\n return idx === -1 ? 0 : idx;\n}\n\n/** Index of the last enabled option, for wrapping from the button onto\n * the bottom of the grid. */\nfunction lastEnabled<T>(options: PickerOption<T>[]): number {\n for (let i = options.length - 1; i >= 0; i--) {\n if (!options[i]?.disabled) return i;\n }\n return options.length - 1;\n}\n\ninterface PickerMenuProps<T> {\n message?: string;\n options: PickerOption<T>[];\n mode?: 'single' | 'multi';\n centered?: boolean;\n columns?: 1 | 2 | 3 | 4;\n /**\n * Vertical space between options, in TUI rows. Defaults to 0 — i.e.\n * options stack tightly. Set to 1+ when the option labels are long\n * (wrap across multiple lines) or for visual breathing room.\n */\n optionMarginBottom?: number;\n onSelect: (value: T | T[]) => void;\n}\n\nexport const PickerMenu = <T,>({\n message,\n options,\n mode = 'single',\n centered = false,\n columns = 1,\n optionMarginBottom = 0,\n onSelect,\n}: PickerMenuProps<T>) => {\n if (mode === 'multi') {\n return (\n <MultiPickerMenu\n message={message}\n options={options}\n centered={centered}\n columns={columns}\n optionMarginBottom={optionMarginBottom}\n onSelect={onSelect}\n />\n );\n }\n\n return (\n <SinglePickerMenu\n message={message}\n options={options}\n centered={centered}\n columns={columns}\n optionMarginBottom={optionMarginBottom}\n onSelect={onSelect}\n />\n );\n};\n\n/** Custom single-select with triangle indicator and accent highlight. */\nconst SinglePickerMenu = <T,>({\n message,\n options,\n centered = false,\n columns = 1,\n optionMarginBottom = 0,\n onSelect,\n}: {\n message?: string;\n options: PickerOption<T>[];\n centered?: boolean;\n columns?: number;\n optionMarginBottom?: number;\n onSelect: (value: T | T[]) => void;\n}) => {\n const [focused, setFocused] = useState(() => firstEnabled(options));\n const rows = Math.ceil(options.length / columns);\n\n // Re-validate focus when the options change while mounted \\u2014 a list\n // that shrinks or disables entries can leave `focused` pointing at a\n // missing or disabled option, which would make enter a no-op.\n useEffect(() => {\n if (focused >= options.length || options[focused]?.disabled) {\n setFocused(firstEnabled(options));\n }\n }, [options, focused]);\n\n const bindings: KeyBinding[] = [\n {\n match: [KeyMatch.UpArrow, KeyMatch.DownArrow],\n label: '\\u2191\\u2193',\n action: 'navigate',\n handler: (_input, key) => {\n if (key.upArrow) {\n setFocused(stepEnabled(options, rows, focused, -1));\n }\n if (key.downArrow) {\n setFocused(stepEnabled(options, rows, focused, 1));\n }\n },\n },\n {\n match: KeyMatch.Return,\n label: 'enter',\n action: 'select',\n handler: () => {\n const selected = options[focused];\n if (selected && !selected.disabled) {\n onSelect(selected.value);\n }\n },\n },\n ];\n\n if (columns > 1) {\n bindings.splice(1, 0, {\n match: [KeyMatch.LeftArrow, KeyMatch.RightArrow],\n label: '\\u2190\\u2192',\n action: 'navigate',\n handler: (_input, key) => {\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n\n let next = focused;\n if (key.leftArrow) {\n const prevCol = col > 0 ? col - 1 : columns - 1;\n next = Math.min(prevCol * rows + row, options.length - 1);\n }\n if (key.rightArrow) {\n const nextCol = col < columns - 1 ? col + 1 : 0;\n next = Math.min(nextCol * rows + row, options.length - 1);\n }\n // Landing on a disabled option slides to the column's nearest\n // enabled one.\n if (options[next]?.disabled) {\n next = stepEnabled(options, rows, next, 1);\n }\n setFocused(next);\n },\n });\n }\n\n useKeyBindings('single-picker', bindings);\n\n // Chunk options into columns (column-first ordering)\n const columnArrays: PickerOption<T>[][] = [];\n for (let c = 0; c < columns; c++) {\n columnArrays.push(options.slice(c * rows, c * rows + rows));\n }\n\n const align = centered ? 'center' : undefined;\n\n return (\n <Box flexDirection=\"column\" alignItems={align}>\n <PromptLabel message={message} />\n <Box flexDirection=\"row\" gap={4}>\n {columnArrays.map((colOpts, colIdx) => (\n <Box key={colIdx} flexDirection=\"column\">\n {colOpts.map((opt, rowIdx) => {\n const flatIdx = colIdx * rows + rowIdx;\n const isFocused = flatIdx === focused;\n const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;\n return (\n <Box key={flatIdx} gap={1} marginBottom={optionMarginBottom}>\n <Text\n color={isFocused ? Colors.accent : undefined}\n dimColor={!isFocused}\n >\n {isFocused ? Icons.triangleSmallRight : ' '}\n </Text>\n {opt.icon && (\n <Text color={opt.icon.color}>{opt.icon.glyph}</Text>\n )}\n <Text\n color={\n opt.disabled\n ? Colors.muted\n : isFocused\n ? Colors.accent\n : undefined\n }\n bold={isFocused && !opt.disabled}\n dimColor={!isFocused || opt.disabled}\n >\n {label}\n </Text>\n </Box>\n );\n })}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n\n/**\n * Custom multi-select with checkbox glyphs and accent highlight.\n *\n * Interaction model (shared with GroupedPickerMenu):\n * - \\u2191\\u2193 move the cursor through the options AND onto the Confirm button,\n * which lives just past the last option.\n * - enter toggles the focused option (no more \"space toggles but enter\n * advances\" split that tripped people up). Space is kept as an\n * undocumented alias, but the hints bar advertises only enter.\n * - moving onto the Confirm button and pressing enter submits the\n * current selection.\n */\nconst MultiPickerMenu = <T,>({\n message,\n options,\n centered = false,\n columns = 1,\n optionMarginBottom = 0,\n onSelect,\n}: {\n message?: string;\n options: PickerOption<T>[];\n centered?: boolean;\n columns?: number;\n optionMarginBottom?: number;\n onSelect: (value: T | T[]) => void;\n}) => {\n const [focused, setFocused] = useState(() => firstEnabled(options));\n // When true, the cursor is on the Confirm button rather than an option.\n const [onButton, setOnButton] = useState(false);\n const [selected, setSelected] = useState<Set<number>>(new Set());\n const rows = Math.ceil(options.length / columns);\n\n // Re-validate focus when the options change while mounted — a list\n // that shrinks or disables entries can leave `focused` pointing at a\n // missing or disabled option, which would make enter a no-op.\n useEffect(() => {\n if (focused >= options.length || options[focused]?.disabled) {\n setFocused(firstEnabled(options));\n }\n }, [options, focused]);\n\n const confirm = () => {\n const values = [...selected]\n .sort((a, b) => a - b)\n .map((i) => options[i].value);\n onSelect(values);\n };\n\n const bindings: KeyBinding[] = [\n {\n match: [KeyMatch.UpArrow, KeyMatch.DownArrow],\n label: '\\u2191\\u2193',\n action: 'navigate',\n handler: (_input, key) => {\n if (key.upArrow) {\n if (onButton) {\n // Button \\u2192 bottom of the grid (last enabled option).\n setOnButton(false);\n setFocused(lastEnabled(options));\n return;\n }\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n // Nearest enabled option above in this column.\n let r = row - 1;\n while (r >= 0 && options[col * rows + r]?.disabled) r--;\n if (r >= 0) {\n setFocused(col * rows + r);\n } else {\n // Top of the column \\u2192 wrap up onto the button.\n setOnButton(true);\n }\n }\n if (key.downArrow) {\n if (onButton) {\n // Button \\u2192 top of the grid (first enabled option).\n setOnButton(false);\n setFocused(firstEnabled(options));\n return;\n }\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n const colLen = Math.min(rows, options.length - col * rows);\n // Nearest enabled option below in this column.\n let r = row + 1;\n while (r < colLen && options[col * rows + r]?.disabled) r++;\n if (r < colLen) {\n setFocused(col * rows + r);\n } else {\n // Bottom of the column \\u2192 down onto the button.\n setOnButton(true);\n }\n }\n },\n },\n {\n match: [KeyMatch.Space, KeyMatch.Return],\n label: 'enter',\n action: 'select',\n handler: () => {\n if (onButton) {\n confirm();\n return;\n }\n if (options[focused]?.disabled) return;\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(focused)) {\n next.delete(focused);\n return next;\n }\n // Enforce mutual exclusivity: an exclusive option clears every other\n // pick; any other option clears previously-picked exclusive ones.\n if (options[focused]?.exclusive) {\n return new Set([focused]);\n }\n for (const i of next) {\n if (options[i]?.exclusive) {\n next.delete(i);\n }\n }\n next.add(focused);\n return next;\n });\n },\n },\n ];\n\n if (columns > 1) {\n bindings.splice(1, 0, {\n match: [KeyMatch.LeftArrow, KeyMatch.RightArrow],\n label: '\\u2190\\u2192',\n action: 'navigate',\n handler: (_input, key) => {\n if (onButton) return;\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n\n let next = focused;\n if (key.leftArrow) {\n const prevCol = col > 0 ? col - 1 : columns - 1;\n next = Math.min(prevCol * rows + row, options.length - 1);\n }\n if (key.rightArrow) {\n const nextCol = col < columns - 1 ? col + 1 : 0;\n next = Math.min(nextCol * rows + row, options.length - 1);\n }\n // Landing on a disabled option slides to the column's nearest\n // enabled one.\n if (options[next]?.disabled) {\n next = stepEnabled(options, rows, next, 1);\n }\n setFocused(next);\n },\n });\n }\n\n useKeyBindings('multi-picker', bindings);\n\n const columnArrays: PickerOption<T>[][] = [];\n for (let c = 0; c < columns; c++) {\n columnArrays.push(options.slice(c * rows, c * rows + rows));\n }\n\n return (\n <Box flexDirection=\"column\" alignItems={centered ? 'center' : undefined}>\n <PromptLabel message={message} />\n <Box\n flexDirection=\"row\"\n gap={4}\n marginLeft={centered ? 0 : 2}\n marginTop={1}\n >\n {columnArrays.map((colOpts, colIdx) => (\n <Box key={colIdx} flexDirection=\"column\">\n {colOpts.map((opt, rowIdx) => {\n const flatIdx = colIdx * rows + rowIdx;\n const isFocused = !onButton && flatIdx === focused;\n const isSelected = selected.has(flatIdx);\n const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;\n const checkbox = isSelected\n ? Icons.squareFilled\n : Icons.squareOpen;\n return (\n <Box\n key={flatIdx}\n flexDirection=\"column\"\n marginBottom={optionMarginBottom}\n >\n <Box gap={1}>\n <Text\n color={isSelected ? 'white' : Colors.muted}\n dimColor={!isFocused && !isSelected}\n >\n {checkbox}\n </Text>\n {opt.icon && (\n <Text color={opt.icon.color}>{opt.icon.glyph}</Text>\n )}\n <Text\n color={\n opt.disabled\n ? Colors.muted\n : isFocused\n ? Colors.accent\n : undefined\n }\n bold={isFocused && !opt.disabled}\n dimColor={!isFocused || opt.disabled}\n >\n {label}\n </Text>\n </Box>\n {/* Optional dimmed, wrapped explanation under the label. The\n explicit width forces Ink to wrap (an unconstrained Box\n shrinks to its content and never wraps). Renders only when\n set, so label-only rows are byte-for-byte unchanged. */}\n {opt.description && (\n <Box marginLeft={4} width={56}>\n <Text dimColor wrap=\"wrap\">\n {opt.description}\n </Text>\n </Box>\n )}\n </Box>\n );\n })}\n </Box>\n ))}\n </Box>\n <Box marginTop={1} marginLeft={centered ? 0 : 2}>\n <ConfirmButton focused={onButton} count={selected.size} />\n </Box>\n </Box>\n );\n};\n","/**\n * Mount an Ink picker over a command's `children` and dispatch the\n * selected child's handler.\n *\n * Used as the `interactiveDefault` for family parents like\n * `wizard audit` — when the user invokes the parent without a leaf, this\n * shows a TUI menu instead of yargs's `demandCommand(1)` help dump.\n *\n * The picker opens when a family surfaces more than one option; the `default`\n * flag controls which one is pre-highlighted. When a family surfaces a single\n * option (today `audit` → `events`), `familyCommandFactory` runs it directly\n * instead, so the user lands on its intro screen rather than a one-item menu.\n *\n * Single-option commands aren't families — they should be flat\n * commands wired with `skillCommandFactory` / `nativeCommandFactory`\n * directly, not run through this module.\n */\n\nimport type { Arguments } from 'yargs';\nimport { Box, Text, render } from 'ink';\nimport { createElement } from 'react';\n\nimport { Colors } from '@ui/tui/styles';\nimport { PickerMenu } from '@ui/tui/primitives/PickerMenu';\n\nimport { commandKeys, type Command } from '../command';\n\ninterface FamilyPickerAppProps {\n parentLabel: string;\n options: { label: string; value: Command; hint?: string }[];\n onSelect: (cmd: Command) => void;\n}\n\nfunction FamilyPickerApp(props: FamilyPickerAppProps) {\n return createElement(\n Box,\n { flexDirection: 'column', paddingX: 1, paddingY: 1 },\n createElement(\n Text,\n { bold: true, color: Colors.accent },\n props.parentLabel,\n ),\n createElement(Box, { height: 1 }),\n createElement(PickerMenu<Command>, {\n message: 'Pick a subcommand',\n options: props.options,\n optionMarginBottom: 1,\n onSelect: (value) => {\n // PickerMenu in single mode returns one value; only the multi-mode\n // signature is the array variant. Narrow defensively.\n const cmd = Array.isArray(value) ? value[0] : value;\n if (cmd) props.onSelect(cmd);\n },\n }),\n );\n}\n\nfunction describe(child: Command): string {\n // Strip positional syntax (`search <query>` → `search`) for the picker label.\n return commandKeys(child.name)[0] ?? '';\n}\n\n/**\n * Reorder children so the `default`-marked entry is first, while\n * preserving the relative order of the rest. The picker's initial\n * focus is index 0, so this is what makes \"press Enter on\n * `wizard audit`\" run the default leaf (today `audit events`).\n *\n * Exported for testability — the ordering logic stays pure and\n * inspectable without mounting Ink.\n */\nexport function orderFamilyChildren(children: readonly Command[]): Command[] {\n const selectable = children.filter((c) => c.handler || c.children?.length);\n const defaults = selectable.filter((c) => c.default);\n const rest = selectable.filter((c) => !c.default);\n return [...defaults, ...rest];\n}\n\n/**\n * Render the picker. Resolves once the user has selected a child;\n * dispatching the child's handler is the caller's responsibility (so this\n * function stays pure-UI and easy to test by stubbing `render`).\n */\nexport function chooseFamilyChild(\n parentLabel: string,\n children: readonly Command[],\n): Promise<Command | null> {\n const ordered = orderFamilyChildren(children);\n if (ordered.length === 0) return Promise.resolve(null);\n\n const options = ordered.map((child) => ({\n label: describe(child),\n value: child,\n hint: child.description,\n }));\n\n return new Promise((resolve) => {\n let app: ReturnType<typeof render> | null = null;\n const handleSelect = (cmd: Command): void => {\n app?.unmount();\n resolve(cmd);\n };\n app = render(\n createElement(FamilyPickerApp, {\n parentLabel,\n options,\n onSelect: handleSelect,\n }),\n );\n });\n}\n\n/**\n * Returns an `interactiveDefault` handler for a family parent's no-leaf\n * invocation. Always opens the picker; the `default`-marked child is\n * shown first (pre-highlighted), so a single Enter keystroke runs it.\n *\n * Discovery + consent in one extra keystroke vs. auto-running silently.\n *\n * Wire onto a family parent:\n * export const auditCommand: Command = {\n * name: 'audit',\n * description: '...',\n * children: [...],\n * interactiveDefault: createFamilyPickerDefault('audit', auditChildren),\n * };\n */\nexport function createFamilyPickerDefault(\n parentLabel: string,\n children: readonly Command[],\n chooser: (\n label: string,\n children: readonly Command[],\n ) => Promise<Command | null> = chooseFamilyChild,\n): (argv: Arguments) => Promise<void> {\n return async (argv) => {\n const chosen = await chooser(parentLabel, children);\n if (!chosen) return;\n // We forward the PARENT's parsed argv straight to the chosen child. The\n // child's own option defaults and `check` validator do NOT run on this\n // path — they only run when the leaf is invoked directly\n // (`wizard audit events`). Harmless while leaves declare neither, but if a\n // leaf ever grows a `check` or a defaulted option, this path will skip it.\n await Promise.resolve(chosen.handler?.(argv));\n };\n}\n","import type { Arguments } from 'yargs';\n\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport {\n buildFamilyPickerChildren,\n dispatchFamily,\n pickerChildrenToShow,\n} from '@lib/programs/dispatch-family';\nimport { getSkillsBaseUrl } from '@lib/constants';\nimport { fetchSkillMenu } from '@lib/wizard-tools';\n\nimport type { Command } from '../command';\nimport { createFamilyPickerDefault } from './family-picker';\nimport { mergeCommandOptions, runCommandHandler } from './shared';\n\nexport interface FamilyCommandFactoryOpts {\n /** The family's CLI name (e.g. 'audit'). */\n family: string;\n /** Help text for `wizard <family> --help`. */\n description: string;\n /**\n * Source for shared CLI options (e.g. --install-dir) merged onto the\n * family parent. Usually the family's flagship native config, or the\n * generic agent-skill config.\n */\n optionsFrom: ProgramConfig;\n}\n\n/**\n * Build a yargs `Command` for a family parent (`wizard audit`, etc.).\n *\n * - `wizard <family> <sub>` — `dispatchFamily` resolves `<sub>` against\n * native handlers first, then the live `cliEntries` from\n * `skill-menu.json`. Unknown subs error with the available list.\n * - `wizard <family>` (no positional) — in an interactive terminal, runs the\n * family's single shown entry directly (today `audit events`, so the user\n * lands on its intro screen); opens the picker once a family shows more than\n * one. In non-TTY/CI, falls through to `dispatchFamily`, which prints\n * \"requires a subcommand\" rather than running something unprompted.\n *\n * No static yargs children. New skill-backed subcommands appear after a\n * context-mill release without a wizard release. New *native* subcommands\n * (rare) are added by updating `NATIVE_HANDLERS` in `dispatch-family.ts`.\n */\nexport function familyCommandFactory({\n family,\n description,\n optionsFrom,\n}: FamilyCommandFactoryOpts): Command {\n // Bare `wizard <family>` in an interactive terminal. With a single option\n // today (e.g. `audit events`), skip the picker and run it directly so the\n // user lands on its own intro screen rather than a one-item menu. When a\n // family grows past one shown option, this opens the picker instead — no\n // wiring change needed.\n const openFamilyEntry = async (argv: Arguments): Promise<void> => {\n const skillsBaseUrl = getSkillsBaseUrl(Boolean(argv['local-mcp']));\n const menu = await fetchSkillMenu(skillsBaseUrl);\n const children = buildFamilyPickerChildren(family, menu?.cliEntries ?? []);\n const toShow = pickerChildrenToShow(children);\n if (toShow.length === 1 && toShow[0]?.handler) {\n await Promise.resolve(toShow[0].handler(argv));\n return;\n }\n const picker = createFamilyPickerDefault(`wizard ${family}`, toShow);\n await picker(argv);\n };\n\n return {\n name: `${family} [skill]`,\n description,\n options: mergeCommandOptions(optionsFrom),\n positionals: {\n skill: {\n type: 'string',\n describe: 'Subcommand to run (omit to run the default)',\n },\n },\n handler: (argv: Arguments) => {\n const sub = (argv.skill as string | undefined)?.trim();\n // With a subcommand, resolve and run it. Without one, run the family's\n // default entry (or open the picker if there's more than one) — but only\n // in an interactive terminal. In non-TTY/CI, fall through to\n // dispatchFamily, which prints \"requires a subcommand\" rather than\n // running something unprompted or hanging on a picker that can't render.\n // runCommandHandler awaits the async work so a rejection surfaces as a\n // clean error instead of an unhandled promise rejection.\n runCommandHandler(() =>\n sub || !process.stdout.isTTY\n ? dispatchFamily(family, argv)\n : openFamilyEntry(argv),\n );\n },\n interactiveDefault: openFamilyEntry,\n };\n}\n","import { auditConfig } from '@lib/programs/audit/index';\n\nimport type { Command } from './command';\nimport { familyCommandFactory } from './factories/family-command-factory';\n\n/**\n * The `wizard audit` family.\n *\n * Subcommands are resolved at runtime: the wizard fetches `cliEntries` from\n * `skill-menu.json` and dispatches based on `parentCommand: 'audit'`. The\n * wizard-native handler for `web-analytics` lives in `NATIVE_HANDLERS` over\n * in `dispatch-family.ts`. `wizard audit` with no positional opens the\n * family picker, which combines native + live entries.\n *\n * Adding a new skill-backed audit subcommand is a context-mill release —\n * no wizard release needed.\n */\nexport const auditCommand: Command = familyCommandFactory({\n family: 'audit',\n description: auditConfig.description,\n optionsFrom: auditConfig,\n});\n","import { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { readApiKeyFromEnv } from '@utils/env-api-key';\nimport { runWizard } from '@lib/runners';\nimport {\n posthogDoctorConfig,\n fetchHealthIssues,\n getKindMeta,\n} from '@lib/programs/posthog-doctor/index';\nimport { skillProgramOptions } from './skill-program-options';\nimport type { Command } from './command';\n\nexport const doctorCommand: Command = {\n name: 'doctor',\n description: posthogDoctorConfig.description,\n options: {\n ...skillProgramOptions,\n ...(posthogDoctorConfig.cliOptions ?? {}),\n },\n handler: (argv) => {\n const extras =\n posthogDoctorConfig.mapCliOptions?.(argv as Record<string, unknown>) ??\n {};\n const options = { ...argv, ...extras };\n // doctor is otherwise a TUI-only diagnostic (it has no agent run); in CI we\n // fetch the project's health issues headlessly and report them instead.\n if (options.ci) {\n void runDoctorCI(options);\n } else {\n runWizard(posthogDoctorConfig, options);\n }\n },\n};\n\nconst SEVERITY_ORDER = { critical: 0, warning: 1, info: 2 } as const;\n\nasync function runDoctorCI(options: Record<string, unknown>): Promise<void> {\n setUI(new LoggingUI());\n const apiKey = (options.apiKey as string) ?? readApiKeyFromEnv() ?? undefined;\n if (!apiKey) {\n getUI().intro('PostHog Wizard');\n getUI().log.error('CI mode requires --api-key (personal API key phx_xxx)');\n process.exit(1);\n }\n\n getUI().intro('Welcome to the PostHog setup wizard');\n getUI().log.info('Running posthog-doctor in CI mode');\n\n try {\n const { getOrAskForProjectData } = await import('@utils/setup-utils');\n const { host, accessToken, projectId } = await getOrAskForProjectData({\n signup: false,\n ci: true,\n apiKey,\n projectId: options.projectId\n ? Number(options.projectId as string)\n : undefined,\n });\n\n const issues = await fetchHealthIssues(accessToken, host, projectId);\n if (issues.length === 0) {\n getUI().log.success('No active issues — your project looks healthy.');\n process.exit(0);\n }\n\n const sorted = [...issues].sort(\n (a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity],\n );\n getUI().log.warn(\n `${issues.length} active issue${issues.length === 1 ? '' : 's'} found:`,\n );\n for (const issue of sorted) {\n getUI().log.info(\n ` • [${issue.severity}] ${getKindMeta(issue.kind).title}`,\n );\n }\n process.exit(1);\n } catch (error) {\n const { ApiError } = await import('@lib/api');\n const message =\n error instanceof ApiError && error.statusCode === 401\n ? 'Your PostHog API key is invalid or expired.'\n : error instanceof Error\n ? error.message\n : String(error);\n getUI().log.error(`Doctor failed: ${message}`);\n process.exit(1);\n }\n}\n","import type { ProgramConfig } from '@lib/programs/program-step';\n\nimport type { Command } from '../command';\n\nimport { dispatchProgram, mergeCommandOptions } from './shared';\n\nexport interface NativeCommandFactoryOpts {\n /** Subcommands nested under this command. */\n children?: readonly Command[];\n}\n\n/**\n * Build a yargs `Command` from a wizard-native `ProgramConfig`.\n *\n * Collapses the previously duplicated boilerplate (read `config.command`,\n * merge skill-program flags with program-specific options, dispatch via\n * `runWizard` / `runWizardCI`) into a single call.\n */\nexport function nativeCommandFactory(\n config: ProgramConfig,\n opts: NativeCommandFactoryOpts = {},\n): Command {\n if (!config.command) {\n throw new Error(\n `nativeCommandFactory: program \"${config.id}\" has no \\`command\\` — wizard-native programs must declare a CLI name`,\n );\n }\n return {\n name: config.command,\n description: config.description,\n options: mergeCommandOptions(config),\n children: opts.children,\n handler: (argv) => dispatchProgram(config, argv),\n };\n}\n","import { migrationConfig } from '@lib/programs/migration/index';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard migrate` — flat skill command, Statsig today.\n *\n * Stays flat while there's only one vendor. When a second vendor lands,\n * restructure into a family with `familyCommandFactory` and publish each\n * vendor as a `cliEntries` entry with `parentCommand: 'migrate'` from\n * context-mill. That move is a deliberate breaking change for users\n * (`wizard migrate` stops running Statsig directly), so do it explicitly\n * when the second vendor arrives, not pre-emptively.\n */\nexport const migrateCommand: Command = nativeCommandFactory(migrationConfig);\n","import { revenueAnalyticsConfig } from '@lib/programs/revenue-analytics/index';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard revenue-analytics` — flat skill command, Stripe today.\n *\n * Stays flat while there's only one provider. Restructure into a family\n * if/when a second provider lands.\n */\nexport const revenueCommand: Command = nativeCommandFactory(\n revenueAnalyticsConfig,\n);\n","import { warehouseSourceConfig } from '@lib/programs/warehouse-source/index';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard warehouse` — detect and connect a data warehouse source.\n *\n * Mirrors `revenue-analytics`: flat skill command driven by the\n * warehouse-source program.\n */\nexport const warehouseCommand: Command = nativeCommandFactory(\n warehouseSourceConfig,\n);\n","import { runWizard, runWizardCI } from '@lib/runners';\nimport { selfDrivingConfig } from '@lib/programs/self-driving/index';\nimport { skillProgramOptions } from './skill-program-options';\nimport type { Command } from './command';\n\nexport const selfDrivingCommand: Command = {\n name: 'self-driving',\n description: selfDrivingConfig.description,\n options: {\n ...skillProgramOptions,\n ...(selfDrivingConfig.cliOptions ?? {}),\n },\n check: (argv) => {\n // self-driving builds on an existing integration and is fully interactive,\n // so the modes that break it are rejected before the TUI/agent loop spins\n // up rather than failing late (a 403 on the first MCP probe under --signup,\n // or a stalled `wizard_ask` with no bridge under --ci).\n if (argv.signup) {\n throw new Error(\n '`self-driving` cannot run with --signup. It builds on an existing ' +\n 'PostHog integration — run the base `wizard` to create your account ' +\n 'and set up PostHog first, then run `wizard self-driving`.',\n );\n }\n if (argv.ci) {\n throw new Error(\n '`self-driving` cannot run in CI mode — it requires interactive steps ' +\n '(GitHub connect, issue-tracker selection, custom-scout approval).',\n );\n }\n return true;\n },\n handler: (argv) => {\n const extras =\n selfDrivingConfig.mapCliOptions?.(argv as Record<string, unknown>) ?? {};\n const options = { ...argv, ...extras };\n if (options.ci) {\n runWizardCI(selfDrivingConfig, options);\n } else {\n runWizard(selfDrivingConfig, options);\n }\n },\n};\n","import type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { Program } from '@lib/programs/program-registry';\nimport { VERSION } from '@lib/version';\nimport type { Command } from './command';\n\nexport const slackCommand: Command = {\n name: 'slack',\n description: 'Connect PostHog to your Slack',\n handler: runSlackConnect,\n // Mirrors the mcp command family shape: `wizard slack` and\n // `wizard slack add` run the same connect flow.\n children: [\n {\n name: 'add',\n description: 'Connect PostHog to your Slack',\n handler: runSlackConnect,\n },\n ],\n};\n\nfunction runSlackConnect(argv: Arguments): void {\n void (async () => {\n const debug = argv.debug as boolean | undefined;\n\n try {\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession } = await import('@lib/wizard-session');\n const tui = startTUI(VERSION, Program.SlackConnect);\n tui.store.session = buildSession({ debug });\n } catch (err) {\n // TUI unavailable — connecting Slack has no headless fallback.\n setUI(new LoggingUI());\n getUI().log.error(\n `Connecting Slack requires an interactive terminal. ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n process.exit(1);\n }\n })();\n}\n","import { runWizard, runWizardCI } from '@lib/runners';\nimport { errorTrackingUploadSourceMapsConfig } from '@lib/programs/error-tracking-upload-source-maps/index';\nimport { skillProgramOptions } from './skill-program-options';\nimport type { Command } from './command';\n\nexport const uploadSourcemapsCommand: Command = {\n // Must match ProgramConfig.command; legacy alias kept for #489 regression.\n name: [errorTrackingUploadSourceMapsConfig.command!, 'upload-sourcemaps'],\n description: errorTrackingUploadSourceMapsConfig.description,\n options: {\n ...skillProgramOptions,\n ...(errorTrackingUploadSourceMapsConfig.cliOptions ?? {}),\n },\n handler: (argv) => {\n const extras =\n errorTrackingUploadSourceMapsConfig.mapCliOptions?.(\n argv as Record<string, unknown>,\n ) ?? {};\n const options = { ...argv, ...extras };\n if (options.ci) {\n runWizardCI(errorTrackingUploadSourceMapsConfig, options);\n } else {\n runWizard(errorTrackingUploadSourceMapsConfig, options);\n }\n },\n};\n","import type { Arguments } from 'yargs';\nimport { POSTHOG_DOCS_URL } from '@lib/constants';\nimport { runWizard, runWizardCI } from '@lib/runners';\nimport { createSkillProgram } from '@lib/programs/agent-skill/index';\n\n/** Run an arbitrary context-mill skill by id (`wizard skill <id>`, headless with `--ci`). */\nexport function runSkillMode(argv: Arguments): void {\n const skillId = argv.skill as string;\n const config = createSkillProgram({\n skillId,\n command: 'skill',\n id: 'agent-skill',\n description: `Run skill: ${skillId}`,\n integrationLabel: skillId,\n successMessage: `${skillId} completed!`,\n reportFile: `posthog-${skillId}-report.md`,\n docsUrl: POSTHOG_DOCS_URL,\n spinnerMessage: `Running ${skillId}...`,\n estimatedDurationMinutes: 5,\n });\n const options = { ...argv, skillId };\n if (argv.ci) {\n runWizardCI(config, options);\n } else {\n runWizard(config, options);\n }\n}\n","import type { Arguments } from 'yargs';\n\nimport { getSkillsBaseUrl } from '@lib/constants';\nimport { fetchSkillMenu, type CliEntry } from '@lib/wizard-tools';\nimport { analytics } from '@utils/analytics';\n\nimport { runSkillMode } from './basic-integration/skill';\nimport { skillProgramOptions } from './skill-program-options';\nimport { runCommandHandler } from './factories/shared';\nimport type { Command } from './command';\n\n/** Read the `<skill-name>` positional (yargs camelCases the hyphenated key). */\nfunction readSkillName(argv: Arguments): string {\n return String(argv.skillName ?? argv['skill-name'] ?? '').trim();\n}\n\nconst BROWSABLE_ROLES: ReadonlySet<CliEntry['role']> = new Set([\n 'command',\n 'skill',\n]);\n\nfunction formatEntry(entry: CliEntry): string {\n const path = entry.parentCommand\n ? `wizard ${entry.parentCommand} ${entry.command}`\n : entry.command\n ? `wizard ${entry.command}`\n : `wizard skill ${entry.skillId}`;\n return ` ${entry.skillId.padEnd(38)} ${path.padEnd(36)} ${\n entry.description\n }`;\n}\n\n/**\n * `wizard skill list` — fetch and print every browsable skill in the catalog.\n *\n * Reads the live `skill-menu.json` so new skills appear immediately after a\n * context-mill release. `internal` skills are excluded from the listing.\n */\nconst listCommand: Command = {\n name: 'list',\n description: 'List every browsable skill in the catalog',\n handler: (argv) => {\n runCommandHandler(async () => {\n const skillsBaseUrl = getSkillsBaseUrl(Boolean(argv['local-mcp']));\n const menu = await fetchSkillMenu(skillsBaseUrl);\n if (!menu) {\n analytics.wizardCapture('cli dispatch error', {\n reason: 'registry unreachable',\n family: 'skill',\n sub: 'list',\n skillsBaseUrl,\n });\n try {\n await analytics.flush();\n } catch {\n /* best-effort */\n }\n process.stderr.write(\n `\\n\\x1b[1;91m✖ Couldn't reach the skill registry.\\x1b[0m\\n` +\n ` Check your network connection and try again.\\n\\n`,\n );\n process.exit(1);\n }\n const entries = (menu.cliEntries ?? []).filter((e) =>\n BROWSABLE_ROLES.has(e.role),\n );\n if (entries.length === 0) {\n process.stdout.write('No skills found.\\n');\n return;\n }\n process.stdout.write(\n `${entries.length} skill${entries.length === 1 ? '' : 's'}:\\n`,\n );\n process.stdout.write(\n ` ${'SKILL ID'.padEnd(38)} ${'COMMAND'.padEnd(36)} DESCRIPTION\\n`,\n );\n for (const entry of entries) {\n process.stdout.write(`${formatEntry(entry)}\\n`);\n }\n });\n },\n};\n\n/**\n * `wizard skill <skill-name>` — run a single context-mill skill by id.\n * `wizard skill list` — list every browsable skill in the catalog.\n *\n * Replaces the old `--skill=<id>` flag on the default command. The skill id\n * is fetched from context-mill's release at runtime (same mechanism the flag\n * used), so any published skill id works. Pass `--ci` to run headlessly.\n */\nexport const skillCommand: Command = {\n name: 'skill <skill-name>',\n description: 'Run a specific context-mill skill by name (or `list` them)',\n children: [listCommand],\n options: {\n ...skillProgramOptions,\n },\n // yargs already enforces the `<skill-name>` positional, but an\n // explicitly-empty value (`wizard skill \"\"`) would otherwise slip\n // through to a broken run. Reject it with the same friendly message\n // the old --skill flag gave. When `wizard skill list` matched the\n // child instead, yargs leaves the positional unset — the `null` guard\n // keeps the check from rejecting that route.\n check: (argv) => {\n if (argv.skillName == null && argv['skill-name'] == null) return true;\n if (!readSkillName(argv)) {\n throw new Error(\n 'skill needs a skill name, e.g. `wizard skill audit-events`',\n );\n }\n return true;\n },\n handler: (argv) => {\n // runSkillMode reads `argv.skill`; bridge the positional onto it.\n runSkillMode({ ...argv, skill: readSkillName(argv) });\n },\n};\n","import { spawnSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\nimport { debug } from '@utils/debug';\n\n/**\n * A coding agent whose global instructions file the PostHog CLI steering\n * snippet can be installed into. Project-level installs are handled by\n * `posthog-cli api agents-md install` in the target repo; this step only\n * manages the per-user (global) instruction files.\n */\nexport interface CliSteeringTarget {\n id: string;\n name: string;\n /** Global agent instructions file the steering snippet is written to. */\n instructionsPath(): string;\n /** Whether the agent appears to be installed on this machine. */\n isDetected(): boolean;\n}\n\nconst dirExists = (...segments: string[]): boolean => {\n try {\n return fs.existsSync(path.join(os.homedir(), ...segments));\n } catch {\n return false;\n }\n};\n\nexport const CLI_STEERING_TARGETS: readonly CliSteeringTarget[] = [\n {\n id: 'claude-code',\n name: 'Claude Code',\n instructionsPath: () => path.join(os.homedir(), '.claude', 'CLAUDE.md'),\n isDetected: () => dirExists('.claude'),\n },\n {\n id: 'codex',\n name: 'Codex',\n instructionsPath: () => path.join(os.homedir(), '.codex', 'AGENTS.md'),\n isDetected: () => dirExists('.codex'),\n },\n {\n id: 'gemini',\n name: 'Gemini CLI',\n instructionsPath: () => path.join(os.homedir(), '.gemini', 'GEMINI.md'),\n isDetected: () => dirExists('.gemini'),\n },\n];\n\nexport function findTarget(id: string): CliSteeringTarget | undefined {\n return CLI_STEERING_TARGETS.find((target) => target.id === id);\n}\n\nexport function detectTargets(): CliSteeringTarget[] {\n return CLI_STEERING_TARGETS.filter((target) => target.isDetected());\n}\n\nexport interface SteeringInstallResult {\n success: boolean;\n filePath: string;\n error?: string;\n}\n\nexport interface CliInstallResult {\n success: boolean;\n error?: string;\n}\n\nconst spawnOptions = {\n encoding: 'utf-8' as const,\n // npm/posthog-cli are npm.cmd/posthog-cli.cmd on Windows; spawnSync only\n // resolves them through a shell.\n shell: process.platform === 'win32',\n};\n\n/**\n * Install or update the PostHog CLI in the user's environment. `npm install\n * --global @posthog/cli@latest` covers both first-time installs and upgrades\n * for existing npm-installed CLIs.\n */\nexport function installOrUpdatePostHogCli(): CliInstallResult {\n const args = ['install', '--global', '@posthog/cli@latest'];\n debug(`Running npm ${args.join(' ')}`);\n\n const result = spawnSync('npm', args, spawnOptions);\n\n if (result.error) {\n return {\n success: false,\n error: `Failed to run npm: ${result.error.message}. Is Node.js installed?`,\n };\n }\n if (result.status !== 0) {\n const detail = (result.stderr || result.stdout || '').trim();\n return {\n success: false,\n error:\n detail ||\n `npm install --global @posthog/cli@latest exited with status ${\n result.status ?? 'unknown'\n }`,\n };\n }\n return { success: true };\n}\n\n/**\n * Delegate the actual write to the installed `posthog-cli api agents-md\n * install`. The steering snippet lives in the CLI (its single source of truth),\n * so the command should run only after `installOrUpdatePostHogCli` refreshes\n * the CLI to the latest release.\n */\nexport function installSteeringSnippet(\n filePath: string,\n): SteeringInstallResult {\n const args = ['api', 'agents-md', 'install', '--path', filePath];\n debug(`Running posthog-cli ${args.join(' ')}`);\n\n const result = spawnSync('posthog-cli', args, {\n ...spawnOptions,\n env: { ...process.env, POSTHOG_CLI_EXPERIMENTAL_API: '1' },\n });\n\n if (result.error) {\n return {\n success: false,\n filePath,\n error: `Failed to run posthog-cli: ${result.error.message}. Make sure npm's global bin directory is on your PATH.`,\n };\n }\n if (result.status !== 0) {\n const detail = (result.stderr || result.stdout || '').trim();\n return {\n success: false,\n filePath,\n error:\n detail ||\n `posthog-cli exited with status ${result.status ?? 'unknown'}`,\n };\n }\n return { success: true, filePath };\n}\n","import * as path from 'node:path';\nimport * as readline from 'node:readline/promises';\nimport type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { analytics } from '@utils/analytics';\nimport {\n CLI_STEERING_TARGETS,\n type CliSteeringTarget,\n detectTargets,\n findTarget,\n installOrUpdatePostHogCli,\n installSteeringSnippet,\n} from '@steps/install-cli-steering';\nimport type { Command } from '../command';\n\nexport const cliAddCommand: Command = {\n name: 'add',\n description:\n \"Install or update PostHog CLI and add steering instructions to your coding agent's global instructions file\",\n options: {\n agent: {\n describe: 'Agent to install the instructions for',\n choices: CLI_STEERING_TARGETS.map((target) => target.id),\n type: 'string',\n },\n path: {\n describe:\n 'Write to an explicit instructions file instead of a detected agent',\n type: 'string',\n },\n all: {\n default: false,\n describe: 'Install for every detected agent without prompting',\n type: 'boolean',\n },\n },\n examples: [\n ['wizard cli add', 'Detect your coding agents and pick one'],\n [\n 'wizard cli add --agent claude-code',\n 'Install for Claude Code (~/.claude/CLAUDE.md)',\n ],\n ['wizard cli add --all', 'Install for every detected agent'],\n [\n 'wizard cli add --path ./AGENTS.md',\n 'Install into a specific instructions file',\n ],\n ],\n check: (argv) => {\n if (argv.all && (argv.agent || argv.path)) {\n throw new Error('--all cannot be combined with --agent or --path');\n }\n return true;\n },\n handler: (argv) => {\n void runCliAdd(argv);\n },\n};\n\nasync function runCliAdd(argv: Arguments): Promise<void> {\n setUI(new LoggingUI());\n const ui = getUI();\n ui.intro('PostHog CLI setup');\n\n const files = await resolveTargetFiles(argv);\n if (files.length === 0) {\n process.exit(1);\n return;\n }\n\n ui.log.info('Installing or updating PostHog CLI...');\n const cliInstallResult = installOrUpdatePostHogCli();\n if (!cliInstallResult.success) {\n ui.log.error(\n `Failed to install or update PostHog CLI: ${\n cliInstallResult.error ?? ''\n }`,\n );\n analytics.wizardCapture('cli steering installed', {\n files: files.length,\n failures: files.length,\n cli_install_failed: true,\n agent: typeof argv.agent === 'string' ? argv.agent : undefined,\n });\n process.exit(1);\n return;\n }\n ui.log.success('Installed or updated PostHog CLI.');\n\n let failures = 0;\n for (const file of files) {\n const result = installSteeringSnippet(file);\n if (result.success) {\n ui.log.success(`Installed PostHog steering instructions in ${file}`);\n } else {\n failures += 1;\n ui.log.error(`Failed to update ${file}: ${result.error ?? ''}`);\n }\n }\n\n analytics.wizardCapture('cli steering installed', {\n files: files.length,\n failures,\n agent: typeof argv.agent === 'string' ? argv.agent : undefined,\n });\n\n if (failures > 0) {\n process.exit(1);\n return;\n }\n ui.outro(\n 'Done. PostHog CLI is installed and your agent will now use `posthog-cli api` for PostHog tasks.',\n );\n process.exit(0);\n}\n\n/** Resolve which instruction files to write, from flags, detection, or a prompt. */\nasync function resolveTargetFiles(argv: Arguments): Promise<string[]> {\n const ui = getUI();\n\n if (typeof argv.path === 'string' && argv.path.trim()) {\n return [path.resolve(argv.path.trim())];\n }\n\n if (typeof argv.agent === 'string') {\n // yargs `choices` already rejected unknown ids.\n const target = findTarget(argv.agent);\n if (!target) {\n ui.log.error(`Unsupported agent: ${argv.agent}`);\n return [];\n }\n return [target.instructionsPath()];\n }\n\n const detected = detectTargets();\n if (detected.length === 0) {\n ui.log.error(\n 'No supported coding agents detected. Pass --agent <id> or --path <file> to choose a target.',\n );\n ui.log.info(\n `Supported agents: ${CLI_STEERING_TARGETS.map((t) => t.id).join(', ')}`,\n );\n return [];\n }\n\n if (argv.all === true) {\n ui.log.info(\n `Installing for all detected agents: ${detected\n .map((t) => t.name)\n .join(', ')}`,\n );\n return detected.map((target) => target.instructionsPath());\n }\n\n if (detected.length === 1) {\n ui.log.info(\n `Detected ${detected[0].name} (${detected[0].instructionsPath()})`,\n );\n return [detected[0].instructionsPath()];\n }\n\n // Non-interactive shells can't pick, so install for every detected agent —\n // the snippet is additive and idempotent, mirroring how MCP install treats\n // all supported clients.\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n ui.log.info(\n `Installing for all detected agents: ${detected\n .map((t) => t.name)\n .join(', ')}`,\n );\n return detected.map((target) => target.instructionsPath());\n }\n\n const selected = await promptForTargets(detected);\n return selected.map((target) => target.instructionsPath());\n}\n\n/** Minimal numbered selection — this command is intentionally not a TUI flow. */\nasync function promptForTargets(\n detected: CliSteeringTarget[],\n): Promise<CliSteeringTarget[]> {\n const ui = getUI();\n ui.log.info('Which coding agent are you using?');\n detected.forEach((target, index) => {\n ui.log.info(\n ` ${index + 1}) ${target.name} (${target.instructionsPath()})`,\n );\n });\n ui.log.info(` ${detected.length + 1}) All of the above`);\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n try {\n for (;;) {\n const answer = (\n await rl.question(`Select 1-${detected.length + 1}: `)\n ).trim();\n const choice = Number(answer);\n if (\n Number.isInteger(choice) &&\n choice >= 1 &&\n choice <= detected.length\n ) {\n return [detected[choice - 1]];\n }\n if (choice === detected.length + 1) {\n return detected;\n }\n ui.log.warn(`Enter a number between 1 and ${detected.length + 1}.`);\n }\n } finally {\n rl.close();\n }\n}\n","import { cliAddCommand } from './add';\nimport type { Command } from '../command';\n\nexport const cliCommand: Command = {\n name: 'cli',\n description: 'PostHog CLI agent integration commands',\n children: [cliAddCommand],\n};\n","#!/usr/bin/env node\nimport { satisfies } from 'semver';\n\nconst NODE_VERSION_RANGE = '>=18.17.0';\n\n// Have to run this above the other imports because they are importing clack that\n// has the problematic imports.\nif (!satisfies(process.version, NODE_VERSION_RANGE)) {\n // eslint-disable-next-line no-console\n console.log(\n `PostHog wizard requires Node.js ${NODE_VERSION_RANGE}. You are using Node.js ${process.version}. Please upgrade your Node.js version.`,\n );\n process.exit(1);\n}\n\n// Test mock server — only loaded when NODE_ENV is 'test'.\n// In production builds, tsdown replaces process.env.NODE_ENV with 'production',\n// making this block dead code.\nif (process.env.NODE_ENV === 'test') {\n void (async () => {\n try {\n const { server } = await import('./e2e-tests/mocks/server.js');\n server.listen({\n onUnhandledRequest: 'bypass',\n });\n } catch (error) {\n // Mock server import failed - this can happen during non-E2E tests\n }\n })();\n}\n\nimport { Wizard } from './src/wizard';\nimport { basicIntegrationCommand } from './src/commands/basic-integration';\nimport { mcpCommand } from './src/commands/mcp';\nimport { auditCommand } from './src/commands/audit';\nimport { doctorCommand } from './src/commands/doctor';\nimport { migrateCommand } from './src/commands/migrate';\nimport { revenueCommand } from './src/commands/revenue';\nimport { warehouseCommand } from './src/commands/warehouse';\nimport { selfDrivingCommand } from './src/commands/self-driving';\nimport { slackCommand } from './src/commands/slack';\nimport { uploadSourcemapsCommand } from './src/commands/upload-sourcemaps';\nimport { skillCommand } from './src/commands/skill';\nimport { cliCommand } from './src/commands/cli';\nimport { recoverOrphanedSettingsBackups } from './src/lib/agent/claude-settings';\n\n// Heal any .claude/settings backup a previous interrupted run left orphaned,\n// before anything else reads Claude settings — conflict detection, OAuth, and\n// the agent all need to see the user's real settings file. The install dir is\n// read directly from argv/env because yargs hasn't parsed yet.\nrecoverOrphanedSettingsBackups(resolveInstallDir());\n\nfunction resolveInstallDir(): string {\n const args = process.argv.slice(2);\n const flagIndex = args.indexOf('--install-dir');\n if (flagIndex !== -1 && args[flagIndex + 1]) return args[flagIndex + 1];\n const inline = args.find((a) => a.startsWith('--install-dir='));\n if (inline) return inline.slice('--install-dir='.length);\n return process.env.POSTHOG_WIZARD_INSTALL_DIR ?? process.cwd();\n}\n\nWizard.use(basicIntegrationCommand)\n .use(mcpCommand)\n .use(cliCommand)\n .use(auditCommand)\n .use(doctorCommand)\n .use(migrateCommand)\n .use(revenueCommand)\n .use(warehouseCommand)\n .use(selfDrivingCommand)\n .use(slackCommand)\n .use(uploadSourcemapsCommand)\n .use(skillCommand)\n .init();\n"],"mappings":"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"}
1
+ {"version":3,"file":"bin.js","names":["getContentBlocks","DOCS_URL","REPORT_FILE","DOCS_URL","getContentBlocks","REPORT_FILE","DOCS_URL","agentSkillContentBlocks","agentSkillContentBlocks","fs","path","path"],"sources":["../src/commands/command.ts","../src/wizard.ts","../src/commands/provision.ts","../src/commands/basic-integration/index.ts","../src/lib/programs/shared/package-scanning.ts","../src/lib/programs/revenue-analytics/detect.ts","../src/lib/programs/revenue-analytics/steps.ts","../src/lib/programs/agent-skill/content/index.tsx","../src/lib/programs/revenue-analytics/index.ts","../src/lib/warehouse-sources/registry.ts","../src/lib/warehouse-sources/detect.ts","../src/lib/programs/warehouse-source/detect.ts","../src/lib/programs/warehouse-source/steps.ts","../src/lib/programs/warehouse-source/index.ts","../src/lib/programs/agent-skill/steps.ts","../src/lib/programs/agent-skill/index.ts","../src/lib/programs/audit/detect.ts","../src/lib/programs/audit/seed.ts","../src/lib/programs/audit/index.ts","../src/lib/programs/events-audit/steps.ts","../src/lib/programs/events-audit/seed.ts","../src/lib/programs/events-audit/index.ts","../src/lib/programs/posthog-doctor/steps.ts","../src/lib/programs/posthog-doctor/types.ts","../src/lib/programs/posthog-doctor/fetch.ts","../src/lib/programs/posthog-doctor/kind-metadata.ts","../src/lib/programs/posthog-doctor/index.ts","../src/lib/programs/web-analytics-doctor/detect.ts","../src/lib/programs/web-analytics-doctor/steps.ts","../src/lib/programs/web-analytics-doctor/index.ts","../src/lib/programs/migration/steps.ts","../src/lib/programs/migration/content/vendor-stack.tsx","../src/lib/programs/migration/content/free-tier.tsx","../src/lib/programs/migration/content/pricing-structure.tsx","../src/lib/programs/migration/content/index.tsx","../src/lib/programs/migration/index.ts","../src/lib/programs/error-tracking-upload-source-maps/detect.ts","../src/lib/programs/error-tracking-upload-source-maps/steps.ts","../src/lib/programs/error-tracking-upload-source-maps/prompt.ts","../src/lib/programs/error-tracking-upload-source-maps/content/index.tsx","../src/lib/programs/error-tracking-upload-source-maps/index.ts","../src/lib/programs/self-driving/detect.ts","../src/lib/programs/self-driving/steps.ts","../src/lib/programs/self-driving/prompt.ts","../src/lib/programs/self-driving/content/tips.ts","../src/lib/programs/self-driving/index.ts","../src/lib/programs/mcp/index.ts","../src/lib/programs/slack/index.ts","../src/lib/programs/program-registry.ts","../src/commands/mcp/add.ts","../src/commands/mcp/remove.ts","../src/commands/mcp/tutorial.ts","../src/commands/mcp/index.ts","../src/lib/runners/resolve-no-telemetry.ts","../src/lib/runners/run-wizard.ts","../src/lib/runners/run-wizard-ci.ts","../src/commands/skill-program-options.ts","../src/commands/factories/shared.ts","../src/lib/programs/dispatch-family.ts","../src/ui/tui/primitives/PromptLabel.tsx","../src/ui/tui/primitives/ConfirmButton.tsx","../src/ui/tui/hooks/keyboard-hints-utils.ts","../src/ui/tui/hooks/useKeyboardHints.tsx","../src/ui/tui/hooks/useKeyBindings.ts","../src/ui/tui/primitives/PickerMenu.tsx","../src/commands/factories/family-picker.tsx","../src/commands/factories/family-command-factory.ts","../src/commands/audit.ts","../src/commands/doctor.ts","../src/commands/factories/native-command-factory.ts","../src/commands/migrate.ts","../src/commands/revenue.ts","../src/commands/warehouse.ts","../src/commands/self-driving.ts","../src/commands/slack.ts","../src/commands/upload-sourcemaps.ts","../src/commands/basic-integration/skill.ts","../src/commands/skill.ts","../src/steps/install-cli-steering/index.ts","../src/commands/cli/add.ts","../src/commands/cli/index.ts","../bin.ts"],"sourcesContent":["import type {\n Arguments,\n Argv,\n CommandModule,\n Options,\n PositionalOptions,\n} from 'yargs';\nimport { setEntryCommand } from '@utils/links';\n\nexport interface Command {\n /** Yargs command name. Use `['$0']` for the default command. */\n name: string | readonly string[];\n description: string;\n /** Flags exposed by this command. Same shape as yargs `.options()`. */\n options?: Record<string, Options>;\n /**\n * Positional arguments declared in `name` (e.g. the `id` in `skill [id]`).\n * Under `.strictOptions()`, yargs only treats a positional as a known\n * argument once it's registered via `.positional()` — a command-string\n * positional alone is rejected as `Unknown argument`. Declare each one here\n * so an optional positional like `skill [id]` actually accepts its value.\n */\n positionals?: Record<string, PositionalOptions>;\n /** Nested subcommands. */\n children?: readonly Command[];\n /** `--help` examples shown for this command. */\n examples?: ReadonlyArray<readonly [string, string]>;\n /**\n * Called synchronously by yargs when the command matches. Wrap async work in\n * `void (async () => { ... })()`. Optional only when `children` is set — in\n * that case yargs requires the user to pick a subcommand (or to set\n * `interactiveDefault` for an in-process picker).\n */\n handler?: (argv: Arguments) => void;\n /**\n * Cross-flag validation run by yargs after parsing. Throw to reject (yargs\n * prints the message and exits non-zero); return `true` to accept. Prefer\n * this over per-option `conflicts` for mutually exclusive flags: yargs\n * counts a `default`-valued flag as \"present\", so `conflicts` misfires on\n * boolean flags that default to `false` — a hand-written predicate only\n * sees what you test for (e.g. truthiness).\n */\n check?: (argv: Arguments) => boolean;\n /**\n * Optional handler invoked when this command has `children` but the user\n * supplied no subcommand. Use it to mount an interactive picker over the\n * children so `wizard audit` (no leaf) opens a TUI menu instead of yargs\n * help. When set, suppresses the implicit `demandCommand(1)`.\n *\n * May return a Promise — yargs awaits the result before exiting.\n */\n interactiveDefault?: (argv: Arguments) => void | Promise<void>;\n /**\n * When true, this child is the \"default\" leaf in its family: the\n * family picker pre-highlights it so a single Enter runs it. The picker\n * still always opens — this never auto-runs the child. At most one child\n * per parent should be marked. Propagated from the context-mill manifest\n * entry's `default` flag through `skillCommandFactory`.\n */\n default?: boolean;\n}\n\n/** Extract the bare command word(s) from a yargs name spec, dropping positionals and aliases' arg syntax. */\nexport function commandKeys(name: string | readonly string[]): string[] {\n const list: readonly string[] = typeof name === 'string' ? [name] : name;\n return list.map((n) => n.trim().split(/\\s+/)[0]);\n}\n\nexport function toCommandModule(\n cmd: Command,\n parentPath: readonly string[],\n): CommandModule {\n // `wizard slack` → 'slack', `wizard mcp add` → 'mcp-add'. The default\n // `$0` resolves to '' and is skipped — its handler reports itself.\n const entryCommand = [...parentPath, commandKeys(cmd.name)[0]]\n .filter((key) => key !== '$0')\n .join('-');\n return {\n command: cmd.name,\n describe: cmd.description,\n builder: (y: Argv) => {\n let next = cmd.options ? y.options(cmd.options) : y;\n for (const [key, opts] of Object.entries(cmd.positionals ?? {})) {\n next = next.positional(key, opts);\n }\n if (cmd.check) next = next.check(cmd.check);\n for (const [usage, description] of cmd.examples ?? []) {\n next = next.example(usage, description);\n }\n const ownPath = [...parentPath, commandKeys(cmd.name)[0]];\n for (const child of cmd.children ?? []) {\n next = next.command(toCommandModule(child, ownPath));\n }\n if (cmd.children?.length && !cmd.handler && !cmd.interactiveDefault) {\n next = next.demandCommand(1);\n }\n return next;\n },\n handler: (argv: Arguments) => {\n if (entryCommand) setEntryCommand(entryCommand);\n const run = cmd.handler ?? cmd.interactiveDefault ?? (() => undefined);\n run(argv);\n },\n };\n}\n","import yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport type { Argv } from 'yargs';\nimport { IS_PRODUCTION_BUILD } from '@env';\nimport { toCommandModule, type Command } from './commands/command';\n\n/**\n * Global yargs options applied to every command. These are read from the\n * `POSTHOG_WIZARD` env prefix as well as flags.\n *\n * Options with `hidden: true` are \"internal modes\" — they don't show up in\n * `--help` but are still accepted on every command. The catalog of internal\n * flags and what each one does lives in CONTRIBUTING.md.\n */\nexport const GLOBAL_OPTIONS = {\n debug: {\n default: false,\n describe: 'Enable verbose logging\\nenv: POSTHOG_WIZARD_DEBUG',\n type: 'boolean' as const,\n },\n region: {\n describe: 'PostHog cloud region\\nenv: POSTHOG_WIZARD_REGION',\n choices: ['us', 'eu'] as const,\n type: 'string' as const,\n },\n signup: {\n default: false,\n describe:\n 'Create a new PostHog account during setup\\nenv: POSTHOG_WIZARD_SIGNUP',\n type: 'boolean' as const,\n },\n telemetry: {\n default: true,\n describe:\n 'Send wizard run state to PostHog (pass --no-telemetry to disable)\\nenv: POSTHOG_WIZARD_TELEMETRY',\n type: 'boolean' as const,\n },\n 'api-key': {\n describe:\n 'PostHog personal API key (phx_xxx) for authentication\\nenv: POSTHOG_WIZARD_API_KEY',\n type: 'string' as const,\n },\n 'project-id': {\n describe:\n 'PostHog project ID to use (optional; when not set, uses default from API key or OAuth)\\nenv: POSTHOG_WIZARD_PROJECT_ID',\n type: 'string' as const,\n },\n email: {\n describe:\n 'Email address for signup (used with --signup)\\nenv: POSTHOG_WIZARD_EMAIL',\n type: 'string' as const,\n },\n // ── Internal modes ─────────────────────────────────────────────────\n // Hidden from `--help`. See CONTRIBUTING.md for what each one does.\n 'local-mcp': {\n default: false,\n describe:\n 'Use local MCP server at http://localhost:8787/mcp\\nenv: POSTHOG_WIZARD_LOCAL_MCP',\n type: 'boolean' as const,\n hidden: true,\n },\n benchmark: {\n default: false,\n describe:\n 'Run in benchmark mode with per-phase token tracking\\nenv: POSTHOG_WIZARD_BENCHMARK',\n type: 'boolean' as const,\n hidden: true,\n },\n 'yara-report': {\n default: false,\n describe:\n 'Print YARA scanner summary after the agent run\\nenv: POSTHOG_WIZARD_YARA_REPORT',\n type: 'boolean' as const,\n hidden: true,\n },\n};\n\nexport class Wizard {\n private cli: Argv;\n\n private constructor() {\n let cli = yargs(hideBin(process.argv))\n .env('POSTHOG_WIZARD')\n .options(GLOBAL_OPTIONS);\n\n // CI mode (--ci) is only supported in dev/test. It is left undeclared in\n // published builds (NODE_ENV==='production'), so .strictOptions() rejects\n // it there as an unknown argument — exactly like any other unrecognized\n // flag. init() additionally detects it up front to print a clearer message.\n if (!IS_PRODUCTION_BUILD) {\n cli = cli.option('ci', {\n default: false,\n describe:\n 'Enable CI mode for non-interactive execution\\nenv: POSTHOG_WIZARD_CI',\n type: 'boolean',\n hidden: true,\n });\n }\n\n this.cli = cli\n .strictOptions()\n // Reject unrecognized commands (e.g. `wizard bogus`) instead of letting\n // them fall through to the default `$0` integration flow.\n .strictCommands()\n // Print a concise error and point to `--help`, instead of yargs' default\n // of dumping the entire usage screen under every failure.\n .fail((msg, err) => {\n const text = msg || (err && err.message) || 'Invalid arguments';\n process.stderr.write(\n `\\n\\x1b[1;91m✖ ${text}\\x1b[0m\\n` +\n ` Run \\`wizard --help\\` to see available commands and options.\\n\\n`,\n );\n process.exit(1);\n })\n .help()\n .alias('help', 'h')\n .version()\n .alias('version', 'v');\n }\n\n /** Start a chain; equivalent to `new Wizard().use(...cmds)`. */\n static use(...cmds: Command[]): Wizard {\n return new Wizard().use(...cmds);\n }\n\n /** Register one or more commands with yargs. */\n use(...cmds: Command[]): this {\n for (const cmd of cmds) {\n this.cli = this.cli.command(toCommandModule(cmd, []));\n }\n return this;\n }\n\n /** Parse argv and dispatch to the matching registered command. */\n init(): void {\n // In published builds, `--ci` is undeclared, so yargs would reject it as\n // an unknown argument — accurate but unhelpful, since --help doesn't list\n // --ci either and the user has no path forward. POSTHOG_WIZARD_CI silently\n // no-ops for the same reason (yargs only resolves env vars for declared\n // options). Detect both up front and exit with a message that explains why.\n if (IS_PRODUCTION_BUILD) {\n const args = process.argv.slice(2);\n const argvHasCI = args.some(\n (a) => a === '--ci' || a === '--no-ci' || a.startsWith('--ci='),\n );\n const envHasCI =\n process.env.POSTHOG_WIZARD_CI != null &&\n process.env.POSTHOG_WIZARD_CI !== '';\n if (argvHasCI || envHasCI) {\n process.stderr.write(\n `\\n\\x1b[1;91m✖ CI mode is not currently supported in published builds.\\x1b[0m\\n\\n`,\n );\n process.exit(1);\n }\n }\n void this.cli.wrap(process.stdout.isTTY ? this.cli.terminalWidth() : 80)\n .argv;\n }\n}\n","import type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport type { ProvisioningResult } from '@utils/provisioning';\nimport type { Command } from './command';\n\nexport const provisionCommand: Command = {\n name: 'provision',\n description: 'Create a new PostHog account (headless, no TUI)',\n options: {\n email: {\n describe: 'Email address for the new account',\n type: 'string',\n demandOption: true,\n },\n region: {\n describe: 'Cloud region (us or eu)',\n choices: ['us', 'eu'] as const,\n default: 'us',\n },\n name: {\n describe: 'Name for the new account',\n type: 'string',\n default: '',\n },\n json: {\n describe:\n 'Emit JSON result to stdout (defaults to true when stdout is not a TTY)',\n type: 'boolean',\n },\n },\n examples: [\n ['wizard provision --email matt+test@posthog.com --region us', ''],\n ['wizard provision --email user@example.com --region eu --json', ''],\n ],\n handler: runProvision,\n};\n\nfunction runProvision(argv: Arguments): void {\n const jsonMode =\n argv.json === undefined ? !process.stdout.isTTY : Boolean(argv.json);\n if (!jsonMode) setUI(new LoggingUI());\n\n void provision({\n email: argv.email as string,\n region: (argv.region as string).toUpperCase() as 'US' | 'EU',\n name: (argv.name as string) ?? '',\n jsonMode,\n });\n}\n\ntype ProvisionArgs = {\n email: string;\n region: 'US' | 'EU';\n name: string;\n jsonMode: boolean;\n};\n\nasync function provision({\n email,\n region,\n name,\n jsonMode,\n}: ProvisionArgs): Promise<void> {\n try {\n const { provisionNewAccount } = await import('@utils/provisioning');\n if (!jsonMode) {\n getUI().log.info(`Provisioning account for ${email} in ${region}...`);\n }\n const result = await provisionNewAccount(email, name, region);\n emitResult(result, jsonMode);\n process.exit(0);\n } catch (error) {\n emitError(error, jsonMode);\n process.exit(1);\n }\n}\n\nfunction emitResult(result: ProvisioningResult, jsonMode: boolean): void {\n if (jsonMode) {\n process.stdout.write(`${JSON.stringify(result)}\\n`);\n return;\n }\n getUI().log.success('Account provisioned successfully:');\n getUI().log.info(` API Key: ${result.projectApiKey}`);\n getUI().log.info(` Host: ${result.host}`);\n getUI().log.info(` Project ID: ${result.projectId}`);\n getUI().log.info(` Account ID: ${result.accountId}`);\n getUI().log.info(` Access Token: ${result.accessToken}`);\n getUI().log.info(` Refresh Token: ${result.refreshToken}`);\n if (result.personalApiKey) {\n getUI().log.info(` Personal API Key: ${result.personalApiKey}`);\n }\n}\n\nfunction emitError(error: unknown, jsonMode: boolean): void {\n const msg = error instanceof Error ? error.message : String(error);\n const code = msg.includes('already associated')\n ? 'email_exists'\n : 'provisioning_failed';\n if (jsonMode) {\n process.stderr.write(`${JSON.stringify({ error: msg, code })}\\n`);\n return;\n }\n getUI().log.error(`Provisioning failed: ${msg}`);\n}\n","import { isNonInteractiveEnvironment } from '@utils/environment';\nimport { setEntryCommand } from '@utils/links';\nimport { provisionCommand } from '../provision';\nimport type { Command } from '../command';\n\nexport const basicIntegrationCommand: Command = {\n name: ['$0'],\n description: 'Run the PostHog setup wizard',\n // provision is a one-shot HTTP call tied to the base flow, not a wizard\n // program — it rides under the base command rather than as a peer.\n children: [provisionCommand],\n options: {\n 'install-dir': {\n describe:\n 'Directory to install PostHog in\\nenv: POSTHOG_WIZARD_INSTALL_DIR',\n type: 'string',\n },\n name: {\n describe:\n 'Name for account creation with --ci --signup\\nenv: POSTHOG_WIZARD_NAME',\n type: 'string',\n },\n // ── Internal modes ───────────────────────────────────────────────\n // Hidden from `--help`. See CONTRIBUTING.md for what each one does.\n playground: {\n default: false,\n describe: 'Launch the TUI primitives playground',\n type: 'boolean',\n hidden: true,\n },\n },\n check: (argv) => {\n // --playground is the standalone TUI demo; it can't combine with --ci.\n if (argv.playground && argv.ci) {\n throw new Error('--playground cannot be combined with --ci.');\n }\n return true;\n },\n handler: (argv) => {\n // The bare run is the integrate flow.\n setEntryCommand('integrate');\n // Each mode file is loaded only when its branch is taken, so a plain\n // `npx @posthog/wizard` never pulls in the CI or playground paths.\n void (async () => {\n if (argv.ci) {\n const { runCIInstall } = await import('./ci-install');\n return runCIInstall(argv);\n }\n if (isNonInteractiveEnvironment()) {\n const { failNonInteractive } = await import('./non-interactive');\n return failNonInteractive();\n }\n if (argv.playground) {\n const { runPlayground } = await import('./playground');\n return runPlayground();\n }\n const { runInteractive } = await import('./interactive');\n runInteractive(argv);\n })();\n },\n};\n","import type { Dirent } from 'fs';\nimport { readFileSync, readdirSync } from 'fs';\nimport { join, relative } from 'path';\nimport { IGNORED_DIRS } from '@utils/file-utils';\n\nexport const POSTHOG_SDKS = [\n 'posthog-js',\n 'posthog-node',\n 'posthog-react-native',\n 'posthog-android',\n 'posthog-ios',\n];\n\nexport const STRIPE_SDKS = [\n 'stripe',\n '@stripe/stripe-js',\n '@stripe/react-stripe-js',\n];\n\nexport interface PackageMatch {\n /** Path to the package.json relative to installDir */\n path: string;\n posthogSdks: string[];\n stripeSdks: string[];\n}\n\n/**\n * Recursively find all package.json files under installDir (max depth 3),\n * skipping common ignored directories. Returns matches with detected SDKs.\n */\nexport function findPackageJsons(\n installDir: string,\n maxDepth = 3,\n): PackageMatch[] {\n const matches: PackageMatch[] = [];\n\n function scan(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') && entry.name !== '.') continue;\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = join(dir, entry.name);\n\n if (entry.isFile() && entry.name === 'package.json') {\n try {\n const pkg = JSON.parse(readFileSync(fullPath, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const depNames = [\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ];\n const posthogSdks = depNames.filter((d) => POSTHOG_SDKS.includes(d));\n const stripeSdks = depNames.filter((d) => STRIPE_SDKS.includes(d));\n matches.push({\n path: relative(installDir, fullPath) || 'package.json',\n posthogSdks,\n stripeSdks,\n });\n } catch {\n // Skip malformed package.json\n }\n } else if (entry.isDirectory()) {\n scan(fullPath, depth + 1);\n }\n }\n }\n\n scan(installDir, 0);\n return matches;\n}\n","/**\n * Revenue analytics prerequisite detection.\n *\n * Scans the project for PostHog + Stripe SDKs and writes results\n * into frameworkContext for the intro screen to render.\n */\n\nimport { existsSync, statSync } from 'fs';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\nimport { findPackageJsons } from '@lib/programs/shared/package-scanning';\n\nexport {\n findPackageJsons,\n POSTHOG_SDKS,\n STRIPE_SDKS,\n type PackageMatch,\n} from '@lib/programs/shared/package-scanning';\n\n/**\n * Structured detection errors. The screen renders each kind into JSX\n * with proper formatting — keeps error data separate from presentation.\n */\nexport type RevenueDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-package-json' }\n | { kind: 'no-sdks'; scannedCount: number }\n | { kind: 'missing-posthog'; foundStripe: string[] }\n | { kind: 'missing-stripe'; foundPosthog: string[] };\n\n/** `[ABORT] <reason>` cases the revenue analytics skill can emit. */\nexport const REVENUE_ABORT_CASES: AbortCase[] = [\n {\n // Skill emits: [ABORT] Could not find a PostHog distinct_id\n match: /^could not find a posthog distinct_id$/i,\n message: 'Could not find a PostHog distinct_id',\n body:\n 'The agent could not find PostHog distinct_id usage in your codebase. ' +\n 'Your users must be identified in PostHog before they can be tagged in Stripe. ' +\n 'Please identify your users and try again.',\n docsUrl: 'https://posthog.com/docs/product-analytics/identify',\n },\n {\n // Skill emits: [ABORT] Could not find a Stripe integration\n match: /^could not find a stripe integration$/i,\n message: 'Could not find a Stripe integration',\n body:\n 'The Wizard could not find an existing Stripe customer, charge, ' +\n 'subscription, or other Stripe operations. Please run the Revenue ' +\n 'Analytics Wizard on a project with an existing Stripe integration.',\n docsUrl: 'https://posthog.com/docs/revenue-analytics',\n },\n];\n\n/**\n * Scan `session.installDir` for PostHog + Stripe SDKs. Writes detection\n * results into frameworkContext via the callback — either the detected\n * SDK lists (for the intro screen) or a `RevenueDetectError` on failure.\n *\n * The skill install happens later in the bootstrap runner, not here.\n */\nexport function detectRevenuePrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: RevenueDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n // Verify the install directory exists and is readable\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n // Find all package.json files (root + monorepo subpackages)\n const matches = findPackageJsons(installDir);\n\n if (matches.length === 0) {\n fail({ kind: 'no-package-json' });\n return;\n }\n\n // Aggregate detected SDKs across all package.json files\n const allPosthogSdks = new Set<string>();\n const allStripeSdks = new Set<string>();\n for (const match of matches) {\n for (const sdk of match.posthogSdks) allPosthogSdks.add(sdk);\n for (const sdk of match.stripeSdks) allStripeSdks.add(sdk);\n }\n\n const detectedPosthogSdks = [...allPosthogSdks];\n const detectedStripeSdks = [...allStripeSdks];\n\n if (detectedPosthogSdks.length === 0 && detectedStripeSdks.length === 0) {\n fail({ kind: 'no-sdks', scannedCount: matches.length });\n return;\n }\n\n if (detectedPosthogSdks.length === 0) {\n fail({ kind: 'missing-posthog', foundStripe: detectedStripeSdks });\n return;\n }\n\n if (detectedStripeSdks.length === 0) {\n fail({ kind: 'missing-stripe', foundPosthog: detectedPosthogSdks });\n return;\n }\n\n setFrameworkContext('detectedPosthogSdks', detectedPosthogSdks);\n setFrameworkContext('detectedStripeSdks', detectedStripeSdks);\n setFrameworkContext(\n 'detectedPackagePaths',\n matches\n .filter((m) => m.posthogSdks.length > 0 || m.stripeSdks.length > 0)\n .map((m) => m.path),\n );\n}\n","/**\n * Revenue analytics program step list.\n *\n * The detect step checks for PostHog + Stripe SDKs. The skill install\n * and agent run live in the program runner (see agent-runner.ts).\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\nimport { detectRevenuePrerequisites } from './detect.js';\n\nexport const REVENUE_ANALYTICS_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting prerequisites',\n // Headless step: no screen, no gate. onReady fires after bin.ts\n // assigns the session — the hook scans for PostHog + Stripe SDKs\n // and writes the results (or a detectError) to frameworkContext\n // for the intro screen to render.\n onReady: (ctx) =>\n detectRevenuePrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'revenue-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Revenue analytics',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","/**\n * Agent-skill learn-deck — the short three-line sequence shown while a\n * skill-based program (audit, revenue-analytics, agent-skill, etc.)\n * runs. Skill programs don't need the full PostHog onboarding narrative.\n */\n\nimport { Text } from 'ink';\nimport type { WizardStore } from '@ui/tui/store';\nimport { TextRevealMode } from '@ui/tui/primitives/TextBlock';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const getContentBlocks = (store?: WizardStore): ContentBlock[] => {\n const skillId = store?.session.skillId ?? 'unknown';\n return [\n {\n content: 'Welcome.',\n pause: 3000,\n mode: TextRevealMode.Typewriter,\n animationInterval: 160,\n },\n { content: 'The Wizard is an agent.', pause: 4000 },\n {\n pause: 60000,\n content: (\n <Text>\n Running the <Text color=\"cyan\">{skillId}</Text> skill...\n </Text>\n ),\n },\n ];\n};\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { REVENUE_ANALYTICS_PROGRAM } from './steps.js';\nimport { REVENUE_ABORT_CASES } from './detect.js';\nimport { getContentBlocks } from './content/index.js';\n\nexport const revenueAnalyticsConfig: ProgramConfig = {\n command: 'revenue-analytics',\n description: 'Set up PostHog revenue analytics (e.g. Stripe integration)',\n id: 'revenue-analytics-setup',\n skillId: 'revenue-analytics-setup',\n steps: REVENUE_ANALYTICS_PROGRAM,\n getContentBlocks,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n run: {\n skillId: 'revenue-analytics-setup',\n integrationLabel: 'revenue-analytics-setup',\n customPrompt: () => 'Set up revenue analytics for this project.',\n successMessage: 'Revenue analytics configured!',\n reportFile: 'posthog-revenue-report.md',\n docsUrl: 'https://posthog.com/docs/revenue-analytics',\n spinnerMessage: 'Setting up revenue analytics...',\n estimatedDurationMinutes: 5,\n abortCases: REVENUE_ABORT_CASES,\n },\n requires: ['posthog-integration'],\n};\n\nexport { REVENUE_ANALYTICS_PROGRAM } from './steps.js';\nexport {\n detectRevenuePrerequisites,\n POSTHOG_SDKS,\n STRIPE_SDKS,\n type RevenueDetectError,\n} from './detect.js';\n","/**\n * Registry of data warehouse source detectors.\n *\n * Each entry maps a codebase footprint to a PostHog source `kind`. The `kind`\n * strings are validated against the MCP `external-data-sources-wizard` tool —\n * keep them in sync with PostHog's released source types.\n *\n * `in-cli` sources are created from the terminal (databases + API-key SaaS).\n * `deep-link` sources have no safe terminal credential path (OAuth) but a\n * codebase footprint worth nudging the user about — we open the app instead.\n */\n\nimport type { SourceDetector } from './types.js';\n\nexport const SOURCE_DETECTORS: SourceDetector[] = [\n {\n kind: 'Postgres',\n label: 'PostgreSQL',\n mode: 'in-cli',\n signals: {\n npm: ['pg', 'postgres', 'postgres.js', 'knex', 'sequelize'],\n python: ['psycopg', 'psycopg2', 'psycopg2-binary', 'asyncpg'],\n ruby: ['pg'],\n envKeys: [\n // NOTE: DATABASE_URL is ambiguous — MySQL/SQLite projects (Prisma,\n // Rails) use it too. We only read key NAMES, not the scheme, so this\n // is a deliberate precision/recall tradeoff biased toward the most\n // common convention (DATABASE_URL → Postgres).\n /^DATABASE_URL$/,\n /^POSTGRES_/,\n /^PG(HOST|DATABASE|USER|PORT)$/,\n ],\n },\n },\n {\n kind: 'MySQL',\n label: 'MySQL',\n mode: 'in-cli',\n signals: {\n npm: ['mysql', 'mysql2'],\n python: ['pymysql', 'mysqlclient', 'mysql-connector-python'],\n ruby: ['mysql2'],\n envKeys: [/^MYSQL_/],\n },\n },\n {\n kind: 'MongoDB',\n label: 'MongoDB',\n mode: 'in-cli',\n signals: {\n npm: ['mongodb', 'mongoose'],\n python: ['pymongo', 'motor'],\n ruby: ['mongo', 'mongoid'],\n // Matches both MONGO_* and MONGODB_* prefixes (e.g. MONGO_HOST,\n // MONGODB_URI) in one pattern.\n envKeys: [/^MONGO(DB)?_/],\n },\n },\n {\n kind: 'Snowflake',\n label: 'Snowflake',\n mode: 'in-cli',\n signals: {\n npm: ['snowflake-sdk'],\n python: ['snowflake-connector-python', 'snowflake-sqlalchemy'],\n envKeys: [/^SNOWFLAKE_/],\n },\n },\n {\n kind: 'BigQuery',\n label: 'BigQuery',\n mode: 'in-cli',\n signals: {\n npm: ['@google-cloud/bigquery'],\n python: ['google-cloud-bigquery'],\n envKeys: [/^BIGQUERY_/],\n },\n },\n {\n kind: 'Redshift',\n label: 'Redshift',\n mode: 'in-cli',\n signals: {\n npm: ['node-redshift'],\n python: ['redshift-connector'],\n envKeys: [/^REDSHIFT_/],\n },\n },\n {\n kind: 'MSSQL',\n label: 'SQL Server',\n mode: 'in-cli',\n signals: {\n npm: ['mssql', 'tedious'],\n python: ['pyodbc', 'pymssql'],\n envKeys: [/^MSSQL_/],\n },\n },\n {\n kind: 'Supabase',\n label: 'Supabase',\n mode: 'in-cli',\n signals: {\n npm: ['@supabase/supabase-js'],\n python: ['supabase'],\n envKeys: [/^SUPABASE_/],\n },\n },\n {\n kind: 'ClickHouse',\n label: 'ClickHouse',\n mode: 'in-cli',\n signals: {\n npm: ['@clickhouse/client'],\n python: ['clickhouse-connect', 'clickhouse-driver'],\n envKeys: [/^CLICKHOUSE_/],\n },\n },\n {\n kind: 'Convex',\n label: 'Convex',\n mode: 'in-cli',\n signals: {\n npm: ['convex'],\n python: ['convex'],\n envKeys: [/^CONVEX_/, /^NEXT_PUBLIC_CONVEX_URL$/],\n },\n },\n {\n kind: 'Stripe',\n label: 'Stripe',\n mode: 'in-cli',\n signals: {\n npm: ['stripe', '@stripe/stripe-js', '@stripe/react-stripe-js'],\n python: ['stripe'],\n ruby: ['stripe'],\n envKeys: [/^STRIPE_(SECRET|API)_KEY$/],\n },\n },\n {\n kind: 'Clerk',\n label: 'Clerk',\n mode: 'in-cli',\n signals: {\n npm: [\n '@clerk/nextjs',\n '@clerk/clerk-react',\n '@clerk/backend',\n '@clerk/express',\n '@clerk/fastify',\n '@clerk/remix',\n ],\n envKeys: [/^CLERK_SECRET_KEY$/, /^NEXT_PUBLIC_CLERK_/],\n },\n },\n {\n kind: 'Resend',\n label: 'Resend',\n mode: 'in-cli',\n signals: {\n npm: ['resend'],\n python: ['resend'],\n envKeys: [/^RESEND_API_KEY$/],\n },\n },\n {\n kind: 'Shopify',\n label: 'Shopify',\n mode: 'in-cli',\n signals: {\n npm: ['@shopify/shopify-api', 'shopify-api-node'],\n python: ['shopifyapi'],\n envKeys: [/^SHOPIFY_/],\n },\n },\n {\n kind: 'Klaviyo',\n label: 'Klaviyo',\n mode: 'in-cli',\n signals: {\n npm: ['klaviyo-api'],\n python: ['klaviyo-api'],\n envKeys: [/^KLAVIYO_/],\n },\n },\n {\n kind: 'Chargebee',\n label: 'Chargebee',\n mode: 'in-cli',\n signals: {\n npm: ['chargebee'],\n python: ['chargebee'],\n envKeys: [/^CHARGEBEE_/],\n },\n },\n {\n kind: 'Paddle',\n label: 'Paddle',\n mode: 'in-cli',\n signals: {\n npm: ['@paddle/paddle-node-sdk', '@paddle/paddle-js'],\n envKeys: [/^PADDLE_/],\n },\n },\n {\n kind: 'Polar',\n label: 'Polar',\n mode: 'in-cli',\n signals: {\n npm: ['@polar-sh/sdk', '@polar-sh/nextjs'],\n envKeys: [/^POLAR_/],\n },\n },\n {\n kind: 'Mailchimp',\n label: 'Mailchimp',\n mode: 'in-cli',\n signals: {\n npm: ['@mailchimp/mailchimp_marketing'],\n python: ['mailchimp-marketing'],\n envKeys: [/^MAILCHIMP_/],\n },\n },\n {\n kind: 'CustomerIO',\n label: 'Customer.io',\n mode: 'in-cli',\n signals: {\n npm: ['customerio-node'],\n python: ['customerio'],\n envKeys: [/^CUSTOMER_?IO_/],\n },\n },\n {\n kind: 'Typeform',\n label: 'Typeform',\n mode: 'in-cli',\n signals: {\n npm: ['@typeform/api-client'],\n envKeys: [/^TYPEFORM_/],\n },\n },\n {\n kind: 'Sentry',\n label: 'Sentry',\n mode: 'in-cli',\n signals: {\n npm: [\n '@sentry/node',\n '@sentry/browser',\n '@sentry/react',\n '@sentry/nextjs',\n ],\n python: ['sentry-sdk'],\n ruby: ['sentry-ruby'],\n },\n },\n {\n kind: 'Plaid',\n label: 'Plaid',\n mode: 'in-cli',\n signals: {\n npm: ['plaid'],\n python: ['plaid-python', 'plaid'],\n ruby: ['plaid'],\n envKeys: [/^PLAID_/],\n },\n },\n {\n kind: 'Braintree',\n label: 'Braintree',\n mode: 'in-cli',\n signals: {\n npm: ['braintree'],\n python: ['braintree'],\n ruby: ['braintree'],\n envKeys: [/^BRAINTREE_/],\n },\n },\n {\n kind: 'Square',\n label: 'Square',\n mode: 'in-cli',\n signals: {\n npm: ['square'],\n python: ['squareup'],\n ruby: ['square'],\n envKeys: [/^SQUARE_/],\n },\n },\n {\n kind: 'GoCardless',\n label: 'GoCardless',\n mode: 'in-cli',\n signals: {\n npm: ['gocardless-nodejs'],\n python: ['gocardless-pro'],\n ruby: ['gocardless_pro'],\n envKeys: [/^GOCARDLESS_/],\n },\n },\n {\n kind: 'Mollie',\n label: 'Mollie',\n mode: 'in-cli',\n signals: {\n npm: ['@mollie/api-client'],\n python: ['mollie-api-python'],\n envKeys: [/^MOLLIE_/],\n },\n },\n {\n kind: 'CheckoutCom',\n label: 'Checkout.com',\n mode: 'in-cli',\n signals: {\n npm: ['checkout-sdk-node'],\n python: ['checkout-sdk'],\n // Checkout.com's own convention is the CKO_ prefix.\n envKeys: [/^CKO_/, /^CHECKOUT_COM_/],\n },\n },\n {\n kind: 'Recurly',\n label: 'Recurly',\n mode: 'in-cli',\n signals: {\n npm: ['recurly'],\n python: ['recurly'],\n ruby: ['recurly'],\n envKeys: [/^RECURLY_/],\n },\n },\n {\n kind: 'RevenueCat',\n label: 'RevenueCat',\n mode: 'in-cli',\n signals: {\n npm: [\n '@revenuecat/purchases-js',\n 'react-native-purchases',\n '@revenuecat/purchases-capacitor',\n ],\n envKeys: [/^REVENUE_?CAT_/],\n },\n },\n {\n kind: 'Twilio',\n label: 'Twilio',\n mode: 'in-cli',\n signals: {\n npm: ['twilio'],\n python: ['twilio'],\n ruby: ['twilio-ruby'],\n envKeys: [/^TWILIO_/],\n },\n },\n {\n kind: 'SendGrid',\n label: 'SendGrid',\n mode: 'in-cli',\n signals: {\n npm: ['@sendgrid/mail', '@sendgrid/client'],\n python: ['sendgrid'],\n ruby: ['sendgrid-ruby'],\n envKeys: [/^SENDGRID_/],\n },\n },\n {\n kind: 'Mailgun',\n label: 'Mailgun',\n mode: 'in-cli',\n signals: {\n npm: ['mailgun.js', 'mailgun-js'],\n python: ['mailgun'],\n ruby: ['mailgun-ruby'],\n envKeys: [/^MAILGUN_/],\n },\n },\n {\n kind: 'Postmark',\n label: 'Postmark',\n mode: 'in-cli',\n signals: {\n npm: ['postmark'],\n python: ['postmarker'],\n ruby: ['postmark'],\n envKeys: [/^POSTMARK_/],\n },\n },\n {\n kind: 'Brevo',\n label: 'Brevo',\n mode: 'in-cli',\n signals: {\n npm: ['@getbrevo/brevo', 'sib-api-v3-sdk'],\n python: ['sib-api-v3-sdk'],\n envKeys: [/^BREVO_/],\n },\n },\n {\n kind: 'MailerLite',\n label: 'MailerLite',\n mode: 'in-cli',\n signals: {\n npm: ['@mailerlite/mailerlite-nodejs'],\n python: ['mailerlite'],\n envKeys: [/^MAILERLITE_/],\n },\n },\n {\n kind: 'Mailjet',\n label: 'Mailjet',\n mode: 'in-cli',\n signals: {\n npm: ['node-mailjet'],\n python: ['mailjet-rest'],\n // Mailjet's documented env convention is MJ_APIKEY_PUBLIC / *_PRIVATE.\n envKeys: [/^MAILJET_/, /^MJ_APIKEY_/],\n },\n },\n {\n kind: 'LaunchDarkly',\n label: 'LaunchDarkly',\n mode: 'in-cli',\n signals: {\n npm: [\n 'launchdarkly-node-server-sdk',\n '@launchdarkly/node-server-sdk',\n 'launchdarkly-js-client-sdk',\n 'launchdarkly-react-client-sdk',\n ],\n python: ['launchdarkly-server-sdk'],\n ruby: ['launchdarkly-server-sdk'],\n envKeys: [/^LAUNCHDARKLY_/, /^LD_SDK_KEY$/],\n },\n },\n {\n kind: 'Optimizely',\n label: 'Optimizely',\n mode: 'in-cli',\n signals: {\n npm: ['@optimizely/optimizely-sdk'],\n python: ['optimizely-sdk'],\n envKeys: [/^OPTIMIZELY_/],\n },\n },\n {\n kind: 'Braze',\n label: 'Braze',\n mode: 'in-cli',\n signals: {\n npm: ['@braze/web-sdk', '@braze/react-native-sdk'],\n python: ['braze-client'],\n envKeys: [/^BRAZE_/],\n },\n },\n {\n kind: 'Rollbar',\n label: 'Rollbar',\n mode: 'in-cli',\n signals: {\n npm: ['rollbar'],\n python: ['rollbar', 'pyrollbar'],\n ruby: ['rollbar'],\n envKeys: [/^ROLLBAR_/],\n },\n },\n {\n kind: 'Okta',\n label: 'Okta',\n mode: 'in-cli',\n signals: {\n npm: ['@okta/okta-sdk-nodejs', '@okta/okta-auth-js', '@okta/okta-react'],\n python: ['okta'],\n envKeys: [/^OKTA_/],\n },\n },\n {\n kind: 'WorkOS',\n label: 'WorkOS',\n mode: 'in-cli',\n signals: {\n npm: ['@workos-inc/node'],\n python: ['workos'],\n envKeys: [/^WORKOS_/],\n },\n },\n {\n kind: 'Notion',\n label: 'Notion',\n mode: 'in-cli',\n signals: {\n npm: ['@notionhq/client'],\n python: ['notion-client'],\n envKeys: [/^NOTION_/],\n },\n },\n {\n kind: 'FullStory',\n label: 'FullStory',\n mode: 'in-cli',\n signals: {\n npm: ['@fullstory/browser', '@fullstory/react-native'],\n envKeys: [/^FULLSTORY_/],\n },\n },\n {\n kind: 'Amplitude',\n label: 'Amplitude',\n mode: 'in-cli',\n signals: {\n npm: [\n '@amplitude/analytics-browser',\n '@amplitude/analytics-node',\n '@amplitude/analytics-react-native',\n 'amplitude-js',\n ],\n python: ['amplitude-analytics'],\n envKeys: [/^AMPLITUDE_/],\n },\n },\n {\n kind: 'Mixpanel',\n label: 'Mixpanel',\n mode: 'in-cli',\n signals: {\n npm: ['mixpanel', 'mixpanel-browser'],\n python: ['mixpanel'],\n ruby: ['mixpanel-ruby'],\n envKeys: [/^MIXPANEL_/],\n },\n },\n {\n kind: 'Pendo',\n label: 'Pendo',\n mode: 'in-cli',\n signals: {\n npm: ['@pendo/agent'],\n envKeys: [/^PENDO_/],\n },\n },\n {\n kind: 'Salesforce',\n label: 'Salesforce',\n mode: 'deep-link',\n signals: {\n npm: ['jsforce'],\n python: ['simple-salesforce'],\n envKeys: [/^SALESFORCE_/],\n },\n },\n {\n kind: 'Hubspot',\n label: 'HubSpot',\n mode: 'deep-link',\n signals: {\n npm: ['@hubspot/api-client'],\n python: ['hubspot-api-client'],\n envKeys: [/^HUBSPOT_/],\n },\n },\n {\n kind: 'Zendesk',\n label: 'Zendesk',\n mode: 'deep-link',\n signals: {\n npm: ['node-zendesk'],\n python: ['zenpy'],\n envKeys: [/^ZENDESK_/],\n },\n },\n {\n kind: 'Intercom',\n label: 'Intercom',\n mode: 'deep-link',\n signals: {\n npm: ['intercom-client', '@intercom/messenger-js-sdk'],\n python: ['python-intercom'],\n envKeys: [/^INTERCOM_/],\n },\n },\n {\n kind: 'Linear',\n label: 'Linear',\n mode: 'deep-link',\n signals: {\n npm: ['@linear/sdk'],\n envKeys: [/^LINEAR_API_KEY$/],\n },\n },\n {\n // OAuth-only in PostHog (Slack app integration), so deep-link.\n kind: 'Slack',\n label: 'Slack',\n mode: 'deep-link',\n signals: {\n npm: ['@slack/web-api', '@slack/bolt'],\n python: ['slack-sdk', 'slack-bolt'],\n envKeys: [/^SLACK_(BOT|APP|SIGNING|CLIENT)_/],\n },\n },\n {\n // 'Github' (not 'GitHub') — matches the ExternalDataSourceType value.\n // Default auth is the GitHub App integration (OAuth), so deep-link.\n kind: 'Github',\n label: 'GitHub',\n mode: 'deep-link',\n signals: {\n npm: ['@octokit/rest', '@octokit/core', '@octokit/graphql', 'octokit'],\n python: ['pygithub'],\n ruby: ['octokit'],\n },\n },\n];\n","/**\n * Data warehouse source detection.\n *\n * Scans a project for codebase signals (npm/python/ruby deps, `.env` key\n * names) and matches them against the `SOURCE_DETECTORS` registry. Pure\n * function: no store mutations, no UI calls. Reads files locally — only the\n * wizard process does this; the agent never sees secret values.\n *\n * Note we only read `.env` KEY NAMES, never values.\n */\n\nimport { analytics } from '@utils/analytics';\nimport { walkProjectFiles, safeReadFile } from '@utils/file-utils';\nimport type { PackageJson } from '@utils/package-json';\nimport {\n parseRequirementsTxt,\n parsePyprojectToml,\n parsePipfile,\n} from '@lib/detection/features';\nimport { SOURCE_DETECTORS } from './registry.js';\nimport type { DetectedSource, SourceDetector } from './types.js';\n\ninterface ProjectSignals {\n npm: Set<string>;\n python: Set<string>;\n ruby: Set<string>;\n envKeys: Set<string>;\n}\n\nconst MAX_DEPTH = 3;\n\n/**\n * Detect which warehouse sources the project at `installDir` appears to use.\n * Returns one `DetectedSource` per matched registry entry (kinds are unique,\n * so the result is naturally deduped).\n */\nexport function detectWarehouseSources(installDir: string): DetectedSource[] {\n // No directory guard here: walkProjectFiles is best-effort and yields no\n // signals for a missing/unreadable dir (→ []). The program-level detect\n // step is responsible for surfacing a structured `bad-directory` error.\n const signals = collectSignals(installDir);\n\n const detected: DetectedSource[] = [];\n for (const detector of SOURCE_DETECTORS) {\n const match = matchDetector(detector, signals);\n if (match) {\n detected.push({\n kind: detector.kind,\n label: detector.label,\n mode: detector.mode,\n matchedSignal: match,\n });\n }\n }\n return detected;\n}\n\n/** Returns a human-readable description of the first matching signal, or null. */\nfunction matchDetector(\n detector: SourceDetector,\n signals: ProjectSignals,\n): string | null {\n const { npm, python, ruby, envKeys } = detector.signals;\n\n const npmHit = npm?.find((dep) => signals.npm.has(dep));\n if (npmHit) return `found \\`${npmHit}\\` in package.json`;\n\n const pyHit = python?.find((dep) => signals.python.has(dep));\n if (pyHit) return `found \\`${pyHit}\\` in Python dependencies`;\n\n const rubyHit = ruby?.find((gem) => signals.ruby.has(gem));\n if (rubyHit) return `found \\`${rubyHit}\\` in Gemfile`;\n\n if (envKeys) {\n for (const key of signals.envKeys) {\n if (envKeys.some((re) => re.test(key))) {\n return `found \\`${key}\\` in .env`;\n }\n }\n }\n\n return null;\n}\n\nfunction collectSignals(installDir: string): ProjectSignals {\n const signals: ProjectSignals = {\n npm: new Set(),\n python: new Set(),\n ruby: new Set(),\n envKeys: new Set(),\n };\n\n walkProjectFiles(\n installDir,\n (name, fullPath) => ingestFile(name, fullPath, signals),\n MAX_DEPTH,\n );\n\n return signals;\n}\n\n/**\n * Route a file to the right parser BY NAME, reading its contents only when the\n * name matches one of the ~6 manifests we care about. Checking the name first\n * avoids slurping every file in the tree (lockfiles, binaries, assets) into\n * memory just to discard it.\n */\nfunction ingestFile(\n name: string,\n fullPath: string,\n signals: ProjectSignals,\n): void {\n const ingest = ingestorFor(name);\n if (!ingest) return;\n\n const content = safeReadFile(fullPath);\n if (content === null) return;\n\n ingest(content, signals);\n}\n\ntype Ingestor = (content: string, signals: ProjectSignals) => void;\n\n/** Pick the parser for a manifest filename, or null if it's not one we read. */\nfunction ingestorFor(name: string): Ingestor | null {\n if (name === 'package.json') return addNpmDeps;\n if (name === 'requirements.txt')\n return (c, s) => parseRequirementsTxt(c).forEach((d) => s.python.add(d));\n if (name === 'pyproject.toml')\n return (c, s) => parsePyprojectToml(c).forEach((d) => s.python.add(d));\n if (name === 'Pipfile')\n return (c, s) => parsePipfile(c).forEach((d) => s.python.add(d));\n if (name === 'Gemfile')\n return (c, s) => parseGemfile(c).forEach((g) => s.ruby.add(g));\n if (name.startsWith('.env'))\n return (c, s) => parseEnvKeys(c).forEach((k) => s.envKeys.add(k));\n return null;\n}\n\nfunction addNpmDeps(content: string, signals: ProjectSignals): void {\n try {\n const pkg = JSON.parse(content) as PackageJson;\n for (const dep of Object.keys({\n ...pkg.dependencies,\n ...pkg.devDependencies,\n })) {\n signals.npm.add(dep);\n }\n } catch (error) {\n // Malformed package.json — skip it, but record that we hit it.\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'detectWarehouseSources.parsePackageJson' },\n );\n }\n}\n\n/** Extract gem names from `gem 'name'` declarations. */\nexport function parseGemfile(content: string): string[] {\n const gems: string[] = [];\n for (const match of content.matchAll(/^\\s*gem\\s+['\"]([^'\"]+)['\"]/gm)) {\n gems.push(match[1]);\n }\n return gems;\n}\n\n/** Extract KEY NAMES from a dotenv file. Values are intentionally discarded. */\nexport function parseEnvKeys(content: string): string[] {\n const keys: string[] = [];\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const match = trimmed.match(/^(?:export\\s+)?([A-Za-z_][A-Za-z0-9_]*)\\s*=/);\n if (match) keys.push(match[1]);\n }\n return keys;\n}\n","/**\n * Warehouse-source program detection step.\n *\n * Thin adapter over `detectWarehouseSources` that writes results into\n * frameworkContext for the intro screen, plus the `[ABORT]` cases the\n * data-warehouse-source-setup skill can emit.\n */\n\nimport { existsSync, statSync } from 'fs';\nimport { analytics } from '@utils/analytics';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\nimport { detectWarehouseSources } from '@lib/warehouse-sources/detect';\nimport type { DetectedSource } from '@lib/warehouse-sources/types';\n\n/** Structured detection errors rendered by the intro screen. */\nexport type WarehouseDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-sources' };\n\n/** frameworkContext key holding the detected sources (set on success). */\nexport const DETECTED_WAREHOUSE_SOURCES_KEY = 'detectedWarehouseSources';\n\n/**\n * Read the detected sources out of frameworkContext. Single accessor shared by\n * the intro screen and the prompt builder so the key + cast live in one place.\n */\nexport function getDetectedWarehouseSources(\n session: WizardSession,\n): DetectedSource[] {\n return (\n (session.frameworkContext[DETECTED_WAREHOUSE_SOURCES_KEY] as\n | DetectedSource[]\n | undefined) ?? []\n );\n}\n\n/** `[ABORT] <reason>` cases the skill can emit. */\nexport const WAREHOUSE_ABORT_CASES: AbortCase[] = [\n {\n // Skill emits: [ABORT] No data source detected\n // Tolerant of plural (\"sources\") and a trailing period.\n match: /^no data sources? detected\\.?$/i,\n message: 'No data source detected',\n body:\n 'The agent could not confirm a data warehouse source to connect. ' +\n 'Run this command from a project that uses a supported source ' +\n '(a database, Stripe, etc.).',\n docsUrl: 'https://posthog.com/docs/data-warehouse',\n },\n {\n // Skill emits: [ABORT] Source creation failed\n match: /^source creation failed\\.?$/i,\n message: 'Source creation failed',\n body:\n 'PostHog could not create the data warehouse source with the ' +\n 'credentials provided. Double-check the connection details and try ' +\n 'again, or set the source up directly in the PostHog app.',\n docsUrl: 'https://posthog.com/docs/data-warehouse',\n },\n];\n\n/**\n * Scan `session.installDir` for warehouse-source signals. Writes the detected\n * sources (or a `detectError`) into frameworkContext for the intro screen.\n */\nexport function detectWarehousePrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: WarehouseDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch (error) {\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'detectWarehousePrerequisites.stat', path: installDir },\n );\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n const sources = detectWarehouseSources(installDir);\n\n if (sources.length === 0) {\n fail({ kind: 'no-sources' });\n return;\n }\n\n setFrameworkContext(DETECTED_WAREHOUSE_SOURCES_KEY, sources);\n}\n","/**\n * Warehouse-source program step list.\n *\n * The detect step scans for warehouse-source signals. The skill install and\n * agent run live in the program runner (see agent-runner.ts). The skill drives\n * both in-CLI source creation and deep-link emission per detected source.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { detectWarehousePrerequisites } from './detect.js';\n\nexport const WAREHOUSE_SOURCE_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting data sources',\n // Headless step: no screen. onReady scans installDir and writes the\n // detected sources (or a detectError) to frameworkContext for the\n // intro screen to render.\n onReady: (ctx) =>\n detectWarehousePrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'warehouse-intro',\n gate: (session) => session.setupConfirmed,\n },\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Data warehouse',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { WAREHOUSE_SOURCE_PROGRAM } from './steps.js';\nimport {\n WAREHOUSE_ABORT_CASES,\n getDetectedWarehouseSources,\n} from './detect.js';\nimport { getContentBlocks } from './content/index.js';\n\n/**\n * Inject the detected sources (and their creation mode) into the prompt so the\n * skill knows what to set up. The *how* — in-CLI creation vs deep-link, field\n * collection, validation — lives in the skill, not here.\n */\nfunction buildPrompt(session: WizardSession): string {\n const sources = getDetectedWarehouseSources(session);\n if (sources.length === 0) {\n return 'Set up a data warehouse source for this project.';\n }\n\n const lines = sources.map(\n (s) =>\n `- ${s.label} (kind: ${s.kind}, mode: ${s.mode}) — ${s.matchedSignal}`,\n );\n\n return [\n 'The wizard detected the following data warehouse sources in this project:',\n ...lines,\n '',\n 'Set these up in PostHog following the skill instructions: create `in-cli` ' +\n 'sources directly via the PostHog MCP after collecting credentials; for ' +\n '`deep-link` sources, provide the user the pre-filled new-source URL.',\n ].join('\\n');\n}\n\nexport const warehouseSourceConfig: ProgramConfig = {\n command: 'warehouse',\n description:\n 'Detect and connect a data warehouse source (Postgres, Stripe, …)',\n id: 'warehouse-source',\n skillId: 'data-warehouse-source-setup',\n steps: WAREHOUSE_SOURCE_PROGRAM,\n getContentBlocks,\n reportFile: 'posthog-warehouse-report.md',\n allowedTools: ['Agent'],\n run: (session: WizardSession): Promise<ProgramRun> =>\n Promise.resolve({\n skillId: 'data-warehouse-source-setup',\n integrationLabel: 'data-warehouse-source-setup',\n customPrompt: () => buildPrompt(session),\n successMessage: 'Data warehouse source connected!',\n reportFile: 'posthog-warehouse-report.md',\n docsUrl: 'https://posthog.com/docs/data-warehouse',\n spinnerMessage: 'Connecting your data source...',\n estimatedDurationMinutes: 5,\n abortCases: WAREHOUSE_ABORT_CASES,\n }),\n requires: ['posthog-integration'],\n};\n\nexport { WAREHOUSE_SOURCE_PROGRAM } from './steps.js';\nexport {\n detectWarehousePrerequisites,\n getDetectedWarehouseSources,\n DETECTED_WAREHOUSE_SOURCES_KEY,\n WAREHOUSE_ABORT_CASES,\n type WarehouseDetectError,\n} from './detect.js';\n","/**\n * Generic agent skill step list.\n *\n * Minimal flow: intro → health-check → auth → run → outro → skills.\n * No detection, no setup, no MCP.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\n\nexport const AGENT_SKILL_STEPS: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'agent-skill-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Running',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","/**\n * Generic agent skill program factory.\n *\n * Creates a ProgramConfig for any context-mill skill. Provide a\n * skill ID and basic UI config — the factory handles the rest.\n *\n * Usage:\n * createSkillProgram({\n * skillId: 'error-tracking-setup',\n * command: 'errors',\n * id: 'error-tracking',\n * description: 'Set up PostHog error tracking',\n * integrationLabel: 'error-tracking',\n * successMessage: 'Error tracking configured!',\n * reportFile: 'posthog-error-tracking-report.md',\n * docsUrl: 'https://posthog.com/docs/error-tracking',\n * spinnerMessage: 'Setting up error tracking...',\n * estimatedDurationMinutes: 5,\n * })\n */\n\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun, AbortCase } from '@lib/agent/agent-runner';\nimport { AGENT_SKILL_STEPS } from './steps.js';\nimport { getContentBlocks } from './content/index.js';\n\nexport interface SkillProgramOptions {\n /** Context-mill skill ID to install */\n skillId: string;\n /** CLI subcommand name */\n command: string;\n /** Unique flow key — must match a Program enum entry */\n id: string;\n /** CLI description shown in --help */\n description: string;\n /** Analytics integration label */\n integrationLabel: string;\n /** Custom prompt instruction. Appended after default project prompt. */\n customPrompt?: string;\n successMessage: string;\n reportFile: string;\n docsUrl: string;\n spinnerMessage: string;\n estimatedDurationMinutes: number;\n /** Other program ids that must be satisfied first */\n requires?: string[];\n /** Override the default outro. Receives the same args as ProgramRun.buildOutroData. */\n buildOutroData?: ProgramRun['buildOutroData'];\n /** Known `[ABORT] <reason>` cases the skill can emit. */\n abortCases?: AbortCase[];\n}\n\nexport function createSkillProgram(opts: SkillProgramOptions): ProgramConfig {\n return {\n command: opts.command,\n description: opts.description,\n id: opts.id,\n skillId: opts.skillId,\n steps: AGENT_SKILL_STEPS,\n reportFile: opts.reportFile,\n getContentBlocks,\n run: {\n skillId: opts.skillId,\n integrationLabel: opts.integrationLabel,\n customPrompt: opts.customPrompt ? () => opts.customPrompt! : undefined,\n successMessage: opts.successMessage,\n reportFile: opts.reportFile,\n docsUrl: opts.docsUrl,\n spinnerMessage: opts.spinnerMessage,\n estimatedDurationMinutes: opts.estimatedDurationMinutes,\n buildOutroData: opts.buildOutroData,\n abortCases: opts.abortCases,\n },\n requires: opts.requires,\n };\n}\n\nexport { AGENT_SKILL_STEPS } from './steps.js';\n","import type { AbortCase } from '@lib/agent/agent-runner';\n\n/** `[ABORT] <reason>` cases the audit skill can emit. Reason strings are\n * defined in the skill's `Abort statuses` section. */\nexport const AUDIT_ABORT_CASES: AbortCase[] = [\n {\n match: /^no posthog sdk found$/i,\n message: 'No PostHog SDK found',\n body:\n 'The audit needs an existing PostHog integration to review. No PostHog ' +\n 'SDK appears in this project’s dependency manifests. Run the basic ' +\n 'integration program to install PostHog first, then re-run the audit.',\n docsUrl: 'https://posthog.com/docs/getting-started/install',\n },\n];\n","import fs from 'fs';\nimport path from 'path';\nimport { logToFile } from '@utils/debug';\nimport { AUDIT_CHECKS_FILE, type AuditCheck } from './types.js';\n\n/**\n * The 10 data-integrity checks the audit runs, plus one workflow row for the\n * notebook upload at the end (so the skill's `audit_resolve_checks` call for\n * `upload-notebook` succeeds — the skill writes the report to a PostHog\n * notebook as its final step).\n */\nexport const AUDIT_SEED_CHECKS: AuditCheck[] = [\n {\n id: 'sdk-installed',\n area: 'Installation',\n label: 'PostHog SDK installed',\n status: 'pending',\n },\n {\n id: 'sdk-up-to-date',\n area: 'Installation',\n label: 'SDK version up to date',\n status: 'pending',\n },\n {\n id: 'init-correct',\n area: 'Installation',\n label: 'Initialization is correct',\n status: 'pending',\n },\n {\n id: 'identify-stable-distinct-id',\n area: 'Identification',\n label: 'Stable distinct_id (not session UUID)',\n status: 'pending',\n },\n {\n id: 'identify-not-late',\n area: 'Identification',\n label: 'identify() called before captures / flag evals',\n status: 'pending',\n },\n {\n id: 'cross-runtime-distinct-id',\n area: 'Identification',\n label: 'Same distinct_id across client and server',\n status: 'pending',\n },\n {\n id: 'identify-reset-on-logout',\n area: 'Identification',\n label: 'reset() called on logout / account switch',\n status: 'pending',\n },\n {\n id: 'capture-event-names-static',\n area: 'Event Capture',\n label: 'Event names are static and consistent',\n status: 'pending',\n },\n {\n id: 'capture-uses-proxy',\n area: 'Event Capture',\n label: 'Captures route through a reverse proxy',\n status: 'pending',\n },\n {\n id: 'capture-growth-events',\n area: 'Event Capture',\n label: 'Key activation events captured',\n status: 'pending',\n },\n {\n id: 'write-report',\n area: 'Write report',\n label: 'Create posthog-audit-report.md',\n status: 'pending',\n },\n {\n id: 'upload-notebook',\n area: 'Upload notebook',\n label: 'Write the report into a PostHog notebook',\n status: 'pending',\n },\n];\n\n/**\n * Atomically write a seeded ledger to the project's audit checks file.\n *\n * Each audit-flavored program (doctor, events-audit) owns its own seed\n * shape — pass the seed in so this writer stays program-agnostic.\n */\nexport function seedAuditLedger(\n installDir: string,\n checks: AuditCheck[] = AUDIT_SEED_CHECKS,\n): void {\n const target = path.join(installDir, AUDIT_CHECKS_FILE);\n const tmp = `${target}.tmp`;\n fs.writeFileSync(tmp, JSON.stringify(checks, null, 2), 'utf8');\n fs.renameSync(tmp, target);\n logToFile(`seedAuditLedger: wrote ${checks.length} entries to ${target}`);\n}\n","import {\n AGENT_SKILL_STEPS,\n createSkillProgram,\n} from '@lib/programs/agent-skill/index';\nimport type { ProgramStep, ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { OutroKind } from '@lib/wizard-session';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { getCloudUrlFromRegion } from '@utils/urls';\nimport { AUDIT_ABORT_CASES } from './detect.js';\nimport { AUDIT_CHECKS_KEY, AUDIT_REPORT_FILE } from './types.js';\nimport { AUDIT_SEED_CHECKS, seedAuditLedger } from './seed.js';\n\n/** Audit-specific screens for the shared agent-skill pipeline. */\nconst AUDIT_SCREEN_BY_STEP: Record<string, string> = {\n intro: 'audit-intro',\n run: 'audit-run',\n outro: 'audit-outro',\n};\n\nconst seedBeforeAuditRun = (session: WizardSession): void => {\n seedAuditLedger(session.installDir);\n session.frameworkContext[AUDIT_CHECKS_KEY] = AUDIT_SEED_CHECKS;\n};\n\nconst withAuditScreens = (steps: ProgramStep[]): ProgramStep[] =>\n steps.map((step) => {\n const override = AUDIT_SCREEN_BY_STEP[step.id];\n return override ? { ...step, screenId: override } : step;\n });\n\nconst auditSteps: ProgramStep[] = withAuditScreens(AGENT_SKILL_STEPS);\n\nconst baseConfig = createSkillProgram({\n skillId: 'audit',\n command: 'audit',\n id: 'audit',\n description:\n 'Audit an existing PostHog integration for correctness and best practices',\n integrationLabel: 'audit',\n customPrompt:\n 'Run a comprehensive audit of the existing PostHog integration. Follow the skill program steps in order. Do not modify any project files — only create the final audit report.',\n successMessage:\n 'Audit complete! You can view the audit report at ./posthog-audit-report.md',\n reportFile: AUDIT_REPORT_FILE,\n docsUrl: 'https://posthog.com/docs/product-analytics/best-practices',\n spinnerMessage: 'Auditing PostHog integration...',\n estimatedDurationMinutes: 5,\n requires: ['posthog-integration'],\n abortCases: AUDIT_ABORT_CASES,\n});\n\nconst auditRun = async (session: WizardSession): Promise<ProgramRun> => {\n seedBeforeAuditRun(session);\n\n if (!baseConfig.run) {\n throw new Error('Audit program has no run configuration.');\n }\n\n const baseRun =\n typeof baseConfig.run === 'function'\n ? await baseConfig.run(session)\n : baseConfig.run;\n\n return {\n ...baseRun,\n // Override the default outro so the dashboard + notebook URLs the\n // agent emits via `[DASHBOARD_URL]` / `[NOTEBOOK_URL]` are surfaced\n // on the post-run screen.\n buildOutroData: (sess, _credentials, cloudRegion) => {\n const cloudUrl = cloudRegion\n ? getCloudUrlFromRegion(cloudRegion)\n : undefined;\n const continueUrl =\n sess.signup && cloudUrl\n ? `${cloudUrl}/products?source=wizard`\n : undefined;\n\n // Note: `sess` here is the agent-runner's snapshot of session at\n // runAgent() invocation time. Any URL emissions during the run land\n // on the live store, NOT on this snapshot. The UI layer\n // (InkUI.setOutroData) merges live URLs in on top of this return\n // value, so it's safe to leave dashboardUrl/notebookUrl as undefined\n // here when the snapshot doesn't have them.\n return {\n kind: OutroKind.Success as const,\n message: baseRun.successMessage,\n reportFile: baseRun.reportFile,\n docsUrl: baseRun.docsUrl,\n continueUrl,\n dashboardUrl: sess.dashboardUrl ?? undefined,\n notebookUrl: sess.notebookUrl ?? undefined,\n };\n },\n };\n};\n\nexport const auditConfig: ProgramConfig = {\n ...baseConfig,\n steps: auditSteps,\n run: auditRun,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n};\n","/**\n * Events-audit program.\n *\n * Mirrors the posthog-integration step list, except:\n * - The initial framework detection step is omitted — the events-audit\n * skill handles detection at agent run time.\n * - The intro step uses the audit intro screen (no framework selection\n * logic) instead of the integration intro.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\n\nfunction needsSetup(session: WizardSession): boolean {\n const config = session.frameworkConfig;\n if (!config?.metadata.setup?.questions) return false;\n\n return config.metadata.setup.questions.some(\n (q: { key: string }) => !(q.key in session.frameworkContext),\n );\n}\n\nexport const EVENTS_AUDIT_PROGRAM: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'audit-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'setup',\n label: 'Setup',\n screenId: 'setup',\n show: needsSetup,\n isComplete: (session) => !needsSetup(session),\n },\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Events audit',\n screenId: 'audit-run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'mcp',\n label: 'MCP servers',\n screenId: 'mcp',\n isComplete: (session) => session.mcpComplete,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'audit-outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'keep-skills',\n label: 'Keep Skills',\n screenId: 'keep-skills',\n },\n];\n","import type { AuditCheck } from '@lib/programs/audit/types';\n\n/**\n * The 7 phases the events-audit skill marches through. One check per area\n * so PendingChecksList renders a clean linear pipeline (area = bold header,\n * single row = the active spinner).\n *\n * Phase ids match what the skill's step files resolve via\n * `mcp__wizard-tools__audit_resolve_checks` as each phase completes. The\n * skill's step 1 also seeds these same ids — keep both in sync so the\n * wizard pre-seed and the skill's MCP seed agree.\n */\nexport const EVENTS_AUDIT_SEED_CHECKS: AuditCheck[] = [\n {\n id: 'detect-sdk',\n area: 'Detect SDK',\n label: 'Identify PostHog SDK(s) in dependencies',\n status: 'pending',\n },\n {\n id: 'scan-sites',\n area: 'Scan capture sites',\n label: 'Grep capture/identify/group call sites',\n status: 'pending',\n },\n {\n id: 'enrich-sites',\n area: 'Enrich',\n label: 'Subagent fan-out to read capture files',\n status: 'pending',\n },\n {\n id: 'query-volume',\n area: 'Query PostHog',\n label: '30-day volume + last_seen via MCP',\n status: 'pending',\n },\n {\n id: 'write-report',\n area: 'Write report',\n label: 'Create posthog-events-audit-report.md',\n status: 'pending',\n },\n {\n id: 'create-dashboard',\n area: 'Create dashboard',\n label: 'Optional: dashboard for resolved events',\n status: 'pending',\n },\n {\n id: 'upload-notebook',\n area: 'Upload notebook',\n label: 'Write the report into a PostHog notebook',\n status: 'pending',\n },\n];\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { OutroKind } from '@lib/wizard-session';\nimport { SPINNER_MESSAGE } from '@lib/framework-config';\nimport { isUsingTypeScript } from '@utils/setup-utils';\nimport { getCloudUrlFromRegion } from '@utils/urls';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { EVENTS_AUDIT_PROGRAM } from './steps.js';\nimport { AUDIT_CHECKS_KEY } from '@lib/programs/audit/types';\nimport { seedAuditLedger } from '@lib/programs/audit/seed';\nimport { EVENTS_AUDIT_SEED_CHECKS } from './seed.js';\n\n// SETUP_REPORT_FILE is also re-exported for backward compat with existing\n// imports from `@lib/programs/events-audit`. EVENT_INVENTORY_FILE and\n// EVENT_INVENTORY_PART_PATTERN are only used by yara-hooks, which imports\n// them directly from `./constants` — no re-export needed.\nimport { SETUP_REPORT_FILE } from './constants.js';\nexport { SETUP_REPORT_FILE };\n\nconst DOCS_URL = 'https://posthog.com/docs/product-analytics/best-practices';\n\nexport const eventsAuditConfig: ProgramConfig = {\n command: 'events-audit',\n description: 'Audit PostHog event tracking in this project',\n id: 'events-audit',\n skillId: 'events-audit',\n steps: EVENTS_AUDIT_PROGRAM,\n // Top-level reportFile so AuditRunScreen can resolve the report path\n // synchronously without unwrapping the deferred `run` function.\n reportFile: SETUP_REPORT_FILE,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n\n run: (session: WizardSession): Promise<ProgramRun> => {\n const typeScriptDetected = isUsingTypeScript({\n installDir: session.installDir,\n });\n session.typescript = typeScriptDetected;\n\n // Seed the audit ledger so AuditRunScreen has something to render\n // before the agent emits its first check update. The events-audit\n // ledger is the 6-phase pipeline, not the doctor's 10 integrity checks.\n seedAuditLedger(session.installDir, EVENTS_AUDIT_SEED_CHECKS);\n session.frameworkContext[AUDIT_CHECKS_KEY] = EVENTS_AUDIT_SEED_CHECKS;\n\n return Promise.resolve({\n skillId: 'events-audit',\n integrationLabel: 'events-audit',\n spinnerMessage: SPINNER_MESSAGE,\n successMessage:\n 'Events audit complete! You can view the report at ./posthog-events-audit-report.md',\n estimatedDurationMinutes: 5,\n reportFile: SETUP_REPORT_FILE,\n docsUrl: DOCS_URL,\n errorMessage: 'Events audit failed',\n additionalFeatureQueue: session.additionalFeatureQueue,\n\n customPrompt: (ctx) =>\n `Audit PostHog event capture in this project. Do not modify any project files — produce a read-only report only.\n\nProject context:\n- PostHog Project ID: ${ctx.projectId}\n- TypeScript: ${typeScriptDetected ? 'Yes' : 'No'}\n- PostHog public token: ${ctx.projectApiKey}\n- PostHog Host: ${ctx.host}\n`,\n\n buildOutroData: (sess, _credentials, cloudRegion) => {\n const cloudUrl = cloudRegion\n ? getCloudUrlFromRegion(cloudRegion)\n : undefined;\n const continueUrl =\n sess.signup && cloudUrl\n ? `${cloudUrl}/products?source=wizard`\n : undefined;\n // The agent emits `[DASHBOARD_URL] <url>` once it creates the\n // dashboard; the SDK-message interceptor stores it on the session.\n // Fall back to the dashboards index if nothing was emitted.\n const dashboardUrl =\n sess.dashboardUrl ?? (cloudUrl ? `${cloudUrl}/dashboard` : undefined);\n\n // The agent emits `[NOTEBOOK_URL] <url>` once it uploads the report\n // to a PostHog notebook. No fallback: if the notebook upload was\n // skipped (e.g. MCP unavailable) we just don't show a link.\n const notebookUrl = sess.notebookUrl ?? undefined;\n\n return {\n kind: OutroKind.Success as const,\n message: 'Your events audit was successful',\n reportFile: SETUP_REPORT_FILE,\n changes: [],\n docsUrl: DOCS_URL,\n continueUrl,\n dashboardUrl,\n notebookUrl,\n };\n },\n });\n },\n};\n\nexport { EVENTS_AUDIT_PROGRAM } from './steps.js';\n","import type { ProgramStep } from '@lib/programs/program-step';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\n\nexport const POSTHOG_DOCTOR_PROGRAM: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'doctor-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'report',\n label: 'Doctor report',\n screenId: 'doctor-report',\n isComplete: (session) => session.outroData !== null,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n];\n","import { z } from 'zod';\n\nexport const HealthIssueSeveritySchema = z.enum([\n 'critical',\n 'warning',\n 'info',\n]);\nexport type HealthIssueSeverity = z.infer<typeof HealthIssueSeveritySchema>;\n\nexport const HealthIssueStatusSchema = z.enum(['active', 'resolved']);\n\nexport const HealthIssueSchema = z.object({\n id: z.string(),\n kind: z.string(),\n severity: HealthIssueSeveritySchema,\n status: HealthIssueStatusSchema,\n dismissed: z.boolean(),\n created_at: z.string(),\n updated_at: z.string(),\n resolved_at: z.string().nullable().optional(),\n});\nexport type HealthIssue = z.infer<typeof HealthIssueSchema>;\n\nexport const HealthIssueListResponseSchema = z.object({\n results: z.array(HealthIssueSchema),\n count: z.number().optional(),\n next: z.string().nullable().optional(),\n previous: z.string().nullable().optional(),\n});\nexport type HealthIssueListResponse = z.infer<\n typeof HealthIssueListResponseSchema\n>;\n\nexport interface HealthIssueSummary {\n total: number;\n by_severity: Record<HealthIssueSeverity, number>;\n}\n","import axios from 'axios';\nimport { analytics } from '@utils/analytics';\nimport { handleApiError } from '@lib/api';\nimport { WIZARD_USER_AGENT } from '@lib/constants';\nimport { HealthIssueListResponseSchema, type HealthIssue } from './types';\n\nexport async function fetchHealthIssues(\n accessToken: string,\n baseUrl: string,\n projectId: number,\n): Promise<HealthIssue[]> {\n const endpoint = `/api/environments/${projectId}/health_issues/`;\n const url = `${baseUrl}${endpoint}?status=active&dismissed=false&limit=250`;\n try {\n const response = await axios.get(url, {\n headers: {\n Authorization: `Bearer ${accessToken}`,\n 'User-Agent': WIZARD_USER_AGENT,\n },\n });\n return HealthIssueListResponseSchema.parse(response.data).results;\n } catch (error) {\n const apiError = handleApiError(error, 'fetch health issues');\n analytics.captureException(apiError, { endpoint, baseUrl, projectId });\n throw apiError;\n }\n}\n","import { POSTHOG_DOCS_URL } from '@lib/constants';\n\nexport interface KindMeta {\n title: string;\n description: string;\n docsUrl: string;\n}\n\nexport const KIND_METADATA: Record<string, KindMeta> = {\n ingestion_lag: {\n title: 'Ingestion is delayed',\n description:\n 'Events are being received but are taking longer than usual to appear.',\n docsUrl: `${POSTHOG_DOCS_URL}/support/troubleshooting`,\n },\n ingestion_warning: {\n title: 'Ingestion warnings on recent events',\n description:\n 'Some recent events were rejected or flagged by the ingestion pipeline.',\n docsUrl: `${POSTHOG_DOCS_URL}/support/troubleshooting`,\n },\n sdk_outdated: {\n title: 'SDK version is out of date',\n description:\n 'One or more SDKs are running an old version. Upgrade to get the latest fixes.',\n docsUrl: `${POSTHOG_DOCS_URL}/libraries`,\n },\n no_live_events: {\n title: 'No $pageview or $screen events in the last 30 days',\n description:\n 'PostHog is not receiving page or screen events from this project.',\n docsUrl: `${POSTHOG_DOCS_URL}/getting-started/install`,\n },\n no_pageleave_events: {\n title: '$pageleave events not being sent',\n description:\n 'Enable pageleave tracking to power bounce rate and session duration.',\n docsUrl: `${POSTHOG_DOCS_URL}/libraries/js#config`,\n },\n scroll_depth: {\n title: 'Scroll depth tracking disabled',\n description:\n 'Turn on scroll depth to capture how far users read each page.',\n docsUrl: `${POSTHOG_DOCS_URL}/libraries/js#config`,\n },\n authorized_urls: {\n title: 'No authorized URLs configured',\n description:\n 'Some web analytics filters require at least one authorized URL to work.',\n docsUrl: `${POSTHOG_DOCS_URL}/web-analytics/faq`,\n },\n reverse_proxy: {\n title: 'No reverse proxy detected',\n description: 'A reverse proxy reduces data loss from ad blockers.',\n docsUrl: `${POSTHOG_DOCS_URL}/advanced/proxy`,\n },\n web_vitals: {\n title: 'Web Vitals tracking disabled',\n description:\n 'Enable Web Vitals to capture LCP, CLS and other performance metrics.',\n docsUrl: `${POSTHOG_DOCS_URL}/web-analytics/web-vitals`,\n },\n materialized_view_failure: {\n title: 'A materialized view is failing',\n description: 'A data modeling pipeline failed its most recent run.',\n docsUrl: `${POSTHOG_DOCS_URL}/data-warehouse`,\n },\n external_data_failure: {\n title: 'External data source is failing',\n description: 'An external data source sync failed and data may be stale.',\n docsUrl: `${POSTHOG_DOCS_URL}/data-warehouse/sources`,\n },\n};\n\nexport const UNKNOWN_KIND_META: KindMeta = {\n title: 'Unknown issue',\n description:\n 'PostHog reported an issue kind the wizard does not yet recognize.',\n docsUrl: POSTHOG_DOCS_URL,\n};\n\nexport function getKindMeta(kind: string): KindMeta {\n return KIND_METADATA[kind] ?? { ...UNKNOWN_KIND_META, title: kind };\n}\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { POSTHOG_DOCTOR_PROGRAM } from './steps.js';\n\nexport const posthogDoctorConfig: ProgramConfig = {\n command: 'doctor',\n description:\n 'Diagnose your PostHog project for configuration issues and setup warnings',\n id: 'posthog-doctor',\n requiresAi: false,\n steps: POSTHOG_DOCTOR_PROGRAM,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n};\n\nexport { POSTHOG_DOCTOR_PROGRAM } from './steps.js';\nexport { fetchHealthIssues } from './fetch.js';\nexport { getKindMeta, KIND_METADATA } from './kind-metadata.js';\nexport type { KindMeta } from './kind-metadata.js';\nexport type {\n HealthIssue,\n HealthIssueSeverity,\n HealthIssueSummary,\n} from './types.js';\n","import { existsSync, statSync } from 'fs';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\nimport { findPackageJsons } from '@lib/programs/shared/package-scanning';\n\nexport type WebAnalyticsDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-package-json' }\n | { kind: 'no-posthog'; scannedCount: number };\n\nexport const WEB_ANALYTICS_ABORT_CASES: AbortCase[] = [\n {\n match: /^no web analytics events$/i,\n message: 'No web analytics events',\n body:\n 'The doctor found no $pageview events in the last 30 days, so there is ' +\n 'nothing to audit yet. Make sure PostHog is initialized and capturing ' +\n 'pageviews, then run the doctor again.',\n docsUrl: 'https://posthog.com/docs/web-analytics/getting-started',\n },\n {\n match: /^insufficient permissions$/i,\n message: 'Insufficient permissions',\n body:\n 'The doctor could not query your project — the authenticated token is ' +\n 'missing query access. Re-run the wizard to sign in again, or use a key ' +\n 'with read access to your events.',\n docsUrl: 'https://posthog.com/docs/web-analytics',\n },\n {\n match: /^posthog sdk not installed$/i,\n message: 'PostHog SDK not installed',\n body:\n 'The doctor could not find a PostHog SDK in this project. Install and ' +\n 'configure PostHog first (run `npx @posthog/wizard`), then run the ' +\n 'doctor to check your web analytics setup.',\n docsUrl: 'https://posthog.com/docs/libraries/js',\n },\n];\n\nexport function detectWebAnalyticsPrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: WebAnalyticsDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n const matches = findPackageJsons(installDir);\n\n if (matches.length === 0) {\n fail({ kind: 'no-package-json' });\n return;\n }\n\n const sdks = [...new Set(matches.flatMap((m) => m.posthogSdks))];\n\n if (sdks.length === 0) {\n fail({ kind: 'no-posthog', scannedCount: matches.length });\n return;\n }\n\n setFrameworkContext('detectedPosthogSdks', sdks);\n}\n","import type { ProgramStep } from '@lib/programs/program-step';\nimport { AGENT_SKILL_STEPS } from '@lib/programs/agent-skill/steps';\nimport { detectWebAnalyticsPrerequisites } from './detect.js';\n\nexport const WEB_ANALYTICS_DOCTOR_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting prerequisites',\n onReady: (ctx) =>\n detectWebAnalyticsPrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n ...AGENT_SKILL_STEPS,\n];\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport { createSkillProgram } from '../agent-skill/index.js';\nimport { WEB_ANALYTICS_DOCTOR_PROGRAM } from './steps.js';\nimport { WEB_ANALYTICS_ABORT_CASES } from './detect.js';\n\nconst REPORT_FILE = 'posthog-web-analytics-report.md';\nconst DOCS_URL = 'https://posthog.com/docs/web-analytics';\n\nexport const webAnalyticsDoctorConfig: ProgramConfig = {\n ...createSkillProgram({\n skillId: 'web-analytics-doctor',\n command: 'web-analytics',\n id: 'web-analytics-doctor',\n description: 'Audit and fix your PostHog web analytics setup',\n integrationLabel: 'web-analytics-doctor',\n customPrompt:\n \"Run the web-analytics-doctor skill to check this project's PostHog web \" +\n 'analytics setup. Audit read-only first, then present the findings to the ' +\n 'user with a single wizard_ask multi-select and apply only the fixes they ' +\n 'choose — editing project code and/or PostHog project settings via the ' +\n 'MCP — before writing the report.',\n successMessage:\n 'Web analytics check complete! You can view the report at ./posthog-web-analytics-report.md',\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n spinnerMessage: 'Checking your web analytics setup...',\n estimatedDurationMinutes: 5,\n requires: ['posthog-integration'],\n abortCases: WEB_ANALYTICS_ABORT_CASES,\n }),\n steps: WEB_ANALYTICS_DOCTOR_PROGRAM,\n parentCommand: 'audit',\n};\n\nexport { WEB_ANALYTICS_DOCTOR_PROGRAM } from './steps.js';\nexport {\n detectWebAnalyticsPrerequisites,\n WEB_ANALYTICS_ABORT_CASES,\n type WebAnalyticsDetectError,\n} from './detect.js';\n","import type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\n\nexport const MIGRATION_PROGRAM: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'migration-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Migration',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","/**\n * Vendor cost stack — the multi-tool baseline a typical migration target has\n * before consolidating onto PostHog. Numbers from each vendor's published\n * starter pricing.\n */\n\nimport { Text } from 'ink';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const VENDOR_STACK_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 600,\n pause: 9000,\n lines: [\n <Text bold>{' Typical pre-migration stack'}</Text>,\n <Text> </Text>,\n <Text>\n <Text color=\"gray\">{' Sentry'}</Text>\n <Text>{' error tracking '}</Text>\n <Text color=\"red\">{'$26/mo+'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' LaunchDarkly'}</Text>\n <Text>{' feature flags '}</Text>\n <Text color=\"red\">{'$8.33/mo+'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' Amplitude'}</Text>\n <Text>{' product analytics '}</Text>\n <Text color=\"red\">{'$49/mo+'}</Text>\n </Text>,\n <Text>\n <Text color=\"gray\">{' Braintrust'}</Text>\n <Text>{' LLM analytics '}</Text>\n <Text color=\"red\">{'$50/mo+'}</Text>\n </Text>,\n <Text color=\"gray\">{' ─────────────────────────────────────'}</Text>,\n <Text>\n <Text>{' Total'}</Text>\n <Text>{' '}</Text>\n <Text bold color=\"red\">\n {'$133/mo+'}\n </Text>\n </Text>,\n <Text dimColor>{' plus ~450KB of JavaScript SDKs'}</Text>,\n ],\n};\n","/**\n * PostHog free-tier highlights — the numbers a migrating team gets back when\n * they consolidate. Sourced from posthog.com/pricing.md.\n */\n\nimport { Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const FREE_TIER_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 400,\n pause: 9000,\n lines: [\n <Text bold>{' Free every month, on every product'}</Text>,\n <Text> </Text>,\n <Text>\n <Text color={Colors.accent}>{' 1,000,000 '}</Text>\n <Text>events </Text>\n <Text dimColor>product analytics</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 1,000,000 '}</Text>\n <Text>requests </Text>\n <Text dimColor>feature flags + experiments</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 5,000 '}</Text>\n <Text>recordings </Text>\n <Text dimColor>session replay</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 100,000 '}</Text>\n <Text>exceptions </Text>\n <Text dimColor>error tracking</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 100,000 '}</Text>\n <Text>events </Text>\n <Text dimColor>LLM analytics</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 50 GB '}</Text>\n <Text>logs </Text>\n <Text dimColor>logs</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 1,500 '}</Text>\n <Text>responses </Text>\n <Text dimColor>surveys</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' 1,000,000 '}</Text>\n <Text>rows </Text>\n <Text dimColor>data warehouse</Text>\n </Text>,\n ],\n};\n","/**\n * Pricing structure block — what happens after the free tier.\n */\n\nimport { Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\n\nexport const PRICING_STRUCTURE_BLOCK: ContentBlock = {\n type: 'lines',\n interval: 500,\n pause: 8000,\n lines: [\n <Text bold>{' After the free tier'}</Text>,\n <Text> </Text>,\n <Text>\n <Text color={Colors.accent}>{' $0 '}</Text>\n <Text>base price · pay only for what you use</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>per-event prices decrease with volume</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>no per-seat charges — your whole team is included</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>web analytics bundled with product analytics</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>experiments bundled with feature flags</Text>\n </Text>,\n <Text>\n <Text color={Colors.accent}>{' ◆ '}</Text>\n <Text>revenue analytics bundled with data warehouse</Text>\n </Text>,\n ],\n};\n","/**\n * Migration learn deck (statsig variant). Statsig is the only `migrate`\n * variant today, so this deck plays as-is when the wizard runs\n * `migrate --product=statsig`. Three movements:\n *\n * 1. Welcome and reassure.\n * 2. What to expect — the migration is replacement-only, takes a few\n * minutes, leaves the build green.\n * 3. What's a little different — how flags and experiments work in\n * PostHog, presented as right-way guidance rather than gotchas.\n *\n * FF/experiments guidance paraphrased from PostHog public docs:\n * - posthog.com/docs/feature-flags/best-practices\n * - posthog.com/docs/feature-flags/common-questions\n * - posthog.com/docs/experiments/best-practices\n */\n\nimport { Text } from 'ink';\nimport type { WizardStore } from '@ui/tui/store';\nimport { Colors } from '@ui/tui/styles';\nimport { TextRevealMode } from '@ui/tui/primitives/TextBlock';\nimport type { ContentBlock } from '@ui/tui/primitives/content-types';\nimport { StatusPeekTrigger } from '@ui/tui/components/StatusPeekTrigger';\nimport { PRODUCT_SUITE_BLOCK } from '@lib/programs/posthog-integration/content/product-suite';\nimport { LINE_CHART_BLOCK } from '@lib/programs/posthog-integration/content/line-chart';\nimport { FUNNEL_BLOCK } from '@lib/programs/posthog-integration/content/funnel';\nimport { VENDOR_STACK_BLOCK } from './vendor-stack.js';\nimport { FREE_TIER_BLOCK } from './free-tier.js';\nimport { PRICING_STRUCTURE_BLOCK } from './pricing-structure.js';\n\nexport const getContentBlocks = (store?: WizardStore): ContentBlock[] => [\n // ── Welcome ────────────────────────────────────────────────────────────\n {\n content: 'Hello.',\n pause: 3000,\n mode: TextRevealMode.Typewriter,\n animationInterval: 160,\n },\n\n { content: 'The Wizard is an agent.', pause: 4000 },\n\n {\n content:\n 'As we speak, it’s making a plan to migrate from Statsig to PostHog.',\n pause: 6000,\n },\n\n {\n content: 'PostHog covers the cost of running this agent.',\n pause: 4000,\n },\n\n { type: 'clear', pause: 2000 },\n\n {\n pause: 5000,\n persist: true,\n content: <StatusPeekTrigger store={store} />,\n },\n\n {\n pause: 6000,\n persist: true,\n content: (\n <Text>\n Press{' '}\n <Text color={Colors.accent} bold>\n S\n </Text>{' '}\n to expand or collapse the status.\n </Text>\n ),\n },\n\n { type: 'clear', pause: 2000 },\n\n // ── What to expect ─────────────────────────────────────────────────────\n { content: 'Here’s what to expect.', pause: 3000 },\n\n { content: 'The migration takes about ten minutes.', pause: 3000 },\n\n {\n content:\n 'Every Statsig call gets replaced in place with its PostHog equivalent.',\n pause: 5500,\n },\n\n {\n content:\n 'Nothing new gets added. No extra captures, no surprise instrumentation.',\n pause: 5500,\n },\n\n {\n content:\n 'The Statsig package gets removed at the end. We’ll run build and lint to clean up after ourselves.',\n pause: 6500,\n },\n\n { type: 'clear', pause: 2000 },\n\n // ── What's a little different ─────────────────────────────────────────\n {\n content: 'A few things work a little differently in PostHog.',\n pause: 4500,\n },\n\n {\n content: (\n <Text>\n Flags evaluate against a stable user. Call{' '}\n <Text bold color={Colors.accent}>\n identify()\n </Text>{' '}\n first, then check the flag.\n </Text>\n ),\n pause: 6000,\n persist: true,\n },\n\n {\n content:\n 'For anything in the first paint, evaluate server-side and bootstrap the values into the client.',\n pause: 6500,\n },\n\n {\n content: (\n <Text>\n In production, route requests through a reverse proxy to avoid ad\n blockers breaking your flags.{'\\n'}\n <Text dimColor>https://posthog.com/docs/advanced/proxy</Text>\n </Text>\n ),\n pause: 6500,\n persist: true,\n },\n\n {\n content:\n 'When a flag reaches 100% rollout, retire it. Flags are signals, not switches.',\n pause: 5500,\n },\n\n {\n content: (\n <Text>\n Name flags descriptively. No double negatives. Reflect the return type.{' '}\n <Text dimColor>For example </Text>\n <Text bold>show-new-checkout</Text>\n <Text dimColor>.</Text>\n </Text>\n ),\n pause: 6500,\n persist: true,\n },\n\n { type: 'clear', pause: 1500 },\n\n // ── Experiments ────────────────────────────────────────────────────────\n {\n content: (\n <Text bold color={Colors.accent}>\n Experiments\n </Text>\n ),\n pause: 2500,\n persist: true,\n },\n\n {\n content:\n 'Change one thing per variant. Multiple changes in one variant blur the result.',\n pause: 5500,\n },\n\n {\n content:\n 'Decide the running time up front. PostHog includes a sample-size and duration calculator in the setup flow.',\n pause: 6500,\n },\n\n {\n content: 'Roll out to 5–10% first. Watch the metrics. Then increase.',\n pause: 5000,\n },\n\n {\n content:\n 'Exclude users who already completed the flow. They can’t be affected by the test.',\n pause: 5500,\n },\n\n { type: 'clear', pause: 1500 },\n\n // ── Close ──────────────────────────────────────────────────────────────\n {\n content: 'Flags and experiments live alongside the rest of your data.',\n pause: 4500,\n },\n\n {\n content: 'Ship behind a flag, watch replays, check analytics for impact.',\n pause: 4500,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n content:\n 'PostHog also provides every other analytics and AI tool to build your product.',\n pause: 4500,\n },\n\n PRODUCT_SUITE_BLOCK,\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'And consolidating onto one platform saves real money.',\n pause: 4500,\n },\n\n { content: 'Here’s the math.', pause: 1500 },\n\n VENDOR_STACK_BLOCK,\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'Pricing is usage-based, with a generous free tier.',\n pause: 4000,\n },\n\n FREE_TIER_BLOCK,\n\n { type: 'clear', pause: 1500 },\n\n PRICING_STRUCTURE_BLOCK,\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'Gain clarity and really understand your users.',\n pause: 4000,\n },\n\n { content: 'Use trends to measure growth.', pause: 2500 },\n\n LINE_CHART_BLOCK,\n\n { type: 'clear', pause: 500 },\n\n { content: 'Use funnels to reveal bottlenecks.', pause: 2500 },\n\n FUNNEL_BLOCK,\n];\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport type { AbortCase } from '@lib/agent/agent-runner';\nimport { WIZARD_TOOL_NAMES } from '@lib/wizard-tools';\nimport { MIGRATION_PROGRAM } from './steps.js';\nimport { getContentBlocks } from './content/index.js';\n\nconst MIGRATION_REPORT_FILE = 'migration-report.md';\n\nconst MIGRATION_ABORT_CASES: AbortCase[] = [\n {\n match: /^no source-sdk calls found$/i,\n message: 'No source-SDK calls found',\n body:\n 'The migration needs an existing third-party SDK to migrate from. No ' +\n 'calls to the source SDK appear anywhere in this project. If you ' +\n \"haven't installed PostHog yet, you don't need this command — run \" +\n '`npx @posthog/wizard@latest` to add PostHog from scratch.',\n },\n];\n\n// Default skill id when nothing else picks one. The `wizard migrate <vendor>`\n// subcommands override this via skillCommandFactory using each manifest\n// entry's skillId, so this default only kicks in for legacy callers (e.g.\n// programmatic uses of migrationConfig directly).\nconst DEFAULT_MIGRATE_SKILL_ID = 'migrate-statsig';\n\nexport const migrationConfig: ProgramConfig = {\n command: 'migrate',\n description: 'Migrate to PostHog from another analytics provider',\n id: 'migration',\n skillId: DEFAULT_MIGRATE_SKILL_ID,\n steps: MIGRATION_PROGRAM,\n reportFile: MIGRATION_REPORT_FILE,\n getContentBlocks,\n allowedTools: ['Agent'],\n disallowedTools: [WIZARD_TOOL_NAMES.wizardAsk],\n run: {\n skillId: DEFAULT_MIGRATE_SKILL_ID,\n integrationLabel: 'migration',\n customPrompt: () =>\n 'Migrate this project from its existing third-party analytics, ' +\n 'feature-flag, and observability tools to PostHog. Run the `migrate` ' +\n 'skill end-to-end: follow the step chain starting at ' +\n 'references/1-presence.md. Only replace existing source-SDK call sites ' +\n 'with PostHog equivalents — make zero unrelated changes and no ' +\n `net-new instrumentation. The final report is written to ./${MIGRATION_REPORT_FILE}.`,\n successMessage: `Migration complete! View the report at ./${MIGRATION_REPORT_FILE}`,\n reportFile: MIGRATION_REPORT_FILE,\n docsUrl: '',\n spinnerMessage: 'Migrating to PostHog...',\n estimatedDurationMinutes: 8,\n abortCases: MIGRATION_ABORT_CASES,\n },\n requires: ['posthog-integration'],\n};\n\nexport { MIGRATION_PROGRAM } from './steps.js';\n","/**\n * Source maps upload prerequisite detection.\n *\n * Scans the project for signals that identify the platform and build system,\n * then maps to one of the context-mill `error-tracking-upload-source-maps-*`\n * skill variants. Results are written to frameworkContext for the intro\n * screen to render and for the agent prompt to consume.\n */\n\nimport type { Dirent } from 'fs';\nimport { readFileSync, readdirSync, existsSync, statSync } from 'fs';\nimport { join, relative } from 'path';\nimport { IGNORED_DIRS } from '@utils/file-utils';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\n\n/**\n * Skill variants published under the `error-tracking-upload-source-maps`\n * category in context-mill. The agent loads\n * `error-tracking-upload-source-maps-<variant>`.\n */\nexport type SkillVariant =\n | 'web'\n | 'nextjs'\n | 'node'\n | 'react'\n | 'angular'\n | 'nuxt'\n | 'react-native'\n | 'android'\n | 'flutter'\n | 'ios'\n | 'vite'\n | 'webpack'\n | 'rollup';\n\nconst DISPLAY_NAME: Record<SkillVariant, string> = {\n web: 'Web (JavaScript)',\n nextjs: 'Next.js',\n node: 'Node.js',\n react: 'React',\n angular: 'Angular',\n nuxt: 'Nuxt',\n 'react-native': 'React Native',\n android: 'Android',\n flutter: 'Flutter',\n ios: 'iOS',\n vite: 'Vite',\n webpack: 'Webpack',\n rollup: 'Rollup',\n};\n\n/**\n * Variants the wizard can wire up source-map upload for automatically. The\n * native variants (react-native, android, flutter, ios) are recognised but not\n * yet automatable, so the agentic picker treats them as non-instrumentable.\n */\nexport const AUTOMATABLE_VARIANTS: readonly SkillVariant[] = [\n 'web',\n 'nextjs',\n 'node',\n 'react',\n 'angular',\n 'nuxt',\n 'vite',\n 'webpack',\n 'rollup',\n];\n\nconst POSTHOG_SDKS = [\n 'posthog-js',\n 'posthog-node',\n 'posthog-react-native',\n 'posthog-android',\n 'posthog-ios',\n];\n\n/**\n * Structured detection errors. The screen renders each kind into JSX\n * with proper formatting — keeps error data separate from presentation.\n */\nexport type SourceMapsDetectError =\n | {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n }\n | { kind: 'no-project-files' }\n | { kind: 'unsupported-platform'; detected: string }\n | { kind: 'no-posthog-sdk'; platform: SkillVariant };\n\n/** `[ABORT] <reason>` cases the source maps skill can emit. */\nexport const SOURCE_MAPS_ABORT_CASES: AbortCase[] = [\n {\n match: /^no posthog sdk detected$/i,\n message: 'No PostHog SDK detected',\n body:\n 'The agent could not find a PostHog SDK in your project. ' +\n 'Source map upload requires the SDK to already be installed so it can ' +\n 'report errors. Run `npx @posthog/wizard` first to install the SDK.',\n docsUrl: 'https://posthog.com/docs/error-tracking',\n },\n {\n match: /^build command not found$/i,\n message: 'Build command not found',\n body:\n 'The agent could not identify how to build your project. Source map ' +\n 'upload runs as part of the production build. Add a build script to ' +\n 'your project and run this wizard again.',\n docsUrl: 'https://posthog.com/docs/error-tracking/upload-source-maps',\n },\n];\n\n// ── File / dependency probes ─────────────────────────────────────────\n\ninterface ProjectSignals {\n packageJsons: Array<{ path: string; deps: Set<string> }>;\n hasXcodeProject: boolean;\n hasPodfile: boolean;\n hasSwiftPackage: boolean;\n hasGradle: boolean;\n hasPubspec: boolean;\n scannedFileCount: number;\n}\n\nfunction collectSignals(installDir: string, maxDepth = 3): ProjectSignals {\n const signals: ProjectSignals = {\n packageJsons: [],\n hasXcodeProject: false,\n hasPodfile: false,\n hasSwiftPackage: false,\n hasGradle: false,\n hasPubspec: false,\n scannedFileCount: 0,\n };\n\n function scan(dir: string, depth: number): void {\n if (depth > maxDepth) return;\n\n let entries: Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith('.') && entry.name !== '.') continue;\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = join(dir, entry.name);\n\n if (entry.isFile()) {\n signals.scannedFileCount += 1;\n if (entry.name === 'package.json') {\n try {\n const pkg = JSON.parse(readFileSync(fullPath, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const deps = new Set([\n ...Object.keys(pkg.dependencies ?? {}),\n ...Object.keys(pkg.devDependencies ?? {}),\n ]);\n signals.packageJsons.push({\n path: relative(installDir, fullPath) || 'package.json',\n deps,\n });\n } catch {\n // skip malformed package.json\n }\n } else if (entry.name === 'Podfile') {\n signals.hasPodfile = true;\n } else if (entry.name === 'Package.swift') {\n signals.hasSwiftPackage = true;\n } else if (entry.name === 'pubspec.yaml') {\n signals.hasPubspec = true;\n } else if (\n entry.name === 'build.gradle' ||\n entry.name === 'build.gradle.kts' ||\n entry.name === 'settings.gradle' ||\n entry.name === 'settings.gradle.kts'\n ) {\n signals.hasGradle = true;\n }\n } else if (entry.isDirectory()) {\n if (entry.name.endsWith('.xcodeproj')) {\n signals.hasXcodeProject = true;\n } else {\n scan(fullPath, depth + 1);\n }\n }\n }\n }\n\n scan(installDir, 0);\n return signals;\n}\n\n// ── Skill selection ──────────────────────────────────────────────────\n\nfunction pickJsVariant(deps: Set<string>): SkillVariant {\n // Opinionated full-stack frameworks first — they own their build pipeline\n // and have dedicated skill variants, so bundler detection underneath\n // them is irrelevant.\n if (deps.has('react-native')) return 'react-native';\n if (deps.has('nuxt')) return 'nuxt';\n if (deps.has('next')) return 'nextjs';\n if (deps.has('@angular/core')) return 'angular';\n // Bundlers next — prefer these over the bare `react` variant because\n // their skills are simpler (one bundler-plugin config) than wiring\n // posthog-cli into an arbitrary React setup.\n if (deps.has('vite')) return 'vite';\n if (deps.has('webpack')) return 'webpack';\n if (deps.has('rollup')) return 'rollup';\n // Plain React with no recognised bundler.\n if (deps.has('react')) return 'react';\n // Server-only Node project\n if (deps.has('posthog-node')) return 'node';\n // Fallback: generic web\n return 'web';\n}\n\nfunction selectVariant(signals: ProjectSignals): SkillVariant | null {\n // Mobile / native first — they don't coexist with JS bundlers in the\n // detection signals we look at.\n if (signals.hasPubspec) return 'flutter';\n if (signals.hasXcodeProject || signals.hasPodfile || signals.hasSwiftPackage)\n return 'ios';\n if (signals.hasGradle) return 'android';\n\n if (signals.packageJsons.length > 0) {\n // Union all deps across package.json files (covers monorepos)\n const allDeps = new Set<string>();\n for (const pkg of signals.packageJsons) {\n for (const dep of pkg.deps) allDeps.add(dep);\n }\n return pickJsVariant(allDeps);\n }\n\n return null;\n}\n\nfunction hasPostHogSdk(signals: ProjectSignals): boolean {\n for (const pkg of signals.packageJsons) {\n for (const sdk of POSTHOG_SDKS) {\n if (pkg.deps.has(sdk)) return true;\n }\n }\n // For native platforms the PostHog SDK lives outside package.json and\n // is detected by the agent during the skill run. Assume present here.\n return (\n signals.hasXcodeProject ||\n signals.hasPodfile ||\n signals.hasSwiftPackage ||\n signals.hasGradle ||\n signals.hasPubspec\n );\n}\n\n// ── Entry point ──────────────────────────────────────────────────────\n\nexport const SOURCE_MAPS_CONTEXT_KEYS = {\n skillVariant: 'sourceMapsSkillVariant',\n displayName: 'sourceMapsDisplayName',\n packagePaths: 'sourceMapsPackagePaths',\n detectError: 'detectError',\n // Set by the agentic picker once the user chooses a project to instrument.\n selectedVariant: 'sourceMapsSelectedVariant',\n selectedDisplayName: 'sourceMapsSelectedDisplayName',\n selectedPath: 'sourceMapsSelectedPath',\n} as const;\n\n/**\n * Scan `session.installDir` for platform / build-system signals. Writes\n * detection results into frameworkContext via the callback — either the\n * picked skill variant + display name, or a `SourceMapsDetectError`.\n *\n * The skill install happens later in the agent run, not here. This step\n * only picks which variant the prompt should ask the agent to load.\n */\nexport function detectSourceMapsPrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: SourceMapsDetectError) =>\n setFrameworkContext(SOURCE_MAPS_CONTEXT_KEYS.detectError, error);\n\n const installDir = session.installDir;\n\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n\n const signals = collectSignals(installDir);\n const variant = selectVariant(signals);\n\n // This program currently targets JS-like stacks only. Avoid selecting native\n // platforms until dedicated skill variants are available.\n if (\n variant &&\n ['react-native', 'flutter', 'ios', 'android'].includes(variant)\n ) {\n fail({ kind: 'unsupported-platform', detected: variant });\n return;\n }\n\n if (!variant) {\n if (signals.scannedFileCount === 0) {\n fail({ kind: 'no-project-files' });\n } else {\n fail({ kind: 'unsupported-platform', detected: 'unknown' });\n }\n return;\n }\n\n if (!hasPostHogSdk(signals)) {\n fail({ kind: 'no-posthog-sdk', platform: variant });\n return;\n }\n\n setFrameworkContext(SOURCE_MAPS_CONTEXT_KEYS.skillVariant, variant);\n setFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.displayName,\n DISPLAY_NAME[variant],\n );\n setFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.packagePaths,\n signals.packageJsons.map((p) => p.path),\n );\n}\n\nexport { DISPLAY_NAME as VARIANT_DISPLAY_NAME };\n","/**\n * Error tracking source maps upload program step list.\n *\n * Flow: a static intro (no detection yet) → login → an agentic detect+pick\n * screen that scans the repo on Haiku and lets the user choose a project →\n * agent run → outro. Detection runs after auth because the detection agent\n * needs credentials.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { RunPhase } from '@lib/wizard-session';\nimport { SOURCE_MAPS_CONTEXT_KEYS } from './detect.js';\n\nfunction projectSelected(session: WizardSession): boolean {\n return (\n session.frameworkContext[SOURCE_MAPS_CONTEXT_KEYS.selectedVariant] != null\n );\n}\n\nexport const ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM: ProgramStep[] = [\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'source-maps-intro',\n gate: (session) => session.setupConfirmed,\n },\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'detect',\n label: 'Detecting projects',\n // The Haiku agent scans the repo, surfaces an instrumentable / not-yet map,\n // and the user picks the project to wire up. Advances once a project is\n // chosen (its variant is written to frameworkContext). The gate lets the\n // agent runner park after auth until the pick lands, so the run prompt sees\n // the chosen variant.\n screenId: 'source-maps-detect',\n isComplete: projectSelected,\n gate: projectSelected,\n },\n {\n id: 'run',\n label: 'Upload source maps',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'source-maps-outro',\n isComplete: (session) => session.outroDismissed,\n },\n {\n id: 'skills',\n label: 'Skills',\n screenId: 'keep-skills',\n },\n];\n","import { AgentSignals } from '@lib/agent/agent-interface';\nimport type { SkillVariant } from './detect.js';\n\nexport type SourceMapsUploadPromptParams = {\n displayName: string | undefined;\n variant: SkillVariant;\n skillId: string;\n /** Project to instrument, relative to the repo root (\".\" or undefined = root). */\n projectPath?: string;\n projectId: number;\n host: string;\n settingsUrl: string;\n uiHost: string;\n};\n\nexport const SOURCE_MAPS_DETECTION_FAILED_PROMPT = `Detection did not pick a source maps skill variant for this project.\nEmit: ${AgentSignals.ABORT} unsupported-platform\nThen halt.`;\n\nexport function buildSourceMapsUploadPrompt(\n params: SourceMapsUploadPromptParams,\n): string {\n const {\n displayName,\n variant,\n skillId,\n projectPath,\n projectId,\n host,\n settingsUrl,\n uiHost,\n } = params;\n const platformLabel = displayName ?? variant;\n const inSubproject = projectPath != null && projectPath !== '.';\n const projectLine = inSubproject\n ? `- Project directory (relative to repo root): ${projectPath}`\n : '- Project directory: the repo root';\n\n return `You are wiring up PostHog Error Tracking source map upload for this ${platformLabel} project.\n\nProject context:\n- PostHog Project ID: ${projectId}\n- PostHog Host: ${host}\n- Detected platform: ${platformLabel}\n- Skill to use: ${skillId}\n${projectLine}\n- Personal API keys settings page: ${settingsUrl}\n\nAll file changes, build/run commands, and config edits target the project directory above${\n inSubproject\n ? ` — this is a monorepo, so scope your work to \\`${projectPath}\\` and do not touch other packages`\n : ''\n }.\n\nThe skill you install in STEP 2 is the source of truth for the HOW of every\nstep: its \"## Steps\" section has an overview, tips and per-technology\nexamples for each named step, and its reference files carry the exact\nper-framework API. The STEPS below give the order, the conditionals, and the\nwizard-specific mechanics (which MCP tool to call, signals to emit) — read\nthe matching skill step (named in parentheses) before doing the work, and do\nnot invent steps the skill doesn't describe.\n\nFollow these steps IN ORDER. Do not skip or reorder.\n\nYour FIRST message must contain ONLY parallel tool calls, in this order:\n - the STEP 1 wizard_ask call FIRST — tool calls execute as they stream,\n so this puts the API-key prompt in front of the user within seconds —\n then\n - one TaskCreate call PER task below, all in this same message (the tool\n takes a single task per call). The TUI shows only the subject, so keep\n every description to a few words — never a sentence.\nDo not read files, explore the project, or write any text first, and keep\nany thinking before the calls to a single short sentence.\n\nUse exactly these tasks, in this order — do not collapse, rename, or omit\nany of them. Getting the API key is NOT a task — its prompt is already on\nscreen by the time the list renders:\n 1. Install source maps skill\n 2. Apply build-config changes (per skill)\n 3. Make credentials readable at build time\n 4. Write keys to .env\n 5. Identify build & run commands\n 6. Set up CI for auto-upload\n 7. Test the local setup\n 8. Summarise & hand off\nDrive the list with TaskUpdate — mark a task in_progress when you start it\nand completed when done. ALWAYS keep task 7 (\"Test the local setup\") in the\nlist even if the user declines it in STEP 8: mark it completed rather than\ndeleting it, so the user can see it was offered.\n\nSTEP 1 — Get a personal API key from the user. (skill: \"Get a personal API key\")\n This wizard_ask call ships in your FIRST message, per the rule above.\n The wizard cannot mint keys — never call the PostHog API or any tool to\n create one. Ask the user with the wizard_ask MCP tool; you receive the\n answer as a vaulted secretRef (never the raw value), which you reuse in\n STEP 5:\n {\n id: \"api-key\",\n prompt: \"Paste your PostHog personal API key below.\\\\n\\\\nDon't have one yet? Create one here:\\\\n${settingsUrl}\\\\n\\\\nWhen creating the key, choose the 'Source map upload' preset, then come back and paste it here.\",\n kind: \"text\",\n sensitive: true\n }\n Keep the \\\\n line breaks exactly as written — Ink's <Text> renders them\n as separate lines. The answer is { secretRef: \"secret:...\" }.\n If wizard_ask is unavailable (CI / non-interactive), emit\n ${AgentSignals.ABORT} requires-interactive-mode and halt.\n\nSTEP 2 — Install the skill.\n Call install_skill (wizard-tools MCP server) with skillId \"${skillId}\".\n Do NOT run shell commands to install skills. Then read the installed\n SKILL.md and its reference files — they drive STEPS 3-9.\n If install fails, emit ${\n AgentSignals.ERROR_RESOURCE_MISSING\n } skill ${skillId} could not be installed.\n\nSTEP 3 — Apply build-config changes. (skill: \"Apply build-config changes\")\n Make the bundler / build-config changes the skill's step instructs. The\n skill and its reference are the source of truth for this platform.\n\nSTEP 4 — Make the credentials readable at build time. (skill: \"Make credentials available at build time\")\n Follow the skill's step. Wizard-specific: if it calls for a loader (e.g.\n \\`dotenv\\`), install it SILENTLY — do NOT ask the user or call wizard_ask.\n Skip this step entirely if the platform already auto-loads .env.\n\nSTEP 5 — Write the credentials to the env file. (skill: \"Write credentials to the env file\")\n Use the wizard-tools MCP server. Reuse the env file the skill tells you to\n pick — the prerequisite PostHog integration usually already wrote\n POSTHOG_* vars to one, so seed your keys alongside them.\n - First call check_env_keys on that file (returns present/absent, never\n values — don't read the file directly).\n - Then call set_env_values, passing the STEP 1 secretRef as a value\n object, not a literal string:\n values: {\n \"POSTHOG_CLI_API_KEY\": { secretRef: \"<the ref from STEP 1>\" },\n \"POSTHOG_CLI_PROJECT_ID\": \"${projectId}\",\n \"POSTHOG_CLI_HOST\": \"${host}\"\n }\n Variable names follow the skill's per-uploader conventions. The wizard\n resolves the ref locally before writing, so you never see the key value.\n\nSTEP 6 — Identify the build AND run commands. (skill: \"Identify the build and run commands\")\n Per the skill, resolve the production BUILD command and the RUN command\n for THIS project (use detect_package_manager for the package manager). Do\n NOT run either yourself — the user runs them. If you cannot identify a\n build command, emit ${AgentSignals.ABORT} build command not found.\n\nSTEP 7 — Set up CI for automatic uploads. (skill: \"Set up CI for automatic uploads\")\n Source maps only upload when the production build runs, so the build's\n CI/CD must carry the same upload credentials you wrote in STEP 5. Do this\n step without asking — there is no opt-in question for it. Follow the\n skill's \"Set up CI for automatic uploads\" step — it is the source of\n truth for tracing where the production build runs and wiring the\n credentials through every layer, whatever the CI provider.\n Wizard-specific rules on top:\n - Trace the deploy path by reading the project's files — do NOT ask the\n user, and do NOT invent config that isn't there.\n - Carry every manual follow-up the skill has you hand off (secrets the\n user must create, an untraceable build path) into STEP 9.\n\nSTEP 8 — Offer to test the local setup. (skill: \"Test the local setup\")\n Call wizard_ask:\n {\n id: \"test-affordance\",\n prompt: \"Want me to help you test your local setup? I'll add a temporary test button (or route) to your app so you can confirm errors show up in Error Tracking with readable stack traces after your next build. I'll remove it once you've confirmed it works.\",\n kind: \"single\",\n options: [\n { label: \"Yes, help me test it\", value: \"yes\" },\n { label: \"No, I'll test on my own later\", value: \"no\" }\n ]\n }\n\n If \"no\", skip to STEP 9.\n\n If \"yes\", follow the skill's \"Test the local setup\" step for the\n platform-appropriate affordance, the captureException shape, the\n placement, and the read-before-edit / always-revert rules. Then pause for\n the user with wizard_ask, baking the EXACT build and run commands from\n STEP 6 (and the exact button label / route) into the prompt as literal,\n copy-pasteable steps. Separate each numbered step with \\\\n\\\\n so the TUI\n renders them as distinct lines:\n {\n id: \"test-done\",\n prompt: \"1) Run \\`<your detected build command>\\` to upload source maps and build the app with the test affordance.\\\\n\\\\n2) Start the app with \\`<your detected run command>\\`, then click the \\\\\"<your test button label>\\\\\" button (or hit \\`<your test route>\\`).\\\\n\\\\n3) Open Error Tracking in PostHog (${uiHost}/project/${projectId}/error_tracking) and confirm the test error appears with a source-resolved stack trace pointing at real source files (not minified bundle paths).\\\\n\\\\nWhen you're done, select Continue and I'll revert the test code.\",\n kind: \"single\",\n options: [{ label: \"Continue (revert test code)\", value: \"continue\" }]\n }\n After the user continues, revert the test code per the skill's rules and\n surface any failure in STEP 9.\n\nSTEP 9 — Summarise and hand off. (skill: \"Verify and hand off\")\n Follow the skill's \"Verify and hand off\" step. The Symbol sets page for\n this project — where the user confirms the upload landed — is:\n ${uiHost}/project/${projectId}/error_tracking/configuration\n`;\n}\n","/**\n * Source-maps learn-deck — the narrative played in the run screen's left\n * pane (LearnCard) while the agent wires source-map upload into the build.\n *\n * It educates the user on what source maps are and why uploading them\n * matters, built around a before/after stack-trace contrast: a minified\n * production trace nobody can read, then the same trace resolved back to\n * real source. Program-owned; wired onto the program's getContentBlocks.\n *\n * Lines stay narrow (~36 cols) because this renders in the left half of a\n * split pane — see LearnCard's paneWidth math.\n */\n\nimport { Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\nimport type { WizardStore } from '@ui/tui/store';\nimport { TextRevealMode } from '@ui/tui/primitives/TextBlock';\nimport {\n isClearBlock,\n type ContentBlock,\n} from '@ui/tui/primitives/content-types';\nimport { StatusPeekTrigger } from '@ui/tui/components/StatusPeekTrigger';\n\n/**\n * Per-slide dwell multiplier. Each block stays on screen for `pause * SLIDE_PACE`\n * ms after it finishes animating, before the deck advances. Bump this single\n * knob to give every slide more reading time. Clear (page-break) blocks are\n * left untouched so the blank gap between slides stays snappy.\n */\nconst SLIDE_PACE = 1.5;\n\nconst withPace = (block: ContentBlock): ContentBlock => {\n if (typeof block === 'string' || isClearBlock(block) || block.pause == null) {\n return block;\n }\n return { ...block, pause: Math.round(block.pause * SLIDE_PACE) };\n};\n\n/** Apply the dwell multiplier to every block in a deck. */\nconst pace = (blocks: ContentBlock[]): ContentBlock[] => blocks.map(withPace);\n\n/**\n * A minified production stack trace — the problem source maps solve. Framed as\n * a labelled, muted example (no error-red ✘) so a glance reads it as\n * illustrative content, not as the wizard itself having errored mid-run.\n */\nconst MINIFIED_TRACE: ContentBlock = {\n type: 'lines',\n interval: 400,\n pause: 7000,\n lines: [\n <Text dimColor>{'example — minified production trace'}</Text>,\n <Text color={Colors.muted}>{' TypeError: cart is undefined'}</Text>,\n <Text dimColor>{' at t.min.js:1:48213'}</Text>,\n <Text dimColor>{' at t.min.js:1:9402'}</Text>,\n <Text dimColor>{' at t.min.js:1:71150'}</Text>,\n ],\n};\n\n/** The same trace, resolved through uploaded source maps. */\nconst RESOLVED_TRACE: ContentBlock = {\n type: 'lines',\n interval: 400,\n pause: 8000,\n lines: [\n <Text dimColor>{'example — resolved with source maps'}</Text>,\n <Text color={Colors.success}>{' ✔ TypeError: cart is undefined'}</Text>,\n <Text>\n <Text dimColor>{' at '}</Text>\n <Text color=\"cyan\">Cart.tsx:42</Text>\n <Text dimColor>{' loadCart'}</Text>\n </Text>,\n <Text>\n <Text dimColor>{' at '}</Text>\n <Text color=\"cyan\">App.tsx:88</Text>\n <Text dimColor>{' render'}</Text>\n </Text>,\n <Text>\n <Text dimColor>{' at '}</Text>\n <Text color=\"cyan\">index.tsx:5</Text>\n <Text dimColor>{' main'}</Text>\n </Text>,\n ],\n};\n\n/**\n * How a bundle is tied to its map: PostHog injects a chunk-ID marker into the\n * built JS and stamps the matching source map with the same ID.\n */\nconst CHUNK_ID_LINK: ContentBlock = {\n type: 'lines',\n interval: 450,\n pause: 7500,\n lines: [\n <Text dimColor>app.min.js</Text>,\n <Text dimColor>{' …minified code…'}</Text>,\n <Text>\n <Text color=\"cyan\">{' //# chunkId=a1b2c3d4'}</Text>\n <Text dimColor>{' ← injected'}</Text>\n </Text>,\n <Text dimColor>{' ↕ matched by id'}</Text>,\n <Text>\n <Text dimColor>app.min.js.map</Text>\n <Text dimColor>{' ← uploaded'}</Text>\n </Text>,\n ],\n};\n\n/** Many similar exceptions collapse into a single issue. */\nconst GROUPING: ContentBlock = {\n type: 'lines',\n interval: 450,\n pause: 7000,\n lines: [\n <Text dimColor>{'exception ─┐'}</Text>,\n <Text>\n <Text dimColor>{'exception ─┼──→ '}</Text>\n <Text color={Colors.accent} bold>\n 1 issue\n </Text>\n </Text>,\n <Text dimColor>{'exception ─┘'}</Text>,\n ],\n};\n\nexport const getContentBlocks = (store?: WizardStore): ContentBlock[] =>\n pace([\n {\n content: 'Welcome.',\n pause: 3000,\n mode: TextRevealMode.Typewriter,\n animationInterval: 160,\n },\n\n {\n content: \"I'm wiring PostHog Error Tracking into your build.\",\n pause: 5000,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'When you ship to production, your code gets minified.',\n pause: 5000,\n },\n {\n content: 'Thousands of readable lines collapse into one dense bundle.',\n pause: 5000,\n },\n {\n content: 'So a thrown error gives you a stack trace like this:',\n pause: 2000,\n },\n\n MINIFIED_TRACE,\n\n { content: 'Just offsets into a file no human can read.', pause: 5000 },\n\n { type: 'clear', pause: 1500 },\n\n { content: 'Source maps are the key.', pause: 3500 },\n {\n content:\n 'They map every position in that bundle back to your original source — the real file, line, and function.',\n pause: 6000,\n },\n {\n content:\n \"Right now I'm hooking source-map generation and upload into your build, tied to each release you ship.\",\n pause: 6000,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'But how does PostHog know which map belongs to which build?',\n pause: 4500,\n },\n {\n content:\n 'During the build, it injects a unique chunk ID into each bundle:',\n pause: 2500,\n },\n\n CHUNK_ID_LINK,\n\n {\n content:\n 'The matching source map is stamped with that same ID before it ships to PostHog.',\n pause: 6000,\n },\n {\n content:\n 'When an error comes in, PostHog reads the chunk ID off the bundle, finds the map with the exact same ID, and uses it to map each frame back to your source — even for a release you shipped weeks ago.',\n pause: 8000,\n },\n\n { type: 'clear', pause: 1500 },\n\n { content: 'So that same error becomes:', pause: 2000 },\n\n RESOLVED_TRACE,\n\n {\n content: 'Readable stack traces, straight from production.',\n pause: 5000,\n },\n {\n content: 'You debug a live error like it happened on your own machine.',\n pause: 6000,\n },\n\n { type: 'clear', pause: 1500 },\n\n { content: 'Zooming out — this is how Error Tracking works.', pause: 4000 },\n {\n content: 'Every error your app throws is captured as an exception.',\n pause: 5000,\n },\n {\n content: 'PostHog groups similar exceptions into a single issue:',\n pause: 2500,\n },\n\n GROUPING,\n\n {\n content:\n 'So a bug that fires ten thousand times is one issue to triage — not ten thousand alerts.',\n pause: 6500,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n content: 'And this is where source maps earn their keep again.',\n pause: 4500,\n },\n {\n content:\n 'Grouping reads the stack trace. Minified frames all look alike — so unrelated crashes get merged, and one real bug scatters across many issues.',\n pause: 8000,\n },\n {\n content:\n 'With source maps, PostHog groups on your real frames — so each distinct bug lands as one clean issue.',\n pause: 7000,\n },\n\n { type: 'clear', pause: 1500 },\n\n {\n pause: 5000,\n persist: true,\n content: <StatusPeekTrigger store={store} />,\n },\n {\n pause: 90000,\n content: (\n <Text>\n Press{' '}\n <Text color={Colors.accent} bold>\n S\n </Text>{' '}\n to follow along — or sit tight, I'll let you know when it's done.\n </Text>\n ),\n },\n ]);\n","import type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { OutroKind } from '@lib/wizard-session';\nimport { ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM } from './steps.js';\nimport {\n buildSourceMapsUploadPrompt,\n SOURCE_MAPS_DETECTION_FAILED_PROMPT,\n} from './prompt.js';\nimport {\n SOURCE_MAPS_ABORT_CASES,\n SOURCE_MAPS_CONTEXT_KEYS,\n type SkillVariant,\n} from './detect.js';\nimport { getContentBlocks } from './content/index.js';\nimport { getUiHostFromHost } from '@utils/urls';\nimport { getUI } from '@ui';\n\nconst REPORT_FILE = 'posthog-source-maps-report.md';\nconst DOCS_URL = 'https://posthog.com/docs/error-tracking/upload-source-maps';\n\nexport const errorTrackingUploadSourceMapsConfig: ProgramConfig = {\n command: 'upload-source-maps',\n description: 'Upload source maps to PostHog Error Tracking',\n id: 'error-tracking-upload-source-maps',\n requiresAi: true,\n steps: ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM,\n reportFile: REPORT_FILE,\n getContentBlocks,\n requires: ['posthog-integration'],\n\n run: (_session: WizardSession): Promise<ProgramRun> => {\n // Read the picked project LIVE at prompt-build time, not here: the picker\n // screen runs AFTER this run config is resolved (post-auth), and the store\n // forks the session reference, so the `session` passed in never sees the\n // choice. getUI().getFrameworkContext reads the live store session.\n const readSelection = () => {\n const variant = getUI().getFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.selectedVariant,\n ) as SkillVariant | undefined;\n const displayName = getUI().getFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.selectedDisplayName,\n ) as string | undefined;\n const projectPath = getUI().getFrameworkContext(\n SOURCE_MAPS_CONTEXT_KEYS.selectedPath,\n ) as string | undefined;\n const skillId = variant\n ? `error-tracking-upload-source-maps-${variant}`\n : undefined;\n return { variant, displayName, projectPath, skillId };\n };\n\n return Promise.resolve({\n integrationLabel: 'error-tracking-upload-source-maps',\n // Skill is installed by the agent (after the API-key choice is made)\n // rather than pre-installed by the runner, so leave skillId unset.\n successMessage: 'Source maps wired up!',\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n spinnerMessage: 'Wiring up source maps...',\n estimatedDurationMinutes: 3,\n abortCases: SOURCE_MAPS_ABORT_CASES,\n // The flow parks on wizard_ask while the user does slow work — create\n // a personal API key in the browser (STEP 1), or run a production\n // build, trigger the test error, and check Error Tracking (STEP 8).\n // The 5-minute default cancels the question mid-task and the agent\n // wraps up to the outro, so give these answers half an hour.\n askTimeoutMs: 30 * 60 * 1000,\n\n customPrompt: (ctx) => {\n const { variant, displayName, projectPath, skillId } = readSelection();\n if (!skillId || !variant) {\n // No project was selected — abort with a structured signal so the\n // runner renders a friendly outro.\n return SOURCE_MAPS_DETECTION_FAILED_PROMPT;\n }\n\n const uiHost = getUiHostFromHost(ctx.host).replace(/\\/$/, '');\n\n return buildSourceMapsUploadPrompt({\n displayName,\n variant,\n skillId,\n projectPath,\n projectId: ctx.projectId,\n host: ctx.host,\n settingsUrl: `${uiHost}/project/${ctx.projectId}/settings/user-api-keys`,\n uiHost,\n });\n },\n\n postRun: () => {\n // Stash a hint for the outro about what variant we shipped.\n const { variant } = readSelection();\n if (variant) {\n getUI().setFrameworkContext('sourceMapsCompletedVariant', variant);\n }\n return Promise.resolve();\n },\n\n buildOutroData: () => {\n // SourceMapsOutroScreen renders static \"what we did + how it works\"\n // guidance, so no per-run `changes` list is needed here.\n return {\n kind: OutroKind.Success as const,\n message: 'Source maps wired up!',\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n };\n },\n });\n },\n};\n\nexport { ERROR_TRACKING_UPLOAD_SOURCE_MAPS_PROGRAM } from './steps.js';\nexport {\n detectSourceMapsPrerequisites,\n SOURCE_MAPS_ABORT_CASES,\n SOURCE_MAPS_CONTEXT_KEYS,\n VARIANT_DISPLAY_NAME,\n type SkillVariant,\n type SourceMapsDetectError,\n} from './detect.js';\n","/**\n * Self-driving prerequisite detection + abort vocabulary.\n *\n * The only thing worth verifying before auth is local and cheap: that\n * `session.installDir` is a real, readable directory. We deliberately do\n * NOT require the base posthog-integration report to be present — it is a\n * report many users never commit, and `requires: ['posthog-integration']`\n * is metadata, not a hard runtime gate. Real readiness (integration state\n * + beta access) is established by the agent's STEP 1 Signals API probe at\n * the start of the run. The beta gates (the `product-autonomy` access flag\n * and `signals-scout` enrollment — PostHog-side flag names, unchanged by\n * the wizard-side \"self-driving\" rename) are PostHog-internal flags with no\n * customer-facing read API, which is why that probe lives in the run and\n * emits a structured `[ABORT]` when the product is not available.\n */\n\nimport { existsSync, statSync } from 'fs';\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { AbortCase } from '@lib/agent/agent-runner';\n\n/**\n * Structured detection errors. The intro screen renders each kind into\n * JSX — keeps error data separate from presentation.\n */\nexport type SelfDrivingDetectError = {\n kind: 'bad-directory';\n path: string;\n reason: 'missing' | 'not-dir' | 'unreadable';\n};\n\n/**\n * `[ABORT] <reason>` cases the self-driving skill can emit. The\n * reason strings are part of the skill contract — the context-mill\n * `self-driving-setup` skill emits these exact strings.\n */\nexport const SELF_DRIVING_ABORT_CASES: AbortCase[] = [\n {\n // Skill emits: [ABORT] self-driving is not available for this project\n match: /^self-driving is not available for this project$/i,\n message: 'PostHog Self-driving is not available for this project',\n body:\n 'Self-driving is in beta and is enabled per ' +\n 'team by PostHog. This project does not appear to have access yet. ' +\n 'Reach out to your PostHog contact (or wizard@posthog.com) to join ' +\n 'the beta, then run the wizard again.',\n },\n {\n // Skill emits: [ABORT] github connection declined\n match: /^github connection declined$/i,\n message: 'GitHub connection required',\n body:\n 'Self-driving needs GitHub access to research issues in your code and ' +\n 'open fixes, so setup cannot finish without it. Nothing was left ' +\n 'half-configured. When you are ready to install the PostHog GitHub ' +\n 'App, run the wizard again.',\n },\n {\n // Skill emits: [ABORT] requires-interactive-mode\n match: /^requires-interactive-mode$/i,\n message: 'Interactive terminal required',\n body:\n 'Self-driving setup asks questions along the way (GitHub and ' +\n 'issue trackers), so it needs an interactive terminal. Run ' +\n 'the wizard outside CI / non-interactive mode.',\n },\n {\n // The wizard_ask tool's own error texts (non-interactive host, ask cap\n // reached) instruct the agent to emit this reason — cover it so those\n // paths render a friendly screen instead of the generic abort outro.\n match: /^requirements-incomplete$/i,\n message: 'Setup needs your input',\n body:\n 'The wizard could not collect the answers this setup needs (the ' +\n 'environment was non-interactive, or the question budget ran out). ' +\n 'Nothing was left half-configured. Run the wizard again in an ' +\n 'interactive terminal.',\n },\n];\n\n/**\n * Verify `session.installDir` is a readable directory. Writes a\n * `SelfDrivingDetectError` to frameworkContext on failure — the intro\n * screen renders it and blocks.\n */\nexport function detectSelfDrivingPrerequisites(\n session: WizardSession,\n setFrameworkContext: (key: string, value: unknown) => void,\n): void {\n const fail = (error: SelfDrivingDetectError) =>\n setFrameworkContext('detectError', error);\n\n const installDir = session.installDir;\n\n if (!existsSync(installDir)) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'missing' });\n return;\n }\n try {\n if (!statSync(installDir).isDirectory()) {\n fail({ kind: 'bad-directory', path: installDir, reason: 'not-dir' });\n return;\n }\n } catch {\n fail({ kind: 'bad-directory', path: installDir, reason: 'unreadable' });\n return;\n }\n}\n","/**\n * Self-driving program step list.\n *\n * detect → intro → health-check → auth → run → outro. No keep-skills\n * step: the setup skill is transient orchestration knowledge the user\n * won't reuse, so postRun removes it instead of prompting.\n */\n\nimport type { ProgramStep } from '@lib/programs/program-step';\nimport { RunPhase } from '@lib/wizard-session';\nimport { HEALTH_CHECK_STEP } from '@lib/programs/shared/health-check-step';\nimport { detectSelfDrivingPrerequisites } from './detect.js';\n\nexport const SELF_DRIVING_PROGRAM: ProgramStep[] = [\n {\n id: 'detect',\n label: 'Detecting prerequisites',\n // Headless step: no screen, no gate. onReady fires after bin.ts\n // assigns the session — verifies the PostHog setup report exists\n // and writes a detectError to frameworkContext for the intro\n // screen to render when it doesn't.\n onReady: (ctx) =>\n detectSelfDrivingPrerequisites(ctx.session, ctx.setFrameworkContext),\n },\n {\n id: 'intro',\n label: 'Welcome',\n screenId: 'self-driving-intro',\n gate: (session) => session.setupConfirmed,\n },\n HEALTH_CHECK_STEP,\n {\n id: 'auth',\n label: 'Authentication',\n screenId: 'auth',\n isComplete: (session) => session.credentials !== null,\n },\n {\n id: 'run',\n label: 'Self-driving',\n screenId: 'run',\n isComplete: (session) =>\n session.runPhase === RunPhase.Completed ||\n session.runPhase === RunPhase.Error,\n },\n {\n id: 'outro',\n label: 'Done',\n screenId: 'outro',\n isComplete: (session) => session.outroDismissed,\n },\n];\n","import { AgentSignals } from '@lib/agent/agent-interface';\nimport type { PromptContext } from '@lib/agent/agent-runner';\nimport { getUiHostFromHost } from '@utils/urls';\n\n/**\n * Build the self-driving run prompt. The installed\n * `self-driving-setup` skill is the source of truth for the HOW of\n * every step (which MCP tools to call, which sources/scouts apply, how\n * to verify); this prompt carries the order, the wizard-specific\n * mechanics (wizard_ask, abort signals), and the project URLs.\n */\nexport function buildSelfDrivingPrompt(ctx: PromptContext): string {\n const uiHost = getUiHostFromHost(ctx.host).replace(/\\/$/, '');\n const projectBase = `${uiHost}/project/${ctx.projectId}`;\n const integrationsSettingsUrl = `${projectBase}/settings/environment-integrations`;\n const orgAiSettingsUrl = `${uiHost}/settings/organization#organization-ai-consent`;\n const newWarehouseSourceUrl = `${projectBase}/pipeline/new/source`;\n const inboxUrl = `${projectBase}/inbox`;\n const optIn = (value: boolean | null | undefined): string =>\n value === true ? 'ON' : value === false ? 'OFF' : 'unknown';\n const optIns = ctx.teamProductOptIns;\n\n return `You are setting up PostHog Self-driving for this project: you will enable the right signal sources, make sure GitHub is connected, tune the scout troop, design custom scouts for what this product uniquely needs, and hand the user a configured inbox.\n\nProject URLs:\n- Integrations settings: ${integrationsSettingsUrl}\n- Organization AI settings: ${orgAiSettingsUrl}\n- New data warehouse source (Linear / Zendesk / GitHub issues / pganalyze): ${newWarehouseSourceUrl}\n- Self-driving inbox: ${inboxUrl}\n\nProject state read at auth time (PostHog project settings — authoritative\nfor whether a product is enabled, regardless of what this repo\ninstruments; products are often instrumented from other repos or the\nsnippet, so repo evidence may rule a product IN but never OUT):\n- Session replay recording: ${optIn(optIns?.sessionReplay)}\n- Exception autocapture (error tracking): ${optIn(optIns?.exceptionAutocapture)}\n- Surveys: ${optIn(optIns?.surveys)}\n\nThe installed skill is the source of truth for the HOW of every step:\nwhich MCP tools to call, which sources and scouts apply to this product,\nand how to verify each change. The STEPS below give the order and the\nwizard-specific mechanics — read the matching skill reference before\ndoing the work, and do not invent steps the skill doesn't describe.\n\nBefore doing any work, create your FULL task list in a single TaskCreate\ncall so the user can follow your progress in the TUI. Use exactly these\ntasks, in this order:\n 1. Check Self-driving access\n 2. Read project and current Self-driving state\n 3. Connect GitHub (required)\n 4. Enable signal sources\n 5. Offer issue-tracker integrations\n 6. Configure the scout troop\n 7. Design custom scouts\n 8. Write report and hand off\nDrive the list with TaskUpdate — mark a task in_progress when you start\nit and completed when done. If a step turns out to be a no-op (e.g.\nGitHub is already connected), still mark its task completed.\n\nWizard mechanics:\n- Ask the user things ONLY with the wizard_ask MCP tool, and batch\n related questions (e.g. one multi-select for all issue trackers, not\n one ask per tool). The per-run ask budget is limited.\n- If wizard_ask is unavailable (CI / non-interactive), emit\n ${AgentSignals.ABORT} requires-interactive-mode and halt.\n- When a step requires the user to do something in the browser, give\n them the exact URL inside the wizard_ask prompt text — do not try to\n open a browser yourself.\n- Emit ${AgentSignals.STATUS} lines as you complete each step so the\n user sees progress.\n\nFollow these steps IN ORDER. Do not skip or reorder.\n\nSTEP 1 — Check Self-driving access. (skill: \"Check access\")\n Probe the Signals API as the skill describes. If the API is not\n available for this project (permission or not-found errors), emit\n ${AgentSignals.ABORT} self-driving is not available for this project\n and halt.\n\nSTEP 2 — Read project and current Signals state. (skill: \"Read context\")\n If ./posthog-setup-report.md exists, read it as a strong hint for what\n THIS repo instruments — but it is often absent (users frequently don't\n commit it), so do NOT depend on it. Combine whatever you find with the\n project-state block above and the skill's server-side usage probes —\n repo evidence rules products in, never out. Do a light scan ONLY for\n what neither covers. List the currently enabled signal sources so every\n later write is idempotent.\n\nSTEP 3 — Connect GitHub. REQUIRED. (skill: \"Connect GitHub\")\n Signals cannot research or fix issues without code access. Check for\n an existing GitHub integration first; if absent, send the user\n through the GitHub App connection via wizard_ask exactly as the skill\n describes (it builds the one-click authorize link), and verify the\n connection after they confirm. If the user cannot connect now, emit\n ${AgentSignals.ABORT} github connection declined\n and halt — never finish setup without GitHub.\n\nSTEP 4 — Enable signal sources. (skill: \"Enable sources\")\n Enable the sources that match what this product actually uses, per\n the skill. Never enable a source for a tool the user hasn't\n confirmed they use.\n\nSTEP 5 — Offer issue-tracker integrations. (skill: \"Connected tools\")\n One batched multi-select wizard_ask for the external tools the skill\n lists. The run auto-connects the ones it can (GitHub Issues, and\n Linear via a one-click OAuth link), verifying each with a single\n silent check — never nudge. It arms the rest as dormant responders to\n finish later: for tools it can't auto-connect (Zendesk, pganalyze) it\n never sends the user to paste credentials and never re-prompts. Enable\n a source only for a tool the user picked.\n\nSTEP 6 — Configure the scout troop. (skill: \"Scouts\")\n Materialize the troop, then enable only a small set — the \"general\"\n scout plus the one or two specialists for the products this project\n uses most — and disable the rest, per the skill.\n\nSTEP 7 — Design custom scouts for this product. (skill: \"Custom scouts\")\n You are the only actor that has read this repo — turn that into\n coverage per the skill: a real gap analysis of the project's\n watchable surfaces against what the built-in troop already covers,\n then custom scouts for the uncovered ones. Keep scout bodies\n high-level: describe the behavior and signal conditions to watch,\n referencing repo evidence by file/function name — never paste raw\n source, secrets, env values, or customer data into a scout body.\n Never edit built-in scout bodies. Propose all candidates in ONE\n batched wizard_ask\n before creating anything; the user declining everything (or finding\n no gap at all) is a valid outcome, not an abort. Mark the task\n completed either way.\n\nSTEP 8 — Write the report and hand off. (skill: \"Report\")\n Write the report per the skill, including follow-ups for anything\n deferred. Tell the user findings will start appearing in their inbox\n at ${inboxUrl} within about 30 minutes.`;\n}\n","/**\n * Sidebar tips for the self-driving run. Unlike the generic\n * onboarding tips (`DEFAULT_TIPS`), these explain Signals' core nouns —\n * signal sources and scouts — in plain language, so the agent's\n * questions during the run land with a user who's never seen the terms.\n *\n * Product knowledge lives here in the program, not in the generic\n * `TipsCard`. Wired onto the program's `getTips`.\n */\n\nimport type { Tip } from '@ui/tui/components/TipsCard';\n\nexport const SELF_DRIVING_TIPS: Tip[] = [\n {\n id: 'what-is-a-signal-source',\n title: \"What's a signal source?\",\n description:\n 'A signal source is one of the streams PostHog plugs straight into — your errors, session replays, support, GitHub or Linear issues. Each one watches its own stream and speaks up the moment something specific goes wrong there.',\n },\n {\n id: 'what-is-a-scout',\n title: \"What's a scout?\",\n description:\n 'A scout is like an analyst PostHog runs for you on a schedule: rather than watching one stream, it ranges freely across your product data, looking for the bigger trends and surprises — a spike in errors, a funnel quietly dropping — that no single stream would catch.',\n },\n {\n id: 'findings-in-inbox',\n title: 'Findings land in your inbox',\n description:\n 'Once setup finishes, PostHog starts scanning within ~30 minutes and surfaces what it finds in your Self-driving inbox — grouped, researched, and ready to act on.',\n },\n];\n\nexport const getTips = (): Tip[] => SELF_DRIVING_TIPS;\n","import { join } from 'path';\nimport { access, rm } from 'node:fs/promises';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun } from '@lib/agent/agent-runner';\nimport { OutroKind } from '@lib/wizard-session';\nimport { getUiHostFromHost } from '@utils/urls';\nimport { createSkillProgram } from '../agent-skill/index.js';\nimport { getContentBlocks as agentSkillContentBlocks } from '../agent-skill/content/index.js';\nimport { SELF_DRIVING_PROGRAM } from './steps.js';\nimport { SELF_DRIVING_ABORT_CASES } from './detect.js';\nimport { buildSelfDrivingPrompt } from './prompt.js';\nimport { getTips } from './content/tips.js';\n\nexport const SELF_DRIVING_SKILL_ID = 'self-driving-setup';\nconst REPORT_FILE = 'posthog-self-driving-report.md';\nconst DOCS_URL = 'https://posthog.com/docs';\nconst SUCCESS_MESSAGE =\n 'Self-driving is on! PostHog will start scanning within ~30 minutes ' +\n 'and surface findings in your inbox.';\nconst WIZARD_MARKER = '.posthog-wizard';\n\n/**\n * Remove the installed setup skill. It is transient orchestration\n * knowledge (unlike integration skills such as the Next.js one, which\n * are worth keeping for the user's coding agents), so the program\n * cleans it up instead of showing the keep-skills prompt. Marker-\n * guarded: only directories the wizard installed are touched.\n */\nasync function removeInstalledSkill(installDir: string): Promise<void> {\n const skillDir = join(installDir, '.claude', 'skills', SELF_DRIVING_SKILL_ID);\n try {\n await access(join(skillDir, WIZARD_MARKER));\n } catch {\n return;\n }\n await rm(skillDir, { recursive: true, force: true }).catch(() => undefined);\n}\n\nconst run: ProgramRun = {\n skillId: SELF_DRIVING_SKILL_ID,\n integrationLabel: SELF_DRIVING_SKILL_ID,\n customPrompt: buildSelfDrivingPrompt,\n successMessage: SUCCESS_MESSAGE,\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n spinnerMessage: 'Setting up PostHog Self-driving...',\n estimatedDurationMinutes: 10,\n abortCases: SELF_DRIVING_ABORT_CASES,\n // The flow legitimately needs several interactions (GitHub connect +\n // verify, issue-tracker picks, the scout-tailoring proposal), so raise\n // the wizard_ask budget a little above the default 10.\n maxQuestions: 13,\n // This flow hands the user long OAuth/authorize URLs (Linear, GitHub\n // fallback, Zendesk) in wizard_ask prompts. Render them as OSC 8\n // hyperlinks + clipboard copy so the overlay's line wrapping can't break\n // the click target. Scoped to this program only.\n richLinks: true,\n // STEP 3 (GitHub App install) and STEP 5 (Linear OAuth) park on wizard_ask\n // while the user does slow browser work; a first-time GitHub App install\n // routinely exceeds the 5-min default, and a timeout is indistinguishable\n // from a decline (both resolve to __cancelled__). Match upload-source-maps.\n askTimeoutMs: 30 * 60 * 1000,\n\n // Emit a `wizard: step` analytics event on each agent task transition so we\n // can build a step-level drop-off funnel (where a run stops — GitHub connect,\n // scout enable, etc.), including silent steps with no wizard_ask. Opt-in, so\n // only self-driving runs emit these; every other program is unchanged.\n trackStepProgress: true,\n\n postRun: async (session) => {\n await removeInstalledSkill(session.installDir);\n },\n\n buildOutroData: (_session, credentials) => {\n const uiHost = getUiHostFromHost(credentials.host).replace(/\\/$/, '');\n const inboxUrl = `${uiHost}/project/${credentials.projectId}/inbox`;\n return {\n kind: OutroKind.Success as const,\n message:\n 'Self-driving is on. PostHog is scanning your project — ' +\n 'first findings hit your inbox within ~30 minutes.',\n primaryLink: { label: 'Your Self-driving inbox', url: inboxUrl },\n nextSteps: {\n heading: 'In your inbox you can:',\n items: [\n 'Review the findings PostHog surfaces',\n 'Triage what matters and dismiss the noise',\n 'Kick off fixes and open issues',\n ],\n },\n reportFile: REPORT_FILE,\n };\n },\n};\n\nexport const selfDrivingConfig: ProgramConfig = {\n ...createSkillProgram({\n skillId: SELF_DRIVING_SKILL_ID,\n command: 'self-driving',\n id: 'self-driving',\n description: 'Set up PostHog Self-driving for this project',\n integrationLabel: SELF_DRIVING_SKILL_ID,\n successMessage: SUCCESS_MESSAGE,\n reportFile: REPORT_FILE,\n docsUrl: DOCS_URL,\n spinnerMessage: 'Setting up PostHog Self-driving...',\n estimatedDurationMinutes: 10,\n requires: ['posthog-integration'],\n abortCases: SELF_DRIVING_ABORT_CASES,\n }),\n steps: SELF_DRIVING_PROGRAM,\n run,\n getTips,\n // The shared agent-skill Learn deck lingers ~60s on its last block before\n // RunScreen flips to the Self-driving Tips pane; shorten that final pause\n // so the scout/source/inbox tips appear promptly (the Tasks pane already\n // shows progress). Same deck, just a quicker hand-off.\n getContentBlocks: (store) => {\n const blocks = agentSkillContentBlocks(store);\n return blocks.map((b, i) =>\n i === blocks.length - 1 && typeof b === 'object'\n ? { ...b, pause: 5000 }\n : b,\n );\n },\n};\n\nexport { SELF_DRIVING_PROGRAM } from './steps.js';\nexport {\n detectSelfDrivingPrerequisites,\n SELF_DRIVING_ABORT_CASES,\n type SelfDrivingDetectError,\n} from './detect.js';\n","/**\n * MCP add / remove / tutorial programs.\n *\n * None of these run the agent pipeline — they're TUI-only flows invoked\n * by the `mcp add` / `mcp remove` / `mcp tutorial` subcommands in\n * bin.ts. They live in the program registry so the screen sequence is\n * derived alongside every other program (no special-cases in\n * screen-sequences.ts).\n */\n\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport { McpOutcome } from '@lib/wizard-session';\n\nexport const mcpAddConfig: ProgramConfig = {\n id: 'mcp-add',\n requiresAi: false,\n description: 'Add PostHog MCP server to supported clients',\n // Order: install → Slack → tutorial. Slack runs before the tutorial\n // because it renders gracefully without credentials (no surprise\n // OAuth on the loginless install path). The tutorial is last so its\n // explicit \"Start tutorial\" opt-in is the moment OAuth fires — and\n // skipping the tutorial doesn't bury Slack discovery behind a\n // dismissal screen.\n steps: [\n {\n id: 'mcp-add',\n label: 'Add MCP server',\n screenId: 'mcp-add',\n isComplete: (s) => s.mcpComplete,\n },\n {\n id: 'slack-connect',\n label: 'Connect Slack',\n screenId: 'slack-connect',\n // Gate on a successful install so no-clients / skipped / failed\n // outcomes go straight to program end without a \"what's next\" prompt.\n show: (s) => s.mcpOutcome === McpOutcome.Installed,\n isComplete: (s) => s.slackStepDismissed,\n },\n {\n id: 'mcp-suggested-prompts',\n label: 'Suggested prompts',\n screenId: 'mcp-suggested-prompts',\n // Same install gate — without a working MCP there's nothing to\n // talk to from the tutorial.\n show: (s) => s.mcpOutcome === McpOutcome.Installed,\n isComplete: (s) => s.mcpSuggestedPromptsDismissed,\n },\n ],\n};\n\n/**\n * `wizard mcp remove` — single-step uninstall flow.\n *\n * DO NOT append `mcp-suggested-prompts` (or any other tutorial-shaped\n * step) here. A user who just removed MCP is opting OUT of the agent having\n * access to PostHog; immediately pivoting into a tutorial that asks\n * them to log in and try prompts is wrong on intent and confusing on\n * UX. The screen also reads `session.mcpInstalledClients` for its\n * Choose-phase copy (\"MCP is installed for X\") — that array is empty\n * post-remove, so the copy would be a lie.\n *\n * If you want a \"did you mean to keep it?\" confirmation, build that as\n * a screen earlier in this program — don't reuse the tutorial.\n */\nexport const mcpRemoveConfig: ProgramConfig = {\n id: 'mcp-remove',\n requiresAi: false,\n description: 'Remove PostHog MCP server from supported clients',\n steps: [\n {\n id: 'mcp-remove',\n label: 'Remove MCP server',\n screenId: 'mcp-remove',\n isComplete: (s) => s.mcpComplete,\n },\n ],\n};\n\n/**\n * Standalone tutorial flow — boots directly into the Choose phase of\n * McpSuggestedPromptsScreen without going through MCP install first.\n * Useful for users who already installed MCP and want to revisit the\n * tutorial, or anyone who just wants to try the agent against PostHog\n * without touching their IDE config.\n *\n * The screen handles its own OAuth (via services.performLogin) so this\n * program doesn't pre-populate credentials.\n */\nexport const mcpTutorialConfig: ProgramConfig = {\n id: 'mcp-tutorial',\n requiresAi: false,\n description: 'Try the PostHog MCP with your agent — no install needed',\n steps: [\n {\n id: 'mcp-suggested-prompts',\n label: 'MCP tutorial',\n screenId: 'mcp-suggested-prompts',\n isComplete: (s) => s.mcpSuggestedPromptsDismissed,\n },\n {\n id: 'slack-connect',\n label: 'Connect Slack',\n screenId: 'slack-connect',\n isComplete: (s) => s.slackStepDismissed,\n },\n ],\n};\n","/**\n * Slack connect program — TUI-only flow invoked by `wizard slack`. One\n * step: the same Connect Slack screen the MCP flows end on. The screen\n * renders the no-creds nudge (marketing copy + \"Open Slack setup\" link);\n * we deliberately don't force OAuth here because connecting Slack itself\n * happens in the browser, so a wizard login adds nothing for the user.\n */\n\nimport type { ProgramConfig } from '@lib/programs/program-step';\n\nexport const slackConnectConfig: ProgramConfig = {\n id: 'slack',\n description: 'Connect PostHog to your Slack',\n steps: [\n {\n id: 'slack-connect',\n label: 'Connect Slack',\n screenId: 'slack-connect',\n isComplete: (s) => s.slackStepDismissed,\n },\n ],\n};\n","/**\n * Central registry of all wizard programs.\n *\n * Adding a new program:\n * 1. Create src/lib/programs/<name>/ with index.ts exporting a ProgramConfig\n * 2. Import and add it to PROGRAM_REGISTRY below\n * 3. (If custom intro screen) add to src/ui/tui/screen-registry.tsx\n *\n * screen-sequences.ts, store.ts, and bin.ts all derive their wiring from\n * this array — no need to touch those files when adding a program.\n */\n\nimport type { ProgramConfig } from './program-step.js';\nimport { POSTHOG_DOCS_URL } from '../constants.js';\nimport { posthogIntegrationConfig } from './posthog-integration/index.js';\nimport { revenueAnalyticsConfig } from './revenue-analytics/index.js';\nimport { warehouseSourceConfig } from './warehouse-source/index.js';\nimport { auditConfig } from './audit/index.js';\nimport { eventsAuditConfig } from './events-audit/index.js';\nimport { posthogDoctorConfig } from './posthog-doctor/index.js';\nimport { webAnalyticsDoctorConfig } from './web-analytics-doctor/index.js';\nimport { migrationConfig } from './migration/index.js';\nimport { errorTrackingUploadSourceMapsConfig } from './error-tracking-upload-source-maps/index.js';\nimport { selfDrivingConfig } from './self-driving/index.js';\nimport { AGENT_SKILL_STEPS } from './agent-skill/index.js';\nimport { getContentBlocks as agentSkillContentBlocks } from './agent-skill/content/index.js';\nimport {\n mcpAddConfig,\n mcpRemoveConfig,\n mcpTutorialConfig,\n} from './mcp/index.js';\nimport { slackConnectConfig } from './slack/index.js';\n\n// Generic skill program — runs an arbitrary context-mill skill chosen at\n// dispatch time (session.skillId) rather than a registered named program.\n// Backs `wizard skill <name>` and the narrow `audit` leaves (events,\n// feature-flags, identify, session-replay, autocapture); each injects its\n// skillId onto the config, which lands on session.skillId before the run.\n//\n// The `run` recipe is a function rather than a static block because the\n// skillId isn't known until dispatch. Without a `run` recipe the runner's\n// `skipAgent` guard (run-wizard.ts) fires and the skill never executes — so we\n// derive generic run metadata from the resolved skill id at run time.\nexport const agentSkillConfig: ProgramConfig = {\n id: 'agent-skill',\n description: 'Run an arbitrary context-mill skill',\n steps: AGENT_SKILL_STEPS,\n getContentBlocks: agentSkillContentBlocks,\n allowedTools: ['Agent'],\n run: (session) => {\n const skillId = session.skillId ?? 'agent-skill';\n return Promise.resolve({\n skillId,\n integrationLabel: skillId,\n spinnerMessage: `Running ${skillId}...`,\n successMessage: `${skillId} complete!`,\n estimatedDurationMinutes: 5,\n reportFile: `posthog-${skillId}-report.md`,\n docsUrl: POSTHOG_DOCS_URL,\n });\n },\n};\n\nexport const PROGRAM_REGISTRY = [\n posthogIntegrationConfig,\n revenueAnalyticsConfig,\n warehouseSourceConfig,\n errorTrackingUploadSourceMapsConfig,\n auditConfig,\n eventsAuditConfig,\n posthogDoctorConfig,\n webAnalyticsDoctorConfig,\n migrationConfig,\n selfDrivingConfig,\n agentSkillConfig,\n mcpAddConfig,\n mcpRemoveConfig,\n mcpTutorialConfig,\n slackConnectConfig,\n] as const satisfies readonly ProgramConfig[];\n\n/**\n * Typed program names. Values come from each config's `id`, so there's\n * no parallel string list to keep in sync — adding `Program.Foo` here is\n * just exposing `fooConfig.id` under a friendly name for call sites.\n */\nexport const Program = {\n PostHogIntegration: posthogIntegrationConfig.id,\n RevenueAnalyticsSetup: revenueAnalyticsConfig.id,\n WarehouseSource: warehouseSourceConfig.id,\n ErrorTrackingUploadSourceMaps: errorTrackingUploadSourceMapsConfig.id,\n Migration: migrationConfig.id,\n Audit: auditConfig.id,\n EventsAudit: eventsAuditConfig.id,\n PosthogDoctor: posthogDoctorConfig.id,\n WebAnalyticsDoctor: webAnalyticsDoctorConfig.id,\n SelfDriving: selfDrivingConfig.id,\n AgentSkill: agentSkillConfig.id,\n McpAdd: mcpAddConfig.id,\n McpRemove: mcpRemoveConfig.id,\n McpTutorial: mcpTutorialConfig.id,\n SlackConnect: slackConnectConfig.id,\n} as const;\n\n/** Compile-time union of every registered program id. */\nexport type ProgramId = (typeof PROGRAM_REGISTRY)[number]['id'];\n\n/**\n * Look up a program config by its id. `ProgramId` is a union of every\n * registered id, so the lookup is statically guaranteed to find a match\n * — the `!` is a load-bearing assertion of that invariant, not a hope.\n */\nexport function getProgramConfig(id: ProgramId): ProgramConfig {\n return PROGRAM_REGISTRY.find((c) => c.id === id)!;\n}\n\n/** A program config that is exposed as a CLI subcommand. */\nexport type SubcommandProgram = ProgramConfig & { command: string };\n\n/** All program configs that are exposed as CLI subcommands. */\nexport function getSubcommandPrograms(): SubcommandProgram[] {\n return PROGRAM_REGISTRY.filter(\n (c): c is SubcommandProgram => c.command != null,\n );\n}\n","import type { Arguments } from 'yargs';\nimport { setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { Program } from '@lib/programs/program-registry';\nimport { VERSION } from '@lib/version';\nimport type { Command } from '../command';\n\nexport const mcpAddCommand: Command = {\n name: 'add',\n description: 'Install PostHog MCP server to supported clients',\n options: {\n local: {\n default: false,\n describe: 'Add local development MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n features: {\n describe: 'Comma-separated list of features to enable (default: all)',\n type: 'string',\n },\n 'api-key': {\n describe: 'PostHog personal API key (phx_xxx) for MCP authentication',\n type: 'string',\n },\n },\n handler: runMcpAdd,\n};\n\nfunction runMcpAdd(argv: Arguments): void {\n const features = parseFeatures(argv.features);\n void (async () => {\n const { readApiKeyFromEnv } = await import('@utils/env-api-key');\n const apiKey = (argv.apiKey as string | undefined) || readApiKeyFromEnv();\n const debug = argv.debug as boolean | undefined;\n const localMcp = argv.local as boolean | undefined;\n\n try {\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession } = await import('@lib/wizard-session');\n const tui = startTUI(VERSION, Program.McpAdd);\n tui.store.session = buildSession({\n debug,\n localMcp,\n mcpFeatures: features,\n apiKey,\n });\n } catch (error) {\n if (!isTUIUnavailable(error)) throw error;\n setUI(new LoggingUI());\n const { addMCPServerToClientsStep } = await import(\n '@steps/add-mcp-server-to-clients/index'\n );\n await addMCPServerToClientsStep({ local: localMcp, features, apiKey });\n }\n })();\n}\n\n/**\n * Ink throws \"Raw mode is not supported\" when stdin has no TTY (piped input,\n * CI, some IDE terminals). That is the only TUI failure we degrade to\n * LoggingUI for — any other error from the TUI path is a real bug and must\n * surface rather than be silently swallowed.\n */\nfunction isTUIUnavailable(error: unknown): boolean {\n return (\n error instanceof Error && /raw mode is not supported/i.test(error.message)\n );\n}\n\nfunction parseFeatures(raw: unknown): string[] | undefined {\n if (typeof raw !== 'string') return undefined;\n return raw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean);\n}\n","import type { Arguments } from 'yargs';\nimport { setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { Program } from '@lib/programs/program-registry';\nimport { VERSION } from '@lib/version';\nimport type { Command } from '../command';\n\nexport const mcpRemoveCommand: Command = {\n name: 'remove',\n description: 'Remove PostHog MCP server from supported clients',\n options: {\n local: {\n default: false,\n describe: 'Remove local development MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n },\n handler: runMcpRemove,\n};\n\nfunction runMcpRemove(argv: Arguments): void {\n void (async () => {\n const debug = argv.debug as boolean | undefined;\n const localMcp = argv.local as boolean | undefined;\n\n try {\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession } = await import('@lib/wizard-session');\n const tui = startTUI(VERSION, Program.McpRemove);\n tui.store.session = buildSession({ debug, localMcp });\n } catch {\n setUI(new LoggingUI());\n const { removeMCPServerFromClientsStep } = await import(\n '@steps/add-mcp-server-to-clients/index'\n );\n await removeMCPServerFromClientsStep({ local: localMcp });\n }\n })();\n}\n","import type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { Program } from '@lib/programs/program-registry';\nimport { VERSION } from '@lib/version';\nimport type { Command } from '../command';\n\nexport const mcpTutorialCommand: Command = {\n name: 'tutorial',\n description: 'Try the PostHog MCP with your agent (no install needed)',\n options: {\n local: {\n default: false,\n describe:\n 'Point the tutorial at the local MCP server (http://localhost:8787)',\n type: 'boolean',\n },\n },\n handler: runMcpTutorial,\n};\n\nfunction runMcpTutorial(argv: Arguments): void {\n void (async () => {\n const debug = argv.debug as boolean | undefined;\n const localMcp = argv.local as boolean | undefined;\n\n try {\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession } = await import('@lib/wizard-session');\n const tui = startTUI(VERSION, Program.McpTutorial);\n tui.store.session = buildSession({ debug, localMcp });\n } catch (err) {\n // TUI unavailable — the tutorial has no headless fallback.\n setUI(new LoggingUI());\n getUI().log.error(\n `The MCP tutorial requires an interactive terminal. ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n process.exit(1);\n }\n })();\n}\n","import { mcpAddCommand } from './add';\nimport { mcpRemoveCommand } from './remove';\nimport { mcpTutorialCommand } from './tutorial';\nimport type { Command } from '../command';\n\nexport const mcpCommand: Command = {\n name: 'mcp',\n description: 'MCP server management commands',\n children: [mcpAddCommand, mcpRemoveCommand, mcpTutorialCommand],\n};\n","/**\n * `--no-telemetry` flips `telemetry: false` via yargs negation;\n * `POSTHOG_WIZARD_NO_TELEMETRY` is honoured separately so the env-var\n * form documented in the README keeps working.\n */\nexport function resolveNoTelemetry(options: Record<string, unknown>): boolean {\n if (options.telemetry === false) return true;\n const env = process.env.POSTHOG_WIZARD_NO_TELEMETRY;\n if (env == null || env === '') return false;\n const norm = env.toLowerCase();\n return norm !== '0' && norm !== 'false';\n}\n","import { VERSION } from '@lib/version';\nimport { logToFile, getLogFilePath } from '@utils/debug';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport type { startTUI as StartTUIFn } from '@ui/tui/start-tui';\nimport type { TaskStreamPush as TaskStreamPushClass } from '@lib/task-stream/task-stream-push';\nimport { resolveNoTelemetry } from './resolve-no-telemetry';\nimport { runCleanups } from '@utils/wizard-abort';\n\nconst WIZARD_VERSION = VERSION;\n\n/**\n * Run a full wizard program in the TUI. Handles the full lifecycle: start TUI,\n * build session, run detection, wait for intro gate, execute the\n * agent pipeline, wait for outro dismissal, then exit.\n */\nexport function runWizard(\n config: ProgramConfig,\n options: Record<string, unknown>,\n): void {\n let tui: ReturnType<typeof StartTUIFn> | null = null;\n let taskStream: TaskStreamPushClass | null = null;\n let onSignal: (() => void) | null = null;\n let exitInProgress = false;\n\n void (async () => {\n try {\n const installDir = (options.installDir as string) || process.cwd();\n\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession, RunPhase } = await import('@lib/wizard-session');\n const { TaskStreamPush } = await import('@lib/task-stream/index');\n const { PostHogDestination } = await import(\n '@lib/task-stream/destinations/posthog'\n );\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n tui = startTUI(WIZARD_VERSION, config.id as any);\n const activeTui = tui;\n\n const session = buildSession({\n debug: options.debug as boolean | undefined,\n localMcp: options.localMcp as boolean | undefined,\n installDir,\n ci: false,\n signup: options.signup as boolean | undefined,\n apiKey: options.apiKey as string | undefined,\n projectId: options.projectId as string | undefined,\n email: options.email as string | undefined,\n benchmark: options.benchmark as boolean | undefined,\n yaraReport: options.yaraReport as boolean | undefined,\n noTelemetry: resolveNoTelemetry(options),\n });\n session.programLabel = config.id;\n if (options.skillId) {\n session.skillId = options.skillId as string;\n } else if (config.skillId) {\n session.skillId = config.skillId;\n }\n\n activeTui.store.session = session;\n\n const taskStreamEnabled = !session.noTelemetry;\n taskStream = new TaskStreamPush({\n store: activeTui.store,\n programId: config.id,\n destinations: [\n new PostHogDestination({\n getCredentials: () => activeTui.store.session.credentials,\n onError: (err) => logToFile('[task-stream-push]', err.message),\n }),\n ],\n enabled: taskStreamEnabled,\n });\n const activeStream = taskStream;\n activeStream.attach();\n\n // Flush a terminal-phase push on Ctrl-C so the web app sees the\n // run ended in error rather than hanging on the last \"running\"\n // snapshot.\n let signalled = false;\n onSignal = (): void => {\n if (signalled || exitInProgress) return;\n signalled = true;\n logToFile('[run-wizard] signal received, flushing task stream');\n // Run cleanups synchronously first — settings restore is sync fs work\n // and must complete even if the stream shutdown below times out.\n runCleanups();\n if (activeTui.store.session.runPhase === RunPhase.Running) {\n activeTui.store.setRunPhase(RunPhase.Error);\n }\n void activeStream\n .shutdown(2000)\n .catch((e) =>\n logToFile('[run-wizard] task stream shutdown error on signal:', e),\n )\n .finally(() => {\n try {\n activeTui.unmount();\n } catch {\n // terminal may already be torn down\n }\n process.exit(130);\n });\n };\n process.on('SIGINT', onSignal);\n process.on('SIGTERM', onSignal);\n\n await activeTui.store.runReadyHooks();\n await activeTui.store.getGate('intro');\n await activeTui.store.getGate('health-check');\n\n const skipAgent = config.run == null;\n\n if (skipAgent) {\n const { getOrAskForProjectData } = await import('@utils/setup-utils');\n const { projectApiKey, host, accessToken, projectId } =\n await getOrAskForProjectData({\n signup: session.signup,\n ci: session.ci,\n apiKey: session.apiKey,\n projectId: session.projectId,\n programId: config.id,\n });\n activeTui.store.setCredentials({\n accessToken,\n projectApiKey,\n host,\n projectId,\n });\n } else {\n const { runAgent } = await import('@lib/agent/agent-runner');\n await runAgent(config, activeTui.store.session);\n }\n\n const isDone = (): boolean =>\n skipAgent\n ? activeTui.store.session.outroDismissed\n : activeTui.store.session.skillsComplete;\n\n await new Promise<void>((resolve) => {\n const unsub = activeTui.store.subscribe(() => {\n if (isDone()) {\n unsub();\n resolve();\n }\n });\n if (isDone()) {\n unsub();\n resolve();\n }\n });\n\n exitInProgress = true;\n await activeStream.shutdown(2000);\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n activeTui.unmount();\n process.exit(0);\n } catch (err) {\n // File-log first — the cleanup below can throw or exit.\n logToFile('[run-wizard] FATAL:', err);\n // Run cleanups before anything async so settings are restored even if\n // the stream shutdown hangs.\n runCleanups();\n // The task-stream debounce timer keeps the event loop alive, so\n // we have to drain it before exiting on the error path.\n exitInProgress = true;\n if (onSignal) {\n process.off('SIGINT', onSignal);\n process.off('SIGTERM', onSignal);\n }\n if (taskStream) {\n try {\n await taskStream.shutdown(2000);\n } catch {\n // ignore\n }\n }\n if (tui) {\n try {\n tui.unmount();\n } catch {\n // ignore\n }\n }\n // Print after unmount — anything printed into the alt screen is wiped.\n // eslint-disable-next-line no-console\n console.error('Wizard run failed:', err);\n // eslint-disable-next-line no-console\n console.error(`Full logs: ${getLogFilePath()}`);\n process.exit(1);\n }\n })();\n}\n","import { POSTHOG_DOCS_URL } from '@lib/constants';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport { analytics } from '@utils/analytics';\nimport { resolveNoTelemetry } from './resolve-no-telemetry';\n\n/**\n * The single CI validation layer: defaults region and requires api-key and\n * install-dir. Every CI entry point routes through `runWizardCI`, so this is\n * the one place these checks live. UI must be initialized before calling.\n */\nexport function validateCiOptions(options: Record<string, unknown>): void {\n if (!options.region) options.region = 'us';\n if (!options.apiKey) {\n getUI().intro('PostHog Wizard');\n getUI().log.error('CI mode requires --api-key (personal API key phx_xxx)');\n process.exit(1);\n }\n if (!options.installDir) {\n getUI().intro('PostHog Wizard');\n getUI().log.error(\n 'CI mode requires --install-dir (directory to install in)',\n );\n process.exit(1);\n }\n}\n\n/**\n * CI-mode pipeline shared by every non-interactive entry point.\n *\n * Validates flags, builds a `ci:true` session, runs `config.ciPreRun` (or the\n * program's `onReady` hooks by default), executes `runAgent`, and routes any\n * failure through `wizardAbort`. `wizardAbort` owns all exits — never add a\n * raw `process.exit` here.\n */\nexport function runWizardCI(\n config: ProgramConfig,\n options: Record<string, unknown>,\n): void {\n setUI(new LoggingUI());\n validateCiOptions(options);\n // Every CI entry point routes through here — upgrade the non-prod\n // build tag from 'dev' to 'ci'.\n analytics.setTag('build', 'ci');\n\n void (async () => {\n const path = await import('path');\n const { buildSession } = await import('@lib/wizard-session');\n const { readEnvironment } = await import('@utils/environment');\n const { readApiKeyFromEnv } = await import('@utils/env-api-key');\n const { configureLogFileFromEnvironment, logToFile } = await import(\n '@utils/debug'\n );\n const { wizardAbort, WizardError } = await import('@utils/wizard-abort');\n\n configureLogFileFromEnvironment();\n\n const env = readEnvironment();\n const apiKey =\n (options.apiKey as string) ?? readApiKeyFromEnv() ?? undefined;\n const installDir = path.isAbsolute(options.installDir as string)\n ? (options.installDir as string)\n : path.join(process.cwd(), options.installDir as string);\n\n const session = buildSession({\n debug: options.debug as boolean | undefined,\n installDir,\n ci: true,\n signup: options.signup as boolean | undefined,\n localMcp: options.localMcp as boolean | undefined,\n apiKey,\n email: options.email as string | undefined,\n projectId: options.projectId as string | undefined,\n benchmark: options.benchmark as boolean | undefined,\n yaraReport: options.yaraReport as boolean | undefined,\n noTelemetry: resolveNoTelemetry(options),\n ...env,\n });\n session.programLabel = config.id;\n if (config.skillId) {\n session.skillId = config.skillId;\n }\n const runDef = typeof config.run === 'object' ? config.run : null;\n\n getUI().intro('Welcome to the PostHog setup wizard');\n getUI().log.info(`Running ${config.id} in CI mode`);\n\n try {\n if (config.ciPreRun) {\n await config.ciPreRun(session);\n } else {\n const readyCtx = {\n session,\n setFrameworkContext: (key: string, value: unknown) => {\n session.frameworkContext[key] = value;\n },\n setFrameworkConfig: () => undefined,\n setDetectedFramework: () => undefined,\n // CI session is a plain object (no nanostore copy-on-write),\n // so direct assignment is safe here.\n setSkillId: (skillId: string | null) => {\n session.skillId = skillId;\n },\n setUnsupportedVersion: () => undefined,\n addDiscoveredFeature: () => undefined,\n setDetectionComplete: () => undefined,\n };\n for (const step of config.steps) {\n if (step.onReady) {\n await step.onReady(readyCtx);\n }\n }\n\n const detectError = session.frameworkContext.detectError as\n | { kind: string; [k: string]: unknown }\n | undefined;\n if (detectError) {\n await wizardAbort({\n message: `Prerequisites not met: ${detectError.kind}\\n\\nSee ${\n runDef?.docsUrl ?? POSTHOG_DOCS_URL\n }`,\n error: new WizardError(`${config.id} prerequisites failed`, {\n integration: config.id,\n detect_error_kind: detectError.kind,\n }),\n });\n }\n }\n\n const { runAgent } = await import('@lib/agent/agent-runner');\n await runAgent(config, session);\n } catch (error) {\n const errorMessage =\n error instanceof Error ? error.message : String(error);\n const errorStack =\n error instanceof Error && error.stack ? error.stack : undefined;\n\n logToFile(`[bin.ts CI] ERROR: ${errorMessage}`);\n if (errorStack) logToFile(`[bin.ts CI] STACK: ${errorStack}`);\n\n const debugInfo = session.debug && errorStack ? `\\n\\n${errorStack}` : '';\n const docsUrl =\n session.frameworkConfig?.metadata.docsUrl ??\n runDef?.docsUrl ??\n POSTHOG_DOCS_URL;\n await wizardAbort({\n message: `Something went wrong: ${errorMessage}\\n\\nYou can read the documentation at ${docsUrl} to set up manually.${debugInfo}`,\n error: error as Error,\n });\n }\n })().catch(() => {\n process.exit(1);\n });\n}\n","/**\n * Per-command options shared by every skill-based program command\n * (`audit events`, `migrate statsig`, `revenue`, `source-maps`, …).\n *\n * Only flags that are unique to skill commands live here. Global flags\n * (`--debug`, `--local-mcp`, `--benchmark`, `--yara-report`, `--ci`) are\n * declared once in `wizard.ts::GLOBAL_OPTIONS` and apply automatically\n * across every command — no need to repeat them per subcommand.\n */\nexport const skillProgramOptions = {\n 'install-dir': {\n describe: 'Directory to install in',\n type: 'string' as const,\n },\n};\n","import type { Arguments, Options } from 'yargs';\n\nimport { runWizard, runWizardCI } from '@lib/runners';\nimport type { ProgramConfig } from '@lib/programs/program-step';\n\nimport { skillProgramOptions } from '../skill-program-options';\n\n/**\n * Dispatch a parsed yargs invocation to the wizard runner. Applies the\n * program's `mapCliOptions` transform, then routes to `runWizard` or\n * `runWizardCI` based on the `--ci` flag.\n *\n * Every command file used to inline this; the factories call it instead.\n */\n/**\n * Run a command's async body as fire-and-forget while still surfacing failures.\n * yargs handlers are synchronous, so async work kicks off a detached promise —\n * without this, a rejection becomes an unhandled promise rejection (no message,\n * wrong exit code). This awaits the work and turns any error into a clean\n * message + non-zero exit.\n */\nexport function runCommandHandler(work: () => void | Promise<void>): void {\n void (async () => {\n try {\n await work();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n process.stderr.write(`\\n\\x1b[1;91m✖ ${msg}\\x1b[0m\\n\\n`);\n process.exit(1);\n }\n })();\n}\n\nexport function dispatchProgram(config: ProgramConfig, argv: Arguments): void {\n const argvRecord = argv as unknown as Record<string, unknown>;\n const extras = config.mapCliOptions?.(argvRecord) ?? {};\n const options = { ...argvRecord, ...extras };\n if (options.ci) {\n runWizardCI(config, options);\n } else {\n runWizard(config, options);\n }\n}\n\n/**\n * Merge the standard skill-program flags (`--debug`, `--install-dir`, etc.)\n * with any program-specific options declared on `cliOptions`.\n *\n * Program-specific options shadow the standard ones — that's intentional, so\n * a program can override a default flag if it ever needs to.\n */\nexport function mergeCommandOptions(\n config: ProgramConfig,\n): Record<string, Options> {\n return {\n ...skillProgramOptions,\n ...((config.cliOptions ?? {}) as Record<string, Options>),\n };\n}\n","import type { Arguments } from 'yargs';\n\nimport { auditConfig } from '@lib/programs/audit/index';\nimport { agentSkillConfig } from '@lib/programs/program-registry';\nimport { webAnalyticsDoctorConfig } from '@lib/programs/web-analytics-doctor/index';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport { getSkillsBaseUrl } from '@lib/constants';\nimport { fetchSkillMenu, type CliEntry } from '@lib/wizard-tools';\nimport { analytics } from '@utils/analytics';\n\nimport { dispatchProgram } from '../../commands/factories/shared';\nimport type { Command } from '../../commands/command';\n\n/**\n * Capture a CLI dispatch error, flush analytics, and exit. The wizard never\n * starts a run from these paths — use flush() (not shutdown()) so we don't\n * fire a \"setup wizard finished\" event for a parse error that didn't run.\n */\nasync function exitDispatchError(\n reason: string,\n properties: Record<string, unknown>,\n message: string,\n code = 1,\n): Promise<never> {\n analytics.wizardCapture('cli dispatch error', { reason, ...properties });\n try {\n await analytics.flush();\n } catch {\n /* flush is best-effort; never block the exit */\n }\n process.stderr.write(message);\n return process.exit(code);\n}\n\n/**\n * Family commands (`wizard audit`, `wizard migrate`, ...) resolve their\n * subcommands at runtime against the published `cliEntries` inside\n * `skill-menu.json`. Adding a subcommand is a context-mill release — no\n * wizard release needed.\n *\n * Wizard-native subcommands (programs that aren't backed by a single skill,\n * e.g. `wizard audit web-analytics`) live here in code, dispatched directly\n * without touching the registry. Adding a native is a wizard PR.\n */\n\n/** Wizard-native subcommands keyed by family. */\nconst NATIVE_HANDLERS: Record<string, Record<string, ProgramConfig>> = {\n audit: { 'web-analytics': webAnalyticsDoctorConfig },\n};\n\n/**\n * Resolve a fetched CliEntry to the ProgramConfig that actually runs it.\n * Most entries run via the generic agent-skill program with the entry's\n * `skillId` injected. The comprehensive `audit all` is the one exception —\n * skillId 'audit' triggers the specialized auditConfig (custom hooks,\n * content blocks, screens).\n */\nfunction configForCliEntry(entry: CliEntry): ProgramConfig {\n if (entry.skillId === 'audit') return auditConfig;\n return { ...agentSkillConfig, skillId: entry.skillId };\n}\n\nfunction familyEntries(family: string, entries: CliEntry[]): CliEntry[] {\n return entries.filter(\n (e) =>\n e.role === 'command' && e.parentCommand === family && Boolean(e.command),\n );\n}\n\n/**\n * Dispatch `wizard <family> <sub>` to the right program.\n *\n * Order:\n * 1. Native handler for (family, sub) — runs immediately, no network.\n * 2. Fetched CliEntry — runs the resolved skill.\n * 3. Unknown — prints the available list and exits non-zero.\n */\nexport async function dispatchFamily(\n family: string,\n argv: Arguments,\n): Promise<void> {\n const sub = (argv.skill as string | undefined)?.trim();\n if (!sub) {\n // Reached only in non-TTY/CI — an interactive terminal routes the no-sub\n // case to the picker before this runs, so don't suggest opening it here.\n return exitDispatchError(\n 'missing subcommand',\n { family },\n `\\n\\x1b[1;91m✖ \\`wizard ${family}\\` requires a subcommand.\\x1b[0m\\n` +\n ` Pass one (e.g. \\`wizard ${family} <subcommand>\\`), or run it in an interactive terminal to pick from a menu.\\n\\n`,\n );\n }\n\n const native = NATIVE_HANDLERS[family]?.[sub];\n if (native) {\n dispatchProgram(native, argv);\n return;\n }\n\n const skillsBaseUrl = getSkillsBaseUrl(Boolean(argv['local-mcp']));\n const menu = await fetchSkillMenu(skillsBaseUrl);\n if (!menu) {\n return exitDispatchError(\n 'registry unreachable',\n { family, sub, skillsBaseUrl },\n `\\n\\x1b[1;91m✖ Couldn't reach the skill registry at ${skillsBaseUrl}.\\x1b[0m\\n` +\n ` Check your network connection and try again.\\n\\n`,\n );\n }\n\n const entries = menu.cliEntries ?? [];\n const entry = familyEntries(family, entries).find((e) => e.command === sub);\n if (entry) {\n dispatchProgram(configForCliEntry(entry), argv);\n return;\n }\n\n const available = [\n ...Object.keys(NATIVE_HANDLERS[family] ?? {}),\n ...familyEntries(family, entries).map((e) => e.command!),\n ].sort();\n return exitDispatchError(\n 'unknown subcommand',\n { family, sub, available },\n `\\n\\x1b[1;91m✖ Unknown subcommand \"${sub}\" under \\`${family}\\`.\\x1b[0m\\n` +\n (available.length\n ? ` Available: ${available.join(', ')}\\n\\n`\n : ` No subcommands published for \"${family}\" yet.\\n\\n`),\n );\n}\n\n/**\n * Build the children list shown in the family's interactive picker.\n * Combines native handlers with skill-backed entries from the live registry.\n * Used by `familyCommandFactory`'s `interactiveDefault`.\n */\nexport function buildFamilyPickerChildren(\n family: string,\n entries: CliEntry[],\n): Command[] {\n const natives: Command[] = Object.entries(NATIVE_HANDLERS[family] ?? {}).map(\n ([cmd, program]) => ({\n name: cmd,\n description: program.description,\n handler: (argv: Arguments) => dispatchProgram(program, argv),\n }),\n );\n const live: Command[] = familyEntries(family, entries).map((entry) => ({\n name: entry.command!,\n description: entry.description,\n handler: (argv: Arguments) => {\n void dispatchFamily(family, {\n ...argv,\n skill: entry.command,\n } as Arguments);\n },\n default: entry.default,\n }));\n return [...natives, ...live];\n}\n\n/**\n * The children the family picker shows **today**: only the leaf marked\n * `default` (e.g. `audit events`). Every other subcommand stays runnable\n * directly (`wizard audit <name>`) — they just aren't listed in the picker yet.\n * Falls back to all children when nothing is marked `default`.\n *\n * Temporary: when we're ready to surface the full menu, return `children`\n * unchanged (and delete this note).\n */\nexport function pickerChildrenToShow(children: readonly Command[]): Command[] {\n const defaults = children.filter((c) => c.default);\n return defaults.length > 0 ? [...defaults] : [...children];\n}\n","/**\n * PromptLabel — Compact inline label for input prompts.\n *\n * Renders: [!] message\n * where [!] is black text on accent background.\n */\n\nimport { Box, Text } from 'ink';\nimport { Colors } from '@ui/tui/styles';\n\ninterface PromptLabelProps {\n message?: string;\n}\n\nexport const PromptLabel = ({ message }: PromptLabelProps) => {\n return (\n <Box>\n <Text bold color={Colors.accent}>\n {' '}\n {message}\n </Text>\n </Box>\n );\n};\n","/**\n * ConfirmButton — the confirm row used to submit a selection.\n *\n * Pure render. Multi-select menus (PickerMenu mode=\"multi\", GroupedPickerMenu)\n * append this below their options as the final focusable row: the user toggles\n * options with enter, then arrows down onto this row and presses enter to\n * submit. This replaces the older \"enter anywhere submits\" pattern, which\n * confused people who expected enter to toggle the focused item.\n *\n * Renders flat, mirroring the option rows — a focus triangle and the label,\n * accent and bold when focused, dimmed otherwise — so it lines up under the\n * options instead of sitting in a separate boxed target.\n */\n\nimport { Text } from 'ink';\nimport { Icons, Colors } from '@ui/tui/styles';\n\ninterface ConfirmButtonProps {\n /** Button text. Defaults to \"Confirm\". */\n label?: string;\n /** Whether the cursor is currently on the button. */\n focused: boolean;\n /** Optional selected-item count, rendered as \"Label (n)\" when > 0. */\n count?: number;\n}\n\nexport const ConfirmButton = ({\n label = 'Confirm',\n focused,\n count,\n}: ConfirmButtonProps) => {\n const text = count && count > 0 ? `${label} (${count})` : label;\n return (\n <Text\n color={focused ? Colors.accent : undefined}\n bold={focused}\n dimColor={!focused}\n >\n {focused ? Icons.triangleSmallRight : ' '} {text}\n </Text>\n );\n};\n","/**\n * Pure utility functions for keyboard hints — no React or Ink dependencies.\n * Extracted for testability in a node Jest environment.\n */\n\nexport interface KeyboardHint {\n label: string;\n action: string;\n priority: number;\n}\n\n/** Well-known key matches corresponding to Ink's key.* properties. */\nexport enum KeyMatch {\n UpArrow = 'upArrow',\n DownArrow = 'downArrow',\n LeftArrow = 'leftArrow',\n RightArrow = 'rightArrow',\n Return = 'return',\n Escape = 'escape',\n Space = 'space',\n}\n\n/** A key match: either a KeyMatch enum value or a literal character string (e.g. 'a', 's'). */\nexport type KeyMatchOrChar = KeyMatch | (string & NonNullable<unknown>);\n\n/** Default priorities by key type. */\nconst DEFAULT_PRIORITY: Record<string, number> = {\n [KeyMatch.UpArrow]: 0,\n [KeyMatch.DownArrow]: 0,\n [KeyMatch.LeftArrow]: 1,\n [KeyMatch.RightArrow]: 1,\n [KeyMatch.Space]: 10,\n [KeyMatch.Escape]: 20,\n [KeyMatch.Return]: 21,\n};\n\n/** Get the default display priority for a key match. */\nexport function getDefaultPriority(\n match: KeyMatchOrChar | KeyMatchOrChar[],\n): number {\n const first = Array.isArray(match) ? match[0] : match;\n return DEFAULT_PRIORITY[first] ?? 15;\n}\n\n/** Check if a KeyMatchOrChar matches the given input string and key flags. */\nexport function matchesKey(\n m: KeyMatchOrChar,\n input: string,\n key: { [k: string]: unknown },\n): boolean {\n switch (m) {\n case KeyMatch.UpArrow:\n return !!key.upArrow;\n case KeyMatch.DownArrow:\n return !!key.downArrow;\n case KeyMatch.LeftArrow:\n return !!key.leftArrow;\n case KeyMatch.RightArrow:\n return !!key.rightArrow;\n case KeyMatch.Return:\n return !!key.return;\n case KeyMatch.Escape:\n return !!key.escape;\n case KeyMatch.Space:\n return input === ' ';\n default:\n return input === m;\n }\n}\n\n/** Serialize hints for comparison. */\nexport function hintsKey(hints: KeyboardHint[]): string {\n return hints.map((h) => `${h.label}:${h.action}`).join('|');\n}\n\n/** Deduplicate hints by label+action and sort by priority. */\nexport function deduplicateAndSort(hints: KeyboardHint[]): KeyboardHint[] {\n const seen = new Set<string>();\n const deduped: KeyboardHint[] = [];\n for (const hint of hints) {\n const k = `${hint.label}:${hint.action}`;\n if (!seen.has(k)) {\n seen.add(k);\n deduped.push(hint);\n }\n }\n deduped.sort((a, b) => a.priority - b.priority);\n return deduped;\n}\n","/**\n * KeyboardHintsProvider — Context for collecting and displaying keyboard hints.\n *\n * Input components register their hints via useKeyBindings. The provider\n * flattens, deduplicates, and sorts them. The hints bar stays visible for as\n * long as a screen has registered hints — it never auto-dismisses.\n */\n\nimport {\n createContext,\n useCallback,\n useContext,\n useRef,\n useState,\n type ReactNode,\n} from 'react';\nimport {\n hintsKey,\n deduplicateAndSort,\n type KeyboardHint,\n} from './keyboard-hints-utils.js';\n\nexport type { KeyboardHint } from './keyboard-hints-utils.js';\n\ninterface KeyboardHintsContextValue {\n register(id: string, hints: KeyboardHint[]): void;\n unregister(id: string): void;\n hints: KeyboardHint[];\n}\n\nconst KeyboardHintsContext = createContext<KeyboardHintsContextValue>({\n register: () => undefined,\n unregister: () => undefined,\n hints: [],\n});\n\nexport const useKeyboardHintsContext = () => useContext(KeyboardHintsContext);\n\nexport const KeyboardHintsProvider = ({\n children,\n}: {\n children: ReactNode;\n}) => {\n const registrationsRef = useRef(new Map<string, KeyboardHint[]>());\n const [hints, setHints] = useState<KeyboardHint[]>([]);\n const prevHintsKeyRef = useRef('');\n\n const recompute = useCallback(() => {\n const all: KeyboardHint[] = [];\n for (const h of registrationsRef.current.values()) {\n all.push(...h);\n }\n const deduped = deduplicateAndSort(all);\n\n const newKey = hintsKey(deduped);\n if (newKey !== prevHintsKeyRef.current) {\n prevHintsKeyRef.current = newKey;\n setHints(deduped);\n }\n }, []);\n\n const register = useCallback(\n (id: string, h: KeyboardHint[]) => {\n registrationsRef.current.set(id, h);\n recompute();\n },\n [recompute],\n );\n\n const unregister = useCallback(\n (id: string) => {\n registrationsRef.current.delete(id);\n recompute();\n },\n [recompute],\n );\n\n return (\n <KeyboardHintsContext.Provider value={{ register, unregister, hints }}>\n {children}\n </KeyboardHintsContext.Provider>\n );\n};\n","/**\n * useKeyBindings — Declarative keyboard input + automatic hint registration.\n *\n * Replaces raw `useInput` in input components. Define bindings as data;\n * the hook wires up the Ink input handler AND registers hints in the\n * KeyboardHintsProvider. One source of truth for keys and their labels.\n */\n\nimport { useInput, type Key } from 'ink';\nimport { useEffect, useRef } from 'react';\nimport { useKeyboardHintsContext } from './useKeyboardHints.js';\nimport {\n matchesKey,\n getDefaultPriority,\n KeyMatch,\n type KeyboardHint,\n type KeyMatchOrChar,\n} from './keyboard-hints-utils.js';\n\nexport { KeyMatch };\nexport type { KeyMatchOrChar } from './keyboard-hints-utils.js';\n\nexport interface KeyBinding {\n /** Which key(s) trigger this binding. Array = multiple keys, one hint. */\n match: KeyMatchOrChar | KeyMatchOrChar[];\n /** Display label in hints bar (e.g. \"↑↓\", \"space\", \"enter\") */\n label: string;\n /** Description in hints bar (e.g. \"navigate\", \"toggle\") */\n action: string;\n /** Ordering priority (lower = further left). Defaults based on key type. */\n priority?: number;\n /** Handler called when the key matches. */\n handler: (input: string, key: Key) => void;\n}\n\n/**\n * Declarative key bindings hook. Replaces `useInput` in input components.\n * Registers hints automatically with the KeyboardHintsProvider.\n *\n * @param id Unique identifier for this component's hints registration\n * @param bindings Array of key binding definitions\n */\nexport function useKeyBindings(id: string, bindings: KeyBinding[]): void {\n const ctx = useKeyboardHintsContext();\n\n // Extract hints and register. Use a serialized key to avoid unnecessary updates.\n const hintsRef = useRef<string>('');\n const hints: KeyboardHint[] = bindings.map((b) => ({\n label: b.label,\n action: b.action,\n priority: b.priority ?? getDefaultPriority(b.match),\n }));\n const serialized = hints\n .map((h) => `${h.label}:${h.action}:${h.priority}`)\n .join('|');\n\n useEffect(() => {\n if (serialized !== hintsRef.current) {\n hintsRef.current = serialized;\n ctx.register(id, hints);\n }\n return () => ctx.unregister(id);\n // eslint-disable-next-line\n }, [id, serialized]);\n\n // Wire up input handling\n useInput((input, key) => {\n for (const binding of bindings) {\n const matches = Array.isArray(binding.match)\n ? binding.match\n : [binding.match];\n if (matches.some((m) => matchesKey(m, input, key))) {\n binding.handler(input, key);\n return;\n }\n }\n });\n}\n","/**\n * PickerMenu — Single and multi select.\n * Single mode: custom renderer with small triangle indicator; enter selects.\n * Multi mode: checkbox glyphs toggled with enter, plus a focusable\n * Confirm button below the options. The cursor moves onto the button and\n * enter submits — see MultiPickerMenu for the rationale.\n *\n * Key bindings are declared via useKeyBindings, which auto-registers\n * hints in the KeyboardHintsBar.\n */\n\nimport { Box, Text } from 'ink';\nimport { useEffect, useState } from 'react';\nimport { Icons, Colors } from '@ui/tui/styles';\nimport { PromptLabel } from './PromptLabel.js';\nimport { ConfirmButton } from './ConfirmButton.js';\nimport {\n useKeyBindings,\n KeyMatch,\n type KeyBinding,\n} from '@ui/tui/hooks/useKeyBindings';\n\ninterface PickerOption<T> {\n label: string;\n value: T;\n hint?: string;\n /**\n * Multi-select only: a secondary explanation rendered dimmed and wrapped on\n * its own line(s) beneath the label, for choices that need more than a title.\n * When unset, the row renders exactly as a label-only row.\n */\n description?: string;\n /** Glyph rendered before the label, in its own color — unaffected by\n * focus and disabled styling. */\n icon?: { glyph: string; color?: string };\n /** Dimmed and unselectable; navigation skips over it. */\n disabled?: boolean;\n /**\n * Multi-select only: marks this option mutually exclusive with every other\n * option. Selecting it clears all other picks; selecting any non-exclusive\n * option clears it. Used e.g. for a browser connector that can't be\n * installed alongside local editors.\n */\n exclusive?: boolean;\n}\n\n/**\n * Step through a column's options in `dir`, wrapping, until an enabled\n * option is found. Returns `from` unchanged if the column is entirely\n * disabled.\n */\nfunction stepEnabled<T>(\n options: PickerOption<T>[],\n rows: number,\n from: number,\n dir: 1 | -1,\n): number {\n const col = Math.floor(from / rows);\n const colStart = col * rows;\n const colLen = Math.min(rows, options.length - colStart);\n let row = from % rows;\n for (let i = 0; i < colLen; i++) {\n row = (row + dir + colLen) % colLen;\n const idx = colStart + row;\n if (!options[idx]?.disabled) return idx;\n }\n return from;\n}\n\n/** Index of the first enabled option, for the initial focus. */\nfunction firstEnabled<T>(options: PickerOption<T>[]): number {\n const idx = options.findIndex((o) => !o.disabled);\n return idx === -1 ? 0 : idx;\n}\n\n/** Index of the last enabled option, for wrapping from the button onto\n * the bottom of the grid. */\nfunction lastEnabled<T>(options: PickerOption<T>[]): number {\n for (let i = options.length - 1; i >= 0; i--) {\n if (!options[i]?.disabled) return i;\n }\n return options.length - 1;\n}\n\ninterface PickerMenuProps<T> {\n message?: string;\n options: PickerOption<T>[];\n mode?: 'single' | 'multi';\n centered?: boolean;\n columns?: 1 | 2 | 3 | 4;\n /**\n * Vertical space between options, in TUI rows. Defaults to 0 — i.e.\n * options stack tightly. Set to 1+ when the option labels are long\n * (wrap across multiple lines) or for visual breathing room.\n */\n optionMarginBottom?: number;\n onSelect: (value: T | T[]) => void;\n}\n\nexport const PickerMenu = <T,>({\n message,\n options,\n mode = 'single',\n centered = false,\n columns = 1,\n optionMarginBottom = 0,\n onSelect,\n}: PickerMenuProps<T>) => {\n if (mode === 'multi') {\n return (\n <MultiPickerMenu\n message={message}\n options={options}\n centered={centered}\n columns={columns}\n optionMarginBottom={optionMarginBottom}\n onSelect={onSelect}\n />\n );\n }\n\n return (\n <SinglePickerMenu\n message={message}\n options={options}\n centered={centered}\n columns={columns}\n optionMarginBottom={optionMarginBottom}\n onSelect={onSelect}\n />\n );\n};\n\n/** Custom single-select with triangle indicator and accent highlight. */\nconst SinglePickerMenu = <T,>({\n message,\n options,\n centered = false,\n columns = 1,\n optionMarginBottom = 0,\n onSelect,\n}: {\n message?: string;\n options: PickerOption<T>[];\n centered?: boolean;\n columns?: number;\n optionMarginBottom?: number;\n onSelect: (value: T | T[]) => void;\n}) => {\n const [focused, setFocused] = useState(() => firstEnabled(options));\n const rows = Math.ceil(options.length / columns);\n\n // Re-validate focus when the options change while mounted \\u2014 a list\n // that shrinks or disables entries can leave `focused` pointing at a\n // missing or disabled option, which would make enter a no-op.\n useEffect(() => {\n if (focused >= options.length || options[focused]?.disabled) {\n setFocused(firstEnabled(options));\n }\n }, [options, focused]);\n\n const bindings: KeyBinding[] = [\n {\n match: [KeyMatch.UpArrow, KeyMatch.DownArrow],\n label: '\\u2191\\u2193',\n action: 'navigate',\n handler: (_input, key) => {\n if (key.upArrow) {\n setFocused(stepEnabled(options, rows, focused, -1));\n }\n if (key.downArrow) {\n setFocused(stepEnabled(options, rows, focused, 1));\n }\n },\n },\n {\n match: KeyMatch.Return,\n label: 'enter',\n action: 'select',\n handler: () => {\n const selected = options[focused];\n if (selected && !selected.disabled) {\n onSelect(selected.value);\n }\n },\n },\n ];\n\n if (columns > 1) {\n bindings.splice(1, 0, {\n match: [KeyMatch.LeftArrow, KeyMatch.RightArrow],\n label: '\\u2190\\u2192',\n action: 'navigate',\n handler: (_input, key) => {\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n\n let next = focused;\n if (key.leftArrow) {\n const prevCol = col > 0 ? col - 1 : columns - 1;\n next = Math.min(prevCol * rows + row, options.length - 1);\n }\n if (key.rightArrow) {\n const nextCol = col < columns - 1 ? col + 1 : 0;\n next = Math.min(nextCol * rows + row, options.length - 1);\n }\n // Landing on a disabled option slides to the column's nearest\n // enabled one.\n if (options[next]?.disabled) {\n next = stepEnabled(options, rows, next, 1);\n }\n setFocused(next);\n },\n });\n }\n\n useKeyBindings('single-picker', bindings);\n\n // Chunk options into columns (column-first ordering)\n const columnArrays: PickerOption<T>[][] = [];\n for (let c = 0; c < columns; c++) {\n columnArrays.push(options.slice(c * rows, c * rows + rows));\n }\n\n const align = centered ? 'center' : undefined;\n\n return (\n <Box flexDirection=\"column\" alignItems={align}>\n <PromptLabel message={message} />\n <Box flexDirection=\"row\" gap={4}>\n {columnArrays.map((colOpts, colIdx) => (\n <Box key={colIdx} flexDirection=\"column\">\n {colOpts.map((opt, rowIdx) => {\n const flatIdx = colIdx * rows + rowIdx;\n const isFocused = flatIdx === focused;\n const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;\n return (\n <Box key={flatIdx} gap={1} marginBottom={optionMarginBottom}>\n <Text\n color={isFocused ? Colors.accent : undefined}\n dimColor={!isFocused}\n >\n {isFocused ? Icons.triangleSmallRight : ' '}\n </Text>\n {opt.icon && (\n <Text color={opt.icon.color}>{opt.icon.glyph}</Text>\n )}\n <Text\n color={\n opt.disabled\n ? Colors.muted\n : isFocused\n ? Colors.accent\n : undefined\n }\n bold={isFocused && !opt.disabled}\n dimColor={!isFocused || opt.disabled}\n >\n {label}\n </Text>\n </Box>\n );\n })}\n </Box>\n ))}\n </Box>\n </Box>\n );\n};\n\n/**\n * Custom multi-select with checkbox glyphs and accent highlight.\n *\n * Interaction model (shared with GroupedPickerMenu):\n * - \\u2191\\u2193 move the cursor through the options AND onto the Confirm button,\n * which lives just past the last option.\n * - enter toggles the focused option (no more \"space toggles but enter\n * advances\" split that tripped people up). Space is kept as an\n * undocumented alias, but the hints bar advertises only enter.\n * - moving onto the Confirm button and pressing enter submits the\n * current selection.\n */\nconst MultiPickerMenu = <T,>({\n message,\n options,\n centered = false,\n columns = 1,\n optionMarginBottom = 0,\n onSelect,\n}: {\n message?: string;\n options: PickerOption<T>[];\n centered?: boolean;\n columns?: number;\n optionMarginBottom?: number;\n onSelect: (value: T | T[]) => void;\n}) => {\n const [focused, setFocused] = useState(() => firstEnabled(options));\n // When true, the cursor is on the Confirm button rather than an option.\n const [onButton, setOnButton] = useState(false);\n const [selected, setSelected] = useState<Set<number>>(new Set());\n const rows = Math.ceil(options.length / columns);\n\n // Re-validate focus when the options change while mounted — a list\n // that shrinks or disables entries can leave `focused` pointing at a\n // missing or disabled option, which would make enter a no-op.\n useEffect(() => {\n if (focused >= options.length || options[focused]?.disabled) {\n setFocused(firstEnabled(options));\n }\n }, [options, focused]);\n\n const confirm = () => {\n const values = [...selected]\n .sort((a, b) => a - b)\n .map((i) => options[i].value);\n onSelect(values);\n };\n\n const bindings: KeyBinding[] = [\n {\n match: [KeyMatch.UpArrow, KeyMatch.DownArrow],\n label: '\\u2191\\u2193',\n action: 'navigate',\n handler: (_input, key) => {\n if (key.upArrow) {\n if (onButton) {\n // Button \\u2192 bottom of the grid (last enabled option).\n setOnButton(false);\n setFocused(lastEnabled(options));\n return;\n }\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n // Nearest enabled option above in this column.\n let r = row - 1;\n while (r >= 0 && options[col * rows + r]?.disabled) r--;\n if (r >= 0) {\n setFocused(col * rows + r);\n } else {\n // Top of the column \\u2192 wrap up onto the button.\n setOnButton(true);\n }\n }\n if (key.downArrow) {\n if (onButton) {\n // Button \\u2192 top of the grid (first enabled option).\n setOnButton(false);\n setFocused(firstEnabled(options));\n return;\n }\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n const colLen = Math.min(rows, options.length - col * rows);\n // Nearest enabled option below in this column.\n let r = row + 1;\n while (r < colLen && options[col * rows + r]?.disabled) r++;\n if (r < colLen) {\n setFocused(col * rows + r);\n } else {\n // Bottom of the column \\u2192 down onto the button.\n setOnButton(true);\n }\n }\n },\n },\n {\n match: [KeyMatch.Space, KeyMatch.Return],\n label: 'enter',\n action: 'select',\n handler: () => {\n if (onButton) {\n confirm();\n return;\n }\n if (options[focused]?.disabled) return;\n setSelected((prev) => {\n const next = new Set(prev);\n if (next.has(focused)) {\n next.delete(focused);\n return next;\n }\n // Enforce mutual exclusivity: an exclusive option clears every other\n // pick; any other option clears previously-picked exclusive ones.\n if (options[focused]?.exclusive) {\n return new Set([focused]);\n }\n for (const i of next) {\n if (options[i]?.exclusive) {\n next.delete(i);\n }\n }\n next.add(focused);\n return next;\n });\n },\n },\n ];\n\n if (columns > 1) {\n bindings.splice(1, 0, {\n match: [KeyMatch.LeftArrow, KeyMatch.RightArrow],\n label: '\\u2190\\u2192',\n action: 'navigate',\n handler: (_input, key) => {\n if (onButton) return;\n const col = Math.floor(focused / rows);\n const row = focused % rows;\n\n let next = focused;\n if (key.leftArrow) {\n const prevCol = col > 0 ? col - 1 : columns - 1;\n next = Math.min(prevCol * rows + row, options.length - 1);\n }\n if (key.rightArrow) {\n const nextCol = col < columns - 1 ? col + 1 : 0;\n next = Math.min(nextCol * rows + row, options.length - 1);\n }\n // Landing on a disabled option slides to the column's nearest\n // enabled one.\n if (options[next]?.disabled) {\n next = stepEnabled(options, rows, next, 1);\n }\n setFocused(next);\n },\n });\n }\n\n useKeyBindings('multi-picker', bindings);\n\n const columnArrays: PickerOption<T>[][] = [];\n for (let c = 0; c < columns; c++) {\n columnArrays.push(options.slice(c * rows, c * rows + rows));\n }\n\n return (\n <Box flexDirection=\"column\" alignItems={centered ? 'center' : undefined}>\n <PromptLabel message={message} />\n <Box\n flexDirection=\"row\"\n gap={4}\n marginLeft={centered ? 0 : 2}\n marginTop={1}\n >\n {columnArrays.map((colOpts, colIdx) => (\n <Box key={colIdx} flexDirection=\"column\">\n {colOpts.map((opt, rowIdx) => {\n const flatIdx = colIdx * rows + rowIdx;\n const isFocused = !onButton && flatIdx === focused;\n const isSelected = selected.has(flatIdx);\n const label = opt.hint ? `${opt.label} (${opt.hint})` : opt.label;\n const checkbox = isSelected\n ? Icons.squareFilled\n : Icons.squareOpen;\n return (\n <Box\n key={flatIdx}\n flexDirection=\"column\"\n marginBottom={optionMarginBottom}\n >\n <Box gap={1}>\n <Text\n color={isSelected ? 'white' : Colors.muted}\n dimColor={!isFocused && !isSelected}\n >\n {checkbox}\n </Text>\n {opt.icon && (\n <Text color={opt.icon.color}>{opt.icon.glyph}</Text>\n )}\n <Text\n color={\n opt.disabled\n ? Colors.muted\n : isFocused\n ? Colors.accent\n : undefined\n }\n bold={isFocused && !opt.disabled}\n dimColor={!isFocused || opt.disabled}\n >\n {label}\n </Text>\n </Box>\n {/* Optional dimmed, wrapped explanation under the label. The\n explicit width forces Ink to wrap (an unconstrained Box\n shrinks to its content and never wraps). Renders only when\n set, so label-only rows are byte-for-byte unchanged. */}\n {opt.description && (\n <Box marginLeft={4} width={56}>\n <Text dimColor wrap=\"wrap\">\n {opt.description}\n </Text>\n </Box>\n )}\n </Box>\n );\n })}\n </Box>\n ))}\n </Box>\n <Box marginTop={1} marginLeft={centered ? 0 : 2}>\n <ConfirmButton focused={onButton} count={selected.size} />\n </Box>\n </Box>\n );\n};\n","/**\n * Mount an Ink picker over a command's `children` and dispatch the\n * selected child's handler.\n *\n * Used as the `interactiveDefault` for family parents like\n * `wizard audit` — when the user invokes the parent without a leaf, this\n * shows a TUI menu instead of yargs's `demandCommand(1)` help dump.\n *\n * The picker opens when a family surfaces more than one option; the `default`\n * flag controls which one is pre-highlighted. When a family surfaces a single\n * option (today `audit` → `events`), `familyCommandFactory` runs it directly\n * instead, so the user lands on its intro screen rather than a one-item menu.\n *\n * Single-option commands aren't families — they should be flat\n * commands wired with `skillCommandFactory` / `nativeCommandFactory`\n * directly, not run through this module.\n */\n\nimport type { Arguments } from 'yargs';\nimport { Box, Text, render } from 'ink';\nimport { createElement } from 'react';\n\nimport { Colors } from '@ui/tui/styles';\nimport { PickerMenu } from '@ui/tui/primitives/PickerMenu';\n\nimport { commandKeys, type Command } from '../command';\n\ninterface FamilyPickerAppProps {\n parentLabel: string;\n options: { label: string; value: Command; hint?: string }[];\n onSelect: (cmd: Command) => void;\n}\n\nfunction FamilyPickerApp(props: FamilyPickerAppProps) {\n return createElement(\n Box,\n { flexDirection: 'column', paddingX: 1, paddingY: 1 },\n createElement(\n Text,\n { bold: true, color: Colors.accent },\n props.parentLabel,\n ),\n createElement(Box, { height: 1 }),\n createElement(PickerMenu<Command>, {\n message: 'Pick a subcommand',\n options: props.options,\n optionMarginBottom: 1,\n onSelect: (value) => {\n // PickerMenu in single mode returns one value; only the multi-mode\n // signature is the array variant. Narrow defensively.\n const cmd = Array.isArray(value) ? value[0] : value;\n if (cmd) props.onSelect(cmd);\n },\n }),\n );\n}\n\nfunction describe(child: Command): string {\n // Strip positional syntax (`search <query>` → `search`) for the picker label.\n return commandKeys(child.name)[0] ?? '';\n}\n\n/**\n * Reorder children so the `default`-marked entry is first, while\n * preserving the relative order of the rest. The picker's initial\n * focus is index 0, so this is what makes \"press Enter on\n * `wizard audit`\" run the default leaf (today `audit events`).\n *\n * Exported for testability — the ordering logic stays pure and\n * inspectable without mounting Ink.\n */\nexport function orderFamilyChildren(children: readonly Command[]): Command[] {\n const selectable = children.filter((c) => c.handler || c.children?.length);\n const defaults = selectable.filter((c) => c.default);\n const rest = selectable.filter((c) => !c.default);\n return [...defaults, ...rest];\n}\n\n/**\n * Render the picker. Resolves once the user has selected a child;\n * dispatching the child's handler is the caller's responsibility (so this\n * function stays pure-UI and easy to test by stubbing `render`).\n */\nexport function chooseFamilyChild(\n parentLabel: string,\n children: readonly Command[],\n): Promise<Command | null> {\n const ordered = orderFamilyChildren(children);\n if (ordered.length === 0) return Promise.resolve(null);\n\n const options = ordered.map((child) => ({\n label: describe(child),\n value: child,\n hint: child.description,\n }));\n\n return new Promise((resolve) => {\n let app: ReturnType<typeof render> | null = null;\n const handleSelect = (cmd: Command): void => {\n app?.unmount();\n resolve(cmd);\n };\n app = render(\n createElement(FamilyPickerApp, {\n parentLabel,\n options,\n onSelect: handleSelect,\n }),\n );\n });\n}\n\n/**\n * Returns an `interactiveDefault` handler for a family parent's no-leaf\n * invocation. Always opens the picker; the `default`-marked child is\n * shown first (pre-highlighted), so a single Enter keystroke runs it.\n *\n * Discovery + consent in one extra keystroke vs. auto-running silently.\n *\n * Wire onto a family parent:\n * export const auditCommand: Command = {\n * name: 'audit',\n * description: '...',\n * children: [...],\n * interactiveDefault: createFamilyPickerDefault('audit', auditChildren),\n * };\n */\nexport function createFamilyPickerDefault(\n parentLabel: string,\n children: readonly Command[],\n chooser: (\n label: string,\n children: readonly Command[],\n ) => Promise<Command | null> = chooseFamilyChild,\n): (argv: Arguments) => Promise<void> {\n return async (argv) => {\n const chosen = await chooser(parentLabel, children);\n if (!chosen) return;\n // We forward the PARENT's parsed argv straight to the chosen child. The\n // child's own option defaults and `check` validator do NOT run on this\n // path — they only run when the leaf is invoked directly\n // (`wizard audit events`). Harmless while leaves declare neither, but if a\n // leaf ever grows a `check` or a defaulted option, this path will skip it.\n await Promise.resolve(chosen.handler?.(argv));\n };\n}\n","import type { Arguments } from 'yargs';\n\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport {\n buildFamilyPickerChildren,\n dispatchFamily,\n pickerChildrenToShow,\n} from '@lib/programs/dispatch-family';\nimport { getSkillsBaseUrl } from '@lib/constants';\nimport { fetchSkillMenu } from '@lib/wizard-tools';\n\nimport type { Command } from '../command';\nimport { createFamilyPickerDefault } from './family-picker';\nimport { mergeCommandOptions, runCommandHandler } from './shared';\n\nexport interface FamilyCommandFactoryOpts {\n /** The family's CLI name (e.g. 'audit'). */\n family: string;\n /** Help text for `wizard <family> --help`. */\n description: string;\n /**\n * Source for shared CLI options (e.g. --install-dir) merged onto the\n * family parent. Usually the family's flagship native config, or the\n * generic agent-skill config.\n */\n optionsFrom: ProgramConfig;\n}\n\n/**\n * Build a yargs `Command` for a family parent (`wizard audit`, etc.).\n *\n * - `wizard <family> <sub>` — `dispatchFamily` resolves `<sub>` against\n * native handlers first, then the live `cliEntries` from\n * `skill-menu.json`. Unknown subs error with the available list.\n * - `wizard <family>` (no positional) — in an interactive terminal, runs the\n * family's single shown entry directly (today `audit events`, so the user\n * lands on its intro screen); opens the picker once a family shows more than\n * one. In non-TTY/CI, falls through to `dispatchFamily`, which prints\n * \"requires a subcommand\" rather than running something unprompted.\n *\n * No static yargs children. New skill-backed subcommands appear after a\n * context-mill release without a wizard release. New *native* subcommands\n * (rare) are added by updating `NATIVE_HANDLERS` in `dispatch-family.ts`.\n */\nexport function familyCommandFactory({\n family,\n description,\n optionsFrom,\n}: FamilyCommandFactoryOpts): Command {\n // Bare `wizard <family>` in an interactive terminal. With a single option\n // today (e.g. `audit events`), skip the picker and run it directly so the\n // user lands on its own intro screen rather than a one-item menu. When a\n // family grows past one shown option, this opens the picker instead — no\n // wiring change needed.\n const openFamilyEntry = async (argv: Arguments): Promise<void> => {\n const skillsBaseUrl = getSkillsBaseUrl(Boolean(argv['local-mcp']));\n const menu = await fetchSkillMenu(skillsBaseUrl);\n const children = buildFamilyPickerChildren(family, menu?.cliEntries ?? []);\n const toShow = pickerChildrenToShow(children);\n if (toShow.length === 1 && toShow[0]?.handler) {\n await Promise.resolve(toShow[0].handler(argv));\n return;\n }\n const picker = createFamilyPickerDefault(`wizard ${family}`, toShow);\n await picker(argv);\n };\n\n return {\n name: `${family} [skill]`,\n description,\n options: mergeCommandOptions(optionsFrom),\n positionals: {\n skill: {\n type: 'string',\n describe: 'Subcommand to run (omit to run the default)',\n },\n },\n handler: (argv: Arguments) => {\n const sub = (argv.skill as string | undefined)?.trim();\n // With a subcommand, resolve and run it. Without one, run the family's\n // default entry (or open the picker if there's more than one) — but only\n // in an interactive terminal. In non-TTY/CI, fall through to\n // dispatchFamily, which prints \"requires a subcommand\" rather than\n // running something unprompted or hanging on a picker that can't render.\n // runCommandHandler awaits the async work so a rejection surfaces as a\n // clean error instead of an unhandled promise rejection.\n runCommandHandler(() =>\n sub || !process.stdout.isTTY\n ? dispatchFamily(family, argv)\n : openFamilyEntry(argv),\n );\n },\n interactiveDefault: openFamilyEntry,\n };\n}\n","import { auditConfig } from '@lib/programs/audit/index';\n\nimport type { Command } from './command';\nimport { familyCommandFactory } from './factories/family-command-factory';\n\n/**\n * The `wizard audit` family.\n *\n * Subcommands are resolved at runtime: the wizard fetches `cliEntries` from\n * `skill-menu.json` and dispatches based on `parentCommand: 'audit'`. The\n * wizard-native handler for `web-analytics` lives in `NATIVE_HANDLERS` over\n * in `dispatch-family.ts`. `wizard audit` with no positional opens the\n * family picker, which combines native + live entries.\n *\n * Adding a new skill-backed audit subcommand is a context-mill release —\n * no wizard release needed.\n */\nexport const auditCommand: Command = familyCommandFactory({\n family: 'audit',\n description: auditConfig.description,\n optionsFrom: auditConfig,\n});\n","import { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { readApiKeyFromEnv } from '@utils/env-api-key';\nimport { runWizard } from '@lib/runners';\nimport {\n posthogDoctorConfig,\n fetchHealthIssues,\n getKindMeta,\n} from '@lib/programs/posthog-doctor/index';\nimport { skillProgramOptions } from './skill-program-options';\nimport type { Command } from './command';\n\nexport const doctorCommand: Command = {\n name: 'doctor',\n description: posthogDoctorConfig.description,\n options: {\n ...skillProgramOptions,\n ...(posthogDoctorConfig.cliOptions ?? {}),\n },\n handler: (argv) => {\n const extras =\n posthogDoctorConfig.mapCliOptions?.(argv as Record<string, unknown>) ??\n {};\n const options = { ...argv, ...extras };\n // doctor is otherwise a TUI-only diagnostic (it has no agent run); in CI we\n // fetch the project's health issues headlessly and report them instead.\n if (options.ci) {\n void runDoctorCI(options);\n } else {\n runWizard(posthogDoctorConfig, options);\n }\n },\n};\n\nconst SEVERITY_ORDER = { critical: 0, warning: 1, info: 2 } as const;\n\nasync function runDoctorCI(options: Record<string, unknown>): Promise<void> {\n setUI(new LoggingUI());\n const apiKey = (options.apiKey as string) ?? readApiKeyFromEnv() ?? undefined;\n if (!apiKey) {\n getUI().intro('PostHog Wizard');\n getUI().log.error('CI mode requires --api-key (personal API key phx_xxx)');\n process.exit(1);\n }\n\n getUI().intro('Welcome to the PostHog setup wizard');\n getUI().log.info('Running posthog-doctor in CI mode');\n\n try {\n const { getOrAskForProjectData } = await import('@utils/setup-utils');\n const { host, accessToken, projectId } = await getOrAskForProjectData({\n signup: false,\n ci: true,\n apiKey,\n projectId: options.projectId\n ? Number(options.projectId as string)\n : undefined,\n });\n\n const issues = await fetchHealthIssues(accessToken, host, projectId);\n if (issues.length === 0) {\n getUI().log.success('No active issues — your project looks healthy.');\n process.exit(0);\n }\n\n const sorted = [...issues].sort(\n (a, b) => SEVERITY_ORDER[a.severity] - SEVERITY_ORDER[b.severity],\n );\n getUI().log.warn(\n `${issues.length} active issue${issues.length === 1 ? '' : 's'} found:`,\n );\n for (const issue of sorted) {\n getUI().log.info(\n ` • [${issue.severity}] ${getKindMeta(issue.kind).title}`,\n );\n }\n process.exit(1);\n } catch (error) {\n const { ApiError } = await import('@lib/api');\n const message =\n error instanceof ApiError && error.statusCode === 401\n ? 'Your PostHog API key is invalid or expired.'\n : error instanceof Error\n ? error.message\n : String(error);\n getUI().log.error(`Doctor failed: ${message}`);\n process.exit(1);\n }\n}\n","import type { ProgramConfig } from '@lib/programs/program-step';\n\nimport type { Command } from '../command';\n\nimport { dispatchProgram, mergeCommandOptions } from './shared';\n\nexport interface NativeCommandFactoryOpts {\n /** Subcommands nested under this command. */\n children?: readonly Command[];\n}\n\n/**\n * Build a yargs `Command` from a wizard-native `ProgramConfig`.\n *\n * Collapses the previously duplicated boilerplate (read `config.command`,\n * merge skill-program flags with program-specific options, dispatch via\n * `runWizard` / `runWizardCI`) into a single call.\n */\nexport function nativeCommandFactory(\n config: ProgramConfig,\n opts: NativeCommandFactoryOpts = {},\n): Command {\n if (!config.command) {\n throw new Error(\n `nativeCommandFactory: program \"${config.id}\" has no \\`command\\` — wizard-native programs must declare a CLI name`,\n );\n }\n return {\n name: config.command,\n description: config.description,\n options: mergeCommandOptions(config),\n children: opts.children,\n handler: (argv) => dispatchProgram(config, argv),\n };\n}\n","import { migrationConfig } from '@lib/programs/migration/index';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard migrate` — flat skill command, Statsig today.\n *\n * Stays flat while there's only one vendor. When a second vendor lands,\n * restructure into a family with `familyCommandFactory` and publish each\n * vendor as a `cliEntries` entry with `parentCommand: 'migrate'` from\n * context-mill. That move is a deliberate breaking change for users\n * (`wizard migrate` stops running Statsig directly), so do it explicitly\n * when the second vendor arrives, not pre-emptively.\n */\nexport const migrateCommand: Command = nativeCommandFactory(migrationConfig);\n","import { revenueAnalyticsConfig } from '@lib/programs/revenue-analytics/index';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard revenue-analytics` — flat skill command, Stripe today.\n *\n * Stays flat while there's only one provider. Restructure into a family\n * if/when a second provider lands.\n */\nexport const revenueCommand: Command = nativeCommandFactory(\n revenueAnalyticsConfig,\n);\n","import { warehouseSourceConfig } from '@lib/programs/warehouse-source/index';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard warehouse` — detect and connect a data warehouse source.\n *\n * Mirrors `revenue-analytics`: flat skill command driven by the\n * warehouse-source program.\n */\nexport const warehouseCommand: Command = nativeCommandFactory(\n warehouseSourceConfig,\n);\n","import { runWizard, runWizardCI } from '@lib/runners';\nimport { selfDrivingConfig } from '@lib/programs/self-driving/index';\nimport { skillProgramOptions } from './skill-program-options';\nimport type { Command } from './command';\n\nexport const selfDrivingCommand: Command = {\n name: 'self-driving',\n description: selfDrivingConfig.description,\n options: {\n ...skillProgramOptions,\n ...(selfDrivingConfig.cliOptions ?? {}),\n },\n check: (argv) => {\n // self-driving builds on an existing integration and is fully interactive,\n // so the modes that break it are rejected before the TUI/agent loop spins\n // up rather than failing late (a 403 on the first MCP probe under --signup,\n // or a stalled `wizard_ask` with no bridge under --ci).\n if (argv.signup) {\n throw new Error(\n '`self-driving` cannot run with --signup. It builds on an existing ' +\n 'PostHog integration — run the base `wizard` to create your account ' +\n 'and set up PostHog first, then run `wizard self-driving`.',\n );\n }\n if (argv.ci) {\n throw new Error(\n '`self-driving` cannot run in CI mode — it requires interactive steps ' +\n '(GitHub connect, issue-tracker selection, custom-scout approval).',\n );\n }\n return true;\n },\n handler: (argv) => {\n const extras =\n selfDrivingConfig.mapCliOptions?.(argv as Record<string, unknown>) ?? {};\n const options = { ...argv, ...extras };\n if (options.ci) {\n runWizardCI(selfDrivingConfig, options);\n } else {\n runWizard(selfDrivingConfig, options);\n }\n },\n};\n","import type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { Program } from '@lib/programs/program-registry';\nimport { VERSION } from '@lib/version';\nimport type { Command } from './command';\n\nexport const slackCommand: Command = {\n name: 'slack',\n description: 'Connect PostHog to your Slack',\n handler: runSlackConnect,\n // Mirrors the mcp command family shape: `wizard slack` and\n // `wizard slack add` run the same connect flow.\n children: [\n {\n name: 'add',\n description: 'Connect PostHog to your Slack',\n handler: runSlackConnect,\n },\n ],\n};\n\nfunction runSlackConnect(argv: Arguments): void {\n void (async () => {\n const debug = argv.debug as boolean | undefined;\n\n try {\n const { startTUI } = await import('@ui/tui/start-tui');\n const { buildSession } = await import('@lib/wizard-session');\n const tui = startTUI(VERSION, Program.SlackConnect);\n tui.store.session = buildSession({ debug });\n } catch (err) {\n // TUI unavailable — connecting Slack has no headless fallback.\n setUI(new LoggingUI());\n getUI().log.error(\n `Connecting Slack requires an interactive terminal. ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n process.exit(1);\n }\n })();\n}\n","import { runWizard, runWizardCI } from '@lib/runners';\nimport { errorTrackingUploadSourceMapsConfig } from '@lib/programs/error-tracking-upload-source-maps/index';\nimport { skillProgramOptions } from './skill-program-options';\nimport type { Command } from './command';\n\nexport const uploadSourcemapsCommand: Command = {\n // Must match ProgramConfig.command; legacy alias kept for #489 regression.\n name: [errorTrackingUploadSourceMapsConfig.command!, 'upload-sourcemaps'],\n description: errorTrackingUploadSourceMapsConfig.description,\n options: {\n ...skillProgramOptions,\n ...(errorTrackingUploadSourceMapsConfig.cliOptions ?? {}),\n },\n handler: (argv) => {\n const extras =\n errorTrackingUploadSourceMapsConfig.mapCliOptions?.(\n argv as Record<string, unknown>,\n ) ?? {};\n const options = { ...argv, ...extras };\n if (options.ci) {\n runWizardCI(errorTrackingUploadSourceMapsConfig, options);\n } else {\n runWizard(errorTrackingUploadSourceMapsConfig, options);\n }\n },\n};\n","import type { Arguments } from 'yargs';\nimport { POSTHOG_DOCS_URL } from '@lib/constants';\nimport { runWizard, runWizardCI } from '@lib/runners';\nimport { createSkillProgram } from '@lib/programs/agent-skill/index';\n\n/** Run an arbitrary context-mill skill by id (`wizard skill <id>`, headless with `--ci`). */\nexport function runSkillMode(argv: Arguments): void {\n const skillId = argv.skill as string;\n const config = createSkillProgram({\n skillId,\n command: 'skill',\n id: 'agent-skill',\n description: `Run skill: ${skillId}`,\n integrationLabel: skillId,\n successMessage: `${skillId} completed!`,\n reportFile: `posthog-${skillId}-report.md`,\n docsUrl: POSTHOG_DOCS_URL,\n spinnerMessage: `Running ${skillId}...`,\n estimatedDurationMinutes: 5,\n });\n const options = { ...argv, skillId };\n if (argv.ci) {\n runWizardCI(config, options);\n } else {\n runWizard(config, options);\n }\n}\n","import type { Arguments } from 'yargs';\n\nimport { getSkillsBaseUrl } from '@lib/constants';\nimport { fetchSkillMenu, type CliEntry } from '@lib/wizard-tools';\nimport { analytics } from '@utils/analytics';\n\nimport { runSkillMode } from './basic-integration/skill';\nimport { skillProgramOptions } from './skill-program-options';\nimport { runCommandHandler } from './factories/shared';\nimport type { Command } from './command';\n\n/** Read the `<skill-name>` positional (yargs camelCases the hyphenated key). */\nfunction readSkillName(argv: Arguments): string {\n return String(argv.skillName ?? argv['skill-name'] ?? '').trim();\n}\n\nconst BROWSABLE_ROLES: ReadonlySet<CliEntry['role']> = new Set([\n 'command',\n 'skill',\n]);\n\nfunction formatEntry(entry: CliEntry): string {\n const path = entry.parentCommand\n ? `wizard ${entry.parentCommand} ${entry.command}`\n : entry.command\n ? `wizard ${entry.command}`\n : `wizard skill ${entry.skillId}`;\n return ` ${entry.skillId.padEnd(38)} ${path.padEnd(36)} ${\n entry.description\n }`;\n}\n\n/**\n * `wizard skill list` — fetch and print every browsable skill in the catalog.\n *\n * Reads the live `skill-menu.json` so new skills appear immediately after a\n * context-mill release. `internal` skills are excluded from the listing.\n */\nconst listCommand: Command = {\n name: 'list',\n description: 'List every browsable skill in the catalog',\n handler: (argv) => {\n runCommandHandler(async () => {\n const skillsBaseUrl = getSkillsBaseUrl(Boolean(argv['local-mcp']));\n const menu = await fetchSkillMenu(skillsBaseUrl);\n if (!menu) {\n analytics.wizardCapture('cli dispatch error', {\n reason: 'registry unreachable',\n family: 'skill',\n sub: 'list',\n skillsBaseUrl,\n });\n try {\n await analytics.flush();\n } catch {\n /* best-effort */\n }\n process.stderr.write(\n `\\n\\x1b[1;91m✖ Couldn't reach the skill registry.\\x1b[0m\\n` +\n ` Check your network connection and try again.\\n\\n`,\n );\n process.exit(1);\n }\n const entries = (menu.cliEntries ?? []).filter((e) =>\n BROWSABLE_ROLES.has(e.role),\n );\n if (entries.length === 0) {\n process.stdout.write('No skills found.\\n');\n return;\n }\n process.stdout.write(\n `${entries.length} skill${entries.length === 1 ? '' : 's'}:\\n`,\n );\n process.stdout.write(\n ` ${'SKILL ID'.padEnd(38)} ${'COMMAND'.padEnd(36)} DESCRIPTION\\n`,\n );\n for (const entry of entries) {\n process.stdout.write(`${formatEntry(entry)}\\n`);\n }\n });\n },\n};\n\n/**\n * `wizard skill <skill-name>` — run a single context-mill skill by id.\n * `wizard skill list` — list every browsable skill in the catalog.\n *\n * Replaces the old `--skill=<id>` flag on the default command. The skill id\n * is fetched from context-mill's release at runtime (same mechanism the flag\n * used), so any published skill id works. Pass `--ci` to run headlessly.\n */\nexport const skillCommand: Command = {\n name: 'skill <skill-name>',\n description: 'Run a specific context-mill skill by name (or `list` them)',\n children: [listCommand],\n options: {\n ...skillProgramOptions,\n },\n // yargs already enforces the `<skill-name>` positional, but an\n // explicitly-empty value (`wizard skill \"\"`) would otherwise slip\n // through to a broken run. Reject it with the same friendly message\n // the old --skill flag gave. When `wizard skill list` matched the\n // child instead, yargs leaves the positional unset — the `null` guard\n // keeps the check from rejecting that route.\n check: (argv) => {\n if (argv.skillName == null && argv['skill-name'] == null) return true;\n if (!readSkillName(argv)) {\n throw new Error(\n 'skill needs a skill name, e.g. `wizard skill audit-events`',\n );\n }\n return true;\n },\n handler: (argv) => {\n // runSkillMode reads `argv.skill`; bridge the positional onto it.\n runSkillMode({ ...argv, skill: readSkillName(argv) });\n },\n};\n","import { spawnSync } from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport * as path from 'node:path';\n\nimport { debug } from '@utils/debug';\n\n/**\n * A coding agent whose global instructions file the PostHog CLI steering\n * snippet can be installed into. Project-level installs are handled by\n * `posthog-cli api agents-md install` in the target repo; this step only\n * manages the per-user (global) instruction files.\n */\nexport interface CliSteeringTarget {\n id: string;\n name: string;\n /** Global agent instructions file the steering snippet is written to. */\n instructionsPath(): string;\n /** Whether the agent appears to be installed on this machine. */\n isDetected(): boolean;\n}\n\nconst dirExists = (...segments: string[]): boolean => {\n try {\n return fs.existsSync(path.join(os.homedir(), ...segments));\n } catch {\n return false;\n }\n};\n\nexport const CLI_STEERING_TARGETS: readonly CliSteeringTarget[] = [\n {\n id: 'claude-code',\n name: 'Claude Code',\n instructionsPath: () => path.join(os.homedir(), '.claude', 'CLAUDE.md'),\n isDetected: () => dirExists('.claude'),\n },\n {\n id: 'codex',\n name: 'Codex',\n instructionsPath: () => path.join(os.homedir(), '.codex', 'AGENTS.md'),\n isDetected: () => dirExists('.codex'),\n },\n {\n id: 'gemini',\n name: 'Gemini CLI',\n instructionsPath: () => path.join(os.homedir(), '.gemini', 'GEMINI.md'),\n isDetected: () => dirExists('.gemini'),\n },\n];\n\nexport function findTarget(id: string): CliSteeringTarget | undefined {\n return CLI_STEERING_TARGETS.find((target) => target.id === id);\n}\n\nexport function detectTargets(): CliSteeringTarget[] {\n return CLI_STEERING_TARGETS.filter((target) => target.isDetected());\n}\n\nexport interface SteeringInstallResult {\n success: boolean;\n filePath: string;\n error?: string;\n}\n\nexport interface CliInstallResult {\n success: boolean;\n error?: string;\n}\n\nconst spawnOptions = {\n encoding: 'utf-8' as const,\n // npm/posthog-cli are npm.cmd/posthog-cli.cmd on Windows; spawnSync only\n // resolves them through a shell.\n shell: process.platform === 'win32',\n};\n\n/**\n * Install or update the PostHog CLI in the user's environment. `npm install\n * --global @posthog/cli@latest` covers both first-time installs and upgrades\n * for existing npm-installed CLIs.\n */\nexport function installOrUpdatePostHogCli(): CliInstallResult {\n const args = ['install', '--global', '@posthog/cli@latest'];\n debug(`Running npm ${args.join(' ')}`);\n\n const result = spawnSync('npm', args, spawnOptions);\n\n if (result.error) {\n return {\n success: false,\n error: `Failed to run npm: ${result.error.message}. Is Node.js installed?`,\n };\n }\n if (result.status !== 0) {\n const detail = (result.stderr || result.stdout || '').trim();\n return {\n success: false,\n error:\n detail ||\n `npm install --global @posthog/cli@latest exited with status ${\n result.status ?? 'unknown'\n }`,\n };\n }\n return { success: true };\n}\n\n/**\n * Delegate the actual write to the installed `posthog-cli api agents-md\n * install`. The steering snippet lives in the CLI (its single source of truth),\n * so the command should run only after `installOrUpdatePostHogCli` refreshes\n * the CLI to the latest release.\n */\nexport function installSteeringSnippet(\n filePath: string,\n): SteeringInstallResult {\n const args = ['api', 'agents-md', 'install', '--path', filePath];\n debug(`Running posthog-cli ${args.join(' ')}`);\n\n const result = spawnSync('posthog-cli', args, {\n ...spawnOptions,\n env: { ...process.env, POSTHOG_CLI_EXPERIMENTAL_API: '1' },\n });\n\n if (result.error) {\n return {\n success: false,\n filePath,\n error: `Failed to run posthog-cli: ${result.error.message}. Make sure npm's global bin directory is on your PATH.`,\n };\n }\n if (result.status !== 0) {\n const detail = (result.stderr || result.stdout || '').trim();\n return {\n success: false,\n filePath,\n error:\n detail ||\n `posthog-cli exited with status ${result.status ?? 'unknown'}`,\n };\n }\n return { success: true, filePath };\n}\n","import * as path from 'node:path';\nimport * as readline from 'node:readline/promises';\nimport type { Arguments } from 'yargs';\nimport { getUI, setUI } from '@ui';\nimport { LoggingUI } from '@ui/logging-ui';\nimport { analytics } from '@utils/analytics';\nimport {\n CLI_STEERING_TARGETS,\n type CliSteeringTarget,\n detectTargets,\n findTarget,\n installOrUpdatePostHogCli,\n installSteeringSnippet,\n} from '@steps/install-cli-steering';\nimport type { Command } from '../command';\n\nexport const cliAddCommand: Command = {\n name: 'add',\n description:\n \"Install or update PostHog CLI and add steering instructions to your coding agent's global instructions file\",\n options: {\n agent: {\n describe: 'Agent to install the instructions for',\n choices: CLI_STEERING_TARGETS.map((target) => target.id),\n type: 'string',\n },\n path: {\n describe:\n 'Write to an explicit instructions file instead of a detected agent',\n type: 'string',\n },\n all: {\n default: false,\n describe: 'Install for every detected agent without prompting',\n type: 'boolean',\n },\n },\n examples: [\n ['wizard cli add', 'Detect your coding agents and pick one'],\n [\n 'wizard cli add --agent claude-code',\n 'Install for Claude Code (~/.claude/CLAUDE.md)',\n ],\n ['wizard cli add --all', 'Install for every detected agent'],\n [\n 'wizard cli add --path ./AGENTS.md',\n 'Install into a specific instructions file',\n ],\n ],\n check: (argv) => {\n if (argv.all && (argv.agent || argv.path)) {\n throw new Error('--all cannot be combined with --agent or --path');\n }\n return true;\n },\n handler: (argv) => {\n void runCliAdd(argv);\n },\n};\n\nasync function runCliAdd(argv: Arguments): Promise<void> {\n setUI(new LoggingUI());\n const ui = getUI();\n ui.intro('PostHog CLI setup');\n\n const files = await resolveTargetFiles(argv);\n if (files.length === 0) {\n process.exit(1);\n return;\n }\n\n ui.log.info('Installing or updating PostHog CLI...');\n const cliInstallResult = installOrUpdatePostHogCli();\n if (!cliInstallResult.success) {\n ui.log.error(\n `Failed to install or update PostHog CLI: ${\n cliInstallResult.error ?? ''\n }`,\n );\n analytics.wizardCapture('cli steering installed', {\n files: files.length,\n failures: files.length,\n cli_install_failed: true,\n agent: typeof argv.agent === 'string' ? argv.agent : undefined,\n });\n process.exit(1);\n return;\n }\n ui.log.success('Installed or updated PostHog CLI.');\n\n let failures = 0;\n for (const file of files) {\n const result = installSteeringSnippet(file);\n if (result.success) {\n ui.log.success(`Installed PostHog steering instructions in ${file}`);\n } else {\n failures += 1;\n ui.log.error(`Failed to update ${file}: ${result.error ?? ''}`);\n }\n }\n\n analytics.wizardCapture('cli steering installed', {\n files: files.length,\n failures,\n agent: typeof argv.agent === 'string' ? argv.agent : undefined,\n });\n\n if (failures > 0) {\n process.exit(1);\n return;\n }\n ui.outro(\n 'Done. PostHog CLI is installed and your agent will now use `posthog-cli api` for PostHog tasks.',\n );\n process.exit(0);\n}\n\n/** Resolve which instruction files to write, from flags, detection, or a prompt. */\nasync function resolveTargetFiles(argv: Arguments): Promise<string[]> {\n const ui = getUI();\n\n if (typeof argv.path === 'string' && argv.path.trim()) {\n return [path.resolve(argv.path.trim())];\n }\n\n if (typeof argv.agent === 'string') {\n // yargs `choices` already rejected unknown ids.\n const target = findTarget(argv.agent);\n if (!target) {\n ui.log.error(`Unsupported agent: ${argv.agent}`);\n return [];\n }\n return [target.instructionsPath()];\n }\n\n const detected = detectTargets();\n if (detected.length === 0) {\n ui.log.error(\n 'No supported coding agents detected. Pass --agent <id> or --path <file> to choose a target.',\n );\n ui.log.info(\n `Supported agents: ${CLI_STEERING_TARGETS.map((t) => t.id).join(', ')}`,\n );\n return [];\n }\n\n if (argv.all === true) {\n ui.log.info(\n `Installing for all detected agents: ${detected\n .map((t) => t.name)\n .join(', ')}`,\n );\n return detected.map((target) => target.instructionsPath());\n }\n\n if (detected.length === 1) {\n ui.log.info(\n `Detected ${detected[0].name} (${detected[0].instructionsPath()})`,\n );\n return [detected[0].instructionsPath()];\n }\n\n // Non-interactive shells can't pick, so install for every detected agent —\n // the snippet is additive and idempotent, mirroring how MCP install treats\n // all supported clients.\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n ui.log.info(\n `Installing for all detected agents: ${detected\n .map((t) => t.name)\n .join(', ')}`,\n );\n return detected.map((target) => target.instructionsPath());\n }\n\n const selected = await promptForTargets(detected);\n return selected.map((target) => target.instructionsPath());\n}\n\n/** Minimal numbered selection — this command is intentionally not a TUI flow. */\nasync function promptForTargets(\n detected: CliSteeringTarget[],\n): Promise<CliSteeringTarget[]> {\n const ui = getUI();\n ui.log.info('Which coding agent are you using?');\n detected.forEach((target, index) => {\n ui.log.info(\n ` ${index + 1}) ${target.name} (${target.instructionsPath()})`,\n );\n });\n ui.log.info(` ${detected.length + 1}) All of the above`);\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n try {\n for (;;) {\n const answer = (\n await rl.question(`Select 1-${detected.length + 1}: `)\n ).trim();\n const choice = Number(answer);\n if (\n Number.isInteger(choice) &&\n choice >= 1 &&\n choice <= detected.length\n ) {\n return [detected[choice - 1]];\n }\n if (choice === detected.length + 1) {\n return detected;\n }\n ui.log.warn(`Enter a number between 1 and ${detected.length + 1}.`);\n }\n } finally {\n rl.close();\n }\n}\n","import { cliAddCommand } from './add';\nimport type { Command } from '../command';\n\nexport const cliCommand: Command = {\n name: 'cli',\n description: 'PostHog CLI agent integration commands',\n children: [cliAddCommand],\n};\n","#!/usr/bin/env node\nimport { satisfies } from 'semver';\n\nconst NODE_VERSION_RANGE = '>=18.17.0';\n\n// Have to run this above the other imports because they are importing clack that\n// has the problematic imports.\nif (!satisfies(process.version, NODE_VERSION_RANGE)) {\n // eslint-disable-next-line no-console\n console.log(\n `PostHog wizard requires Node.js ${NODE_VERSION_RANGE}. You are using Node.js ${process.version}. Please upgrade your Node.js version.`,\n );\n process.exit(1);\n}\n\n// Test mock server — only loaded when NODE_ENV is 'test'.\n// In production builds, tsdown replaces process.env.NODE_ENV with 'production',\n// making this block dead code.\nif (process.env.NODE_ENV === 'test') {\n void (async () => {\n try {\n const { server } = await import('./e2e-tests/mocks/server.js');\n server.listen({\n onUnhandledRequest: 'bypass',\n });\n } catch (error) {\n // Mock server import failed - this can happen during non-E2E tests\n }\n })();\n}\n\nimport { Wizard } from './src/wizard';\nimport { basicIntegrationCommand } from './src/commands/basic-integration';\nimport { mcpCommand } from './src/commands/mcp';\nimport { auditCommand } from './src/commands/audit';\nimport { doctorCommand } from './src/commands/doctor';\nimport { migrateCommand } from './src/commands/migrate';\nimport { revenueCommand } from './src/commands/revenue';\nimport { warehouseCommand } from './src/commands/warehouse';\nimport { selfDrivingCommand } from './src/commands/self-driving';\nimport { slackCommand } from './src/commands/slack';\nimport { uploadSourcemapsCommand } from './src/commands/upload-sourcemaps';\nimport { skillCommand } from './src/commands/skill';\nimport { cliCommand } from './src/commands/cli';\nimport { recoverOrphanedSettingsBackups } from './src/lib/agent/claude-settings';\n\n// Heal any .claude/settings backup a previous interrupted run left orphaned,\n// before anything else reads Claude settings — conflict detection, OAuth, and\n// the agent all need to see the user's real settings file. The install dir is\n// read directly from argv/env because yargs hasn't parsed yet.\nrecoverOrphanedSettingsBackups(resolveInstallDir());\n\nfunction resolveInstallDir(): string {\n const args = process.argv.slice(2);\n const flagIndex = args.indexOf('--install-dir');\n if (flagIndex !== -1 && args[flagIndex + 1]) return args[flagIndex + 1];\n const inline = args.find((a) => a.startsWith('--install-dir='));\n if (inline) return inline.slice('--install-dir='.length);\n return process.env.POSTHOG_WIZARD_INSTALL_DIR ?? process.cwd();\n}\n\nWizard.use(basicIntegrationCommand)\n .use(mcpCommand)\n .use(cliCommand)\n .use(auditCommand)\n .use(doctorCommand)\n .use(migrateCommand)\n .use(revenueCommand)\n .use(warehouseCommand)\n .use(selfDrivingCommand)\n .use(slackCommand)\n .use(uploadSourcemapsCommand)\n .use(skillCommand)\n .init();\n"],"mappings":"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"}