@posthog/wizard 2.36.0 → 2.37.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 (63) hide show
  1. package/README.md +6 -3
  2. package/dist/{add-mcp-server-to-clients-D5e3JbUC.js → add-mcp-server-to-clients-CNn9br9l.js} +4 -4
  3. package/dist/{add-mcp-server-to-clients-D5e3JbUC.js.map → add-mcp-server-to-clients-CNn9br9l.js.map} +1 -1
  4. package/dist/{agent-interface-CPn9pZ8j.js → agent-interface-D8jnkEnB.js} +71 -8
  5. package/dist/agent-interface-D8jnkEnB.js.map +1 -0
  6. package/dist/{agent-runner-Cic1uZZ8.js → agent-runner-BxIYcxmA.js} +9 -71
  7. package/dist/agent-runner-BxIYcxmA.js.map +1 -0
  8. package/dist/{analytics-Be_wRgxD.js → analytics-Du8Z_3oX.js} +2 -2
  9. package/dist/{analytics-Be_wRgxD.js.map → analytics-Du8Z_3oX.js.map} +1 -1
  10. package/dist/{api-C_R_ybiA.js → api-BqKMQVhj.js} +3 -3
  11. package/dist/{api-C_R_ybiA.js.map → api-BqKMQVhj.js.map} +1 -1
  12. package/dist/bin.js +54 -40
  13. package/dist/bin.js.map +1 -1
  14. package/dist/{ci-install-B0BHTkGI.js → ci-install-UlWb3u5t.js} +4 -4
  15. package/dist/{ci-install-B0BHTkGI.js.map → ci-install-UlWb3u5t.js.map} +1 -1
  16. package/dist/{debug-DJS2KPGb.js → debug-B4AH8Ahp.js} +1 -1
  17. package/dist/{debug-BpWrz3hX.js → debug-CZwmzyDx.js} +2 -2
  18. package/dist/{debug-BpWrz3hX.js.map → debug-CZwmzyDx.js.map} +1 -1
  19. package/dist/{environment-Dc6VTWyK.js → environment-BRXwshJO.js} +3 -3
  20. package/dist/{environment-Dc6VTWyK.js.map → environment-BRXwshJO.js.map} +1 -1
  21. package/dist/{file-utils-Buj9-umf.js → file-utils-D6CWLaOm.js} +2 -2
  22. package/dist/{file-utils-Buj9-umf.js.map → file-utils-D6CWLaOm.js.map} +1 -1
  23. package/dist/{headless-ui-BplqZRcO.js → headless-ui-DvkogF0b.js} +2 -2
  24. package/dist/{headless-ui-BplqZRcO.js.map → headless-ui-DvkogF0b.js.map} +1 -1
  25. package/dist/{host-resolution-BD6TcZG0.js → host-resolution-DrOzdKdY.js} +3 -3
  26. package/dist/{host-resolution-BD6TcZG0.js.map → host-resolution-DrOzdKdY.js.map} +1 -1
  27. package/dist/{interactive-BspTioP_.js → interactive-CXL8oJwb.js} +2 -2
  28. package/dist/{interactive-BspTioP_.js.map → interactive-CXL8oJwb.js.map} +1 -1
  29. package/dist/{mcp-prompt-streaming-BCNzyL12.js → mcp-prompt-streaming-Dumivcgi.js} +4 -4
  30. package/dist/{mcp-prompt-streaming-BCNzyL12.js.map → mcp-prompt-streaming-Dumivcgi.js.map} +1 -1
  31. package/dist/{non-interactive-CFikUAzO.js → non-interactive-BI5b25U7.js} +2 -2
  32. package/dist/{non-interactive-CFikUAzO.js.map → non-interactive-BI5b25U7.js.map} +1 -1
  33. package/dist/{package-manager-L7gsAbE0.js → package-manager-9nhQBKAy.js} +2 -2
  34. package/dist/{package-manager-L7gsAbE0.js.map → package-manager-9nhQBKAy.js.map} +1 -1
  35. package/dist/{playground-Bl2iPxdt.js → playground-DDYYs2ub.js} +5 -5
  36. package/dist/{playground-Bl2iPxdt.js.map → playground-DDYYs2ub.js.map} +1 -1
  37. package/dist/{posthog-integration-B6pTHVcn.js → posthog-integration-Cx4RvC7E.js} +13 -13
  38. package/dist/{posthog-integration-B6pTHVcn.js.map → posthog-integration-Cx4RvC7E.js.map} +1 -1
  39. package/dist/{provisioning-C9ts56R5.js → provisioning-PosLaOt4.js} +4 -4
  40. package/dist/{provisioning-C9ts56R5.js.map → provisioning-PosLaOt4.js.map} +1 -1
  41. package/dist/{registry-DFazVUSE.js → registry-B43CNAAx.js} +4 -4
  42. package/dist/{registry-DFazVUSE.js.map → registry-B43CNAAx.js.map} +1 -1
  43. package/dist/{setup-utils-BxdW2R0r.js → setup-utils-CR8X8Fmf.js} +19 -11
  44. package/dist/setup-utils-CR8X8Fmf.js.map +1 -0
  45. package/dist/{start-tui-oGWfxdTd.js → start-tui-DeewAqJg.js} +15 -15
  46. package/dist/{start-tui-oGWfxdTd.js.map → start-tui-DeewAqJg.js.map} +1 -1
  47. package/dist/{steps-O0v5UU1G.js → steps-CPvI-2Ms.js} +7 -7
  48. package/dist/{steps-O0v5UU1G.js.map → steps-CPvI-2Ms.js.map} +1 -1
  49. package/dist/{store-Di9OvMql.js → store-0uzey9Am.js} +3 -3
  50. package/dist/{store-Di9OvMql.js.map → store-0uzey9Am.js.map} +1 -1
  51. package/dist/{telemetry-D5WQ4-Ic.js → telemetry-DJNpvkYP.js} +3 -3
  52. package/dist/{telemetry-D5WQ4-Ic.js.map → telemetry-DJNpvkYP.js.map} +1 -1
  53. package/dist/{terminal-Bd-k7pCi.js → terminal-Bd6q58zn.js} +10 -10
  54. package/dist/{terminal-Bd-k7pCi.js.map → terminal-Bd6q58zn.js.map} +1 -1
  55. package/dist/{urls-DpTCPWLD.js → urls-B1a2v93j.js} +2 -2
  56. package/dist/{urls-DpTCPWLD.js.map → urls-B1a2v93j.js.map} +1 -1
  57. package/dist/{wizard-abort-t41wO4Bh.js → wizard-abort-BG8VNOI9.js} +3 -3
  58. package/dist/{wizard-abort-t41wO4Bh.js.map → wizard-abort-BG8VNOI9.js.map} +1 -1
  59. package/dist/{wizard-abort-C1t9M-JN.js → wizard-abort-DyAGpw-u.js} +1 -1
  60. package/package.json +1 -1
  61. package/dist/agent-interface-CPn9pZ8j.js.map +0 -1
  62. package/dist/agent-runner-Cic1uZZ8.js.map +0 -1
  63. package/dist/setup-utils-BxdW2R0r.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent-runner-Cic1uZZ8.js","names":["path","runAgent","executeAgent"],"sources":["../src/lib/agent/runner/orchestrator/executor.ts","../src/lib/agent/runner/orchestrator/run-metrics.ts","../src/lib/agent/agent-prompt-loader.ts","../src/lib/agent/runner/orchestrator/orchestrator-runner.ts","../src/lib/agent/runner/shared/authenticate.ts","../src/lib/agent/runner/shared/bootstrap.ts","../src/lib/middleware/phase-detector.ts","../src/lib/middleware/pipeline.ts","../src/lib/middleware/config.ts","../src/lib/middleware/benchmarks/turn-counter.ts","../src/lib/middleware/benchmarks/token-tracker.ts","../src/lib/middleware/benchmarks/cache-tracker.ts","../src/lib/middleware/benchmarks/compaction-tracker.ts","../src/lib/middleware/benchmarks/context-size-tracker.ts","../src/lib/middleware/benchmarks/cost-tracker.ts","../src/lib/middleware/benchmarks/duration-tracker.ts","../src/lib/middleware/benchmarks/summary.ts","../src/lib/middleware/benchmarks/json-writer.ts","../src/lib/middleware/benchmarks/index.ts","../src/lib/middleware/benchmark.ts","../src/lib/wizard-ask-bridge.ts","../src/lib/agent/agent-prompt.ts","../src/lib/agent/runner/shared/errors.ts","../src/lib/agent/runner/linear.ts","../src/lib/agent/runner/index.ts","../src/lib/agent/agent-runner.ts"],"sourcesContent":["/**\n * The executor drains the queue. It starts every runnable task (dependencies\n * satisfied) as soon as it becomes runnable — parallelism is decided by the\n * task graph, not by an executor knob. Each task runs through an injected\n * `runTask` function and reports its outcome via `complete_task`; a task that\n * ends without reporting is retried while attempts remain, then failed. A\n * `maxStarts` backstop guarantees termination.\n *\n * The drain loop is independent of how a task actually runs. `runTask` is\n * injected: the real one spins up a fresh agent, the tests use a fake.\n */\nimport { analytics } from '@utils/analytics';\nimport { logToFile } from '@utils/debug';\nimport { TaskStatus, type QueueStore, type QueuedTask } from './queue';\n\n/** Per-task agent configuration the resolver produces from a task's type. */\nexport interface ResolvedTask {\n model: string;\n allowedTools: readonly string[];\n disallowedTools: readonly string[];\n /** Mini-skills to install before the task runs (the HOW). */\n skills: readonly string[];\n prompt: string;\n}\n\n/** Resolves a queued task to what the agent needs. The real one is markdown-backed. */\nexport type TaskResolver = (\n task: QueuedTask,\n store: QueueStore,\n) => ResolvedTask;\n\n/** Runs one task's agent. It is expected to drive the task to a terminal state\n * (via the task agent calling complete_task). */\nexport type RunTask = (task: QueuedTask) => Promise<void>;\n\nexport interface DrainOptions {\n /** Backstop against a pathological always-one-more-pending loop. */\n maxStarts: number;\n}\n\nexport const DEFAULT_DRAIN_OPTIONS: DrainOptions = {\n maxStarts: 200,\n};\n\nasync function runOne(\n store: QueueStore,\n runTask: RunTask,\n task: QueuedTask,\n): Promise<void> {\n store.start(task.id);\n try {\n await runTask(task);\n } catch (error) {\n // The task threw rather than reporting. The outcome check below handles\n // the queue; the exception itself should never be silent.\n logToFile(`[executor] runTask threw for ${task.type}:`, error);\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'orchestrator_run_task', task_type: task.type },\n );\n }\n\n const after = store.get(task.id);\n if (!after) return;\n\n if (after.status === TaskStatus.Running) {\n // The agent ended without calling complete_task. Retry or fail.\n if (after.attempts < after.maxAttempts) {\n store.requeue(task.id);\n } else {\n store.fail(task.id, {\n type: 'no-report',\n message: 'Task ended without calling complete_task.',\n });\n }\n return;\n }\n\n if (\n after.status === TaskStatus.Failed &&\n after.attempts < after.maxAttempts\n ) {\n store.requeue(task.id);\n }\n}\n\n/**\n * Drain the queue to a terminal state. Every runnable task starts the moment\n * its dependencies finish; independent branches run concurrently. Returns when\n * every task is done, failed, or blocked by a failed dependency, or when the\n * start backstop trips.\n */\nexport async function drainQueue(\n store: QueueStore,\n runTask: RunTask,\n opts: DrainOptions = DEFAULT_DRAIN_OPTIONS,\n): Promise<void> {\n const running = new Map<string, Promise<void>>();\n let starts = 0;\n\n for (;;) {\n for (const task of store.nextRunnable()) {\n if (++starts > opts.maxStarts) break;\n // runOne marks the task running synchronously, so the next\n // nextRunnable() call no longer offers it.\n const p = runOne(store, runTask, task).finally(() =>\n running.delete(task.id),\n );\n running.set(task.id, p);\n }\n if (running.size === 0) break;\n // Wake on the first finish; it may have unblocked dependents or requeued.\n await Promise.race(running.values());\n }\n}\n","/**\n * Responsiveness metrics for an orchestrator run.\n *\n * Responsiveness is the experiment's headline: how quickly the user sees the\n * first progress, and whether progress stays steady (no long silences). The math\n * is accumulated from queue transitions but kept here, pure and time-injected, so\n * it is unit-testable away from the runner. Wall-clock times are passed in as\n * milliseconds; the caller owns the clock.\n */\n\nexport interface RunMetricsSummary {\n /** Run start → first task started. */\n time_to_first_task_ms?: number;\n /** Run start → first task completed (the first visible \"done\"). */\n time_to_first_completion_ms?: number;\n /** Longest silence between two consecutive user-visible transitions. */\n max_gap_ms?: number;\n}\n\n/** The per-event timing the `orchestrator task started` event reports. */\nexport interface StartTiming {\n ms_since_run_start: number;\n gap_since_prev_start_ms?: number;\n}\n\nexport class RunMetrics {\n private firstStartMs?: number;\n private lastStartMs?: number;\n private firstCompleteMs?: number;\n private lastVisibleMs?: number;\n private maxGapMs = 0;\n\n constructor(private readonly runStartMs: number) {}\n\n /** A task started. Returns the per-start-event timing for the start event. */\n recordStart(nowMs: number): StartTiming {\n const timing: StartTiming = {\n ms_since_run_start: nowMs - this.runStartMs,\n gap_since_prev_start_ms:\n this.lastStartMs === undefined ? undefined : nowMs - this.lastStartMs,\n };\n this.firstStartMs ??= nowMs;\n this.lastStartMs = nowMs;\n this.markVisible(nowMs);\n return timing;\n }\n\n /** A task completed. */\n recordComplete(nowMs: number): void {\n this.firstCompleteMs ??= nowMs;\n this.markVisible(nowMs);\n }\n\n /** A task reached a terminal non-complete state the user sees (skip/fail). */\n recordTerminal(nowMs: number): void {\n this.markVisible(nowMs);\n }\n\n /**\n * The run-level responsiveness summary. Timings are `undefined` when the\n * relevant transition never happened (e.g. a run that started no task), so a\n * no-task run stays distinguishable from a genuine zero.\n */\n summary(): RunMetricsSummary {\n return {\n time_to_first_task_ms:\n this.firstStartMs === undefined\n ? undefined\n : this.firstStartMs - this.runStartMs,\n time_to_first_completion_ms:\n this.firstCompleteMs === undefined\n ? undefined\n : this.firstCompleteMs - this.runStartMs,\n max_gap_ms: this.lastVisibleMs === undefined ? undefined : this.maxGapMs,\n };\n }\n\n /** requeue is not user-visible, so a retry stall counts as silence here. */\n private markVisible(nowMs: number): void {\n if (this.lastVisibleMs !== undefined) {\n this.maxGapMs = Math.max(this.maxGapMs, nowMs - this.lastVisibleMs);\n }\n this.lastVisibleMs = nowMs;\n }\n}\n","/**\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 { QueueStore, QueuedTask } from './runner/orchestrator/queue';\nimport type { ResolvedTask } from './runner/orchestrator/executor';\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: string;\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 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}`;\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\nconst TASK_BASICS = `You are one isolated task in a larger PostHog workflow, run as a fresh agent with no memory of the other tasks beyond the context you are given. 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 \\`skipped\\` 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 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. You are not a task yourself: do not call complete_task and do not edit the project.`;\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): string {\n return [projectContext(ctx), SEED_BASICS, body].join('\\n\\n');\n}\n\n/** Used when neither the enqueue call nor the prompt frontmatter names a model. */\nconst DEFAULT_TASK_MODEL = 'claude-sonnet-4-6';\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/** 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 model?: string;\n skills: string[];\n allowedTools: string[];\n disallowedTools: string[];\n dependsOn: string[];\n body: string;\n}\n\nexport interface AgentRegistry {\n /** The flow's enqueueable task types — every prompt except the seed. */\n readonly types: 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?: { exclude?: readonly string[] },\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.filter(\n (p) => p.flow === flow && !excluded.has(p.type),\n );\n const byType = new Map(inFlow.map((p) => [p.type, p]));\n return {\n types: inFlow.filter((p) => !p.seed).map((p) => p.type),\n seed: inFlow.find((p) => p.seed),\n get: (type) => byType.get(type),\n };\n}\n\ninterface AgentMenu {\n agents: { id: string; downloadUrl: string }[];\n}\n\n/** A native tool passes through; an orchestrator tool gets its MCP-qualified name. */\nfunction expandToolName(name: string): string {\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` is the menu id, used when the body omits\n * `type:`.\n */\nexport function parseAgentPrompt(\n text: string,\n fallbackType: 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 model = typeof fields.model === 'string' ? fields.model : undefined;\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 : undefined,\n seed: fields.seed === 'true',\n model,\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 fetch(url);\n if (!res.ok) {\n throw new Error(`Fetch ${url} failed: ${res.status} ${res.statusText}`);\n }\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?: { exclude?: readonly string[] },\n): Promise<AgentRegistry> {\n const menuRaw = await fetchText(`${skillsBaseUrl}/agent-menu.json`);\n const menu = JSON.parse(menuRaw) as AgentMenu;\n\n const prompts = await Promise.all(\n (menu.agents ?? []).map(async (entry) => {\n const text = await fetchText(entry.downloadUrl);\n return parseAgentPrompt(text, entry.id);\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 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 model: taskModel(registry, task),\n ...agentRunTools(prompt),\n prompt: body,\n skills: prompt.skills,\n };\n}\n\n/** The model a task runs on: enqueue override, then prompt frontmatter, then default. */\nexport function taskModel(registry: AgentRegistry, task: QueuedTask): string {\n return task.model ?? registry.get(task.type)?.model ?? DEFAULT_TASK_MODEL;\n}\n","/**\n * Experimental task-queue orchestrator runner.\n *\n * Branches from the linear runner when the `wizard-orchestrator` flag is on. An\n * orchestrator agent inspects the repo and seeds an in-memory task queue; an\n * executor drains it, running one fresh agent per task.\n *\n * Both the WHAT (agent prompts: model, goal, success criteria, tools) and the\n * HOW (mini-skills) are markdown served from context-mill — the seed and every\n * task resolve to a prompt fetched at startup into the registry. The wizard side\n * stays product-ignorant: it is the queue, the executor, and the loader.\n */\nimport { randomUUID } from 'crypto';\nimport { existsSync, rmSync } from 'fs';\nimport * as path from 'path';\nimport {\n initializeAgent,\n runAgent,\n type AgentConfig,\n} from '@lib/agent/agent-interface';\nimport { OutroKind, type WizardSession } from '@lib/wizard-session';\nimport { detectNodePackageManagers } from '@lib/detection/package-manager';\nimport { installSkillById, fetchSkillMenu } from '@lib/wizard-tools';\nimport { getUI } from '@ui';\nimport { analytics } from '@utils/analytics';\nimport { ciExcludedTaskTypes } from '@utils/ci-flag-overrides';\nimport { logToFile } from '@utils/debug';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport type { BootstrapResult } from '../shared/types';\nimport type { WizardRunOptions } from '@utils/types';\nimport {\n QueueStore,\n QUEUE_DIR_NAME,\n TaskStatus,\n type QueuedTask,\n} from './queue';\nimport { drainQueue, type RunTask } from './executor';\nimport { RunMetrics } from './run-metrics';\nimport {\n agentRunTools,\n assembleSeedPrompt,\n assembleTaskPrompt,\n loadAgentRegistry,\n resolveTask,\n taskModel,\n type OrchestratorPromptContext,\n} from '@lib/agent/agent-prompt-loader';\n\nfunction toTodoStatus(status: TaskStatus): string {\n switch (status) {\n case TaskStatus.Running:\n return 'in_progress';\n case TaskStatus.Done:\n case TaskStatus.Failed:\n return 'completed';\n case TaskStatus.Skipped:\n return 'skipped';\n default:\n return 'pending';\n }\n}\n\nfunction sessionRunOptions(session: WizardSession): WizardRunOptions {\n return {\n installDir: session.installDir,\n debug: session.debug,\n default: false,\n signup: session.signup,\n localMcp: session.localMcp,\n ci: session.ci,\n benchmark: session.benchmark,\n projectId: session.projectId,\n apiKey: session.apiKey,\n yaraReport: session.yaraReport,\n };\n}\n\n/**\n * The framework reference is the full `integration` skill. `session.skillId` is\n * the bare framework (e.g. `django`), but the skill menu ids it as\n * `integration-<variant>`. Resolve to the menu id: exact `integration-<framework>`\n * (the 1:1 frameworks — django, python, flask, …), else the first granular variant\n * under it (e.g. `integration-nextjs-app-router`). Undefined when none exists.\n */\nasync function resolveReferenceSkillId(\n skillsBaseUrl: string,\n framework: string,\n): Promise<string | undefined> {\n const menu = await fetchSkillMenu(skillsBaseUrl);\n if (!menu) return undefined;\n const ids = Object.values(menu.categories)\n .flat()\n .map((s) => s.id);\n const exact = `integration-${framework}`;\n if (ids.includes(exact)) return exact;\n return ids.find((id) => id.startsWith(`integration-${framework}-`));\n}\n\nexport async function runOrchestrator(\n session: WizardSession,\n programConfig: ProgramConfig,\n boot: BootstrapResult,\n): Promise<void> {\n const runId = randomUUID();\n\n const options = sessionRunOptions(session);\n\n // The WHAT (agent prompts) is served from context-mill. Fetch the registry\n // once up front: its types drive enqueue validation, and resolving a task to\n // its run config is then synchronous, with no mid-drain network latency.\n const registry = await loadAgentRegistry(\n boot.skillsBaseUrl,\n programConfig.id,\n { exclude: ciExcludedTaskTypes() },\n );\n const seedPrompt = registry.seed;\n if (!seedPrompt) {\n throw new Error(\n `No seed agent prompt (frontmatter \\`seed: true\\`) for flow \"${programConfig.id}\" is available from ${boot.skillsBaseUrl}.`,\n );\n }\n\n // Responsiveness is the headline metric of the dark launch: time to first\n // visible progress, and no single step dominating wall-clock. Track it from\n // queue transitions, with the resolved model so cheap work is attributable\n // to cheap models.\n const runStartMs = Date.now();\n const metrics = new RunMetrics(runStartMs);\n const durationMs = (t: QueuedTask) =>\n t.startedAt && t.finishedAt\n ? Date.parse(t.finishedAt) - Date.parse(t.startedAt)\n : undefined;\n\n const store = new QueueStore(session.installDir, runId, {\n onTransition: (event, task) => {\n const base = {\n type: task.type,\n model: taskModel(registry, task),\n attempts: task.attempts,\n };\n switch (event) {\n case 'enqueue':\n analytics.wizardCapture('orchestrator task enqueued', {\n type: task.type,\n enqueued_by: task.enqueuedBy,\n dynamic: task.enqueuedBy !== 'orchestrator',\n });\n break;\n case 'start':\n analytics.wizardCapture('orchestrator task started', {\n ...base,\n ...metrics.recordStart(Date.now()),\n });\n break;\n case 'complete':\n metrics.recordComplete(Date.now());\n analytics.wizardCapture('orchestrator task completed', {\n ...base,\n duration_ms: durationMs(task),\n });\n break;\n case 'skip':\n metrics.recordTerminal(Date.now());\n analytics.wizardCapture('orchestrator task skipped', {\n ...base,\n duration_ms: durationMs(task),\n });\n break;\n case 'fail':\n metrics.recordTerminal(Date.now());\n analytics.wizardCapture('orchestrator task failed', {\n ...base,\n duration_ms: durationMs(task),\n error: task.error?.type,\n });\n break;\n case 'requeue':\n break;\n }\n },\n });\n\n // Give task agents the framework's finished reference integration to match,\n // the same EXAMPLE.md the linear flow uses. Install it under the run dir rather\n // than .claude/skills so its \"do everything\" workflow is not auto-loaded as a\n // skill — only the example file is read, when the agent's prompt points at it.\n let examplePath: string | undefined;\n let commandmentsPath: string | undefined;\n const referenceSkillId = session.skillId\n ? await resolveReferenceSkillId(boot.skillsBaseUrl, session.skillId)\n : undefined;\n if (referenceSkillId) {\n const ref = await installSkillById(\n referenceSkillId,\n session.installDir,\n boot.skillsBaseUrl,\n path.join(QUEUE_DIR_NAME, 'reference'),\n );\n if (ref.kind === 'ok') {\n const example = path.join(ref.path, 'references', 'EXAMPLE.md');\n if (existsSync(path.join(session.installDir, example))) {\n examplePath = example;\n }\n const commandments = path.join(ref.path, 'references', 'COMMANDMENTS.md');\n if (existsSync(path.join(session.installDir, commandments))) {\n commandmentsPath = commandments;\n }\n } else {\n logToFile(\n `[orchestrator] reference unavailable: ${ref.kind} (${referenceSkillId})`,\n );\n }\n } else if (session.skillId) {\n logToFile(\n `[orchestrator] no integration skill for framework \"${session.skillId}\"`,\n );\n }\n\n // The client injects the basics (project context + the I/O contract) around\n // every authored agent-prompt body.\n const promptContext: OrchestratorPromptContext = {\n projectId: boot.projectId,\n projectApiKey: boot.projectApiKey,\n host: boot.host,\n examplePath,\n commandmentsPath,\n };\n\n logToFile(\n `[orchestrator] START program=${programConfig.id} dir=${session.installDir} run=${runId}`,\n );\n analytics.wizardCapture('orchestrator started', {\n program_id: programConfig.id,\n });\n getUI().startRun();\n\n // Label precedence: what the orchestrator set at enqueue, then the agent\n // prompt's default, then the bare type.\n const labelFor = (t: { type: string; label?: string }) =>\n t.label ?? registry.get(t.type)?.label ?? t.type;\n const renderQueue = () =>\n getUI().syncTodos(\n store.list().map((t) => ({\n content: labelFor(t),\n status: toTodoStatus(t.status),\n activeForm: labelFor(t),\n })),\n );\n\n // Each agent gets its own config so its wizard-tools server is bound to the\n // task it runs — independent tasks run in parallel, and attribution of\n // complete_task / enqueue_task must hold per agent. The seed is not a task,\n // so its context has no task id.\n const agentConfigFor = (currentTaskId?: string): AgentConfig => ({\n workingDirectory: session.installDir,\n posthogMcpUrl: boot.mcpUrl,\n posthogApiKey: boot.accessToken,\n posthogApiHost: boot.host,\n detectPackageManager: detectNodePackageManagers,\n skillsBaseUrl: boot.skillsBaseUrl,\n wizardFlags: boot.wizardFlags,\n wizardMetadata: boot.wizardMetadata,\n integrationLabel: programConfig.id,\n orchestrator: {\n store,\n validTypes: registry.types,\n currentTaskId,\n },\n });\n\n const spinner = getUI().spinner();\n\n // 1. Seed the queue with the orchestrator agent. It is itself an agent prompt\n // (the WHAT), so its model and tools come from its frontmatter. The seed\n // plans the graph, it is not a task.\n const seedAgent = await initializeAgent(agentConfigFor(), options);\n const seedResult = await runAgent(\n {\n ...seedAgent,\n model: seedPrompt.model ?? seedAgent.model,\n ...agentRunTools(seedPrompt),\n },\n assembleSeedPrompt(promptContext, seedPrompt.body),\n options,\n spinner,\n {\n spinnerMessage: 'Planning the integration...',\n successMessage: 'Planned the integration',\n additionalFeatureQueue: [],\n requestRemark: false,\n analyticsProperties: { task_type: 'seed' },\n },\n );\n if (seedResult.error) {\n logToFile(\n `[orchestrator] seed error: ${seedResult.error} ${\n seedResult.message ?? ''\n }`,\n );\n }\n analytics.wizardCapture('orchestrator seeded', {\n task_count: store.list().length,\n types: store.list().map((t) => t.type),\n });\n renderQueue();\n\n // 2. Drain the queue, one fresh agent per task; independent tasks run in\n // parallel, the seed's graph being the only schedule. Each task resolves to\n // its agent prompt (the WHAT) and the mini-skills it needs (the HOW), then\n // runs on its own model and tools.\n const taskSkillsRoot = path.join(QUEUE_DIR_NAME, 'skills');\n let remarkRequested = false;\n const runTask: RunTask = async (task) => {\n renderQueue();\n try {\n const resolved = resolveTask(registry, task, store);\n const agent = await initializeAgent(agentConfigFor(task.id), options);\n // Task instructions are one-run scaffolding, not durable skills, so they\n // install under the run dir rather than .claude/skills — the SDK must not\n // auto-load them and they must never land in the project (or a CI PR).\n // The prompt points the agent at them instead.\n const skillPaths: string[] = [];\n for (const skillId of resolved.skills) {\n const result = await installSkillById(\n skillId,\n session.installDir,\n boot.skillsBaseUrl,\n taskSkillsRoot,\n );\n if (result.kind === 'ok') {\n skillPaths.push(path.join(result.path, 'SKILL.md'));\n } else {\n logToFile(\n `[orchestrator] skill install failed type=${task.type} skill=${skillId} ${result.kind}`,\n );\n }\n }\n // The run-end reflection fires once, on the task that is last in the\n // queue when it starts — nothing else pending or running alongside it.\n const isLastTask = !store\n .list()\n .some(\n (t) =>\n t.id !== task.id &&\n (t.status === TaskStatus.Pending ||\n t.status === TaskStatus.Running),\n );\n const requestRemark = isLastTask && !remarkRequested;\n if (requestRemark) remarkRequested = true;\n await runAgent(\n {\n ...agent,\n model: resolved.model,\n allowedTools: resolved.allowedTools,\n disallowedTools: resolved.disallowedTools,\n },\n assembleTaskPrompt(promptContext, resolved.prompt, skillPaths),\n options,\n spinner,\n // Empty messages suppress the per-task spinner lines (the spinner renders\n // only when a message is set); the queue panel shows progress. Errors\n // still surface — runAgent stops the spinner with its own error text.\n {\n spinnerMessage: '',\n successMessage: '',\n additionalFeatureQueue: [],\n requestRemark,\n analyticsProperties: { task_type: task.type, task_id: task.id },\n },\n );\n } finally {\n renderQueue();\n }\n };\n try {\n await drainQueue(store, runTask);\n } finally {\n // Success or failure, no run artifact outlives the run — wipe the whole\n // cache folder (queue, handoffs, reference example, installed task\n // instructions). The .DELETE-ME.md inside is the fallback if we don't.\n try {\n rmSync(path.join(session.installDir, QUEUE_DIR_NAME), {\n recursive: true,\n force: true,\n });\n } catch (err) {\n analytics.captureException(\n err instanceof Error ? err : new Error(String(err)),\n { step: 'orchestrator_cache_cleanup' },\n );\n }\n }\n\n renderQueue();\n\n const summary = store.summary();\n logToFile(\n `[orchestrator] DONE done=${summary.done} failed=${summary.failed} total=${summary.total}`,\n );\n analytics.wizardCapture('orchestrator run finished', {\n tasks_total: summary.total,\n tasks_done: summary.done,\n tasks_failed: summary.failed,\n tasks_skipped: summary.skipped,\n total_duration_ms: Date.now() - runStartMs,\n ...metrics.summary(),\n dynamic_enqueue_count: store\n .list()\n .filter((t) => t.enqueuedBy !== 'orchestrator').length,\n retried_task_count: store.list().filter((t) => t.attempts > 1).length,\n });\n\n // The build step flags any unresolved conflict in its handoff; surface the\n // one-liner here and point the user at the report for the detail.\n const buildTask = store.list().find((t) => t.type === 'build');\n const conflict = buildTask\n ? store.readHandoff(buildTask.id)?.conflict\n : undefined;\n\n // Prefer the report the run wrote; fall back to the raw queue if it is missing.\n const reportPath = path.join(session.installDir, 'posthog-setup-report.md');\n const reportFile = existsSync(reportPath)\n ? 'posthog-setup-report.md'\n : store.queuePath;\n\n const message = conflict\n ? 'PostHog set up, with one conflict to review.'\n : `PostHog set up: ${summary.done}/${summary.total} steps completed.`;\n getUI().setOutroData({\n kind: OutroKind.Success,\n message,\n body: conflict\n ? `⚠ Build conflict: ${conflict}\\nFull details are in the report.`\n : undefined,\n reportFile,\n docsUrl: 'https://posthog.com/docs/ai-engineering/ai-wizard',\n });\n getUI().outro(message);\n await analytics.shutdown('success');\n}\n","/**\n * Authenticate the wizard — once per invocation.\n *\n * Idempotent: when `session.credentials` is already set, this is a no-op. So a\n * second agent run in the same invocation (e.g. self-driving runs the\n * integration program as a phase, then the Self-driving run) reuses the first\n * login instead of launching another OAuth — a second OAuth re-prompts and\n * fails with a 400 (the first authorization code is already spent). The first\n * call stores the full result on the session so any later bootstrap reads it\n * back rather than fetching again.\n */\n\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { ProgramId } from '@lib/programs/program-registry';\nimport { getOrAskForProjectData } from '@utils/setup-utils';\nimport { analytics, groupsFromUser } from '@utils/analytics';\nimport { getUI } from '@ui';\nimport { logToFile } from '@utils/debug';\n\nexport async function authenticate(\n session: WizardSession,\n programId: ProgramId,\n): Promise<void> {\n if (session.credentials) return;\n\n logToFile('[agent-runner] starting OAuth');\n const {\n projectApiKey,\n host,\n accessToken,\n projectId,\n cloudRegion,\n roleAtOrganization,\n user,\n project,\n } = await getOrAskForProjectData({\n signup: session.signup,\n ci: session.ci,\n apiKey: session.apiKey,\n projectId: session.projectId,\n email: session.email,\n region: session.region,\n baseUrl: session.baseUrl,\n programId,\n });\n\n session.credentials = { accessToken, projectApiKey, host, projectId };\n session.cloudRegion = cloudRegion;\n session.apiProject = project;\n session.roleAtOrganization = roleAtOrganization;\n session.apiUser = user;\n\n getUI().setCredentials(session.credentials);\n getUI().setRoleAtOrganization(roleAtOrganization);\n getUI().setApiUser(user);\n\n // Identify the user (email, name) before flags are evaluated, so flags can\n // target the individual user and not just $app_name.\n if (user) analytics.identifyUser(user);\n analytics.setGroups(groupsFromUser(user, host));\n}\n","/**\n * Shared bootstrap for the runner pipeline.\n *\n * Runs before the fork into the linear or orchestrator arm: logging, health\n * check, settings conflicts, OAuth and credentials, feature flags, variant\n * metadata, and MCP url. Sets `session.credentials`, role, and user as side\n * effects. Returns the values the arms still need.\n */\n\nimport type { WizardSession } from '@lib/wizard-session';\nimport { analytics } from '@utils/analytics';\nimport { getUI } from '@ui';\nimport { authenticate } from './authenticate';\nimport { buildRunTags } from '@lib/agent/agent-interface';\nimport {\n checkAllSettingsConflicts,\n backupAndFixClaudeSettings,\n classifySettingsConflicts,\n} from '@lib/agent/claude-settings';\nimport {\n evaluateWizardReadiness,\n WizardReadiness,\n SIGNUP_WIZARD_READINESS_CONFIG,\n getBlockingServiceKeys,\n SERVICE_LABELS,\n} from '@lib/health-checks/readiness';\nimport { enableDebugLogs, logToFile, initLogFile } from '@utils/debug';\nimport { wizardAbort } from '@utils/wizard-abort';\nimport { isNonInteractiveEnvironment } from '@utils/environment';\nimport { getSkillsBaseUrl } from '@lib/constants';\nimport { runtimeEnv } from '@env';\nimport type { WizardRunOptions } from '@utils/types';\nimport type { ProgramConfig } from '@lib/programs/program-step';\nimport type { ProgramRun, BootstrapResult } from './types';\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\n/**\n * Decide whether the `wizard_ask` overlay should be wired for this run.\n * Disabled in non-interactive modes (CI, signup) — there's no human to\n * answer. Per-program disabling is done by adding WIZARD_ASK_TOOL_NAME to\n * the program's `disallowedTools` so the SDK rejects calls outright.\n * Extracted so the policy can be unit-tested directly.\n */\nexport function shouldDisableAsk(\n session: Pick<WizardSession, 'ci' | 'signup'>,\n): boolean {\n return session.ci || session.signup;\n}\n\nexport function sessionToOptions(session: WizardSession): WizardRunOptions {\n return {\n installDir: session.installDir,\n debug: session.debug,\n default: false,\n signup: session.signup,\n localMcp: session.localMcp,\n ci: session.ci,\n benchmark: session.benchmark,\n projectId: session.projectId,\n apiKey: session.apiKey,\n yaraReport: session.yaraReport,\n };\n}\n\n// ── Bootstrap ─────────────────────────────────────────────────────────\n\n/**\n * Shared setup for both arms: logging, health check, settings conflicts, OAuth\n * and credentials, then the feature flags, variant metadata, and MCP url. Sets\n * `session.credentials`, role, and user as a side effect. Returns the values the\n * arms still need.\n */\nexport async function bootstrapProgram(\n session: WizardSession,\n config: ProgramRun,\n programConfig: ProgramConfig,\n): Promise<BootstrapResult> {\n // 1. Init logging + debug\n initLogFile();\n session.skillId = config.skillId ?? config.integrationLabel;\n logToFile(`[agent-runner] START ${config.integrationLabel}`);\n\n if (session.debug) {\n enableDebugLogs();\n }\n\n const skillsBaseUrl = getSkillsBaseUrl(session.localMcp);\n\n // 2. Health check (guarded — skip if TUI already ran it). Only\n // programs that declare a health-check screen get pre-flight checks;\n // for everything else the checks never fire and never block.\n const hasHealthCheckScreen = programConfig.steps.some(\n (s) => s.screenId === 'health-check',\n );\n if (session.readinessResult) {\n logToFile(\n `[agent-runner] readiness pre-computed by TUI: decision=${session.readinessResult.decision}` +\n `${\n session.outageDismissed ? ' (outage dismissed by user)' : ''\n } — skipping re-check`,\n );\n }\n if (hasHealthCheckScreen && !session.readinessResult) {\n logToFile('[agent-runner] evaluating wizard readiness');\n const readinessConfig = session.signup\n ? SIGNUP_WIZARD_READINESS_CONFIG\n : undefined;\n const readiness = await evaluateWizardReadiness(readinessConfig);\n logToFile(`[agent-runner] readiness=${readiness.decision}`);\n if (readiness.decision === WizardReadiness.No) {\n const blockingKeys = getBlockingServiceKeys(\n readiness.health,\n readinessConfig,\n );\n const blockingLabels = blockingKeys.map(\n (k) => `${SERVICE_LABELS[k]} (${readiness.health[k].status})`,\n );\n logToFile(`[agent-runner] blocked by: ${blockingLabels.join(', ')}`);\n\n await getUI().showBlockingOutage(readiness);\n\n // The TUI lets the user continue past an outage; non-interactive runs\n // (CI) do the same automatically — the degraded services are reported\n // above, but we proceed rather than aborting on a transient upstream blip.\n if (!isNonInteractiveEnvironment()) {\n await wizardAbort({\n message:\n 'Cannot start — external services are down:\\n' +\n blockingLabels.map((l) => ` - ${l}`).join('\\n') +\n '\\n\\nPlease try again later.',\n });\n }\n } else if (readiness.decision === WizardReadiness.YesWithWarnings) {\n getUI().setReadinessWarnings(readiness);\n }\n }\n\n // 3. Settings conflicts\n const settingsConflicts = checkAllSettingsConflicts(session.installDir);\n logToFile(\n `[agent-runner] settings conflicts: ${\n settingsConflicts.length > 0\n ? settingsConflicts\n .map((c) => `${c.source}(${c.keys.join(',')})`)\n .join('; ')\n : 'none'\n }`,\n );\n\n if (settingsConflicts.length > 0) {\n for (const conflict of settingsConflicts) {\n const level = conflict.source === 'managed' ? 'org' : conflict.source;\n analytics.wizardCapture('settings conflict detected', {\n level,\n keys: conflict.keys,\n });\n }\n\n const { autoFix, failClosed, warnOnly } =\n classifySettingsConflicts(settingsConflicts);\n\n // User-global and project-local files are already neutralized — the agent\n // runs with settingSources:['project'], so the SDK never reads them. Record\n // it and move on; don't make the user act on a setting that can't bite.\n for (const conflict of warnOnly) {\n logToFile(\n `[agent-runner] settings conflict in ${conflict.source} (${conflict.path}) ` +\n `neutralized by settingSources:['project'] — not blocking`,\n );\n analytics.wizardCapture('settings conflict neutralized', {\n level: conflict.source,\n keys: conflict.keys,\n });\n }\n\n // Writable project settings.json — the SDK *does* read it, but we can back\n // it up and remove it (restored at outro). Neutralize without prompting.\n let unfixable = failClosed;\n if (autoFix.length > 0) {\n const fixed = backupAndFixClaudeSettings(session.installDir);\n if (fixed) {\n logToFile('[agent-runner] auto-neutralized writable settings conflict');\n analytics.wizardCapture('settings conflict auto-neutralized', {\n keys: autoFix.flatMap((c) => c.keys),\n });\n } else {\n // Couldn't remove it — don't run into the redirect; fail closed instead.\n logToFile(\n '[agent-runner] could not back up writable settings conflict — failing closed',\n );\n unfixable = [...failClosed, ...autoFix];\n }\n }\n\n // What we cannot neutralize (org-managed, always read by the SDK; or a\n // writable file we failed to back up) must be fixed by the user. Fail\n // closed: the screen names the file + keys and exits.\n if (unfixable.length > 0) {\n await getUI().showSettingsOverride(unfixable, () =>\n backupAndFixClaudeSettings(session.installDir),\n );\n logToFile('[agent-runner] settings override resolved');\n }\n }\n\n analytics.wizardCapture('agent started', {\n integration: config.integrationLabel,\n program_id: programConfig.id,\n skill_id: config.skillId ?? null,\n });\n\n // 4. Authenticate — idempotent within a run (see authenticate()). A second\n // agent run in the same invocation (self-driving's integration phase) reuses\n // the first login; it does not launch another OAuth. authenticate() also\n // identifies the user and sets analytics groups.\n await authenticate(session, programConfig.id);\n const { projectApiKey, host, accessToken, projectId } = session.credentials!;\n const cloudRegion = session.cloudRegion!;\n const project = session.apiProject;\n\n // 4.5. AI opt-in enforcement. Parks here while AiOptInRequiredScreen is\n // up if the org hasn't approved third-party AI — BEFORE the skill\n // install and agent start, so no source leaves the machine. The screen\n // alone is cosmetic; this await is the actual gate. Resolves\n // immediately when the program declared requiresAi: false or in CI.\n // In bootstrapProgram so both the linear and orchestrator arms gate.\n logToFile('[agent-runner] checking AI opt-in gate');\n await getUI().waitForAiOptIn();\n logToFile('[agent-runner] AI opt-in gate cleared');\n\n // Park for any interactive step the user must complete AFTER authenticating\n // but BEFORE the agent runs — e.g. the source-maps project picker, which\n // needs credentials to scan and writes its choice to frameworkContext that\n // the run prompt reads. Generic: await every gated step between auth and run.\n const authIndex = programConfig.steps.findIndex((s) => s.screenId === 'auth');\n const runIndex = programConfig.steps.findIndex((s) => s.screenId === 'run');\n if (authIndex !== -1 && runIndex > authIndex) {\n for (const step of programConfig.steps.slice(authIndex + 1, runIndex)) {\n if (step.gate) {\n logToFile(`[agent-runner] awaiting post-auth gate: ${step.id}`);\n await getUI().waitForGate(step.id);\n logToFile(`[agent-runner] post-auth gate cleared: ${step.id}`);\n }\n }\n }\n\n // Feature flags and MCP url. Both arms need these, and the fork decision reads\n // the flags.\n const wizardFlags = await analytics.getAllFlagsForWizard();\n // Gateway trace tags for this run. The runner stamps its variant onto this\n // after the fork (see runProgram), so the value reflects which arm ran.\n const wizardMetadata = buildRunTags({\n programId: programConfig.id,\n integration: config.integrationLabel,\n runId: analytics.runId,\n build: analytics.build,\n skillId: config.skillId,\n });\n\n // One MCP url for every region: the server resolves the user's region from\n // the bearer token, so the EU subdomain (a Claude Code OAuth workaround) is\n // not needed here.\n const mcpUrl = session.localMcp\n ? 'http://localhost:8787/mcp'\n : runtimeEnv('MCP_URL') || 'https://mcp.posthog.com/mcp';\n\n return {\n skillsBaseUrl,\n projectApiKey,\n host,\n accessToken,\n projectId,\n cloudRegion,\n mcpUrl,\n wizardFlags,\n wizardMetadata,\n project,\n };\n}\n","/** Phase transitions from [STATUS] in assistant text. Keep in sync with program \"Status to report\" bullets. */\n\nconst PHASES_ORDER = [\n '1.0-begin',\n '1.1-edit',\n '1.2-revise',\n '1.3-conclude',\n] as const;\n\nconst STATUS_PHRASES_BY_PHASE: Record<(typeof PHASES_ORDER)[number], string[]> =\n {\n '1.0-begin': [\n 'Checking project structure',\n 'Verifying PostHog dependencies',\n 'Generating events based on project',\n ],\n '1.1-edit': ['Inserting PostHog capture code'],\n '1.2-revise': [\n 'Finding and correcting errors',\n 'Report details of any errors you fix',\n 'Linting, building and prettying',\n ],\n '1.3-conclude': ['Configured dashboard', 'Created setup report'],\n };\n\nexport class PhaseDetector {\n private currentPhase: 'setup' | (typeof PHASES_ORDER)[number] = 'setup';\n\n detect(message: any): string | null {\n if (message.type !== 'assistant') return null;\n\n const nextPhase = this.getNextPhase();\n if (nextPhase === null) return null;\n\n const content = message.message?.content;\n if (!Array.isArray(content)) return null;\n\n for (const block of content) {\n if (block.type !== 'text' || typeof block.text !== 'string') continue;\n if (!block.text.includes('[STATUS]')) continue;\n\n const phrases = STATUS_PHRASES_BY_PHASE[nextPhase];\n for (const phrase of phrases) {\n if (block.text.includes(phrase)) {\n this.currentPhase = nextPhase;\n return nextPhase;\n }\n }\n }\n\n return null;\n }\n\n private getNextPhase(): (typeof PHASES_ORDER)[number] | null {\n if (this.currentPhase === 'setup') return '1.0-begin';\n const i = PHASES_ORDER.indexOf(this.currentPhase);\n if (i < 0 || i >= PHASES_ORDER.length - 1) return null;\n return PHASES_ORDER[i + 1];\n }\n\n reset(): void {\n this.currentPhase = 'setup';\n }\n}\n","/**\n * Middleware pipeline orchestrator.\n *\n * Implements the same { onMessage, finalize } interface that runAgent() expects,\n * while internally dispatching to an ordered list of middleware plugins.\n */\n\nimport { PhaseDetector } from './phase-detector';\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n SDKMessage,\n} from './types';\n\nexport class MiddlewarePipeline {\n private middlewares: Middleware[];\n private store = new Map<string, unknown>();\n private phaseDetector: PhaseDetector;\n private autoDetectPhases: boolean;\n private _currentPhase = 'setup';\n private _currentPhaseFreshContext = true;\n\n constructor(\n middlewares: Middleware[],\n opts?: { phaseDetector?: PhaseDetector; autoDetectPhases?: boolean },\n ) {\n this.middlewares = middlewares;\n this.phaseDetector = opts?.phaseDetector ?? new PhaseDetector();\n this.autoDetectPhases = opts?.autoDetectPhases ?? true;\n\n const ctx = this.createContext();\n for (const mw of this.middlewares) {\n mw.onInit?.(ctx);\n }\n }\n\n /** Feed an SDK message through all middleware (satisfies tracker.onMessage) */\n onMessage(message: SDKMessage): void {\n // Phase detection first — updates context before middleware sees it\n if (this.autoDetectPhases) {\n const newPhase = this.phaseDetector.detect(message);\n if (newPhase && newPhase !== this._currentPhase) {\n this.transitionPhase(newPhase, false);\n }\n }\n\n const ctx = this.createContext();\n const storeHandle = this.createStore();\n for (const mw of this.middlewares) {\n mw.onMessage?.(message, ctx, storeHandle);\n }\n }\n\n /** Finalize the run (satisfies tracker.finalize) */\n finalize(resultMessage: any, totalDurationMs: number): any {\n const ctx = this.createContext();\n const storeHandle = this.createStore();\n let result: any;\n for (const mw of this.middlewares) {\n const r = mw.onFinalize?.(\n resultMessage,\n totalDurationMs,\n ctx,\n storeHandle,\n );\n if (r !== undefined) result = r;\n }\n return result;\n }\n\n /** Explicit phase start (for phased runner support) */\n startPhase(name: string, freshContext: boolean): void {\n this.transitionPhase(name, freshContext);\n }\n\n private transitionPhase(newPhase: string, freshContext: boolean): void {\n const oldPhase = this._currentPhase;\n this._currentPhase = newPhase;\n this._currentPhaseFreshContext = freshContext;\n const ctx = this.createContext();\n const storeHandle = this.createStore();\n for (const mw of this.middlewares) {\n mw.onPhaseTransition?.(oldPhase, newPhase, ctx, storeHandle);\n }\n }\n\n private createContext(): MiddlewareContext {\n return {\n currentPhase: this._currentPhase,\n currentPhaseFreshContext: this._currentPhaseFreshContext,\n get: <T>(key: string) => this.store.get(key) as T | undefined,\n };\n }\n\n private createStore(): MiddlewareStore {\n return {\n set: (key: string, value: unknown) => this.store.set(key, value),\n };\n }\n}\n","/**\n * Benchmark configuration loader.\n *\n * Loads .benchmark-config.json from the working directory with sensible defaults.\n * All fields are optional — missing fields fall back to defaults.\n */\n\nimport fs from 'fs';\nimport path from 'path';\nimport { logToFile } from '@utils/debug';\nimport { AgentSignals } from '@lib/agent/agent-interface';\nimport { runtimeEnv } from '@env';\nimport { WIZARD_BENCHMARK_FILE, WIZARD_LOG_FILE } from '@utils/paths';\n\nexport interface BenchmarkConfig {\n /** Enable/disable individual metric plugins */\n plugins: Record<string, boolean>;\n output: {\n /** Path for the benchmark JSON output file */\n benchmarkPath: string;\n /** Whether to write the benchmark JSON file */\n benchmarkEnabled: boolean;\n /** Path for the main wizard debug log file */\n logPath: string;\n /** Whether to write the main wizard debug log */\n logEnabled: boolean;\n /** Suppress benchmark console output (disables the summary plugin) */\n suppressWizardLogs: boolean;\n };\n}\n\nconst DEFAULT_CONFIG: BenchmarkConfig = {\n plugins: {\n tokens: true,\n cache: true,\n turns: true,\n compactions: true,\n contextSize: true,\n cost: true,\n duration: true,\n summary: true,\n jsonWriter: true,\n },\n output: {\n benchmarkPath: WIZARD_BENCHMARK_FILE,\n benchmarkEnabled: true,\n logPath: WIZARD_LOG_FILE,\n logEnabled: true,\n suppressWizardLogs: false,\n },\n};\n\nexport function loadBenchmarkConfig(installDir: string): BenchmarkConfig {\n const configPath =\n runtimeEnv('POSTHOG_WIZARD_BENCHMARK_CONFIG') ??\n path.join(installDir, '.benchmark-config.json');\n try {\n const raw = fs.readFileSync(configPath, 'utf-8');\n const parsed = JSON.parse(raw);\n const config: BenchmarkConfig = {\n plugins: { ...DEFAULT_CONFIG.plugins, ...parsed.plugins },\n output: { ...DEFAULT_CONFIG.output, ...parsed.output },\n };\n\n // Env var overrides for parallel runs\n const benchFile = runtimeEnv('POSTHOG_WIZARD_BENCHMARK_FILE');\n if (benchFile) {\n config.output.benchmarkPath = benchFile;\n }\n const logDir = runtimeEnv('POSTHOG_WIZARD_LOG_DIR');\n if (logDir) {\n config.output.logPath = path.join(logDir, 'posthog-wizard.log');\n }\n\n // If benchmark output is disabled, disable the jsonWriter plugin\n if (!config.output.benchmarkEnabled) {\n config.plugins.jsonWriter = false;\n }\n\n logToFile(`${AgentSignals.BENCHMARK} Loaded config from ${configPath}`);\n return config;\n } catch {\n // No config file or invalid JSON — use defaults\n const config = structuredClone(DEFAULT_CONFIG);\n\n // Env var overrides\n const benchFile2 = runtimeEnv('POSTHOG_WIZARD_BENCHMARK_FILE');\n if (benchFile2) {\n config.output.benchmarkPath = benchFile2;\n }\n const logDir2 = runtimeEnv('POSTHOG_WIZARD_LOG_DIR');\n if (logDir2) {\n config.output.logPath = path.join(logDir2, 'posthog-wizard.log');\n }\n\n return config;\n }\n}\n\nexport function getDefaultConfig(): BenchmarkConfig {\n return structuredClone(DEFAULT_CONFIG);\n}\n","/**\n * Turn counting plugin with message deduplication.\n *\n * The SDK emits multiple assistant events per turn (one per content block)\n * with the same message ID. This plugin deduplicates and publishes turn\n * counts + a duplicate flag for downstream plugins.\n */\n\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\n\nexport interface TurnData {\n /** Whether the current message is a duplicate of the last processed turn */\n isDuplicate: boolean;\n /** Turns in the current phase */\n phaseTurns: number;\n /** Total turns across all phases */\n totalTurns: number;\n /** Per-phase turn snapshots: [{ phase, turns }] */\n phaseSnapshots: Array<{ phase: string; turns: number }>;\n}\n\nexport class TurnCounterPlugin implements Middleware {\n readonly name = 'turns';\n\n private lastMessageId: string | null = null;\n private phaseTurns = 0;\n private totalTurns = 0;\n private isDuplicate = false;\n private phaseSnapshots: Array<{ phase: string; turns: number }> = [];\n private currentPhase = 'setup';\n\n onMessage(\n message: any,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n if (message.type !== 'assistant') {\n this.isDuplicate = false;\n store.set('turns', this.getData());\n return;\n }\n\n const msgId: string | undefined = message.message?.id;\n this.isDuplicate = msgId != null && msgId === this.lastMessageId;\n if (msgId) this.lastMessageId = msgId;\n\n if (!this.isDuplicate) {\n this.phaseTurns++;\n this.totalTurns++;\n }\n\n store.set('turns', this.getData());\n }\n\n onPhaseTransition(\n fromPhase: string,\n _toPhase: string,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n this.phaseSnapshots.push({ phase: fromPhase, turns: this.phaseTurns });\n this.currentPhase = _toPhase;\n this.phaseTurns = 0;\n this.lastMessageId = null;\n store.set('turns', this.getData());\n }\n\n onFinalize(\n _resultMessage: any,\n _totalDurationMs: number,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n this.phaseSnapshots.push({\n phase: this.currentPhase,\n turns: this.phaseTurns,\n });\n store.set('turns', this.getData());\n }\n\n private getData(): TurnData {\n return {\n isDuplicate: this.isDuplicate,\n phaseTurns: this.phaseTurns,\n totalTurns: this.totalTurns,\n phaseSnapshots: [...this.phaseSnapshots],\n };\n }\n}\n","/**\n * Token tracking plugin for input/output tokens.\n *\n * Accumulates per-turn token usage (input_tokens + cache_read_input_tokens\n * + cache_creation_input_tokens = total input; output_tokens = output).\n * Respects the dedup flag from TurnCounterPlugin. Cache breakdown (r/5m/1h)\n * is tracked by CacheTrackerPlugin for reporting and pricing.\n */\n\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\nimport type { TurnData } from './turn-counter';\n\nexport interface TokenData {\n phaseInput: number;\n phaseOutput: number;\n totalInput: number;\n totalOutput: number;\n /** The raw usage object from the last non-duplicate assistant message */\n lastUsage: any;\n /** Per-phase token snapshots */\n phaseSnapshots: Array<{\n phase: string;\n inputTokens: number;\n outputTokens: number;\n /** Number of turns in this phase that had usage (SDK may not report all) */\n messagesWithUsage: number;\n }>;\n}\n\nexport class TokenTrackerPlugin implements Middleware {\n readonly name = 'tokens';\n\n private phaseInput = 0;\n private phaseOutput = 0;\n private totalInput = 0;\n private totalOutput = 0;\n private lastUsage: any = null;\n private phaseSnapshots: Array<{\n phase: string;\n inputTokens: number;\n outputTokens: number;\n messagesWithUsage: number;\n }> = [];\n private currentPhase = 'setup';\n private phaseMessagesWithUsage = 0;\n\n onMessage(\n message: any,\n ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n if (message.type !== 'assistant') return;\n\n const turns = ctx.get<TurnData>('turns');\n if (turns?.isDuplicate) return;\n\n const usage = message.message?.usage;\n if (usage) {\n const input =\n Number(usage.input_tokens ?? 0) +\n Number(usage.cache_read_input_tokens ?? 0) +\n Number(usage.cache_creation_input_tokens ?? 0);\n const output = Number(usage.output_tokens ?? 0);\n this.phaseInput += input;\n this.phaseOutput += output;\n this.totalInput += input;\n this.totalOutput += output;\n this.lastUsage = usage;\n this.phaseMessagesWithUsage += 1;\n }\n\n store.set('tokens', this.getData());\n }\n\n onPhaseTransition(\n fromPhase: string,\n toPhase: string,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n this.phaseSnapshots.push({\n phase: fromPhase,\n inputTokens: this.phaseInput,\n outputTokens: this.phaseOutput,\n messagesWithUsage: this.phaseMessagesWithUsage,\n });\n this.currentPhase = toPhase;\n this.phaseInput = 0;\n this.phaseOutput = 0;\n this.phaseMessagesWithUsage = 0;\n store.set('tokens', this.getData());\n }\n\n onFinalize(\n _resultMessage: any,\n _totalDurationMs: number,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n this.phaseSnapshots.push({\n phase: this.currentPhase,\n inputTokens: this.phaseInput,\n outputTokens: this.phaseOutput,\n messagesWithUsage: this.phaseMessagesWithUsage,\n });\n store.set('tokens', this.getData());\n }\n\n private getData(): TokenData {\n return {\n phaseInput: this.phaseInput,\n phaseOutput: this.phaseOutput,\n totalInput: this.totalInput,\n totalOutput: this.totalOutput,\n lastUsage: this.lastUsage,\n phaseSnapshots: [...this.phaseSnapshots],\n };\n }\n}\n","/**\n * Cache token tracking plugin (cache_read and cache_creation).\n *\n * Respects the dedup flag from TurnCounterPlugin.\n */\n\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\nimport type { TurnData } from './turn-counter';\n\n/** Matches SDK usage.cache_creation (ephemeral 5m vs 1h for pricing). */\nexport interface CacheCreationBreakdown {\n ephemeral_5m_input_tokens: number;\n ephemeral_1h_input_tokens: number;\n}\n\nexport interface CacheData {\n phaseRead: number;\n phaseCreation: number;\n totalRead: number;\n totalCreation: number;\n totalCreation5m: number;\n totalCreation1h: number;\n phaseSnapshots: Array<{\n phase: string;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n /** When present, use for pricing (5m vs 1h rates). */\n cacheCreation5m: number;\n cacheCreation1h: number;\n }>;\n}\n\nexport class CacheTrackerPlugin implements Middleware {\n readonly name = 'cache';\n\n private phaseRead = 0;\n private phaseCreation = 0;\n private phaseCreation5m = 0;\n private phaseCreation1h = 0;\n private totalRead = 0;\n private totalCreation = 0;\n private totalCreation5m = 0;\n private totalCreation1h = 0;\n private phaseSnapshots: Array<{\n phase: string;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n cacheCreation5m: number;\n cacheCreation1h: number;\n }> = [];\n private currentPhase = 'setup';\n\n onMessage(\n message: any,\n ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n if (message.type !== 'assistant') return;\n\n const turns = ctx.get<TurnData>('turns');\n if (turns?.isDuplicate) return;\n\n const usage = message.message?.usage;\n if (usage) {\n const read = Number(usage.cache_read_input_tokens ?? 0);\n const creation = Number(usage.cache_creation_input_tokens ?? 0);\n const cc = usage.cache_creation;\n const creation5m = Number(cc?.ephemeral_5m_input_tokens ?? 0);\n const creation1h = Number(cc?.ephemeral_1h_input_tokens ?? 0);\n this.phaseRead += read;\n this.phaseCreation += creation;\n this.phaseCreation5m += creation5m;\n this.phaseCreation1h += creation1h;\n this.totalRead += read;\n this.totalCreation += creation;\n }\n\n store.set('cache', this.getData());\n }\n\n onPhaseTransition(\n fromPhase: string,\n toPhase: string,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n this.phaseSnapshots.push({\n phase: fromPhase,\n cacheReadTokens: this.phaseRead,\n cacheCreationTokens: this.phaseCreation,\n cacheCreation5m: this.phaseCreation5m,\n cacheCreation1h: this.phaseCreation1h,\n });\n this.currentPhase = toPhase;\n this.phaseRead = 0;\n this.phaseCreation = 0;\n this.phaseCreation5m = 0;\n this.phaseCreation1h = 0;\n store.set('cache', this.getData());\n }\n\n onFinalize(\n _resultMessage: any,\n _totalDurationMs: number,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n this.phaseSnapshots.push({\n phase: this.currentPhase,\n cacheReadTokens: this.phaseRead,\n cacheCreationTokens: this.phaseCreation,\n cacheCreation5m: this.phaseCreation5m,\n cacheCreation1h: this.phaseCreation1h,\n });\n store.set('cache', this.getData());\n }\n\n private getData(): CacheData {\n return {\n phaseRead: this.phaseRead,\n phaseCreation: this.phaseCreation,\n totalRead: this.totalRead,\n totalCreation: this.totalCreation,\n totalCreation5m: this.totalCreation5m,\n totalCreation1h: this.totalCreation1h,\n phaseSnapshots: [...this.phaseSnapshots],\n };\n }\n}\n","/**\n * Compaction event tracking plugin.\n *\n * Tracks context compaction events (compact_boundary system messages)\n * including pre-compaction token counts per phase.\n */\n\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\nimport { logToFile } from '@utils/debug';\nimport { AgentSignals } from '@lib/agent/agent-interface';\n\nexport interface CompactionData {\n phaseCompactions: number;\n phasePreTokens: number[];\n totalCompactions: number;\n phaseSnapshots: Array<{\n phase: string;\n compactions: number;\n preTokens: number[];\n }>;\n}\n\nexport class CompactionTrackerPlugin implements Middleware {\n readonly name = 'compactions';\n\n private phaseCompactions = 0;\n private phasePreTokens: number[] = [];\n private totalCompactions = 0;\n private phaseSnapshots: Array<{\n phase: string;\n compactions: number;\n preTokens: number[];\n }> = [];\n private currentPhase = 'setup';\n\n onMessage(\n message: any,\n ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n if (message.type !== 'system' || message.subtype !== 'compact_boundary') {\n return;\n }\n\n const preTokens = message.compact_metadata?.pre_tokens ?? 0;\n const trigger = message.compact_metadata?.trigger ?? 'unknown';\n this.phaseCompactions++;\n this.totalCompactions++;\n this.phasePreTokens.push(preTokens);\n\n logToFile(\n `${AgentSignals.BENCHMARK} [COMPACTION] Context compacted during \"${ctx.currentPhase}\" (trigger: ${trigger}, pre_tokens: ${preTokens})`,\n );\n\n store.set('compactions', this.getData());\n }\n\n onPhaseTransition(\n fromPhase: string,\n toPhase: string,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n this.phaseSnapshots.push({\n phase: fromPhase,\n compactions: this.phaseCompactions,\n preTokens: [...this.phasePreTokens],\n });\n this.currentPhase = toPhase;\n this.phaseCompactions = 0;\n this.phasePreTokens = [];\n store.set('compactions', this.getData());\n }\n\n onFinalize(\n _resultMessage: any,\n _totalDurationMs: number,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n this.phaseSnapshots.push({\n phase: this.currentPhase,\n compactions: this.phaseCompactions,\n preTokens: [...this.phasePreTokens],\n });\n store.set('compactions', this.getData());\n }\n\n private getData(): CompactionData {\n return {\n phaseCompactions: this.phaseCompactions,\n phasePreTokens: [...this.phasePreTokens],\n totalCompactions: this.totalCompactions,\n phaseSnapshots: [...this.phaseSnapshots],\n };\n }\n}\n","/**\n * Context size tracking plugin (context tokens in/out per phase).\n *\n * Context tokens out = sum of input + cache_read + cache_creation from the\n * last assistant message's usage (per-turn, NOT aggregate).\n * Context tokens in = previous phase's context tokens out.\n */\n\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\nimport type { TokenData } from './token-tracker';\n\nexport interface ContextSizeData {\n /** Per-phase context size snapshots */\n phaseSnapshots: Array<{\n phase: string;\n contextTokensIn?: number;\n contextTokensOut?: number;\n freshContext: boolean;\n }>;\n}\n\nexport class ContextSizeTrackerPlugin implements Middleware {\n readonly name = 'contextSize';\n\n private phaseSnapshots: Array<{\n phase: string;\n contextTokensIn?: number;\n contextTokensOut?: number;\n freshContext: boolean;\n }> = [];\n private lastContextTokensOut?: number;\n\n onPhaseTransition(\n fromPhase: string,\n _toPhase: string,\n ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n const tokens = ctx.get<TokenData>('tokens');\n const contextTokensOut = this.computeContextTokensOut(tokens?.lastUsage);\n\n this.phaseSnapshots.push({\n phase: fromPhase,\n contextTokensIn: ctx.currentPhaseFreshContext\n ? undefined\n : this.lastContextTokensOut,\n contextTokensOut,\n freshContext: ctx.currentPhaseFreshContext,\n });\n\n this.lastContextTokensOut = contextTokensOut;\n store.set('contextSize', this.getData());\n }\n\n onFinalize(\n _resultMessage: any,\n _totalDurationMs: number,\n ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n const tokens = ctx.get<TokenData>('tokens');\n const contextTokensOut = this.computeContextTokensOut(tokens?.lastUsage);\n\n this.phaseSnapshots.push({\n phase: ctx.currentPhase,\n contextTokensIn: ctx.currentPhaseFreshContext\n ? undefined\n : this.lastContextTokensOut,\n contextTokensOut,\n freshContext: ctx.currentPhaseFreshContext,\n });\n\n store.set('contextSize', this.getData());\n }\n\n private computeContextTokensOut(usage: any): number | undefined {\n if (!usage) return undefined;\n return (\n Number(usage.input_tokens ?? 0) +\n Number(usage.cache_read_input_tokens ?? 0) +\n Number(usage.cache_creation_input_tokens ?? 0)\n );\n }\n\n private getData(): ContextSizeData {\n return {\n phaseSnapshots: [...this.phaseSnapshots],\n };\n }\n}\n","import type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\nimport type { TokenData } from './token-tracker';\nimport type { CacheData } from './cache-tracker';\n\nexport interface CostData {\n totalCost: number;\n phaseCosts: Array<{ phase: string; cost: number }>;\n}\n\n/** Claude Sonnet 4.6 pricing (USD per 1M tokens) */\nconst PRICE_PER_MTOK = {\n input: 3,\n output: 15,\n cacheRead: 0.3,\n cacheCreation5m: 3.75,\n cacheCreation1h: 6,\n} as const;\n\nfunction computeCost(\n inputTokens: number,\n outputTokens: number,\n cacheReadTokens: number,\n cacheCreation5m: number,\n cacheCreation1h: number,\n cacheCreationFallback: number,\n): number {\n const hasBreakdown = cacheCreation5m > 0 || cacheCreation1h > 0;\n return (\n inputTokens * (PRICE_PER_MTOK.input / 1e6) +\n outputTokens * (PRICE_PER_MTOK.output / 1e6) +\n cacheReadTokens * (PRICE_PER_MTOK.cacheRead / 1e6) +\n (hasBreakdown\n ? cacheCreation5m * (PRICE_PER_MTOK.cacheCreation5m / 1e6) +\n cacheCreation1h * (PRICE_PER_MTOK.cacheCreation1h / 1e6)\n : cacheCreationFallback * (PRICE_PER_MTOK.cacheCreation5m / 1e6))\n );\n}\n\nexport class CostTrackerPlugin implements Middleware {\n readonly name = 'cost';\n\n private phaseCosts: Array<{ phase: string; cost: number }> = [];\n private totalCost = 0;\n\n onPhaseTransition(\n fromPhase: string,\n _toPhase: string,\n ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n const tokens = ctx.get<TokenData>('tokens');\n const cache = ctx.get<CacheData>('cache');\n const tokenSnap = tokens?.phaseSnapshots.at(-1);\n const cacheSnap = cache?.phaseSnapshots.at(-1);\n\n const totalIn = tokenSnap?.inputTokens ?? 0;\n const read = cacheSnap?.cacheReadTokens ?? 0;\n const creation = cacheSnap?.cacheCreationTokens ?? 0;\n const c5m = cacheSnap?.cacheCreation5m ?? 0;\n const c1h = cacheSnap?.cacheCreation1h ?? 0;\n const baseIn = Math.max(0, totalIn - read - creation);\n\n const phaseCost = computeCost(\n baseIn,\n tokenSnap?.outputTokens ?? 0,\n read,\n c5m,\n c1h,\n creation,\n );\n\n this.phaseCosts.push({ phase: fromPhase, cost: phaseCost });\n this.totalCost += phaseCost;\n store.set('cost', this.getData());\n }\n\n onFinalize(\n resultMessage: any,\n _totalDurationMs: number,\n ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n const tokens = ctx.get<TokenData>('tokens');\n const cache = ctx.get<CacheData>('cache');\n const tokenSnap = tokens?.phaseSnapshots.at(-1);\n const cacheSnap = cache?.phaseSnapshots.at(-1);\n\n const totalIn = tokenSnap?.inputTokens ?? 0;\n const read = cacheSnap?.cacheReadTokens ?? 0;\n const creation = cacheSnap?.cacheCreationTokens ?? 0;\n const c5m = cacheSnap?.cacheCreation5m ?? 0;\n const c1h = cacheSnap?.cacheCreation1h ?? 0;\n const baseIn = Math.max(0, totalIn - read - creation);\n\n const lastPhaseCost = computeCost(\n baseIn,\n tokenSnap?.outputTokens ?? 0,\n read,\n c5m,\n c1h,\n creation,\n );\n\n this.phaseCosts.push({ phase: ctx.currentPhase, cost: lastPhaseCost });\n this.totalCost += lastPhaseCost;\n\n const sdkTotal =\n Number(resultMessage?.usage?.total_cost_usd ?? 0) ||\n Number(resultMessage?.total_cost_usd ?? 0);\n\n if (sdkTotal > 0 && this.totalCost > 0) {\n const scale = sdkTotal / this.totalCost;\n this.phaseCosts = this.phaseCosts.map((p) => ({\n phase: p.phase,\n cost: p.cost * scale,\n }));\n this.totalCost = sdkTotal;\n }\n\n store.set('cost', this.getData());\n }\n\n private getData(): CostData {\n return {\n totalCost: this.totalCost,\n phaseCosts: [...this.phaseCosts],\n };\n }\n}\n","/**\n * Duration tracking plugin (per-phase and total).\n */\n\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\n\nexport interface DurationData {\n phaseSnapshots: Array<{\n phase: string;\n startTime: number;\n endTime: number;\n durationMs: number;\n }>;\n totalDurationMs: number;\n}\n\nexport class DurationTrackerPlugin implements Middleware {\n readonly name = 'duration';\n\n private phaseStartTime = Date.now();\n private phaseSnapshots: Array<{\n phase: string;\n startTime: number;\n endTime: number;\n durationMs: number;\n }> = [];\n\n onPhaseTransition(\n fromPhase: string,\n _toPhase: string,\n _ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n const now = Date.now();\n this.phaseSnapshots.push({\n phase: fromPhase,\n startTime: this.phaseStartTime,\n endTime: now,\n durationMs: now - this.phaseStartTime,\n });\n this.phaseStartTime = now;\n store.set('duration', {\n phaseSnapshots: [...this.phaseSnapshots],\n totalDurationMs: 0,\n } satisfies DurationData);\n }\n\n onFinalize(\n _resultMessage: any,\n totalDurationMs: number,\n ctx: MiddlewareContext,\n store: MiddlewareStore,\n ): void {\n const now = Date.now();\n this.phaseSnapshots.push({\n phase: ctx.currentPhase,\n startTime: this.phaseStartTime,\n endTime: now,\n durationMs: now - this.phaseStartTime,\n });\n\n store.set('duration', {\n phaseSnapshots: [...this.phaseSnapshots],\n totalDurationMs,\n } satisfies DurationData);\n }\n}\n","import { getUI, type SpinnerHandle } from '@ui';\nimport { AgentSignals } from '@lib/agent/agent-interface';\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\nimport type { TokenData } from './token-tracker';\nimport type { TurnData } from './turn-counter';\nimport type { CostData } from './cost-tracker';\nimport type { DurationData } from './duration-tracker';\nimport type { CompactionData } from './compaction-tracker';\nimport type { ContextSizeData } from './context-size-tracker';\nimport type { CacheData } from './cache-tracker';\n\nfunction fmtDuration(ms: number): string {\n const s = Math.round(ms / 1000);\n const m = Math.floor(s / 60);\n return m > 0 ? `${m}m ${s % 60}s` : `${s}s`;\n}\n\nfunction fmtTok(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1000).toFixed(1)}K`;\n return n.toLocaleString();\n}\n\nfunction fmtCost(usd: number): string {\n if (usd > 0 && usd < 0.01) return `$${usd.toFixed(4)}`;\n return `$${usd.toFixed(2)}`;\n}\n\ninterface PhaseStats {\n phase: string;\n durationMs: number;\n turns: number;\n inputTokens: number;\n outputTokens: number;\n cacheRead: number;\n cacheCreation5m: number;\n cacheCreation1h: number;\n cost: number;\n compactions: number;\n contextOut: number | undefined;\n}\n\nfunction printPhase(s: PhaseStats): string {\n const baseIn = Math.max(\n 0,\n s.inputTokens - s.cacheRead - s.cacheCreation5m - s.cacheCreation1h,\n );\n return [\n `${s.phase}: ${fmtDuration(s.durationMs)}, ${\n s.turns\n } turns, cost: ${fmtCost(s.cost)}`,\n ` in: ${fmtTok(baseIn)}, out: ${fmtTok(\n s.outputTokens,\n )}, cache_read: ${fmtTok(s.cacheRead)}, cache_5m: ${fmtTok(\n s.cacheCreation5m,\n )}, cache_1h: ${fmtTok(s.cacheCreation1h)}`,\n s.compactions > 0 ? ` ${s.compactions} compaction(s)` : null,\n s.contextOut !== undefined ? ` ctx_out: ${fmtTok(s.contextOut)}` : null,\n ]\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction getPhaseStats(i: number, ctx: MiddlewareContext): PhaseStats | null {\n const duration = ctx.get<DurationData>('duration');\n const dur = duration?.phaseSnapshots[i];\n if (!dur) return null;\n\n const tokens = ctx.get<TokenData>('tokens');\n const turns = ctx.get<TurnData>('turns');\n const cost = ctx.get<CostData>('cost');\n const compactions = ctx.get<CompactionData>('compactions');\n const contextSize = ctx.get<ContextSizeData>('contextSize');\n const cache = ctx.get<CacheData>('cache');\n\n return {\n phase: dur.phase,\n durationMs: dur.durationMs,\n turns: turns?.phaseSnapshots[i]?.turns ?? 0,\n inputTokens: tokens?.phaseSnapshots[i]?.inputTokens ?? 0,\n outputTokens: tokens?.phaseSnapshots[i]?.outputTokens ?? 0,\n cacheRead: cache?.phaseSnapshots[i]?.cacheReadTokens ?? 0,\n cacheCreation5m: cache?.phaseSnapshots[i]?.cacheCreation5m ?? 0,\n cacheCreation1h: cache?.phaseSnapshots[i]?.cacheCreation1h ?? 0,\n cost: cost?.phaseCosts[i]?.cost ?? 0,\n compactions: compactions?.phaseSnapshots[i]?.compactions ?? 0,\n contextOut: contextSize?.phaseSnapshots[i]?.contextTokensOut,\n };\n}\n\nexport class SummaryPlugin implements Middleware {\n readonly name = 'summary';\n\n private spinner: SpinnerHandle;\n\n constructor(spinner: SpinnerHandle) {\n this.spinner = spinner;\n }\n\n onPhaseTransition(\n fromPhase: string,\n toPhase: string,\n ctx: MiddlewareContext,\n _store: MiddlewareStore,\n ): void {\n const duration = ctx.get<DurationData>('duration');\n const idx = (duration?.phaseSnapshots.length ?? 1) - 1;\n const stats = getPhaseStats(idx, ctx);\n\n if (stats) {\n this.spinner.stop(`${AgentSignals.BENCHMARK} ${printPhase(stats)}`);\n } else {\n this.spinner.stop(`${AgentSignals.BENCHMARK} ${fromPhase}`);\n }\n\n getUI().log.info(`${AgentSignals.BENCHMARK} Starting phase: ${toPhase}`);\n this.spinner.start(`Integrating PostHog (${toPhase})...`);\n }\n\n onFinalize(\n _resultMessage: any,\n totalDurationMs: number,\n ctx: MiddlewareContext,\n _store: MiddlewareStore,\n ): void {\n const duration = ctx.get<DurationData>('duration');\n const cost = ctx.get<CostData>('cost');\n const tokens = ctx.get<TokenData>('tokens');\n const cache = ctx.get<CacheData>('cache');\n\n const phaseCount = duration?.phaseSnapshots.length ?? 0;\n const totalCost = cost?.totalCost ?? 0;\n\n getUI().log.info('');\n getUI().log.info(\n `◇ ${AgentSignals.BENCHMARK} ${phaseCount} phases in ${fmtDuration(\n totalDurationMs,\n )}, cost: ${fmtCost(totalCost)}`,\n );\n getUI().log.info(\n ` total in: ${fmtTok(tokens?.totalInput ?? 0)}, out: ${fmtTok(\n tokens?.totalOutput ?? 0,\n )}, cache_read: ${fmtTok(cache?.totalRead ?? 0)}, cache_5m: ${fmtTok(\n cache?.totalCreation5m ?? 0,\n )}, cache_1h: ${fmtTok(cache?.totalCreation1h ?? 0)}`,\n );\n getUI().log.info('');\n getUI().log.info(`● ${AgentSignals.BENCHMARK} Summary by phase:`);\n\n if (duration?.phaseSnapshots) {\n for (let i = 0; i < duration.phaseSnapshots.length; i++) {\n const stats = getPhaseStats(i, ctx);\n if (stats) {\n getUI().log.info(printPhase(stats));\n }\n }\n }\n\n getUI().log.info('');\n }\n}\n","/**\n * JSON file output plugin.\n *\n * Assembles the BenchmarkData structure from all upstream plugin data\n * and writes it to a JSON file. Returns the BenchmarkData for backward compat.\n */\n\nimport fs from 'fs';\nimport { getUI } from '@ui';\nimport { logToFile } from '@utils/debug';\nimport { AgentSignals } from '@lib/agent/agent-interface';\nimport type {\n Middleware,\n MiddlewareContext,\n MiddlewareStore,\n} from '@lib/middleware/types';\nimport type { TokenData } from './token-tracker';\nimport type { CacheData } from './cache-tracker';\nimport type { TurnData } from './turn-counter';\nimport type { CostData } from './cost-tracker';\nimport type { DurationData } from './duration-tracker';\nimport type { CompactionData } from './compaction-tracker';\nimport type { ContextSizeData } from './context-size-tracker';\nimport type { BenchmarkData, StepUsage } from '@lib/middleware/benchmark';\n\n/**\n * Sum token usage across all models from the SDK's modelUsage field.\n */\nfunction sumModelUsage(modelUsage: Record<string, any>): {\n input_tokens: number;\n output_tokens: number;\n cache_creation_input_tokens: number;\n cache_read_input_tokens: number;\n} {\n let input_tokens = 0;\n let output_tokens = 0;\n let cache_creation_input_tokens = 0;\n let cache_read_input_tokens = 0;\n\n for (const model of Object.values(modelUsage)) {\n input_tokens += model.inputTokens ?? 0;\n output_tokens += model.outputTokens ?? 0;\n cache_creation_input_tokens += model.cacheCreationInputTokens ?? 0;\n cache_read_input_tokens += model.cacheReadInputTokens ?? 0;\n }\n\n return {\n input_tokens,\n output_tokens,\n cache_creation_input_tokens,\n cache_read_input_tokens,\n };\n}\n\nexport class JsonWriterPlugin implements Middleware {\n readonly name = 'jsonWriter';\n\n private outputPath: string;\n\n constructor(outputPath: string) {\n this.outputPath = outputPath;\n }\n\n onFinalize(\n resultMessage: any,\n totalDurationMs: number,\n ctx: MiddlewareContext,\n _store: MiddlewareStore,\n ): BenchmarkData {\n const tokens = ctx.get<TokenData>('tokens');\n const cache = ctx.get<CacheData>('cache');\n const turns = ctx.get<TurnData>('turns');\n const cost = ctx.get<CostData>('cost');\n const duration = ctx.get<DurationData>('duration');\n const compactions = ctx.get<CompactionData>('compactions');\n const contextSize = ctx.get<ContextSizeData>('contextSize');\n\n const modelUsage = resultMessage?.modelUsage ?? {};\n const aggregateUsage = sumModelUsage(modelUsage);\n\n const phaseCount = duration?.phaseSnapshots.length ?? 0;\n const steps: StepUsage[] = [];\n\n for (let i = 0; i < phaseCount; i++) {\n const dur = duration!.phaseSnapshots[i];\n const tokenSnap = tokens?.phaseSnapshots[i];\n const cacheSnap = cache?.phaseSnapshots[i];\n const turnSnap = turns?.phaseSnapshots[i];\n const costSnap = cost?.phaseCosts[i];\n const compSnap = compactions?.phaseSnapshots[i];\n const ctxSnap = contextSize?.phaseSnapshots[i];\n\n const step: StepUsage = {\n name: dur.phase,\n usage: {\n input_tokens: tokenSnap?.inputTokens ?? 0,\n output_tokens: tokenSnap?.outputTokens ?? 0,\n cache_creation_input_tokens: cacheSnap?.cacheCreationTokens ?? 0,\n cache_read_input_tokens: cacheSnap?.cacheReadTokens ?? 0,\n ...((cacheSnap?.cacheCreation5m ?? 0) +\n (cacheSnap?.cacheCreation1h ?? 0) >\n 0 && {\n cache_creation: {\n ephemeral_5m_input_tokens: cacheSnap?.cacheCreation5m ?? 0,\n ephemeral_1h_input_tokens: cacheSnap?.cacheCreation1h ?? 0,\n },\n }),\n },\n modelUsage: {},\n totalCostUsd: costSnap?.cost ?? 0,\n durationMs: dur.durationMs,\n durationApiMs: 0,\n numTurns: turnSnap?.turns ?? 0,\n ...(ctxSnap?.contextTokensIn !== undefined && {\n contextTokensIn: ctxSnap.contextTokensIn,\n }),\n ...(ctxSnap?.contextTokensOut !== undefined && {\n contextTokensOut: ctxSnap.contextTokensOut,\n }),\n ...(compSnap && compSnap.compactions > 0\n ? {\n compactions: compSnap.compactions,\n compactionPreTokens: compSnap.preTokens,\n }\n : {}),\n };\n\n steps.push(step);\n }\n\n const totalTurns = turns?.totalTurns ?? 0;\n const totalCost = cost?.totalCost ?? 0;\n const totalCompactions = compactions?.totalCompactions ?? 0;\n const fromModelUsage =\n aggregateUsage.input_tokens +\n aggregateUsage.cache_read_input_tokens +\n aggregateUsage.cache_creation_input_tokens;\n const inputTokens =\n fromModelUsage > 0\n ? fromModelUsage\n : (tokens?.totalInput ?? 0) +\n (cache?.totalRead ?? 0) +\n (cache?.totalCreation ?? 0);\n const outputTokens =\n aggregateUsage.output_tokens > 0\n ? aggregateUsage.output_tokens\n : tokens?.totalOutput ?? 0;\n\n const benchmark: BenchmarkData = {\n timestamp: new Date().toISOString(),\n steps,\n totals: {\n totalCostUsd: totalCost,\n durationMs: totalDurationMs,\n inputTokens,\n outputTokens,\n numTurns: resultMessage?.num_turns ?? totalTurns,\n totalCompactions,\n totalCacheReadTokens: cache?.totalRead ?? 0,\n totalCacheCreation5mTokens: cache?.totalCreation5m ?? 0,\n totalCacheCreation1hTokens: cache?.totalCreation1h ?? 0,\n },\n };\n\n this.writeBenchmarkData(benchmark);\n return benchmark;\n }\n\n private writeBenchmarkData(data: BenchmarkData): void {\n try {\n fs.writeFileSync(this.outputPath, JSON.stringify(data, null, 2));\n logToFile(`Benchmark data written to ${this.outputPath}`);\n getUI().log.info(\n `● ${AgentSignals.BENCHMARK} Results written to ${this.outputPath}`,\n );\n } catch (error) {\n logToFile('Failed to write benchmark data:', error);\n }\n }\n}\n","/**\n * Plugin registry and factory.\n *\n * Maps plugin names to constructors and creates the ordered plugin list\n * from a BenchmarkConfig.\n */\n\nimport type {\n Middleware,\n MiddlewareFactoryOptions,\n} from '@lib/middleware/types';\nimport type { BenchmarkConfig } from '@lib/middleware/config';\nimport { TurnCounterPlugin } from './turn-counter';\nimport { TokenTrackerPlugin } from './token-tracker';\nimport { CacheTrackerPlugin } from './cache-tracker';\nimport { CompactionTrackerPlugin } from './compaction-tracker';\nimport { ContextSizeTrackerPlugin } from './context-size-tracker';\nimport { CostTrackerPlugin } from './cost-tracker';\nimport { DurationTrackerPlugin } from './duration-tracker';\nimport { SummaryPlugin } from './summary';\nimport { JsonWriterPlugin } from './json-writer';\n\ntype PluginFactory = (opts: MiddlewareFactoryOptions) => Middleware;\n\nconst PLUGIN_REGISTRY: Record<string, PluginFactory> = {\n turns: () => new TurnCounterPlugin(),\n tokens: () => new TokenTrackerPlugin(),\n cache: () => new CacheTrackerPlugin(),\n compactions: () => new CompactionTrackerPlugin(),\n contextSize: () => new ContextSizeTrackerPlugin(),\n cost: () => new CostTrackerPlugin(),\n duration: () => new DurationTrackerPlugin(),\n summary: (opts) => new SummaryPlugin(opts.spinner!),\n jsonWriter: (opts) => new JsonWriterPlugin(opts.outputPath!),\n};\n\n/**\n * Execution order — data producers before consumers:\n * turns (dedup) -> tokens -> cache -> compactions -> contextSize -> cost -> duration -> summary -> jsonWriter\n */\nconst PLUGIN_ORDER = [\n 'turns',\n 'tokens',\n 'cache',\n 'compactions',\n 'contextSize',\n 'cost',\n 'duration',\n 'summary',\n 'jsonWriter',\n];\n\nexport function createPluginsFromConfig(\n config: BenchmarkConfig,\n opts: MiddlewareFactoryOptions,\n): Middleware[] {\n const resolvedOpts: MiddlewareFactoryOptions = {\n ...opts,\n outputPath: opts.outputPath ?? config.output.benchmarkPath,\n };\n\n // If suppressWizardLogs is set, disable the summary plugin\n const effectivePlugins = { ...config.plugins };\n if (config.output.suppressWizardLogs) {\n effectivePlugins.summary = false;\n }\n\n return PLUGIN_ORDER.filter((name) => effectivePlugins[name] !== false)\n .map((name) => PLUGIN_REGISTRY[name])\n .filter(Boolean)\n .map((factory) => factory(resolvedOpts));\n}\n","/**\n * Benchmark tracking for wizard runs.\n *\n * Usage:\n * const pipeline = createBenchmarkPipeline(spinner, options);\n * pipeline.onMessage(message);\n * pipeline.finalize(resultMessage, durationMs);\n */\n\nimport { getUI, type SpinnerHandle } from '@ui';\nimport { logToFile, getLogFilePath, configureLogFile } from '@utils/debug';\nimport { MiddlewarePipeline } from './pipeline';\nimport { PhaseDetector } from './phase-detector';\nimport { loadBenchmarkConfig } from './config';\nimport { createPluginsFromConfig } from './benchmarks';\nimport type { BenchmarkConfig } from './config';\nimport type { WizardRunOptions } from '@utils/types';\nimport { AgentSignals } from '@lib/agent/agent-interface';\n\n// ── Types ──────────────────────────────────────────────────────────────\n\nexport interface StepUsage {\n name: string;\n usage: {\n input_tokens: number;\n output_tokens: number;\n cache_creation_input_tokens: number;\n cache_read_input_tokens: number;\n cache_creation?: {\n ephemeral_5m_input_tokens: number;\n ephemeral_1h_input_tokens: number;\n };\n };\n modelUsage: Record<string, unknown>;\n totalCostUsd: number;\n durationMs: number;\n durationApiMs: number;\n numTurns: number;\n contextTokensIn?: number;\n contextTokensOut?: number;\n compactions?: number;\n compactionPreTokens?: number[];\n}\n\nexport interface BenchmarkData {\n timestamp: string;\n steps: StepUsage[];\n totals: {\n totalCostUsd: number;\n durationMs: number;\n inputTokens: number;\n outputTokens: number;\n numTurns: number;\n totalCompactions: number;\n totalCacheReadTokens: number;\n totalCacheCreation5mTokens: number;\n totalCacheCreation1hTokens: number;\n };\n}\n\n// ── Factory ────────────────────────────────────────────────────────────\n\n/**\n * Create a middleware pipeline configured for benchmarking.\n * Loads .benchmark-config.json from the install dir, falls back to defaults.\n */\nexport function createBenchmarkPipeline(\n spinner: SpinnerHandle,\n options: WizardRunOptions,\n configOverride?: BenchmarkConfig,\n): MiddlewarePipeline {\n const config = configOverride ?? loadBenchmarkConfig(options.installDir);\n\n configureLogFile({\n path: config.output.logPath,\n enabled: config.output.logEnabled,\n });\n\n const plugins = createPluginsFromConfig(config, {\n spinner,\n phased: false,\n outputPath: config.output.benchmarkPath,\n });\n\n if (!config.output.suppressWizardLogs) {\n getUI().log.info(\n `${AgentSignals.BENCHMARK} Verbose logs: ${getLogFilePath()}`,\n );\n getUI().log.info(\n `${AgentSignals.BENCHMARK} Benchmark data will be written to: ${config.output.benchmarkPath}`,\n );\n }\n\n logToFile(\n `${AgentSignals.BENCHMARK} Tracking enabled, starting with setup phase`,\n );\n\n return new MiddlewarePipeline(plugins, {\n phaseDetector: new PhaseDetector(),\n autoDetectPhases: true,\n });\n}\n","/**\n * WizardAskBridge — host-side promise broker for the `wizard_ask` MCP tool.\n *\n * The `wizard_ask` tool needs to (a) read information from the wizard\n * session (the active skill id, used as the analytics `source`) and\n * (b) drive the TUI overlay. Wiring `wizard-tools.ts` directly to either\n * would couple our pure-data MCP server to the runtime UI layer.\n *\n * The bridge is the seam: `wizard-tools.ts` depends on this interface,\n * and `agent-runner.ts` constructs an implementation that knows about\n * both the session and `getUI()`.\n */\nimport { randomUUID } from 'crypto';\n\nimport { analytics } from '@utils/analytics';\nimport type {\n AskAnswers,\n AskQuestion,\n PendingQuestion,\n} from './wizard-session';\n\nexport interface WizardAskRequest {\n questions: AskQuestion[];\n}\n\nexport interface WizardAskBridge {\n /**\n * Open the WizardAsk overlay and resolve with the user's answers.\n * One answer per question id (string for `single`/`text`, string[] for\n * `multi`). Cancelled fields come back as the literal `\"__cancelled__\"`.\n */\n request(req: WizardAskRequest): Promise<AskAnswers>;\n}\n\nexport interface WizardAskBridgeOptions {\n /** Returns the active skill id, used as the analytics `source` on the request. */\n getSource: () => string;\n /** Opens the overlay and resolves once the user submits or cancels. */\n showQuestion: (question: PendingQuestion) => Promise<AskAnswers>;\n /**\n * Per-question timeout in milliseconds. When the user takes longer than\n * this to answer, every unanswered field resolves with the\n * {@link CANCELLED_SENTINEL} value. Defaults to {@link DEFAULT_ASK_TIMEOUT_MS}.\n */\n timeoutMs?: number;\n /**\n * Opt the rendered overlay into rich link handling (OSC 8 hyperlinks +\n * clipboard copy for prompt URLs). Set per program; defaults to false.\n * Propagated onto every {@link PendingQuestion} this bridge creates.\n */\n richLinks?: boolean;\n}\n\n/** Sentinel returned for unanswered fields on cancellation or timeout. */\nexport const CANCELLED_SENTINEL = '__cancelled__';\n\n/** Default per-question timeout (5 minutes). */\nexport const DEFAULT_ASK_TIMEOUT_MS = 5 * 60 * 1000;\n\nfunction buildCancelledAnswers(questions: AskQuestion[]): AskAnswers {\n const out: AskAnswers = {};\n for (const q of questions) {\n out[q.id] = CANCELLED_SENTINEL;\n }\n return out;\n}\n\nfunction isFullyCancelled(answers: AskAnswers): boolean {\n const values = Object.values(answers);\n if (values.length === 0) return false;\n return values.every((v) => v === CANCELLED_SENTINEL);\n}\n\nexport function createWizardAskBridge(\n opts: WizardAskBridgeOptions,\n): WizardAskBridge {\n const timeoutMs = opts.timeoutMs ?? DEFAULT_ASK_TIMEOUT_MS;\n\n return {\n async request({ questions }) {\n const pending: PendingQuestion = {\n id: randomUUID(),\n questions,\n source: opts.getSource(),\n richLinks: opts.richLinks ?? false,\n };\n\n const startedAt = Date.now();\n let timer: ReturnType<typeof setTimeout> | undefined;\n\n // Race the user against the timeout. Whichever fires first wins; the\n // other branch is harmless because the overlay still resolves via the\n // store when the user eventually submits (and the answers are simply\n // discarded).\n const timeoutPromise = new Promise<AskAnswers>((resolve) => {\n timer = setTimeout(() => {\n resolve(buildCancelledAnswers(questions));\n }, timeoutMs);\n });\n\n try {\n const answers = await Promise.race([\n opts.showQuestion(pending),\n timeoutPromise,\n ]);\n const durationMs = Date.now() - startedAt;\n\n if (isFullyCancelled(answers)) {\n analytics.wizardCapture('wizard_ask cancelled', {\n source: pending.source,\n question_count: questions.length,\n duration_ms: durationMs,\n timed_out: durationMs >= timeoutMs,\n });\n } else {\n analytics.wizardCapture('wizard_ask answered', {\n source: pending.source,\n question_count: questions.length,\n duration_ms: durationMs,\n });\n }\n\n return answers;\n } finally {\n if (timer) clearTimeout(timer);\n }\n },\n };\n}\n","/**\n * Agent prompt assembly.\n *\n * Three sections, always in this order:\n * 1. Default project prompt — credentials and base context (always included)\n * 2. Custom prompt — additional program-specific instructions (if set)\n * 3. Skill prompt — \"follow SKILL.md\" instructions (if a skill was installed)\n */\n\nimport type { ProgramRun } from './agent-runner.js';\n\n/**\n * Values available to prompt builders after OAuth completes.\n */\nexport interface PromptContext {\n projectId: number;\n projectApiKey: string;\n host: string;\n /** Set when skillId was provided and the skill was installed successfully. */\n skillPath?: string;\n /**\n * Org-level AI consent (`is_ai_data_processing_approved`) read from the\n * `/api/users/@me/` payload at auth time. `null` = unknown (older orgs,\n * or the user fetch failed). Lets prompts pre-resolve consent state so\n * agents only ask the user when it is actually off or unknown.\n */\n orgAiDataProcessingApproved?: boolean | null;\n /**\n * Team product opt-ins from the `/api/projects/:id/` payload at auth\n * time. Project-level truth for \"is this product enabled\" — products\n * can be instrumented from other repos or the snippet, so repo-local\n * evidence must never rule them out. `null` field = unknown.\n */\n teamProductOptIns?: {\n sessionReplay?: boolean | null;\n exceptionAutocapture?: boolean | null;\n surveys?: boolean | null;\n } | null;\n}\n\nfunction defaultProjectPrompt(ctx: PromptContext): string {\n return `You have access to the PostHog MCP server.\n\nProject context:\n- PostHog Project ID: ${ctx.projectId}\n- PostHog public token: ${ctx.projectApiKey}\n- PostHog Host: ${ctx.host}`;\n}\n\nfunction skillPrompt(skillPath: string, reportFile: string): string {\n return `A PostHog skill has been installed at ${skillPath}/. Read ${skillPath}/SKILL.md and follow its instructions completely.\n\nAfter completing the skill workflow, write a brief markdown report to ./${reportFile} summarizing:\n- What changes were made to the project\n- Which files were modified or created\n- Any manual steps the user should take next\n\nImportant: You must read a file immediately before attempting to write it, even if you have previously read it; failure to do so will cause a tool failure.`;\n}\n\n/**\n * Assemble the final agent prompt from the program's run config.\n */\nexport function assemblePrompt(runDef: ProgramRun, ctx: PromptContext): string {\n const parts: string[] = [];\n\n // Always include the default project prompt\n parts.push(defaultProjectPrompt(ctx));\n\n // Additional program-specific instructions\n if (runDef.customPrompt) {\n parts.push(runDef.customPrompt(ctx));\n }\n\n // Skill prompt (appended when a skill was pre-installed)\n if (ctx.skillPath) {\n parts.push(skillPrompt(ctx.skillPath, runDef.reportFile));\n }\n\n return parts.join('\\n\\n');\n}\n","/**\n * Shared error helpers for the runner pipeline.\n */\n\nimport type { InstallSkillResult } from '@lib/wizard-tools';\nimport { wizardAbort, WizardError } from '@utils/wizard-abort';\n\nexport async function abortOnInstallFailure(\n integrationLabel: string,\n result: InstallSkillResult,\n): Promise<void> {\n if (result.kind === 'ok') return;\n\n const message = (() => {\n switch (result.kind) {\n case 'menu-fetch-failed':\n return 'Could not fetch the skill menu from context-mill.\\nCheck your network connection and try again.';\n case 'skill-not-found':\n return `Could not find the \"${result.skillId}\" skill in the context-mill menu.\\nPlease try again later.`;\n case 'download-failed':\n return `Failed to install skill: ${result.message}\\nPlease try again.`;\n }\n })();\n\n await wizardAbort({\n message,\n error: new WizardError(`Skill install failed: ${result.kind}`, {\n integration: integrationLabel,\n error_type: result.kind,\n }),\n });\n}\n","/**\n * The linear pipeline. Single execution path for all non-orchestrator programs,\n * both skill-based (revenue analytics) and framework-based (core integration).\n * The `ProgramRun` controls what varies between them; `programConfig` carries the\n * program-level static metadata (tool allow/disallow lists, etc.).\n */\n\nimport type { WizardSession } from '../../wizard-session';\nimport { OutroKind } from '../../wizard-session';\nimport { getUI } from '../../../ui';\nimport {\n initializeAgent,\n runAgent as executeAgent,\n AgentErrorType,\n AgentSignals,\n} from '../agent-interface';\nimport { restoreClaudeSettings } from '../claude-settings';\nimport { HostResolution } from '@lib/host-resolution';\nimport { logToFile, getLogFilePath } from '../../../utils/debug';\nimport { createBenchmarkPipeline } from '../../middleware/benchmark';\nimport {\n wizardAbort,\n WizardError,\n registerCleanup,\n} from '../../../utils/wizard-abort';\nimport { analytics } from '../../../utils/analytics';\nimport {\n formatScanReport,\n formatYaraAbortMessage,\n writeScanReport,\n} from '../../yara-hooks';\nimport { detectNodePackageManagers } from '../../detection/package-manager';\nimport { installSkillById } from '../../wizard-tools';\nimport { createWizardAskBridge } from '../../wizard-ask-bridge';\nimport type { ProgramConfig } from '../../programs/program-step';\nimport { assemblePrompt } from '../agent-prompt';\nimport type { ProgramRun, BootstrapResult } from './shared/types';\nimport { abortOnInstallFailure } from './shared/errors';\nimport { shouldDisableAsk, sessionToOptions } from './shared/bootstrap';\n\nexport async function runLinearProgram(\n session: WizardSession,\n config: ProgramRun,\n programConfig: ProgramConfig,\n boot: BootstrapResult,\n composed = false,\n): Promise<void> {\n const {\n skillsBaseUrl,\n projectApiKey,\n host,\n accessToken,\n projectId,\n cloudRegion,\n mcpUrl,\n wizardFlags,\n wizardMetadata,\n project,\n } = boot;\n\n // 5. Skill install (if skillId provided)\n let skillPath: string | undefined;\n if (config.skillId) {\n logToFile(`[agent-runner] installing skill ${config.skillId}`);\n const installResult = await installSkillById(\n config.skillId,\n session.installDir,\n skillsBaseUrl,\n );\n if (installResult.kind !== 'ok') {\n await abortOnInstallFailure(config.integrationLabel, installResult);\n return;\n }\n skillPath = installResult.path;\n logToFile(`[agent-runner] skill installed at ${skillPath}`);\n }\n\n // 6. Initialize agent\n const spinner = getUI().spinner();\n\n const restoreSettings = () => restoreClaudeSettings(session.installDir);\n getUI().onEnterScreen('outro', restoreSettings);\n\n if (session.yaraReport) {\n registerCleanup(() => {\n const reportPath = writeScanReport();\n if (reportPath) {\n const summary = formatScanReport();\n getUI().log.info(`YARA scan report: ${reportPath}${summary ?? ''}`);\n }\n });\n }\n\n getUI().startRun();\n\n // wizard_ask is only available in interactive mode. CI/signup users have\n // no way to answer; we omit the bridge so the tool returns an actionable\n // error rather than hanging on a never-resolving prompt.\n const askDisabled = shouldDisableAsk(session);\n const askBridge = askDisabled\n ? undefined\n : createWizardAskBridge({\n getSource: () => session.skillId ?? config.integrationLabel,\n showQuestion: (q) => getUI().requestQuestion(q),\n richLinks: config.richLinks ?? false,\n timeoutMs: config.askTimeoutMs,\n });\n\n getUI().log.step('Initializing Claude agent...');\n const agent = await initializeAgent(\n {\n workingDirectory: session.installDir,\n posthogMcpUrl: mcpUrl,\n posthogApiKey: accessToken,\n posthogApiHost: host,\n additionalMcpServers: config.additionalMcpServers,\n detectPackageManager:\n config.detectPackageManager ?? detectNodePackageManagers,\n skillsBaseUrl,\n wizardFlags,\n wizardMetadata,\n integrationLabel: config.integrationLabel,\n askBridge,\n askMaxQuestions: config.maxQuestions,\n allowedTools: programConfig.allowedTools,\n disallowedTools: programConfig.disallowedTools,\n getPendingQuestion: () => session.pendingQuestion,\n },\n sessionToOptions(session),\n );\n getUI().log.step(`Verbose logs: ${getLogFilePath()}`);\n getUI().log.success(\"Agent initialized. Let's get cooking!\");\n\n logToFile('[agent-runner] agent initialized');\n\n const middleware = session.benchmark\n ? createBenchmarkPipeline(spinner, sessionToOptions(session))\n : undefined;\n\n // 7. Build prompt\n const prompt = assemblePrompt(config, {\n projectId,\n projectApiKey,\n host,\n skillPath,\n orgAiDataProcessingApproved:\n session.apiUser?.organization?.is_ai_data_processing_approved ?? null,\n teamProductOptIns: project\n ? {\n sessionReplay: project.session_recording_opt_in ?? null,\n exceptionAutocapture: project.autocapture_exceptions_opt_in ?? null,\n surveys: project.surveys_opt_in ?? null,\n }\n : null,\n });\n logToFile(`[agent-runner] prompt assembled (${prompt.length} chars)`);\n\n // 8. Run agent\n const agentResult = await executeAgent(\n agent,\n prompt,\n sessionToOptions(session),\n spinner,\n {\n estimatedDurationMinutes: config.estimatedDurationMinutes,\n spinnerMessage: config.spinnerMessage,\n successMessage: config.successMessage,\n errorMessage: config.errorMessage ?? `${config.integrationLabel} failed`,\n additionalFeatureQueue: config.additionalFeatureQueue ?? [],\n abortCases: config.abortCases,\n emitStepEvents: config.trackStepProgress ?? false,\n },\n middleware,\n );\n\n // 9. Error handling (full set from both runners)\n if (agentResult.error === AgentErrorType.ABORT) {\n const reason = agentResult.message ?? '';\n const matched = config.abortCases?.find((c) => c.match.test(reason));\n const outroData: WizardSession['outroData'] = matched\n ? {\n kind: OutroKind.Error,\n message: matched.message,\n body: matched.body,\n docsUrl: matched.docsUrl,\n }\n : {\n kind: OutroKind.Error,\n message: `${config.integrationLabel} aborted`,\n body: reason || 'The agent aborted the program.',\n docsUrl: config.docsUrl,\n };\n analytics.wizardCapture('agent aborted', {\n integration: config.integrationLabel,\n reason,\n matched: matched?.message ?? null,\n });\n await wizardAbort({\n outroData,\n error: new WizardError(`Agent aborted: ${reason}`, {\n integration: config.integrationLabel,\n error_type: AgentErrorType.ABORT,\n reason,\n }),\n });\n }\n\n if (agentResult.error === AgentErrorType.MCP_MISSING) {\n await wizardAbort({\n message:\n 'Could not access the PostHog MCP server\\n\\n' +\n 'The wizard was unable to connect to the PostHog MCP server.\\n' +\n 'This could be due to a network issue or a configuration problem.\\n\\n' +\n `Please try again, or check the documentation:\\n${config.docsUrl}`,\n error: new WizardError('Agent could not access PostHog MCP server', {\n integration: config.integrationLabel,\n error_type: AgentErrorType.MCP_MISSING,\n signal: AgentSignals.ERROR_MCP_MISSING,\n }),\n });\n }\n\n if (agentResult.error === AgentErrorType.RESOURCE_MISSING) {\n await wizardAbort({\n message:\n 'Could not access the setup resource\\n\\n' +\n 'This may indicate a version mismatch or a temporary service issue.\\n\\n' +\n `Please try again, or check the documentation:\\n${config.docsUrl}`,\n error: new WizardError('Agent could not access setup resource', {\n integration: config.integrationLabel,\n error_type: AgentErrorType.RESOURCE_MISSING,\n signal: AgentSignals.ERROR_RESOURCE_MISSING,\n }),\n });\n }\n\n if (agentResult.error === AgentErrorType.YARA_VIOLATION) {\n await wizardAbort({\n message: formatYaraAbortMessage(),\n error: new WizardError('YARA scanner terminated session', {\n integration: config.integrationLabel,\n error_type: AgentErrorType.YARA_VIOLATION,\n }),\n });\n }\n\n if (\n agentResult.error === AgentErrorType.RATE_LIMIT ||\n agentResult.error === AgentErrorType.API_ERROR\n ) {\n analytics.wizardCapture('agent api error', {\n integration: config.integrationLabel,\n error_type: agentResult.error,\n error_message: agentResult.message,\n });\n\n await wizardAbort({\n message: `API Error\\n\\n${\n agentResult.message || 'Unknown error'\n }\\n\\nPlease report this to: wizard@posthog.com`,\n error: new WizardError(`API error: ${agentResult.message}`, {\n integration: config.integrationLabel,\n error_type: agentResult.error,\n }),\n });\n }\n\n // 10. Post-run hooks\n if (config.postRun) {\n await config.postRun(session, {\n accessToken,\n projectApiKey,\n host,\n projectId,\n });\n }\n\n // A composed sub-run (integration inside self-driving) skips the terminal\n // outro + analytics shutdown so the shared client survives the host's run.\n if (composed) return;\n\n // 11. Outro\n // Push outro data through the UI (not via direct `session.outroData = ...`\n // mutation) so the live store gets the value. agent-runner's `session`\n // parameter is captured at runAgent() invocation time, and any `setKey`\n // call between then and here (e.g. setDashboardUrl, setNotebookUrl) forks\n // the session reference — direct mutation then lands on a stale snapshot\n // that the screen never reads. UI.setOutroData() goes through the store\n // and also merges in any post-snapshot URLs from the live session.\n const outroData = config.buildOutroData\n ? config.buildOutroData(\n session,\n { accessToken, projectApiKey, host, projectId },\n cloudRegion,\n )\n : {\n kind: OutroKind.Success,\n message: config.successMessage,\n reportFile: config.reportFile,\n docsUrl: config.docsUrl,\n // TODO: clean up in #755\n continueUrl: session.signup\n ? `${\n HostResolution.fromRegion(cloudRegion, {\n baseUrl: session.baseUrl,\n }).appHost\n }/products?source=wizard`\n : undefined,\n };\n if (outroData) {\n getUI().setOutroData(outroData);\n }\n\n getUI().outro(config.successMessage);\n\n // 12. Analytics shutdown\n await analytics.shutdown('success');\n}\n","/**\n * Unified program runner — dispatcher.\n *\n * Single configurable pipeline for all programs. Each program\n * provides a ProgramRun (via the `run` field on ProgramConfig)\n * that controls:\n * - Whether a skill is pre-installed or discovered at runtime\n * - How the agent prompt is built\n * - What MCP servers and package manager detector to use\n * - What happens after the agent completes\n *\n * The pipeline runs a shared bootstrap (logging, health check, settings, OAuth,\n * flags, MCP url), then forks. The `orchestrator` variant routes to the\n * experimental task-queue runner. Every other variant runs the fixed linear\n * pipeline:\n * [skill install] → agent init → prompt → run → errors → [postRun] → outro\n */\n\nimport type { WizardSession } from '../../wizard-session';\nimport { analytics } from '@utils/analytics';\nimport { isOrchestratorEnabled } from '../agent-interface';\nimport { getUI } from '../../../ui';\nimport { runOrchestrator } from './orchestrator/orchestrator-runner';\nimport type { ProgramConfig } from '../../programs/program-step';\nimport { WizardVariant } from './shared/types';\nimport type { ProgramRun, BootstrapResult } from './shared/types';\nimport { bootstrapProgram } from './shared/bootstrap';\nimport { runLinearProgram } from './linear';\nimport { flushScanReport } from '../../yara-hooks';\nimport { registerCleanup } from '../../../utils/wizard-abort';\n\nexport type {\n ProgramRun,\n BootstrapResult,\n AbortCase,\n PromptContext,\n Credentials,\n} from './shared/types';\nexport { shouldDisableAsk } from './shared/bootstrap';\n\n/**\n * Resolve a ProgramConfig's agent run definition and execute the pipeline.\n * Entry point for bin.ts — handles buildRunConfig, bootstrap, and (future) run field.\n */\nexport async function runAgent(\n programConfig: ProgramConfig,\n session: WizardSession,\n options: { composed?: boolean } = {},\n): Promise<void> {\n if (!programConfig.run) {\n throw new Error(`Program \"${programConfig.id}\" has no run configuration.`);\n }\n\n const runDef =\n typeof programConfig.run === 'function'\n ? await programConfig.run(session)\n : programConfig.run;\n\n await runProgram(session, runDef, programConfig, options);\n}\n\n/**\n * Run a program's agent pipeline.\n *\n * Runs the shared bootstrap, then forks on the `wizard-orchestrator` flag.\n * When enabled the run routes to the experimental task-queue runner; otherwise\n * it runs the linear pipeline.\n */\nexport async function runProgram(\n session: WizardSession,\n config: ProgramRun,\n programConfig: ProgramConfig,\n options: { composed?: boolean } = {},\n): Promise<void> {\n const boot = await bootstrapProgram(session, config, programConfig);\n\n // Flush the warlock scan report once, at this single seam, on every\n // termination path and for every harness (linear, orchestrator, or future):\n // - registerCleanup covers the abort/cancel path (wizardAbort runs the\n // registered cleanups; the success path never calls them)\n // - the finally covers normal completion and any direct throw that unwinds\n // through here\n // flushScanReport is idempotent (it zeroes scan state), so the overlap is a\n // harmless no-op. No harness has to know reporting exists.\n registerCleanup(() => flushScanReport(session));\n try {\n if (isOrchestratorEnabled(boot.wizardFlags)) {\n getUI().log.info('Task-queue orchestrator enabled.');\n stampVariant(boot, WizardVariant.ORCHESTRATOR);\n // composed-run guard is linear-only; the orchestrator is experimental.\n return await runOrchestrator(session, programConfig, boot);\n }\n\n stampVariant(boot, WizardVariant.BASE);\n return await runLinearProgram(\n session,\n config,\n programConfig,\n boot,\n options.composed ?? false,\n );\n } finally {\n flushScanReport(session);\n }\n}\n\n/**\n * Record which runner arm ran. Tags every wizard event and every gateway trace\n * with the variant, so runs segment by arm (base vs orchestrator, later pi).\n */\nfunction stampVariant(boot: BootstrapResult, variant: WizardVariant): void {\n analytics.setTag('variant', variant);\n boot.wizardMetadata.VARIANT = variant;\n}\n","/**\n * Re-export shim. The runner has been split into agent/runner/.\n * Import from there directly; this shim keeps existing importers working.\n */\n\nexport {\n runAgent,\n runProgram,\n shouldDisableAsk,\n type ProgramRun,\n type BootstrapResult,\n type AbortCase,\n type PromptContext,\n type Credentials,\n} from './runner/index';\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"setup-utils-BxdW2R0r.js","names":["fs","path","join","fs"],"sources":["../src/utils/package-manager.ts","../src/lib/oauth/program-scopes.ts","../src/utils/oauth.ts","../src/utils/project-resolution.ts","../src/utils/semver.ts","../src/utils/setup-utils.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport { withProgress } from '../telemetry';\nimport { getPackageDotJson, updatePackageDotJson } from './setup-utils';\nimport type { PackageJson } from './package-json';\nimport { analytics } from './analytics';\nimport type { WizardRunOptions } from './types';\n\ntype InstallDirOpt = Pick<WizardRunOptions, 'installDir'>;\n\nexport interface PackageManager {\n name: string;\n label: string;\n installCommand: string;\n buildCommand: string;\n /** Command the manager uses to execute a `package.json` script. */\n runScriptCommand: string;\n flags: string;\n detect: (opts: InstallDirOpt) => boolean;\n addOverride: (\n pkgName: string,\n pkgVersion: string,\n opts: InstallDirOpt,\n ) => Promise<void>;\n}\n\nfunction hasLockfile(installDir: string, file: string): boolean {\n return fs.existsSync(path.join(installDir, file));\n}\n\nfunction lockfileHeaderContains(\n installDir: string,\n file: string,\n needle: string,\n): boolean {\n try {\n const head = fs\n .readFileSync(path.join(installDir, file), 'utf-8')\n .slice(0, 500);\n return head.includes(needle);\n } catch {\n return false;\n }\n}\n\ntype OverrideSlot = 'npm' | 'yarn' | 'pnpm';\n\nasync function writeOverride(\n slot: OverrideSlot,\n pkgName: string,\n pkgVersion: string,\n { installDir }: InstallDirOpt,\n): Promise<void> {\n const pkg = await getPackageDotJson({ installDir });\n let next: PackageJson;\n if (slot === 'yarn') {\n next = {\n ...pkg,\n resolutions: { ...(pkg.resolutions ?? {}), [pkgName]: pkgVersion },\n };\n } else if (slot === 'pnpm') {\n next = {\n ...pkg,\n pnpm: {\n ...(pkg.pnpm ?? {}),\n overrides: { ...(pkg.pnpm?.overrides ?? {}), [pkgName]: pkgVersion },\n },\n };\n } else {\n next = {\n ...pkg,\n overrides: { ...(pkg.overrides ?? {}), [pkgName]: pkgVersion },\n };\n }\n await updatePackageDotJson(next, { installDir });\n}\n\nexport const BUN: PackageManager = {\n name: 'bun',\n label: 'Bun',\n installCommand: 'bun add',\n buildCommand: 'bun run build',\n runScriptCommand: 'bun run',\n flags: '',\n detect: ({ installDir }) =>\n hasLockfile(installDir, 'bun.lockb') || hasLockfile(installDir, 'bun.lock'),\n addOverride: (pkgName, pkgVersion, opts) =>\n writeOverride('npm', pkgName, pkgVersion, opts),\n};\n\nexport const YARN_V1: PackageManager = {\n name: 'yarn',\n label: 'Yarn V1',\n installCommand: 'yarn add',\n buildCommand: 'yarn build',\n runScriptCommand: 'yarn',\n flags: '--ignore-workspace-root-check',\n detect: ({ installDir }) =>\n lockfileHeaderContains(installDir, 'yarn.lock', 'yarn lockfile v1'),\n addOverride: (pkgName, pkgVersion, opts) =>\n writeOverride('yarn', pkgName, pkgVersion, opts),\n};\n\n/** YARN V2/3/4 */\nexport const YARN_V2: PackageManager = {\n name: 'yarn',\n label: 'Yarn V2/3/4',\n installCommand: 'yarn add',\n buildCommand: 'yarn build',\n runScriptCommand: 'yarn',\n flags: '',\n detect: ({ installDir }) =>\n lockfileHeaderContains(installDir, 'yarn.lock', '__metadata'),\n addOverride: (pkgName, pkgVersion, opts) =>\n writeOverride('yarn', pkgName, pkgVersion, opts),\n};\n\nexport const PNPM: PackageManager = {\n name: 'pnpm',\n label: 'pnpm',\n installCommand: 'pnpm add',\n buildCommand: 'pnpm build',\n runScriptCommand: 'pnpm',\n flags: '--ignore-workspace-root-check',\n detect: ({ installDir }) => hasLockfile(installDir, 'pnpm-lock.yaml'),\n addOverride: (pkgName, pkgVersion, opts) =>\n writeOverride('pnpm', pkgName, pkgVersion, opts),\n};\n\nexport const NPM: PackageManager = {\n name: 'npm',\n label: 'npm',\n installCommand: 'npm add',\n buildCommand: 'npm run build',\n runScriptCommand: 'npm run',\n flags: '',\n detect: ({ installDir }) => hasLockfile(installDir, 'package-lock.json'),\n addOverride: (pkgName, pkgVersion, opts) =>\n writeOverride('npm', pkgName, pkgVersion, opts),\n};\n\n// Expo is selected by upstream config (app.json / app.config.*) rather than\n// a lockfile, so its detect always returns false here.\nexport const EXPO: PackageManager = {\n name: 'expo',\n label: 'Expo',\n installCommand: 'npx expo install',\n buildCommand: 'npx expo build',\n runScriptCommand: 'npx expo run',\n flags: '',\n detect: () => false,\n addOverride: (pkgName, pkgVersion, opts) =>\n writeOverride('npm', pkgName, pkgVersion, opts),\n};\n\nexport const packageManagers: PackageManager[] = [\n BUN,\n YARN_V1,\n YARN_V2,\n PNPM,\n NPM,\n EXPO,\n];\n\nexport function detectAllPackageManagers({\n installDir,\n}: InstallDirOpt): PackageManager[] {\n return withProgress('detect-package-manager', () => {\n const matches = packageManagers.filter((pm) => pm.detect({ installDir }));\n if (matches.length === 0) {\n analytics.setTag('package-manager', 'not-detected');\n }\n return matches;\n });\n}\n","/**\n * OAuth scope resolver — every program starts from the shared\n * `WIZARD_OAUTH_SCOPES` base set and a program can layer additional\n * scopes on top via `PROGRAM_SCOPE_ADDITIONS`.\n *\n * final scope set = WIZARD_OAUTH_SCOPES ∪ programAdditions\n *\n * Additions are merged in declaration order and deduped, so a program\n * never accidentally weakens the base set — only widens it. Programs\n * not listed in `PROGRAM_SCOPE_ADDITIONS` request the unchanged\n * base set, exactly like before.\n *\n * Current additions: `McpTutorial` layers read-only on every product\n * surface (feature flags, experiments, surveys, replays, errors, web\n * analytics, LLM analytics, cohorts, persons) plus read/write on\n * annotations; `AgentSkill` adds feature-flag read/write; the default\n * `PostHogIntegration` run and the standalone `slack` flow add\n * `integration:read` for the Connect-Slack step. Persistence writes (dashboard:write,\n * insight:write, notebook:write, query:read) come for free from the\n * base set, so the tutorial's \"save as insight / pin to dashboard /\n * add to notebook\" follow-ups keep working.\n *\n * Add a new program override by extending `PROGRAM_SCOPE_ADDITIONS`\n * below — no other call-site changes required as long as the program's\n * `programId` is threaded into `getOrAskForProjectData`.\n */\n\n// IMPORTANT: type-only import. A value import would create a circular\n// dependency (setup-utils → program-scopes → program-registry →\n// posthog-integration → ... → setup-utils), and `Program` would be\n// read as `undefined` at module init. Keep this type-only and reference\n// program IDs by their string-literal value below — TypeScript still\n// catches renames via the `Partial<Record<ProgramId, ...>>` keying.\nimport type { ProgramId } from '@lib/programs/program-registry';\nimport { WIZARD_OAUTH_SCOPES } from '@lib/constants';\n\n/**\n * Extra scopes the MCP tutorial needs on top of `WIZARD_OAUTH_SCOPES`.\n *\n * Every scope requested here must stay within the wizard OAuth app's\n * ceiling on the PostHog side (`OAuthApplication.scopes`) — the full\n * list lives in the README under \"OAuth app scope ceiling\". The\n * tutorial's prompts and follow-ups touch most of the read surface,\n * plus annotation write for the \"PostHog wizard install\" verify-prompt.\n *\n * Already in the base `WIZARD_OAUTH_SCOPES` (and therefore not\n * repeated here):\n * • user:read, project:read, llm_gateway:read — auth + gateway\n * • query:read — HogQL\n * • dashboard:write, insight:write, notebook:write — Phase-5 persist\n *\n * Deliberately omitted (writes on read-only product surfaces):\n * • feature_flag:write, experiment:write, survey:write,\n * cohort:write, session_recording:write, error_tracking:write,\n * alert:write, subscription:write\n */\nexport const MCP_TUTORIAL_SCOPE_ADDITIONS = [\n // Explicit reads on the persistence surfaces. `*:write` usually\n // implies read on PostHog, but the consent flow grants exactly the\n // strings requested — explicit reads avoid a 403 when the agent\n // lists existing dashboards/insights/notebooks before saving.\n 'dashboard:read',\n 'insight:read',\n 'notebook:read',\n\n // Read on every product surface the tutorial demos.\n 'feature_flag:read',\n 'experiment:read',\n 'experiment_saved_metric:read',\n 'survey:read',\n 'session_recording:read',\n 'error_tracking:read',\n 'web_analytics:read',\n 'llm_analytics:read',\n 'cohort:read',\n 'person:read',\n\n // Annotation read + write — the verify prompt's \"annotate today\"\n // is the only mutation the tutorial performs outside the\n // dashboard/insight/notebook persistence triplet.\n 'annotation:read',\n 'annotation:write',\n\n // Metadata / exploration reads — for \"break down by user property\",\n // \"did that change land alongside a deploy\", autocapture actions,\n // etc. Otherwise the agent 403s on the supporting catalog calls\n // even though the parent query has `query:read`.\n 'activity_log:read',\n 'property_definition:read',\n 'event_definition:read',\n 'action:read',\n\n // Data warehouse reads — for the data-role cross-sells that join\n // event data with Stripe / Salesforce / S3.\n 'warehouse_table:read',\n 'warehouse_view:read',\n\n // Inspection-only — we don't write alerts or subscriptions, but the\n // model might want to read existing ones (e.g. \"is there already an\n // alert on this metric?\").\n 'alert:read',\n 'subscription:read',\n 'integration:read',\n] as const;\n\n/**\n * Extra scopes the agent-skill program needs on top of `WIZARD_OAUTH_SCOPES`.\n *\n * Skills under this program (e.g. `creating-product-tours`) create feature\n * flags during the install flow. PostHog's consent grants exactly the scope\n * strings requested — `:write` does not imply `:read` — so listing existing\n * flags to avoid key collisions needs `feature_flag:read` explicitly.\n * `property_definition:read` lets the agent discover person properties when\n * building flag rollout filters instead of having to ask the user verbatim.\n */\nexport const AGENT_SKILL_SCOPE_ADDITIONS = [\n 'feature_flag:read',\n 'feature_flag:write',\n 'property_definition:read',\n] as const;\n\n/**\n * Extra scopes the self-driving program needs on top of\n * `WIZARD_OAUTH_SCOPES`. All consumed by the PostHog MCP tools the\n * agent drives during the run:\n * • task:read / task:write — the signal source config API\n * (`inbox-source-configs-*`) is permissioned under the generic\n * `task` scope object, NOT a signals-specific one. Unrelated to\n * the Tasks product.\n * • integration:read — `integrations-list`, to check whether the\n * team already has a GitHub integration and to verify the connect\n * flow completed.\n * • signal_scout:read / signal_scout:write — list, sync, and tune\n * the Signals scout troop (`signals-scout-config-*`).\n * • session_recording:read / survey:read / error_tracking:read —\n * server-side product-usage probes (`query-session-recordings-list`,\n * `survey-list`, `error-issue-list`). Product usage is a\n * project-level fact (often instrumented in another repo or via\n * the snippet), so the agent asks the server instead of inferring\n * only from the local setup report. All three are read-only and\n * already in the wizard OAuth app's production scope ceiling (the\n * mcp-tutorial program requests them).\n * • external_data_source:read / external_data_source:write — the\n * connected-tools step creates the GitHub Issues / Linear warehouse\n * sources directly (`external-data-sources-create`) and verifies\n * what's actually connected (`external-data-sources-list`) instead\n * of taking the user's word for it.\n * • llm_skill:read / llm_skill:write — the custom-scouts step\n * (skill step 7b): read the seeded `authoring-signals-scouts`\n * guide and canonical scout bodies (`llma-skill-get` /\n * `llma-skill-file-get`) and author the user-approved custom\n * `signals-scout-*` skills (`llma-skill-create`). Canonical scout\n * bodies are never edited.\n */\nexport const SELF_DRIVING_SCOPE_ADDITIONS = [\n 'task:read',\n 'task:write',\n 'integration:read',\n 'signal_scout:read',\n 'signal_scout:write',\n 'session_recording:read',\n 'survey:read',\n 'error_tracking:read',\n 'external_data_source:read',\n 'external_data_source:write',\n 'llm_skill:read',\n 'llm_skill:write',\n] as const;\n\n/**\n * Extra scopes the warehouse-source program needs on top of\n * `WIZARD_OAUTH_SCOPES`. The agent creates data warehouse sources directly\n * (`external-data-sources-create`) and lists what's connected\n * (`external-data-sources-list`) to verify the result. Both are already within\n * the wizard OAuth app's scope ceiling — the self-driving program requests the\n * same pair.\n */\nexport const WAREHOUSE_SOURCE_SCOPE_ADDITIONS = [\n 'external_data_source:read',\n 'external_data_source:write',\n] as const;\n\n/**\n * Extra scope the Connect-Slack step needs on top of `WIZARD_OAUTH_SCOPES`.\n *\n * The step polls `/api/projects/:id/integrations/` (`fetchSlackConnected`)\n * to render the already-connected variant and to flip live once the user\n * completes the Slack OAuth step in the browser. Without `integration:read`\n * the first poll 403s, the screen stops polling, and an already-connected\n * project is nagged with the connect nudge. Used by the default integration\n * run (the step ends the run) and by the standalone `wizard slack` flow\n * (the step is the whole program).\n */\nexport const CONNECT_SLACK_SCOPE_ADDITIONS = ['integration:read'] as const;\n\n/**\n * Per-program scope additions, layered on top of `WIZARD_OAUTH_SCOPES`.\n *\n * Programs not listed here request the unchanged base set. Use this\n * map only for programs that need *more* than the base — never for\n * narrowing, since narrowing risks breaking shared infrastructure\n * (e.g. dropping `llm_gateway:read` would 401 every agent call).\n *\n * Keyed by `ProgramId` so TypeScript catches stale entries when a\n * program is renamed or removed.\n */\nconst PROGRAM_SCOPE_ADDITIONS: Partial<Record<ProgramId, readonly string[]>> = {\n // String literal (not `Program.McpTutorial`) to avoid a runtime cycle\n // with `program-registry.ts`. The `Partial<Record<ProgramId, ...>>`\n // key constraint catches renames at compile time — if `mcpTutorialConfig.id`\n // ever changes, this line will fail to type-check.\n 'mcp-tutorial': MCP_TUTORIAL_SCOPE_ADDITIONS,\n 'agent-skill': AGENT_SKILL_SCOPE_ADDITIONS,\n 'self-driving': SELF_DRIVING_SCOPE_ADDITIONS,\n 'warehouse-source': WAREHOUSE_SOURCE_SCOPE_ADDITIONS,\n 'posthog-integration': CONNECT_SLACK_SCOPE_ADDITIONS,\n slack: CONNECT_SLACK_SCOPE_ADDITIONS,\n};\n\n/**\n * Resolve the OAuth scope list to request for a given program. Returns\n * `WIZARD_OAUTH_SCOPES` for programs without an addition entry; for\n * programs that do have one, returns the union of base + additions\n * with duplicates dropped (declaration order preserved, base first).\n *\n * `null` / `undefined` programId falls through to the default — same\n * behavior as the historical hardcoded `WIZARD_OAUTH_SCOPES` reference\n * in `askForWizardLogin`, so call sites that haven't been updated to\n * pass a programId continue to work unchanged.\n */\nexport function getOAuthScopesForProgram(\n programId: ProgramId | null | undefined,\n): readonly string[] {\n const additions = (programId && PROGRAM_SCOPE_ADDITIONS[programId]) || [];\n if (additions.length === 0) {\n return WIZARD_OAUTH_SCOPES;\n }\n // Dedupe while preserving order; base scopes appear first so the\n // consent screen shows them in their familiar slot.\n const seen = new Set<string>();\n const merged: string[] = [];\n for (const s of [...WIZARD_OAUTH_SCOPES, ...additions]) {\n if (seen.has(s)) continue;\n seen.add(s);\n merged.push(s);\n }\n return merged;\n}\n","import * as crypto from 'node:crypto';\nimport * as http from 'node:http';\nimport { execSync } from 'node:child_process';\nimport axios from 'axios';\nimport { logToFile } from './debug';\nimport { z } from 'zod';\nimport { getUI } from '@ui';\nimport {\n ISSUES_URL,\n OAUTH_PORTS,\n OAUTH_TIMEOUT_MS,\n POSTHOG_DEV_CLIENT_ID,\n POSTHOG_PROXY_CLIENT_ID,\n WIZARD_USER_AGENT,\n} from '@lib/constants';\nimport { getOAuthUrl, resolveBaseUrl } from './urls';\nimport { abort } from './setup-utils';\nimport { openTrackedLink, withUtm } from './links';\nimport { analytics } from './analytics';\n\nconst OAUTH_CALLBACK_STYLES = `\n <style>\n * {\n font-family: monospace;\n background-color: #1b0a00;\n color: #F7A502;\n font-weight: medium;\n font-size: 24px;\n margin: .25rem;\n }\n\n .blink {\n animation: blink-animation 1s steps(2, start) infinite;\n }\n\n @keyframes blink-animation {\n to {\n opacity: 0;\n }\n }\n </style>\n`;\n\nconst OAuthTokenResponseSchema = z.object({\n access_token: z.string(),\n expires_in: z.number(),\n token_type: z.string(),\n scope: z.string(),\n refresh_token: z.string().optional(),\n scoped_teams: z.array(z.number()).optional(),\n scoped_organizations: z.array(z.string()).optional(),\n});\n\nexport type OAuthTokenResponse = z.infer<typeof OAuthTokenResponseSchema>;\n\n// Stable marker for the authorization-flow timeout. Detection keys off the exact\n// message rather than a loose substring — `.includes('timeout')` never matched\n// `'timed out'`, which silently routed timeouts to the generic failure message.\nconst AUTHORIZATION_TIMEOUT_MESSAGE = 'Authorization timed out';\n\nexport function isAuthorizationTimeout(error: Error): boolean {\n return error.message === AUTHORIZATION_TIMEOUT_MESSAGE;\n}\n\ninterface OAuthConfig {\n scopes: string[];\n signup?: boolean;\n /** Project to pre-select on the consent screen (the `--project-id` flag). */\n projectId?: number;\n /**\n * Explicit base URL override (`--base-url`, from `session.baseUrl`). Pins the\n * OAuth server and selects the matching client ID.\n */\n baseUrl?: string;\n}\n\n/**\n * OAuth client ID for the current target. A pinned base URL (`--base-url`, or\n * IS_DEV's implicit localhost) means we're talking to a dev-seeded stack, which\n * registers the dev client; prod uses the proxy client.\n *\n * TODO: this assumes any pinned base URL is a dev-seeded instance that\n * registers POSTHOG_DEV_CLIENT_ID. If we ever point `--base-url` at a non-dev\n * instance with its own OAuth app, make the client ID configurable (e.g. a\n * `--oauth-client-id` flag) instead of always falling back to the dev client.\n */\nfunction getOAuthClientId(baseUrl?: string): string {\n return resolveBaseUrl(baseUrl)\n ? POSTHOG_DEV_CLIENT_ID\n : POSTHOG_PROXY_CLIENT_ID;\n}\n\nfunction getLocalOAuthOrigin(port: number): string {\n return `http://localhost:${port}`;\n}\n\nfunction getCallbackUrl(port: number): string {\n return `${getLocalOAuthOrigin(port)}/callback`;\n}\n\nfunction getLocalLoginUrl(port: number): string {\n return `${getLocalOAuthOrigin(port)}/authorize`;\n}\n\nfunction getLocalSignupUrl(port: number): string {\n return `${getLocalLoginUrl(port)}?signup=true`;\n}\n\n/**\n * Extract an OAuth authorization code from raw user input. Accepts either the\n * bare code, the full callback URL the browser was redirected to\n * (`http://localhost:8239/callback?code=abc123&...`), or just the query\n * string. Returns null when no code can be found.\n *\n * This backs the manual-entry fallback: in headless/remote environments the\n * browser can't reach the wizard's local callback server, so the user copies\n * the failed callback URL (or the code from it) back into the terminal.\n */\nexport function extractOAuthCode(input: string): string | null {\n const trimmed = input.trim();\n if (!trimmed) return null;\n\n // Full URL — pull the `code` query param.\n let looksLikeUrl = false;\n try {\n const url = new URL(trimmed);\n looksLikeUrl = true;\n const code = url.searchParams.get('code');\n if (code) return code;\n } catch {\n // Not a parseable URL — fall through to the looser checks below.\n }\n\n // A pasted query string or `code=...` fragment.\n const match = trimmed.match(/[?&]?code=([^&\\s]+)/);\n if (match) return decodeURIComponent(match[1]);\n\n // A URL with no code is invalid — don't mistake the whole URL for a code.\n if (looksLikeUrl) return null;\n\n // Otherwise treat the whole input as the bare code (no embedded whitespace).\n if (!/\\s/.test(trimmed)) return trimmed;\n\n return null;\n}\n\nfunction generateCodeVerifier(): string {\n return crypto.randomBytes(32).toString('base64url');\n}\n\nfunction generateCodeChallenge(verifier: string): string {\n return crypto.createHash('sha256').update(verifier).digest('base64url');\n}\n\nasync function startCallbackServer(\n authUrl: string,\n signupUrl: string,\n port: number,\n): Promise<{\n port: number;\n server: http.Server;\n waitForCallback: () => Promise<string>;\n}> {\n return new Promise((resolve, reject) => {\n let callbackResolve: (code: string) => void;\n let callbackReject: (error: Error) => void;\n\n const waitForCallback = () =>\n new Promise<string>((res, rej) => {\n callbackResolve = res;\n callbackReject = rej;\n });\n\n const server = http.createServer((req, res) => {\n if (!req.url) {\n res.writeHead(400);\n res.end();\n return;\n }\n const url = new URL(req.url, getLocalOAuthOrigin(port));\n\n if (url.pathname === '/authorize') {\n const isSignup = url.searchParams.get('signup') === 'true';\n const redirectUrl = isSignup ? signupUrl : authUrl;\n res.writeHead(302, { Location: redirectUrl });\n res.end();\n return;\n }\n\n const code = url.searchParams.get('code');\n const error = url.searchParams.get('error');\n\n if (error) {\n const isAccessDenied = error === 'access_denied';\n const safeError = error.replace(/[^\\x20-\\x7e]/g, '').slice(0, 200);\n logToFile(`[oauth] callback received with error: ${safeError}`);\n res.writeHead(isAccessDenied ? 200 : 400, {\n 'Content-Type': 'text/html; charset=utf-8',\n });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard - Authorization ${\n isAccessDenied ? 'cancelled' : 'failed'\n }</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>${\n isAccessDenied\n ? 'Authorization cancelled.'\n : `Authorization failed.`\n }</p>\n <p>Return to your terminal. This window will close automatically.</p>\n <script>window.close();</script>\n </body>\n </html>\n `);\n callbackReject(new Error(`OAuth error: ${error}`));\n return;\n }\n\n if (code) {\n logToFile('[oauth] callback received with authorization code');\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard is ready</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>PostHog login complete!</p>\n <p>Return to your terminal: the wizard is hard at work on your project<span class=\"blink\">█</span></p>\n <script>window.close();</script>\n </body>\n </html>\n `);\n callbackResolve(code);\n } else {\n res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });\n res.end(`\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>PostHog wizard - Invalid request</title>\n ${OAUTH_CALLBACK_STYLES}\n </head>\n <body>\n <p>Invalid request - no authorization code received.</p>\n <p>You can close this window.</p>\n </body>\n </html>\n `);\n }\n });\n\n server.listen(port, () => {\n resolve({ port, server, waitForCallback });\n });\n\n server.on('error', reject);\n });\n}\n\nfunction getPortProcessInfo(port: number): {\n command: string;\n pid: string;\n port: number;\n user: string;\n} {\n try {\n const output = execSync(`lsof -i :${port} -sTCP:LISTEN 2>/dev/null`, {\n encoding: 'utf-8',\n timeout: 3000,\n }).trim();\n const lines = output.split('\\n');\n // First line is header, second is the process\n if (lines.length < 2)\n return { command: 'unknown', pid: 'unknown', port, user: 'unknown' };\n const fields = lines[1].split(/\\s+/);\n // lsof columns: COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME\n const command = fields[0] ?? 'unknown';\n const pid = fields[1] ?? 'unknown';\n const user = fields[2] ?? 'unknown';\n return { command, pid, port, user };\n } catch {\n return { command: 'unknown', pid: 'unknown', port, user: 'unknown' };\n }\n}\n\nfunction isPortInUseError(error: unknown): boolean {\n return (\n error instanceof Error &&\n 'code' in error &&\n (error as NodeJS.ErrnoException).code === 'EADDRINUSE'\n );\n}\n\nasync function exchangeCodeForToken(\n code: string,\n codeVerifier: string,\n callbackUrl: string,\n baseUrl?: string,\n): Promise<OAuthTokenResponse> {\n const clientId = getOAuthClientId(baseUrl);\n const oauthUrl = getOAuthUrl(baseUrl);\n\n logToFile(`[oauth] exchanging code for token at ${oauthUrl}/oauth/token`);\n let response;\n try {\n response = await axios.post(\n `${oauthUrl}/oauth/token`,\n {\n grant_type: 'authorization_code',\n code,\n redirect_uri: callbackUrl,\n client_id: clientId,\n code_verifier: codeVerifier,\n },\n {\n headers: {\n 'Content-Type': 'application/json',\n 'User-Agent': WIZARD_USER_AGENT,\n },\n },\n );\n } catch (e) {\n const status = axios.isAxiosError(e) ? e.response?.status : undefined;\n logToFile(\n `[oauth] token exchange failed${status ? ` (HTTP ${status})` : ''}:`,\n e instanceof Error ? e.message : e,\n );\n throw e;\n }\n\n const token = OAuthTokenResponseSchema.parse(response.data);\n logToFile(\n `[oauth] token exchange succeeded, granted scopes: ${token.scope}` +\n `${\n token.scoped_teams\n ? `, scoped_teams: [${token.scoped_teams.join(', ')}]`\n : ''\n }` +\n `${\n token.scoped_organizations\n ? `, scoped_organizations: ${token.scoped_organizations.length}`\n : ''\n }`,\n );\n return token;\n}\n\nexport async function performOAuthFlow(\n config: OAuthConfig,\n): Promise<OAuthTokenResponse> {\n const clientId = getOAuthClientId(config.baseUrl);\n const oauthUrl = getOAuthUrl(config.baseUrl);\n const codeVerifier = generateCodeVerifier();\n const codeChallenge = generateCodeChallenge(codeVerifier);\n let shouldRetry = false;\n\n logToFile(\n `[oauth] starting flow against ${oauthUrl}, ` +\n `requested scopes: ${config.scopes.join(' ')}`,\n );\n\n do {\n shouldRetry = false;\n let lastProcessInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n } | null = null;\n\n for (const port of OAUTH_PORTS) {\n const callbackUrl = getCallbackUrl(port);\n const authUrl = new URL(`${oauthUrl}/oauth/authorize`);\n authUrl.searchParams.set('client_id', clientId);\n authUrl.searchParams.set('redirect_uri', callbackUrl);\n authUrl.searchParams.set('response_type', 'code');\n authUrl.searchParams.set('code_challenge', codeChallenge);\n authUrl.searchParams.set('code_challenge_method', 'S256');\n authUrl.searchParams.set('scope', config.scopes.join(' '));\n authUrl.searchParams.set('required_access_level', 'project');\n if (config.projectId !== undefined) {\n // Pre-select this project on the consent screen so the user just clicks Authorize.\n authUrl.searchParams.set('team_id', String(config.projectId));\n }\n\n // UTM-tag both kickoff URLs so the journey into the app is\n // attributable to the wizard command that started it.\n const taggedAuthUrl = withUtm(authUrl.toString(), 'oauth-authorize');\n const signupUrl = new URL(\n withUtm(\n `${oauthUrl}/signup?next=${encodeURIComponent(taggedAuthUrl)}`,\n 'oauth-signup',\n ),\n );\n const localSignupUrl = getLocalSignupUrl(port);\n const localLoginUrl = getLocalLoginUrl(port);\n const urlToOpen = config.signup ? localSignupUrl : localLoginUrl;\n\n logToFile(`[oauth] attempting callback server on port ${port}`);\n\n let server: http.Server;\n let waitForCallback: () => Promise<string>;\n try {\n ({ server, waitForCallback } = await startCallbackServer(\n taggedAuthUrl,\n signupUrl.toString(),\n port,\n ));\n } catch (e) {\n if (!isPortInUseError(e)) throw e;\n lastProcessInfo = getPortProcessInfo(port);\n continue;\n }\n\n logToFile('[oauth] callback server ready, showing login URL');\n\n getUI().setLoginUrl(urlToOpen);\n // The localhost proxy above only works on this machine. Surface the\n // direct PostHog authorize URL too, for the manual-paste modal — on a\n // remote/headless box the user opens it from another machine, where\n // localhost:<port> is unreachable.\n getUI().setAuthorizeUrl(\n config.signup ? signupUrl.toString() : taggedAuthUrl,\n );\n\n // The localhost proxy URL stays untagged — the PostHog destination\n // it redirects to carries the UTMs.\n openTrackedLink(urlToOpen, 'oauth', { auto: true, skipUtm: true });\n\n const loginSpinner = getUI().spinner();\n loginSpinner.start('Waiting for authorization...');\n\n try {\n // Race the local callback server against a manually-pasted code. The\n // manual path is the fallback for headless/remote shells where the\n // browser can't reach localhost — the user opens the auth screen's\n // paste modal and submits the callback URL or code by hand.\n const code = await Promise.race([\n waitForCallback(),\n getUI().waitForManualAuthCode(),\n new Promise<never>((_, reject) =>\n setTimeout(\n () => reject(new Error(AUTHORIZATION_TIMEOUT_MESSAGE)),\n OAUTH_TIMEOUT_MS,\n ),\n ),\n ]);\n\n const token = await exchangeCodeForToken(\n code,\n codeVerifier,\n callbackUrl,\n config.baseUrl,\n );\n\n server.close();\n getUI().setLoginUrl(null);\n getUI().setAuthorizeUrl(null);\n loginSpinner.stop('Authorization complete!');\n\n return token;\n } catch (e) {\n const error = e instanceof Error ? e : new Error('Unknown error');\n const timedOut = isAuthorizationTimeout(error);\n\n loginSpinner.stop(\n timedOut ? 'Session timed out.' : 'Authorization failed.',\n );\n server.close();\n\n logToFile('[oauth] flow failed:', error);\n\n if (timedOut) {\n // Overlay bypasses the auth-step gating (which never completes\n // without credentials), so the user sees the failure instead of a\n // spinner that never stops; any key exits.\n getUI().showSessionTimeout();\n } else if (error.message.includes('access_denied')) {\n getUI().log.info(\n `Authorization was cancelled.\\n\\nYou denied access to PostHog. To use the wizard, you need to authorize access to your PostHog account.\\n\\nYou can try again by re-running the wizard.`,\n );\n } else {\n getUI().log.error(\n `Authorization failed:\\n\\n${error.message}\\n\\nIf you think this is a bug in the PostHog wizard, please create an issue:\\n${ISSUES_URL}`,\n );\n }\n\n const oauthErrorCode = error.message.startsWith('OAuth error: ')\n ? error.message.slice('OAuth error: '.length)\n : timedOut\n ? 'timeout'\n : 'unknown';\n\n analytics.captureException(error, {\n step: 'oauth_flow',\n oauth_error_code: oauthErrorCode,\n client_id: clientId,\n requested_scopes: config.scopes.join(' '),\n // Collapse OAuth callback failures of the same kind into one issue\n // instead of fragmenting by each user's install path in the stack trace.\n $exception_fingerprint: `wizard_oauth_${oauthErrorCode}`,\n });\n\n await abort();\n throw error;\n }\n }\n\n if (!lastProcessInfo) {\n throw new Error('No OAuth callback ports configured');\n }\n\n await getUI().showPortConflict(lastProcessInfo);\n shouldRetry = true;\n } while (shouldRetry);\n\n throw new Error('OAuth port retry loop exited unexpectedly');\n}\n","export type GrantedProjectResolution =\n | { ok: true; projectId: number | undefined }\n | { ok: false; requested: number; granted: number };\n\n/**\n * Decide which project to use after OAuth. `--project-id` (when passed) is authoritative,\n * but only when the user granted access to it on the consent screen; a different grant is a\n * mismatch the caller must surface. With no `--project-id` this returns the granted project\n * (`scopedTeams[0]`), preserving the pre-flag behavior for every wizard program (the main\n * integration flow included).\n */\nexport function resolveGrantedProject(\n requestedProjectId: number | undefined,\n scopedTeams: number[] | undefined,\n): GrantedProjectResolution {\n // No --project-id: use whatever the user granted, exactly as before the flag existed.\n if (requestedProjectId === undefined) {\n return { ok: true, projectId: scopedTeams?.[0] };\n }\n // --project-id was among the granted teams: honor it.\n if (scopedTeams?.includes(requestedProjectId)) {\n return { ok: true, projectId: requestedProjectId };\n }\n // --project-id requested but a different project was authorized: mismatch.\n if (scopedTeams && scopedTeams.length > 0) {\n return {\n ok: false,\n requested: requestedProjectId,\n granted: scopedTeams[0],\n };\n }\n // Nothing granted at all — let the caller's \"no project access\" guard handle it.\n return { ok: true, projectId: undefined };\n}\n","import {\n major,\n minVersion,\n satisfies,\n subset,\n valid,\n validRange,\n} from 'semver';\n\n/**\n * Version strings from package.json that are not semver ranges.\n * URLs, git refs, dist-tags, local paths, workspace protocol, npm aliases, etc.\n * These should be rejected early — we can't determine a clear version from them.\n */\nfunction isNonSemverVersion(version: string): boolean {\n const v = version.trim();\n return (\n v === '' ||\n v.startsWith('http://') ||\n v.startsWith('https://') ||\n v.startsWith('git+') ||\n v.startsWith('git://') ||\n v.startsWith('file:') ||\n v.startsWith('npm:') ||\n v.startsWith('workspace:') ||\n v.startsWith('/') ||\n v.includes('/') // user/repo shorthand\n );\n}\n\nexport function versionSatisfiesRange({\n version,\n acceptableVersions,\n canBeLatest,\n}: {\n version: string;\n acceptableVersions: string;\n canBeLatest: boolean;\n}): boolean {\n if (version === 'latest') return canBeLatest;\n if (isNonSemverVersion(version)) return false;\n\n const concrete = valid(version);\n if (concrete !== null) {\n return satisfies(concrete, acceptableVersions);\n }\n\n const userRange = validRange(version);\n if (userRange === null) return false;\n return subset(userRange, acceptableVersions);\n}\n\n/**\n * Creates a version bucket function for analytics.\n * Converts versions like \"1.2.3\" to \"1.x\" for grouping in analytics.\n *\n * @param minMajorVersion - Optional minimum major version threshold.\n * Versions below this will be bucketed as \"<{min}.0.0\"\n *\n * @example\n * const getVersionBucket = createVersionBucket(); // no minimum\n * getVersionBucket(\"1.2.3\") // \"1.x\"\n *\n * const getVersionBucket = createVersionBucket(11);\n * getVersionBucket(\"15.3.0\") // \"15.x\"\n * getVersionBucket(\"10.0.0\") // \"<11.0.0\"\n */\nexport function createVersionBucket(minMajorVersion?: number) {\n return (version: string | undefined): string => {\n if (!version) {\n return 'none';\n }\n\n if (isNonSemverVersion(version)) {\n return 'unknown';\n }\n\n try {\n const minVer = minVersion(version);\n if (!minVer) {\n return 'invalid';\n }\n const majorVersion = major(minVer);\n if (minMajorVersion !== undefined && majorVersion < minMajorVersion) {\n return `<${minMajorVersion}.0.0`;\n }\n return `${majorVersion}.x`;\n } catch {\n return 'unknown';\n }\n };\n}\n","import * as childProcess from 'node:child_process';\nimport * as fs from 'node:fs';\nimport * as os from 'node:os';\nimport { basename, isAbsolute, join, relative } from 'node:path';\nimport { promisify } from 'node:util';\n\nimport { withProgress } from '../telemetry';\nimport { debug } from './debug';\nimport type { PackageJson } from './package-json';\nimport {\n type PackageManager,\n detectAllPackageManagers,\n NPM as npm,\n} from './package-manager';\nimport type { CloudRegion, WizardRunOptions } from './types';\nimport { getDeclaredVersion } from './package-json';\nimport {\n DEFAULT_HOST_URL,\n DUMMY_PROJECT_API_KEY,\n ISSUES_URL,\n} from '@lib/constants';\nimport { getOAuthScopesForProgram } from '@lib/oauth/program-scopes';\nimport type { ProgramId } from '@lib/programs/program-registry';\nimport { analytics } from './analytics';\nimport { getUI } from '@ui';\nimport { HostResolution } from '@lib/host-resolution';\nimport { performOAuthFlow } from './oauth';\nimport { resolveGrantedProject } from './project-resolution';\nimport { provisionNewAccount } from './provisioning';\nimport {\n fetchUserData,\n fetchProjectData,\n type ApiUser,\n type ApiProject,\n} from '@lib/api';\nimport { versionSatisfiesRange } from './semver';\nimport { wizardAbort } from './wizard-abort';\n\ninterface ProjectData {\n projectApiKey: string;\n accessToken: string;\n host: string;\n distinctId: string;\n projectId: number;\n /**\n * Optional `role_at_organization` from `/api/users/@me/`. Drives the\n * role-tailored prompt suggestions on the McpSuggestedPromptsScreen. Null\n * for signup flows (no role picked yet) and older accounts.\n */\n roleAtOrganization?: string | null;\n /**\n * Full user payload from `/api/users/@me/`. Carried through so\n * `getOrAskForProjectData` can forward it to the session as\n * `session.apiUser`. Null when the request failed or the CI key\n * lacked permissions.\n */\n user?: ApiUser | null;\n /**\n * Full project payload from `/api/projects/:id/`. Carries the team's\n * product opt-ins (replay, exception autocapture, surveys) so prompts\n * can state project-level product enablement instead of agents\n * inferring it from repo evidence. Null on signup flows.\n */\n project?: ApiProject | null;\n}\n\nexport interface CliSetupConfig {\n filename: string;\n name: string;\n gitignore: boolean;\n\n likelyAlreadyHasAuthToken(contents: string): boolean;\n tokenContent(authToken: string): string;\n\n likelyAlreadyHasOrgAndProject(contents: string): boolean;\n orgAndProjContent(org: string, project: string): string;\n\n likelyAlreadyHasUrl?(contents: string): boolean;\n urlContent?(url: string): string;\n}\n\nexport interface CliSetupConfigContent {\n authToken: string;\n org?: string;\n project?: string;\n url?: string;\n}\n\n/** @deprecated Use wizardAbort() directly for new code. */\nexport async function abort(message?: string, status?: number): Promise<never> {\n return wizardAbort({ message, exitCode: status });\n}\n\nexport function isInGitRepo(): boolean {\n try {\n childProcess.execSync('git rev-parse --show-toplevel', {\n stdio: 'ignore',\n });\n } catch {\n return false;\n }\n return true;\n}\n\nconst FREEMAIL_DOMAINS = new Set([\n 'gmail.com',\n 'googlemail.com',\n 'hotmail.com',\n 'outlook.com',\n 'yahoo.com',\n 'icloud.com',\n 'me.com',\n 'mail.com',\n 'protonmail.com',\n 'proton.me',\n 'live.com',\n 'aol.com',\n 'yandex.com',\n 'zoho.com',\n 'gmx.com',\n 'fastmail.com',\n]);\n\nfunction parseGitRemote(): { org: string; repo: string } | null {\n try {\n const url = childProcess\n .execSync('git remote get-url origin', {\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n .toString()\n .trim();\n // git@github.com:acme-corp/my-app.git or https://github.com/acme-corp/my-app.git\n const match = url.match(/[/:]([\\w.-]+)\\/([\\w.-]+?)(?:\\.git)?$/);\n if (match) return { org: match[1], repo: match[2] };\n } catch {\n // not in a git repo or no remote\n }\n return null;\n}\n\nexport function detectOrgAndProject(email: string): {\n orgName: string | undefined;\n projectName: string | undefined;\n} {\n const remote = parseGitRemote();\n\n // Project name: git repo name > directory name\n const projectName = remote?.repo || basename(process.cwd()) || undefined;\n\n // Org name: git remote org > email domain (skip freemail)\n let orgName: string | undefined;\n if (remote?.org) {\n orgName = remote.org;\n } else {\n const domain = email.split('@')[1]?.toLowerCase();\n if (domain && !FREEMAIL_DOMAINS.has(domain)) {\n orgName = domain.split('.')[0];\n }\n }\n\n return { orgName, projectName };\n}\n\nexport function getUncommittedOrUntrackedFiles(): string[] {\n let gitStatus: string;\n try {\n gitStatus = childProcess\n .execSync('git status --porcelain=v1', {\n // we only care about stdout\n stdio: ['ignore', 'pipe', 'ignore'],\n })\n .toString();\n } catch {\n return [];\n }\n\n const result: string[] = [];\n for (const rawLine of gitStatus.split(os.EOL)) {\n const line = rawLine.trim();\n if (!line) continue;\n const match = /^\\S+\\s+(\\S+)/.exec(line);\n result.push(`- ${match?.[1]}`);\n }\n return result;\n}\n\nexport async function isReact19Installed({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>): Promise<boolean> {\n try {\n const packageJson = await tryGetPackageJson({ installDir });\n if (!packageJson) return false;\n const reactVersion = getDeclaredVersion('react', packageJson);\n\n if (!reactVersion) {\n return false;\n }\n\n return versionSatisfiesRange({\n version: reactVersion,\n acceptableVersions: '>=19.0.0',\n canBeLatest: true,\n });\n } catch {\n return false;\n }\n}\n\n/**\n * Installs or updates a package with the user's package manager.\n *\n * IMPORTANT: This function modifies the `package.json`! Be sure to re-read\n * it if you make additional modifications to it after calling this function!\n */\nexport async function installPackage({\n packageName,\n alreadyInstalled,\n packageNameDisplayLabel,\n packageManager,\n integration,\n installDir,\n}: {\n packageName: string;\n alreadyInstalled: boolean;\n packageNameDisplayLabel?: string;\n packageManager?: PackageManager;\n integration?: string;\n installDir: string;\n}): Promise<{ packageManager?: PackageManager }> {\n return withProgress('install-package', async () => {\n const sdkInstallSpinner = getUI().spinner();\n\n const pkgManager =\n packageManager || (await getPackageManager({ installDir }));\n\n const isReact19 = await isReact19Installed({ installDir });\n const legacyPeerDepsFlag =\n isReact19 && pkgManager.name === 'npm' ? '--legacy-peer-deps' : '';\n\n sdkInstallSpinner.start(\n `${alreadyInstalled ? 'Updating' : 'Installing'} ${\n packageNameDisplayLabel ?? packageName\n } with ${pkgManager.label}.`,\n );\n\n const execAsync = promisify(childProcess.exec);\n const installCommand =\n `${pkgManager.installCommand} ${packageName} ${pkgManager.flags} ${legacyPeerDepsFlag}`.trim();\n\n try {\n await execAsync(installCommand, { cwd: installDir });\n } catch (e) {\n const { stdout = '', stderr = '' } = (e ?? {}) as {\n stdout?: string;\n stderr?: string;\n };\n fs.writeFileSync(\n join(\n process.cwd(),\n `posthog-wizard-installation-error-${Date.now()}.log`,\n ),\n JSON.stringify({ stdout, stderr }),\n { encoding: 'utf8' },\n );\n sdkInstallSpinner.stop('Installation failed.');\n getUI().log.error(\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n `Encountered the following error during installation:\\n\\n${e}\\n\\nThe wizard has created a \\`posthog-wizard-installation-error-*.log\\` file. If you think this issue is caused by the PostHog wizard, create an issue on GitHub and include the log file's content:\\n${ISSUES_URL}`,\n );\n await abort();\n }\n\n sdkInstallSpinner.stop(\n `${alreadyInstalled ? 'Updated' : 'Installed'} ${\n packageNameDisplayLabel ?? packageName\n } with ${pkgManager.label}.`,\n );\n\n analytics.wizardCapture('package installed', {\n package_name: packageName,\n package_manager: pkgManager.name,\n integration,\n });\n\n return { packageManager: pkgManager };\n });\n}\n\n/**\n * Get package.json or abort the wizard if not found.\n * Only use where package.json is required (e.g., package install, overrides).\n * For detection/version-checks, use tryGetPackageJson() instead.\n */\nexport async function getPackageDotJson({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>): Promise<PackageJson> {\n const pkgPath = join(installDir, 'package.json');\n\n let raw: string;\n try {\n raw = await fs.promises.readFile(pkgPath, 'utf8');\n } catch {\n getUI().log.error(\n 'Could not find package.json. Make sure to run the wizard in the root of your app!',\n );\n await abort();\n return {};\n }\n\n try {\n const parsed = JSON.parse(raw) as PackageJson | null;\n return parsed ?? {};\n } catch {\n getUI().log.error(\n `Unable to parse your package.json. Make sure it has a valid format!`,\n );\n await abort();\n return {};\n }\n}\n\n/**\n * Try to get package.json, returning null if it doesn't exist.\n * Use this for detection purposes where missing package.json is expected (e.g., Python projects).\n */\nexport async function tryGetPackageJson({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>): Promise<PackageJson | null> {\n try {\n const packageJsonFileContents = await fs.promises.readFile(\n join(installDir, 'package.json'),\n 'utf8',\n );\n return JSON.parse(packageJsonFileContents) as PackageJson;\n } catch {\n return null;\n }\n}\n\nexport async function updatePackageDotJson(\n packageDotJson: PackageJson,\n { installDir }: Pick<WizardRunOptions, 'installDir'>,\n): Promise<void> {\n const pkgPath = join(installDir, 'package.json');\n const serialized = JSON.stringify(packageDotJson, null, 2);\n\n try {\n await fs.promises.writeFile(pkgPath, serialized, {\n encoding: 'utf8',\n flag: 'w',\n });\n return;\n } catch {\n getUI().log.error(`Unable to update your package.json.`);\n await abort();\n }\n}\n\n/**\n * Detect and return the package manager. Pure — no prompts.\n * Falls back to first detected or npm if ambiguous.\n */\n// eslint-disable-next-line @typescript-eslint/require-await\nexport async function getPackageManager(\n options: Pick<WizardRunOptions, 'installDir'> & { ci?: boolean },\n): Promise<PackageManager> {\n const detectedPackageManagers = detectAllPackageManagers({\n installDir: options.installDir,\n });\n\n if (detectedPackageManagers.length >= 1) {\n const selected = detectedPackageManagers[0];\n analytics.setTag('package-manager', selected.name);\n return selected;\n }\n\n // No package manager detected — default to npm\n analytics.setTag('package-manager', npm.name);\n return npm;\n}\n\nexport function isUsingTypeScript({\n installDir,\n}: Pick<WizardRunOptions, 'installDir'>): boolean {\n try {\n fs.accessSync(join(installDir, 'tsconfig.json'));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get project data for the wizard via OAuth or CI API key.\n */\nexport async function getOrAskForProjectData(\n _options: Pick<WizardRunOptions, 'signup' | 'ci' | 'apiKey' | 'projectId'> & {\n email?: string;\n region?: CloudRegion;\n /** Explicit base URL override (`--base-url`, from `session.baseUrl`). When\n * set, pins every PostHog origin and bypasses region resolution. */\n baseUrl?: string;\n /** Optional — picks the OAuth scope set via\n * `getOAuthScopesForProgram`. Omitted → default\n * `WIZARD_OAUTH_SCOPES`. Threaded into `askForWizardLogin`. */\n programId?: ProgramId | null;\n },\n): Promise<{\n host: string;\n projectApiKey: string;\n accessToken: string;\n projectId: number;\n cloudRegion: CloudRegion;\n roleAtOrganization: string | null;\n user: ApiUser | null;\n project: ApiProject | null;\n}> {\n // CI mode: bypass OAuth, use personal API key for LLM gateway\n if (_options.ci && _options.apiKey) {\n getUI().log.info('Using provided API key (CI mode - OAuth bypassed)');\n\n const hosts = await HostResolution.fromAccessToken(_options.apiKey, {\n region: _options.region,\n baseUrl: _options.baseUrl,\n });\n\n const cloudRegion = hosts.region;\n const host = hosts.apiHost;\n const cloudUrl = hosts.appHost;\n\n const projectData =\n _options.projectId != null\n ? await fetchProjectDataById(\n _options.apiKey,\n _options.projectId,\n cloudUrl,\n )\n : await fetchProjectDataWithApiKey(_options.apiKey, cloudUrl);\n\n // Best-effort user fetch — CI flows may run with project-scoped keys\n // that 403 on /api/users/@me/, so swallow errors and continue with\n // a null user (and null role).\n let user: ApiUser | null = null;\n let roleAtOrganization: string | null = null;\n try {\n user = await fetchUserData(_options.apiKey, cloudUrl);\n roleAtOrganization = user.role_at_organization ?? null;\n } catch {\n // best-effort\n }\n if (user) analytics.identifyUser(user);\n\n return {\n host,\n projectApiKey: projectData.api_token,\n accessToken: _options.apiKey,\n projectId: projectData.id,\n cloudRegion,\n roleAtOrganization,\n user,\n project: projectData.project,\n };\n }\n\n const {\n host,\n projectApiKey,\n accessToken,\n projectId,\n cloudRegion,\n roleAtOrganization,\n user,\n project,\n } = await withProgress('login', () =>\n askForWizardLogin({\n signup: _options.signup,\n email: _options.email,\n region: _options.region,\n baseUrl: _options.baseUrl,\n programId: _options.programId,\n projectId: _options.projectId,\n }),\n );\n\n if (!projectApiKey) {\n // TODO: clean up in #755\n const cloudUrl = HostResolution.fromRegion(cloudRegion, {\n baseUrl: _options.baseUrl,\n }).appHost;\n getUI().log.error(`Didn't receive a project token. This shouldn't happen :(\n\nPlease let us know if you think this is a bug in the wizard:\n${ISSUES_URL}`);\n\n getUI().log\n .info(`In the meantime, we'll add a dummy project token (\"${DUMMY_PROJECT_API_KEY}\") for you to replace later.\nYou can find your project token here:\n${cloudUrl}/settings/project#variables`);\n }\n\n return {\n accessToken,\n host: host || DEFAULT_HOST_URL,\n projectApiKey: projectApiKey || DUMMY_PROJECT_API_KEY,\n projectId,\n cloudRegion,\n roleAtOrganization: roleAtOrganization ?? null,\n user: user ?? null,\n project: project ?? null,\n };\n}\n\nasync function fetchProjectDataWithApiKey(\n apiKey: string,\n cloudUrl: string,\n): Promise<{ api_token: string; id: number; project: ApiProject }> {\n const userData = await fetchUserData(apiKey, cloudUrl);\n const projectId = userData.team?.id;\n\n if (!projectId) {\n throw new Error(\n 'Could not determine project ID from API key. Please ensure your API key has access to a project in this cloud region.',\n );\n }\n\n const projectData = await fetchProjectData(apiKey, projectId, cloudUrl);\n return {\n api_token: projectData.api_token,\n id: projectId,\n project: projectData,\n };\n}\n\nasync function fetchProjectDataById(\n apiKey: string,\n projectId: number,\n cloudUrl: string,\n): Promise<{ api_token: string; id: number; project: ApiProject }> {\n const projectData = await fetchProjectData(apiKey, projectId, cloudUrl);\n return {\n api_token: projectData.api_token,\n id: projectId,\n project: projectData,\n };\n}\n\nasync function askForWizardLogin(options: {\n signup: boolean;\n email?: string;\n region?: CloudRegion;\n /** Explicit base URL override (`--base-url`); pins every PostHog origin. */\n baseUrl?: string;\n /** Used to pick the right scope set via `getOAuthScopesForProgram`.\n * Omitted → default `WIZARD_OAUTH_SCOPES`. */\n programId?: ProgramId | null;\n /** `--project-id`, if passed. When the user granted access to it on the consent\n * screen we use it directly; otherwise we fall back to the first granted team. */\n projectId?: number;\n}): Promise<ProjectData & { cloudRegion: CloudRegion }> {\n if (options.signup) {\n return askForProvisioningSignup(\n options.email,\n options.region,\n options.baseUrl,\n );\n }\n\n const tokenResponse = await performOAuthFlow({\n scopes: [...getOAuthScopesForProgram(options.programId)],\n signup: false,\n projectId: options.projectId,\n baseUrl: options.baseUrl,\n });\n\n // `--project-id`, when provided, is authoritative — but only if the user actually\n // granted access to it on the consent screen. If they authorized a different\n // project, fail loudly instead of silently capturing into the wrong one. With no\n // `--project-id` this falls back to the granted project, unchanged for every program.\n const resolution = resolveGrantedProject(\n options.projectId,\n tokenResponse.scoped_teams,\n );\n if (!resolution.ok) {\n const error = new Error(\n `You authorized project ${resolution.granted}, but setup is targeting project ${resolution.requested}. Re-run and grant access to project ${resolution.requested} on the authorization screen.`,\n );\n analytics.captureException(error, {\n step: 'wizard_login',\n requested_project_id: resolution.requested,\n granted_project_id: resolution.granted,\n });\n getUI().log.error(error.message);\n await abort();\n }\n\n const projectId = resolution.ok ? resolution.projectId : undefined;\n\n if (projectId === undefined) {\n const error = new Error(\n 'No project access granted. Please authorize with project-level access.',\n );\n analytics.captureException(error, {\n step: 'wizard_login',\n has_scoped_teams: !!tokenResponse.scoped_teams,\n });\n getUI().log.error(error.message);\n await abort();\n }\n\n const hosts = await HostResolution.fromAccessToken(\n tokenResponse.access_token,\n { baseUrl: options.baseUrl },\n );\n const cloudRegion = hosts.region;\n const cloudUrl = hosts.appHost;\n const host = hosts.apiHost;\n\n const projectData = await fetchProjectData(\n tokenResponse.access_token,\n projectId!,\n cloudUrl,\n );\n const userData = await fetchUserData(tokenResponse.access_token, cloudUrl);\n\n const data = {\n accessToken: tokenResponse.access_token,\n projectApiKey: projectData.api_token,\n host,\n distinctId: userData.distinct_id,\n projectId: projectId!,\n cloudRegion,\n roleAtOrganization: userData.role_at_organization ?? null,\n user: userData,\n project: projectData,\n };\n\n getUI().log.success('Login complete.');\n analytics.setTag('opened-wizard-link', true);\n analytics.identifyUser(userData);\n\n return data;\n}\n\nasync function askForProvisioningSignup(\n email?: string,\n region?: CloudRegion,\n baseUrl?: string,\n): Promise<ProjectData & { cloudRegion: CloudRegion }> {\n if (!email || !email.includes('@')) {\n getUI().log.error(\n 'Email is required for signup. Use --email your@email.com with --signup.',\n );\n await abort();\n throw new Error('unreachable');\n }\n\n const spinner = getUI().spinner();\n spinner.start('Creating your PostHog account...');\n\n try {\n const provisionRegion = (region ?? 'us').toUpperCase() as 'US' | 'EU';\n const { orgName, projectName } = detectOrgAndProject(email);\n const result = await provisionNewAccount(email, '', provisionRegion, {\n orgName,\n projectName,\n baseUrl,\n });\n\n spinner.stop('Account created!');\n getUI().log.success('Welcome to PostHog!');\n\n const host = result.host;\n const cloudRegion: CloudRegion = host.includes('eu.') ? 'eu' : 'us';\n\n analytics.setTag('provisioning-signup', true);\n\n return {\n accessToken: result.accessToken,\n projectApiKey: result.projectApiKey,\n host,\n distinctId: email,\n projectId: parseInt(result.projectId, 10) || 0,\n cloudRegion,\n };\n } catch (error) {\n spinner.stop('Account creation failed.');\n const message = error instanceof Error ? error.message : 'Unknown error';\n\n if (message.includes('already associated')) {\n getUI().log.info(\n 'This email already has a PostHog account. Switching to login flow...',\n );\n\n return askForWizardLogin({ signup: false, baseUrl });\n }\n\n getUI().log.error(`Failed to create account: ${message}`);\n analytics.captureException(\n error instanceof Error ? error : new Error(message),\n { step: 'provisioning_signup' },\n );\n await abort();\n throw error;\n }\n}\n\n/**\n * Creates a new config file with the given filepath and codeSnippet.\n */\nexport async function createNewConfigFile(\n filepath: string,\n codeSnippet: string,\n { installDir }: Pick<WizardRunOptions, 'installDir'>,\n moreInformation?: string,\n): Promise<boolean> {\n if (!isAbsolute(filepath)) {\n debug(`createNewConfigFile: filepath is not absolute: ${filepath}`);\n return false;\n }\n\n const prettyFilename = relative(installDir, filepath);\n\n try {\n await fs.promises.writeFile(filepath, codeSnippet);\n\n getUI().log.success(`Added new ${prettyFilename} file.`);\n\n if (moreInformation) {\n getUI().log.info(moreInformation);\n }\n\n return true;\n } catch (e) {\n debug(e);\n getUI().log.warn(\n `Could not create a new ${prettyFilename} file. Please create one manually and follow the instructions below.`,\n );\n }\n\n return false;\n}\n"],"mappings":"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"}