@posthog/wizard 2.76.0 → 2.77.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.
- package/dist/README.md +16 -15
- package/dist/{add-mcp-server-to-clients-Exddicp2.js → add-mcp-server-to-clients-BnRyE4pw.js} +428 -114
- package/dist/add-mcp-server-to-clients-BnRyE4pw.js.map +1 -0
- package/dist/{agent-interface-CZWRgZMc.js → agent-interface-Avtr_5M5.js} +34 -10
- package/dist/agent-interface-Avtr_5M5.js.map +1 -0
- package/dist/{agent-prompt-loader-BobuLDIg.js → agent-prompt-loader-CHixNPgY.js} +23 -7
- package/dist/agent-prompt-loader-CHixNPgY.js.map +1 -0
- package/dist/{agent-runner-C_R1X_UT.js → agent-runner-COOIUJCP.js} +171 -83
- package/dist/agent-runner-COOIUJCP.js.map +1 -0
- package/dist/{analytics-C_RyE8fz.js → analytics-C67F2vee.js} +2 -2
- package/dist/{analytics-C_RyE8fz.js.map → analytics-C67F2vee.js.map} +1 -1
- package/dist/analytics-CJA1uLlk.js +2 -0
- package/dist/{api-k5aGQpIZ.js → api-Dj1yabTj.js} +3 -3
- package/dist/{api-k5aGQpIZ.js.map → api-Dj1yabTj.js.map} +1 -1
- package/dist/bin.js +41 -41
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-BHLy83N9.js → bounded-fs-CWRYuLAn.js} +3 -3
- package/dist/bounded-fs-CWRYuLAn.js.map +1 -0
- package/dist/{ci-install-CXt4c41q.js → ci-install-CvXL5h13.js} +5 -5
- package/dist/{ci-install-CXt4c41q.js.map → ci-install-CvXL5h13.js.map} +1 -1
- package/dist/{debug-C5Zz8hmm.js → debug-B4kzIZPi.js} +12 -9
- package/dist/debug-B4kzIZPi.js.map +1 -0
- package/dist/{debug-BxMMpepn.js → debug-CziFS0cA.js} +1 -1
- package/dist/{defaults-DulzMJpN.js → defaults-4c4YwTmW.js} +26 -3
- package/dist/defaults-4c4YwTmW.js.map +1 -0
- package/dist/{env-api-key-Ca-CrkgV.js → env-api-key-BZ5wE3Y4.js} +2 -2
- package/dist/{env-api-key-Ca-CrkgV.js.map → env-api-key-BZ5wE3Y4.js.map} +1 -1
- package/dist/{environment-B0uTamFf.js → environment-BEvsey6i.js} +4 -4
- package/dist/{environment-B0uTamFf.js.map → environment-BEvsey6i.js.map} +1 -1
- package/dist/{errors--OqLxmWR.js → errors-BoJvrdw8.js} +4 -2
- package/dist/errors-BoJvrdw8.js.map +1 -0
- package/dist/{file-CNstcW8F.js → file-BoD3REGB.js} +2 -2
- package/dist/{file-CNstcW8F.js.map → file-BoD3REGB.js.map} +1 -1
- package/dist/{file-watcher-CiT-oZpu.js → file-watcher-BPFazvG_.js} +2 -2
- package/dist/{file-watcher-CiT-oZpu.js.map → file-watcher-BPFazvG_.js.map} +1 -1
- package/dist/{gateway-session-BIVN_Xfr.js → gateway-session-C118uACz.js} +1 -1
- package/dist/{gateway-session-C3Uqwc4R.js → gateway-session-xPFv6p5c.js} +5 -5
- package/dist/{gateway-session-C3Uqwc4R.js.map → gateway-session-xPFv6p5c.js.map} +1 -1
- package/dist/{headless-ui-TpSp-F43.js → headless-ui-CsmQrDIl.js} +2 -2
- package/dist/{headless-ui-TpSp-F43.js.map → headless-ui-CsmQrDIl.js.map} +1 -1
- package/dist/{interactive-B72L-sO5.js → interactive-Dej-sxvR.js} +2 -2
- package/dist/{interactive-B72L-sO5.js.map → interactive-Dej-sxvR.js.map} +1 -1
- package/dist/{mcp-CNc6CLK0.js → mcp-Cbuw_xss.js} +2 -2
- package/dist/{mcp-CNc6CLK0.js.map → mcp-Cbuw_xss.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-BvBNkzjv.js → mcp-prompt-streaming-BU_kuur_.js} +5 -5
- package/dist/{mcp-prompt-streaming-BvBNkzjv.js.map → mcp-prompt-streaming-BU_kuur_.js.map} +1 -1
- package/dist/{mint-failure-CZ5FZ0Jd.js → mint-failure-BrleGqMd.js} +72 -39
- package/dist/mint-failure-BrleGqMd.js.map +1 -0
- package/dist/{non-interactive-UeQlnU0U.js → non-interactive-DcOjH2fw.js} +3 -3
- package/dist/{non-interactive-UeQlnU0U.js.map → non-interactive-DcOjH2fw.js.map} +1 -1
- package/dist/{orchestrator-tools-CLADku26.js → orchestrator-tools-DXwr8Sp3.js} +4 -4
- package/dist/orchestrator-tools-DXwr8Sp3.js.map +1 -0
- package/dist/{package-manager-CppzeIgu.js → package-manager-DR23m5Jg.js} +2 -2
- package/dist/{package-manager-CppzeIgu.js.map → package-manager-DR23m5Jg.js.map} +1 -1
- package/dist/{pi-Bs1Tbt0C.js → pi-mY8I2XkG.js} +13 -13
- package/dist/{pi-Bs1Tbt0C.js.map → pi-mY8I2XkG.js.map} +1 -1
- package/dist/{playground-CZgZX4j0.js → playground-CDUUKLkC.js} +13 -9
- package/dist/playground-CDUUKLkC.js.map +1 -0
- package/dist/{posthog-BZ3NNCyh.js → posthog-Hc_-9wrr.js} +2 -2
- package/dist/{posthog-BZ3NNCyh.js.map → posthog-Hc_-9wrr.js.map} +1 -1
- package/dist/{provisioning-Ba7GWKzK.js → provisioning-xfdjhFtA.js} +3 -3
- package/dist/{provisioning-Ba7GWKzK.js.map → provisioning-xfdjhFtA.js.map} +1 -1
- package/dist/{queue-tools-D09PNS0X.js → queue-tools-C8y_xZJi.js} +8 -4
- package/dist/queue-tools-C8y_xZJi.js.map +1 -0
- package/dist/{registry-COcpEsMD.js → registry-DTmREJ-f.js} +5 -5
- package/dist/{registry-COcpEsMD.js.map → registry-DTmREJ-f.js.map} +1 -1
- package/dist/{security-CpAT0fZa.js → security-Dw2oFJjP.js} +5 -5
- package/dist/{security-CpAT0fZa.js.map → security-Dw2oFJjP.js.map} +1 -1
- package/dist/{setup-utils-BUAoRjw3.js → setup-utils-fjJTBhaB.js} +8 -8
- package/dist/setup-utils-fjJTBhaB.js.map +1 -0
- package/dist/{start-tui-Bz23_yym.js → start-tui-UNe2xQ0U.js} +25 -25
- package/dist/start-tui-UNe2xQ0U.js.map +1 -0
- package/dist/{steps-DbsDish5.js → steps-C2yqOk_h.js} +7 -7
- package/dist/{steps-DbsDish5.js.map → steps-C2yqOk_h.js.map} +1 -1
- package/dist/{store-D5ROpUje.js → store-Bic4Cr3L.js} +5 -32
- package/dist/store-Bic4Cr3L.js.map +1 -0
- package/dist/{subagent-CSBZnhgK.js → subagent-Dz41vV9j.js} +2 -2
- package/dist/{subagent-CSBZnhgK.js.map → subagent-Dz41vV9j.js.map} +1 -1
- package/dist/{task-D8sTR7jZ.js → task-5-fw_Vw3.js} +14 -14
- package/dist/{task-D8sTR7jZ.js.map → task-5-fw_Vw3.js.map} +1 -1
- package/dist/{task-stream-Dl0XEsZ9.js → task-stream-dVzl6b_q.js} +6 -6
- package/dist/{task-stream-Dl0XEsZ9.js.map → task-stream-dVzl6b_q.js.map} +1 -1
- package/dist/{tasks-BDt427kT.js → tasks-D1c2z1aw.js} +2 -2
- package/dist/{tasks-BDt427kT.js.map → tasks-D1c2z1aw.js.map} +1 -1
- package/dist/{telemetry-Dp6zjZBj.js → telemetry-BRnxBRWK.js} +3 -3
- package/dist/{telemetry-Dp6zjZBj.js.map → telemetry-BRnxBRWK.js.map} +1 -1
- package/dist/{terminal-pInlleVD.js → terminal-9bvRa4Qt.js} +38 -34
- package/dist/terminal-9bvRa4Qt.js.map +1 -0
- package/dist/{tools-MkyMOjQI.js → tools-Dp6i9k70.js} +8 -8
- package/dist/{tools-MkyMOjQI.js.map → tools-Dp6i9k70.js.map} +1 -1
- package/dist/{wizard-abort-BHLKVKLN.js → wizard-abort-CAcInAxg.js} +1 -1
- package/dist/{wizard-abort-BCnUgT9z.js → wizard-abort-lE6umflt.js} +4 -4
- package/dist/{wizard-abort-BCnUgT9z.js.map → wizard-abort-lE6umflt.js.map} +1 -1
- package/dist/{yara-hooks-BJWVgTpU.js → yara-hooks-BTNJ6MGW.js} +4 -4
- package/dist/{yara-hooks-BJWVgTpU.js.map → yara-hooks-BTNJ6MGW.js.map} +1 -1
- package/dist/yara-hooks-CFY4pGcW.js +2 -0
- package/package.json +8 -1
- package/dist/add-mcp-server-to-clients-Exddicp2.js.map +0 -1
- package/dist/agent-interface-CZWRgZMc.js.map +0 -1
- package/dist/agent-prompt-loader-BobuLDIg.js.map +0 -1
- package/dist/agent-runner-C_R1X_UT.js.map +0 -1
- package/dist/analytics-DXvdQqyp.js +0 -2
- package/dist/bounded-fs-BHLy83N9.js.map +0 -1
- package/dist/debug-C5Zz8hmm.js.map +0 -1
- package/dist/defaults-DulzMJpN.js.map +0 -1
- package/dist/errors--OqLxmWR.js.map +0 -1
- package/dist/mint-failure-CZ5FZ0Jd.js.map +0 -1
- package/dist/orchestrator-tools-CLADku26.js.map +0 -1
- package/dist/playground-CZgZX4j0.js.map +0 -1
- package/dist/queue-tools-D09PNS0X.js.map +0 -1
- package/dist/setup-utils-BUAoRjw3.js.map +0 -1
- package/dist/start-tui-Bz23_yym.js.map +0 -1
- package/dist/store-D5ROpUje.js.map +0 -1
- package/dist/terminal-pInlleVD.js.map +0 -1
- package/dist/yara-hooks-Dp82xJGd.js +0 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { p as getUI } from "./debug-
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
3
|
-
import { t as withProgress } from "./telemetry-
|
|
4
|
-
import "./bounded-fs-
|
|
5
|
-
import "./setup-utils-
|
|
6
|
-
import "./add-mcp-server-to-clients-
|
|
1
|
+
import { p as getUI } from "./debug-B4kzIZPi.js";
|
|
2
|
+
import { n as analytics } from "./analytics-C67F2vee.js";
|
|
3
|
+
import { t as withProgress } from "./telemetry-BRnxBRWK.js";
|
|
4
|
+
import "./bounded-fs-CWRYuLAn.js";
|
|
5
|
+
import "./setup-utils-fjJTBhaB.js";
|
|
6
|
+
import "./add-mcp-server-to-clients-BnRyE4pw.js";
|
|
7
7
|
import * as fs$1 from "fs";
|
|
8
8
|
import * as path$1 from "path";
|
|
9
9
|
import "path";
|
|
@@ -144,4 +144,4 @@ const uploadEnvironmentVariablesStep = async (envVars, { integration, session })
|
|
|
144
144
|
//#endregion
|
|
145
145
|
export { uploadEnvironmentVariablesStep };
|
|
146
146
|
|
|
147
|
-
//# sourceMappingURL=steps-
|
|
147
|
+
//# sourceMappingURL=steps-C2yqOk_h.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"steps-
|
|
1
|
+
{"version":3,"file":"steps-C2yqOk_h.js","names":["path","fs","spawnSync","spawn"],"sources":["../src/steps/upload-environment-variables/EnvironmentProvider.ts","../src/steps/upload-environment-variables/providers/vercel.ts","../src/steps/upload-environment-variables/index.ts"],"sourcesContent":["export abstract class EnvironmentProvider {\n protected options: { installDir: string };\n\n name: string;\n\n constructor(options: { installDir: string }) {\n this.options = options;\n }\n\n abstract detect(): Promise<boolean>;\n\n abstract uploadEnvVars(\n vars: Record<string, string>,\n ): Promise<Record<string, boolean>>;\n}\n","import { execSync, spawn, spawnSync } from 'child_process';\nimport { EnvironmentProvider } from '@steps/upload-environment-variables/EnvironmentProvider';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { getUI } from '@ui';\nimport { analytics } from '@utils/analytics';\n\nexport class VercelEnvironmentProvider extends EnvironmentProvider {\n name = 'Vercel';\n environments = ['production', 'preview', 'development'];\n\n constructor(options: { installDir: string }) {\n super(options);\n }\n\n // eslint-disable-next-line @typescript-eslint/require-await\n async detect(): Promise<boolean> {\n const vercelDetected =\n this.hasVercelCli() && this.isProjectLinked() && this.isAuthenticated();\n\n analytics.setTag('vercel-detected', vercelDetected);\n\n return vercelDetected;\n }\n\n hasDotVercelDir(): boolean {\n const dotVercelDir = path.join(this.options.installDir, '.vercel');\n return fs.existsSync(dotVercelDir);\n }\n\n hasVercelCli(): boolean {\n try {\n execSync('vercel --version', { stdio: 'ignore' });\n analytics.setTag('vercel-cli-installed', true);\n return true;\n } catch {\n analytics.setTag('vercel-cli-installed', false);\n return false;\n }\n }\n\n isProjectLinked(): boolean {\n const isProjectLinked = fs.existsSync(\n path.join(this.options.installDir, '.vercel', 'project.json'),\n );\n\n analytics.setTag('vercel-project-linked', isProjectLinked);\n\n return isProjectLinked;\n }\n\n isAuthenticated(): boolean {\n const result = spawnSync('vercel', ['whoami'], {\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'], // suppress prompts\n env: {\n ...process.env,\n FORCE_COLOR: '0', // avoid ANSI formatting\n CI: '1', // hint to CLI that it's a non-interactive env\n },\n });\n\n const output = (\n String(result.stdout) + String(result.stderr)\n ).toLowerCase();\n\n if (\n output.includes('log in to vercel') ||\n output.includes('vercel login') ||\n result.status !== 0\n ) {\n analytics.setTag('vercel-authenticated', false);\n return false;\n }\n\n analytics.setTag('vercel-authenticated', true);\n\n return true;\n }\n\n async uploadEnvironmentVariable(\n key: string,\n value: string,\n environment: string,\n ): Promise<void> {\n await new Promise<void>((resolve, reject) => {\n const proc = spawn('vercel', ['env', 'add', key, environment], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let stderr = '';\n proc.stderr.on('data', (data) => {\n stderr += data.toString();\n });\n\n proc.stdin.write(value);\n proc.stdin.end();\n\n proc.on('close', (code) => {\n if (\n stderr.includes('already exists') ||\n stderr.includes('already been added') ||\n stderr.includes('vercel env rm')\n ) {\n reject(\n new Error(\n `❌ Environment variable ${key} already exists in ${this.name}. Please upload it manually.`,\n ),\n );\n } else if (code === 0) {\n resolve();\n } else {\n reject(\n new Error(\n `❌ Failed to upload environment variable ${key} to ${this.name}. Please upload it manually.`,\n ),\n );\n }\n });\n });\n }\n\n async uploadEnvVars(\n vars: Record<string, string>,\n ): Promise<Record<string, boolean>> {\n const results: Record<string, boolean> = {};\n\n for (const [key, value] of Object.entries(vars)) {\n const spinner = getUI().spinner();\n\n spinner.start(`Uploading ${key} to ${this.name}...`);\n await Promise.all(\n this.environments.map((environment) =>\n this.uploadEnvironmentVariable(key, value, environment),\n ),\n )\n .then(() => {\n spinner.stop(`✅ Uploaded ${key} to ${this.name}`);\n results[key] = true;\n })\n .catch((err) => {\n spinner.stop(\n err instanceof Error\n ? err.message\n : `❌ Failed to upload environment variables to ${this.name}. Please upload it manually.`,\n );\n results[key] = false;\n });\n }\n\n return results;\n }\n}\n","import type { Integration } from '@lib/constants';\nimport { withProgress } from '../../telemetry';\nimport { analytics } from '@utils/analytics';\nimport { getUI } from '@ui';\nimport type { WizardSession } from '@lib/wizard-session';\nimport { EnvironmentProvider } from './EnvironmentProvider';\nimport { VercelEnvironmentProvider } from './providers/vercel';\n\nexport const uploadEnvironmentVariablesStep = async (\n envVars: Record<string, string>,\n {\n integration,\n session,\n }: {\n integration: Integration;\n session: WizardSession;\n },\n): Promise<string[]> => {\n const providers: EnvironmentProvider[] = [\n new VercelEnvironmentProvider({ installDir: session.installDir }),\n ];\n\n let provider: EnvironmentProvider | null = null;\n\n for (const p of providers) {\n if (await p.detect()) {\n provider = p;\n break;\n }\n }\n\n if (!provider) {\n analytics.wizardCapture('env upload skipped', {\n reason: 'no environment provider found',\n integration,\n });\n return [];\n }\n\n // Auto-accept — the agent already wrote env vars via MCP tools\n getUI().log.info(`Uploading environment variables to ${provider.name}...`);\n\n const results = await withProgress(\n 'uploading environment variables',\n async () => {\n return await provider.uploadEnvVars(envVars);\n },\n );\n\n analytics.wizardCapture('env uploaded', {\n provider: provider.name,\n integration,\n });\n\n return Object.keys(results).filter((key) => results[key]);\n};\n"],"mappings":"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"}
|
|
@@ -1,37 +1,10 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import { S as isTaskStatus, s as logToFile, y as getBlockingServiceKeys } from "./debug-
|
|
2
|
+
import { S as isTaskStatus, s as logToFile, y as getBlockingServiceKeys } from "./debug-B4kzIZPi.js";
|
|
3
3
|
import { a as buildSession } from "./wizard-session-FSJCkTcP.js";
|
|
4
|
-
import { i as sessionProperties, n as analytics } from "./analytics-
|
|
5
|
-
import {
|
|
6
|
-
import { a as PROGRAM_REGISTRY, i as isRunFailure, o as Program, u as getProgramConfig } from "./mint-failure-
|
|
4
|
+
import { i as sessionProperties, n as analytics } from "./analytics-C67F2vee.js";
|
|
5
|
+
import { a as computeTokenCostUsd, i as createProgramSequence, u as reportWarehouseSourcesDetected } from "./agent-runner-COOIUJCP.js";
|
|
6
|
+
import { a as PROGRAM_REGISTRY, i as isRunFailure, o as Program, u as getProgramConfig } from "./mint-failure-BrleGqMd.js";
|
|
7
7
|
import { atom, map } from "nanostores";
|
|
8
|
-
//#region src/lib/programs/program-step.ts
|
|
9
|
-
/**
|
|
10
|
-
* Project program steps into the narrower Screen shape the router consumes.
|
|
11
|
-
*
|
|
12
|
-
* Two things happen here:
|
|
13
|
-
* 1. Headless steps (no `screenId`) are filtered out. The router walks
|
|
14
|
-
* visible screens; gate-only steps like `detect` are store concerns.
|
|
15
|
-
* 2. The step is narrowed to just { id, show, isComplete } — the
|
|
16
|
-
* router has no business touching gate, onInit, or label.
|
|
17
|
-
*
|
|
18
|
-
* This intentional separation keeps the router focused on one question:
|
|
19
|
-
* "Which screen should be rendered right now?"
|
|
20
|
-
*/
|
|
21
|
-
function createProgramSequence(steps) {
|
|
22
|
-
const entries = steps.filter((step) => step.screenId != null).map((step) => ({
|
|
23
|
-
id: step.screenId,
|
|
24
|
-
show: step.show,
|
|
25
|
-
isComplete: step.isComplete ?? step.gate
|
|
26
|
-
}));
|
|
27
|
-
entries.push({
|
|
28
|
-
id: "exit",
|
|
29
|
-
show: void 0,
|
|
30
|
-
isComplete: void 0
|
|
31
|
-
});
|
|
32
|
-
return entries;
|
|
33
|
-
}
|
|
34
|
-
//#endregion
|
|
35
8
|
//#region src/lib/programs/ai-opt-in-gate.ts
|
|
36
9
|
/** Step id — also the ScreenId.AiOptIn enum value in screen-sequences. */
|
|
37
10
|
const AI_OPT_IN_STEP_ID = "ai-opt-in";
|
|
@@ -1032,4 +1005,4 @@ var WizardStore = class {
|
|
|
1032
1005
|
//#endregion
|
|
1033
1006
|
export { store_exports as n, totalTokenCount as r, WizardStore as t };
|
|
1034
1007
|
|
|
1035
|
-
//# sourceMappingURL=store-
|
|
1008
|
+
//# sourceMappingURL=store-Bic4Cr3L.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store-Bic4Cr3L.js","names":[],"sources":["../src/lib/programs/ai-opt-in-gate.ts","../src/ui/tui/screen-sequences.ts","../src/ui/tui/router.ts","../src/ui/tui/store.ts"],"sourcesContent":["/**\n * AI opt-in gate — step injection for programs whose agent run sends\n * source to Anthropic Claude.\n *\n * Injected after the `auth` step for every program that doesn't declare\n * `requiresAi: false`. The injected step carries three predicates:\n *\n * show — renders AiOptInRequiredScreen when the org hasn't\n * approved third-party AI\n * isComplete — router advances once approval lands\n * gate — `await store.getGate('ai-opt-in')` parks the agent\n * runner until approval lands. THIS is the enforcement:\n * the screen alone is cosmetic; the gate is what stops\n * source from leaving the machine.\n *\n * Used by BOTH screen-sequences.ts (screen injection) and the store's\n * _initFromProgram (gate registration) so the two layers can't drift.\n *\n * The predicates mirror Max's strict reading of\n * `organization.is_ai_data_processing_approved`: only literal `true`\n * proceeds; `null` / `undefined` / `false` all block. CI and signup\n * sessions skip the gate:\n * - `--ci` auto-consents to AI usage per the README, and the\n * interactive kill screen would be unworkable headless.\n * - signup (account provisioning) auto-consents too: the provisioning\n * access token deliberately omits the `organization:read` scope\n * (`WIZARD_PROVISIONING_SCOPES` in constants.ts), so the org's\n * approval can never be read back — `apiUser` stays null and the gate\n * could never clear. Creating an account through the wizard to run the\n * AI agent is itself the consent, mirroring how `shouldDisableAsk`\n * already treats `ci || signup` as one non-interactive mode.\n */\n\nimport type { WizardSession } from '@lib/wizard-session';\nimport type { ProgramConfig, ProgramStep } from './program-step.js';\n\n/** Step id — also the ScreenId.AiOptIn enum value in screen-sequences. */\nexport const AI_OPT_IN_STEP_ID = 'ai-opt-in';\n\nfunction aiApproved(session: WizardSession): boolean {\n return !!session.apiUser?.organization?.is_ai_data_processing_approved;\n}\n\n/**\n * Returns the program's steps with the AI opt-in gate injected after\n * `auth`. Programs with `requiresAi: false` or no auth step pass\n * through unchanged — without auth, `apiUser` would never be populated\n * for evaluation anyway.\n */\nexport function withAiOptInGate(config: ProgramConfig): ProgramStep[] {\n if (config.requiresAi === false) return config.steps;\n\n const authIdx = config.steps.findIndex((s) => s.id === 'auth');\n if (authIdx === -1) return config.steps;\n\n const gateStep: ProgramStep = {\n id: AI_OPT_IN_STEP_ID,\n label: 'AI opt-in check',\n screenId: AI_OPT_IN_STEP_ID,\n // Only fire once apiUser has actually been populated — between\n // setCredentials and setApiUser there's a brief emitChange window\n // where apiUser is null, and we don't want to flash the gate then.\n show: (session) =>\n !session.ci &&\n !session.signup &&\n session.apiUser != null &&\n !aiApproved(session),\n isComplete: (session) =>\n session.ci || session.signup || aiApproved(session),\n gate: (session) => session.ci || session.signup || aiApproved(session),\n };\n\n return [\n ...config.steps.slice(0, authIdx + 1),\n gateStep,\n ...config.steps.slice(authIdx + 1),\n ];\n}\n","/**\n * Screen taxonomy + per-program screen sequences.\n *\n * Owns the ScreenId enum and projects each registered program's steps\n * into the router-shaped screen sequence (filtering headless steps and\n * appending the exit screen). Pure leaf module — no store, no React.\n */\n\nimport type { WizardSession } from '@lib/wizard-session';\nimport {\n PROGRAM_REGISTRY,\n type ProgramId,\n} from '@lib/programs/program-registry';\nimport { createProgramSequence } from '@lib/programs/program-step';\nimport { withAiOptInGate } from '@lib/programs/ai-opt-in-gate';\n\n/** Screens that participate in linear programs. */\nexport enum ScreenId {\n Intro = 'intro',\n RevenueIntro = 'revenue-intro',\n WarehouseIntro = 'warehouse-intro',\n SourceMapsIntro = 'source-maps-intro',\n SourceMapsDetect = 'source-maps-detect',\n SourceMapsOutro = 'source-maps-outro',\n MigrationIntro = 'migration-intro',\n AgentSkillIntro = 'agent-skill-intro',\n AiObservabilityIntro = 'ai-observability-intro',\n MetricsIntro = 'metrics-intro',\n ErrorTrackingIntro = 'error-tracking-intro',\n ErrorTrackingDetect = 'error-tracking-detect',\n SelfDrivingIntro = 'self-driving-intro',\n SelfDrivingIntegrationCheck = 'self-driving-integration-check',\n SelfDrivingIntegrationDetect = 'self-driving-integration-detect',\n SelfDrivingHandoff = 'self-driving-handoff',\n SelfDrivingGithub = 'self-driving-github',\n AuditIntro = 'audit-intro',\n AuditRun = 'audit-run',\n AuditOutro = 'audit-outro',\n HealthCheck = 'health-check',\n DoctorIntro = 'doctor-intro',\n DoctorReport = 'doctor-report',\n Setup = 'setup',\n Auth = 'auth',\n Run = 'run',\n Mcp = 'mcp',\n McpSuggestedPrompts = 'mcp-suggested-prompts',\n SlackConnect = 'slack-connect',\n KeepSkills = 'keep-skills',\n Outro = 'outro',\n MintFailure = 'mint-failure',\n Exit = 'exit',\n McpAdd = 'mcp-add',\n McpRemove = 'mcp-remove',\n AiOptIn = 'ai-opt-in',\n}\n\nexport interface Screen {\n /** ScreenId to show */\n id: ScreenId;\n /** If provided, screen is skipped when this returns false. Omit = always show. */\n show?: (session: WizardSession) => boolean;\n /** If provided, screen is considered complete when this returns true. */\n isComplete?: (session: WizardSession) => boolean;\n}\n\n/** An ordered list of screens — a program's screen journey. */\nexport type Sequence = Screen[];\n\n/** Post-run steps a mint-failure handoff continues through; ends on exit. */\nexport const MINT_HANDOFF_SEQUENCE: Sequence = [\n { id: ScreenId.Mcp, isComplete: (s) => s.mcpComplete },\n { id: ScreenId.SlackConnect, isComplete: (s) => s.slackStepDismissed },\n { id: ScreenId.KeepSkills, isComplete: (s) => s.skillsComplete },\n { id: ScreenId.Exit },\n];\n\n/** All program screen sequences keyed by program id. */\nexport const PROGRAM_SEQUENCES: Record<ProgramId, Sequence> =\n Object.fromEntries(\n PROGRAM_REGISTRY.map((c) => [\n c.id,\n createProgramSequence(withAiOptInGate(c)) as Sequence,\n ]),\n ) as Record<ProgramId, Sequence>;\n","/**\n * WizardRouter — declarative program pipelines + overlay stack.\n *\n * Two layers:\n * Program cursor — linear sequence of screens, advanced with next()\n * Overlay stack — interrupts (outage, auth-expired, etc.) that push/pop\n *\n * The visible screen is: top of overlay stack if non-empty, otherwise the program cursor.\n *\n * Adding a program screen = append to a sequence array.\n * Adding an overlay = call pushOverlay() from anywhere.\n * No switch statements, no hardcoded transitions in business logic.\n */\n\nimport { RunPhase, type WizardSession } from '@lib/wizard-session';\nimport { isRunFailure } from '@ui/mint-failure';\nimport { Program, type ProgramId } from '@lib/programs/program-registry';\nimport {\n PROGRAM_SEQUENCES,\n MINT_HANDOFF_SEQUENCE,\n ScreenId,\n type Screen,\n type Sequence,\n} from './screen-sequences.js';\n\n// Re-export so existing imports from './router.js' keep working\nexport { ScreenId, Program };\nexport type { Screen, Sequence, ProgramId };\n\n// ── ScreenId name taxonomy ──────────────────────────────────────────────\n\n/** Screens that interrupt programs as overlays */\nexport enum Overlay {\n SettingsOverride = 'settings-override',\n ManagedSettings = 'managed-settings',\n PortConflict = 'port-conflict',\n ManualAuthCode = 'manual-auth-code',\n AuthError = 'auth-error',\n SessionTimeout = 'session-timeout',\n WizardAsk = 'wizard-ask',\n TaskNotice = 'task-notice',\n}\n\n/** Union of all screen names */\nexport type ScreenName = ScreenId | Overlay;\n\n// ── Router ────────────────────────────────────────────────────────────\n\nexport class WizardRouter {\n private sequence: Sequence;\n private programId: ProgramId;\n private overlays: Overlay[] = [];\n\n constructor(programId: ProgramId = Program.PostHogIntegration) {\n this.setProgram(programId);\n }\n\n /** Point the router at a different program. */\n setProgram(programId: ProgramId): void {\n this.programId = programId;\n this.sequence = PROGRAM_SEQUENCES[programId];\n this.overlays = [];\n }\n\n /**\n * Resolve which screen should be active based on session state.\n * Walks the program sequence, skipping hidden entries and completed entries,\n * returns the first incomplete screen.\n */\n resolve(session: WizardSession): ScreenName {\n // A failed agent run interrupts every program until the user leaves the\n // handoff screen: exit, or continue through the post-run steps.\n const runFailed = isRunFailure(session);\n if (runFailed && session.mintHandoff === 'exit') return ScreenId.Exit;\n if (runFailed && !session.mintHandoff) return ScreenId.MintFailure;\n\n if (this.overlays.length > 0) {\n return this.overlays[this.overlays.length - 1];\n }\n\n const sequence = runFailed ? MINT_HANDOFF_SEQUENCE : this.sequence;\n for (const entry of sequence) {\n if (entry.show && !entry.show(session)) continue;\n if (entry.isComplete && entry.isComplete(session)) continue;\n // A failed login aborts the run: wizardAbort renders the error outro\n // and then waits for its dismissal. But the auth step only completes\n // on credentials — which an aborted login never set — so the walk\n // would park here forever: auth spinner up, outro unreachable, and\n // that wait deadlocked. Route to the outro so the error can be read\n // and dismissed. Auth only: the run steps already complete on\n // RunPhase.Error, so later aborts reach their program's own outro.\n if (\n entry.id === ScreenId.Auth &&\n session.runPhase === RunPhase.Error &&\n session.outroData\n ) {\n return ScreenId.Outro;\n }\n return entry.id;\n }\n\n // All entries complete — show the last screen (outro)\n return sequence[sequence.length - 1].id;\n }\n\n /** The screen that should be rendered right now. */\n get activeScreen(): ScreenName {\n // Overlays take priority — resolve() handles this too,\n // but activeScreen is called before session is available in some paths\n if (this.overlays.length > 0) {\n return this.overlays[this.overlays.length - 1];\n }\n return this.sequence[0].id;\n }\n\n /** The id of the active program. */\n get activeProgram(): ProgramId {\n return this.programId;\n }\n\n /** Whether an overlay is currently active. */\n get hasOverlay(): boolean {\n return this.overlays.length > 0;\n }\n\n /**\n * Push an overlay that interrupts the current program.\n * The program resumes when the overlay is dismissed via popOverlay().\n */\n pushOverlay(overlay: Overlay): void {\n this.overlays.push(overlay);\n }\n\n /**\n * Dismiss the topmost overlay. The program screen underneath resumes.\n */\n popOverlay(): void {\n this.overlays.pop();\n }\n\n /**\n * Direction hint for screen transitions.\n */\n private _lastDirection: 'push' | 'pop' | null = null;\n\n get lastNavDirection(): 'push' | 'pop' | null {\n return this._lastDirection;\n }\n\n /** @internal — called by store wrapper to track direction */\n _setDirection(dir: 'push' | 'pop' | null): void {\n this._lastDirection = dir;\n }\n}\n","/**\n * WizardStore — Nanostore-backed reactive store for the TUI.\n * React components subscribe via useSyncExternalStore.\n *\n * The active screen is derived from session state — WizardRouter walks\n * the flow and shows the first step whose `isComplete` is still false.\n *\n * Define a step `gate` if your screen needs to await user interactions.\n * bin.ts calls `await store.getGate(stepId)` to pause until the gate\n * predicate becomes true.\n *\n * All session mutations that affect screen resolution go through\n * explicit setters so emitChange() is always called.\n */\n\nimport { atom, map } from 'nanostores';\nimport { logToFile } from '@utils/debug';\nimport {\n TaskStatus,\n isTaskStatus,\n type AuthErrorDetail,\n type TokenUsageDelta,\n} from '@ui/wizard-ui';\nimport {\n type WizardSession,\n type OutroData,\n type DiscoveredFeature,\n type PendingQuestion,\n type AskAnswers,\n type CloudRegion,\n AdditionalFeature,\n McpOutcome,\n RunPhase,\n ScanConsent,\n buildSession,\n type TaskNotice,\n} from '@lib/wizard-session';\nimport type { SettingsConflict } from '@lib/agent/claude-settings';\nimport {\n WizardReadiness,\n getBlockingServiceKeys,\n type WizardReadinessResult,\n} from '@lib/health-checks/readiness';\nimport {\n WizardRouter,\n type ScreenName,\n ScreenId,\n Overlay,\n Program,\n type ProgramId,\n} from './router.js';\nimport { analytics, sessionProperties } from '@utils/analytics';\nimport type {\n StoreInitContext,\n ProgramReadyContext,\n} from '@lib/programs/program-step';\nimport { getProgramConfig } from '@lib/programs/program-registry';\nimport { withAiOptInGate } from '@lib/programs/ai-opt-in-gate';\nimport { reportWarehouseSourcesDetected } from '@lib/programs/posthog-integration/detect';\nimport { EXPANDED_COUNT } from '@ui/tui/constants';\nimport { IS_DEV } from '@lib/constants';\nimport { computeTokenCostUsd } from '@lib/agent/token-pricing';\n\nexport { TaskStatus, ScreenId, Overlay, Program, RunPhase, McpOutcome };\nexport type { ScreenName, OutroData, WizardSession, ProgramId };\n\nexport interface TaskItem {\n label: string;\n activeForm?: string;\n status: TaskStatus;\n /** Legacy compat */\n done: boolean;\n}\n\nexport interface PlannedEvent {\n name: string;\n description: string;\n}\n\n/**\n * Running token/cost estimate for the hidden Ctrl+T HUD. Accumulated live\n * from each assistant turn's usage (see `agent-interface.ts`), then\n * reconciled to the SDK's authoritative `total_cost_usd` once the run\n * completes — `costIsFinal` flips so the HUD can show the number as exact\n * rather than a running estimate.\n */\nexport interface TokenUsageSnapshot {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n costUsd: number;\n costIsFinal: boolean;\n}\n\nconst EMPTY_TOKEN_USAGE: TokenUsageSnapshot = {\n inputTokens: 0,\n outputTokens: 0,\n cacheReadTokens: 0,\n cacheCreationTokens: 0,\n costUsd: 0,\n costIsFinal: false,\n};\n\n/** Total tokens across all counters in a `TokenUsageSnapshot` — used by\n * both `TokenCostHud` and `exit-line.ts` to detect \"no agent turns yet\". */\nexport function totalTokenCount(usage: TokenUsageSnapshot): number {\n return (\n usage.inputTokens +\n usage.outputTokens +\n usage.cacheReadTokens +\n usage.cacheCreationTokens\n );\n}\n\ninterface GateEntry {\n predicate: (session: WizardSession) => boolean;\n promise: Promise<void>;\n resolve: () => void;\n resolved: boolean;\n}\n\n/**\n * FIFO cap on retained status lines. The status bar is the only consumer and\n * renders at most EXPANDED_COUNT lines, so there is no reason to retain more —\n * the cap is tied to the window it feeds.\n */\nconst MAX_STATUS_MESSAGES = EXPANDED_COUNT;\n\n// Capture blocked skill downloads once per readiness result.\nfunction captureHealthCheckBlocked(result: WizardReadinessResult): void {\n try {\n const health = result.health;\n const blockingKeys = getBlockingServiceKeys(health);\n const attempts = health.skillsOrigin.rawIndicator?.match(/attempts=(\\d+)/);\n const retriesUsed = Math.max(0, attempts ? Number(attempts[1]) - 1 : 0);\n\n analytics.wizardCapture('health check blocked', {\n decision: 'skills-origin-down',\n blocking_keys: blockingKeys,\n retries_used: retriesUsed,\n });\n } catch (err) {\n logToFile(\n `[health-checks] failed to capture analytics: ${\n err instanceof Error ? err.message : String(err)\n }`,\n );\n }\n}\n\nexport class WizardStore {\n // ── Internal nanostore atoms ─────────────────────────────────────\n private $session = map<WizardSession>(buildSession({}));\n private $statusMessages = atom<string[]>([]);\n private $statusExpanded = atom(false);\n private $tasks = atom<TaskItem[]>([]);\n private $eventPlan = atom<PlannedEvent[]>([]);\n private $handoffText = atom<string | null>(null);\n private $learnCardBlockIdx = atom(0);\n private $learnCardComplete = atom(false);\n private $version = atom(0);\n private $currentStage = atom<{ stage: string; startedAt: number } | null>(\n null,\n );\n private $tokenUsage = atom<TokenUsageSnapshot>(EMPTY_TOKEN_USAGE);\n // Defaults on for local/dev/test runs (tsx, `pnpm try`, vitest) so\n // contributors see it without needing to know the shortcut; defaults off\n // for the published build, where it stays genuinely hidden. Still\n // Ctrl+T-toggleable either way.\n private $tokenHudVisible = atom(IS_DEV);\n\n private _onTasksChanged: (() => void) | null = null;\n /** Last screen seen — used to detect screen transitions for analytics. */\n private _lastScreen: ScreenName | null = null;\n\n /** Hooks run when transitioning onto a screen. */\n private _enterScreenHooks = new Map<ScreenName, (() => void)[]>();\n\n /** Gate promises derived from program step definitions. */\n private _gates = new Map<string, GateEntry>();\n\n version = '';\n\n /** Navigation router — resolves active screen from session state. */\n readonly router: WizardRouter;\n\n /** Blocks agent execution until the settings-override overlay is dismissed. */\n private _resolveSettingsOverride: (() => void) | null = null;\n private _backupAndFixSettings: (() => boolean) | null = null;\n\n /** Blocks the run until an optional step's notice is answered. */\n private _resolveTaskNotice: ((keep: boolean) => void) | null = null;\n /** Blocks OAuth flow until the port-conflict overlay is dismissed. */\n private _resolvePortConflict: (() => void) | null = null;\n\n /** Resolves the OAuth flow with a manually-entered authorization code. */\n private _resolveManualAuthCode: ((code: string) => void) | null = null;\n\n /** Resolves the in-flight wizard_ask request. */\n private _resolvePendingQuestion: ((answers: AskAnswers) => void) | null =\n null;\n\n constructor(program: ProgramId = Program.PostHogIntegration) {\n this.router = new WizardRouter(program);\n this._initFromProgram(program);\n }\n\n /**\n * Scan program steps for gate predicates and create gate promises.\n *\n * Steps are wrapped with withAiOptInGate so the injected ai-opt-in\n * step's gate registers here — the agent runner awaits it (via\n * WizardUI.waitForAiOptIn) before any source leaves the machine.\n * Same wrapper screen-sequences.ts uses, so the gate and its screen\n * can't drift apart.\n */\n private _initFromProgram(program: ProgramId): void {\n const steps = withAiOptInGate(getProgramConfig(program));\n\n // Create gate promises from steps that define them\n for (const step of steps) {\n if (step.gate) {\n let resolve!: () => void;\n const promise = new Promise<void>((r) => {\n resolve = r;\n });\n this._gates.set(step.id, {\n predicate: step.gate,\n promise,\n resolve,\n resolved: false,\n });\n }\n }\n }\n\n /**\n * Run the program steps' onInit callbacks. startTUI calls this once\n * the screens are actually rendering — constructing a store alone\n * (tests, playground) must not fire init work like the health-check\n * pre-flight, whose probes belong only to flows that show its screen.\n */\n runInitHooks(): void {\n const steps = getProgramConfig(this.router.activeProgram).steps;\n const getSession = (): WizardSession => this.session;\n const ctx: StoreInitContext = {\n get session() {\n return getSession();\n },\n setReadinessResult: (r) => this.setReadinessResult(r),\n setFrameworkContext: (k, v) => this.setFrameworkContext(k, v),\n emitChange: () => this.emitChange(),\n };\n for (const step of steps) {\n step.onInit?.(ctx);\n }\n }\n\n /**\n * Run all `onReady` hooks declared by the current flow's steps, in\n * order. Must be called after `store.session = session` so hooks see\n * the real installDir. bin.ts calls this generically — it doesn't\n * need to know which program has which pre-flow work.\n */\n async runReadyHooks(): Promise<void> {\n const steps = getProgramConfig(this.router.activeProgram).steps;\n const ctx: ProgramReadyContext = {\n session: this.session,\n setFrameworkContext: (k, v) => this.setFrameworkContext(k, v),\n setFrameworkConfig: (i, c) => this.setFrameworkConfig(i, c),\n setDetectedFramework: (l) => this.setDetectedFramework(l),\n setPosthogSdkDetected: (d) => this.setPosthogSdkDetected(d),\n setSkillId: (id) => this.setSkillId(id),\n setUnsupportedVersion: (info) => this.setUnsupportedVersion(info),\n addDiscoveredFeature: (f) => this.addDiscoveredFeature(f),\n setDetectionComplete: () => this.setDetectionComplete(),\n };\n for (const step of steps) {\n if (step.onReady) {\n await step.onReady(ctx);\n }\n }\n }\n\n // ── Gate API ────────────────────────────────────────────────────\n\n /**\n * Get a gate promise by step ID — the primary blocking checkpoint API\n * for bin.ts. `await store.getGate('...')` parks the caller until the\n * corresponding program step's gate predicate flips to true (if the\n * predicate stays false, the caller stays parked indefinitely — the\n * TUI keeps rendering so the user can resolve whatever is blocking).\n *\n * If the program doesn't define a step with this ID, or the step\n * has no `gate` predicate, this returns an already-resolved promise\n * so bin.ts flows straight through. This lets programs opt in to\n * gates on a per-step basis without bin.ts needing to know which\n * gates exist in which flow.\n */\n getGate(stepId: string): Promise<void> {\n return this._gates.get(stepId)?.promise ?? Promise.resolve();\n }\n\n /**\n * Resolve once `predicate(session)` is true. Unlike a gate, this is created\n * at the await point and evaluated live against the current session, so it\n * never latches on a startup value — the orchestrator uses it to wait for a\n * decision (a project picked, a handoff acknowledged) without the \"true while\n * undecided\" trap that latched gate predicates have.\n */\n waitUntil(predicate: (session: WizardSession) => boolean): Promise<void> {\n if (predicate(this.session)) return Promise.resolve();\n return new Promise((resolve) => {\n const unsub = this.subscribe(() => {\n if (predicate(this.session)) {\n unsub();\n resolve();\n }\n });\n });\n }\n\n /**\n * Re-evaluate every gate predicate against the current session and\n * resolve any whose predicate now returns true. Called after every\n * emitChange(), so gates unblock as soon as the session mutation\n * that satisfies them lands. Gates only resolve once — a predicate\n * that goes true → false → true will NOT re-block a caller that\n * already awaited through.\n */\n private _checkGates(): void {\n for (const [, gate] of this._gates) {\n if (!gate.resolved && gate.predicate(this.session)) {\n gate.resolved = true;\n gate.resolve();\n }\n }\n }\n\n // ── State accessors (read from atoms) ────────────────────────────\n\n get session(): WizardSession {\n return this.$session.get();\n }\n\n set session(value: WizardSession) {\n this.$session.set(value);\n this.emitChange();\n }\n\n get statusMessages(): string[] {\n return this.$statusMessages.get();\n }\n\n get tasks(): TaskItem[] {\n return this.$tasks.get();\n }\n\n get eventPlan(): PlannedEvent[] {\n return this.$eventPlan.get();\n }\n\n get handoffText(): string | null {\n return this.$handoffText.get();\n }\n\n get currentStage(): { stage: string; startedAt: number } | null {\n return this.$currentStage.get();\n }\n\n /** No-op when the stage hasn't changed, so `startedAt` survives across\n * re-renders and tab switches and measures real stage time. */\n setCurrentStage(stage: string): void {\n const cur = this.$currentStage.get();\n if (cur?.stage === stage) return;\n this.$currentStage.set({ stage, startedAt: Date.now() });\n this.emitChange();\n }\n\n get statusExpanded(): boolean {\n return this.$statusExpanded.get();\n }\n\n toggleStatusExpanded(): void {\n this.$statusExpanded.set(!this.$statusExpanded.get());\n this.emitChange();\n }\n\n setStatusExpanded(expanded: boolean): void {\n if (this.$statusExpanded.get() !== expanded) {\n this.$statusExpanded.set(expanded);\n this.emitChange();\n }\n }\n\n // ── Session setters ─────────────────────────────────────────────\n // Every setter that affects screen resolution calls emitChange().\n // Business logic calls these instead of mutating session directly.\n\n /** Sets setupConfirmed, and is the point consent becomes final. */\n completeSetup(): void {\n this.$session.setKey('setupConfirmed', true);\n // Reports first: analytics merges tags into an event as it is sent, so\n // `setup confirmed` only carries the warehouse tags if they are already\n // set. On main they were, because reporting happened back in detect.\n this._markWarehouseSourcesReportedIfNeeded();\n analytics.wizardCapture('setup confirmed', sessionProperties(this.session));\n this.emitChange();\n }\n\n /**\n * Sharing is on: either the user turned it back on in the panel, or they\n * pressed Continue without ever touching it. Both are reversible until\n * completeSetup() resolves the intro gate and reports.\n */\n grantSharing(): void {\n this.$session.setKey('scanConsent', ScanConsent.Granted);\n this.emitChange();\n }\n\n /**\n * Sharing is off. Suppresses reporting only — local detection still ran and\n * the results stay in the session, so the outro suggestion and the warehouse\n * task are unaffected; see `scanConsent` on `WizardSession`.\n *\n * Deliberately does not report. The panel's toggle can come back here, so\n * marking the run reported would strand a user who turns sharing off and\n * then on again. completeSetup() owns the single report.\n */\n declineSharing(): void {\n this.$session.setKey('scanConsent', ScanConsent.Declined);\n this.emitChange();\n }\n\n /**\n * reportWarehouseSourcesDetected() is the single place scan results turn\n * into telemetry; this just supplies its idempotency flag via the normal\n * setter path (never mutate session directly). A no-op once\n * `warehouseSourcesReported` is set, or for any program that never\n * populated a warehouse-scan result in the first place.\n */\n private _markWarehouseSourcesReportedIfNeeded(): void {\n if (reportWarehouseSourcesDetected(this.session)) {\n this.$session.setKey('warehouseSourcesReported', true);\n }\n }\n\n setRunPhase(phase: RunPhase): void {\n this.$session.setKey('runPhase', phase);\n analytics.setTag('run_phase', phase);\n this.emitChange();\n }\n\n setCredentials(credentials: WizardSession['credentials']): void {\n this.$session.setKey('credentials', credentials);\n if (credentials?.projectId) {\n analytics.setTag('project_id', credentials.projectId);\n }\n analytics.wizardCapture('auth complete', {\n project_id: credentials?.projectId,\n });\n this.emitChange();\n }\n\n /** Post-refresh credential swap. No `auth complete` — see WizardUI. */\n setAccessToken(credentials: WizardSession['credentials']): void {\n this.$session.setKey('credentials', credentials);\n this.emitChange();\n }\n\n setRoleAtOrganization(role: string | null): void {\n this.$session.setKey('roleAtOrganization', role);\n this.emitChange();\n }\n\n setApiUser(user: WizardSession['apiUser']): void {\n this.$session.setKey('apiUser', user);\n this.emitChange();\n }\n\n setFrameworkConfig(\n integration: WizardSession['integration'],\n config: WizardSession['frameworkConfig'],\n ): void {\n this.$session.setKey('integration', integration);\n this.$session.setKey('frameworkConfig', config);\n this.$session.setKey('unsupportedVersion', null);\n if (integration) analytics.setTag('integration', integration);\n this.emitChange();\n }\n\n setDetectionComplete(): void {\n this.$session.setKey('detectionComplete', true);\n this.emitChange();\n }\n\n setDetectedFramework(label: string): void {\n this.$session.setKey('detectedFrameworkLabel', label);\n analytics.setTag('detected_framework', label);\n this.emitChange();\n }\n\n setPosthogSdkDetected(detected: boolean): void {\n this.$session.setKey('posthogSdkDetected', detected);\n this.emitChange();\n }\n\n setSpellbook(spellbook: NonNullable<WizardSession['spellbook']>): void {\n this.$session.setKey('spellbook', spellbook);\n this.emitChange();\n }\n\n setMintHandoff(action: NonNullable<WizardSession['mintHandoff']>): void {\n // The parked agent may still hold a question or notice open.\n this.cancelPendingQuestion();\n if (this.session.taskNotice) this.resolveTaskNotice(false);\n this.$session.setKey('mintHandoff', action);\n this.emitChange();\n }\n\n setSkillId(skillId: string | null): void {\n this.$session.setKey('skillId', skillId);\n this.emitChange();\n }\n\n setUnsupportedVersion(info: {\n current: string;\n minimum: string;\n docsUrl: string;\n }): void {\n this.$session.setKey('unsupportedVersion', info);\n this.emitChange();\n }\n\n setLoginUrl(url: string | null): void {\n this.$session.setKey('loginUrl', url);\n this.emitChange();\n }\n\n setAuthorizeUrl(url: string | null): void {\n this.$session.setKey('authorizeUrl', url);\n this.emitChange();\n }\n\n setReadinessResult(result: WizardReadinessResult | null): void {\n this.$session.setKey('readinessResult', result);\n if (result && result.decision === WizardReadiness.No) {\n captureHealthCheckBlocked(result);\n }\n this.emitChange();\n }\n\n /** User dismissed the blocking outage screen. Gate resolves via _checkGates(). */\n dismissOutage(): void {\n logToFile('[health-checks] user dismissed outage screen, continuing');\n this.$session.setKey('outageDismissed', true);\n this.emitChange();\n }\n\n /**\n * Push the settings-override overlay and return a promise that blocks\n * until the user dismisses it via backupAndFixSettingsOverride().\n */\n showSettingsOverride(\n conflicts: SettingsConflict[],\n backupAndFix: () => boolean,\n ): Promise<void> {\n const allKeys = conflicts.flatMap((c) => c.keys);\n this.$session.setKey('settingsOverrideKeys', allKeys);\n this.$session.setKey('settingsConflicts', conflicts);\n this._backupAndFixSettings = backupAndFix;\n\n const hasReadOnly = conflicts.some((c) => !c.writable);\n if (hasReadOnly) {\n this.pushOverlay(Overlay.ManagedSettings);\n } else {\n this.pushOverlay(Overlay.SettingsOverride);\n }\n\n return new Promise((resolve) => {\n this._resolveSettingsOverride = resolve;\n });\n }\n\n /**\n * Push the port-conflict overlay and return a promise that blocks\n * until the user frees the ports and retries, or exits.\n */\n showPortConflict(processInfo: {\n command: string;\n pid: string;\n port: number;\n user: string;\n }): Promise<void> {\n this.$session.setKey('portConflictProcess', processInfo);\n this.pushOverlay(Overlay.PortConflict);\n return new Promise((resolve) => {\n this._resolvePortConflict = resolve;\n });\n }\n\n /** Dismiss the port-conflict overlay and retry the OAuth port loop. */\n resolvePortConflict(): void {\n this.$session.setKey('portConflictProcess', null);\n this.popOverlay();\n this._resolvePortConflict?.();\n this._resolvePortConflict = null;\n }\n\n /**\n * Show an optional step's notice and return whether to keep that step.\n * Asked before the step runs, so nobody is surprised by a prompt mid-run.\n */\n showTaskNotice(notice: TaskNotice): Promise<boolean> {\n this.$session.setKey('taskNotice', notice);\n this.pushOverlay(Overlay.TaskNotice);\n return new Promise((resolve) => {\n this._resolveTaskNotice = resolve;\n });\n }\n\n /** Dismiss the notice, keeping (`true`) or skipping (`false`) the step. */\n resolveTaskNotice(keep: boolean): void {\n this.$session.setKey('taskNotice', null);\n this.popOverlay();\n this._resolveTaskNotice?.(keep);\n this._resolveTaskNotice = null;\n }\n\n /**\n * Return a promise that resolves when the user submits a manually-entered\n * OAuth code via the paste modal. The OAuth flow races this against the\n * local callback server — see `performOAuthFlow`.\n */\n waitForManualAuthCode(): Promise<string> {\n return new Promise<string>((resolve) => {\n this._resolveManualAuthCode = resolve;\n });\n }\n\n /** Open the manual OAuth code-entry overlay over the auth screen. */\n showManualAuthCode(): void {\n this.pushOverlay(Overlay.ManualAuthCode);\n }\n\n /** Dismiss the manual OAuth code overlay without submitting. */\n dismissManualAuthCode(): void {\n this.popOverlay();\n }\n\n /**\n * Submit a manually-entered authorization code: dismiss the overlay and\n * resolve the in-flight OAuth flow so it can exchange the code for a token.\n */\n submitManualAuthCode(code: string): void {\n this.popOverlay();\n this._resolveManualAuthCode?.(code);\n this._resolveManualAuthCode = null;\n }\n\n /**\n * Open the WizardAsk overlay with a set of questions and return a promise\n * that resolves once the user submits answers (or the request is cancelled).\n *\n * Only one request is in flight at a time — calling this while a request\n * is already pending throws.\n */\n requestQuestion(question: PendingQuestion): Promise<AskAnswers> {\n if (this._resolvePendingQuestion) {\n throw new Error(\n 'requestQuestion called while another wizard_ask request is pending',\n );\n }\n this.$session.setKey('pendingQuestion', question);\n this.pushOverlay(Overlay.WizardAsk);\n analytics.wizardCapture('wizard_ask shown', {\n source: question.source,\n question_count: question.questions.length,\n kinds: question.questions.map((q) => q.kind),\n });\n return new Promise<AskAnswers>((resolve) => {\n this._resolvePendingQuestion = resolve;\n });\n }\n\n /**\n * Resolve the in-flight wizard_ask request with the user's answers and\n * dismiss the overlay. Answers flow back to the agent as the tool result.\n */\n resolvePendingQuestion(answers: AskAnswers): void {\n const resolve = this._resolvePendingQuestion;\n this._resolvePendingQuestion = null;\n this.$session.setKey('pendingQuestion', null);\n this.popOverlay();\n resolve?.(answers);\n }\n\n /**\n * Cancel the in-flight wizard_ask request — the bridge sends a sentinel\n * answer (\"__cancelled__\") so the skill can decide how to handle it.\n */\n cancelPendingQuestion(): void {\n const pending = this.session.pendingQuestion;\n if (!pending) return;\n const cancelled: AskAnswers = {};\n for (const q of pending.questions) {\n cancelled[q.id] = '__cancelled__';\n }\n this.resolvePendingQuestion(cancelled);\n }\n\n /**\n * Back up .claude/settings.json. Dismisses the overlay on success.\n */\n backupAndFixSettingsOverride(): boolean {\n const ok = this._backupAndFixSettings?.() ?? false;\n if (ok) {\n this.$session.setKey('settingsOverrideKeys', null);\n this.$session.setKey('settingsConflicts', null);\n this.popOverlay();\n this._resolveSettingsOverride?.();\n this._resolveSettingsOverride = null;\n this._backupAndFixSettings = null;\n }\n return ok;\n }\n\n /** Push the auth-error overlay (no dismiss — user must exit). */\n showAuthError(detail?: AuthErrorDetail): void {\n this.$session.setKey('authErrorDetail', detail ?? null);\n this.pushOverlay(Overlay.AuthError);\n }\n\n /** Push the session-timeout overlay (no dismiss — user must exit). */\n showSessionTimeout(): void {\n this.pushOverlay(Overlay.SessionTimeout);\n }\n\n addDiscoveredFeature(feature: DiscoveredFeature): void {\n if (!this.session.discoveredFeatures.includes(feature)) {\n this.session.discoveredFeatures.push(feature);\n this.emitChange();\n }\n }\n\n /**\n * Enable an additional feature: enqueue it for the stop hook\n * and set any feature-specific session flags.\n */\n enableFeature(feature: AdditionalFeature): void {\n if (!this.session.additionalFeatureQueue.includes(feature)) {\n this.session.additionalFeatureQueue.push(feature);\n // Distinct key from `sessionProperties()`'s array-valued\n // `additional_features` — see the note in posthog-integration/detect.ts.\n analytics.setTag(\n 'additional_feature_kinds',\n this.session.additionalFeatureQueue.join(','),\n );\n }\n // Feature-specific flags\n if (feature === AdditionalFeature.LLM) {\n this.session.llmOptIn = true;\n }\n analytics.wizardCapture('feature enabled', { feature });\n this.emitChange();\n }\n\n setMcpComplete(\n outcome: McpOutcome = McpOutcome.Skipped,\n installedClients: string[] = [],\n featuresSelected?: 'all' | string[],\n loginCommands: string[] = [],\n ): void {\n this.$session.setKey('mcpComplete', true);\n this.$session.setKey('mcpOutcome', outcome);\n this.$session.setKey('mcpInstalledClients', installedClients);\n this.$session.setKey('mcpLoginCommands', loginCommands);\n const featuresPayload =\n outcome === McpOutcome.Installed && featuresSelected !== undefined\n ? { mcp_features_selected: featuresSelected }\n : {};\n analytics.wizardCapture('mcp complete', {\n mcp_outcome: outcome,\n mcp_installed_clients: installedClients,\n ...featuresPayload,\n ...sessionProperties(this.session),\n });\n this.emitChange();\n }\n\n setSkillsComplete(kept: boolean): void {\n this.$session.setKey('skillsComplete', true);\n analytics.wizardCapture('skills complete', {\n skills_kept: kept,\n ...sessionProperties(this.session),\n });\n this.emitChange();\n }\n\n setMcpSuggestedPromptsDismissed(): void {\n this.$session.setKey('mcpSuggestedPromptsDismissed', true);\n this.emitChange();\n }\n\n setSlackStepDismissed(): void {\n this.$session.setKey('slackStepDismissed', true);\n this.emitChange();\n }\n\n setSlackConnected(connected: boolean): void {\n this.$session.setKey('slackConnected', connected);\n this.emitChange();\n }\n\n setGithubConnected(connected: boolean): void {\n this.$session.setKey('githubConnected', connected);\n this.emitChange();\n }\n\n /**\n * Self-driving GitHub gate declined. Carries the outro the user lands on,\n * since declining ends the flow before the agent runs and there is no abort\n * case to render one.\n */\n declineGithub(outroData: OutroData): void {\n this.$session.setKey('githubDeclined', true);\n this.$session.setKey('outroData', outroData);\n this.emitChange();\n }\n\n /**\n * Self-driving integration-check answer. `true` → integrate the SDK as part\n * of this run; `false` → PostHog is already set up, go straight to\n * Self-driving. Resolves `session.integrate` from null.\n */\n setIntegrate(\n integrate: boolean,\n extra?: { via?: string; path?: string },\n ): void {\n this.$session.setKey('integrate', integrate);\n analytics.wizardCapture('self-driving integration check', {\n self_driving_integrate: integrate,\n ...(extra?.via ? { self_driving_integrate_via: extra.via } : {}),\n ...(extra?.path ? { self_driving_integrate_path: extra.path } : {}),\n ...sessionProperties(this.session),\n });\n this.emitChange();\n }\n\n /**\n * Self-driving \"no PostHog account\" branch of the integration check. The\n * project has no SDK, so we always integrate (`integrate = true`); and since\n * the user has no account, we flip `signup` and record the `email` / `region`\n * collected on the screen so `authenticate` → `getOrAskForProjectData` takes\n * the provisioning path (create account + email a login link) instead of\n * OAuth. The \"yes, I have an account\" branch uses `setIntegrate(true)` and\n * leaves `signup` false so auth runs the normal OAuth login.\n */\n chooseProvisionAccount(email: string, region: CloudRegion): void {\n this.$session.setKey('signup', true);\n this.$session.setKey('email', email);\n this.$session.setKey('region', region);\n this.$session.setKey('integrate', true);\n analytics.wizardCapture('self-driving integration check', {\n self_driving_integrate: true,\n self_driving_has_account: false,\n provision_region: region,\n ...sessionProperties(this.session),\n });\n this.emitChange();\n }\n\n /**\n * Self-driving handoff confirmed — the user acknowledged the post-integration\n * screen, so the Self-driving run can begin. Gate resolves via _checkGates().\n */\n confirmSelfDrivingHandoff(): void {\n this.$session.setKey('selfDrivingHandoffConfirmed', true);\n this.emitChange();\n }\n\n /**\n * Mark a composed run step complete (e.g. self-driving's `integrate-run`).\n * Records the step id so its `isComplete` predicate holds, clears the task\n * list, and resets run phase to Idle so the next run step starts fresh.\n */\n completeRunStep(stepId: string): void {\n const done = this.session.completedRuns;\n if (!done.includes(stepId)) {\n this.$session.setKey('completedRuns', [...done, stepId]);\n }\n this.$tasks.set([]);\n this.setRunPhase(RunPhase.Idle);\n }\n\n setOutroDismissed(dismissed = true): void {\n this.$session.setKey('outroDismissed', dismissed);\n this.emitChange();\n }\n\n setOutroData(data: OutroData): void {\n this.$session.setKey('outroData', data);\n this.emitChange();\n }\n\n setDashboardUrl(url: string): void {\n logToFile(`store.setDashboardUrl: ${url}`);\n this.$session.setKey('dashboardUrl', url);\n this.emitChange();\n }\n\n setNotebookUrl(url: string): void {\n logToFile(`store.setNotebookUrl: ${url}`);\n this.$session.setKey('notebookUrl', url);\n this.emitChange();\n }\n\n setFrameworkContext(key: string, value: unknown): void {\n const ctx = { ...this.$session.get().frameworkContext, [key]: value };\n this.$session.setKey('frameworkContext', ctx);\n this.emitChange();\n }\n\n switchProgram(program: ProgramId): void {\n if (program === this.router.activeProgram) return;\n\n // Flush unresolved promises so the wizard can advance\n for (const gate of this._gates.values()) gate.resolve();\n this._gates.clear();\n\n this.router.setProgram(program);\n this._initFromProgram(program);\n // start-tui stamps this once at launch; without it here every event\n // after the switch still reports under the program the run started as.\n analytics.setTag('program_id', program);\n\n const config = getProgramConfig(program);\n this.$session.setKey('setupConfirmed', false);\n this.$session.setKey('programLabel', config.id);\n this.$session.setKey('skillId', config.skillId ?? null);\n this.emitChange();\n }\n\n // ── Derived state ───────────────────────────────────────────────\n\n /**\n * The screen that should be rendered right now.\n * Derived from session state via the router.\n */\n get currentScreen(): ScreenName {\n return this.router.resolve(this.session);\n }\n\n /** Direction hint for screen transitions. */\n get lastNavDirection(): 'push' | 'pop' | null {\n return this.router.lastNavDirection;\n }\n\n // ── Change notification ─────────────────────────────────────────\n\n getVersion(): number {\n return this.$version.get();\n }\n\n /**\n * Notify React that state has changed.\n * The router re-resolves the active screen on next render.\n * Gate predicates are checked and resolved if ready.\n */\n emitChange(): void {\n this.router._setDirection('push');\n this.$version.set(this.$version.get() + 1);\n this._checkGates();\n this._detectTransition();\n }\n\n // ── Overlay navigation ──────────────────────────────────────────\n\n pushOverlay(overlay: Overlay): void {\n this.router._setDirection('push');\n this.router.pushOverlay(overlay);\n this.$version.set(this.$version.get() + 1);\n this._detectTransition();\n }\n\n popOverlay(): void {\n this.router._setDirection('pop');\n this.router.popOverlay();\n this.$version.set(this.$version.get() + 1);\n this._detectTransition();\n }\n\n // ── ScreenId transition analytics ─────────────────────────────────\n\n /**\n * Register a callback to run when transitioning onto the given screen.\n * Fires after every transition that lands on this screen.\n */\n onEnterScreen(screen: ScreenName, fn: () => void): void {\n const list = this._enterScreenHooks.get(screen) ?? [];\n list.push(fn);\n this._enterScreenHooks.set(screen, list);\n }\n\n /**\n * The program `screen` reports under — its step's `reportsAsProgramId` if it\n * claims one, else the running program (also the fallback for overlays and\n * screens with no owning step).\n */\n private _programIdForScreen(screen: ScreenName): ProgramId {\n const program = this.router.activeProgram;\n const step = getProgramConfig(program).steps.find(\n (s) => s.screenId === screen,\n );\n return step?.reportsAsProgramId ?? program;\n }\n\n /** The program the visible screen reports under; screens stamp this on their\n * own events rather than relying on the run-level `program_id` tag. */\n get analyticsProgramId(): ProgramId {\n return this._programIdForScreen(this.router.resolve(this.session));\n }\n\n /**\n * Detect screen transitions, run enter-screen hooks, and fire analytics.\n * Called at the end of emitChange/pushOverlay/popOverlay.\n */\n private _detectTransition(): void {\n const next = this.router.resolve(this.session);\n const prev = this._lastScreen;\n if (next !== prev) {\n // Every event carries the active TUI screen, filling the\n // \"URL / Screen\" column in PostHog.\n analytics.setTag('$screen_name', next);\n }\n if (prev !== null && next !== prev) {\n const hooks = this._enterScreenHooks.get(next);\n if (hooks) {\n for (const fn of hooks) fn();\n }\n analytics.wizardCapture(`screen ${next}`, {\n from_screen: prev,\n program_id: this._programIdForScreen(next),\n ...sessionProperties(this.session),\n });\n }\n this._lastScreen = next;\n }\n\n // ── Agent observation state ─────────────────────────────────────\n\n pushStatus(message: string): void {\n const msgs = this.$statusMessages.get();\n // Skip consecutive duplicate messages (no allocation on the hot path)\n if (msgs.length > 0 && msgs[msgs.length - 1] === message) return;\n // Nanostore detects change by reference equality, so a new array is\n // required. At the cap, allocate exactly once at the final size (dropping\n // the oldest entry) rather than push-then-truncate.\n const next =\n msgs.length >= MAX_STATUS_MESSAGES\n ? [...msgs.slice(msgs.length - MAX_STATUS_MESSAGES + 1), message]\n : [...msgs, message];\n this.$statusMessages.set(next);\n this.emitChange();\n }\n\n get tokenUsage(): TokenUsageSnapshot {\n return this.$tokenUsage.get();\n }\n\n get tokenHudVisible(): boolean {\n return this.$tokenHudVisible.get();\n }\n\n /** Hidden Ctrl+T shortcut — see ScreenContainer. Not registered as a\n * keyboard hint, so it never shows in the hints bar. */\n toggleTokenHud(): void {\n this.$tokenHudVisible.set(!this.$tokenHudVisible.get());\n this.emitChange();\n }\n\n /**\n * Accumulate one assistant turn's token usage into the running estimate.\n * Approximate by design (no dedup for SDK-retried/replayed turns, unlike\n * the benchmark middleware's TurnCounterPlugin) — it's a live indicator\n * for a hidden debug HUD, not a billing record, and `setFinalTokenCostUsd`\n * corrects the total once the run's authoritative cost is known.\n */\n addTokenUsage(delta: TokenUsageDelta): void {\n const cur = this.$tokenUsage.get();\n if (cur.costIsFinal) return;\n const deltaCostUsd = computeTokenCostUsd(delta);\n this.$tokenUsage.set({\n inputTokens: cur.inputTokens + delta.inputTokens,\n outputTokens: cur.outputTokens + delta.outputTokens,\n cacheReadTokens: cur.cacheReadTokens + delta.cacheReadTokens,\n cacheCreationTokens: cur.cacheCreationTokens + delta.cacheCreationTokens,\n costUsd: cur.costUsd + deltaCostUsd,\n costIsFinal: false,\n });\n this.emitChange();\n }\n\n /** Reconcile the running cost estimate to the SDK's authoritative total\n * once the agent run completes — same trick the benchmark's\n * CostTrackerPlugin.onFinalize uses to correct any per-turn drift. */\n setFinalTokenCostUsd(costUsd: number): void {\n const cur = this.$tokenUsage.get();\n this.$tokenUsage.set({ ...cur, costUsd, costIsFinal: true });\n this.emitChange();\n }\n\n setTasks(tasks: TaskItem[]): void {\n this.$tasks.set(tasks);\n this.emitChange();\n }\n\n updateTask(index: number, done: boolean): void {\n const tasks = this.$tasks.get();\n if (tasks[index]) {\n const updated = [...tasks];\n updated[index] = {\n ...updated[index],\n done,\n status: done ? TaskStatus.Completed : TaskStatus.Pending,\n };\n this.$tasks.set(updated);\n this.emitChange();\n }\n }\n\n setEventPlan(events: PlannedEvent[]): void {\n this.$eventPlan.set(events);\n this.emitChange();\n }\n\n /** No-op on identical text: an emit here means a network push downstream. */\n setHandoffText(text: string): void {\n if (this.$handoffText.get() === text) return;\n logToFile(`store.setHandoffText: ${text.length} chars`);\n this.$handoffText.set(text);\n this.emitChange();\n }\n\n get learnCardBlockIdx(): number {\n return this.$learnCardBlockIdx.get();\n }\n\n setLearnCardBlockIdx(idx: number): void {\n this.$learnCardBlockIdx.set(idx);\n }\n\n get learnCardComplete(): boolean {\n return this.$learnCardComplete.get();\n }\n\n setLearnCardComplete(): void {\n this.$learnCardComplete.set(true);\n this.emitChange();\n }\n\n syncTodos(\n todos: Array<{ content: string; status: string; activeForm?: string }>,\n ): void {\n const incoming = todos.map((t) => {\n const status = isTaskStatus(t.status) ? t.status : TaskStatus.Pending;\n return {\n label: t.content,\n activeForm: t.activeForm,\n status,\n done: status === TaskStatus.Completed,\n };\n });\n\n const incomingLabels = new Set(incoming.map((t) => t.label));\n\n const retained = this.$tasks\n .get()\n .filter((t) => t.done && !incomingLabels.has(t.label));\n\n this.$tasks.set([...retained, ...incoming]);\n this.emitChange();\n this._onTasksChanged?.();\n }\n\n /** Register a listener for task state changes (e.g. task stream push). */\n set onTasksChanged(fn: () => void) {\n this._onTasksChanged = fn;\n }\n\n // ── React integration ───────────────────────────────────────────\n\n subscribe(callback: () => void): () => void {\n return this.$version.listen(() => callback());\n }\n\n getSnapshot(): number {\n return this.$version.get();\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { s as logToFile } from "./debug-
|
|
1
|
+
import { s as logToFile } from "./debug-B4kzIZPi.js";
|
|
2
2
|
import { Type } from "typebox";
|
|
3
3
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
4
4
|
//#region src/lib/agent/runner/harness/pi/subagent.ts
|
|
@@ -105,4 +105,4 @@ function createDispatchAgentTool(ctx) {
|
|
|
105
105
|
//#endregion
|
|
106
106
|
export { createDispatchAgentTool };
|
|
107
107
|
|
|
108
|
-
//# sourceMappingURL=subagent-
|
|
108
|
+
//# sourceMappingURL=subagent-Dz41vV9j.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subagent-
|
|
1
|
+
{"version":3,"file":"subagent-Dz41vV9j.js","names":[],"sources":["../src/lib/agent/runner/harness/pi/subagent.ts"],"sourcesContent":["/**\n * Controlled subagent dispatch for pi (#526). pi has no native subagent\n * mechanism, so a subagent is a nested `createAgentSession` we construct — which\n * means WE decide its powers, closing the leak the claude-agent-sdk path warns\n * about (it can't propagate the parent's disallowedTools into subagents).\n *\n * Controls on every child:\n * - the SAME security extension (canUseTool + YARA, fail-closed) — shared state,\n * so the child shares the parent's tool-call cap and violation latch;\n * - a read-only built-in toolset (read/grep/find/ls + allowlisted bash) — no\n * write/edit, so a subagent can research but never mutate the project;\n * - no custom tools — no .env writes, and crucially no `dispatch_agent`, so a\n * child cannot recurse (depth is hard-capped at 1).\n */\n\nimport { Type } from 'typebox';\nimport { defineTool } from '@earendil-works/pi-coding-agent';\nimport type { ToolDefinition } from '@earendil-works/pi-coding-agent';\nimport { logToFile } from '@utils/debug';\n\n/**\n * Read-only built-ins a subagent may use. bash is supplied separately as the\n * parent's env-scrubbed tool (below), not the built-in, so a subagent's\n * subprocesses are locked down too.\n */\nconst SUBAGENT_TOOLS = ['read', 'grep', 'find', 'ls'];\n\nconst SUBAGENT_SYSTEM_PROMPT = [\n 'You are a read-only research subagent for the PostHog wizard.',\n 'You can read and search files and run safe build/inspect shell commands.',\n 'You cannot edit files, modify .env, or dispatch further subagents.',\n 'Investigate the task you are given and report concise findings as your final message.',\n].join('\\n');\n\nfunction text(s: string): {\n content: [{ type: 'text'; text: string }];\n details: unknown;\n} {\n return { content: [{ type: 'text', text: s }], details: {} };\n}\n\nfunction extractText(message: unknown): string {\n const content = (message as { content?: unknown })?.content;\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content\n .filter((c): c is { type: string; text: string } => {\n const b = c as { type?: string; text?: unknown };\n return b?.type === 'text' && typeof b.text === 'string';\n })\n .map((c) => c.text)\n .join('');\n }\n return '';\n}\n\nexport interface SubagentContext {\n /** Resolved gateway model (same as the parent). */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n model: import('@earendil-works/pi-ai').Model<any>;\n /** Registry holding the gateway provider. */\n modelRegistry: import('@earendil-works/pi-coding-agent').ModelRegistry;\n cwd: string;\n agentDir: string;\n /** The parent's security extension factory — reused so the fence is inherited. */\n securityFactory: (pi: unknown) => void;\n /** The parent's env-scrubbed bash, so a subagent's subprocesses are locked down too. */\n bashTool: ToolDefinition;\n /** pi SDK entrypoints, already imported by the backend. */\n sdk: {\n createAgentSession: typeof import('@earendil-works/pi-coding-agent')['createAgentSession'];\n DefaultResourceLoader: typeof import('@earendil-works/pi-coding-agent')['DefaultResourceLoader'];\n SessionManager: typeof import('@earendil-works/pi-coding-agent')['SessionManager'];\n };\n}\n\nexport function createDispatchAgentTool(ctx: SubagentContext): ToolDefinition {\n return defineTool({\n name: 'dispatch_agent',\n label: 'Dispatch subagent',\n description:\n 'Delegate a focused, read-only research subtask to a subagent (e.g. \"find where events are captured\"). The subagent can read/search files and run safe shell, but CANNOT edit files, change .env, or dispatch further subagents. Returns its findings.',\n promptSnippet:\n 'dispatch_agent(description, prompt) — delegate a read-only research subtask',\n parameters: Type.Object({\n description: Type.String({ description: 'Short label for the subtask' }),\n prompt: Type.String({ description: 'Full instruction for the subagent' }),\n }),\n // eslint-disable-next-line @typescript-eslint/require-await -- pi tool contract returns a Promise\n async execute(_id, args) {\n const { createAgentSession, DefaultResourceLoader, SessionManager } =\n ctx.sdk;\n\n const loader = new DefaultResourceLoader({\n cwd: ctx.cwd,\n agentDir: ctx.agentDir,\n systemPrompt: SUBAGENT_SYSTEM_PROMPT,\n noExtensions: true,\n noSkills: true,\n noContextFiles: true,\n noPromptTemplates: true,\n noThemes: true,\n extensionFactories: [ctx.securityFactory],\n });\n await loader.reload();\n\n const { session: child } = await createAgentSession({\n model: ctx.model,\n modelRegistry: ctx.modelRegistry,\n cwd: ctx.cwd,\n sessionManager: SessionManager.inMemory(ctx.cwd),\n resourceLoader: loader,\n tools: SUBAGENT_TOOLS, // read-only built-ins; no write/edit, no dispatch_agent\n customTools: [ctx.bashTool], // env-scrubbed bash only (still allowlist-fenced)\n });\n\n let result = '';\n const unsub = child.subscribe((e) => {\n if (e.type === 'message_end') {\n const t = extractText(e.message).trim();\n if (t) result = t;\n }\n });\n logToFile(`[pi] subagent dispatch: ${args.description}`);\n try {\n await child.prompt(args.prompt);\n } finally {\n unsub();\n }\n logToFile(`[pi] subagent \"${args.description}\" → ${result.length} chars`);\n return text(result || 'Subagent completed with no textual result.');\n },\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAM,iBAAiB;CAAC;CAAQ;CAAQ;CAAQ;CAAK;AAErD,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACD,CAAC,KAAK,KAAK;AAEZ,SAAS,KAAK,GAGZ;AACA,QAAO;EAAE,SAAS,CAAC;GAAE,MAAM;GAAQ,MAAM;GAAG,CAAC;EAAE,SAAS,EAAE;EAAE;;AAG9D,SAAS,YAAY,SAA0B;CAC7C,MAAM,UAAW,SAAmC;AACpD,KAAI,OAAO,YAAY,SAAU,QAAO;AACxC,KAAI,MAAM,QAAQ,QAAQ,CACxB,QAAO,QACJ,QAAQ,MAA2C;EAClD,MAAM,IAAI;AACV,SAAO,GAAG,SAAS,UAAU,OAAO,EAAE,SAAS;GAC/C,CACD,KAAK,MAAM,EAAE,KAAK,CAClB,KAAK,GAAG;AAEb,QAAO;;AAuBT,SAAgB,wBAAwB,KAAsC;AAC5E,QAAO,WAAW;EAChB,MAAM;EACN,OAAO;EACP,aACE;EACF,eACE;EACF,YAAY,KAAK,OAAO;GACtB,aAAa,KAAK,OAAO,EAAE,aAAa,+BAA+B,CAAC;GACxE,QAAQ,KAAK,OAAO,EAAE,aAAa,qCAAqC,CAAC;GAC1E,CAAC;EAEF,MAAM,QAAQ,KAAK,MAAM;GACvB,MAAM,EAAE,oBAAoB,uBAAuB,mBACjD,IAAI;GAEN,MAAM,SAAS,IAAI,sBAAsB;IACvC,KAAK,IAAI;IACT,UAAU,IAAI;IACd,cAAc;IACd,cAAc;IACd,UAAU;IACV,gBAAgB;IAChB,mBAAmB;IACnB,UAAU;IACV,oBAAoB,CAAC,IAAI,gBAAgB;IAC1C,CAAC;AACF,SAAM,OAAO,QAAQ;GAErB,MAAM,EAAE,SAAS,UAAU,MAAM,mBAAmB;IAClD,OAAO,IAAI;IACX,eAAe,IAAI;IACnB,KAAK,IAAI;IACT,gBAAgB,eAAe,SAAS,IAAI,IAAI;IAChD,gBAAgB;IAChB,OAAO;IACP,aAAa,CAAC,IAAI,SAAS;IAC5B,CAAC;GAEF,IAAI,SAAS;GACb,MAAM,QAAQ,MAAM,WAAW,MAAM;AACnC,QAAI,EAAE,SAAS,eAAe;KAC5B,MAAM,IAAI,YAAY,EAAE,QAAQ,CAAC,MAAM;AACvC,SAAI,EAAG,UAAS;;KAElB;AACF,aAAU,2BAA2B,KAAK,cAAc;AACxD,OAAI;AACF,UAAM,MAAM,OAAO,KAAK,OAAO;aACvB;AACR,WAAO;;AAET,aAAU,kBAAkB,KAAK,YAAY,MAAM,OAAO,OAAO,QAAQ;AACzE,UAAO,KAAK,UAAU,6CAA6C;;EAEtE,CAAC"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { s as REMARK_INSTRUCTION } from "./errors
|
|
2
|
-
import {
|
|
3
|
-
import { n as analytics } from "./analytics-
|
|
4
|
-
import { _ as buildGatewayProvider, g as GATEWAY_PROVIDER, m as assembleCommandments, p as AgentOutputSignals, v as withGatewayRemint } from "./agent-interface-
|
|
5
|
-
import { o as gatewayAuth } from "./gateway-session-
|
|
6
|
-
import {
|
|
7
|
-
import { c as createAioCapture, i as lastStatusLine, n as buildScrubbedEnv, o as withMode, r as extractText, s as runErrorType, t as applyOutroMarkers } from "./pi-
|
|
8
|
-
import { c as queueTools, l as renderToolInventory, r as allowsPostHogMcp } from "./agent-prompt-loader-
|
|
1
|
+
import { s as REMARK_INSTRUCTION } from "./errors-BoJvrdw8.js";
|
|
2
|
+
import { ht as WIZARD_USER_AGENT, p as getUI, pt as WIZARD_REMARK_EVENT_NAME, s as logToFile } from "./debug-B4kzIZPi.js";
|
|
3
|
+
import { n as analytics } from "./analytics-C67F2vee.js";
|
|
4
|
+
import { _ as buildGatewayProvider, g as GATEWAY_PROVIDER, m as assembleCommandments, p as AgentOutputSignals, v as withGatewayRemint } from "./agent-interface-Avtr_5M5.js";
|
|
5
|
+
import { o as gatewayAuth } from "./gateway-session-xPFv6p5c.js";
|
|
6
|
+
import { _ as TaskStatus } from "./queue-tools-C8y_xZJi.js";
|
|
7
|
+
import { c as createAioCapture, i as lastStatusLine, n as buildScrubbedEnv, o as withMode, r as extractText, s as runErrorType, t as applyOutroMarkers } from "./pi-mY8I2XkG.js";
|
|
8
|
+
import { c as queueTools, l as renderToolInventory, r as allowsPostHogMcp } from "./agent-prompt-loader-CHixNPgY.js";
|
|
9
9
|
//#region src/lib/agent/runner/harness/pi/task.ts
|
|
10
10
|
/**
|
|
11
11
|
* Orchestrator-mode execution on pi: one fresh pi session per unit of work —
|
|
@@ -146,19 +146,19 @@ async function runPiTask(inputs) {
|
|
|
146
146
|
message: "pi: gateway model could not be resolved"
|
|
147
147
|
};
|
|
148
148
|
const askState = { pending: false };
|
|
149
|
-
const { createSecurityExtension } = await import("./security-
|
|
149
|
+
const { createSecurityExtension } = await import("./security-Dw2oFJjP.js");
|
|
150
150
|
const security = createSecurityExtension({
|
|
151
151
|
disallowedTools: fenceDisallowList(disallowedTools),
|
|
152
152
|
triageProvider: boot.triageProvider,
|
|
153
153
|
getWizardAskPending: () => askState.pending
|
|
154
154
|
});
|
|
155
|
-
const { prewarmYaraScanner } = await import("./yara-hooks-
|
|
155
|
+
const { prewarmYaraScanner } = await import("./yara-hooks-CFY4pGcW.js");
|
|
156
156
|
prewarmYaraScanner();
|
|
157
157
|
const extensionFactories = [security.factory];
|
|
158
158
|
let mcpCleanup;
|
|
159
159
|
let posthogMcp = false;
|
|
160
160
|
if (allowsPostHogMcp(allowedTools)) try {
|
|
161
|
-
const { setupPostHogMcp } = await import("./mcp-
|
|
161
|
+
const { setupPostHogMcp } = await import("./mcp-Cbuw_xss.js");
|
|
162
162
|
const mcp = await setupPostHogMcp({
|
|
163
163
|
mcpUrl: boot.credentials.host.mcpUrl,
|
|
164
164
|
accessToken: boot.credentials.accessToken,
|
|
@@ -210,7 +210,7 @@ async function runPiTask(inputs) {
|
|
|
210
210
|
find: () => withMode(createFindToolDefinition(dir), "parallel"),
|
|
211
211
|
grep: () => withMode(createGrepToolDefinition(dir), "parallel")
|
|
212
212
|
}).filter(([name]) => codingTools.has(name)).map(([, make]) => make());
|
|
213
|
-
const { createWizardPiTools } = await import("./tools-
|
|
213
|
+
const { createWizardPiTools } = await import("./tools-Dp6i9k70.js");
|
|
214
214
|
const wizardToolNames = allowedPiWizardTools(allowedTools);
|
|
215
215
|
const wizardTools = createWizardPiTools({
|
|
216
216
|
workingDirectory: dir,
|
|
@@ -221,7 +221,7 @@ async function runPiTask(inputs) {
|
|
|
221
221
|
askState.pending = pending;
|
|
222
222
|
}
|
|
223
223
|
}).filter((t) => wizardToolNames.has(t.name));
|
|
224
|
-
const { createPiOrchestratorTools } = await import("./orchestrator-tools-
|
|
224
|
+
const { createPiOrchestratorTools } = await import("./orchestrator-tools-DXwr8Sp3.js");
|
|
225
225
|
const queueTools = createPiOrchestratorTools(orchestrator).filter((t) => orchestratorTools.has(t.name));
|
|
226
226
|
const customTools = [
|
|
227
227
|
...codingToolDefs,
|
|
@@ -344,4 +344,4 @@ async function runPiTask(inputs) {
|
|
|
344
344
|
//#endregion
|
|
345
345
|
export { runPiTask };
|
|
346
346
|
|
|
347
|
-
//# sourceMappingURL=task-
|
|
347
|
+
//# sourceMappingURL=task-5-fw_Vw3.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-D8sTR7jZ.js","names":[],"sources":["../src/lib/agent/runner/harness/pi/task.ts"],"sourcesContent":["/**\n * Orchestrator-mode execution on pi: one fresh pi session per unit of work —\n * the seed plan, or one drained task. The linear pipeline's concerns (skill\n * menu, todo panel, event-plan cleanup) stay in `index.ts`; this module builds\n * the leaner per-task session: gateway model, security fence, the task's\n * allowed coding tools, the wizard env tools, and the in-process orchestrator\n * queue tools.\n *\n * The task's `allowedTools` / `disallowedTools` arrive in the wizard's tool\n * vocabulary (`Read`, `Edit`, `Glob`, …, plus MCP-qualified orchestrator names\n * from `agentRunTools`). pi is where they become real: allowed names decide\n * which pi tool definitions get registered at all, and the disallow list is\n * ALSO handed to the security fence, so a name that never got registered stays\n * blocked even if the model hallucinates it.\n *\n * Loaded lazily from `index.ts` (typebox/ESM constraint, same as tools.ts).\n */\n\nimport { getUI } from '@ui';\nimport { logToFile } from '@utils/debug';\nimport { analytics } from '@utils/analytics';\nimport {\n Harness,\n Sequence,\n WIZARD_REMARK_EVENT_NAME,\n WIZARD_USER_AGENT,\n} from '@lib/constants';\nimport {\n allowsPostHogMcp,\n queueTools,\n renderToolInventory,\n} from '@lib/agent/agent-prompt-loader';\nimport { AgentErrorType } from '@lib/agent/agent-interface';\nimport { REMARK_INSTRUCTION } from '@lib/agent/signals';\nimport { AgentOutputSignals } from '@lib/agent/output-signals';\nimport { TaskStatus } from '../../sequence/orchestrator/queue';\nimport type { OrchestratorToolsContext } from '../../sequence/orchestrator/queue-tools';\nimport type { AgentResult, TaskRunInputs } from '../types';\nimport { gatewayAuth, type GatewayAuth } from '@lib/gateway-session';\nimport {\n buildGatewayProvider,\n GATEWAY_PROVIDER,\n withGatewayRemint,\n} from './gateway';\nimport { runErrorType } from './completion';\nimport { assembleCommandments } from '../../switchboard/commandments';\nimport {\n applyOutroMarkers,\n buildScrubbedEnv,\n extractText,\n lastStatusLine,\n withMode,\n} from './index';\nimport { createAioCapture } from '@lib/agent/aio-capture';\n\n/** wizard tool vocabulary → the pi tool definitions it unlocks. */\nconst CODING_TOOL_MAP: Record<string, readonly string[]> = {\n Read: ['read'],\n Edit: ['edit'],\n Write: ['write'],\n Bash: ['bash'],\n Glob: ['find', 'ls'],\n Grep: ['grep'],\n};\n\n/** `mcp__wizard-tools__wizard_ask` → `wizard_ask`; native names pass through. */\nfunction shortToolName(name: string): string {\n return name.replace(/^mcp__.+?__/, '');\n}\n\n/**\n * The pi coding tools a task may use. An empty allow list means \"no\n * restriction\" (mirrors the SDK), so every coding tool registers.\n */\nexport function allowedPiCodingTools(\n allowedTools: readonly string[] | undefined,\n): Set<string> {\n const allowed = (allowedTools ?? []).map(shortToolName);\n const names = allowed.length\n ? allowed.flatMap((name) => CODING_TOOL_MAP[name] ?? [])\n : Object.values(CODING_TOOL_MAP).flat();\n return new Set(names);\n}\n\n/**\n * The orchestrator queue tools this agent gets. Everything not disallowed:\n * the seed's frontmatter disallows `complete_task` (it is not a task), a\n * task's disallows `enqueue_task` (the seed owns the graph).\n */\nexport function allowedOrchestratorTools(\n disallowedTools: readonly string[] | undefined,\n): Set<string> {\n return new Set(queueTools(disallowedTools ?? []));\n}\n\n/**\n * The wizard tools a task gets. Four are always on — their handlers are fenced\n * and the coding tasks depend on them. The rest are opt-in per task through\n * its frontmatter: `wizard_ask` stops the run until a person answers, and the\n * skill-menu pair (`load_skill_menu`, `install_skill`) lets a task pull its\n * own skill variant.\n */\nconst ALWAYS_ON_WIZARD_TOOLS = [\n 'check_env_keys',\n 'set_env_values',\n 'detect_package_manager',\n 'publish_handoff',\n];\n\nconst OPT_IN_WIZARD_TOOLS = [\n 'wizard_ask',\n 'load_skill_menu',\n 'install_skill',\n // Audit programs only: they declare the ledger tools on `allowedTools`.\n 'audit_seed_checks',\n 'audit_add_checks',\n 'audit_resolve_checks',\n];\n\nexport function allowedPiWizardTools(\n allowedTools: readonly string[] | undefined,\n): Set<string> {\n const allowed = (allowedTools ?? []).map(shortToolName);\n return new Set([\n ...ALWAYS_ON_WIZARD_TOOLS,\n ...OPT_IN_WIZARD_TOOLS.filter((tool) => allowed.includes(tool)),\n ]);\n}\n\n/**\n * The disallow list for the security fence: the wizard-vocabulary names as\n * given (the fence translates pi built-ins to the same vocabulary) plus the\n * short names, so a disallowed orchestrator tool is blocked under the name pi\n * would call it by.\n */\nexport function fenceDisallowList(\n disallowedTools: readonly string[] | undefined,\n): string[] {\n const names = disallowedTools ?? [];\n return [...new Set([...names, ...names.map(shortToolName)])];\n}\n\n/** Nudges when the session returns without the work reaching a terminal state. */\nconst MAX_TASK_NUDGES = 3;\n\nconst TASK_NUDGE =\n 'You have not called complete_task yet. Finish your task now: if the work is done, call complete_task with your handoff; if it cannot be done, call it with status \"failed\" or \"not needed\" and say why.';\n\nconst SEED_NUDGE =\n 'The queue is still empty. Seed it now with enqueue_task calls for the task graph you planned.';\n\n/** Whether this unit of work has reached its terminal state. */\nfunction isSettled(ctx: OrchestratorToolsContext): boolean {\n if (!ctx.currentTaskId) {\n // The seed's job is a seeded queue, not a complete_task call.\n return ctx.store.list().length > 0;\n }\n const task = ctx.store.get(ctx.currentTaskId);\n return (\n !!task &&\n (task.status === TaskStatus.Done ||\n task.status === TaskStatus.Failed ||\n task.status === TaskStatus.Skipped)\n );\n}\n\nexport async function runPiTask(inputs: TaskRunInputs): Promise<AgentResult> {\n const {\n session,\n programConfig,\n boot,\n prompt,\n spinner,\n model: modelId,\n effort,\n allowedTools,\n disallowedTools,\n askBridge,\n orchestrator,\n spinnerMessage,\n successMessage,\n errorMessage,\n requestRemark,\n analyticsProperties,\n } = inputs;\n\n if (spinnerMessage) spinner.start(spinnerMessage);\n\n const capture = createAioCapture({\n enabled: session.captureAio,\n projectApiKey: boot.credentials.projectApiKey,\n apiHost: boot.credentials.host.apiHost,\n runTags: boot.wizardMetadata,\n });\n\n const startTime = Date.now();\n const signals = new AgentOutputSignals();\n let assistantTurns = 0;\n const runDurations = () => {\n const durationMs = Date.now() - startTime;\n return {\n duration_ms: durationMs,\n duration_seconds: Math.round(durationMs / 1000),\n };\n };\n // How this task run failed: the closed AgentErrorType it is about to return.\n // Without it every terminal path below — a security termination, a rate\n // limit, a gateway error — arrived as the same unlabelled event, so a task\n // agent that died could be counted but not diagnosed. A security stop is not\n // an error, hence \"failure mode\" over \"error\".\n //\n // Not `reason`: the linear sequence emits this same event with a `reason`\n // holding the agent's free-text [ABORT] string, and one property cannot be\n // both a closed enum and unbounded prose without making either unreadable.\n const captureAborted = (failureMode: AgentErrorType) =>\n analytics.wizardCapture('agent aborted', {\n failure_mode: failureMode,\n ...runDurations(),\n model: modelId,\n ...analyticsProperties,\n });\n\n try {\n const sdk = await import('@earendil-works/pi-coding-agent');\n const {\n createAgentSession,\n DefaultResourceLoader,\n SessionManager,\n AuthStorage,\n ModelRegistry,\n getAgentDir,\n createLsToolDefinition,\n createFindToolDefinition,\n createGrepToolDefinition,\n createBashToolDefinition,\n createReadToolDefinition,\n createEditToolDefinition,\n createWriteToolDefinition,\n } = sdk;\n\n const refreshAuth = () =>\n gatewayAuth(\n boot.credentials.host,\n boot.credentials.accessToken,\n boot.programId,\n );\n const auth = await refreshAuth();\n const providerInputs = (current: GatewayAuth) => ({\n gatewayUrl: current.gatewayUrl,\n accessToken: current.token,\n teamId: current.teamId,\n wizardMetadata: boot.wizardMetadata,\n wizardFlags: boot.wizardFlags,\n modelId,\n // Per-task agents own their effort via the prompt frontmatter, falling\n // back to the model table.\n effort,\n });\n const { provider, caps } = buildGatewayProvider(providerInputs(auth));\n const registry = ModelRegistry.inMemory(AuthStorage.create());\n registry.registerProvider(GATEWAY_PROVIDER, provider as never);\n const model = registry.find(GATEWAY_PROVIDER, modelId);\n if (!model) {\n return {\n error: AgentErrorType.API_ERROR,\n message: 'pi: gateway model could not be resolved',\n };\n }\n\n // Shared flag: true while a wizard_ask overlay is open. The ask tool sets\n // it (onAskPendingChange, below); the security fence reads it to pause\n // Write/Edit until the answer comes back. Wired the same way as the linear\n // pi run — without it the warehouse task could mutate files while its\n // credential prompt sits open (up to LONGER_ASK_TIMEOUT_MS).\n const askState = { pending: false };\n\n // The same fail-closed fence as the linear run, with the task's disallow\n // list layered in (both the wizard-vocabulary and pi-short names).\n const { createSecurityExtension } = await import('./security');\n const security = createSecurityExtension({\n disallowedTools: fenceDisallowList(disallowedTools),\n triageProvider: boot.triageProvider,\n getWizardAskPending: () => askState.pending,\n });\n const { prewarmYaraScanner } = await import('@lib/yara-hooks');\n void prewarmYaraScanner();\n\n // PostHog MCP, for the tasks whose prompt requests it. Tasks that never\n // asked skip the handshake and never see a posthog tool.\n const extensionFactories = [security.factory] as Array<\n (pi: unknown) => void\n >;\n let mcpCleanup: (() => void) | undefined;\n let posthogMcp = false;\n if (allowsPostHogMcp(allowedTools)) {\n try {\n const { setupPostHogMcp } = await import('./mcp');\n const mcp = await setupPostHogMcp({\n mcpUrl: boot.credentials.host.mcpUrl,\n accessToken: boot.credentials.accessToken,\n userAgent: WIZARD_USER_AGENT,\n });\n extensionFactories.push(mcp.extensionFactory);\n mcpCleanup = mcp.cleanup;\n posthogMcp = true;\n } catch (err) {\n // Silent here reads as a task failure minutes later: a task that asked\n // for this tool can only skip or fail without it.\n logToFile(`[pi-task] PostHog MCP setup skipped: ${String(err)}`);\n analytics.wizardCapture('mcp setup failed', {\n harness: 'pi',\n scope: 'task',\n error: String(err).slice(0, 300),\n });\n }\n }\n\n const codingTools = allowedPiCodingTools(allowedTools);\n const orchestratorTools = allowedOrchestratorTools(disallowedTools);\n\n const resourceLoader = new DefaultResourceLoader({\n cwd: session.installDir,\n agentDir: getAgentDir(),\n systemPrompt: assembleCommandments({\n program: programConfig.id,\n sequence: Sequence.orchestrator,\n harness: Harness.pi,\n caps: { bash: codingTools.has('bash'), posthogMcp },\n }),\n noExtensions: true,\n noSkills: true,\n noContextFiles: true,\n noPromptTemplates: true,\n noThemes: true,\n extensionFactories,\n });\n await resourceLoader.reload();\n\n // The task's coding tools, gated by its allow list. Reads and searches run\n // in parallel; mutating tools stay sequential. Bash subprocesses get the\n // scrubbed env, same as the linear run.\n const dir = session.installDir;\n const codingToolFactories = {\n read: () => withMode(createReadToolDefinition(dir), 'parallel'),\n edit: () => withMode(createEditToolDefinition(dir), 'sequential'),\n write: () => withMode(createWriteToolDefinition(dir), 'sequential'),\n bash: () =>\n withMode(\n createBashToolDefinition(dir, {\n spawnHook: (ctx) => ({ ...ctx, env: buildScrubbedEnv() }),\n }),\n 'sequential',\n ),\n ls: () => withMode(createLsToolDefinition(dir), 'parallel'),\n find: () => withMode(createFindToolDefinition(dir), 'parallel'),\n grep: () => withMode(createGrepToolDefinition(dir), 'parallel'),\n } as const;\n const codingToolDefs = Object.entries(codingToolFactories)\n .filter(([name]) => codingTools.has(name))\n .map(([, make]) => make());\n\n // Wizard env + package-manager tools are always on — their handlers are\n // fenced, and init/build tasks depend on them. publish_handoff rides\n // along (store-only handler) so the report task can publish the handoff.\n const { createWizardPiTools } = await import('./tools');\n const wizardToolNames = allowedPiWizardTools(allowedTools);\n const wizardTools = createWizardPiTools({\n workingDirectory: dir,\n skillsBaseUrl: boot.skillsBaseUrl,\n triageProvider: boot.triageProvider,\n // Present only for a task allowed to ask; without it wizard_ask errors\n // instead of hanging on a prompt nobody will ever see.\n askBridge,\n // Pause Write/Edit while the ask overlay is open (see askState above).\n onAskPendingChange: (pending) => {\n askState.pending = pending;\n },\n }).filter((t) => wizardToolNames.has(t.name));\n\n const { createPiOrchestratorTools } = await import('./orchestrator-tools');\n const queueTools = createPiOrchestratorTools(orchestrator).filter((t) =>\n orchestratorTools.has(t.name),\n );\n\n const customTools = [...codingToolDefs, ...wizardTools, ...queueTools];\n const { session: agentSession } = await createAgentSession({\n model,\n modelRegistry: registry,\n thinkingLevel: caps.thinkingLevel,\n cwd: dir,\n sessionManager: SessionManager.inMemory(dir),\n resourceLoader,\n noTools: 'builtin',\n customTools,\n });\n await agentSession.bindExtensions({});\n\n // A turn that ends on a 401 from an aged bearer re-mints once and\n // continues with the nudge the task would get anyway.\n const turns = withGatewayRemint({\n session: agentSession,\n registry,\n auth,\n refreshAuth,\n providerInputs,\n continueText: () =>\n orchestrator.currentTaskId ? TASK_NUDGE : SEED_NUDGE,\n onRemint: () => {\n logToFile('[pi-task] gateway token renewed after a 401; continuing');\n analytics.wizardCapture('gateway token reminted', { harness: 'pi' });\n },\n });\n\n // The one complete list: exactly the tools registered on this session, in\n // the names the agent will call them by. posthog_exec binds as an extension.\n const toolNames = [\n ...customTools.map((t) => t.name),\n ...(posthogMcp ? ['posthog_exec'] : []),\n ];\n logToFile(`[pi-task] tools passed to model: ${toolNames.join(', ')}`);\n const taskPrompt = `${prompt}\\n\\n${renderToolInventory(toolNames)}`;\n\n const unsubscribe = agentSession.subscribe((event) => {\n // Mirror the turn into AIO. No-op when --capture-aio is off. Runs\n // before the role guard so the module's own filter is authoritative.\n capture.captureFromPiMessageEndEvent(event);\n\n switch (event.type) {\n case 'message_end': {\n // User prompts also emit message_end; only assistant turns count.\n if ((event.message as { role?: string })?.role !== 'assistant') {\n break;\n }\n assistantTurns += 1;\n turns.noteAssistantTurn(event.message);\n const assistant = extractText(event.message).trim();\n if (assistant) {\n logToFile(`[pi-task] assistant: ${assistant.slice(0, 1000)}`);\n applyOutroMarkers(assistant);\n const statusText = lastStatusLine(assistant);\n if (statusText) {\n getUI().pushStatus(statusText);\n spinner.message(statusText);\n }\n for (const line of assistant.split('\\n')) signals.push(line);\n }\n break;\n }\n case 'tool_execution_start': {\n const args = JSON.stringify(event.args ?? {}).slice(0, 200);\n logToFile(`[pi-task] → ${event.toolName} ${args}`);\n break;\n }\n case 'tool_execution_end': {\n if (event.isError) {\n const detail =\n typeof event.result === 'string'\n ? event.result\n : JSON.stringify(event.result ?? '');\n logToFile(`[pi-task] ✗ ${event.toolName}: ${detail.slice(0, 300)}`);\n }\n break;\n }\n default:\n break;\n }\n });\n\n // Seed AIO capture with this task's prompt — includes any handoff data\n // from prior tasks (the orchestrator bakes it into the prompt string\n // before it reaches this call site).\n capture.setInitialPrompt(taskPrompt);\n\n try {\n await turns.prompt(taskPrompt);\n\n // pi's prompt() resolves the moment a turn carries no tool call — which\n // an agent mid-plan does emit. While the work has not reached its\n // terminal state (task not reported, seed queue still empty), nudge.\n let nudges = 0;\n while (\n nudges < MAX_TASK_NUDGES &&\n !security.state.criticalViolation &&\n !isSettled(orchestrator)\n ) {\n nudges += 1;\n logToFile(\n `[pi-task] completion guard: not settled, nudge ${nudges}/${MAX_TASK_NUDGES}`,\n );\n await turns.prompt(\n orchestrator.currentTaskId ? TASK_NUDGE : SEED_NUDGE,\n );\n }\n\n if (requestRemark && !security.state.criticalViolation) {\n try {\n await agentSession.prompt(REMARK_INSTRUCTION);\n } catch (err) {\n logToFile(`[pi-task] remark request failed: ${String(err)}`);\n }\n }\n } finally {\n unsubscribe();\n mcpCleanup?.();\n }\n\n if (security.state.criticalViolation) {\n spinner.stop('Security violation detected');\n logToFile(\n `[pi-task] terminated: YARA violation (blocked ${security.state.blockedCount} call(s))`,\n );\n captureAborted(AgentErrorType.YARA_VIOLATION);\n return { error: AgentErrorType.YARA_VIOLATION };\n }\n\n const remark = signals.remark();\n if (remark) {\n analytics.capture(WIZARD_REMARK_EVENT_NAME, { remark });\n }\n\n const stats = agentSession.getSessionStats();\n const durations = runDurations();\n analytics.wizardCapture('agent completed', {\n ...durations,\n model: modelId,\n num_turns: assistantTurns,\n input_tokens: stats.tokens.input,\n output_tokens: stats.tokens.output,\n cache_creation_input_tokens: stats.tokens.cacheWrite,\n cache_read_input_tokens: stats.tokens.cacheRead,\n ...analyticsProperties,\n });\n // Per-task usage on one parseable line so a run's per-task time and cost are\n // observable from the log, not only from analytics.\n const taskType =\n typeof (analyticsProperties as { task_type?: unknown })?.task_type ===\n 'string'\n ? (analyticsProperties as { task_type: string }).task_type\n : modelId;\n logToFile(\n `[pi-task] usage task=${taskType} model=${modelId} effort=${caps.thinkingLevel} dur=${durations.duration_seconds}s turns=${assistantTurns} in=${stats.tokens.input} out=${stats.tokens.output} cacheR=${stats.tokens.cacheRead} cacheW=${stats.tokens.cacheWrite}`,\n );\n if (successMessage) spinner.stop(successMessage);\n return {};\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n logToFile(`[pi-task] run error: ${message}`);\n if (errorMessage || spinnerMessage) {\n spinner.stop(errorMessage ?? 'Task failed');\n }\n const error = runErrorType(message);\n captureAborted(error);\n return { error, message };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"task-5-fw_Vw3.js","names":[],"sources":["../src/lib/agent/runner/harness/pi/task.ts"],"sourcesContent":["/**\n * Orchestrator-mode execution on pi: one fresh pi session per unit of work —\n * the seed plan, or one drained task. The linear pipeline's concerns (skill\n * menu, todo panel, event-plan cleanup) stay in `index.ts`; this module builds\n * the leaner per-task session: gateway model, security fence, the task's\n * allowed coding tools, the wizard env tools, and the in-process orchestrator\n * queue tools.\n *\n * The task's `allowedTools` / `disallowedTools` arrive in the wizard's tool\n * vocabulary (`Read`, `Edit`, `Glob`, …, plus MCP-qualified orchestrator names\n * from `agentRunTools`). pi is where they become real: allowed names decide\n * which pi tool definitions get registered at all, and the disallow list is\n * ALSO handed to the security fence, so a name that never got registered stays\n * blocked even if the model hallucinates it.\n *\n * Loaded lazily from `index.ts` (typebox/ESM constraint, same as tools.ts).\n */\n\nimport { getUI } from '@ui';\nimport { logToFile } from '@utils/debug';\nimport { analytics } from '@utils/analytics';\nimport {\n Harness,\n Sequence,\n WIZARD_REMARK_EVENT_NAME,\n WIZARD_USER_AGENT,\n} from '@lib/constants';\nimport {\n allowsPostHogMcp,\n queueTools,\n renderToolInventory,\n} from '@lib/agent/agent-prompt-loader';\nimport { AgentErrorType } from '@lib/agent/agent-interface';\nimport { REMARK_INSTRUCTION } from '@lib/agent/signals';\nimport { AgentOutputSignals } from '@lib/agent/output-signals';\nimport { TaskStatus } from '../../sequence/orchestrator/queue';\nimport type { OrchestratorToolsContext } from '../../sequence/orchestrator/queue-tools';\nimport type { AgentResult, TaskRunInputs } from '../types';\nimport { gatewayAuth, type GatewayAuth } from '@lib/gateway-session';\nimport {\n buildGatewayProvider,\n GATEWAY_PROVIDER,\n withGatewayRemint,\n} from './gateway';\nimport { runErrorType } from './completion';\nimport { assembleCommandments } from '../../switchboard/commandments';\nimport {\n applyOutroMarkers,\n buildScrubbedEnv,\n extractText,\n lastStatusLine,\n withMode,\n} from './index';\nimport { createAioCapture } from '@lib/agent/aio-capture';\n\n/** wizard tool vocabulary → the pi tool definitions it unlocks. */\nconst CODING_TOOL_MAP: Record<string, readonly string[]> = {\n Read: ['read'],\n Edit: ['edit'],\n Write: ['write'],\n Bash: ['bash'],\n Glob: ['find', 'ls'],\n Grep: ['grep'],\n};\n\n/** `mcp__wizard-tools__wizard_ask` → `wizard_ask`; native names pass through. */\nfunction shortToolName(name: string): string {\n return name.replace(/^mcp__.+?__/, '');\n}\n\n/**\n * The pi coding tools a task may use. An empty allow list means \"no\n * restriction\" (mirrors the SDK), so every coding tool registers.\n */\nexport function allowedPiCodingTools(\n allowedTools: readonly string[] | undefined,\n): Set<string> {\n const allowed = (allowedTools ?? []).map(shortToolName);\n const names = allowed.length\n ? allowed.flatMap((name) => CODING_TOOL_MAP[name] ?? [])\n : Object.values(CODING_TOOL_MAP).flat();\n return new Set(names);\n}\n\n/**\n * The orchestrator queue tools this agent gets. Everything not disallowed:\n * the seed's frontmatter disallows `complete_task` (it is not a task), a\n * task's disallows `enqueue_task` (the seed owns the graph).\n */\nexport function allowedOrchestratorTools(\n disallowedTools: readonly string[] | undefined,\n): Set<string> {\n return new Set(queueTools(disallowedTools ?? []));\n}\n\n/**\n * The wizard tools a task gets. Four are always on — their handlers are fenced\n * and the coding tasks depend on them. The rest are opt-in per task through\n * its frontmatter: `wizard_ask` stops the run until a person answers, and the\n * skill-menu pair (`load_skill_menu`, `install_skill`) lets a task pull its\n * own skill variant.\n */\nconst ALWAYS_ON_WIZARD_TOOLS = [\n 'check_env_keys',\n 'set_env_values',\n 'detect_package_manager',\n 'publish_handoff',\n];\n\nconst OPT_IN_WIZARD_TOOLS = [\n 'wizard_ask',\n 'load_skill_menu',\n 'install_skill',\n // Audit programs only: they declare the ledger tools on `allowedTools`.\n 'audit_seed_checks',\n 'audit_add_checks',\n 'audit_resolve_checks',\n];\n\nexport function allowedPiWizardTools(\n allowedTools: readonly string[] | undefined,\n): Set<string> {\n const allowed = (allowedTools ?? []).map(shortToolName);\n return new Set([\n ...ALWAYS_ON_WIZARD_TOOLS,\n ...OPT_IN_WIZARD_TOOLS.filter((tool) => allowed.includes(tool)),\n ]);\n}\n\n/**\n * The disallow list for the security fence: the wizard-vocabulary names as\n * given (the fence translates pi built-ins to the same vocabulary) plus the\n * short names, so a disallowed orchestrator tool is blocked under the name pi\n * would call it by.\n */\nexport function fenceDisallowList(\n disallowedTools: readonly string[] | undefined,\n): string[] {\n const names = disallowedTools ?? [];\n return [...new Set([...names, ...names.map(shortToolName)])];\n}\n\n/** Nudges when the session returns without the work reaching a terminal state. */\nconst MAX_TASK_NUDGES = 3;\n\nconst TASK_NUDGE =\n 'You have not called complete_task yet. Finish your task now: if the work is done, call complete_task with your handoff; if it cannot be done, call it with status \"failed\" or \"not needed\" and say why.';\n\nconst SEED_NUDGE =\n 'The queue is still empty. Seed it now with enqueue_task calls for the task graph you planned.';\n\n/** Whether this unit of work has reached its terminal state. */\nfunction isSettled(ctx: OrchestratorToolsContext): boolean {\n if (!ctx.currentTaskId) {\n // The seed's job is a seeded queue, not a complete_task call.\n return ctx.store.list().length > 0;\n }\n const task = ctx.store.get(ctx.currentTaskId);\n return (\n !!task &&\n (task.status === TaskStatus.Done ||\n task.status === TaskStatus.Failed ||\n task.status === TaskStatus.Skipped)\n );\n}\n\nexport async function runPiTask(inputs: TaskRunInputs): Promise<AgentResult> {\n const {\n session,\n programConfig,\n boot,\n prompt,\n spinner,\n model: modelId,\n effort,\n allowedTools,\n disallowedTools,\n askBridge,\n orchestrator,\n spinnerMessage,\n successMessage,\n errorMessage,\n requestRemark,\n analyticsProperties,\n } = inputs;\n\n if (spinnerMessage) spinner.start(spinnerMessage);\n\n const capture = createAioCapture({\n enabled: session.captureAio,\n projectApiKey: boot.credentials.projectApiKey,\n apiHost: boot.credentials.host.apiHost,\n runTags: boot.wizardMetadata,\n });\n\n const startTime = Date.now();\n const signals = new AgentOutputSignals();\n let assistantTurns = 0;\n const runDurations = () => {\n const durationMs = Date.now() - startTime;\n return {\n duration_ms: durationMs,\n duration_seconds: Math.round(durationMs / 1000),\n };\n };\n // How this task run failed: the closed AgentErrorType it is about to return.\n // Without it every terminal path below — a security termination, a rate\n // limit, a gateway error — arrived as the same unlabelled event, so a task\n // agent that died could be counted but not diagnosed. A security stop is not\n // an error, hence \"failure mode\" over \"error\".\n //\n // Not `reason`: the linear sequence emits this same event with a `reason`\n // holding the agent's free-text [ABORT] string, and one property cannot be\n // both a closed enum and unbounded prose without making either unreadable.\n const captureAborted = (failureMode: AgentErrorType) =>\n analytics.wizardCapture('agent aborted', {\n failure_mode: failureMode,\n ...runDurations(),\n model: modelId,\n ...analyticsProperties,\n });\n\n try {\n const sdk = await import('@earendil-works/pi-coding-agent');\n const {\n createAgentSession,\n DefaultResourceLoader,\n SessionManager,\n AuthStorage,\n ModelRegistry,\n getAgentDir,\n createLsToolDefinition,\n createFindToolDefinition,\n createGrepToolDefinition,\n createBashToolDefinition,\n createReadToolDefinition,\n createEditToolDefinition,\n createWriteToolDefinition,\n } = sdk;\n\n const refreshAuth = () =>\n gatewayAuth(\n boot.credentials.host,\n boot.credentials.accessToken,\n boot.programId,\n );\n const auth = await refreshAuth();\n const providerInputs = (current: GatewayAuth) => ({\n gatewayUrl: current.gatewayUrl,\n accessToken: current.token,\n teamId: current.teamId,\n wizardMetadata: boot.wizardMetadata,\n wizardFlags: boot.wizardFlags,\n modelId,\n // Per-task agents own their effort via the prompt frontmatter, falling\n // back to the model table.\n effort,\n });\n const { provider, caps } = buildGatewayProvider(providerInputs(auth));\n const registry = ModelRegistry.inMemory(AuthStorage.create());\n registry.registerProvider(GATEWAY_PROVIDER, provider as never);\n const model = registry.find(GATEWAY_PROVIDER, modelId);\n if (!model) {\n return {\n error: AgentErrorType.API_ERROR,\n message: 'pi: gateway model could not be resolved',\n };\n }\n\n // Shared flag: true while a wizard_ask overlay is open. The ask tool sets\n // it (onAskPendingChange, below); the security fence reads it to pause\n // Write/Edit until the answer comes back. Wired the same way as the linear\n // pi run — without it the warehouse task could mutate files while its\n // credential prompt sits open (up to LONGER_ASK_TIMEOUT_MS).\n const askState = { pending: false };\n\n // The same fail-closed fence as the linear run, with the task's disallow\n // list layered in (both the wizard-vocabulary and pi-short names).\n const { createSecurityExtension } = await import('./security');\n const security = createSecurityExtension({\n disallowedTools: fenceDisallowList(disallowedTools),\n triageProvider: boot.triageProvider,\n getWizardAskPending: () => askState.pending,\n });\n const { prewarmYaraScanner } = await import('@lib/yara-hooks');\n void prewarmYaraScanner();\n\n // PostHog MCP, for the tasks whose prompt requests it. Tasks that never\n // asked skip the handshake and never see a posthog tool.\n const extensionFactories = [security.factory] as Array<\n (pi: unknown) => void\n >;\n let mcpCleanup: (() => void) | undefined;\n let posthogMcp = false;\n if (allowsPostHogMcp(allowedTools)) {\n try {\n const { setupPostHogMcp } = await import('./mcp');\n const mcp = await setupPostHogMcp({\n mcpUrl: boot.credentials.host.mcpUrl,\n accessToken: boot.credentials.accessToken,\n userAgent: WIZARD_USER_AGENT,\n });\n extensionFactories.push(mcp.extensionFactory);\n mcpCleanup = mcp.cleanup;\n posthogMcp = true;\n } catch (err) {\n // Silent here reads as a task failure minutes later: a task that asked\n // for this tool can only skip or fail without it.\n logToFile(`[pi-task] PostHog MCP setup skipped: ${String(err)}`);\n analytics.wizardCapture('mcp setup failed', {\n harness: 'pi',\n scope: 'task',\n error: String(err).slice(0, 300),\n });\n }\n }\n\n const codingTools = allowedPiCodingTools(allowedTools);\n const orchestratorTools = allowedOrchestratorTools(disallowedTools);\n\n const resourceLoader = new DefaultResourceLoader({\n cwd: session.installDir,\n agentDir: getAgentDir(),\n systemPrompt: assembleCommandments({\n program: programConfig.id,\n sequence: Sequence.orchestrator,\n harness: Harness.pi,\n caps: { bash: codingTools.has('bash'), posthogMcp },\n }),\n noExtensions: true,\n noSkills: true,\n noContextFiles: true,\n noPromptTemplates: true,\n noThemes: true,\n extensionFactories,\n });\n await resourceLoader.reload();\n\n // The task's coding tools, gated by its allow list. Reads and searches run\n // in parallel; mutating tools stay sequential. Bash subprocesses get the\n // scrubbed env, same as the linear run.\n const dir = session.installDir;\n const codingToolFactories = {\n read: () => withMode(createReadToolDefinition(dir), 'parallel'),\n edit: () => withMode(createEditToolDefinition(dir), 'sequential'),\n write: () => withMode(createWriteToolDefinition(dir), 'sequential'),\n bash: () =>\n withMode(\n createBashToolDefinition(dir, {\n spawnHook: (ctx) => ({ ...ctx, env: buildScrubbedEnv() }),\n }),\n 'sequential',\n ),\n ls: () => withMode(createLsToolDefinition(dir), 'parallel'),\n find: () => withMode(createFindToolDefinition(dir), 'parallel'),\n grep: () => withMode(createGrepToolDefinition(dir), 'parallel'),\n } as const;\n const codingToolDefs = Object.entries(codingToolFactories)\n .filter(([name]) => codingTools.has(name))\n .map(([, make]) => make());\n\n // Wizard env + package-manager tools are always on — their handlers are\n // fenced, and init/build tasks depend on them. publish_handoff rides\n // along (store-only handler) so the report task can publish the handoff.\n const { createWizardPiTools } = await import('./tools');\n const wizardToolNames = allowedPiWizardTools(allowedTools);\n const wizardTools = createWizardPiTools({\n workingDirectory: dir,\n skillsBaseUrl: boot.skillsBaseUrl,\n triageProvider: boot.triageProvider,\n // Present only for a task allowed to ask; without it wizard_ask errors\n // instead of hanging on a prompt nobody will ever see.\n askBridge,\n // Pause Write/Edit while the ask overlay is open (see askState above).\n onAskPendingChange: (pending) => {\n askState.pending = pending;\n },\n }).filter((t) => wizardToolNames.has(t.name));\n\n const { createPiOrchestratorTools } = await import('./orchestrator-tools');\n const queueTools = createPiOrchestratorTools(orchestrator).filter((t) =>\n orchestratorTools.has(t.name),\n );\n\n const customTools = [...codingToolDefs, ...wizardTools, ...queueTools];\n const { session: agentSession } = await createAgentSession({\n model,\n modelRegistry: registry,\n thinkingLevel: caps.thinkingLevel,\n cwd: dir,\n sessionManager: SessionManager.inMemory(dir),\n resourceLoader,\n noTools: 'builtin',\n customTools,\n });\n await agentSession.bindExtensions({});\n\n // A turn that ends on a 401 from an aged bearer re-mints once and\n // continues with the nudge the task would get anyway.\n const turns = withGatewayRemint({\n session: agentSession,\n registry,\n auth,\n refreshAuth,\n providerInputs,\n continueText: () =>\n orchestrator.currentTaskId ? TASK_NUDGE : SEED_NUDGE,\n onRemint: () => {\n logToFile('[pi-task] gateway token renewed after a 401; continuing');\n analytics.wizardCapture('gateway token reminted', { harness: 'pi' });\n },\n });\n\n // The one complete list: exactly the tools registered on this session, in\n // the names the agent will call them by. posthog_exec binds as an extension.\n const toolNames = [\n ...customTools.map((t) => t.name),\n ...(posthogMcp ? ['posthog_exec'] : []),\n ];\n logToFile(`[pi-task] tools passed to model: ${toolNames.join(', ')}`);\n const taskPrompt = `${prompt}\\n\\n${renderToolInventory(toolNames)}`;\n\n const unsubscribe = agentSession.subscribe((event) => {\n // Mirror the turn into AIO. No-op when --capture-aio is off. Runs\n // before the role guard so the module's own filter is authoritative.\n capture.captureFromPiMessageEndEvent(event);\n\n switch (event.type) {\n case 'message_end': {\n // User prompts also emit message_end; only assistant turns count.\n if ((event.message as { role?: string })?.role !== 'assistant') {\n break;\n }\n assistantTurns += 1;\n turns.noteAssistantTurn(event.message);\n const assistant = extractText(event.message).trim();\n if (assistant) {\n logToFile(`[pi-task] assistant: ${assistant.slice(0, 1000)}`);\n applyOutroMarkers(assistant);\n const statusText = lastStatusLine(assistant);\n if (statusText) {\n getUI().pushStatus(statusText);\n spinner.message(statusText);\n }\n for (const line of assistant.split('\\n')) signals.push(line);\n }\n break;\n }\n case 'tool_execution_start': {\n const args = JSON.stringify(event.args ?? {}).slice(0, 200);\n logToFile(`[pi-task] → ${event.toolName} ${args}`);\n break;\n }\n case 'tool_execution_end': {\n if (event.isError) {\n const detail =\n typeof event.result === 'string'\n ? event.result\n : JSON.stringify(event.result ?? '');\n logToFile(`[pi-task] ✗ ${event.toolName}: ${detail.slice(0, 300)}`);\n }\n break;\n }\n default:\n break;\n }\n });\n\n // Seed AIO capture with this task's prompt — includes any handoff data\n // from prior tasks (the orchestrator bakes it into the prompt string\n // before it reaches this call site).\n capture.setInitialPrompt(taskPrompt);\n\n try {\n await turns.prompt(taskPrompt);\n\n // pi's prompt() resolves the moment a turn carries no tool call — which\n // an agent mid-plan does emit. While the work has not reached its\n // terminal state (task not reported, seed queue still empty), nudge.\n let nudges = 0;\n while (\n nudges < MAX_TASK_NUDGES &&\n !security.state.criticalViolation &&\n !isSettled(orchestrator)\n ) {\n nudges += 1;\n logToFile(\n `[pi-task] completion guard: not settled, nudge ${nudges}/${MAX_TASK_NUDGES}`,\n );\n await turns.prompt(\n orchestrator.currentTaskId ? TASK_NUDGE : SEED_NUDGE,\n );\n }\n\n if (requestRemark && !security.state.criticalViolation) {\n try {\n await agentSession.prompt(REMARK_INSTRUCTION);\n } catch (err) {\n logToFile(`[pi-task] remark request failed: ${String(err)}`);\n }\n }\n } finally {\n unsubscribe();\n mcpCleanup?.();\n }\n\n if (security.state.criticalViolation) {\n spinner.stop('Security violation detected');\n logToFile(\n `[pi-task] terminated: YARA violation (blocked ${security.state.blockedCount} call(s))`,\n );\n captureAborted(AgentErrorType.YARA_VIOLATION);\n return { error: AgentErrorType.YARA_VIOLATION };\n }\n\n const remark = signals.remark();\n if (remark) {\n analytics.capture(WIZARD_REMARK_EVENT_NAME, { remark });\n }\n\n const stats = agentSession.getSessionStats();\n const durations = runDurations();\n analytics.wizardCapture('agent completed', {\n ...durations,\n model: modelId,\n num_turns: assistantTurns,\n input_tokens: stats.tokens.input,\n output_tokens: stats.tokens.output,\n cache_creation_input_tokens: stats.tokens.cacheWrite,\n cache_read_input_tokens: stats.tokens.cacheRead,\n ...analyticsProperties,\n });\n // Per-task usage on one parseable line so a run's per-task time and cost are\n // observable from the log, not only from analytics.\n const taskType =\n typeof (analyticsProperties as { task_type?: unknown })?.task_type ===\n 'string'\n ? (analyticsProperties as { task_type: string }).task_type\n : modelId;\n logToFile(\n `[pi-task] usage task=${taskType} model=${modelId} effort=${caps.thinkingLevel} dur=${durations.duration_seconds}s turns=${assistantTurns} in=${stats.tokens.input} out=${stats.tokens.output} cacheR=${stats.tokens.cacheRead} cacheW=${stats.tokens.cacheWrite}`,\n );\n if (successMessage) spinner.stop(successMessage);\n return {};\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n logToFile(`[pi-task] run error: ${message}`);\n if (errorMessage || spinnerMessage) {\n spinner.stop(errorMessage ?? 'Task failed');\n }\n const error = runErrorType(message);\n captureAborted(error);\n return { error, message };\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { n as sanitizeErrorDetail } from "./errors
|
|
2
|
-
import { s as logToFile } from "./debug-
|
|
1
|
+
import { n as sanitizeErrorDetail } from "./errors-BoJvrdw8.js";
|
|
2
|
+
import { s as logToFile } from "./debug-B4kzIZPi.js";
|
|
3
3
|
import "./wizard-session-FSJCkTcP.js";
|
|
4
|
-
import { t as startFileWatcher } from "./file-watcher-
|
|
5
|
-
import { createFileDestination } from "./file-
|
|
6
|
-
import { PostHogDestination } from "./posthog-
|
|
4
|
+
import { t as startFileWatcher } from "./file-watcher-BPFazvG_.js";
|
|
5
|
+
import { createFileDestination } from "./file-BoD3REGB.js";
|
|
6
|
+
import { PostHogDestination } from "./posthog-Hc_-9wrr.js";
|
|
7
7
|
//#region src/lib/task-stream/event-plan-watcher.ts
|
|
8
8
|
const MAX_EVENT_PLAN_FILE_BYTES = 256 * 1024;
|
|
9
9
|
const MAX_EVENT_COUNT = 50;
|
|
@@ -330,4 +330,4 @@ var TaskStreamPush = class {
|
|
|
330
330
|
//#endregion
|
|
331
331
|
export { PostHogDestination, TaskStreamPush, createFileDestination };
|
|
332
332
|
|
|
333
|
-
//# sourceMappingURL=task-stream-
|
|
333
|
+
//# sourceMappingURL=task-stream-dVzl6b_q.js.map
|