@posthog/wizard 2.82.0 → 2.84.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 (149) hide show
  1. package/README.md +1 -29
  2. package/dist/{PickerMenu-BGGeYqd-.js → PickerMenu-BtheKi1o.js} +1 -1
  3. package/dist/{PickerMenu-BGGeYqd-.js.map → PickerMenu-BtheKi1o.js.map} +1 -1
  4. package/dist/_dev-only-stub-B0db0Klc.js +1 -0
  5. package/dist/{agent-interface-3YfIWZmY.js → agent-interface-BNssNetq.js} +86 -32
  6. package/dist/agent-interface-BNssNetq.js.map +1 -0
  7. package/dist/{agent-prompt-loader-hOHONY7u.js → agent-prompt-loader-iV11XVEF.js} +16 -8
  8. package/dist/agent-prompt-loader-iV11XVEF.js.map +1 -0
  9. package/dist/{analytics-B_xFshPY.js → analytics-Drox5LSW.js} +7 -5
  10. package/dist/analytics-Drox5LSW.js.map +1 -0
  11. package/dist/analytics-Ix9HEra3.js +2 -0
  12. package/dist/{api-C_9KsN-7.js → api-Dfu655Qt.js} +2 -2
  13. package/dist/{api-C_9KsN-7.js.map → api-Dfu655Qt.js.map} +1 -1
  14. package/dist/api-H2UaPgjv.js +2 -0
  15. package/dist/{api-key-login-oUJQDmOV.js → api-key-login-BgwfAXfv.js} +5 -5
  16. package/dist/{api-key-login-oUJQDmOV.js.map → api-key-login-BgwfAXfv.js.map} +1 -1
  17. package/dist/api-key-login-Cow3UDAN.js +2 -0
  18. package/dist/bin.js +1 -1
  19. package/dist/{bounded-fs-iRaQcKYL.js → bounded-fs-TRL6IsoU.js} +32 -16
  20. package/dist/bounded-fs-TRL6IsoU.js.map +1 -0
  21. package/dist/{ci-install-BGlijoTo.js → ci-install-nc1IKuX2.js} +6 -6
  22. package/dist/{ci-install-BGlijoTo.js.map → ci-install-nc1IKuX2.js.map} +1 -1
  23. package/dist/{console-log-DJiTqYT2.js → console-log-BMhBoX-o.js} +2 -2
  24. package/dist/{console-log-DJiTqYT2.js.map → console-log-BMhBoX-o.js.map} +1 -1
  25. package/dist/{debug-BvEbemym.js → debug-BfO_Txo8.js} +3 -3
  26. package/dist/debug-BfO_Txo8.js.map +1 -0
  27. package/dist/{defaults-DDVl3tKN.js → defaults-BWLIffh5.js} +1 -1
  28. package/dist/{defaults-DDVl3tKN.js.map → defaults-BWLIffh5.js.map} +1 -1
  29. package/dist/{errors-DhFeR8Sp.js → errors-BXlWujEw.js} +1 -1
  30. package/dist/{errors-DhFeR8Sp.js.map → errors-BXlWujEw.js.map} +1 -1
  31. package/dist/{family-picker-BKs-tTyu.js → family-picker-CAW_VtYf.js} +2 -2
  32. package/dist/{family-picker-BKs-tTyu.js.map → family-picker-CAW_VtYf.js.map} +1 -1
  33. package/dist/{gateway-CWoYlPz7.js → gateway-CLQQb96F.js} +39 -9
  34. package/dist/{gateway-CWoYlPz7.js.map → gateway-CLQQb96F.js.map} +1 -1
  35. package/dist/headless-CHGNEzO3.js +3 -0
  36. package/dist/{headless-Bfi950Qh.js → headless-DMO8N_FD.js} +2 -2
  37. package/dist/{headless-Bfi950Qh.js.map → headless-DMO8N_FD.js.map} +1 -1
  38. package/dist/{host-resolution-BxnNn8Jm.js → host-resolution-DftfSjJD.js} +4 -4
  39. package/dist/{host-resolution-BxnNn8Jm.js.map → host-resolution-DftfSjJD.js.map} +1 -1
  40. package/dist/{install-CDVeUT_5.js → install-C9FPM37m.js} +6 -6
  41. package/dist/{install-CDVeUT_5.js.map → install-C9FPM37m.js.map} +1 -1
  42. package/dist/{install-CX65IxGa.js → install-MWoo1hXL.js} +1 -1
  43. package/dist/{interactive-5-Numwwb.js → interactive-DOnolJHB.js} +3 -3
  44. package/dist/{interactive-5-Numwwb.js.map → interactive-DOnolJHB.js.map} +1 -1
  45. package/dist/{links-Dmj3Wj9X.js → links-CatXPRxH.js} +3 -3
  46. package/dist/{links-Dmj3Wj9X.js.map → links-CatXPRxH.js.map} +1 -1
  47. package/dist/{main-5KNn80Vt.js → main-CINmZtoW.js} +27 -24
  48. package/dist/main-CINmZtoW.js.map +1 -0
  49. package/dist/{mcp-Buf9sfFm.js → mcp-KVV6Z_bq.js} +3 -3
  50. package/dist/{mcp-Buf9sfFm.js.map → mcp-KVV6Z_bq.js.map} +1 -1
  51. package/dist/{mcp-prompt-streaming-DHPxJK-F.js → mcp-prompt-streaming-M6UnLgGX.js} +5 -5
  52. package/dist/{mcp-prompt-streaming-DHPxJK-F.js.map → mcp-prompt-streaming-M6UnLgGX.js.map} +1 -1
  53. package/dist/{mode-label-DB3ol_sj.js → mode-label--bJuXny5.js} +1 -1
  54. package/dist/{mode-label-DB3ol_sj.js.map → mode-label--bJuXny5.js.map} +1 -1
  55. package/dist/{models-C9rjXPZ6.js → models-B0huHItG.js} +6 -2
  56. package/dist/models-B0huHItG.js.map +1 -0
  57. package/dist/{non-interactive-DkldwWDM.js → non-interactive-DiEu4_6l.js} +3 -3
  58. package/dist/{non-interactive-DkldwWDM.js.map → non-interactive-DiEu4_6l.js.map} +1 -1
  59. package/dist/{oauth-session-Bi1MLRCC.js → oauth-session-9EU3ky0v.js} +2 -2
  60. package/dist/{oauth-session-Bi1MLRCC.js.map → oauth-session-9EU3ky0v.js.map} +1 -1
  61. package/dist/{orchestrator-tools-DyKws92o.js → orchestrator-tools-QWyDLu_7.js} +3 -3
  62. package/dist/{orchestrator-tools-DyKws92o.js.map → orchestrator-tools-QWyDLu_7.js.map} +1 -1
  63. package/dist/package-json-BAtJRHSq.js +2 -0
  64. package/dist/{package-json-2UrhE6kP.js → package-json-z1agAYXs.js} +1 -1
  65. package/dist/{package-json-2UrhE6kP.js.map → package-json-z1agAYXs.js.map} +1 -1
  66. package/dist/{package-manager-DpCdmMmB.js → package-manager-B-9I_fAT.js} +4 -4
  67. package/dist/{package-manager-DpCdmMmB.js.map → package-manager-B-9I_fAT.js.map} +1 -1
  68. package/dist/{pi-DTj1hsJe.js → pi-BSnSk6rv.js} +50 -31
  69. package/dist/pi-BSnSk6rv.js.map +1 -0
  70. package/dist/{playground-CiH6zZPb.js → playground-Drz1qszs.js} +4 -4
  71. package/dist/{playground-CiH6zZPb.js.map → playground-Drz1qszs.js.map} +1 -1
  72. package/dist/{posthog-integration-CpinLWNO.js → posthog-integration-mIQGBc1f.js} +883 -2513
  73. package/dist/posthog-integration-mIQGBc1f.js.map +1 -0
  74. package/dist/programs-Bv0_YHzE.js +3 -0
  75. package/dist/{programs-Bq9Ju9xk.js → programs-mxhRXwP-.js} +306 -125
  76. package/dist/programs-mxhRXwP-.js.map +1 -0
  77. package/dist/provisioning-BVsxSNve.js +2 -0
  78. package/dist/{provisioning-D-AM_7DG.js → provisioning-CHUjae9V.js} +4 -4
  79. package/dist/{provisioning-D-AM_7DG.js.map → provisioning-CHUjae9V.js.map} +1 -1
  80. package/dist/{queue-tools-BoIITT7w.js → queue-tools-PFG6H93Q.js} +14 -5
  81. package/dist/queue-tools-PFG6H93Q.js.map +1 -0
  82. package/dist/{results-CDqlHogZ.js → results-5yCKf2cI.js} +2 -2
  83. package/dist/{results-CDqlHogZ.js.map → results-5yCKf2cI.js.map} +1 -1
  84. package/dist/{run-CfMArkpV.js → run-D5TKJuSL.js} +10 -10
  85. package/dist/{run-CfMArkpV.js.map → run-D5TKJuSL.js.map} +1 -1
  86. package/dist/{run-DcaVJSeI.js → run-W03b6jNM.js} +12 -12
  87. package/dist/{run-DcaVJSeI.js.map → run-W03b6jNM.js.map} +1 -1
  88. package/dist/{run-tool-DJZWnnR9.js → run-tool-DTQF8mmI.js} +17 -17
  89. package/dist/{run-tool-DJZWnnR9.js.map → run-tool-DTQF8mmI.js.map} +1 -1
  90. package/dist/run-tool-DjERhu7G.js +2 -0
  91. package/dist/{runners-Cvnk9BcA.js → runners-B_84kPyf.js} +11 -11
  92. package/dist/{runners-Cvnk9BcA.js.map → runners-B_84kPyf.js.map} +1 -1
  93. package/dist/{security-Cz3a-d7r.js → security-pApVawYb.js} +6 -5
  94. package/dist/{security-Cz3a-d7r.js.map → security-pApVawYb.js.map} +1 -1
  95. package/dist/{setup-utils-C7kaDP5X.js → setup-utils-CQY8PHjR.js} +3 -3
  96. package/dist/{setup-utils-C7kaDP5X.js.map → setup-utils-CQY8PHjR.js.map} +1 -1
  97. package/dist/{start-playground-B62_pYfu.js → start-playground-DAw1GbLt.js} +8 -8
  98. package/dist/{start-playground-B62_pYfu.js.map → start-playground-DAw1GbLt.js.map} +1 -1
  99. package/dist/{subagent-BBfETG17.js → subagent-YLGSvgoZ.js} +13 -5
  100. package/dist/subagent-YLGSvgoZ.js.map +1 -0
  101. package/dist/{task-CmNe3xeg.js → task-3hRSovmK.js} +39 -29
  102. package/dist/task-3hRSovmK.js.map +1 -0
  103. package/dist/{tasks-BfJhVky2.js → tasks-C03QbXTx.js} +1 -1
  104. package/dist/{tasks-BfJhVky2.js.map → tasks-C03QbXTx.js.map} +1 -1
  105. package/dist/{telemetry-DKM7VGuJ.js → telemetry-BPBzqsb_.js} +2 -2
  106. package/dist/{telemetry-DKM7VGuJ.js.map → telemetry-BPBzqsb_.js.map} +1 -1
  107. package/dist/{terminal-Bkxwzkhn.js → terminal-DZsYFbm9.js} +471 -81
  108. package/dist/terminal-DZsYFbm9.js.map +1 -0
  109. package/dist/{tools-DZCEvDv9.js → tools-D_AtrhbO.js} +15 -15
  110. package/dist/{tools-DZCEvDv9.js.map → tools-D_AtrhbO.js.map} +1 -1
  111. package/dist/{tools-Bm0FDT6f.js → tools-DyzRi_dQ.js} +8 -8
  112. package/dist/{tools-Bm0FDT6f.js.map → tools-DyzRi_dQ.js.map} +1 -1
  113. package/dist/{tui-B56jvkbi.js → tui-CRp0iCuT.js} +5 -5
  114. package/dist/tui-CRp0iCuT.js.map +1 -0
  115. package/dist/{tui-tKI95MSr.js → tui-UI6ctBQJ.js} +1 -1
  116. package/dist/{upload-step-DqTgn6UB.js → upload-step-DrYXnpzI.js} +3 -3
  117. package/dist/{upload-step-DqTgn6UB.js.map → upload-step-DrYXnpzI.js.map} +1 -1
  118. package/dist/{urls-B82v7gfO.js → urls-WeqfBLP4.js} +2 -2
  119. package/dist/{urls-B82v7gfO.js.map → urls-WeqfBLP4.js.map} +1 -1
  120. package/dist/{wizard-abort-Cd-7sfCw.js → wizard-abort-BwEefm6P.js} +5 -5
  121. package/dist/{wizard-abort-Cd-7sfCw.js.map → wizard-abort-BwEefm6P.js.map} +1 -1
  122. package/dist/yara-hooks-MDtFbuoM.js +2 -0
  123. package/dist/{yara-hooks-BS0n3ekf.js → yara-hooks-aDbdsitJ.js} +41 -5
  124. package/dist/{yara-hooks-BS0n3ekf.js.map → yara-hooks-aDbdsitJ.js.map} +1 -1
  125. package/package.json +9 -7
  126. package/dist/agent-interface-3YfIWZmY.js.map +0 -1
  127. package/dist/agent-prompt-loader-hOHONY7u.js.map +0 -1
  128. package/dist/analytics-B_xFshPY.js.map +0 -1
  129. package/dist/analytics-DGDr6-iD.js +0 -2
  130. package/dist/api-DhLSO3ai.js +0 -2
  131. package/dist/api-key-login-DiRuZ8Lm.js +0 -2
  132. package/dist/bounded-fs-iRaQcKYL.js.map +0 -1
  133. package/dist/debug-BvEbemym.js.map +0 -1
  134. package/dist/headless-Gisv3faN.js +0 -3
  135. package/dist/main-5KNn80Vt.js.map +0 -1
  136. package/dist/models-C9rjXPZ6.js.map +0 -1
  137. package/dist/package-json-Dblip2_X.js +0 -2
  138. package/dist/pi-DTj1hsJe.js.map +0 -1
  139. package/dist/posthog-integration-CpinLWNO.js.map +0 -1
  140. package/dist/programs-Bq9Ju9xk.js.map +0 -1
  141. package/dist/programs-CnOSdQo1.js +0 -3
  142. package/dist/provisioning-D6Cqbc36.js +0 -2
  143. package/dist/queue-tools-BoIITT7w.js.map +0 -1
  144. package/dist/run-tool-zMLQroVh.js +0 -2
  145. package/dist/subagent-BBfETG17.js.map +0 -1
  146. package/dist/task-CmNe3xeg.js.map +0 -1
  147. package/dist/terminal-Bkxwzkhn.js.map +0 -1
  148. package/dist/tui-B56jvkbi.js.map +0 -1
  149. package/dist/yara-hooks-CxksH-GZ.js +0 -2
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent-prompt-loader-hOHONY7u.js","names":[],"sources":["../src/agent/agent-prompt-loader.ts"],"sourcesContent":["/**\n * Agent-prompt loader + registry.\n *\n * Agent prompts are the WHAT of a task: a markdown file per type, served from\n * context-mill as the `agents` content type (parallel to skills). The frontmatter\n * carries the artifacts the executor needs — model, the mini-skills to load (the\n * HOW), the tools the task may use, and its dependencies — and the body is the\n * instruction the agent reads.\n *\n * The registry is fetched once at startup and scoped to one flow — agents\n * declare `flow` and (for the planner) `seed: true` in frontmatter, so each\n * program (integration, audit, migration, ...) ships its own agent set and the\n * loader stays generic. Every prompt is downloaded and parsed up front, so\n * resolving a task to its run config is synchronous and adds no mid-drain\n * network latency. The registry's type list also drives `enqueue_task`\n * validation.\n */\nimport type {\n QueueStore,\n QueuedTask,\n} from './runner/sequence/orchestrator/queue';\nimport type { ResolvedTask } from './runner/sequence/orchestrator/executor';\nimport type { HostResolution } from '@shared/host-resolution';\nimport {\n isThinkingLevel,\n type ThinkingLevel,\n} from './runner/switchboard/models';\nimport { logToFile } from '@utils/debug';\nimport { analytics } from '@utils/analytics';\nimport { fetchWithRetry } from '@shared/fetch-retry';\nimport { WIZARD_TOOL_NAMES } from './tools/tools';\n\n/**\n * The basics the client injects around every agent-prompt body. The `/agents/`\n * files carry intent only (goal, success criteria); the wizard owns the I/O\n * contract — who the agent is, how it reports, how it surfaces progress — so the\n * authored prompts never restate it.\n */\nexport interface OrchestratorPromptContext {\n projectId: number;\n projectApiKey: string;\n host: HostResolution;\n /** Path to the framework's reference implementation (EXAMPLE.md), if available. */\n examplePath?: string;\n /** Path to the framework's rules (COMMANDMENTS.md), if available. */\n commandmentsPath?: string;\n}\n\nfunction projectContext(ctx: OrchestratorPromptContext): string {\n // Both hosts, distinctly labelled: `apiHost` is the ingestion/API origin the\n // SDK talks to, `appHost` the user-facing web app. A task that hands the user\n // a link (e.g. the data-warehouse new-source fallback) must build it from the\n // app host — the ingestion host does not serve those pages.\n return `You have access to the PostHog MCP server and the wizard tools.\n\nProject context:\n- PostHog Project ID: ${ctx.projectId}\n- PostHog public token: ${ctx.projectApiKey}\n- PostHog Host: ${ctx.host.apiHost}\n- PostHog app URL (base for any link you show the user in a browser): ${ctx.host.appHost}`;\n}\n\n/** Points the agent at the framework's reference integration to learn patterns from. */\nfunction exampleReference(ctx: OrchestratorPromptContext): string | null {\n if (!ctx.examplePath) return null;\n return `A reference PostHog integration for this framework is at \\`${ctx.examplePath}\\`. It shows the target implementation pattern. Reference its patterns and conventions, adapting them to this codebase.`;\n}\n\n/** The framework's rules ship with the reference skill; every task follows them. */\nfunction commandmentsReference(ctx: OrchestratorPromptContext): string | null {\n if (!ctx.commandmentsPath) return null;\n return `Framework rules for this integration are at \\`${ctx.commandmentsPath}\\`. Read them before you edit and follow them.`;\n}\n\n/**\n * The task's own tool list, injected so an agent never has to discover a tool's\n * absence by trying it — and never reports that absence as a finding. Later\n * tasks hold tools this one does not, so work it cannot do is handed on rather\n * than attempted.\n */\n/** Renders the inventory from the tool names a harness actually registered for\n * the run — the one complete list, in the vocabulary the agent will call. */\nexport function renderToolInventory(toolNames: readonly string[]): string {\n if (toolNames.length === 0) return '';\n return `Your tools for this task: ${toolNames.join(\n ', ',\n )}. Do not look for a tool that is not listed or treat its absence as a problem to report. Later tasks in this run hold tools you do not: when your task needs one, hand that work off in your handoff for the task that can do it, or note it for the final report.`;\n}\n\nconst TASK_BASICS = `You are one step in a larger PostHog workflow made of several tasks, run as a fresh agent with no memory of the other tasks beyond the context you are given. Other tasks — before and after you — own the rest of the work, so stay strictly on your own task: do not do a neighbouring step's job, redo what an upstream handoff already did, or reach beyond what you were asked. Do only your task, then report exactly once by calling complete_task with a structured handoff: what your goal was, what you did, and what the next agent should know. When you are given context from previous steps, trust it — those agents already did their work, so do not re-verify or re-read what their handoffs tell you. Build on it and move fast. Read a file before you edit it, so your own changes do not duplicate what is already there. Work only inside this project's own directory: never read, list, or search (find, ls, grep, glob) outside it — not the OS, not other projects, not global package caches. If your task seems to need something outside this directory, it does not — skip that part and say so in your handoff rather than hunting across the filesystem. If your task does not apply to this project — there is genuinely nothing for it to do — report it with status \\`not needed\\` and say why, rather than marking it done.`;\n\nconst SEED_BASICS = `You are the orchestrator. Plan the work and seed the queue with enqueue_task — each call names the task kind in its \\`type\\` field (the tool has no \\`task\\` field) and returns an id you can pass as a dependency to a later task. Give each task a short label for the UI — the action in a few words, not file names, class names, or other specifics. The last task you queue, the one that reports on the run, must depend on every other task in the queue — directly, or through a task it already depends on. You are not a task yourself: do not call complete_task and do not edit the project.`;\n\n/**\n * Injected only when the run excludes task types (a flag or CI gate), so the\n * seed prompt of an ordinary run is byte-identical to one with no exclusions.\n * Naming the types beats a \"check the tool's list\" rule: the planner has\n * nothing to infer, and the pre-queued (runner-seeded) tasks — absent from the\n * enqueue list by design — cannot be mistaken for exclusions.\n */\nfunction excludedTypesNote(types: readonly string[]): string | null {\n if (types.length === 0) return null;\n return `The plan below may mention these task types, but this run excludes them: ${types.join(\n ', ',\n )}. enqueue_task will not accept them — do not queue them, do not retry them, and hang nothing off them.`;\n}\n\n/**\n * Tasks the wizard queued before the planner ran. It has to see them: they are\n * part of the run it is planning around, and the task that reports last has to\n * depend on them. Their ids are real, so it can wire the edge directly.\n *\n * The one-way rule matters as much as the sink edge. These tasks are deferred to\n * the end of the drain after planning (`seeded-deps.ts`) and may block on a\n * person, so a task the planner hangs off one would wait on the user too — which\n * is the interruption deferring them removed. The resolver drops such a task\n * from the seeded task's own dependencies to stay acyclic, so the damage is\n * silent; saying so here is what prevents it.\n */\nfunction preQueuedTasks(\n tasks: readonly { id: string; type: string }[],\n): string | null {\n if (tasks.length === 0) return null;\n const lines = tasks.map((t) => `- ${t.type} (id: ${t.id})`);\n return `The queue already holds these tasks, placed by the wizard from what it found in this project. Do not queue them again. They run late — after every task you queue — and one may stop to ask the user for input, so make the reporting task depend on each one and hang nothing else off them: any other task you made depend on one would end up waiting on a person.\\n${lines.join(\n '\\n',\n )}`;\n}\n\n/**\n * Points the agent at its installed task instructions (the HOW). They live under\n * the wizard's run dir, not `.claude/skills/`, so the SDK does not auto-load\n * them — the prompt has to name them.\n */\nfunction skillReference(paths: readonly string[]): string | null {\n if (paths.length === 0) return null;\n const list = paths.map((p) => `\\`${p}\\``).join(', ');\n return `Your task instructions are at ${list}. Read them before you start and follow them. They are wizard scaffolding, not part of the project.`;\n}\n\n/** A task agent's full prompt: injected basics, then the authored intent. */\nexport function assembleTaskPrompt(\n ctx: OrchestratorPromptContext,\n body: string,\n skillPaths: readonly string[] = [],\n): string {\n return [\n projectContext(ctx),\n exampleReference(ctx),\n commandmentsReference(ctx),\n skillReference(skillPaths),\n TASK_BASICS,\n body,\n ]\n .filter(Boolean)\n .join('\\n\\n');\n}\n\n/** The seed agent's full prompt: injected basics, then the authored intent. */\nexport function assembleSeedPrompt(\n ctx: OrchestratorPromptContext,\n body: string,\n preQueued: readonly { id: string; type: string }[] = [],\n excludedTypes: readonly string[] = [],\n): string {\n return [\n projectContext(ctx),\n SEED_BASICS,\n excludedTypesNote(excludedTypes),\n preQueuedTasks(preQueued),\n body,\n ]\n .filter(Boolean)\n .join('\\n\\n');\n}\n\n/** Orchestrator tools are MCP tools under the `posthog-wizard` server. Frontmatter\n * names them short (e.g. `enqueue_task`); the SDK gates on the full name. */\nconst ORCHESTRATOR_TOOL_PREFIX = 'mcp__posthog-wizard__';\nconst ORCHESTRATOR_TOOLS = new Set([\n 'enqueue_task',\n 'complete_task',\n 'read_handoffs',\n]);\n\n/** The one tool that stops a task until a person answers. Named short in frontmatter. */\nexport const ASK_TOOL = 'wizard_ask';\n\n/** The skill-menu tools, as agents ask for them in frontmatter. */\nconst SKILL_MENU_TOOL = 'load_skill_menu';\nconst INSTALL_SKILL_TOOL = 'install_skill';\n\n/**\n * The PostHog MCP, as an agent asks for it in frontmatter. Every tool a task\n * gets is granted by its own prompt, this one included: a task that never names\n * it never has the server wired in, and one that does gets it under this name\n * on both harnesses.\n */\nexport const POSTHOG_MCP_TOOL = 'posthog_exec';\n/** The same tool as the anthropic SDK names it, on the hosted PostHog server. */\nconst POSTHOG_MCP_SDK_TOOL = 'mcp__posthog-wizard__exec';\n\n/** Whether a task asked for the PostHog MCP — accepts either spelling. */\nexport function allowsPostHogMcp(\n allowedTools: readonly string[] | undefined,\n): boolean {\n return (allowedTools ?? []).some(\n (name) => name === POSTHOG_MCP_TOOL || name === POSTHOG_MCP_SDK_TOOL,\n );\n}\n\n/** The queue tools a task holds — all of them minus its disallows. Short names.\n * Single source for both the injected inventory and the harness's tool grant. */\nexport function queueTools(disallowedTools: readonly string[]): string[] {\n const disallowed = new Set(\n disallowedTools.map((n) => n.replace(ORCHESTRATOR_TOOL_PREFIX, '')),\n );\n return [...ORCHESTRATOR_TOOLS].filter((t) => !disallowed.has(t));\n}\n\n/** A parsed agent prompt. The frontmatter fields plus the markdown body. */\nexport interface AgentPrompt {\n type: string;\n /** Human-readable title for the TUI; falls back to `type` when absent. */\n label?: string;\n /** The flow this agent belongs to (the program id, e.g. \\`posthog-integration\\`). */\n flow?: string;\n /** Marks the flow's planner: it seeds the queue and is not an enqueueable task. */\n seed: boolean;\n /** Marks a task that runs last: it must depend on every other task in the queue. */\n sink: boolean;\n /**\n * Marks a task only the wizard may queue. The planner never sees the type, so\n * whether it runs is a decision the client makes from what it detected, not\n * one an agent can reach — it can neither invent the task nor forget it.\n */\n runnerSeeded: boolean;\n /** Marks a supplementary task: terminal failure unblocks dependents and never fails the run. */\n optional: boolean;\n /** Per-harness model/effort; both profiles also require gateway admission and prompt compatibility. */\n modelPi?: string;\n effortPi?: ThinkingLevel;\n modelSdk?: string;\n effortSdk?: ThinkingLevel;\n skills: string[];\n allowedTools: string[];\n disallowedTools: string[];\n /**\n * Task types this one runs after. Read differently by the two kinds of task:\n *\n * - **Enqueueable types**: advisory. The planner authors the real graph with\n * `enqueue_task`, passing ids, and its seed prompt describes the shape it\n * should build. Nothing resolves this field for them.\n * - **`runnerSeeded` types**: authoritative. Such a task is queued before the\n * planner runs, so it cannot name ids; the runner resolves these types to\n * the ids the planner produced and applies them (see `seeded-deps.ts`).\n * Empty means \"after everything that is not the sink\".\n */\n dependsOn: string[];\n body: string;\n}\n\n/** Pi selects the pi profile; the legacy Anthropic SDK selects the sdk profile. */\nexport function promptModelFor(\n prompt: AgentPrompt,\n harness: string,\n): { model?: string; effort?: ThinkingLevel } {\n const pi = harness === 'pi';\n return {\n model: pi ? prompt.modelPi : prompt.modelSdk,\n effort: pi ? prompt.effortPi : prompt.effortSdk,\n };\n}\n\nexport interface AgentRegistry {\n /** The flow's task types — every prompt except the seed. */\n readonly types: string[];\n /** The types an agent may enqueue: `types` minus the runner-seeded ones. */\n readonly enqueueableTypes: string[];\n /** The types that run last and must depend on the whole queue. */\n readonly sinkTypes: string[];\n /** The types only the wizard queues, from what it detected before the run. */\n readonly runnerSeededTypes: string[];\n /** The types whose terminal failure must not block dependents or fail the run. */\n readonly optionalTypes: string[];\n /**\n * The excluded types this flow actually had, deduped — the honest list for\n * the seed prompt's exclusion note. An exclusion naming a type the flow\n * never carried is dropped: telling the planner it was \"excluded\" would\n * describe work that was never available.\n */\n readonly excludedTypes: string[];\n /** The flow's planner, the one prompt marked `seed: true` in its frontmatter. */\n readonly seed?: AgentPrompt;\n get(type: string): AgentPrompt | undefined;\n}\n\n/** The registry for one flow's prompts. Pure; the loader feeds it the fetched set. */\nexport function buildRegistry(\n prompts: readonly AgentPrompt[],\n flow: string,\n opts?: {\n exclude?: readonly string[];\n /** Per-stage pi model/effort overlays, keyed by task type ('seed' for the planner). Applied here — the one place prompts enter the wizard — so every downstream read sees the effective spec. */\n overrides?: Record<\n string,\n { model?: string; effort?: ThinkingLevel } | undefined\n >;\n },\n): AgentRegistry {\n // The harness can exclude task types (CI excludes dashboards). An excluded\n // type does not exist for the run: the seed cannot enqueue it and no agent\n // is ever spun up for it.\n const excluded = new Set(opts?.exclude ?? []);\n const inFlow = prompts\n .filter((p) => p.flow === flow && !excluded.has(p.type))\n .map((p) => {\n const o = opts?.overrides?.[p.seed ? 'seed' : p.type];\n if (!o) return p;\n return {\n ...p,\n modelPi: o.model ?? p.modelPi,\n effortPi: o.effort ?? p.effortPi,\n };\n });\n const byType = new Map(inFlow.map((p) => [p.type, p]));\n const tasks = inFlow.filter((p) => !p.seed);\n const flowTypes = new Set(\n prompts.filter((p) => p.flow === flow && !p.seed).map((p) => p.type),\n );\n return {\n types: tasks.map((p) => p.type),\n enqueueableTypes: tasks.filter((p) => !p.runnerSeeded).map((p) => p.type),\n sinkTypes: tasks.filter((p) => p.sink).map((p) => p.type),\n runnerSeededTypes: tasks.filter((p) => p.runnerSeeded).map((p) => p.type),\n optionalTypes: tasks.filter((p) => p.optional).map((p) => p.type),\n excludedTypes: [...excluded].filter((t) => flowTypes.has(t)),\n seed: inFlow.find((p) => p.seed),\n get: (type) => byType.get(type),\n };\n}\n\ninterface AgentMenu {\n /** `flow` arrived with context-mill's flow-scoped agents folder; older menus omit it. */\n agents: { id: string; flow?: string; downloadUrl: string }[];\n}\n\n/** A native tool passes through; an MCP tool gets its fully-qualified name. */\nfunction expandToolName(name: string): string {\n if (name === ASK_TOOL) return WIZARD_TOOL_NAMES.wizardAsk;\n if (name === SKILL_MENU_TOOL) return WIZARD_TOOL_NAMES.loadSkillMenu;\n if (name === INSTALL_SKILL_TOOL) return WIZARD_TOOL_NAMES.installSkill;\n if (name === POSTHOG_MCP_TOOL) return POSTHOG_MCP_SDK_TOOL;\n return ORCHESTRATOR_TOOLS.has(name)\n ? `${ORCHESTRATOR_TOOL_PREFIX}${name}`\n : name;\n}\n\n/** A prompt's allow/disallow lists with orchestrator tool names MCP-qualified. */\nexport function agentRunTools(prompt: AgentPrompt): {\n allowedTools: string[];\n disallowedTools: string[];\n} {\n return {\n allowedTools: prompt.allowedTools.map(expandToolName),\n disallowedTools: prompt.disallowedTools.map(expandToolName),\n };\n}\n\nfunction toStringArray(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.filter((v): v is string => typeof v === 'string');\n}\n\n/**\n * Parse the leading `---` frontmatter block and the markdown body. The\n * frontmatter is a small, known schema (scalars and inline `[a, b]` arrays), so\n * a tiny parser covers it without a YAML dependency. Inline `# comments` after a\n * value are stripped. `fallbackType` (the menu id) and `fallbackFlow` (the\n * menu entry's flow) apply when the frontmatter omits `type:`/`flow:`.\n */\nexport function parseAgentPrompt(\n text: string,\n fallbackType: string,\n fallbackFlow?: string,\n): AgentPrompt {\n const match = text.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?([\\s\\S]*)$/);\n const frontmatter = match ? match[1] : '';\n const body = (match ? match[2] : text).trim();\n\n const fields: Record<string, unknown> = {};\n for (const rawLine of frontmatter.split(/\\r?\\n/)) {\n const line = rawLine.replace(/\\s+#.*$/, '').trim();\n if (!line || line.startsWith('#')) continue;\n const kv = line.match(/^([\\w-]+):\\s*(.*)$/);\n if (!kv) continue;\n const [, key, raw] = kv;\n if (raw.startsWith('[') && raw.endsWith(']')) {\n fields[key] = raw\n .slice(1, -1)\n .split(',')\n .map((s) => s.trim().replace(/^['\"]|['\"]$/g, ''))\n .filter(Boolean);\n } else {\n fields[key] = raw.replace(/^['\"]|['\"]$/g, '');\n }\n }\n\n const str = (v: unknown) => (typeof v === 'string' ? v : undefined);\n // Effort is remote data — reject typos here so downstream carries ThinkingLevel.\n const effort = (v: unknown, key: string): ThinkingLevel | undefined => {\n if (v === undefined) return undefined;\n if (isThinkingLevel(v)) return v;\n logToFile(\n `[agent-prompt] ${fallbackType}: ignoring invalid ${key} \"${String(v)}\"`,\n );\n analytics.wizardCapture('agent prompt invalid effort', {\n task_type: fallbackType,\n key,\n value: String(v),\n });\n return undefined;\n };\n return {\n type: typeof fields.type === 'string' ? fields.type : fallbackType,\n label: typeof fields.label === 'string' ? fields.label : undefined,\n flow: typeof fields.flow === 'string' ? fields.flow : fallbackFlow,\n seed: fields.seed === 'true',\n sink: fields.sink === 'true',\n runnerSeeded: fields.runnerSeeded === 'true',\n optional: fields.optional === 'true',\n modelPi: str(fields.model_pi),\n effortPi: effort(fields.effort_pi, 'effort_pi'),\n modelSdk: str(fields.model_sdk),\n effortSdk: effort(fields.effort_sdk, 'effort_sdk'),\n skills: toStringArray(fields.skills),\n allowedTools: toStringArray(fields.allowedTools),\n disallowedTools: toStringArray(fields.disallowedTools),\n dependsOn: toStringArray(fields.dependsOn),\n body,\n };\n}\n\nasync function fetchText(url: string): Promise<string> {\n const res = await fetchWithRetry(url);\n return res.text();\n}\n\n/**\n * Fetch the agent menu and every agent prompt it lists, parse them, and build\n * the registry for one flow. Throws if the menu cannot be fetched — the\n * orchestrator cannot run without its prompts.\n */\nexport async function loadAgentRegistry(\n skillsBaseUrl: string,\n flow: string,\n opts?: Parameters<typeof buildRegistry>[2],\n): Promise<AgentRegistry> {\n const menuRaw = await fetchText(`${skillsBaseUrl}/agent-menu.json`);\n const menu = JSON.parse(menuRaw) as AgentMenu;\n\n // Menus that carry a flow per entry let us skip other flows' prompts before\n // fetching them; entries without one are fetched and filtered by their\n // frontmatter in buildRegistry, as before.\n const entries = (menu.agents ?? []).filter(\n (entry) => !entry.flow || entry.flow === flow,\n );\n const prompts = await Promise.all(\n entries.map(async (entry) => {\n const text = await fetchText(entry.downloadUrl);\n return parseAgentPrompt(text, entry.id, entry.flow);\n }),\n );\n\n return buildRegistry(prompts, flow, opts);\n}\n\n/**\n * Render a task's own inputs into a section, so a fanned-out task (e.g. one\n * `capture` per event) sees the specific thing it owns. Empty when there are none.\n */\nfunction renderInputs(task: QueuedTask): string {\n const entries = Object.entries(task.inputs ?? {});\n if (entries.length === 0) return '';\n const lines = entries.map(([k, v]) => `- ${k}: ${formatInputValue(v)}`);\n return `## Your task input\\n\\n${lines.join('\\n')}`;\n}\n\nfunction formatInputValue(value: unknown): string {\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n\n/**\n * The ids of every task `task` transitively depends on — the full upstream\n * chain, not just direct dependencies — ordered roots-first, each once. A `seen`\n * set dedupes diamonds and guards against cycles.\n */\nfunction ancestorIds(task: QueuedTask, store: QueueStore): string[] {\n const seen = new Set<string>();\n const ordered: string[] = [];\n const visit = (id: string): void => {\n if (seen.has(id)) return;\n seen.add(id);\n const t = store.get(id);\n if (!t) return;\n for (const dep of t.dependsOn) visit(dep); // ancestors before dependents\n ordered.push(id);\n };\n for (const dep of task.dependsOn) visit(dep);\n return ordered;\n}\n\n/**\n * Render the handoffs of every step `task` transitively depends on into a context\n * section, so a fresh agent sees the whole upstream chain — not just its direct\n * dependencies. Reliability over token economy: a step must never have to\n * re-discover what any ancestor already established just because an intermediate\n * handoff happened to omit it. Empty when there are no completed ancestors.\n */\nfunction renderHandoffContext(task: QueuedTask, store: QueueStore): string {\n const lines: string[] = [];\n for (const id of ancestorIds(task, store)) {\n const dep = store.get(id);\n const handoff = store.readHandoff(id);\n if (!dep || !handoff) continue;\n lines.push(`### ${dep.type}`);\n lines.push(`- did: ${handoff.did}`);\n lines.push(`- for you: ${handoff.forNextAgent}`);\n if (handoff.filesTouched?.length) {\n lines.push(`- files: ${handoff.filesTouched.join(', ')}`);\n }\n if (handoff.evidence) {\n lines.push(`- evidence: ${handoff.evidence}`);\n }\n if (handoff.assumptions) {\n lines.push(`- assumed: ${handoff.assumptions}`);\n }\n if (handoff.reportSection) {\n lines.push(`- report section:\\n${handoff.reportSection}`);\n }\n lines.push('');\n }\n if (lines.length === 0) return '';\n return `## Context from previous steps\\n\\n${lines.join('\\n')}`.trim();\n}\n\n/**\n * Resolve a queued task to its run config: the prompt body (with upstream\n * handoffs appended), the model, and the tool lists with orchestrator tool names\n * MCP-qualified. The model precedence is enqueue override, then prompt, then\n * default. Throws if no prompt is registered for the task's type.\n */\nexport function resolveTask(\n registry: AgentRegistry,\n task: QueuedTask,\n store: QueueStore,\n): ResolvedTask {\n const prompt = registry.get(task.type);\n if (!prompt) {\n throw new Error(`No agent prompt registered for task type \"${task.type}\"`);\n }\n\n const body = [\n renderInputs(task),\n prompt.body,\n renderHandoffContext(task, store),\n ]\n .filter(Boolean)\n .join('\\n\\n');\n\n return {\n ...agentRunTools(prompt),\n prompt: body,\n skills: prompt.skills,\n };\n}\n\n/** The model + effort a task runs on for a harness: enqueue override, then the\n * prompt's per-profile frontmatter; the caller's switchboard pick is the fallback. */\nexport function taskModelSpec(\n registry: AgentRegistry,\n task: QueuedTask,\n harness: string,\n): { model?: string; effort?: ThinkingLevel } {\n const picked = promptModelFor(\n registry.get(task.type) ?? EMPTY_PROMPT,\n harness,\n );\n return {\n model: task.model ?? picked.model,\n effort: picked.effort,\n };\n}\n\nconst EMPTY_PROMPT = {} as AgentPrompt;\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"analytics-B_xFshPY.js","names":["uuidv4"],"sources":["../src/shared/local-dev.ts","../src/shared/constants.ts","../src/shared/run-state.ts","../src/shared/utils/ci-flag-overrides.ts","../src/shared/utils/analytics.ts"],"sourcesContent":["/**\n * Local development targets: context-mill (skills), MCP, and PostHog. Each is\n * independently switchable — CI runs local skills against the *production* MCP\n * — with `--local-dev` as a shorthand for all three.\n *\n * `wizard mcp add --local` is unrelated: it writes a `posthog-local` entry into\n * the user's editor config rather than retargeting this run. Hence no\n * `--local` here.\n */\n\n// `CONTEXT_MILL_URL` points `--local-context-mill` at another port.\nexport const CONTEXT_MILL_LOCAL_URL =\n process.env.CONTEXT_MILL_URL || 'http://localhost:8765';\nexport const MCP_LOCAL_URL = 'http://localhost:8787/mcp';\n/** Pins the API, app, OAuth, and the LLM gateway derived from them. */\nexport const POSTHOG_LOCAL_URL = 'http://localhost:8010';\n\n/**\n * Raw yargs values. The three specific flags are declared without a `default`\n * so they stay `undefined` when absent — see `resolveLocalDev`.\n */\nexport type LocalDevFlags = {\n localDev?: boolean;\n localMcp?: boolean;\n localContextMill?: boolean;\n localPosthog?: boolean;\n};\n\nexport type ResolvedLocalDev = {\n localMcp: boolean;\n localContextMill: boolean;\n localPosthog: boolean;\n};\n\n/**\n * A specific flag beats `--local-dev` in both directions. `??` is load-bearing:\n * it falls through only on `undefined`, so giving the specific flags a yargs\n * `default: false` would silently break both the umbrella and `--no-local-mcp`.\n */\nexport function resolveLocalDev(flags: LocalDevFlags): ResolvedLocalDev {\n const umbrella = flags.localDev ?? false;\n return {\n localMcp: flags.localMcp ?? umbrella,\n localContextMill: flags.localContextMill ?? umbrella,\n localPosthog: flags.localPosthog ?? umbrella,\n };\n}\n\n/** yargs populates both spellings, so read either. */\nexport function localDevFromArgv(\n argv: Record<string, unknown>,\n): ResolvedLocalDev {\n const read = (kebab: string, camel: string): boolean | undefined => {\n const value = argv[camel] ?? argv[kebab];\n return typeof value === 'boolean' ? value : undefined;\n };\n return resolveLocalDev({\n localDev: read('local-dev', 'localDev'),\n localMcp: read('local-mcp', 'localMcp'),\n localContextMill: read('local-context-mill', 'localContextMill'),\n localPosthog: read('local-posthog', 'localPosthog'),\n });\n}\n\nconst PRODUCTION_TARGETS: ResolvedLocalDev = {\n localMcp: false,\n localContextMill: false,\n localPosthog: false,\n};\n\nlet resolved: ResolvedLocalDev | null = null;\n\n/**\n * Resolve this process's targets. Called once from the yargs middleware, which\n * covers every command and the env-var spellings alike.\n */\nexport function initLocalDev(argv: Record<string, unknown>): ResolvedLocalDev {\n resolved = localDevFromArgv(argv);\n return resolved;\n}\n\n/**\n * Where this run points. Resolved once because the flags are parsed at startup\n * and never change; threading them through state let call sites read whichever\n * field they happened to have, which is how the intro screens ended up asking\n * the MCP flag where to fetch skills.\n *\n * Uninitialized means no CLI parse ran (a direct-call test) — production.\n */\nexport function getLocalDev(): ResolvedLocalDev {\n return resolved ?? PRODUCTION_TARGETS;\n}\n\n/** Tests only. */\nexport function resetLocalDev(): void {\n resolved = null;\n}\n\ntype LocalService = {\n key: keyof ResolvedLocalDev;\n label: string;\n flag: string;\n /** Probed for reachability — any HTTP reply proves the port is bound. */\n url: string;\n startHint: string;\n};\n\nconst LOCAL_SERVICES: readonly LocalService[] = [\n {\n key: 'localContextMill',\n label: 'context-mill',\n flag: '--local-context-mill',\n url: `${CONTEXT_MILL_LOCAL_URL}/skill-menu.json`,\n startHint: 'npm run dev (in the context-mill repo)',\n },\n {\n key: 'localMcp',\n label: 'MCP server',\n flag: '--local-mcp',\n url: MCP_LOCAL_URL,\n startHint:\n 'hogli start (or pnpm dev:local-resources in posthog/services/mcp)',\n },\n {\n key: 'localPosthog',\n label: 'PostHog',\n flag: '--local-posthog',\n url: POSTHOG_LOCAL_URL,\n startHint: './bin/start (in the posthog repo)',\n },\n] as const;\n\n// Retries because this gate gates `fetchWithRetry` (see fetch-retry.ts) — a\n// blip it would ride out must not abort the run instead. A missing server\n// refuses instantly, so the retries only cost time when one is slow to answer,\n// which is exactly when they're worth paying for.\nconst PROBE_TIMEOUT_MS = 2_000;\nconst PROBE_ATTEMPTS = 3;\nconst PROBE_BACKOFF_MS = 250;\n\nasync function isReachable(url: string): Promise<boolean> {\n for (let attempt = 1; attempt <= PROBE_ATTEMPTS; attempt++) {\n try {\n // Any reply — including 404 or 405 — proves something is listening, which\n // is the only question here. Deliberately not `fetchWithRetry`: that\n // treats a non-ok status as failure, and here it is a pass.\n await fetch(url, { signal: AbortSignal.timeout(PROBE_TIMEOUT_MS) });\n return true;\n } catch {\n if (attempt < PROBE_ATTEMPTS) {\n await new Promise((r) =>\n setTimeout(r, PROBE_BACKOFF_MS * 2 ** (attempt - 1)),\n );\n }\n }\n }\n return false;\n}\n\n/**\n * Probe every service the flags asked to be local. Returns one message naming\n * each unreachable one, or undefined if all are up (or none were requested).\n *\n * Without this a dead local server surfaces late and badly: a missing\n * context-mill looks like a registry outage, a missing MCP fails mid-run after\n * the agent has already edited files.\n */\nexport async function checkLocalServices(\n resolved: ResolvedLocalDev,\n): Promise<string | undefined> {\n const requested = LOCAL_SERVICES.filter((s) => resolved[s.key]);\n if (requested.length === 0) return undefined;\n\n const reachable = await Promise.all(requested.map((s) => isReachable(s.url)));\n const dead = requested.filter((_, i) => !reachable[i]);\n if (dead.length === 0) return undefined;\n\n return [\n `Local ${dead.length === 1 ? 'service is' : 'services are'} not running:`,\n '',\n ...dead.map(\n (s) =>\n ` ${s.label} — nothing listening at ${new URL(s.url).origin}\\n` +\n ` requested by ${s.flag}\\n` +\n ` start it with: ${s.startHint}`,\n ),\n '',\n 'Start the missing services, or drop the flag to use production.',\n ].join('\\n');\n}\n\n/**\n * `--local-mcp` used to select local skills too; anyone still relying on that\n * would silently get production skills. Temporary — drop after a release or two.\n */\nexport function localMcpSkillsNotice(flags: LocalDevFlags): string | undefined {\n if (flags.localMcp !== true) return undefined;\n if (flags.localContextMill !== undefined || flags.localDev === true) {\n return undefined;\n }\n return (\n '--local-mcp now points only at the local MCP server. ' +\n 'For local skills, add --local-context-mill (or use --local-dev for both).'\n );\n}\n","/**\n * Shared constants for the PostHog wizard.\n */\n\nimport { VERSION } from './version';\n\n// ── Models ──────────────────────────────────────────────────────────\n// Coordinate IDs/efforts with the mint allowlists and gateway transport/required prompt policy; see agent/runner/README.md.\n\n/** Next sonnet generation (a `MODEL_FLAG_VARIANTS` key in the switchboard). */\nexport const SONNET_5_MODEL = 'claude-sonnet-5';\n\n/**\n * Default model for agent runs. Bare model IDs (no `anthropic/` prefix) so the\n * LLM gateway's Bedrock fallback can match map_to_bedrock_model().\n */\nexport const DEFAULT_AGENT_MODEL = SONNET_5_MODEL;\n\n/** Undated haiku, for scan triage. The alias tracks the current 4.5 release rather than pinning one. */\nexport const HAIKU_TRIAGE_MODEL = 'claude-haiku-4-5';\n\n/**\n * Cheaper, faster model for mechanical agent work (e.g. repo classification\n * during source-map detection). Passed via AgentConfig.modelOverride.\n */\nexport const HAIKU_MODEL = HAIKU_TRIAGE_MODEL;\n\n// Locally supported OpenAI models; constants alone do not authorize gateway use.\nexport const GPT5_6_LUNA_MODEL = 'openai/gpt-5.6-luna';\nexport const GPT5_6_TERRA_MODEL = 'openai/gpt-5.6-terra';\nexport const GPT5_6_SOL_MODEL = 'openai/gpt-5.6-sol';\n\n// ── Agent runner routing axes ────────────────────────────────────────\n\n/**\n * The two agent runner routing axes: **harness** (which agent SDK drives the LLM)\n * and **sequence** (which pipeline shape orchestrates the work). Single source\n * of truth for yargs `choices`, session fields, the runner registry, and tests\n * — `Object.values(Harness)` gives an iterable of the values when an array is\n * needed. Adding a member is enough to pick it up everywhere.\n *\n * Naming matches the directory layout — see `src/agent/runner/harness/`\n * and `src/agent/runner/sequence/`.\n */\nexport enum Harness {\n anthropic = 'anthropic',\n pi = 'pi',\n}\n\nexport enum Sequence {\n linear = 'linear',\n orchestrator = 'orchestrator',\n}\n\n/**\n * What kind of call produced a gateway generation — the `call_type` trace tag.\n * Splits a program's LLM spend by workload. Every member is sent explicitly so\n * an absent value means \"old build\", not \"agent\".\n */\nexport enum CallType {\n /** The agent doing the work the user asked for. */\n agent = 'agent',\n /** Warlock's classifier deciding whether a YARA match is a true positive. */\n yaraTriage = 'yara-triage',\n /** The cheap repo scan that classifies which projects a program acts on. */\n detection = 'detection',\n}\n\n// ── Integration / CLI ───────────────────────────────────────────────\n\n/**\n * Detection order matters: put framework-specific integrations BEFORE basic language fallbacks.\n */\nexport enum Integration {\n // Frameworks\n nextjs = 'nextjs',\n nuxt = 'nuxt',\n vue = 'vue',\n reactRouter = 'react-router',\n tanstackStart = 'tanstack-start',\n tanstackRouter = 'tanstack-router',\n reactNative = 'react-native',\n angular = 'angular',\n astro = 'astro',\n django = 'django',\n flask = 'flask',\n fastapi = 'fastapi',\n laravel = 'laravel',\n sveltekit = 'sveltekit',\n flutter = 'flutter',\n kmp = 'kmp',\n swift = 'swift',\n android = 'android',\n rails = 'rails',\n elixir = 'elixir',\n go = 'go',\n rust = 'rust',\n // Must stay after kmp/swift/android: those claim gradle projects first.\n java = 'java',\n\n // Language fallbacks. Keep javascriptNode last: it matches any package.json.\n python = 'python',\n ruby = 'ruby',\n javascript_web = 'javascript_web',\n javascriptNode = 'javascript_node',\n}\n\n/**\n * The platforms session replay can actually record on. Replay vision watches\n * recordings, so a platform with no recordings has nothing to set up — the\n * run must stop before any work, not after a pointless agent run.\n *\n * Web frameworks record through posthog-js (server-rendered frameworks\n * included — they serve pages), and the mobile SDKs with replay support are\n * React Native, Android, iOS, and Flutter. Excluded: pure backend targets\n * (`javascript_node`, `python`, `ruby`) and KMP, which has no replay support\n * yet.\n */\nexport const REPLAY_VISION_SUPPORTED: ReadonlySet<Integration> = new Set([\n Integration.nextjs,\n Integration.nuxt,\n Integration.vue,\n Integration.reactRouter,\n Integration.tanstackStart,\n Integration.tanstackRouter,\n Integration.angular,\n Integration.astro,\n Integration.sveltekit,\n Integration.javascript_web,\n Integration.django,\n Integration.flask,\n Integration.fastapi,\n Integration.laravel,\n Integration.rails,\n Integration.reactNative,\n Integration.android,\n Integration.swift,\n Integration.flutter,\n]);\n\n// ── Documents the wizard's programs write into the user's project ────\n// Named here so the scanner's documentation allowlist can list them without\n// importing a program; each program re-exports its own.\n/** The events-audit report. */\nexport const EVENTS_AUDIT_REPORT_FILE = 'posthog-events-audit-report.md';\nexport const EVENT_INVENTORY_FILE = '.posthog-events-inventory.json';\n/** Per-part filename pattern emitted by events-audit subagents (e.g. `.posthog-events-inventory.part-3.json`). */\nexport const EVENT_INVENTORY_PART_PATTERN =\n /^\\.posthog-events-inventory\\.part-\\d+\\.json$/;\n/** The integration program's event plan. */\nexport const EVENT_PLAN_FILE = '.posthog-events.json';\n/** The integration program's setup report; Self-driving reads it as a hint. */\nexport const SETUP_REPORT_FILE = 'posthog-setup-report.md';\n\nexport interface Args {\n debug: boolean;\n integration: Integration;\n}\n\n// ── Environment ──────────────────────────────────────────────────────\n\nimport { IS_DEV } from '@env';\nimport {\n CONTEXT_MILL_LOCAL_URL,\n getLocalDev,\n POSTHOG_LOCAL_URL,\n} from './local-dev';\nexport { IS_DEV };\nexport const DEBUG = false;\n\n// ── URLs ─────────────────────────────────────────────────────────────\n\nexport const DEFAULT_URL = IS_DEV\n ? POSTHOG_LOCAL_URL\n : 'https://us.posthog.com';\n/**\n * Region-agnostic PostHog app URL. Resolves to us.posthog.com or\n * eu.posthog.com server-side based on the signed-in user's profile.\n * Use this for share-with-user links (e.g. settings pages) so they\n * land on the right region without us needing to know it client-side.\n */\nexport const POSTHOG_APP_URL = IS_DEV\n ? POSTHOG_LOCAL_URL\n : 'https://app.posthog.com';\nexport const DEFAULT_HOST_URL = IS_DEV\n ? POSTHOG_LOCAL_URL\n : 'https://us.i.posthog.com';\nexport const ISSUES_URL = 'https://github.com/posthog/wizard/issues';\n/** Public status page, linked from transient-failure guidance (e.g. OAuth server_error). */\nexport const POSTHOG_STATUS_PAGE_URL = 'https://www.posthogstatus.com';\nexport const CONTEXT_MILL_URL = 'https://github.com/PostHog/context-mill';\n/**\n * Latest context-mill release page — the BYOAI download link shown in\n * the privacy panel. Deliberately the release PAGE, not a direct asset\n * URL: asset URLs are ~89 chars and hard-wrap inside the 64-col panel,\n * which corrupts terminal copy/paste with a mid-URL line break. This\n * stays under one line; the panel names the exact asset to grab.\n */\nexport const CONTEXT_MILL_RELEASES_URL =\n 'https://github.com/PostHog/context-mill/releases/latest';\nexport const POSTHOG_DOCS_URL = 'https://posthog.com/docs';\nexport const POSTHOG_WIZARD_REPO_URL = 'https://github.com/PostHog/wizard';\nexport const POSTHOG_TERMS_URL = 'https://posthog.com/terms';\nexport const POSTHOG_PRIVACY_URL = 'https://posthog.com/privacy';\nexport const POSTHOG_ORG_AI_SETTINGS_URL =\n 'https://app.posthog.com/settings/organization-details#setting=organization-ai-consent';\nexport const WIZARD_CONTACT_EMAIL = 'wizard@posthog.com';\n\n/**\n * Two origins for the same release, same filenames. Interchangeable bases, so\n * making AWS primary is a `getSkillsBaseUrl` change, not a code change.\n */\nexport const GITHUB_SKILLS_BASE_URL =\n 'https://github.com/PostHog/context-mill/releases/latest/download';\nexport const AWS_SKILLS_BASE_URL = 'https://context-mill.posthog.com/latest';\n/** Alias of `@shared/local-dev`'s constant, kept for existing importers. */\nexport const LOCAL_SKILLS_BASE_URL = CONTEXT_MILL_LOCAL_URL;\n\n/**\n * Driven by `--local-context-mill`, NOT `--local-mcp` (which used to select\n * both). Takes no argument on purpose: callers can't pass the wrong flag.\n */\nexport function getSkillsBaseUrl(): string {\n return getLocalDev().localContextMill\n ? LOCAL_SKILLS_BASE_URL\n : GITHUB_SKILLS_BASE_URL;\n}\n\n// ── Analytics (internal) ──────────────────────────────────────────────\n\nexport const ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY = 'sTMFPsFhdP1Ssg';\nexport const ANALYTICS_HOST_URL = 'https://internal-j.posthog.com';\nexport const ANALYTICS_TEAM_TAG = 'docs-and-wizard';\n\n// ── OAuth / Auth ────────────────────────────────────────────────────\n\nexport const OAUTH_PORTS = [8239, 8238, 8240, 8237, 8236, 8235] as const;\nexport const POSTHOG_US_CLIENT_ID = 'c4Rdw8DIxgtQfA80IiSnGKlNX8QN00cFWF00QQhM';\nexport const POSTHOG_EU_CLIENT_ID = 'bx2C5sZRN03TkdjraCcetvQFPGH6N2Y9vRLkcKEy';\nexport const POSTHOG_DEV_CLIENT_ID = 'DC5uRLVbGI02YQ82grxgnK6Qn12SXWpCqdPb60oZ';\nexport const POSTHOG_PROXY_CLIENT_ID = POSTHOG_US_CLIENT_ID;\nexport const DUMMY_PROJECT_API_KEY = '_YOUR_POSTHOG_PROJECT_TOKEN_';\n\n/**\n * Scopes the wizard requests during the agentic provisioning signup flow.\n *\n * Each entry is justified by what the wizard's agent step does after signup:\n * - user:read identify the user for analytics + agent context\n * - project:read look up the freshly-provisioned project\n * - llm_gateway:read authenticate to gateway.{us,eu}.posthog.com/wizard\n * (the agent's LLM calls — without this scope, every\n * agent message returns 401)\n * - query:read run HogQL queries when the agent needs data\n * - dashboard:write create the onboarding dashboard during setup\n * - insight:write create the onboarding insights during setup\n * - notebook:write upload the events-audit report as a PostHog notebook\n * in step 6 of the events-audit skill (notebooks-create\n * MCP tool requires this scope), and mirror the handoff\n * report into a notebook (`publish_handoff`)\n * - event_definition:write\n * create event definitions from the completed wizard\n * session's event plan\n *\n * Must be a subset of `ALLOWED_PROVISIONING_SCOPES` in\n * `ee/api/agentic_provisioning/views.py` on the backend.\n */\nexport const WIZARD_PROVISIONING_SCOPES = [\n 'user:read',\n 'project:read',\n 'llm_gateway:read',\n 'dashboard:write',\n 'insight:write',\n 'query:read',\n 'notebook:write',\n 'event_definition:write',\n] as const;\n\n/**\n * Scopes the wizard requests during the OAuth login flow. Superset of\n * `WIZARD_PROVISIONING_SCOPES` with scopes that only apply to the login\n * path and are not in the provisioning allowlist:\n * - health_issue:read used by `wizard doctor`\n * - wizard_session:read list / retrieve / stream sessions\n * - wizard_session:write stream run state to /api/projects/{id}/wizard/sessions/\n * - event_definition:write\n * create event definitions when a session completes\n * - organization:read read `organization.is_ai_data_processing_approved`\n * from /api/users/@me/ for the AI opt-in gate\n *\n * NOTE: every scope here must be within the wizard OAuth application's\n * server-side scope ceiling (`OAuthApplication.scopes` in posthog, set\n * via Django admin on BOTH prod regions). A scope outside the ceiling\n * does NOT fail the authorize request — the server silently clamps the\n * request to the ceiling (`clamp_scopes_to_ceiling` in posthog) and the\n * token comes back without it. Separately, the consent screen lets the\n * user deselect any scope the app doesn't mark required. Both paths\n * yield a granted `scope` narrower than requested, with no error, so\n * never assume the token carries this list — the token response's\n * `scope` field is the truth, and `missingOAuthScopes` (utils/oauth.ts)\n * diffs it at login. Ceiling procedure: the \"scope-ceiling-invalid-scope\"\n * runbook in PostHog/runbooks. Keep its worked example in sync when this\n * list changes.\n */\nexport const WIZARD_OAUTH_SCOPES = [\n ...WIZARD_PROVISIONING_SCOPES,\n 'health_issue:read',\n 'wizard_session:read',\n 'wizard_session:write',\n 'wizard_run:write',\n 'organization:read',\n] as const;\n\n// ── Wizard run / variants ───────────────────────────────────────────\n\nexport const WIZARD_INTERACTION_EVENT_NAME = 'wizard interaction';\nexport const WIZARD_REMARK_EVENT_NAME = 'wizard remark';\n/** Multivariate flag: `wizard-run` publishes to WizardRun, anything else to WizardSession. */\nexport const WIZARD_RUN_SYNC_FLAG_KEY = 'wizard-run-sync';\n/** Boolean feature flag that routes a run to the experimental orchestrator runner. */\nexport const WIZARD_ORCHESTRATOR_FLAG_KEY = 'wizard-orchestrator';\n/** Multivariate flag: per-stage orchestrator overrides ride each variant's JSON payload (`{stage: {model?, effort?}}`). */\nexport const WIZARD_ORCHESTRATOR_OVERRIDE_FLAG_KEY =\n 'wizard-orchestrator-override';\n/** Boolean flag: on → pi for self-driving. Payload carries `{model, effort?, harness?, sequence?}` (model = a `MODEL_FLAG_VARIANTS` key); missing/invalid payload keeps the non-flagged default. */\nexport const WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY =\n 'wizard-self-driving-use-pi-harness';\n/** Boolean flag: agentic project scoping for non-interactive basic-integration runs. */\nexport const WIZARD_BASIC_INTEGRATION_AGENTIC_DETECTION_FLAG_KEY =\n 'wizard-basic-integration-agentic-detection';\n/** Boolean flag: the orchestrator queues the program's runner-seeded tasks (the warehouse step). Off, no task is queued and the run is byte-identical to a no-sources project. */\nexport const WIZARD_ORCHESTRATOR_SEEDED_TASKS_FLAG_KEY =\n 'wizard-orchestrator-seeded-tasks';\n/** Kill switch over a shipped default: ONLY an explicit 'false' excludes the AI Observability and Logs tasks from default integration runs — absent or fetch-failed means include, so the default never vanishes on a network hiccup. */\nexport const WIZARD_DEFAULT_AIO_LOGS_FLAG_KEY = 'wizard-default-aio-logs';\n// Reading a flag enters this run into that flag's experiment, so a closed set — not a\n// `wizard-` prefix anyone can name into — decides what a run evaluates. Test-pinned exhaustive.\nexport const WIZARD_FLAG_KEYS = [\n WIZARD_RUN_SYNC_FLAG_KEY,\n WIZARD_ORCHESTRATOR_FLAG_KEY,\n WIZARD_ORCHESTRATOR_OVERRIDE_FLAG_KEY,\n WIZARD_ORCHESTRATOR_SEEDED_TASKS_FLAG_KEY,\n WIZARD_SELF_DRIVING_USE_PI_HARNESS_FLAG_KEY,\n WIZARD_BASIC_INTEGRATION_AGENTIC_DETECTION_FLAG_KEY,\n WIZARD_DEFAULT_AIO_LOGS_FLAG_KEY,\n] as const;\n/** User-Agent for wizard HTTP requests and MCP server identification. */\nexport const WIZARD_USER_AGENT = `posthog/wizard; version: ${VERSION}`;\n\n/**\n * User-Agent for a specific program's MCP calls, tagged with `program: <id>` so the\n * backend can attribute work per program (e.g. the `self-driving` program's warehouse\n * sources are recorded as `created_via=self_driving` rather than plain `wizard`). The\n * base `posthog/wizard` token is preserved, so anything keying only on that still matches.\n */\nexport function wizardUserAgentForProgram(programId?: string): string {\n return programId\n ? `${WIZARD_USER_AGENT}; program: ${programId}`\n : WIZARD_USER_AGENT;\n}\n\n// ── Timeouts ─────────────────────────────────────────────────────────\n\n/** Timeout for framework / project detection probes (ms). */\nexport const DETECTION_TIMEOUT_MS = 10_000;\n\n/** Timeout for the agentic project scan (ms); past it the run falls back to root detection. */\nexport const AGENTIC_DETECTION_FIRST_ATTEMPT_TIMEOUT_MS = 60_000;\nexport const AGENTIC_DETECTION_RETRY_TIMEOUT_MS = 90_000;\n\n/**\n * Timeout for the OAuth authorization flow (ms).\n *\n * How long the user has to complete the browser login. The authorization\n * code is minted at approval and exchanged immediately on callback, so the\n * server-side code expiry (`AUTHORIZATION_CODE_EXPIRE_SECONDS`, 5 minutes)\n * bounds only the approval→exchange gap — manual-paste users have 5 minutes\n * from approval to submit the code — not how long this window may stay open.\n */\nexport const OAUTH_TIMEOUT_MS = 1_800_000;\n","/** Run lifecycle and consent states the TUI, the CLI and programs share. */\n\nimport type { DiscoveredFeature } from './discovered-feature';\n\n/** How an agent run ended: the agent decides it, and the programs and hosts read it. */\nexport enum RunOutcome {\n Success = 'success',\n Aborted = 'aborted',\n Failed = 'failed',\n Crashed = 'crashed',\n}\n\n/** Lifecycle phase of the main work (agent run, MCP install, etc.) */\nexport enum RunPhase {\n /** Still gathering input (intro, setup screens) */\n Idle = 'idle',\n /** Main work is in progress */\n Running = 'running',\n /** Main work finished successfully */\n Completed = 'completed',\n /** Main work finished with an error */\n Error = 'error',\n}\n\n/** Consent to report what local detection found (see `scanConsent` below). */\nexport enum ScanConsent {\n Undecided = 'undecided',\n Granted = 'granted',\n Declined = 'declined',\n}\n\n/** Outcome of the MCP server installation step */\nexport enum McpOutcome {\n NoClients = 'no_clients',\n Skipped = 'skipped',\n Installed = 'installed',\n Failed = 'failed',\n}\n\n/** One place to ask, so a new consent state does not need three edits. */\nexport function mayReportScanResults(session: {\n scanConsent: ScanConsent;\n}): boolean {\n return session.scanConsent === ScanConsent.Granted;\n}\n\n/** Lives here so analytics infrastructure never learns what consent means. */\nexport function reportableDiscoveredFeatures(session: {\n scanConsent: ScanConsent;\n discoveredFeatures: DiscoveredFeature[];\n}): DiscoveredFeature[] | undefined {\n return mayReportScanResults(session) ? session.discoveredFeatures : undefined;\n}\n\n/** Also a scan result, so it travels under the same consent as the rest. */\nexport function reportablePosthogSdkDetected(session: {\n scanConsent: ScanConsent;\n posthogSdkDetected: boolean;\n}): boolean | undefined {\n return mayReportScanResults(session) ? session.posthogSdkDetected : undefined;\n}\n","/**\n * CI-only feature-flag overrides.\n *\n * CI must route deterministically: a run that tests the orchestrator arm says\n * so explicitly instead of depending on a live feature flag someone can edit\n * mid-week. The override env var (see the allowlist in `env.ts`) is a JSON\n * object of flag key → value, merged over whatever PostHog returned.\n *\n * The override path exists only in CI builds (`pnpm build:ci`). Published\n * builds inline NODE_ENV as the literal \"production\", the guards collapse,\n * and tsdown strips the rest from the bundle — and the smoke test asserts the\n * env var names are physically absent from production output (which is also\n * why no comment in this file may spell them out), so this can never quietly\n * become a production surface.\n */\nimport { runtimeEnv } from '@env';\nimport { logToFile } from './debug';\n\nexport function applyCiFlagOverrides(\n flags: Record<string, string>,\n payloads: Record<string, unknown> = {},\n): { flags: Record<string, string>; payloads: Record<string, unknown> } {\n // Compared inline (not via env.ts's IS_PRODUCTION_BUILD) so tsdown replaces\n // it with a literal right here and the bundler can prove the rest of this\n // function unreachable in production builds. The smoke test enforces that.\n if (process.env.NODE_ENV === 'production') return { flags, payloads };\n\n const raw = runtimeEnv('WIZARD_CI_FLAG_OVERRIDES');\n if (!raw) return { flags, payloads };\n\n let overrides: Record<string, unknown>;\n try {\n overrides = JSON.parse(raw) as Record<string, unknown>;\n } catch {\n // A malformed override is a CI misconfiguration. Fail the run loudly\n // rather than silently testing whatever the live flags happen to say.\n throw new Error(\n 'The CI flag-override env var is not valid JSON (expected {\"flag-key\": value, ...}).',\n );\n }\n\n const mergedFlags = { ...flags };\n const mergedPayloads = { ...payloads };\n for (const [key, value] of Object.entries(overrides)) {\n // An object/array override is a flag payload: the flag reads 'true' and\n // the value rides the payload channel, matching a payload-carrying flag.\n if (typeof value === 'object' && value !== null) {\n mergedFlags[key] = 'true';\n mergedPayloads[key] = value;\n } else {\n mergedFlags[key] = String(value);\n }\n }\n logToFile('[flags] CI overrides applied', overrides);\n return { flags: mergedFlags, payloads: mergedPayloads };\n}\n\n/**\n * Task types excluded from this run. The exclusion env var (see the allowlist\n * in `env.ts`) is a comma-separated list (e.g. `dashboard`), set by the CI\n * harness that owns the policy — the wizard and the served content stay\n * run-mode agnostic. CI-build only, same as the flag overrides: published\n * builds strip this path.\n */\nexport function ciExcludedTaskTypes(): readonly string[] {\n if (process.env.NODE_ENV === 'production') return [];\n\n const raw = runtimeEnv('WIZARD_CI_EXCLUDE_TASKS');\n if (!raw) return [];\n const types = raw\n .split(',')\n .map((t) => t.trim())\n .filter(Boolean);\n if (types.length > 0) logToFile('[flags] CI task exclusions', types);\n return types;\n}\n","import { PostHog } from 'posthog-node';\nimport {\n ANALYTICS_HOST_URL,\n ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY,\n ANALYTICS_TEAM_TAG,\n WIZARD_FLAG_KEYS,\n} from '@shared/constants';\nimport {\n reportableDiscoveredFeatures,\n reportablePosthogSdkDetected,\n type RunPhase,\n type ScanConsent,\n} from '@shared/run-state';\nimport type { DiscoveredFeature } from '@shared/discovered-feature';\nimport type { Integration } from '@shared/constants';\nimport type { ApiUser } from '@shared/api';\nimport { v4 as uuidv4 } from 'uuid';\nimport { IS_PRODUCTION_BUILD, RUN_SURFACE, TASK_ID, TASK_RUN_ID } from '@env';\nimport { VERSION } from '@shared/version';\nimport { WizardError } from '@shared/errors';\nimport { logToFile } from './debug';\nimport { applyCiFlagOverrides } from './ci-flag-overrides';\n\n/**\n * The invocation, reduced to flag-safe strings: the command word (first\n * positional, 'default' for the bare flow) and the sorted option NAMES.\n * Option values never leave the machine — they carry paths, emails, keys.\n */\nfunction invocationProperties(): { command: string; cli_flags: string } {\n const args = process.argv.slice(2);\n const command = args.find((a) => !a.startsWith('-')) ?? 'default';\n const flags = [\n ...new Set(\n args\n .filter((a) => a.startsWith('--'))\n .map((a) => a.slice(2).split('=')[0]),\n ),\n ].sort();\n return { command, cli_flags: flags.join(',') };\n}\n\n/** The session facts analytics reports on every capture. */\nexport type SessionFacts = {\n integration: Integration | null;\n skillId: string | null;\n detectedFrameworkLabel: string | null;\n typescript: boolean;\n credentials: { projectId: number } | null;\n discoveredFeatures: DiscoveredFeature[];\n scanConsent: ScanConsent;\n runPhase: RunPhase;\n posthogSdkDetected: boolean;\n};\n\n/**\n * Extract a standard property bag from the current session.\n * Used by store-level analytics and available for ad-hoc captures.\n */\nexport function sessionProperties(\n session: SessionFacts,\n): Record<string, unknown> {\n // reportableDiscoveredFeatures() owns the consent decision; this file\n // never needs to know what `scanConsent` means, only that the result\n // might be absent. An absent key is unambiguous, while an empty array\n // would read as \"we looked and found nothing\" instead of \"not reported\".\n const discoveredFeatures = reportableDiscoveredFeatures(session);\n const posthogSdkDetected = reportablePosthogSdkDetected(session);\n\n return {\n integration: session.integration,\n // Discriminates a family leaf: `command` is the first positional, so every\n // `wizard audit <leaf>` reports the same `audit`.\n skill_id: session.skillId,\n detected_framework: session.detectedFrameworkLabel,\n typescript: session.typescript,\n project_id: session.credentials?.projectId,\n ...(discoveredFeatures !== undefined\n ? { discovered_features: discoveredFeatures }\n : {}),\n scan_consent: session.scanConsent,\n run_phase: session.runPhase,\n ...(posthogSdkDetected !== undefined\n ? { posthog_sdk_detected: posthogSdkDetected }\n : {}),\n };\n}\n\nexport function groupsFromUser(\n user: ApiUser | null,\n host: string,\n): Record<string, string> {\n const groups: Record<string, string> = { instance: host };\n if (!user) return groups;\n\n const organizationId = user.organization?.id;\n if (organizationId) groups.organization = organizationId;\n\n const customerId = user.organization?.customer_id;\n if (customerId) groups.customer = customerId;\n\n const projectUuid = user.team?.uuid;\n if (projectUuid) groups.project = projectUuid;\n\n return groups;\n}\n\nconst WIZARD_FLAGS: ReadonlySet<string> = new Set(WIZARD_FLAG_KEYS);\n\n// Widen back to the SDK's shape — a filter on `true` never matches `'true'`.\nfunction flagResponseValue(value: string): string | boolean {\n if (value === 'true') return true;\n if (value === 'false') return false;\n return value;\n}\n\nexport class Analytics {\n private client: PostHog;\n private tags: Record<string, string | boolean | number | null | undefined> =\n {};\n private distinctId?: string;\n private anonymousId: string;\n private _runId: string;\n private sessionId: string | null = null;\n private appName = 'wizard';\n private activeFlags: Record<string, string> | null = null;\n private activeFlagPayloads: Record<string, unknown> = {};\n private groups: Record<string, string> = {};\n private personProperties: Record<string, string> = {};\n private terminalEventSent = false;\n\n constructor() {\n this.client = new PostHog(ANALYTICS_POSTHOG_PUBLIC_PROJECT_WRITE_KEY, {\n host: ANALYTICS_HOST_URL,\n flushAt: 1,\n flushInterval: 0,\n enableExceptionAutocapture: true,\n before_send: (event) => {\n if (!event) return event;\n if (Object.keys(this.groups).length > 0) {\n event.groups = { ...this.groups, ...event.groups };\n }\n // Autocaptured exceptions arrive with a random uuid and\n // `$process_person_profile: false` — reattach the run's identity\n // and tags so they land on the same person as everything else.\n if (event.event === '$exception') {\n event.distinctId = this.distinctId ?? this.anonymousId;\n const { $process_person_profile, ...properties } =\n event.properties ?? {};\n void $process_person_profile;\n event.properties = { ...this.tags, ...properties };\n }\n // The SDK captures this one itself, bypassing capture(), so tags merge here.\n if (event.event === '$feature_flag_called') {\n event.properties = { ...this.tags, ...(event.properties ?? {}) };\n }\n return event;\n },\n });\n\n this.tags = { $app_name: this.appName };\n // Tag every run with its build type so prod / dev / ci / headless segment\n // cleanly in analytics. tsdown inlines IS_PRODUCTION_BUILD to `true` in\n // published builds and `false` for dev/tsx/test runs. Non-interactive runs\n // upgrade this in runWizardCI: dev `--ci` runs to 'ci', published headless\n // runs to 'headless'.\n this.tags.build = IS_PRODUCTION_BUILD ? 'prod' : 'dev';\n\n this.tags.run_surface = RUN_SURFACE;\n\n // The build this run came from. Already sent as a flag-evaluation person\n // property; tagging it makes every event attributable to a release, so a\n // regression can be bounded to the versions that carry it.\n this.tags.version = VERSION;\n\n // Cloud runs only: the task run that owns the sandbox. Without these the\n // wizard's events and the run that launched it are two unrelated streams,\n // since run_id above is minted per process and never leaves the wizard.\n // Left unset for local runs so the properties stay absent rather than null.\n if (TASK_RUN_ID) this.tags.task_run_id = TASK_RUN_ID;\n if (TASK_ID) this.tags.task_id = TASK_ID;\n\n this.anonymousId = uuidv4();\n\n // One id per process = one id per wizard run, registered in the tag bag\n // so it rides on every capture, exception, and autocaptured exception\n // (all of which merge `this.tags`). Lets you separate two runs by the\n // same logged-in user, who otherwise share one distinct id. Distinct\n // from `anonymousId`, the pre-login *person* id that gets aliased onto\n // the real user at login. `$session_id` is intentionally not set here —\n // it stays null until OAuth completes (see identifyUser).\n this._runId = uuidv4();\n this.tags.run_id = this._runId;\n\n this.distinctId = undefined;\n }\n\n /** Per-process run id, tagged on every event and gateway trace. */\n get runId(): string {\n return this._runId;\n }\n\n /** Build type for this run ('prod' | 'dev' | 'ci' | 'headless') — the same value tagged on every analytics event. */\n get build(): string {\n return String(this.tags.build ?? 'dev');\n }\n\n /**\n * Associate the run with the logged-in user, once per id. Identifies them\n * (email, name) and records those person properties so events carry them and\n * feature flags can target the individual user — without the email here the\n * wizard only sends `$app_name`, so email-targeted flags never match. Opens\n * the analytics session on first login, then aliases the run's anonymous id\n * onto the identified person so pre-login events merge in.\n */\n identifyUser(user: ApiUser) {\n const distinctId = user.distinct_id;\n if (this.distinctId === distinctId || distinctId === this.anonymousId) {\n return;\n }\n this.distinctId = distinctId;\n // Open the analytics session on first login. Null until here, so\n // pre-OAuth events carry only `run_id`; from now on every event also\n // carries `$session_id` and PostHog groups the authenticated run into a\n // native Session. Stored in the tag bag so it rides on every subsequent\n // capture and exception.\n if (!this.sessionId) {\n this.sessionId = uuidv4();\n this.tags.$session_id = this.sessionId;\n }\n const props: Record<string, string> = {};\n if (user.email) props.email = user.email;\n const name = [user.first_name, user.last_name]\n .filter(Boolean)\n .join(' ')\n .trim();\n if (name) props.name = name;\n this.personProperties = props;\n this.client.identify({ distinctId, properties: { $set: props } });\n this.client.alias({\n distinctId,\n alias: this.anonymousId,\n });\n // The flag snapshot is per identity. Anything evaluated before login (the\n // intro screen reads the tools-menu flag) was anonymous — drop it so the\n // next read re-evaluates as this user.\n this.activeFlags = null;\n this.activeFlagPayloads = {};\n }\n\n /** Person properties sent with flag evaluation: app name plus the user's. */\n private flagPersonProperties(): Record<string, string> {\n // Environment facts flag conditions can scope on — evaluation-time only,\n // never persisted onto the person. `version` gates an experiment to\n // releases that implement it (a condition on a property older builds\n // don't send silently never matches them); `run_surface`/`build` scope\n // by invocation surface; `command`/`cli_flags` by subcommand; `os`/\n // `node_major` by platform.\n return {\n $app_name: this.appName,\n version: VERSION,\n run_surface: RUN_SURFACE,\n build: String(this.tags.build ?? 'dev'),\n os: process.platform,\n node_major: process.versions.node.split('.')[0],\n ...invocationProperties(),\n ...this.personProperties,\n };\n }\n\n setTag(key: string, value: string | boolean | number | null | undefined) {\n this.tags[key] = value;\n }\n\n setGroups(groups: Record<string, string>) {\n this.groups = groups;\n }\n\n captureException(error: Error, properties: Record<string, unknown> = {}) {\n const code =\n (error instanceof WizardError && error.code) ||\n (typeof properties.error_code === 'string' ? properties.error_code : '');\n this.client.captureException(error, this.distinctId ?? this.anonymousId, {\n team: ANALYTICS_TEAM_TAG,\n // One issue per error code: the stack's install path and chunk hash otherwise split it per route and release.\n ...(code ? { $exception_fingerprint: `wizard_${code}` } : {}),\n ...this.tags,\n ...properties,\n });\n }\n\n capture(eventName: string, properties?: Record<string, unknown>) {\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: eventName,\n properties: {\n ...this.tags,\n ...this.wizardFlagFeatureProperties(),\n ...properties,\n },\n });\n }\n\n groupIdentify(\n groupType: string,\n groupKey: string,\n properties: Record<string, unknown>,\n ) {\n this.client.groupIdentify({ groupType, groupKey, properties });\n }\n\n // Built from the resolved map, not the SDK snapshot: a CI-forced variant must own its events.\n private wizardFlagFeatureProperties(): Record<string, unknown> {\n if (this.activeFlags === null) return {};\n const props: Record<string, unknown> = {};\n const active: string[] = [];\n for (const [key, value] of Object.entries(this.activeFlags)) {\n if (!WIZARD_FLAGS.has(key)) continue;\n const resolved = flagResponseValue(value);\n props[`$feature/${key}`] = resolved;\n if (resolved !== false) active.push(key);\n }\n if (active.length > 0) props.$active_feature_flags = active.sort();\n return props;\n }\n\n /**\n * Capture a wizard-specific event. Automatically prepends \"wizard: \" to the event name.\n * All new wizard analytics should use this method instead of capture() directly.\n */\n wizardCapture(eventName: string, properties?: Record<string, unknown>): void {\n this.capture(`wizard: ${eventName}`, properties);\n }\n\n /**\n * Flush pending events without firing the \"setup wizard finished\" terminal\n * event. Use this from CLI error paths that exit before any wizard run\n * starts — `shutdown()` would inflate the run count with a \"finished\" event\n * for a parse error that never actually ran the wizard.\n */\n async flush(): Promise<void> {\n await this.client.shutdown();\n }\n\n /**\n * Evaluate all feature flags for the current user at the start of a run.\n * Result is cached; subsequent calls in the same run return the same map.\n * Returns flag key -> string value (booleans become 'true'/'false').\n */\n // Only a getFlag read records an exposure; the bulk response records none.\n async getAllFlagsForWizard(): Promise<Record<string, string>> {\n if (this.activeFlags !== null) {\n return this.activeFlags;\n }\n const out: Record<string, string> = {};\n const payloads: Record<string, unknown> = {};\n try {\n const distinctId = this.distinctId ?? this.anonymousId;\n logToFile('[flags] evaluating as', {\n distinctId,\n identified: this.distinctId !== undefined,\n personProperties: this.flagPersonProperties(),\n });\n const evaluation = await this.client.evaluateFlags(distinctId, {\n personProperties: this.flagPersonProperties(),\n });\n for (const key of WIZARD_FLAG_KEYS) {\n const value = evaluation.getFlag(key);\n if (value === undefined) continue;\n out[key] = String(value);\n const payload = evaluation.getFlagPayload(key);\n if (payload !== undefined) payloads[key] = payload;\n }\n } catch (error) {\n logToFile('Failed to get all feature flags:', error);\n this.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'get_all_flags' },\n );\n }\n // Outside the fetch guard on purpose: a malformed CI override must fail\n // the run loudly, and a valid one applies even when the fetch failed —\n // CI routing stays deterministic either way.\n const merged = applyCiFlagOverrides(out, payloads);\n this.activeFlags = merged.flags;\n this.activeFlagPayloads = merged.payloads;\n logToFile('[flags] evaluated', this.activeFlags);\n return this.activeFlags;\n }\n\n getCachedWizardFlags(): Readonly<Record<string, string>> | null {\n return this.activeFlags;\n }\n\n /** Flag payloads from the same snapshot; empty until the flags are fetched. */\n getWizardFlagPayloads(): Record<string, unknown> {\n return this.activeFlagPayloads;\n }\n\n async shutdown(status: 'success' | 'error' | 'cancelled') {\n if (Object.keys(this.tags).length === 0) {\n return;\n }\n\n // First status wins. The interrupt fallback in start-tui fires\n // shutdown('cancelled') on every TUI teardown; without this guard a run\n // that already reported 'success' would emit a second, contradicting\n // terminal event when the user dismisses the outro.\n if (this.terminalEventSent) {\n return;\n }\n this.terminalEventSent = true;\n\n this.client.capture({\n distinctId: this.distinctId ?? this.anonymousId,\n event: 'setup wizard finished',\n properties: {\n // Flat for filtering; the nested `tags` snapshot stays for back-compat.\n ...this.tags,\n run_id: this._runId,\n ...(this.sessionId ? { $session_id: this.sessionId } : {}),\n status,\n tags: this.tags,\n },\n });\n\n await this.client.shutdown();\n }\n}\n\nexport const analytics = new Analytics();\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import { n as analytics } from "./analytics-B_xFshPY.js";
2
- export { analytics };
@@ -1,2 +0,0 @@
1
- import { n as ApiError } from "./api-C_9KsN-7.js";
2
- export { ApiError };
@@ -1,2 +0,0 @@
1
- import { t as resolveApiKeyProject } from "./api-key-login-oUJQDmOV.js";
2
- export { resolveApiKeyProject };
@@ -1 +0,0 @@
1
- {"version":3,"file":"bounded-fs-iRaQcKYL.js","names":[],"sources":["../src/shared/utils/bounded-fs.ts"],"sourcesContent":["/**\n * Bounded filesystem primitives for scanning USER project trees. Every\n * detection-time glob, walk, and project-file read goes through here so the\n * worst case is a constant, never a function of the user's repo.\n */\nimport path from 'path';\nimport fs from 'fs';\nimport type { Dirent } from 'fs';\nimport fg from 'fast-glob';\nimport { analytics } from './analytics';\nimport { logToFile } from './debug';\nimport type { WizardRunOptions } from './types';\n\n/**\n * Errno codes that are expected while walking an arbitrary tree and mean\n * \"skip this entry\", not \"something is broken\". Scanning from a broad dir\n * (e.g. `~`) routinely hits OS-protected paths (macOS `Library/Group\n * Containers/group.com.apple.*`) that throw EPERM/EACCES per entry — capturing\n * each as an exception buried real errors under thousands of noise events.\n */\nconst BENIGN_FS_ERROR_CODES = new Set<string>([\n 'EACCES', // permission denied\n 'EPERM', // operation not permitted (macOS-protected dirs)\n 'ENOENT', // entry vanished mid-walk\n 'ENOTDIR', // path component isn't a directory\n 'ELOOP', // symlink loop\n 'ENAMETOOLONG', // path too long\n 'EMFILE', // too many open files (environmental, not a wizard bug)\n 'ENFILE',\n 'EBUSY', // file locked by another process (Windows)\n 'UNKNOWN', // libuv could not map the OS error (Windows locked/placeholder files)\n]);\n\n/**\n * Report a swallowed filesystem error. Traversal stays best-effort — the caller\n * still skips the failing entry. Expected errno codes (permission denied, entry\n * vanished, symlink loops…) are logged to the debug file only; anything else is\n * genuinely unexpected and gets captured to error tracking. Preserves the\n * original Error (and its `code`, e.g. EACCES / ENOENT) when available.\n */\nfunction reportFsError(step: string, filePath: string, error: unknown): void {\n const code = (error as NodeJS.ErrnoException | null)?.code;\n if (code && BENIGN_FS_ERROR_CODES.has(code)) {\n logToFile(`[bounded-fs] skipped ${step} (${code}): ${filePath}`);\n return;\n }\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step, path: filePath },\n );\n}\n\nexport function getDotGitignore({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>) {\n const gitignorePath = path.join(installDir, '.gitignore');\n const gitignoreExists = fs.existsSync(gitignorePath);\n\n if (gitignoreExists) {\n return gitignorePath;\n }\n\n return undefined;\n}\n\n/**\n * Directory names to skip when scanning a project tree — dependency\n * directories, build output, virtual environments, vendored trees.\n * Used verbatim by walkProjectFiles and as glob patterns by boundedGlob.\n */\nexport const IGNORED_DIRS = new Set<string>([\n 'node_modules',\n '.git',\n '.next',\n '.nuxt',\n '.svelte-kit',\n '.turbo',\n '.cache',\n '.parcel-cache',\n 'dist',\n 'build',\n 'out',\n 'coverage',\n '.coverage',\n 'venv',\n '.venv',\n '__pycache__',\n '.pytest_cache',\n 'vendor',\n 'target',\n '.gradle',\n '.idea',\n '.vscode',\n 'site-packages',\n 'DerivedData',\n 'Pods',\n]);\n\n/** IGNORED_DIRS as fast-glob ignore patterns. */\nexport const PROJECT_IGNORE_GLOBS: readonly string[] = [...IGNORED_DIRS].map(\n (dir) => `**/${dir}/**`,\n);\n\n// Files larger than this are skipped, never materialized.\nexport const MAX_PROJECT_FILE_BYTES = 2 * 1024 * 1024;\n\n// A glob returns at most this many entries.\nexport const MAX_GLOB_MATCHES = 500;\n\n// A glob's traversal is destroyed after this long, even when abandoned.\nexport const GLOB_DEADLINE_MS = 8_000;\n\n// A directory contributes at most this many entries to a walk.\nexport const MAX_DIR_ENTRIES = 10_000;\n\n// A walk fires at most this many onFile callbacks.\nexport const MAX_WALK_FILES = 100_000;\n\nexport interface BoundedGlobOptions {\n cwd: string;\n /** Appended to PROJECT_IGNORE_GLOBS. */\n extraIgnore?: readonly string[];\n /** Stop after this many matches. Defaults to MAX_GLOB_MATCHES. */\n limit?: number;\n /** Match dotfiles. Traversal of dot-DIRECTORIES stays blocked by the ignore set. */\n dot?: boolean;\n /** fast-glob `deep` — maximum directory depth. */\n deep?: number;\n}\n\n/**\n * Streams matches, stops at `limit`, destroys the crawl at GLOB_DEADLINE_MS.\n * Returns paths relative to `cwd`, possibly truncated.\n */\nexport async function boundedGlob(\n patterns: string | string[],\n options: BoundedGlobOptions,\n): Promise<string[]> {\n const limit = options.limit ?? MAX_GLOB_MATCHES;\n const stream = fg.stream(patterns, {\n cwd: options.cwd,\n dot: options.dot ?? false,\n onlyFiles: true,\n deep: options.deep,\n ignore: [...PROJECT_IGNORE_GLOBS, ...(options.extraIgnore ?? [])],\n suppressErrors: true,\n followSymbolicLinks: false,\n }) as NodeJS.ReadableStream & { destroy(): void };\n\n const matches: string[] = [];\n return new Promise((resolve) => {\n let settled = false;\n const finish = (): void => {\n if (settled) return;\n settled = true;\n clearTimeout(timer);\n resolve(matches);\n };\n const timer = setTimeout(() => {\n stream.destroy();\n finish();\n }, GLOB_DEADLINE_MS);\n stream.on('data', (entry: string | Buffer) => {\n matches.push(String(entry));\n if (matches.length >= limit) {\n stream.destroy();\n finish();\n }\n });\n stream.once('error', finish);\n stream.once('end', finish);\n stream.once('close', finish);\n });\n}\n\n/**\n * Walk a project tree, invoking `onFile(name, fullPath)` for every regular\n * file — including dotfiles like `.env` (the caller decides what it cares\n * about). Skips `IGNORED_DIRS` and hidden directories, follows symlinked\n * directories with realpath-based loop protection, descends at most\n * `maxDepth` levels below `rootDir`, and stops at the per-directory and\n * whole-walk caps. Filesystem errors are reported and skipped (best-effort).\n */\nexport function walkProjectFiles(\n rootDir: string,\n onFile: (name: string, fullPath: string) => void,\n maxDepth = 3,\n): void {\n const visited = new Set<string>();\n let filesSeen = 0;\n // Explicit stack — no call-stack recursion.\n const stack: Array<{ dir: string; depth: number }> = [\n { dir: rootDir, depth: 0 },\n ];\n\n while (stack.length > 0 && filesSeen < MAX_WALK_FILES) {\n const { dir, depth } = stack.pop()!;\n\n // realpath both resolves symlinked dirs and gives us a stable key to\n // detect loops (symlink cycles, e.g. a -> ../a).\n let realDir: string;\n try {\n realDir = fs.realpathSync(dir);\n } catch (error) {\n reportFsError('walkProjectFiles.realpath', dir, error);\n continue;\n }\n if (visited.has(realDir)) continue;\n visited.add(realDir);\n\n let handle: fs.Dir;\n try {\n handle = fs.opendirSync(dir);\n } catch (error) {\n reportFsError('walkProjectFiles.opendir', dir, error);\n continue;\n }\n try {\n let entriesRead = 0;\n let entry: Dirent | null;\n while ((entry = handle.readSync()) !== null) {\n if (++entriesRead > MAX_DIR_ENTRIES || filesSeen >= MAX_WALK_FILES) {\n logToFile(\n `[bounded-fs] walk capped in ${dir} (entries=${entriesRead}, files=${filesSeen})`,\n );\n break;\n }\n if (IGNORED_DIRS.has(entry.name)) continue;\n\n const fullPath = path.join(dir, entry.name);\n\n // Symlinks report isDirectory()/isFile() as false under withFileTypes,\n // so resolve the target before deciding how to handle the entry.\n let isDir = entry.isDirectory();\n let isFile = entry.isFile();\n if (entry.isSymbolicLink()) {\n try {\n const st = fs.statSync(fullPath);\n isDir = st.isDirectory();\n isFile = st.isFile();\n } catch (error) {\n reportFsError('walkProjectFiles.stat', fullPath, error);\n continue;\n }\n }\n\n if (isDir) {\n if (entry.name.startsWith('.')) continue; // skip hidden directories\n if (depth < maxDepth) stack.push({ dir: fullPath, depth: depth + 1 });\n } else if (isFile) {\n filesSeen += 1;\n onFile(entry.name, fullPath);\n }\n }\n } finally {\n try {\n handle.closeSync();\n } catch {\n /* already closed */\n }\n }\n }\n}\n\n/**\n * Read a project file as UTF-8, or null when missing, unreadable, or over\n * `maxBytes` (stat-gated: an oversized file is never materialized).\n */\nexport function readProjectFile(\n filePath: string,\n maxBytes = MAX_PROJECT_FILE_BYTES,\n): string | null {\n try {\n if (fs.statSync(filePath).size > maxBytes) return null;\n return fs.readFileSync(filePath, 'utf-8');\n } catch {\n return null;\n }\n}\n\n/**\n * `readProjectFile` that also reports unexpected errors to error tracking.\n * For walk callbacks where a failing read is worth a telemetry breadcrumb.\n */\nexport function safeReadFile(fullPath: string): string | null {\n try {\n if (fs.statSync(fullPath).size > MAX_PROJECT_FILE_BYTES) {\n logToFile(`[bounded-fs] skipped oversized file: ${fullPath}`);\n return null;\n }\n return fs.readFileSync(fullPath, 'utf-8');\n } catch (error) {\n reportFsError('safeReadFile', fullPath, error);\n return null;\n }\n}\n\n/**\n * The first `bytes` of a file without materializing the rest.\n */\nexport function readFileHead(filePath: string, bytes: number): string | null {\n try {\n const fd = fs.openSync(filePath, 'r');\n try {\n const buffer = Buffer.alloc(bytes);\n const read = fs.readSync(fd, buffer, 0, bytes, 0);\n return buffer.toString('utf-8', 0, read);\n } finally {\n fs.closeSync(fd);\n }\n } catch {\n return null;\n }\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"debug-BvEbemym.js","names":["join","sep"],"sources":["../src/env.ts","../src/shared/version.ts","../src/shared/utils/paths.ts","../src/shared/utils/debug.ts"],"sourcesContent":["/**\n * Central environment variable access for the PostHog wizard.\n *\n * ── Build-time constants ────────────────────────────────────────────\n * Inlined by tsdown's `env` option at compile time. After build, the\n * runtime value of these env vars has zero effect on the wizard.\n *\n * ── Runtime variables ───────────────────────────────────────────────\n * Read through `runtimeEnv()` with a typed allowlist. This makes every\n * runtime dependency on the environment explicit and grep-able.\n *\n * ── Direct process.env access ───────────────────────────────────────\n * Reserved for subprocess environment configuration (writes) and\n * vendored code. Production source outside those cases should use\n * this module instead.\n */\n\n/**\n * The on-CLI flag name. Intentionally ugly + undocumented; do not surface it in\n * `--help`, the README, or user-facing error messages.\n */\nexport const HEADLESS_FLAG = 'headless-DONOTUSE-EXPERIMENTAL';\n\n// ── Build-time constants ─────────────────────────────────────────────\n// tsdown replaces `process.env.NODE_ENV` with a string literal.\n// After build these are just `\"production\"`, `false`, etc.\n\nexport const NODE_ENV = process.env.NODE_ENV as string;\nexport const IS_DEV =\n process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test';\n\n/**\n * True only in published/production builds. tsdown inlines\n * `process.env.NODE_ENV` as the literal `\"production\"` at build time, so this\n * collapses to `true` in `dist/` and stays `false` for `tsx`/dev/test runs\n * (where NODE_ENV is unset, `development`, or `test`). Used to gate features\n * that aren't supported in the shipped package — e.g. `--ci` mode.\n */\nexport const IS_PRODUCTION_BUILD = process.env.NODE_ENV === 'production';\n\n/** 'cloud' when launched with the experimental headless flag, else 'local' — resolved once from argv at launch. */\nexport const RUN_SURFACE: 'cloud' | 'local' = process.argv.some(\n (a) => a === `--${HEADLESS_FLAG}` || a.startsWith(`--${HEADLESS_FLAG}=`),\n)\n ? 'cloud'\n : 'local';\n\n// ── Runtime environment ──────────────────────────────────────────────\n\n/**\n * Exhaustive allowlist of env vars the wizard reads at runtime.\n * Add new keys here when a new runtime dependency is needed.\n */\ntype RuntimeEnvKey =\n // CI-build-only flag overrides (see utils/ci-flag-overrides.ts).\n // Deliberately NOT POSTHOG_WIZARD_-prefixed: yargs .env('POSTHOG_WIZARD')\n // would claim it as an unknown CLI option and strict-reject the run.\n | 'WIZARD_CI_FLAG_OVERRIDES'\n | 'WIZARD_CI_EXCLUDE_TASKS'\n | 'WIZARD_CI_GATEWAY_TOKEN_FILE'\n | 'WIZARD_CI_GATEWAY_URL'\n // Wizard CLI configuration (yargs POSTHOG_WIZARD_ prefix)\n | 'POSTHOG_WIZARD_BENCHMARK_CONFIG'\n | 'POSTHOG_WIZARD_BENCHMARK_FILE'\n | 'POSTHOG_WIZARD_LOG_DIR'\n | 'POSTHOG_WIZARD_DEBUG'\n // Identity of the PostHog task run whose sandbox launched this wizard. Set by\n // the sandbox for every run it starts, agent or wizard. Deliberately NOT\n // POSTHOG_WIZARD_-prefixed, for the same reason as the two keys above:\n // yargs .env('POSTHOG_WIZARD') would claim them as CLI options and\n // .strictOptions() would reject the run unless the wizard also declared them,\n // which would tie every sandbox deploy to an npm release of this package.\n | 'POSTHOG_WIZARD_RUN_ID'\n | 'POSTHOG_TASK_RUN_ID'\n | 'POSTHOG_TASK_ID'\n | 'POSTHOG_HANDOFF_OUTPUT_PATH'\n // Local/CI escape hatch to disable Warlock scanning without the PostHog flag.\n | 'POSTHOG_WIZARD_WARLOCK_DISABLED'\n | 'DEBUG'\n // Agent / MCP\n | 'MCP_URL'\n | 'POSTHOG_API_KEY'\n // Platform: terminal detection\n | 'TERM'\n | 'TERM_PROGRAM'\n | 'TERMINAL_EMULATOR'\n | 'CI'\n | 'WT_SESSION'\n | 'TERMINUS_SUBLIME'\n | 'ConEmuTask'\n // Platform: paths\n | 'APPDATA'\n | 'OPENCODE_CONFIG_DIR'\n | 'XDG_CONFIG_HOME';\n\n/** Read a runtime environment variable. Only allowlisted keys compile. */\nexport function runtimeEnv(key: RuntimeEnvKey): string | undefined {\n return process.env[key];\n}\n\n/**\n * The PostHog task run that launched this wizard, when one did. A cloud run's\n * sandbox exports both ids into the wizard's environment; every local run\n * leaves them undefined. Resolved once at launch, like RUN_SURFACE above.\n */\nexport const TASK_RUN_ID: string | undefined =\n runtimeEnv('POSTHOG_TASK_RUN_ID') || undefined;\nexport const TASK_ID: string | undefined =\n runtimeEnv('POSTHOG_TASK_ID') || undefined;\n","// Auto-generated by scripts/generate-version.js — do not edit\nexport const VERSION = '2.82.0';\n","import { tmpdir } from 'node:os';\nimport { join, sep } from 'node:path';\n\n// /tmp is stable and discoverable on macOS/Linux; Windows needs os.tmpdir()\nconst TMP = process.platform === 'win32' ? tmpdir() : '/tmp';\n\nexport const WIZARD_LOG_FILE = join(TMP, 'posthog-wizard.log');\nexport const WIZARD_BENCHMARK_FILE = join(TMP, 'posthog-wizard-benchmark.json');\n/** Default target of `--task-stream-log`. Dev builds only. */\nexport const WIZARD_TASK_STREAM_FILE = join(\n TMP,\n 'posthog-wizard-task-stream.jsonl',\n);\nexport const WIZARD_YARA_REPORT_FILE = join(\n TMP,\n 'posthog-wizard-yara-report.json',\n);\n/**\n * Strip an absolute installDir prefix off a project file path so the UI\n * renders `index.js:12` instead of `/Users/.../index.js:12`. Defends\n * against false matches like `/Users/foo` ⊂ `/Users/foobar/x.js` by\n * normalizing to a trailing path separator before the prefix check.\n */\nexport function relativeToInstallDir(file: string, installDir: string): string {\n const prefix = installDir.endsWith(sep) ? installDir : installDir + sep;\n return file.startsWith(prefix) ? file.slice(prefix.length) : file;\n}\n","import { appendFileSync, mkdirSync } from 'fs';\nimport path from 'path';\nimport { inspect } from 'node:util';\nimport { IS_DEV, runtimeEnv } from '@env';\nimport { WIZARD_LOG_FILE } from './paths';\n\n// Dev builds may redirect the log so concurrent runs don't interleave one file.\nlet logFilePath =\n (IS_DEV && process.env.POSTHOG_WIZARD_LOG_FILE) || WIZARD_LOG_FILE;\nlet fileLoggingEnabled = true;\n// An explicit --log-file wins over every later path change while pinned.\nlet logFilePinned = false;\n\nfunction stringify(value: unknown): string {\n if (typeof value === 'string') return value;\n if (value instanceof Error) return value.stack ?? String(value);\n try {\n // JSON.stringify throws on cycles and skips some values — fall back to\n // inspect so a crash log line is never dropped.\n return JSON.stringify(value, null, 2) ?? inspect(value, { depth: 3 });\n } catch {\n return inspect(value, { depth: 3 });\n }\n}\n\n/** One log line from `logToFile`-style arguments: strings as they are, errors as their stack, the rest as JSON. */\nexport function formatLogLine(...args: readonly unknown[]): string {\n return args.map(stringify).join(' ');\n}\n\nexport function getLogFilePath(): string {\n return logFilePath;\n}\n\nexport function configureLogFile(opts: {\n path?: string;\n enabled?: boolean;\n pin?: boolean;\n}): void {\n if (opts.pin === false) logFilePinned = false;\n if (opts.path !== undefined && !logFilePinned) {\n logFilePath = opts.path;\n ensuredLogDir = false;\n }\n if (opts.pin === true) logFilePinned = true;\n if (opts.enabled !== undefined) fileLoggingEnabled = opts.enabled;\n}\n\nlet ensuredLogDir = false;\nlet reportedLogFailure = false;\n\n// Failed log writes go to error tracking, once per process. Dynamic import:\n// analytics logs through this module, so a static import would be a cycle.\nfunction reportLogFailureOnce(err: unknown): void {\n if (reportedLogFailure) return;\n reportedLogFailure = true;\n void import('./analytics')\n .then(({ analytics }) =>\n analytics.captureException(\n err instanceof Error ? err : new Error(String(err)),\n {\n source: 'log-file-write',\n log_path: logFilePath,\n platform: process.platform,\n },\n ),\n )\n .catch(() => {\n // Reporting must never crash the wizard either.\n });\n}\n\n// The log's directory isn't guaranteed to exist (Windows %TEMP%,\n// POSTHOG_WIZARD_LOG_DIR) — create it on first failure.\nfunction appendLine(text: string): void {\n try {\n appendFileSync(logFilePath, text);\n } catch (err) {\n if (ensuredLogDir) {\n reportLogFailureOnce(err);\n return;\n }\n ensuredLogDir = true;\n try {\n mkdirSync(path.dirname(logFilePath), { recursive: true });\n appendFileSync(logFilePath, text);\n } catch (retryErr) {\n reportLogFailureOnce(retryErr);\n }\n }\n}\n\nexport function configureLogFileFromEnvironment(): void {\n const dir = runtimeEnv('POSTHOG_WIZARD_LOG_DIR');\n if (dir) {\n configureLogFile({ path: path.join(dir, 'posthog-wizard.log') });\n }\n}\n\nexport function initLogFile(): void {\n if (!fileLoggingEnabled) return;\n const divider = '='.repeat(60);\n appendLine(\n `\\n${divider}\\nPostHog Wizard Run: ${new Date().toISOString()}\\n${divider}\\n`,\n );\n}\n\nexport function logToFile(...args: unknown[]): void {\n if (!fileLoggingEnabled) return;\n const ts = new Date().toISOString();\n appendLine(`[${ts}] ${formatLogLine(...args)}\\n`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,gBAAgB;AAM7B,MAAa,WAAA;;AAcb,MAAa,cAAiC,QAAQ,KAAK,MACxD,MAAM,MAAM,sCAAwB,EAAE,WAAW,oCAAsB,CACzE,GACG,UACA;;AAmDJ,SAAgB,WAAW,KAAwC;AACjE,QAAO,QAAQ,IAAI;;;;;;;AAQrB,MAAa,cACX,WAAW,sBAAsB,IAAI,KAAA;AACvC,MAAa,UACX,WAAW,kBAAkB,IAAI,KAAA;;;AC3GnC,MAAa,UAAU;;;ACGvB,MAAM,MAAM,QAAQ,aAAa,UAAU,QAAQ,GAAG;AAEtD,MAAa,kBAAkBA,OAAK,KAAK,qBAAqB;AAC9D,MAAa,wBAAwBA,OAAK,KAAK,gCAAgC;;AAE/E,MAAa,0BAA0BA,OACrC,KACA,mCACD;AACD,MAAa,0BAA0BA,OACrC,KACA,kCACD;;;;;;;AAOD,SAAgB,qBAAqB,MAAc,YAA4B;CAC7E,MAAM,SAAS,WAAW,SAASC,MAAI,GAAG,aAAa,aAAaA;AACpE,QAAO,KAAK,WAAW,OAAO,GAAG,KAAK,MAAM,OAAO,OAAO,GAAG;;;;AClB/D,IAAI,cACiD;AACrD,IAAI,qBAAqB;AAEzB,IAAI,gBAAgB;AAEpB,SAAS,UAAU,OAAwB;AACzC,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,iBAAiB,MAAO,QAAO,MAAM,SAAS,OAAO,MAAM;AAC/D,KAAI;AAGF,SAAO,KAAK,UAAU,OAAO,MAAM,EAAE,IAAI,QAAQ,OAAO,EAAE,OAAO,GAAG,CAAC;SAC/D;AACN,SAAO,QAAQ,OAAO,EAAE,OAAO,GAAG,CAAC;;;;AAKvC,SAAgB,cAAc,GAAG,MAAkC;AACjE,QAAO,KAAK,IAAI,UAAU,CAAC,KAAK,IAAI;;AAGtC,SAAgB,iBAAyB;AACvC,QAAO;;AAGT,SAAgB,iBAAiB,MAIxB;AACP,KAAI,KAAK,QAAQ,MAAO,iBAAgB;AACxC,KAAI,KAAK,SAAS,KAAA,KAAa,CAAC,eAAe;AAC7C,gBAAc,KAAK;AACnB,kBAAgB;;AAElB,KAAI,KAAK,QAAQ,KAAM,iBAAgB;AACvC,KAAI,KAAK,YAAY,KAAA,EAAW,sBAAqB,KAAK;;AAG5D,IAAI,gBAAgB;AACpB,IAAI,qBAAqB;AAIzB,SAAS,qBAAqB,KAAoB;AAChD,KAAI,mBAAoB;AACxB,sBAAqB;AAChB,QAAO,2BACT,MAAM,EAAE,gBACP,UAAU,iBACR,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,IAAI,CAAC,EACnD;EACE,QAAQ;EACR,UAAU;EACV,UAAU,QAAQ;EACnB,CACF,CACF,CACA,YAAY,GAEX;;AAKN,SAAS,WAAW,MAAoB;AACtC,KAAI;AACF,iBAAe,aAAa,KAAK;UAC1B,KAAK;AACZ,MAAI,eAAe;AACjB,wBAAqB,IAAI;AACzB;;AAEF,kBAAgB;AAChB,MAAI;AACF,aAAU,KAAK,QAAQ,YAAY,EAAE,EAAE,WAAW,MAAM,CAAC;AACzD,kBAAe,aAAa,KAAK;WAC1B,UAAU;AACjB,wBAAqB,SAAS;;;;AAKpC,SAAgB,kCAAwC;CACtD,MAAM,MAAM,WAAW,yBAAyB;AAChD,KAAI,IACF,kBAAiB,EAAE,MAAM,KAAK,KAAK,KAAK,qBAAqB,EAAE,CAAC;;AAIpE,SAAgB,cAAoB;AAClC,KAAI,CAAC,mBAAoB;CACzB,MAAM,UAAU,IAAI,OAAO,GAAG;AAC9B,YACE,KAAK,QAAQ,yCAAwB,IAAI,MAAM,EAAC,aAAa,CAAC,IAAI,QAAQ,IAC3E;;AAGH,SAAgB,UAAU,GAAG,MAAuB;AAClD,KAAI,CAAC,mBAAoB;AAEzB,YAAW,qBADA,IAAI,MAAM,EAAC,aAAa,CACjB,IAAI,cAAc,GAAG,KAAK,CAAC,IAAI"}
@@ -1,3 +0,0 @@
1
- import "./mode-label-DB3ol_sj.js";
2
- import { t as runHeadless } from "./headless-Bfi950Qh.js";
3
- export { runHeadless };
@@ -1 +0,0 @@
1
- {"version":3,"file":"main-5KNn80Vt.js","names":["mcpAnalyticsConfig","replayVisionConfig","aiObservabilityConfig","metricsConfig","webAnalyticsDoctorConfig","agentSkillConfig","migrationConfig","revenueAnalyticsConfig","warehouseSourceConfig","selfDrivingConfig","errorTrackingUploadSourceMapsConfig","errorTrackingConfig"],"sources":["../src/cli/commands/command.ts","../src/cli/wizard.ts","../src/cli/commands/provision.ts","../src/cli/commands/basic-integration/index.ts","../src/cli/commands/mcp/tui-availability.ts","../src/cli/commands/mcp/add.ts","../src/cli/commands/mcp/remove.ts","../src/cli/commands/mcp/tutorial.ts","../src/cli/commands/mcp/index.ts","../src/cli/commands/skill-program-options.ts","../src/cli/commands/factories/shared.ts","../src/cli/commands/factories/native-command-factory.ts","../src/cli/commands/mcp-analytics.ts","../src/cli/commands/replay-vision.ts","../src/cli/commands/ai-observability.ts","../src/cli/commands/metrics.ts","../src/cli/commands/cli/add.ts","../src/cli/commands/cli/index.ts","../src/cli/commands/dispatch-family.ts","../src/cli/commands/factories/family-picker.ts","../src/cli/commands/factories/family-command-factory.ts","../src/cli/commands/audit.ts","../src/cli/commands/doctor.ts","../src/cli/commands/migrate.ts","../src/cli/commands/revenue.ts","../src/cli/commands/warehouse.ts","../src/cli/commands/self-driving.ts","../src/cli/commands/slack.ts","../src/cli/commands/upload-sourcemaps.ts","../src/cli/commands/error-tracking.ts","../src/cli/commands/basic-integration/skill.ts","../src/cli/commands/skill.ts","../src/cli/index.ts","../main.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 { Harness, Sequence } from '@shared/constants';\nimport { regionOption } from '@shared/headless-mode';\nimport { initLocalDev, localMcpSkillsNotice } from '@shared/local-dev';\nimport { configureLogFile } from '@utils/debug';\nimport { toCommandModule, type Command } from './commands/command';\nimport { ErrorCodes } from '@shared/errors';\nimport { emitWizardError } from '@shared/errors';\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 `--local-*` flags live\n * in the constructor's `!IS_PRODUCTION_BUILD` block instead, so published\n * builds reject them; see `docs/local-dev.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 'log-file': {\n describe:\n 'Write the debug log to this file (default: posthog-wizard.log in the temp dir)\\nenv: POSTHOG_WIZARD_LOG_FILE',\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`.\n // NB: the experimental headless flag is deliberately NOT global. Supported\n // commands declare it through `headlessOption` in @shared/headless-mode.\n 'base-url': {\n describe:\n 'Override the PostHog base URL (e.g. http://localhost:8010), bypassing region resolution. Pins the API host, cloud URL, and OAuth server.\\nenv: POSTHOG_WIZARD_BASE_URL',\n type: 'string' as const,\n hidden: true,\n },\n 'run-id': {\n describe: 'Assigned cloud WizardRun UUID',\n type: 'string' 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: Argv = 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 // The published-build, non-interactive path is the experimental headless\n // flag, declared per-command through `headlessOption` (see\n // @shared/headless-mode). CI needs `region` globally because the workbench\n // passes it to every command. --ci and headless stay separate so their\n // behavior can diverge.\n if (!IS_PRODUCTION_BUILD) {\n cli = cli\n .options(regionOption)\n .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 // Runner overrides — dev/test only, same lifecycle as --ci.\n .option('harness', {\n describe:\n 'Override the agent harness (anthropic | pi). Wins over the PostHog runner flag.\\nenv: POSTHOG_WIZARD_HARNESS',\n choices: Object.values(Harness),\n type: 'string',\n hidden: true,\n })\n .option('sequence', {\n describe:\n 'Override the runner sequence (linear | orchestrator). Wins over the PostHog orchestrator flag.\\nenv: POSTHOG_WIZARD_SEQUENCE',\n choices: Object.values(Sequence),\n type: 'string',\n hidden: true,\n })\n .option('model', {\n describe:\n 'Override the agent model (gateway id, e.g. claude-sonnet-5 | openai/gpt-5.6-terra). Wins over the binding default.\\nenv: POSTHOG_WIZARD_MODEL',\n type: 'string',\n hidden: true,\n })\n .option('capture-aio', {\n default: false,\n describe:\n \"Capture wizard LLM calls as $ai_generation events in the authenticated project's AI Observability tab.\\nenv: POSTHOG_WIZARD_CAPTURE_AIO\",\n type: 'boolean',\n hidden: true,\n })\n // Rides beside the PostHog destination rather than replacing it, so a\n // logged run is the same run the backend sees.\n .option('task-stream-log', {\n describe:\n 'Append every task-stream payload to a local JSONL file. Pass a path, or pass the flag alone for /tmp/posthog-wizard-task-stream.jsonl\\nenv: POSTHOG_WIZARD_TASK_STREAM_LOG',\n type: 'string',\n })\n // ── Local dev targets (see docs/local-dev.md) ──────────────────\n // Not `hidden`: the build gate already keeps them from users, so\n // hiding them would only cost the dev-build help row. Deliberately not\n // named `--local`, which `wizard mcp add` already uses for something\n // unrelated.\n .option('local-dev', {\n default: false,\n describe:\n 'Point context-mill, MCP, and PostHog at local dev servers\\nenv: POSTHOG_WIZARD_LOCAL_DEV',\n type: 'boolean',\n })\n // No `default` on the three below — they must stay `undefined` when\n // absent for resolveLocalDev() to honour the umbrella and `--no-*`.\n .option('local-context-mill', {\n describe:\n 'Fetch skills from the local context-mill server (http://localhost:8765)\\nenv: POSTHOG_WIZARD_LOCAL_CONTEXT_MILL',\n type: 'boolean',\n })\n .option('local-mcp', {\n describe:\n 'Use the local MCP server (http://localhost:8787/mcp). Affects MCP only — use --local-context-mill for skills.\\nenv: POSTHOG_WIZARD_LOCAL_MCP',\n type: 'boolean',\n })\n .option('local-posthog', {\n describe:\n 'Point every PostHog origin (API, app, OAuth, gateway) at http://localhost:8010\\nenv: POSTHOG_WIZARD_LOCAL_POSTHOG',\n type: 'boolean',\n });\n }\n\n this.cli = cli\n // Middleware rather than an argv scan so the env path is covered too,\n // and it runs before any TUI takes the terminal.\n .middleware((argv) => {\n if (typeof argv.logFile === 'string' && argv.logFile) {\n configureLogFile({ path: argv.logFile, pin: true });\n }\n // The one place local targets are resolved; everything downstream reads\n // getLocalDev().\n initLocalDev(argv);\n\n // Temporary.\n const notice = localMcpSkillsNotice({\n localDev: argv.localDev as boolean | undefined,\n localMcp: argv.localMcp as boolean | undefined,\n localContextMill: argv.localContextMill as boolean | undefined,\n });\n if (notice) {\n process.stderr.write(`\\n\\x1b[33m! ${notice}\\x1b[0m\\n\\n`);\n }\n })\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 emitWizardError({ code: ErrorCodes.CliBadArgs, message: text });\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 emitWizardError({\n code: ErrorCodes.CliFlagUnavailable,\n message: 'CI mode is not supported in published builds.',\n });\n process.exit(1);\n }\n\n // --harness / --sequence / --model / --capture-aio are dev/test-only.\n // In published builds the env vars would silently no-op, so reject them\n // explicitly instead.\n const argvHasOverride = args.some(\n (a) =>\n a === '--harness' ||\n a.startsWith('--harness=') ||\n a === '--sequence' ||\n a.startsWith('--sequence=') ||\n a === '--model' ||\n a.startsWith('--model=') ||\n a === '--capture-aio' ||\n a === '--no-capture-aio' ||\n a.startsWith('--capture-aio='),\n );\n const envHasOverride =\n (process.env.POSTHOG_WIZARD_HARNESS != null &&\n process.env.POSTHOG_WIZARD_HARNESS !== '') ||\n (process.env.POSTHOG_WIZARD_SEQUENCE != null &&\n process.env.POSTHOG_WIZARD_SEQUENCE !== '') ||\n (process.env.POSTHOG_WIZARD_MODEL != null &&\n process.env.POSTHOG_WIZARD_MODEL !== '') ||\n (process.env.POSTHOG_WIZARD_CAPTURE_AIO != null &&\n process.env.POSTHOG_WIZARD_CAPTURE_AIO !== '');\n if (argvHasOverride || envHasOverride) {\n process.stderr.write(\n `\\n\\x1b[1;91m✖ The --harness, --sequence, --model, and --capture-aio overrides are not available in published builds.\\x1b[0m\\n\\n`,\n );\n emitWizardError({\n code: ErrorCodes.CliFlagUnavailable,\n message:\n 'The --harness, --sequence, --model, and --capture-aio overrides are not available in published builds.',\n });\n process.exit(1);\n }\n\n // `--local-mcp` used to be declared unconditionally, so published builds\n // accepted it and quietly aimed the run at localhost. Reject explicitly.\n const argvHasLocalTarget = args.some((a) =>\n LOCAL_TARGET_FLAGS.some(\n (f) => a === `--${f}` || a === `--no-${f}` || a.startsWith(`--${f}=`),\n ),\n );\n const envHasLocalTarget = LOCAL_TARGET_ENV_VARS.some(\n (k) => process.env[k] != null && process.env[k] !== '',\n );\n if (argvHasLocalTarget || envHasLocalTarget) {\n process.stderr.write(\n `\\n\\x1b[1;91m✖ The --local-dev, --local-context-mill, --local-mcp, and --local-posthog targets are not available in published builds.\\x1b[0m\\n` +\n ` They point the wizard at development servers on localhost.\\n\\n`,\n );\n emitWizardError({\n code: ErrorCodes.CliFlagUnavailable,\n message:\n 'The --local-dev, --local-context-mill, --local-mcp, and --local-posthog targets are not available in published builds.',\n });\n process.exit(1);\n }\n }\n void this.cli.wrap(process.stdout.isTTY ? this.cli.terminalWidth() : 80)\n .argv;\n }\n}\n\n/** Excludes bare `local`: `wizard mcp add --local` stays available in prod. */\nconst LOCAL_TARGET_FLAGS = [\n 'local-dev',\n 'local-context-mill',\n 'local-mcp',\n 'local-posthog',\n] as const;\n\nconst LOCAL_TARGET_ENV_VARS = [\n 'POSTHOG_WIZARD_LOCAL_DEV',\n 'POSTHOG_WIZARD_LOCAL_CONTEXT_MILL',\n 'POSTHOG_WIZARD_LOCAL_MCP',\n 'POSTHOG_WIZARD_LOCAL_POSTHOG',\n] as const;\n","import type { Arguments } from 'yargs';\nimport { consoleLog } from '@shared/console-log';\nimport { runProvision } from '@tools';\nimport { exitWith } from '@cli/runners';\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: provision,\n};\n\nfunction provision(argv: Arguments): void {\n const jsonMode =\n argv.json === undefined ? !process.stdout.isTTY : Boolean(argv.json);\n exitWith(() =>\n runProvision(\n {\n email: argv.email as string,\n region: (argv.region as string).toUpperCase() as 'US' | 'EU',\n name: (argv.name as string) ?? '',\n baseUrl: argv.baseUrl as string | undefined,\n jsonMode,\n },\n { log: consoleLog },\n ),\n );\n}\n","import { isNonInteractiveEnvironment } from '@utils/environment';\nimport { setEntryCommand } from '@utils/links';\nimport {\n headlessOption,\n isHeadless,\n regionOption,\n} from '@shared/headless-mode';\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 // The experimental headless flag — declared here (and on `audit`) rather\n // than globally. Routed by this command's handler via runHeadlessInstall.\n ...headlessOption,\n ...regionOption,\n },\n check: (argv) => {\n // --playground is the standalone TUI demo; it can't combine with a\n // non-interactive run (either --ci or the experimental headless flag).\n if (argv.playground && (argv.ci || isHeadless(argv))) {\n throw new Error('--playground cannot be combined with a headless run.');\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 // ── The CI / headless division ───────────────────────────────────\n // --ci (dev/test only) and the experimental headless flag (the\n // published-build, non-interactive path; see @shared/headless-mode) both\n // request a non-interactive install, but route to dedicated entry points\n // — runHeadlessInstall vs runCIInstall (and below them runWizardHeadless\n // vs runWizardCI). Both share one pipeline today but are separate\n // functions end-to-end, so headless can diverge later without touching\n // the CI path or its callers.\n if (isHeadless(argv)) {\n const { runHeadlessInstall } = await import('./ci-install');\n return runHeadlessInstall(argv);\n }\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 { ErrorCodes } from '@shared/errors';\n\n/**\n * startTUI throws CliInteractiveRequired, and Ink throws \"Raw mode is not\n * supported\", when stdin has no TTY (piped input, CI, some IDE terminals).\n * That is the only TUI failure the mcp commands degrade to console output for\n * — any other error from the TUI path is a real bug and must surface rather\n * than be silently swallowed.\n */\nexport function isTUIUnavailable(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n (error as { code?: unknown }).code === ErrorCodes.CliInteractiveRequired ||\n /raw mode is not supported/i.test(error.message)\n );\n}\n","import type { Arguments } from 'yargs';\nimport { consoleLog } from '@shared/console-log';\nimport { headlessOption, isHeadless } from '@shared/headless-mode';\nimport { readApiKeyFromEnv } from '@utils/env-api-key';\nimport { addMCPServerToClientsStep, Tool } from '@tools';\nimport { exitWith, underSignals } from '@cli/runners';\nimport type { Command } from '../command';\nimport { isTUIUnavailable } from './tui-availability';\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 // Reuses the run pipeline's headless flag rather than minting a public one:\n // this stays reversible, and today the only caller is our own CI.\n ...headlessOption,\n },\n handler: runMcpAdd,\n};\n\nfunction runMcpAdd(argv: Arguments): void {\n const features = parseFeatures(argv.features);\n const apiKey = (argv.apiKey as string | undefined) || readApiKeyFromEnv();\n const localMcp = argv.local as boolean | undefined;\n // Never forwards `ci`: headless implies session.ci elsewhere, and the step\n // reads that as \"skip MCP entirely\" — the opposite of what we're here to do.\n const headless = () =>\n addMCPServerToClientsStep(\n { local: localMcp, features, apiKey },\n { log: consoleLog.log },\n );\n\n // Ink renders into a pipe happily and only throws on raw-mode input, so a\n // non-TTY run reaches the confirm prompt and stalls there rather than\n // hitting the isTUIUnavailable fallback below. The headless flag is the\n // only reliable way to install from a script.\n if (isHeadless(argv)) {\n exitWith(headless);\n return;\n }\n\n exitWith(async () => {\n try {\n const { runTuiTool } = await import('@tui');\n return await underSignals((signal) =>\n runTuiTool(Tool.McpAdd, {\n session: {\n debug: argv.debug as boolean | undefined,\n localMcp,\n mcpFeatures: features,\n apiKey,\n baseUrl: argv.baseUrl as string | undefined,\n },\n signal,\n }),\n );\n } catch (error) {\n if (!isTUIUnavailable(error)) throw error;\n return headless();\n }\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 { consoleLog } from '@shared/console-log';\nimport { headlessOption, isHeadless } from '@shared/headless-mode';\nimport { removeMCPServerFromClientsStep, Tool } from '@tools';\nimport { exitWith, underSignals } from '@cli/runners';\nimport type { Command } from '../command';\nimport { isTUIUnavailable } from './tui-availability';\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 // Mirrors `mcp add` — see the note there on reusing the run pipeline's flag.\n ...headlessOption,\n },\n handler: runMcpRemove,\n};\n\nfunction runMcpRemove(argv: Arguments): void {\n const localMcp = argv.local as boolean | undefined;\n const headless = () =>\n removeMCPServerFromClientsStep(\n { local: localMcp },\n { log: consoleLog.log },\n );\n\n // See the note in add.ts: a non-TTY run stalls on the confirm prompt\n // instead of falling back, so scripts need an explicit flag.\n if (isHeadless(argv)) {\n exitWith(headless);\n return;\n }\n\n exitWith(async () => {\n try {\n const { runTuiTool } = await import('@tui');\n return await underSignals((signal) =>\n runTuiTool(Tool.McpRemove, {\n session: {\n debug: argv.debug as boolean | undefined,\n localMcp,\n baseUrl: argv.baseUrl as string | undefined,\n },\n signal,\n }),\n );\n } catch (error) {\n // Same guard as `mcp add`: only a missing TTY falls back to the console,\n // so a genuine TUI bug surfaces instead of looking like a plain shell.\n if (!isTUIUnavailable(error)) throw error;\n return headless();\n }\n });\n}\n","import type { Arguments } from 'yargs';\nimport { consoleLog } from '@shared/console-log';\nimport { ErrorCodes, emitWizardError } from '@shared/errors';\nimport { Tool } from '@tools';\nimport { exitWith, underSignals } from '@cli/runners';\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 exitWith(async () => {\n try {\n const { runTuiTool } = await import('@tui');\n return await underSignals((signal) =>\n runTuiTool(Tool.McpTutorial, {\n session: {\n debug: argv.debug as boolean | undefined,\n localMcp: argv.local as boolean | undefined,\n baseUrl: argv.baseUrl as string | undefined,\n },\n signal,\n }),\n );\n } catch (err) {\n // TUI unavailable — the tutorial has no headless fallback.\n consoleLog.log.error(\n `The MCP tutorial requires an interactive terminal. ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n emitWizardError({\n code: ErrorCodes.CliInteractiveRequired,\n message: 'The MCP tutorial requires an interactive terminal.',\n });\n return 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 * Per-command options shared by every skill-based program command\n * (`audit events`, `migrate statsig`, `revenue`, `source-maps`, …).\n *\n * Only flags unique to skill commands live here. Global flags are declared\n * once in `wizard.ts` — both in `GLOBAL_OPTIONS` and, for the dev-only ones,\n * the `Wizard` constructor — and apply to every command automatically.\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, runWizardHeadless } from '@cli/runners';\nimport { isHeadless } from '@shared/headless-mode';\nimport type { ProgramConfig } from '@programs/types';\n\nimport { skillProgramOptions } from '../skill-program-options';\nimport { ErrorCodes } from '@shared/errors';\nimport { emitWizardError } from '@shared/errors';\n\n/**\n * Dispatch a parsed yargs invocation to the wizard runner. Applies the\n * program's `mapCliOptions` transform, then routes to `runWizardHeadless`,\n * `runWizardCI`, or `runWizard` based on the headless / `--ci` flags.\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 emitWizardError({ code: ErrorCodes.InternalUnhandled, message: msg });\n process.exit(1);\n }\n })();\n}\n\nexport function dispatchProgram(config: ProgramConfig, argv: Arguments): void {\n const argvRecord: Record<string, unknown> = { ...argv };\n const extras = config.mapCliOptions?.(argvRecord) ?? {};\n const options = { ...argvRecord, ...extras };\n if (isHeadless(options)) {\n // Same non-interactive pipeline `--ci` uses; validation (api-key,\n // install-dir, region) is owned by runNonInteractive.\n runWizardHeadless(config, options);\n } else 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 { ProgramConfig } from '@programs/types';\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 { config as mcpAnalyticsConfig } from '@programs/mcp-analytics';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard mcp-analytics` — flat skill command, instrument-an-MCP-server today.\n *\n * Distinct from `wizard mcp add`: this instruments the user's own MCP server\n * with the PostHog MCP SDK for its language, rather than installing the PostHog MCP server\n * into a coding agent. Stays flat while instrumenting is the only action.\n */\nexport const mcpAnalyticsCommand: Command =\n nativeCommandFactory(mcpAnalyticsConfig);\n","import { config as replayVisionConfig } from '@programs/replay-vision';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard replay-vision` — flat skill command, set up Replay vision today.\n *\n * Enables session replay recording and creates vision scanners tailored to\n * the product's key flows. Runs the `replay-vision` orchestrator flow, which\n * reuses the integration-v2 install/init mini-agents when the repo has no\n * PostHog integration yet.\n */\nexport const replayVisionCommand: Command =\n nativeCommandFactory(replayVisionConfig);\n","import { config as aiObservabilityConfig } from '@programs/ai-observability';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard ai-observability` — flat skill command, wire AI Observability into a\n * project today.\n *\n * Installs the OpenTelemetry SDK, the PostHog span processor, and the\n * provider-specific instrumentation so LLM calls emit `$ai_generation` events.\n * The `ai-observability` context-mill skill has one variant per (LLM provider ×\n * language); the agent picks the right one at run time by scanning the\n * project's manifest and (when ambiguous) asking the user via `wizard_ask`.\n * Stays flat while a single \"add AIO to a project\" flow is the only action.\n */\nexport const aiObservabilityCommand: Command = nativeCommandFactory(\n aiObservabilityConfig,\n);\n","import { config as metricsConfig } from '@programs/metrics';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard metrics` — flat skill command, wire PostHog application metrics\n * (counters, gauges, histograms via \\`posthog.metrics\\`) into a project.\n *\n * The `metrics` context-mill skill has one variant per platform (python,\n * nodejs, javascript, kubernetes, other/OTLP); the agent picks the right one\n * at run time by scanning the project's manifest and (when ambiguous) asking\n * the user via `wizard_ask`. Stays flat while a single \"add metrics to a\n * project\" flow is the only action.\n */\nexport const metricsCommand: Command = nativeCommandFactory(metricsConfig);\n","import { consoleLog } from '@shared/console-log';\nimport { CLI_STEERING_TARGETS } from '@shared/install-cli-steering';\nimport { runCliAdd } from '@tools';\nimport { exitWith } from '@cli/runners';\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 exitWith(() =>\n runCliAdd(\n {\n agent: typeof argv.agent === 'string' ? argv.agent : undefined,\n path: typeof argv.path === 'string' ? argv.path : undefined,\n all: argv.all === true,\n },\n { log: consoleLog },\n ),\n );\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","import type { Arguments } from 'yargs';\n\nimport { AUDIT_CHECKS_FILE } from '@programs/audit';\nimport { WIZARD_TOOL_NAMES } from '@agent';\nimport { getProgramConfig, Program } from '@programs';\nimport { config as agentSkillConfig } from '@programs/agent-skill';\nimport { config as webAnalyticsDoctorConfig } from '@programs/web-analytics-doctor';\nimport type { ProgramConfig } from '@programs/types';\nimport { getSkillsBaseUrl } from '@shared/constants';\nimport { fetchSkillMenu, type CliEntry } from '@shared/skill-menu';\nimport { analytics } from '@utils/analytics';\n\nimport { dispatchProgram } from './factories/shared';\nimport type { Command } from './command';\nimport { ErrorCodes } from '@shared/errors';\nimport { emitWizardError } from '@shared/errors';\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 emitWizardError({ code: ErrorCodes.CliBadArgs, message: reason });\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 `audit` program (custom hooks,\n * content blocks, screens).\n *\n * This is the one place that knows a subcommand belongs to `audit`, so the\n * generic skill program picks up the ledger here rather than for every skill.\n */\nfunction configForCliEntry(entry: CliEntry, family: string): ProgramConfig {\n if (entry.skillId === 'audit') return getProgramConfig(Program.Audit);\n return {\n ...agentSkillConfig,\n skillId: entry.skillId,\n ...(family === 'audit'\n ? {\n auditLedgerFile: AUDIT_CHECKS_FILE,\n streamWorkflowId: family,\n allowedTools: [\n ...(agentSkillConfig.allowedTools ?? []),\n WIZARD_TOOL_NAMES.auditSeedChecks,\n WIZARD_TOOL_NAMES.auditAddChecks,\n WIZARD_TOOL_NAMES.auditResolveChecks,\n ],\n }\n : {}),\n };\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();\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, family), 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 * 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';\n\nimport { commandKeys, type Command } from '../command';\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 over a family's children. Resolves once the user has\n * selected a child; dispatching the child's handler is the caller's\n * responsibility.\n */\nexport async function chooseFamilyChild(\n parentLabel: string,\n children: readonly Command[],\n): Promise<Command | null> {\n const ordered = orderFamilyChildren(children);\n if (ordered.length === 0) return null;\n\n // Loaded here: a headless run never loads the TUI.\n const { renderFamilyPicker } = await import('@tui');\n return renderFamilyPicker(\n parentLabel,\n ordered.map((child) => ({\n label: describe(child),\n value: child,\n hint: child.description,\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 '@programs/types';\nimport {\n buildFamilyPickerChildren,\n dispatchFamily,\n pickerChildrenToShow,\n} from '../dispatch-family';\nimport { getSkillsBaseUrl } from '@shared/constants';\nimport { fetchSkillMenu } from '@shared/skill-menu';\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();\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 { getProgramConfig, Program } from '@programs';\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 */\nconst audit = getProgramConfig(Program.Audit);\n\nexport const auditCommand: Command = familyCommandFactory({\n family: 'audit',\n description: audit.description,\n optionsFrom: audit,\n});\n","import { consoleLog } from '@shared/console-log';\nimport { readApiKeyFromEnv } from '@utils/env-api-key';\nimport { DOCTOR, runDoctorReport, Tool } from '@tools';\nimport { exitWith, tuiSessionArgs, withSignals } from '@cli/runners';\nimport { skillProgramOptions } from './skill-program-options';\nimport type { Command } from './command';\n\nexport const doctorCommand: Command = {\n name: 'doctor',\n description: DOCTOR.description,\n options: { ...skillProgramOptions },\n handler: (argv) => {\n const options = { ...argv } as Record<string, unknown>;\n // In CI there is no screen: fetch the project's health issues and print them.\n if (options.ci) {\n exitWith(() =>\n runDoctorReport(\n {\n apiKey:\n (options.apiKey as string | undefined) ??\n readApiKeyFromEnv() ??\n undefined,\n projectId: options.projectId\n ? Number(options.projectId as string)\n : undefined,\n baseUrl: options.baseUrl as string | undefined,\n },\n { log: consoleLog },\n ),\n );\n return;\n }\n withSignals(async (signal) => {\n // Loaded here, not at startup: a console run never loads the TUI.\n const { runTuiTool } = await import('@tui');\n return runTuiTool(Tool.PosthogDoctor, {\n session: tuiSessionArgs(options),\n signal,\n });\n });\n },\n};\n","import { config as migrationConfig } from '@programs/migration';\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 { config as revenueAnalyticsConfig } from '@programs/revenue-analytics';\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 { config as warehouseSourceConfig } from '@programs/warehouse-source';\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 '@cli/runners';\nimport { config as selfDrivingConfig } from '@programs/self-driving';\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 integrate: {\n describe:\n 'Integrate the PostHog SDK first, then set up Self-driving — skips the integration prompt and logs you in via OAuth (no \"create an account?\" question). Use when the project isn\\'t set up yet but you already have a PostHog account.',\n type: 'boolean',\n default: false,\n },\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. Just run `wizard ' +\n 'self-driving`: when your project has no PostHog, it asks whether ' +\n 'you already have an account and offers to create one for you ' +\n '(no flag needed).',\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 { consoleLog } from '@shared/console-log';\nimport { ErrorCodes, emitWizardError } from '@shared/errors';\nimport { Tool } from '@tools';\nimport { exitWith, underSignals } from '@cli/runners';\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 exitWith(async () => {\n try {\n const { runTuiTool } = await import('@tui');\n return await underSignals((signal) =>\n runTuiTool(Tool.SlackConnect, {\n session: {\n debug: argv.debug as boolean | undefined,\n baseUrl: argv.baseUrl as string | undefined,\n },\n signal,\n }),\n );\n } catch (err) {\n // TUI unavailable — connecting Slack has no headless fallback.\n consoleLog.log.error(\n `Connecting Slack requires an interactive terminal. ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n emitWizardError({\n code: ErrorCodes.CliInteractiveRequired,\n message: 'Connecting Slack requires an interactive terminal.',\n });\n return 1;\n }\n });\n}\n","import { runWizard, runWizardCI } from '@cli/runners';\nimport { config as errorTrackingUploadSourceMapsConfig } from '@programs/error-tracking-upload-source-maps';\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 { config as errorTrackingConfig } from '@programs/error-tracking';\n\nimport type { Command } from './command';\nimport { nativeCommandFactory } from './factories/native-command-factory';\n\n/**\n * `wizard error-tracking` — flat skill command, set up error tracking today.\n *\n * Wires up exception capture and — where the platform needs it — source-map /\n * debug-symbol upload. Runs the `error-tracking` orchestrator flow, which\n * reuses the integration-v2 install/init mini-agents when the repo has no\n * PostHog integration yet, so it works on uninstrumented projects too.\n */\nexport const errorTrackingCommand: Command =\n nativeCommandFactory(errorTrackingConfig);\n","import type { Arguments } from 'yargs';\nimport { POSTHOG_DOCS_URL } from '@shared/constants';\nimport { runWizard, runWizardCI } from '@cli/runners';\nimport { createSkillProgram } from '@programs';\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 '@shared/constants';\nimport { fetchSkillMenu } from '@shared/skill-menu';\nimport { analytics } from '@utils/analytics';\nimport { listSkills } from '@tools';\nimport { exitWith } from '@cli/runners';\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\n/**\n * Reject an unknown skill id before the wizard authenticates.\n *\n * Without this, `readSkillName` accepts any non-empty string and the name is\n * only validated far downstream, when the agent tries to download it — after\n * the user has already logged in. A typo then costs a full auth round-trip\n * (the concern raised in review). We resolve against the same set\n * `downloadSkill` uses (`categories` flattened by `id`), so this never\n * false-rejects a skill the download would have accepted.\n *\n * If the registry is unreachable we stay silent and defer to the download\n * step's own `menu-fetch-failed` handling, rather than adding a second network\n * dependency that could block an otherwise-valid run.\n */\nasync function assertSkillExists(skillName: string): Promise<void> {\n const skillsBaseUrl = getSkillsBaseUrl();\n const menu = await fetchSkillMenu(skillsBaseUrl);\n if (!menu) return; // registry down — let the download step surface it\n const known = Object.values(menu.categories)\n .flat()\n .some((s) => s.id === skillName);\n if (known) return;\n analytics.wizardCapture('cli dispatch error', {\n reason: 'unknown skill',\n family: 'skill',\n sub: skillName,\n skillsBaseUrl,\n });\n try {\n await analytics.flush();\n } catch {\n /* best-effort */\n }\n throw new Error(\n `Unknown skill \"${skillName}\". Run \\`wizard skill list\\` to see available skills.`,\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 options: {\n ...skillProgramOptions,\n },\n // Under `.strictOptions()` yargs rejects a positional declared only in the\n // command string as an \"Unknown argument\" — it has to be registered via\n // `.positional()` too (see the `positionals` note on the Command interface).\n // Declare `skill-name` here so `wizard skill <id>` actually accepts its value.\n positionals: {\n 'skill-name': {\n type: 'string',\n describe: 'Skill id to run (e.g. audit-events), or `list`',\n },\n },\n // yargs already enforces the presence of the `<skill-name>` positional, but\n // an 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.\n check: (argv) => {\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 // `list` is the positional's one reserved value, not a skill id.\n if (readSkillName(argv) === 'list') return exitWith(listSkills);\n runCommandHandler(async () => {\n const skillName = readSkillName(argv);\n await assertSkillExists(skillName);\n // runSkillMode reads `argv.skill`; bridge the positional onto it.\n runSkillMode({ ...argv, skill: skillName });\n });\n },\n};\n","/** The CLI's one entry: `main.ts` runs the `wizard` command line through it. */\nimport { Wizard } from './wizard';\nimport { basicIntegrationCommand } from './commands/basic-integration';\nimport { mcpCommand } from './commands/mcp';\nimport { mcpAnalyticsCommand } from './commands/mcp-analytics';\nimport { replayVisionCommand } from './commands/replay-vision';\nimport { aiObservabilityCommand } from './commands/ai-observability';\nimport { metricsCommand } from './commands/metrics';\nimport { cliCommand } from './commands/cli';\nimport { auditCommand } from './commands/audit';\nimport { doctorCommand } from './commands/doctor';\nimport { migrateCommand } from './commands/migrate';\nimport { revenueCommand } from './commands/revenue';\nimport { warehouseCommand } from './commands/warehouse';\nimport { selfDrivingCommand } from './commands/self-driving';\nimport { slackCommand } from './commands/slack';\nimport { uploadSourcemapsCommand } from './commands/upload-sourcemaps';\nimport { errorTrackingCommand } from './commands/error-tracking';\nimport { skillCommand } from './commands/skill';\n\n/** Register every command and run the one `process.argv` names. */\nexport function runCli(): void {\n Wizard.use(basicIntegrationCommand)\n .use(mcpCommand)\n .use(mcpAnalyticsCommand)\n .use(replayVisionCommand)\n .use(aiObservabilityCommand)\n .use(metricsCommand)\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(errorTrackingCommand)\n .use(skillCommand)\n .init();\n}\n","import { Agent, setGlobalDispatcher } from 'undici';\n\n/*\n * TODO(#1198): remove when fetch over HTTP/2 is safe on Node 26. Remove when all\n * of these are true:\n * - nodejs/node no longer creates an orphan ClientHttp2Stream when a client\n * session gets HEADERS for a stream id it already reset. Repro: abort a fetch\n * before its response headers, then idle 4s on Node 26. Fixed when the\n * process survives.\n * - modelcontextprotocol/typescript-sdk#2526 is closed.\n * - pi-coding-agent's CLI drops `allowH2: false` from its http-dispatcher.\n * Same workaround as pi's CLI and typescript-sdk#2526: HTTP/1.1 only.\n */\nsetGlobalDispatcher(new Agent({ allowH2: false }));\n\nimport { runCli } from '@cli';\nimport { recoverOrphanedSettingsBackups } from '@shared/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\nrunCli();\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"models-C9rjXPZ6.js","names":[],"sources":["../src/agent/runner/switchboard/models.ts"],"sourcesContent":["// Local capabilities inform transport parameters; gateway policy independently admits models and efforts.\nimport {\n SONNET_5_MODEL,\n HAIKU_MODEL,\n GPT5_6_LUNA_MODEL,\n GPT5_6_SOL_MODEL,\n GPT5_6_TERRA_MODEL,\n HAIKU_TRIAGE_MODEL,\n Harness,\n} from '@shared/constants';\n\n/** Reasoning effort, mapped by each harness to its provider transport. */\nconst THINKING_LEVELS = [\n 'off',\n 'minimal',\n 'low',\n 'medium',\n 'high',\n 'xhigh',\n] as const;\nexport type ThinkingLevel = (typeof THINKING_LEVELS)[number];\n\n/** Whether a value (e.g. remote prompt frontmatter) names a valid effort. */\nexport function isThinkingLevel(value: unknown): value is ThinkingLevel {\n return (THINKING_LEVELS as readonly unknown[]).includes(value);\n}\n\n/**\n * An effort *override* is always a positive level — `'off'` is a model trait\n * (`reasoning: false`), not something a flag may force onto a reasoning model.\n */\nexport type EffortLevel = Exclude<ThinkingLevel, 'off'>;\n\nexport interface ModelCapabilities {\n /** Model supports reasoning; safe to request reasoning effort. */\n reasoning: boolean;\n /** Effort to request when reasoning. Omit for the harness/provider default. */\n thinkingLevel?: ThinkingLevel;\n}\n\n/**\n * Explicit per-model traits. Anything absent falls back to `defaultCaps`.\n *\n * A reasoning model without a `thinkingLevel` leaves the effort to the harness,\n * and the mint pins effort per model (posthog `WIZARD_MODEL_ALLOWLIST`), so an\n * unpinned reasoning model is refused with no tool calls. Every level below is\n * one the mint allows for that model.\n */\nexport const MODEL_CAPABILITIES: Record<string, ModelCapabilities> = {\n // The mint takes sonnet 5 at `none` or `high`; high is the only level it\n // serves once reasoning is on.\n [SONNET_5_MODEL]: { reasoning: true, thinkingLevel: 'high' },\n // The mint takes haiku with no effort parameter at all, which is `off`.\n [HAIKU_MODEL]: { reasoning: true, thinkingLevel: 'off' },\n // The openai 5.6 line; all reasoning models, so they must opt in past the\n // openai-completions default (reasoning off). Luna stays low for cheap,\n // short-context mechanical work; terra runs medium as the sonnet-tier parallel\n // — enough reasoning depth for the judgment tasks without high's latency blowup.\n [GPT5_6_LUNA_MODEL]: { reasoning: true, thinkingLevel: 'low' },\n [GPT5_6_TERRA_MODEL]: { reasoning: true, thinkingLevel: 'medium' },\n [GPT5_6_SOL_MODEL]: { reasoning: true, thinkingLevel: 'medium' },\n};\n\n/**\n * The mint's per-model effort pin, mirrored from posthog\n * `WIZARD_MODEL_ALLOWLIST`. `'off'` is the CLI's spelling of the mint's\n * `\"none\"` — a call carrying no effort parameter.\n */\nexport const MINT_ALLOWED_EFFORTS: Record<string, readonly ThinkingLevel[]> = {\n [SONNET_5_MODEL]: ['off', 'high'],\n [HAIKU_MODEL]: ['off'],\n [GPT5_6_LUNA_MODEL]: ['low'],\n [GPT5_6_SOL_MODEL]: ['medium'],\n [GPT5_6_TERRA_MODEL]: ['low', 'medium', 'high'],\n};\n\n// Local model choices; gateway admission also requires allowed models, efforts, and prompt compatibility.\nexport const VALID_MODELS: ReadonlySet<string> = new Set(\n Object.keys(MODEL_CAPABILITIES),\n);\n\n/** Whether the value is an allow-listed model. */\nexport function isValidModel(model: unknown): model is string {\n return typeof model === 'string' && VALID_MODELS.has(model);\n}\n\n/** First allow-listed candidate, else throw so a bad id fails loud. */\nexport function requireKnownModel(\n ...candidates: (string | undefined)[]\n): string {\n for (const c of candidates) if (isValidModel(c)) return c;\n throw new Error(\n `No valid model to dispatch on (tried ${JSON.stringify(candidates)}). ` +\n `Allowed: ${[...VALID_MODELS].join(', ')}.`,\n );\n}\n\n// Unknown Anthropic models default to reasoning; OpenAI models must opt in through the local table.\nfunction defaultCaps(modelId: string): ModelCapabilities {\n return { reasoning: !modelId.startsWith('openai/') };\n}\n\n// Triage requests must satisfy gateway safety policy and preserve Warlock’s classifier format.\nexport const TRIAGE_MODELS: Record<Harness, string> = {\n [Harness.anthropic]: HAIKU_TRIAGE_MODEL,\n [Harness.pi]: GPT5_6_LUNA_MODEL,\n};\n\nexport function triageModelFor(harness: Harness): string {\n return TRIAGE_MODELS[harness];\n}\n\n/**\n * Capabilities for a gateway model id, table override then transport default.\n * `effortOverride` is a switchboard-resolved effort (e.g. from a pi effort\n * flag); it applies only when the model reasons at all — a non-reasoning model\n * rejects reasoning effort, so the override is dropped.\n */\nexport function modelCapabilities(\n modelId: string,\n effortOverride?: EffortLevel,\n): ModelCapabilities {\n const caps = MODEL_CAPABILITIES[modelId] ?? defaultCaps(modelId);\n if (caps.reasoning && effortOverride) {\n return { ...caps, thinkingLevel: effortOverride };\n }\n return caps;\n}\n"],"mappings":";;;AAYA,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACD;;AAID,SAAgB,gBAAgB,OAAwC;AACtE,QAAQ,gBAAuC,SAAS,MAAM;;;;;;;;;;AAwBhE,MAAa,qBAAwD;EAGlE,iBAAiB;EAAE,WAAW;EAAM,eAAe;EAAQ;EAE3D,cAAc;EAAE,WAAW;EAAM,eAAe;EAAO;EAKvD,oBAAoB;EAAE,WAAW;EAAM,eAAe;EAAO;EAC7D,qBAAqB;EAAE,WAAW;EAAM,eAAe;EAAU;EACjE,mBAAmB;EAAE,WAAW;EAAM,eAAe;EAAU;CACjE;AAgBD,MAAa,eAAoC,IAAI,IACnD,OAAO,KAAK,mBAAmB,CAChC;;AAGD,SAAgB,aAAa,OAAiC;AAC5D,QAAO,OAAO,UAAU,YAAY,aAAa,IAAI,MAAM;;;AAI7D,SAAgB,kBACd,GAAG,YACK;AACR,MAAK,MAAM,KAAK,WAAY,KAAI,aAAa,EAAE,CAAE,QAAO;AACxD,OAAM,IAAI,MACR,wCAAwC,KAAK,UAAU,WAAW,CAAC,cACrD,CAAC,GAAG,aAAa,CAAC,KAAK,KAAK,CAAC,GAC5C;;AAIH,SAAS,YAAY,SAAoC;AACvD,QAAO,EAAE,WAAW,CAAC,QAAQ,WAAW,UAAU,EAAE;;AAItD,MAAa,gBAAyC;gBAC/B;SACP;CACf;AAED,SAAgB,eAAe,SAA0B;AACvD,QAAO,cAAc;;;;;;;;AASvB,SAAgB,kBACd,SACA,gBACmB;CACnB,MAAM,OAAO,mBAAmB,YAAY,YAAY,QAAQ;AAChE,KAAI,KAAK,aAAa,eACpB,QAAO;EAAE,GAAG;EAAM,eAAe;EAAgB;AAEnD,QAAO"}
@@ -1,2 +0,0 @@
1
- import { r as hasDeclaredDependency } from "./package-json-2UrhE6kP.js";
2
- export { hasDeclaredDependency };