@posthog/wizard 2.83.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 (145) 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-fcDXqb-_.js → agent-interface-BNssNetq.js} +12 -12
  6. package/dist/agent-interface-BNssNetq.js.map +1 -0
  7. package/dist/{agent-prompt-loader-F9gGPMt0.js → agent-prompt-loader-iV11XVEF.js} +16 -8
  8. package/dist/agent-prompt-loader-iV11XVEF.js.map +1 -0
  9. package/dist/{analytics-GQv--mQm.js → analytics-Drox5LSW.js} +6 -5
  10. package/dist/analytics-Drox5LSW.js.map +1 -0
  11. package/dist/analytics-Ix9HEra3.js +2 -0
  12. package/dist/{api-WUOSLXPJ.js → api-Dfu655Qt.js} +2 -2
  13. package/dist/{api-WUOSLXPJ.js.map → api-Dfu655Qt.js.map} +1 -1
  14. package/dist/api-H2UaPgjv.js +2 -0
  15. package/dist/{api-key-login-tysMeZnR.js → api-key-login-BgwfAXfv.js} +5 -5
  16. package/dist/{api-key-login-tysMeZnR.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-B31zq2ir.js → bounded-fs-TRL6IsoU.js} +32 -16
  20. package/dist/bounded-fs-TRL6IsoU.js.map +1 -0
  21. package/dist/{ci-install-CYSFbFXd.js → ci-install-nc1IKuX2.js} +6 -6
  22. package/dist/{ci-install-CYSFbFXd.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-BTUMatFI.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-CJ8Jqbll.js → gateway-CLQQb96F.js} +25 -9
  34. package/dist/{gateway-CJ8Jqbll.js.map → gateway-CLQQb96F.js.map} +1 -1
  35. package/dist/headless-CHGNEzO3.js +3 -0
  36. package/dist/{headless-le-QqOuj.js → headless-DMO8N_FD.js} +2 -2
  37. package/dist/{headless-le-QqOuj.js.map → headless-DMO8N_FD.js.map} +1 -1
  38. package/dist/{host-resolution-Cht8bL39.js → host-resolution-DftfSjJD.js} +4 -4
  39. package/dist/{host-resolution-Cht8bL39.js.map → host-resolution-DftfSjJD.js.map} +1 -1
  40. package/dist/{install-BhnFP3p3.js → install-C9FPM37m.js} +6 -6
  41. package/dist/{install-BhnFP3p3.js.map → install-C9FPM37m.js.map} +1 -1
  42. package/dist/{install-55JbRsO-.js → install-MWoo1hXL.js} +1 -1
  43. package/dist/{interactive-9qRL8259.js → interactive-DOnolJHB.js} +3 -3
  44. package/dist/{interactive-9qRL8259.js.map → interactive-DOnolJHB.js.map} +1 -1
  45. package/dist/{links-5Blqk4Im.js → links-CatXPRxH.js} +3 -3
  46. package/dist/{links-5Blqk4Im.js.map → links-CatXPRxH.js.map} +1 -1
  47. package/dist/{main-CUIcozEG.js → main-CINmZtoW.js} +23 -23
  48. package/dist/{main-CUIcozEG.js.map → main-CINmZtoW.js.map} +1 -1
  49. package/dist/{mcp-D73aCOHK.js → mcp-KVV6Z_bq.js} +3 -3
  50. package/dist/{mcp-D73aCOHK.js.map → mcp-KVV6Z_bq.js.map} +1 -1
  51. package/dist/{mcp-prompt-streaming-B5lIQ0l1.js → mcp-prompt-streaming-M6UnLgGX.js} +5 -5
  52. package/dist/{mcp-prompt-streaming-B5lIQ0l1.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-CLTglHFZ.js → models-B0huHItG.js} +2 -2
  56. package/dist/{models-CLTglHFZ.js.map → models-B0huHItG.js.map} +1 -1
  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-CfkZ339p.js → oauth-session-9EU3ky0v.js} +2 -2
  60. package/dist/{oauth-session-CfkZ339p.js.map → oauth-session-9EU3ky0v.js.map} +1 -1
  61. package/dist/{orchestrator-tools-lvNVQhzs.js → orchestrator-tools-QWyDLu_7.js} +3 -3
  62. package/dist/{orchestrator-tools-lvNVQhzs.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-BqRNp5y_.js → package-manager-B-9I_fAT.js} +4 -4
  67. package/dist/{package-manager-BqRNp5y_.js.map → package-manager-B-9I_fAT.js.map} +1 -1
  68. package/dist/{pi-2pYz2OY3.js → pi-BSnSk6rv.js} +19 -20
  69. package/dist/pi-BSnSk6rv.js.map +1 -0
  70. package/dist/{playground-jxZNxRwC.js → playground-Drz1qszs.js} +4 -4
  71. package/dist/{playground-jxZNxRwC.js.map → playground-Drz1qszs.js.map} +1 -1
  72. package/dist/{posthog-integration-DxRkw5DI.js → posthog-integration-mIQGBc1f.js} +882 -2512
  73. package/dist/posthog-integration-mIQGBc1f.js.map +1 -0
  74. package/dist/programs-Bv0_YHzE.js +3 -0
  75. package/dist/{programs-eTv2T2rs.js → programs-mxhRXwP-.js} +194 -88
  76. package/dist/programs-mxhRXwP-.js.map +1 -0
  77. package/dist/provisioning-BVsxSNve.js +2 -0
  78. package/dist/{provisioning-c5JJ30KX.js → provisioning-CHUjae9V.js} +4 -4
  79. package/dist/{provisioning-c5JJ30KX.js.map → provisioning-CHUjae9V.js.map} +1 -1
  80. package/dist/{queue-tools-10w8lhEs.js → queue-tools-PFG6H93Q.js} +4 -4
  81. package/dist/{queue-tools-10w8lhEs.js.map → queue-tools-PFG6H93Q.js.map} +1 -1
  82. package/dist/{results-C45prSKD.js → results-5yCKf2cI.js} +2 -2
  83. package/dist/{results-C45prSKD.js.map → results-5yCKf2cI.js.map} +1 -1
  84. package/dist/{run-jugssomh.js → run-D5TKJuSL.js} +10 -10
  85. package/dist/{run-jugssomh.js.map → run-D5TKJuSL.js.map} +1 -1
  86. package/dist/{run-CM24OgPF.js → run-W03b6jNM.js} +12 -12
  87. package/dist/{run-CM24OgPF.js.map → run-W03b6jNM.js.map} +1 -1
  88. package/dist/{run-tool-DZrZFoGq.js → run-tool-DTQF8mmI.js} +17 -17
  89. package/dist/{run-tool-DZrZFoGq.js.map → run-tool-DTQF8mmI.js.map} +1 -1
  90. package/dist/run-tool-DjERhu7G.js +2 -0
  91. package/dist/{runners-CoIYt0iI.js → runners-B_84kPyf.js} +11 -11
  92. package/dist/{runners-CoIYt0iI.js.map → runners-B_84kPyf.js.map} +1 -1
  93. package/dist/{security-ppK2MwCn.js → security-pApVawYb.js} +5 -5
  94. package/dist/{security-ppK2MwCn.js.map → security-pApVawYb.js.map} +1 -1
  95. package/dist/{setup-utils-B5E1rXLa.js → setup-utils-CQY8PHjR.js} +3 -3
  96. package/dist/{setup-utils-B5E1rXLa.js.map → setup-utils-CQY8PHjR.js.map} +1 -1
  97. package/dist/{start-playground-DujiUNFT.js → start-playground-DAw1GbLt.js} +8 -8
  98. package/dist/{start-playground-DujiUNFT.js.map → start-playground-DAw1GbLt.js.map} +1 -1
  99. package/dist/{subagent-BdDWA8j5.js → subagent-YLGSvgoZ.js} +4 -4
  100. package/dist/subagent-YLGSvgoZ.js.map +1 -0
  101. package/dist/{task-Y8lWoDE7.js → task-3hRSovmK.js} +19 -20
  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-Cwqf0iur.js → telemetry-BPBzqsb_.js} +2 -2
  106. package/dist/{telemetry-Cwqf0iur.js.map → telemetry-BPBzqsb_.js.map} +1 -1
  107. package/dist/{terminal-BLL-X6YP.js → terminal-DZsYFbm9.js} +92 -63
  108. package/dist/terminal-DZsYFbm9.js.map +1 -0
  109. package/dist/{tools-C8k90ISV.js → tools-D_AtrhbO.js} +15 -15
  110. package/dist/{tools-C8k90ISV.js.map → tools-D_AtrhbO.js.map} +1 -1
  111. package/dist/{tools-g42e5kJz.js → tools-DyzRi_dQ.js} +8 -8
  112. package/dist/{tools-g42e5kJz.js.map → tools-DyzRi_dQ.js.map} +1 -1
  113. package/dist/{tui-CBnRWnrm.js → tui-CRp0iCuT.js} +5 -5
  114. package/dist/{tui-CBnRWnrm.js.map → tui-CRp0iCuT.js.map} +1 -1
  115. package/dist/{tui-BPWJ-J-k.js → tui-UI6ctBQJ.js} +1 -1
  116. package/dist/{upload-step-CFoxwd5t.js → upload-step-DrYXnpzI.js} +3 -3
  117. package/dist/{upload-step-CFoxwd5t.js.map → upload-step-DrYXnpzI.js.map} +1 -1
  118. package/dist/{urls-BTZhm5eA.js → urls-WeqfBLP4.js} +2 -2
  119. package/dist/{urls-BTZhm5eA.js.map → urls-WeqfBLP4.js.map} +1 -1
  120. package/dist/{wizard-abort-HtpiSsQO.js → wizard-abort-BwEefm6P.js} +5 -5
  121. package/dist/{wizard-abort-HtpiSsQO.js.map → wizard-abort-BwEefm6P.js.map} +1 -1
  122. package/dist/yara-hooks-MDtFbuoM.js +2 -0
  123. package/dist/{yara-hooks-BPYhN9WM.js → yara-hooks-aDbdsitJ.js} +41 -5
  124. package/dist/{yara-hooks-BPYhN9WM.js.map → yara-hooks-aDbdsitJ.js.map} +1 -1
  125. package/package.json +9 -7
  126. package/dist/agent-interface-fcDXqb-_.js.map +0 -1
  127. package/dist/agent-prompt-loader-F9gGPMt0.js.map +0 -1
  128. package/dist/analytics-C9QnGvuc.js +0 -2
  129. package/dist/analytics-GQv--mQm.js.map +0 -1
  130. package/dist/api-CsXfZKkq.js +0 -2
  131. package/dist/api-key-login-CDSxsYtP.js +0 -2
  132. package/dist/bounded-fs-B31zq2ir.js.map +0 -1
  133. package/dist/debug-BTUMatFI.js.map +0 -1
  134. package/dist/headless-DZ3mq07K.js +0 -3
  135. package/dist/package-json-Dblip2_X.js +0 -2
  136. package/dist/pi-2pYz2OY3.js.map +0 -1
  137. package/dist/posthog-integration-DxRkw5DI.js.map +0 -1
  138. package/dist/programs-D2793-PK.js +0 -3
  139. package/dist/programs-eTv2T2rs.js.map +0 -1
  140. package/dist/provisioning-CtQ0GEHa.js +0 -2
  141. package/dist/run-tool-BZFgFb_2.js +0 -2
  142. package/dist/subagent-BdDWA8j5.js.map +0 -1
  143. package/dist/task-Y8lWoDE7.js.map +0 -1
  144. package/dist/terminal-BLL-X6YP.js.map +0 -1
  145. package/dist/yara-hooks-BwhEDXIt.js +0 -2
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent-prompt-loader-F9gGPMt0.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,2 +0,0 @@
1
- import { n as analytics } from "./analytics-GQv--mQm.js";
2
- export { analytics };
@@ -1 +0,0 @@
1
- {"version":3,"file":"analytics-GQv--mQm.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';\nexport const GPT6_SOL_MODEL = 'openai/gpt-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 ApiError } from "./api-WUOSLXPJ.js";
2
- export { ApiError };
@@ -1,2 +0,0 @@
1
- import { t as resolveApiKeyProject } from "./api-key-login-tysMeZnR.js";
2
- export { resolveApiKeyProject };
@@ -1 +0,0 @@
1
- {"version":3,"file":"bounded-fs-B31zq2ir.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-BTUMatFI.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.83.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":"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"}
@@ -1,3 +0,0 @@
1
- import "./mode-label-DB3ol_sj.js";
2
- import { t as runHeadless } from "./headless-le-QqOuj.js";
3
- export { runHeadless };
@@ -1,2 +0,0 @@
1
- import { r as hasDeclaredDependency } from "./package-json-2UrhE6kP.js";
2
- export { hasDeclaredDependency };
@@ -1 +0,0 @@
1
- {"version":3,"file":"pi-2pYz2OY3.js","names":[],"sources":["../src/shared/status-history.ts","../src/agent/runner/shared/progress-collector.ts","../src/agent/aio-capture.ts","../src/agent/runner/harness/pi/completion.ts","../src/agent/runner/harness/pi/cancellation.ts","../src/agent/runner/harness/pi/structured-output.ts","../src/agent/runner/harness/pi/index.ts"],"sourcesContent":["/** Shared FIFO window for agent snapshots and the terminal status panel. */\nexport const MAX_STATUS_MESSAGES = 10;\n\nexport function appendStatus(messages: string[], message: string): string[] {\n if (messages.length > 0 && messages[messages.length - 1] === message) {\n return messages;\n }\n return [...messages.slice(-(MAX_STATUS_MESSAGES - 1)), message];\n}\n","/**\n * The agent's own record of what it reported.\n *\n * `runAgent` accumulates its final `RunSnapshot` here, independently of any\n * observer, so a missing or throwing `onProgress` never makes the result\n * incomplete. The emitter wraps the caller's callback: it applies the event\n * here first, then hands a copy to the observer, and logs rather than\n * propagates anything the observer throws.\n */\n\nimport { logToFile } from '@utils/debug';\nimport { appendStatus } from '@shared/status-history';\nimport type {\n AgentProgress,\n ProgressEmitter,\n SpinnerHandle,\n} from '../../progress';\nimport type { RunSnapshot } from './types';\n\nexport interface ProgressCollector {\n emit: ProgressEmitter;\n snapshot(): RunSnapshot;\n}\n\nexport function createProgressCollector(\n onProgress?: (event: AgentProgress) => unknown,\n): ProgressCollector {\n const snapshot: RunSnapshot = {\n tasks: [],\n statusMessages: [],\n usage: {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheCreationTokens: 0,\n },\n };\n\n const apply = (event: AgentProgress): void => {\n switch (event.kind) {\n case 'tasks':\n snapshot.tasks = event.tasks.map((t) => ({ ...t }));\n break;\n case 'status':\n snapshot.statusMessages = appendStatus(\n snapshot.statusMessages,\n event.message,\n );\n break;\n case 'stage':\n snapshot.stage = event.stage;\n break;\n case 'url':\n if (event.which === 'dashboard') snapshot.dashboardUrl = event.url;\n else snapshot.notebookUrl = event.url;\n break;\n case 'usage':\n snapshot.usage.inputTokens += event.delta.inputTokens;\n snapshot.usage.outputTokens += event.delta.outputTokens;\n snapshot.usage.cacheReadTokens += event.delta.cacheReadTokens;\n snapshot.usage.cacheCreationTokens += event.delta.cacheCreationTokens;\n break;\n case 'finalCost':\n snapshot.finalCostUsd = event.usd;\n break;\n case 'handoff':\n snapshot.handoffText = event.text;\n break;\n default:\n break;\n }\n };\n\n const emit: ProgressEmitter = (event) => {\n apply(event);\n if (!onProgress) return;\n try {\n const observed = onProgress(structuredClone(event));\n if (\n observed &&\n typeof (observed as PromiseLike<unknown>).then === 'function'\n ) {\n void Promise.resolve(observed).catch((error: unknown) => {\n try {\n logToFile(\n `[agent] progress observer rejected on ${event.kind}:`,\n error,\n );\n } catch {\n // Logging is best effort.\n }\n });\n }\n } catch (error) {\n // A broken projection is the host's problem, not the run's. Say so in\n // the log and carry on; the snapshot above is the source of truth.\n try {\n logToFile(\n `[agent] progress observer threw on ${event.kind}:`,\n error instanceof Error ? error.message : error,\n );\n } catch {\n // Logging is best effort.\n }\n }\n };\n\n return {\n emit,\n snapshot: () => ({\n ...snapshot,\n tasks: snapshot.tasks.map((t) => ({ ...t })),\n statusMessages: [...snapshot.statusMessages],\n usage: { ...snapshot.usage },\n }),\n };\n}\n\n/** The run spinner as a progress emitter. One per run, like `getUI().spinner()`. */\nexport function createEmitSpinner(emit: ProgressEmitter): SpinnerHandle {\n return {\n start: (message) => emit({ kind: 'spinner', action: 'start', message }),\n stop: (message) => emit({ kind: 'spinner', action: 'stop', message }),\n message: (message) => emit({ kind: 'spinner', action: 'message', message }),\n };\n}\n\n/** A leveled logger as a progress emitter: each call is one `log` event. */\nexport function createEmitLog(emit: ProgressEmitter): {\n info(message: string): void;\n warn(message: string): void;\n error(message: string): void;\n success(message: string): void;\n step(message: string): void;\n} {\n return {\n info: (message) => emit({ kind: 'log', level: 'info', message }),\n warn: (message) => emit({ kind: 'log', level: 'warn', message }),\n error: (message) => emit({ kind: 'log', level: 'error', message }),\n success: (message) => emit({ kind: 'log', level: 'success', message }),\n step: (message) => emit({ kind: 'log', level: 'step', message }),\n };\n}\n","/**\n * aio-capture — mirror wizard LLM calls into the authenticated project's\n * AI Observability tab as `$ai_generation` events. Gated on `--capture-aio`\n * (dev/test builds only); returns a no-op instance when disabled so the\n * wire-in points stay a no-op with zero overhead.\n *\n * The wizard's LLM calls happen inside subprocesses we don't own (the\n * claude-agent-sdk CLI on the anthropic path, pi's own runtime on pi), so we\n * can't wrap the client with `posthog-node`'s `wrapAnthropic`. Instead, each\n * harness surfaces assistant turns on the way back — the SDK message stream\n * on anthropic, `agentSession.subscribe(message_end)` on pi — and this module\n * composes an `$ai_generation` event from either shape.\n *\n * For the Conversation tab in AIO to render anything, each generation needs\n * `$ai_input` (the messages the model saw when it produced this turn). The\n * initial prompt is passed to the SDK subprocess and never echoed back on\n * the stream, so callers must hand it to `setInitialPrompt` before the run\n * starts. From there we track user/assistant turns as they flow through the\n * stream, snapshotting the running conversation into each generation's\n * `$ai_input` and firing `$ai_input_state` / `$ai_output_state` on the\n * terminal `$ai_trace` event.\n *\n * POSTs are fire-and-forget: failures are debug-logged and never surfaced to\n * the main agent flow. Losing an AIO event must never break a run.\n */\n\nimport { logToFile } from '@utils/debug';\nimport { VERSION } from '@shared/version';\n\n/** Conversation turn shape both harnesses normalize to. Matches Anthropic\n * message role/content conventions, which is also what AIO's Conversation\n * tab knows how to render. */\ntype Turn = { role: 'user' | 'assistant'; content: unknown };\n\n/** Common shape both harness transforms emit; fed to the shared POST. */\ntype LLMTurn = {\n provider: 'anthropic' | 'openai';\n model: string;\n /** Conversation up to (but not including) this assistant turn — the\n * messages the model saw. Sent as `$ai_input`. */\n input: Turn[];\n /** Content blocks (text + tool_use), passed through as $ai_output_choices. */\n outputChoices: unknown[];\n inputTokens?: number;\n outputTokens?: number;\n cacheReadTokens?: number;\n cacheCreationTokens?: number;\n /** Wall-clock ms since the previous assistant turn on this stream. */\n latencyMs: number;\n generationId?: string;\n isError: boolean;\n};\n\nexport type AioCapture = {\n /** Set the initial prompt the harness is about to send to the LLM. The\n * wizard passes this into the SDK subprocess out-of-band, so it never\n * appears on the return message stream — the caller must hand it to us\n * explicitly if we want `$ai_input` to include it. Safe to call multiple\n * times: latest wins, prior conversation state resets. */\n setInitialPrompt(prompt: string): void;\n /** Called for every SDK message on the anthropic harness stream. */\n captureFromAnthropicSDKMessage(msg: unknown): void;\n /** Called for every subscribe event on the pi harness. */\n captureFromPiMessageEndEvent(event: unknown): void;\n finishPiRun(isError: boolean): void;\n};\n\nconst noop = (_: unknown): void => undefined;\nconst NOOP: AioCapture = {\n setInitialPrompt: noop,\n captureFromAnthropicSDKMessage: noop,\n captureFromPiMessageEndEvent: noop,\n finishPiRun: noop,\n};\n\nexport function createAioCapture(args: {\n enabled: boolean;\n projectApiKey: string;\n apiHost: string;\n /** Trace tags from `buildRunTags` (program_id, integration, run_id, build, skill_id). */\n runTags: Record<string, string>;\n}): AioCapture {\n if (!args.enabled || !args.projectApiKey || !args.apiHost) return NOOP;\n\n const { projectApiKey, apiHost, runTags } = args;\n const distinctId = `wizard-cli-${VERSION}`;\n const captureUrl = `${apiHost.replace(/\\/$/, '')}/capture/`;\n const runStartAt = Date.now();\n // Latency is measured against the previous assistant turn on this stream —\n // a rough proxy for time-to-first-token that doesn't require SDK-internal\n // timings. Reset per createAioCapture (once per agent run).\n let prevTurnAt = runStartAt;\n // Fire the top-level `$ai_trace` event at most once per instance. Both\n // harnesses can emit terminal signals, and pi in particular may emit\n // multiple `agent_end` events across nudges — first-wins keeps trace\n // metadata stable in AIO.\n let traceEnded = false;\n\n // Running conversation state — grows as user and assistant turns flow\n // through the stream. Snapshotted into `$ai_input` on each generation.\n let initialPrompt: string | undefined;\n let conversation: Turn[] = [];\n let lastAssistantContent: unknown[] | undefined;\n\n const postEvent = (\n event: string,\n properties: Record<string, unknown>,\n ): void => {\n const body = {\n api_key: projectApiKey,\n event,\n distinct_id: distinctId,\n properties: {\n $ai_trace_id: runTags.run_id ?? '',\n ...runTags,\n ...properties,\n },\n timestamp: new Date().toISOString(),\n };\n\n // Fire-and-forget. `.then` + `.catch` (not `await`) so the caller returns\n // immediately; both branches only log. Errors must never propagate into\n // the agent stream loop.\n fetch(captureUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n .then((res) => {\n if (!res.ok) {\n logToFile(`[aio-capture] POST failed status=${res.status}`);\n }\n })\n .catch((err) => {\n logToFile(\n `[aio-capture] POST error: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n });\n };\n\n const postGeneration = (turn: LLMTurn): void => {\n postEvent('$ai_generation', {\n $ai_provider: turn.provider,\n $ai_model: turn.model,\n $ai_input: turn.input,\n $ai_output_choices: turn.outputChoices,\n $ai_input_tokens: turn.inputTokens ?? 0,\n $ai_output_tokens: turn.outputTokens ?? 0,\n $ai_cache_read_input_tokens: turn.cacheReadTokens ?? 0,\n $ai_cache_creation_input_tokens: turn.cacheCreationTokens ?? 0,\n $ai_latency: turn.latencyMs / 1000,\n $ai_generation_id: turn.generationId ?? '',\n $ai_is_error: turn.isError,\n });\n };\n\n // Emit the top-level `$ai_trace` event. Without this, PostHog builds a\n // pseudo-trace from the generations — the timeline and aggregates still\n // work, but the trace has no readable name and the Conversation tab shows\n // \"No top-level trace event\". Sending this once per run fills that in,\n // and `$ai_input_state` / `$ai_output_state` populate the trace-level\n // Conversation view.\n const sendTraceEnd = (opts: { isError: boolean }): void => {\n if (traceEnded) return;\n traceEnded = true;\n postEvent('$ai_trace', {\n $ai_span_name: runTags.program_id ?? 'wizard-run',\n $ai_latency: (Date.now() - runStartAt) / 1000,\n $ai_is_error: opts.isError,\n $ai_input_state: initialPrompt\n ? [{ role: 'user', content: [{ type: 'text', text: initialPrompt }] }]\n : [],\n $ai_output_state: lastAssistantContent ?? [],\n });\n };\n\n const anthropicAssistantTurn = (msg: unknown): LLMTurn | null => {\n const m = msg as {\n type?: string;\n message?: {\n id?: string;\n model?: string;\n content?: unknown;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n };\n };\n if (m?.type !== 'assistant' || !m.message) return null;\n const now = Date.now();\n const latencyMs = now - prevTurnAt;\n prevTurnAt = now;\n return {\n provider: 'anthropic',\n model: m.message.model ?? 'unknown',\n input: [...conversation],\n outputChoices: Array.isArray(m.message.content) ? m.message.content : [],\n inputTokens: m.message.usage?.input_tokens,\n outputTokens: m.message.usage?.output_tokens,\n cacheReadTokens: m.message.usage?.cache_read_input_tokens,\n cacheCreationTokens: m.message.usage?.cache_creation_input_tokens,\n latencyMs,\n generationId: m.message.id,\n isError: false,\n };\n };\n\n const piAssistantTurn = (event: unknown): LLMTurn | null => {\n const e = event as {\n type?: string;\n message?: {\n id?: string;\n role?: string;\n model?: string;\n content?: unknown;\n stopReason?: string;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n };\n };\n // Pi emits message_end for user prompts too — filter to assistant only,\n // mirroring the existing role guard at harness/pi/index.ts:434.\n if (e?.type !== 'message_end' || e.message?.role !== 'assistant') {\n return null;\n }\n const now = Date.now();\n const latencyMs = now - prevTurnAt;\n prevTurnAt = now;\n return {\n provider: 'anthropic',\n model: e.message.model ?? 'unknown',\n input: [...conversation],\n outputChoices: Array.isArray(e.message.content) ? e.message.content : [],\n inputTokens: e.message.usage?.input_tokens,\n outputTokens: e.message.usage?.output_tokens,\n cacheReadTokens: e.message.usage?.cache_read_input_tokens,\n cacheCreationTokens: e.message.usage?.cache_creation_input_tokens,\n latencyMs,\n generationId: e.message.id,\n isError:\n e.message.stopReason === 'error' || e.message.stopReason === 'aborted',\n };\n };\n\n return {\n setInitialPrompt(prompt) {\n initialPrompt = prompt;\n // Reset conversation to the initial user turn — this is the only way\n // the initial prompt gets into `$ai_input` for the first generation,\n // since the SDK subprocess consumes it internally and doesn't echo it\n // on the return stream.\n conversation = [\n { role: 'user', content: [{ type: 'text', text: prompt }] },\n ];\n lastAssistantContent = undefined;\n },\n captureFromAnthropicSDKMessage(msg) {\n try {\n // User turns (tool_result blocks between assistant turns) accumulate\n // in the conversation so the next assistant generation carries the\n // full context the model actually saw.\n const m = msg as {\n type?: string;\n message?: { role?: string; content?: unknown };\n is_error?: boolean;\n };\n if (m?.type === 'user' && m.message) {\n conversation.push({\n role: 'user',\n content: m.message.content ?? [],\n });\n }\n const turn = anthropicAssistantTurn(msg);\n if (turn) {\n postGeneration(turn);\n // Push the assistant turn AFTER posting so the current generation's\n // $ai_input is the conversation as the model saw it (not including\n // its own response), and later turns include this one.\n conversation.push({\n role: 'assistant',\n content: turn.outputChoices,\n });\n lastAssistantContent = turn.outputChoices;\n }\n // Terminal: SDK emits a `result` message at end of run.\n if (m?.type === 'result') {\n sendTraceEnd({ isError: !!m.is_error });\n }\n } catch (err) {\n logToFile(\n `[aio-capture] anthropic compose failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n },\n captureFromPiMessageEndEvent(event) {\n try {\n // Pi's subscribe callback surfaces both user and assistant\n // message_end events. Accumulate user turns the same way as the\n // anthropic path so `$ai_input` matches the model's view.\n const e = event as {\n type?: string;\n message?: { role?: string; content?: unknown };\n willRetry?: boolean;\n };\n if (\n e?.type === 'message_end' &&\n e.message?.role === 'user' &&\n e.message\n ) {\n conversation.push({\n role: 'user',\n content: e.message.content ?? [],\n });\n }\n const turn = piAssistantTurn(event);\n if (turn) {\n postGeneration(turn);\n conversation.push({\n role: 'assistant',\n content: turn.outputChoices,\n });\n lastAssistantContent = turn.outputChoices;\n }\n // The harness decides whether a final turn recovered before ending the trace.\n } catch (err) {\n logToFile(\n `[aio-capture] pi compose failed: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n },\n finishPiRun(isError) {\n sendTraceEnd({ isError });\n },\n };\n}\n","import { AgentErrorType } from '../../../signals';\nimport type { AgentOutputSignals } from '../../../output-signals';\n\n/** Fatal setup signals use the same precedence as the legacy harness. */\nexport function setupSignalFailure(\n signals: AgentOutputSignals,\n): AgentErrorType.MCP_MISSING | AgentErrorType.RESOURCE_MISSING | undefined {\n if (signals.has('MCP_MISSING')) return AgentErrorType.MCP_MISSING;\n if (signals.has('RESOURCE_MISSING')) return AgentErrorType.RESOURCE_MISSING;\n return undefined;\n}\n\n/** Which completion guard should fail a pi run, or undefined for a clean finish. */\nexport function completionFailure(args: {\n toolCalls: number;\n openTasks: boolean;\n}): AgentErrorType | undefined {\n // No tool call at all — the project was never touched.\n if (args.toolCalls === 0) return AgentErrorType.NO_PROGRESS;\n // Acted but left tasks in its own plan unfinished (skill install not required).\n if (args.openTasks) return AgentErrorType.INCOMPLETE_TASKS;\n return undefined;\n}\n\n/**\n * Which error type a thrown pi run reports.\n *\n * Both pi entry points classified the caught message inline with the same two\n * needles, and both did it *after* firing `agent aborted` — so the event that\n * announces the abort could not name it. Pulling the classification out lets\n * each entry point decide the type first and hand it to the event, and keeps\n * the one rule in one place.\n */\nexport function runErrorType(\n message: string,\n): AgentErrorType.RATE_LIMIT | AgentErrorType.API_ERROR {\n const lower = message.toLowerCase();\n if (lower.includes('rate limit') || lower.includes('429')) {\n return AgentErrorType.RATE_LIMIT;\n }\n return AgentErrorType.API_ERROR;\n}\n","/** Bind a host signal to Pi's abort-and-wait-for-idle operation. */\nexport function bindPiCancellation(\n signal: AbortSignal | undefined,\n session: { abort(): Promise<void> },\n onAbortError?: (error: unknown) => void,\n): { abort(): void; settle(): Promise<void> } {\n let abortPromise: Promise<void> | undefined;\n const onAbort = () => {\n abortPromise ??= Promise.resolve()\n .then(() => session.abort())\n .catch((error: unknown) => {\n try {\n onAbortError?.(error);\n } catch {\n /* Abort diagnostics are best effort. */\n }\n });\n };\n signal?.addEventListener('abort', onAbort, { once: true });\n if (signal?.aborted) onAbort();\n\n return {\n abort: onAbort,\n async settle() {\n signal?.removeEventListener('abort', onAbort);\n await abortPromise;\n },\n };\n}\n","import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';\nimport type { GatewayApi } from './gateway';\n\n/** Apply the output contract at the provider boundary on every agent turn. */\nexport function structuredOutputExtension(\n schema: Record<string, unknown>,\n api: GatewayApi,\n): (pi: ExtensionAPI) => void {\n return (pi) => {\n pi.on('before_provider_request', (event) => {\n const payload = event.payload as Record<string, unknown>;\n const format = { type: 'json_schema', schema };\n switch (api) {\n case 'anthropic-messages':\n return {\n ...payload,\n output_config: { ...(payload.output_config as object), format },\n };\n case 'openai-responses':\n return {\n ...payload,\n text: {\n ...(payload.text as object),\n format: { ...format, name: 'wizard_result', strict: true },\n },\n };\n case 'openai-completions':\n // `gatewayApiFor` never routes here, so no envelope is defined for it.\n throw new Error(\n 'Structured output is not supported on Chat Completions',\n );\n }\n });\n };\n}\n","/**\n * The `pi` backend — the challenger. Drives pi.dev's coding agent\n * (`@earendil-works/pi-coding-agent`) against the PostHog LLM gateway, behind\n * `wizard-orchestrator`. It owns the agent loop and model transport; prompt\n * assembly, error routing, and the outro stay in `linear.ts`, shared with the\n * `anthropic` control.\n *\n * Transport: the gateway is registered as an `anthropic-messages` provider\n * (same protocol the claude-agent-sdk path uses), bearer auth, Bedrock-fallback\n * + wizard metadata/flag headers, model id matched to `anthropic` for a clean\n * A/B. Security parity (canUseTool + YARA) and skills/MCP discovery are\n * follow-ups (#525, #524 skills) — v1 uses pi's built-in coding tools.\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { getLogFilePath, logToFile } from '@utils/debug';\nimport {\n Harness,\n Sequence,\n WIZARD_REMARK_EVENT_NAME,\n wizardUserAgentForProgram,\n} from '@shared/constants';\nimport { analytics } from '@utils/analytics';\nimport { AgentErrorType } from '../../../agent-interface';\nimport {\n AgentSignals,\n REMARK_INSTRUCTION,\n policyAbortReason,\n} from '../../../signals';\nimport { AgentOutputSignals } from '../../../output-signals';\nimport { assembleCommandments } from '../../switchboard/commandments';\nimport { gatewayAuth, type GatewayAuth } from '../../../gateway-session';\nimport { currentAccessToken } from '@shared/oauth-session';\nimport {\n buildGatewayProvider,\n GATEWAY_PROVIDER,\n withGatewayRemint,\n} from './gateway';\nimport { createAioCapture } from '../../../aio-capture';\nimport type {\n AgentResult,\n AgentHarness,\n BackendRunInputs,\n TaskRunInputs,\n} from '../types';\nimport type { BootstrapResult } from '../../shared/types';\nimport type { ProgressEmitter } from '../../../progress';\nimport { createEmitLog } from '../../shared/progress-collector';\nimport type { TaskStore } from './tasks';\nimport type { SecurityState } from './security';\nimport {\n completionFailure,\n runErrorType,\n setupSignalFailure,\n} from './completion';\nimport { bindPiCancellation } from './cancellation';\nimport { structuredOutputExtension } from './structured-output';\nimport { classifyRunFailure, ErrorCodes } from '@shared/errors';\n\n/** Injects the MCP server `instructions` pi-mcp-adapter drops (project env, skill steer, tool domains) into the system prompt, falling back to a bootstrap-derived project block when the warm-connect captured none. */\nfunction piMcpContext(\n boot: BootstrapResult,\n instructions?: string,\n posthogMcp = true,\n): string {\n // No tool, no block. The fallback below names `posthog_exec`, so emitting it\n // after a failed handshake points the agent at a tool that is not registered.\n if (!posthogMcp) return '';\n if (instructions) {\n // Heading + verbatim server instructions (see PR #862 for a full sample).\n return ['', '## PostHog MCP server', instructions].join('\\n');\n }\n const project = boot.project?.name\n ? `${boot.project.name} (id ${boot.credentials.projectId})`\n : `id ${boot.credentials.projectId}`;\n // Fallback: a `## PostHog project` block with name/id, host, region.\n return [\n '',\n '## PostHog project',\n 'Your `posthog_exec` calls run against this project:',\n `- Project: ${project}`,\n `- Host: ${boot.credentials.host.apiHost}`,\n `- Region: ${boot.credentials.host.region}`,\n ].join('\\n');\n}\n\n/**\n * The ONLY environment variables pi's tool subprocesses (bash → npm/pip/…) are\n * allowed to see. Everything else — every secret (POSTHOG_PERSONAL_API_KEY,\n * ANTHROPIC_*, AWS_*), every ambient credential, the parent process's whole env\n * — is dropped before a child is spawned. pi's own gateway auth is programmatic\n * (the access token never lives in env), so a minimal env costs the agent\n * nothing while closing the leak that exposed the key before. Kept to what a\n * package manager genuinely needs to run.\n */\nconst ALLOWED_SUBPROCESS_ENV_KEYS = [\n 'PATH',\n 'HOME',\n 'SHELL',\n 'USER',\n 'LOGNAME',\n 'TMPDIR',\n 'TMP',\n 'TEMP',\n 'TERM',\n 'LANG',\n 'LC_ALL',\n 'LC_CTYPE',\n 'NODE_EXTRA_CA_CERTS',\n 'SSL_CERT_FILE',\n 'SSL_CERT_DIR',\n 'HTTP_PROXY',\n 'HTTPS_PROXY',\n 'NO_PROXY',\n 'http_proxy',\n 'https_proxy',\n 'no_proxy',\n];\n\n/** A fresh subprocess env holding only the allowlisted keys present in process.env. */\nexport function buildScrubbedEnv(): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n for (const key of ALLOWED_SUBPROCESS_ENV_KEYS) {\n const value = process.env[key];\n if (value !== undefined) env[key] = value;\n }\n return env;\n}\n\n/**\n * Tag a tool with an execution mode (mutates + returns it). Read-only tools are\n * `parallel` so a single turn that batches independent reads/searches runs them\n * at once; mutating/install tools are `sequential` so a batch never races writes\n * or concurrent installs. pi-agent-core runs a batch in parallel only when no\n * tool in it is `sequential`.\n */\nexport function withMode<T>(tool: T, mode: 'sequential' | 'parallel'): T {\n (tool as { executionMode?: 'sequential' | 'parallel' }).executionMode = mode;\n return tool;\n}\n\n/**\n * The text blocks of a pi AgentMessage (content is text/image blocks). A\n * Responses model can send several message items in one turn, commentary\n * before its answer, and each becomes its own block.\n */\nfunction textBlocks(message: unknown): string[] {\n const content = (message as { content?: unknown })?.content;\n if (typeof content === 'string') return [content];\n if (Array.isArray(content)) {\n return content\n .filter((c): c is { type: string; text: string } => {\n const block = c as { type?: string; text?: unknown };\n return block?.type === 'text' && typeof block.text === 'string';\n })\n .map((c) => c.text);\n }\n return [];\n}\n\n/** Pull plain text out of a pi AgentMessage. */\nexport function extractText(message: unknown): string {\n return textBlocks(message).join('');\n}\n\n/**\n * Surface `[DASHBOARD_URL]` / `[NOTEBOOK_URL]` markers the agent prints (after\n * the MCP creates them) into the outro link, mirroring the anthropic path's\n * signal parsing (#9). The marker carries the URL the MCP returned.\n */\nexport function applyOutroMarkers(\n textBlock: string,\n emit: ProgressEmitter,\n): void {\n const markers: Array<[string, (url: string) => void]> = [\n [\n AgentSignals.DASHBOARD_URL,\n (url) => emit({ kind: 'url', which: 'dashboard', url }),\n ],\n [\n AgentSignals.NOTEBOOK_URL,\n (url) => emit({ kind: 'url', which: 'notebook', url }),\n ],\n ];\n for (const [marker, apply] of markers) {\n const idx = textBlock.indexOf(marker);\n if (idx === -1) continue;\n const url = textBlock\n .slice(idx + marker.length)\n .trim()\n .split(/\\s/)[0];\n if (url) apply(url);\n }\n}\n\n/**\n * The text of the last `[STATUS] …` line in a block, if any. Last wins so the\n * spinner shows the most recent action when a turn prints several.\n */\nexport function lastStatusLine(textBlock: string): string | undefined {\n let status: string | undefined;\n for (const line of textBlock.split('\\n')) {\n const idx = line.indexOf(AgentSignals.STATUS);\n if (idx !== -1) {\n status = line.slice(idx + AgentSignals.STATUS.length).trim();\n }\n }\n return status || undefined;\n}\n\n/** Cap on completion-guard re-prompts while tasks remain open (see the run loop). */\nconst MAX_CONTINUE_NUDGES = 20;\n\n/** Nudge re-sent when the agent stops early with tasks still open. */\nconst CONTINUE_INSTRUCTION =\n 'You still have open tasks in your list (not all are marked `completed`). Do not stop — pick up the next `in_progress` or `pending` task and keep working until every task is `completed`. Continue now.';\n\n/** True while any task in the store is not yet `completed`. */\nfunction hasOpenTasks(store: TaskStore): boolean {\n for (const t of store.values()) if (t.status !== 'completed') return true;\n return false;\n}\n\nexport const piBackend: AgentHarness = {\n name: Harness.pi,\n\n async run(inputs: BackendRunInputs): Promise<AgentResult> {\n if (inputs.signal?.aborted) {\n return {\n kind: 'abort',\n classification: AgentErrorType.ABORT,\n message: 'Agent run cancelled',\n };\n }\n const {\n config: runConfig,\n input,\n boot,\n emit,\n prompt,\n spinner,\n structured,\n } = inputs;\n const config = runConfig.run;\n const modelId = inputs.model;\n const log = createEmitLog(emit);\n\n const capture = createAioCapture({\n enabled: input.flags.captureAio,\n projectApiKey: boot.credentials.projectApiKey,\n apiHost: boot.credentials.host.apiHost,\n runTags: boot.wizardMetadata,\n });\n\n // Init banner (parity #5).\n if (!structured) {\n log.step('Initializing Wizard agent...');\n log.step(`Verbose logs: ${getLogFilePath()}`);\n log.success(\"Agent initialized. Let's get cooking!\");\n }\n\n spinner.start(config.spinnerMessage ?? 'Customizing your PostHog setup...');\n\n // Same `agent completed`/`agent aborted` shape as anthropic.\n const startTime = Date.now();\n const signals = new AgentOutputSignals();\n let assistantTurns = 0;\n let lastAssistantText = '';\n // Tool calls across the whole run. Zero means the agent only ever produced\n // text and never acted — a no-op that leaves the project untouched.\n let toolCalls = 0;\n const runDurations = () => {\n const durationMs = Date.now() - startTime;\n return {\n duration_ms: durationMs,\n duration_seconds: Math.round(durationMs / 1000),\n };\n };\n // How this run failed: the closed AgentErrorType it is about to return.\n // Without it every terminal path below — a security termination, a no-op\n // run, a plan left open, a rate limit, a gateway error — arrived as the\n // same unlabelled event, so a run that died could be counted but not\n // diagnosed. Only two of those are errors; the rest are an enforcement\n // stop and two agent behaviours, hence \"failure mode\" over \"error\".\n //\n // Not `reason`: the linear sequence emits this same event with a `reason`\n // holding the agent's free-text [ABORT] string, and one property cannot be\n // both a closed enum and unbounded prose without making either unreadable.\n // `source` tells a gateway policy refusal apart from a program's [ABORT].\n const captureAborted = (\n failureMode: AgentErrorType,\n source?: 'gateway_policy',\n ) =>\n analytics.wizardCapture('agent aborted', {\n failure_mode: failureMode,\n ...(source && { source }),\n ...runDurations(),\n model: modelId,\n });\n const timedOutResult = (timeoutMs: number): AgentResult => {\n spinner.stop('Agent run timed out');\n captureAborted(AgentErrorType.AGENTIC_DETECTION_TIMEOUT);\n return {\n kind: 'failure',\n classification: AgentErrorType.AGENTIC_DETECTION_TIMEOUT,\n message: `Agent run timed out after ${timeoutMs / 1000}s`,\n };\n };\n\n let mcpCleanup: (() => void) | undefined;\n let aioFailed = true;\n let cancellation: ReturnType<typeof bindPiCancellation> | undefined;\n let timedOut = false;\n let timeoutAbort: Promise<void> | undefined;\n let abortReason: string | undefined;\n let remarkTurn = false;\n // The gateway's refusal marker ends the run from a work turn, never the remark.\n const policyAbort = (reply: string) => {\n if (remarkTurn) return;\n abortReason ??= policyAbortReason(reply);\n if (abortReason) cancellation?.abort();\n };\n // Read by the catch path; undefined until setup creates the extension.\n let securityState: SecurityState | undefined;\n // A latched violation outranks the timer on both the success and catch paths.\n const yaraViolationResult = (): AgentResult => {\n spinner.stop('Security violation detected');\n logToFile(\n `[pi] terminated: YARA violation (blocked ${securityState?.blockedCount} call(s))`,\n );\n captureAborted(AgentErrorType.YARA_VIOLATION);\n return {\n kind: 'failure',\n classification: AgentErrorType.YARA_VIOLATION,\n };\n };\n try {\n const {\n createAgentSession,\n DefaultResourceLoader,\n SessionManager,\n AuthStorage,\n ModelRegistry,\n getAgentDir,\n createLsToolDefinition,\n createFindToolDefinition,\n createGrepToolDefinition,\n createBashToolDefinition,\n createReadToolDefinition,\n createEditToolDefinition,\n createWriteToolDefinition,\n } = await import('@earendil-works/pi-coding-agent');\n\n // the claude-agent-sdk path. The provider spec is shared with the\n // orchestrator's per-task sessions (gateway.ts). gatewayAuth mints the\n // run's scoped token.\n // Reads the live OAuth token, so a mid-run rotation re-mints on the new one.\n const refreshAuth = async () =>\n gatewayAuth(\n boot.credentials.host,\n await currentAccessToken(boot.credentials),\n boot.programId,\n );\n const auth = await refreshAuth();\n const providerInputs = (current: GatewayAuth) => ({\n gatewayUrl: current.gatewayUrl,\n accessToken: current.token,\n teamId: current.teamId,\n wizardMetadata: boot.wizardMetadata,\n wizardFlags: boot.wizardFlags,\n modelId,\n effort: inputs.thinkingLevel,\n });\n const { provider, caps, api } = buildGatewayProvider(\n providerInputs(auth),\n );\n const registry = ModelRegistry.inMemory(AuthStorage.create());\n registry.registerProvider(GATEWAY_PROVIDER, provider as never);\n\n const model = registry.find(GATEWAY_PROVIDER, modelId);\n if (!model) {\n return {\n kind: 'failure',\n classification: AgentErrorType.API_ERROR,\n message: 'pi: gateway model could not be resolved',\n };\n }\n\n // System prompt = wizard commandments. Skip project context files /\n // user extensions / skills so the run is hermetic; skills discovery is a\n // follow-up (#524).\n //\n // Fail-closed security (#525): an extension intercepts EVERY tool call —\n // built-in and custom — and reuses the anthropic policy (canUseTool\n // allowlist + .env fencing + YARA). `noExtensions: true` only suppresses\n // disk-discovered extensions; explicit `extensionFactories` still load,\n // so the fence is on while the target project can't inject its own.\n // Shared flag: true while a wizard_ask overlay is open. The ask tool\n // flips it; the security gate reads it to block Write/Edit meanwhile.\n const askState = { pending: false };\n\n const { createSecurityExtension, READ_ONLY_PI_TOOLS } = await import(\n './security'\n );\n const security = createSecurityExtension({\n readOnly: config.readOnly,\n disallowedTools: runConfig.disallowedTools,\n getWizardAskPending: () => askState.pending,\n triageProvider: boot.triageProvider,\n // Where pi's bash runs; the rm allowance is confined to this tree.\n workingDirectory: input.installDir,\n });\n securityState = security.state;\n\n // Pay warlock's WASM-init + rule-compile cost now, off the tool-call\n // path, so the first scanned call doesn't eat cold-start latency.\n const { prewarmYaraScanner } = await import('../../../yara-hooks');\n void prewarmYaraScanner();\n\n // Wire the real PostHog MCP into pi (#10): load pi's MCP adapter and point\n // it at the hosted MCP the anthropic path uses, so dashboards/insights are\n // created through the sanctioned MCP. Best-effort — if it can't load or\n // connect, the run continues (minus the dashboard step) rather than failing\n // the whole integration. The security factory is always first.\n const extensionFactories = [security.factory] as Array<\n (pi: unknown) => void\n >;\n let mcpInstructions: string | undefined;\n // Whether the agent really got the tool. The commandments below claim\n // `posthog_exec` exists when this is true, so it must track the setup and\n // not the intent — a hardcoded `true` told the agent to call a tool the\n // failed handshake never registered. `task.ts` has always done this.\n let posthogMcp = false;\n if (!config.readOnly) {\n try {\n const { setupPostHogMcp, fetchInstructions } = await import('./mcp');\n const mcpToken = await currentAccessToken(boot.credentials);\n // The backend reads the `program:` marker off this UA to attribute what the run\n // creates (a self-driving run's warehouse sources become created_via=self_driving).\n // A plain WIZARD_USER_AGENT here records them as generic wizard work.\n const mcpUserAgent = wizardUserAgentForProgram(\n config.integrationLabel,\n );\n // Overlaps the network handshake with the adapter's jiti load.\n const instructionsPromise = fetchInstructions(\n boot.credentials.host.mcpUrl,\n mcpToken,\n mcpUserAgent,\n );\n const mcp = await setupPostHogMcp({\n mcpUrl: boot.credentials.host.mcpUrl,\n accessToken: mcpToken,\n userAgent: mcpUserAgent,\n });\n extensionFactories.push(mcp.extensionFactory);\n mcpCleanup = mcp.cleanup;\n mcpInstructions = await instructionsPromise;\n posthogMcp = true;\n } catch (err) {\n try {\n mcpCleanup?.();\n } catch {\n /* Setup cleanup is best effort. */\n }\n mcpCleanup = undefined;\n logToFile(`[pi] PostHog MCP setup skipped: ${String(err)}`);\n analytics.wizardCapture('mcp setup failed', {\n harness: 'pi',\n scope: 'run',\n error: String(err).slice(0, 300),\n });\n }\n }\n\n if (structured) {\n extensionFactories.push(\n structuredOutputExtension(structured.schema, api),\n );\n }\n\n const resourceLoader = new DefaultResourceLoader({\n cwd: input.installDir,\n agentDir: getAgentDir(),\n systemPrompt:\n assembleCommandments({\n program: runConfig.programId,\n sequence: Sequence.linear,\n harness: Harness.pi,\n caps: { bash: true, posthogMcp },\n }) +\n '\\n' +\n piMcpContext(boot, mcpInstructions, posthogMcp),\n noExtensions: true,\n noSkills: true,\n noContextFiles: true,\n noPromptTemplates: true,\n noThemes: true,\n extensionFactories,\n });\n await resourceLoader.reload();\n\n // Wizard capabilities as custom tools (pi has no MCP): skill\n // discovery/install + fenced .env edits, same names as the MCP server so\n // the shared prompt is unchanged. pi's built-in Read/Write/Edit/Bash do\n // the code changes. Loaded lazily — it pulls in typebox (ESM), which must\n // stay out of the static module graph so CommonJS unit tests can load the\n // backend seam without parsing it.\n const { createWizardPiTools } = await import('./tools');\n const { createWizardPiTaskTools } = await import('./tasks');\n const { createDispatchAgentTool } = await import('./subagent');\n // Created once so the run loop can read the store for the completion guard.\n const wizardTaskTools = createWizardPiTaskTools((tasks) =>\n emit({ kind: 'tasks', tasks }),\n );\n // The one bash the agent (and its subagents) may use: every subprocess it\n // spawns gets a scrubbed env, so no secret or ambient variable reaches an\n // `npm install`. Shared with the subagent so the lockdown is inherited.\n const scrubbedBash = withMode(\n createBashToolDefinition(input.installDir, {\n spawnHook: (ctx) => ({ ...ctx, env: buildScrubbedEnv() }),\n }),\n 'sequential',\n );\n\n const customTools = [\n // Built-ins re-registered explicitly. `noTools: 'builtin'` disables pi's\n // defaults so we can supply the env-scrubbed bash above; read/edit/write\n // are the stock definitions. Reads run in parallel so a batched turn of\n // independent reads executes at once; edit/write/bash stay sequential.\n withMode(createReadToolDefinition(input.installDir), 'parallel'),\n withMode(createEditToolDefinition(input.installDir), 'sequential'),\n withMode(createWriteToolDefinition(input.installDir), 'sequential'),\n scrubbedBash,\n // Native ls/find/grep so the agent explores with proper tools instead\n // of fence-blocked `bash {ls/find}` (the profiled retry-spirals came\n // from this gap). Parallel — exploration batches cleanly.\n withMode(createLsToolDefinition(input.installDir), 'parallel'),\n withMode(createFindToolDefinition(input.installDir), 'parallel'),\n withMode(createGrepToolDefinition(input.installDir), 'parallel'),\n ...createWizardPiTools({\n workingDirectory: input.installDir,\n skillsBaseUrl: boot.skillsBaseUrl,\n triageProvider: boot.triageProvider,\n emit,\n programId: boot.programId,\n handoffNotebook: boot.handoffNotebook,\n detectPackageManager: config.detectPackageManager,\n // The host ask bridge — lets interactive programs (self-driving) ask\n // the user through pi. Threaded from the runner, same path as the\n // anthropic harness. Absent in CI → the tool errors on call.\n askBridge: inputs.askBridge,\n maxQuestions: config.maxQuestions,\n onAskPendingChange: (pending) => {\n askState.pending = pending;\n },\n // Skip wizard_ask when the program disallows it (bare pi tool names\n // don't match the MCP-prefixed disallow list at the security gate).\n disallowedTools: runConfig.disallowedTools,\n }),\n // Task/todo tools (#526): render the todo list live in the TUI, parity\n // with the anthropic path.\n ...wizardTaskTools.tools,\n // Controlled subagent dispatch (#526): a nested fenced session with a\n // read-only toolset and no dispatch_agent of its own, so it can't\n // escape the fence or recurse.\n createDispatchAgentTool({\n model,\n modelRegistry: registry,\n cwd: input.installDir,\n agentDir: getAgentDir(),\n securityFactory: security.subagentFactory,\n bashTool: scrubbedBash,\n sdk: { createAgentSession, DefaultResourceLoader, SessionManager },\n }),\n ].filter((tool) => !config.readOnly || READ_ONLY_PI_TOOLS.has(tool.name));\n\n const { session: agentSession } = await createAgentSession({\n model,\n modelRegistry: registry,\n // Reasoning effort from the switchboard capability matrix (undefined =\n // pi's default). Sent as `reasoning_effort` for openai-completions.\n thinkingLevel: caps.thinkingLevel,\n cwd: input.installDir,\n sessionManager: SessionManager.inMemory(input.installDir),\n resourceLoader,\n // Disable the default built-in tools; `customTools` re-registers\n // read/edit/write + an env-scrubbed bash, so no subprocess inherits the\n // host env. Custom + extension tools stay enabled.\n noTools: 'builtin',\n customTools,\n });\n\n // Fire the extension lifecycle — what interactive mode does via\n // rebindCurrentSession. createAgentSession builds the session but does not\n // emit session_start on its own, and the MCP adapter connects on that\n // event; without this its tools report \"MCP not initialized\".\n cancellation = bindPiCancellation(\n inputs.signal,\n agentSession,\n (error) => {\n logToFile(`[pi] abort failed: ${String(error)}`);\n },\n );\n await agentSession.bindExtensions({});\n\n // A turn that ends on a 401 from an aged bearer re-mints once and\n // continues; pi resolves the provider's apiKey per request, so\n // re-registering is enough.\n const turns = withGatewayRemint({\n signal: inputs.signal,\n session: agentSession,\n registry,\n auth,\n refreshAuth,\n providerInputs,\n continueText: CONTINUE_INSTRUCTION,\n onRemint: () => {\n logToFile('[pi] gateway token renewed after a 401; continuing');\n analytics.wizardCapture('gateway token reminted', { harness: 'pi' });\n },\n });\n\n // Map pi events onto the run spinner + the log file, mirroring the\n // anthropic path's log shape (assistant turns + tool I/O) and driving the\n // single run spinner with one stable status at a time (no overlap).\n const unsubscribe = agentSession.subscribe((event) => {\n // Mirror the turn into AIO. No-op when --capture-aio is off. Runs\n // before the role guard so the module's own filter (assistant-only)\n // stays the single source of truth for what's captured.\n capture.captureFromPiMessageEndEvent(event);\n\n switch (event.type) {\n case 'message_end': {\n // User prompts also emit message_end; only assistant turns count.\n if ((event.message as { role?: string })?.role !== 'assistant') {\n break;\n }\n assistantTurns += 1;\n turns.noteAssistantTurn(event.message);\n const blocks = textBlocks(event.message);\n const assistant = blocks.join('').trim();\n policyAbort(assistant);\n // A schema-bound answer is the turn's last block, not the joined text.\n lastAssistantText = (blocks.at(-1) ?? '').trim();\n if (structured) {\n // One block per transcript line, so recovery can parse each.\n inputs.middleware?.onMessage({\n type: 'assistant',\n message: {\n content: blocks.map((text) => ({ type: 'text', text })),\n },\n });\n }\n if (assistant) {\n logToFile(`[pi] assistant: ${assistant.slice(0, 1000)}`);\n applyOutroMarkers(assistant, emit);\n // Surface [STATUS] lines into the live spinner + status history,\n // mirroring the anthropic path — pi otherwise drops them.\n const statusText = lastStatusLine(assistant);\n if (statusText) {\n emit({ kind: 'status', message: statusText });\n spinner.message(statusText);\n }\n for (const line of assistant.split('\\n')) signals.push(line);\n }\n break;\n }\n case 'tool_execution_start': {\n toolCalls += 1;\n const args = JSON.stringify(event.args ?? {}).slice(0, 200);\n logToFile(`[pi] → ${event.toolName} ${args}`);\n if (structured) {\n inputs.middleware?.onMessage({\n type: 'assistant',\n message: {\n content: [\n {\n type: 'tool_use',\n name: event.toolName,\n input: event.args,\n },\n ],\n },\n });\n }\n // Don't surface raw tool names in the spinner — the anthropic path\n // doesn't, and it reads as noise. The Task panel (syncTodos) is the\n // visible progress, matching the anthropic presentation.\n break;\n }\n case 'tool_execution_end': {\n // Log every result in full, matching the anthropic path's\n // SDK-message logging. Call-only logs make failed runs\n // undiagnosable: a tool can fail (or return something the model\n // misreads) with no trace of what came back.\n logToFile(\n `[pi] ${event.isError ? '✗' : '←'} ${event.toolName}: ${\n typeof event.result === 'string'\n ? event.result\n : JSON.stringify(event.result ?? '')\n }`,\n );\n // A subagent's refusal comes back as its tool result, not as parent text.\n if (event.toolName === 'dispatch_agent')\n policyAbort(extractText(event.result));\n break;\n }\n case 'agent_end': {\n logToFile(`[pi] agent_end (willRetry=${String(event.willRetry)})`);\n break;\n }\n default:\n break;\n }\n });\n\n // Seed AIO capture with the initial prompt so the first assistant\n // turn's `$ai_input` includes it — pi's subscribe stream doesn't emit\n // a message_end for the initial prompt, only for tool_result user\n // turns that follow.\n capture.setInitialPrompt(prompt);\n\n let terminal = turns.terminalFailure();\n // A structured run's budget starts once setup is done.\n const timeout =\n structured &&\n setTimeout(() => {\n timedOut = true;\n timeoutAbort = agentSession.abort().catch((error: unknown) => {\n logToFile(`[pi] timeout abort failed: ${String(error)}`);\n });\n }, structured.timeoutMs);\n try {\n if (inputs.signal?.aborted)\n return {\n kind: 'abort',\n classification: AgentErrorType.ABORT,\n message: 'Agent run cancelled',\n };\n // Non-streaming: resolves when the agent run completes. Throws if no\n // model/api key, or on a transport error.\n await turns.prompt(prompt);\n terminal = turns.terminalFailure();\n\n // Completion guard: pi's prompt() resolves the moment the model returns\n // a turn with no tool call (e.g. a lone [STATUS] line), even mid-plan.\n // While tasks remain open and we're under the cap, nudge it to continue.\n // A schema-bound scan has no plan to finish, so it never gets nudged.\n let continueNudges = 0;\n while (\n !structured &&\n continueNudges < MAX_CONTINUE_NUDGES &&\n !security.state.criticalViolation &&\n !inputs.signal?.aborted &&\n !terminal &&\n !abortReason &&\n !setupSignalFailure(signals) &&\n hasOpenTasks(wizardTaskTools.store)\n ) {\n continueNudges += 1;\n logToFile(\n `[pi] completion guard: tasks still open, nudge ${continueNudges}/${MAX_CONTINUE_NUDGES}`,\n );\n await turns.prompt(CONTINUE_INSTRUCTION);\n terminal = turns.terminalFailure();\n }\n\n // Best-effort remark ask — a failed turn never fails a successful run.\n if (\n !structured &&\n !security.state.criticalViolation &&\n !terminal &&\n !abortReason &&\n !setupSignalFailure(signals) &&\n !inputs.signal?.aborted\n ) {\n remarkTurn = true;\n try {\n await agentSession.prompt(REMARK_INSTRUCTION);\n } catch (err) {\n logToFile(`[pi] remark request failed: ${String(err)}`);\n }\n }\n } finally {\n if (timeout) clearTimeout(timeout);\n try {\n unsubscribe();\n } catch {\n /* Keep the terminal result. */\n }\n }\n\n if (inputs.signal?.aborted) {\n return {\n kind: 'abort',\n classification: AgentErrorType.ABORT,\n message: 'Agent run cancelled',\n };\n }\n if (timedOut && structured && !security.state.criticalViolation)\n return timedOutResult(structured.timeoutMs);\n\n if (abortReason)\n terminal = {\n classification: AgentErrorType.ABORT,\n message: abortReason,\n };\n if (terminal && !security.state.criticalViolation) {\n spinner.stop(\n config.errorMessage ?? `${config.integrationLabel} failed`,\n );\n captureAborted(\n terminal.classification,\n abortReason ? 'gateway_policy' : undefined,\n );\n if (terminal.status === 401) {\n return {\n kind: 'decided_failure',\n failure: {\n code: ErrorCodes.AuthInvalidOrExpired,\n message: 'Authentication failed (401)',\n detail: { providerMessage: terminal.message },\n },\n };\n }\n return terminal.classification === AgentErrorType.ABORT\n ? {\n kind: 'abort',\n classification: AgentErrorType.ABORT,\n message: terminal.message,\n }\n : {\n kind: 'failure',\n classification: terminal.classification,\n message: terminal.message,\n };\n }\n\n // A latched post-scan violation terminates the run as a YARA violation,\n // matching the anthropic path's AgentErrorType.YARA_VIOLATION.\n if (security.state.criticalViolation) return yaraViolationResult();\n\n const setupFailure = setupSignalFailure(signals);\n if (setupFailure) {\n spinner.stop('Agent could not access setup instructions');\n logToFile(`[pi] setup failed: ${setupFailure}`);\n captureAborted(setupFailure);\n return { kind: 'failure', classification: setupFailure };\n }\n\n // pi ends a run on any tool-call-less turn, so guard against a hollow\n // success reaching the outro (nothing done, or stopped mid-plan).\n const openTasks = !structured && hasOpenTasks(wizardTaskTools.store);\n const failure = completionFailure({ toolCalls, openTasks });\n if (failure === AgentErrorType.NO_PROGRESS) {\n spinner.stop('Agent made no changes');\n logToFile(\n `[pi] no progress: ${assistantTurns} assistant turn(s), 0 tool calls`,\n );\n analytics.wizardCapture('agent no progress', {\n assistant_turns: assistantTurns,\n });\n // A schema-bound run with no tool calls produced no typed result.\n const classification = structured\n ? AgentErrorType.INVALID_STRUCTURED_OUTPUT\n : failure;\n captureAborted(classification);\n return { kind: 'failure', classification };\n }\n if (failure === AgentErrorType.INCOMPLETE_TASKS) {\n spinner.stop('Agent stopped before finishing');\n logToFile('[pi] incomplete: tasks left open');\n analytics.wizardCapture('agent incomplete tasks', { open_tasks: true });\n captureAborted(failure);\n return { kind: 'failure', classification: failure };\n }\n\n const remark = signals.remark();\n if (remark) {\n analytics.capture(WIZARD_REMARK_EVENT_NAME, { remark });\n }\n\n // A failed install_skill is non-fatal — the agent continues best-effort\n // without the skill — but every such run must be measurable.\n const skillFailure = signals.skillInstallFailure();\n if (skillFailure !== undefined) {\n analytics.wizardCapture('agent continued without skill', {\n detail: skillFailure,\n });\n }\n\n // The skill plans events into .posthog-events.json then asks the agent to\n // remove it on completion; clean it up host-side too, so a skipped step\n // never leaves a stale (often empty) artifact (#15).\n try {\n const planFile = path.join(input.installDir, '.posthog-events.json');\n if (!structured && fs.existsSync(planFile))\n await fs.promises.rm(planFile);\n } catch (err) {\n logToFile(`[pi] .posthog-events.json cleanup skipped: ${String(err)}`);\n }\n\n const stats = agentSession.getSessionStats();\n analytics.wizardCapture('agent completed', {\n ...runDurations(),\n model: modelId,\n num_turns: assistantTurns,\n // API-reported tokens only; no total_cost_usd — the API returns no\n // cost, and $ai_generation already prices the run authoritatively.\n input_tokens: stats.tokens.input,\n output_tokens: stats.tokens.output,\n cache_creation_input_tokens: stats.tokens.cacheWrite,\n cache_read_input_tokens: stats.tokens.cacheRead,\n });\n spinner.stop(config.successMessage ?? 'PostHog integration complete');\n aioFailed = false;\n if (!structured) return { kind: 'success' };\n try {\n return {\n kind: 'success',\n structuredOutput: JSON.parse(lastAssistantText),\n };\n } catch {\n // The caller validates the result and owns its bounded retry.\n return { kind: 'success' };\n }\n } catch (err) {\n if (inputs.signal?.aborted) {\n return {\n kind: 'abort',\n classification: AgentErrorType.ABORT,\n message: 'Agent run cancelled',\n };\n }\n if (securityState?.criticalViolation) return yaraViolationResult();\n if (timedOut && structured) return timedOutResult(structured.timeoutMs);\n const message = err instanceof Error ? err.message : String(err);\n logToFile(`[pi] run error: ${message}`);\n spinner.stop(config.errorMessage ?? `${config.integrationLabel} failed`);\n log.error(`pi backend error: ${message}`);\n const coded = classifyRunFailure(err);\n if (coded.coded && err instanceof Error) {\n captureAborted(AgentErrorType.API_ERROR);\n return {\n kind: 'decided_failure',\n failure: { code: coded.code, message: coded.message, error: err },\n };\n }\n const classification = runErrorType(message);\n captureAborted(classification);\n return {\n kind: 'failure',\n classification,\n message,\n error: err instanceof Error ? err : undefined,\n };\n } finally {\n await cancellation?.settle();\n await timeoutAbort;\n try {\n mcpCleanup?.();\n } catch {\n /* Keep the terminal result. */\n }\n try {\n capture.finishPiRun(aioFailed);\n } catch {\n /* Telemetry is best effort. */\n }\n }\n },\n\n // Orchestrator mode: one fresh pi session per seed plan / drained task, with\n // the in-process queue tools registered as pi custom tools. Lazily imported —\n // task.ts pulls in typebox (ESM), which must stay out of the static module\n // graph so CommonJS unit tests can load the backend seam without parsing it.\n async runTask(inputs: TaskRunInputs): Promise<AgentResult> {\n const { runPiTask } = await import('./task');\n return runPiTask(inputs);\n },\n};\n"],"mappings":"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"}