@posthog/wizard 2.77.0 → 2.79.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/README.md +50 -26
- package/dist/{add-mcp-server-to-clients-BnRyE4pw.js → add-mcp-server-to-clients-amlJWW7W.js} +6 -5
- package/dist/{add-mcp-server-to-clients-BnRyE4pw.js.map → add-mcp-server-to-clients-amlJWW7W.js.map} +1 -1
- package/dist/agent-CNrEC-9v.js +3184 -0
- package/dist/agent-CNrEC-9v.js.map +1 -0
- package/dist/{agent-interface-Avtr_5M5.js → agent-interface-BXvmAm4c.js} +462 -385
- package/dist/agent-interface-BXvmAm4c.js.map +1 -0
- package/dist/{agent-prompt-loader-CHixNPgY.js → agent-prompt-loader-DiKUbhi_.js} +6 -6
- package/dist/agent-prompt-loader-DiKUbhi_.js.map +1 -0
- package/dist/analytics-DxwRi2Hf.js +2 -0
- package/dist/{analytics-C67F2vee.js → analytics-VRYdebXW.js} +10 -6
- package/dist/analytics-VRYdebXW.js.map +1 -0
- package/dist/{api-Dj1yabTj.js → api-DGuJTzjr.js} +4 -17
- package/dist/api-DGuJTzjr.js.map +1 -0
- package/dist/bin.js +415 -70
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-CWRYuLAn.js → bounded-fs-Cpn129A4.js} +4 -4
- package/dist/bounded-fs-Cpn129A4.js.map +1 -0
- package/dist/check-screens.tsx +1 -1
- package/dist/{ci-install-CvXL5h13.js → ci-install-BPA6gzEq.js} +6 -5
- package/dist/ci-install-BPA6gzEq.js.map +1 -0
- package/dist/constants-CuJfQEcC.js +260 -0
- package/dist/constants-CuJfQEcC.js.map +1 -0
- package/dist/{debug-CziFS0cA.js → debug-B9k4ideV.js} +1 -1
- package/dist/debug-Cj-8vfXY.js +171 -0
- package/dist/debug-Cj-8vfXY.js.map +1 -0
- package/dist/{defaults-4c4YwTmW.js → defaults-C6J7yL4O.js} +1 -1
- package/dist/{defaults-4c4YwTmW.js.map → defaults-C6J7yL4O.js.map} +1 -1
- package/dist/endpoints-DnIX0pZH.js +108 -0
- package/dist/endpoints-DnIX0pZH.js.map +1 -0
- package/dist/{env-api-key-BZ5wE3Y4.js → env-api-key-BWdKpGEr.js} +3 -3
- package/dist/env-api-key-BWdKpGEr.js.map +1 -0
- package/dist/{environment-BEvsey6i.js → environment-DZYUSCpV.js} +6 -6
- package/dist/environment-DZYUSCpV.js.map +1 -0
- package/dist/{errors-BoJvrdw8.js → errors-ddDE6MbA.js} +27 -76
- package/dist/errors-ddDE6MbA.js.map +1 -0
- package/dist/{file-BoD3REGB.js → file-dEhr-l3n.js} +3 -3
- package/dist/file-dEhr-l3n.js.map +1 -0
- package/dist/{file-watcher-BPFazvG_.js → file-watcher-CPM-Nn9L.js} +2 -2
- package/dist/{file-watcher-BPFazvG_.js.map → file-watcher-CPM-Nn9L.js.map} +1 -1
- package/dist/{gateway-session-xPFv6p5c.js → gateway-CVU1G0H3.js} +205 -20
- package/dist/gateway-CVU1G0H3.js.map +1 -0
- package/dist/generate-version.cjs +1 -1
- package/dist/{headless-ui-CsmQrDIl.js → headless-ui-pY2xB5ug.js} +13 -2
- package/dist/headless-ui-pY2xB5ug.js.map +1 -0
- package/dist/{interactive-Dej-sxvR.js → interactive-BOGlinZe.js} +2 -2
- package/dist/interactive-BOGlinZe.js.map +1 -0
- package/dist/{local-dev-DPZiIPCK.js → local-dev-McsurOC-.js} +2 -2
- package/dist/local-dev-McsurOC-.js.map +1 -0
- package/dist/logging-ui-CUxNYF2t.js +226 -0
- package/dist/logging-ui-CUxNYF2t.js.map +1 -0
- package/dist/mcp-JcsBBnWv.js +97 -0
- package/dist/mcp-JcsBBnWv.js.map +1 -0
- package/dist/{mcp-prompt-streaming-BU_kuur_.js → mcp-prompt-streaming-B-p_Pvb2.js} +7 -6
- package/dist/mcp-prompt-streaming-B-p_Pvb2.js.map +1 -0
- package/dist/{mint-failure-BrleGqMd.js → mint-failure-CZFZpHpW.js} +749 -130
- package/dist/mint-failure-CZFZpHpW.js.map +1 -0
- package/dist/models-DnAY67Lg.js +83 -0
- package/dist/models-DnAY67Lg.js.map +1 -0
- package/dist/{non-interactive-DcOjH2fw.js → non-interactive-DR1CWXY1.js} +3 -3
- package/dist/non-interactive-DR1CWXY1.js.map +1 -0
- package/dist/oauth-session-CQTFOk-I.js +74 -0
- package/dist/oauth-session-CQTFOk-I.js.map +1 -0
- package/dist/{orchestrator-tools-DXwr8Sp3.js → orchestrator-tools-CBdt-SXO.js} +4 -4
- package/dist/orchestrator-tools-CBdt-SXO.js.map +1 -0
- package/dist/{package-json-xt3eeyBI.js → package-json-DY70kkNp.js} +2 -2
- package/dist/package-json-DY70kkNp.js.map +1 -0
- package/dist/{pi-mY8I2XkG.js → pi-BtqcLX3y.js} +444 -81
- package/dist/pi-BtqcLX3y.js.map +1 -0
- package/dist/{playground-CDUUKLkC.js → playground-Dz-ZVjBk.js} +11 -7
- package/dist/playground-Dz-ZVjBk.js.map +1 -0
- package/dist/{posthog-Hc_-9wrr.js → posthog-6Uqw_Eux.js} +9 -4
- package/dist/posthog-6Uqw_Eux.js.map +1 -0
- package/dist/{provisioning-xfdjhFtA.js → provisioning-Zf7yPcEs.js} +6 -5
- package/dist/provisioning-Zf7yPcEs.js.map +1 -0
- package/dist/{queue-tools-C8y_xZJi.js → queue-tools-B7_aCyd-.js} +7 -86
- package/dist/queue-tools-B7_aCyd-.js.map +1 -0
- package/dist/{registry-DTmREJ-f.js → registry-B6iLGorH.js} +307 -48
- package/dist/registry-B6iLGorH.js.map +1 -0
- package/dist/run-agent-legacy-6WcYMaR9.js +3541 -0
- package/dist/run-agent-legacy-6WcYMaR9.js.map +1 -0
- package/dist/{security-Dw2oFJjP.js → security-lkBwWbrK.js} +17 -7
- package/dist/security-lkBwWbrK.js.map +1 -0
- package/dist/{setup-utils-fjJTBhaB.js → setup-utils-dCViCC6s.js} +47 -19
- package/dist/setup-utils-dCViCC6s.js.map +1 -0
- package/dist/smoke-test.sh +1 -1
- package/dist/{start-tui-UNe2xQ0U.js → start-tui-oCWMgsDP.js} +40 -46
- package/dist/start-tui-oCWMgsDP.js.map +1 -0
- package/dist/{steps-C2yqOk_h.js → steps-gx0Pq4I4.js} +7 -7
- package/dist/{steps-C2yqOk_h.js.map → steps-gx0Pq4I4.js.map} +1 -1
- package/dist/{store-Bic4Cr3L.js → store-xYy_6Ruv.js} +19 -29
- package/dist/store-xYy_6Ruv.js.map +1 -0
- package/dist/{subagent-Dz41vV9j.js → subagent-Bfy0sfhU.js} +8 -3
- package/dist/subagent-Bfy0sfhU.js.map +1 -0
- package/dist/{task-5-fw_Vw3.js → task-BOfw7GPc.js} +124 -36
- package/dist/task-BOfw7GPc.js.map +1 -0
- package/dist/{task-stream-dVzl6b_q.js → task-stream-kYlm9qd0.js} +47 -17
- package/dist/task-stream-kYlm9qd0.js.map +1 -0
- package/dist/{tasks-D1c2z1aw.js → tasks-Bbv_lOBG.js} +17 -13
- package/dist/tasks-Bbv_lOBG.js.map +1 -0
- package/dist/{telemetry-BRnxBRWK.js → telemetry-Bpv-Mh5B.js} +5 -5
- package/dist/telemetry-Bpv-Mh5B.js.map +1 -0
- package/dist/{terminal-9bvRa4Qt.js → terminal-D07EQ2y0.js} +41 -76
- package/dist/terminal-D07EQ2y0.js.map +1 -0
- package/dist/{tools-Dp6i9k70.js → tools-Cc41af5W.js} +11 -11
- package/dist/tools-Cc41af5W.js.map +1 -0
- package/dist/ui-CGXtC7Vn.js +15 -0
- package/dist/ui-CGXtC7Vn.js.map +1 -0
- package/dist/version-Cadof0Z_.js +6 -0
- package/dist/version-Cadof0Z_.js.map +1 -0
- package/dist/warlock-smoke-test.ts +2 -2
- package/dist/{wizard-abort-lE6umflt.js → wizard-abort-HDbP3YcS.js} +23 -20
- package/dist/wizard-abort-HDbP3YcS.js.map +1 -0
- package/dist/wizard-abort-Y-Ip2K4z.js +3 -0
- package/dist/{wizard-session-FSJCkTcP.js → wizard-session-2w4Ru-Wz.js} +12 -16
- package/dist/wizard-session-2w4Ru-Wz.js.map +1 -0
- package/dist/wizard-session-DGaUHOF3.js +2 -0
- package/dist/wizard-ui-DoyOZxK8.js +16 -0
- package/dist/wizard-ui-DoyOZxK8.js.map +1 -0
- package/dist/yara-hooks-B49RIk5d.js +2 -0
- package/dist/{yara-hooks-BTNJ6MGW.js → yara-hooks-DCfROpZt.js} +19 -68
- package/dist/yara-hooks-DCfROpZt.js.map +1 -0
- package/package.json +2 -1
- package/dist/agent-interface-Avtr_5M5.js.map +0 -1
- package/dist/agent-prompt-loader-CHixNPgY.js.map +0 -1
- package/dist/agent-runner-COOIUJCP.js +0 -6188
- package/dist/agent-runner-COOIUJCP.js.map +0 -1
- package/dist/analytics-C67F2vee.js.map +0 -1
- package/dist/analytics-CJA1uLlk.js +0 -2
- package/dist/api-Dj1yabTj.js.map +0 -1
- package/dist/bounded-fs-CWRYuLAn.js.map +0 -1
- package/dist/ci-install-CvXL5h13.js.map +0 -1
- package/dist/debug-B4kzIZPi.js +0 -754
- package/dist/debug-B4kzIZPi.js.map +0 -1
- package/dist/env-api-key-BZ5wE3Y4.js.map +0 -1
- package/dist/environment-BEvsey6i.js.map +0 -1
- package/dist/errors-BoJvrdw8.js.map +0 -1
- package/dist/file-BoD3REGB.js.map +0 -1
- package/dist/gateway-session-C118uACz.js +0 -2
- package/dist/gateway-session-xPFv6p5c.js.map +0 -1
- package/dist/headless-ui-CsmQrDIl.js.map +0 -1
- package/dist/interactive-Dej-sxvR.js.map +0 -1
- package/dist/local-dev-DPZiIPCK.js.map +0 -1
- package/dist/mcp-Cbuw_xss.js +0 -64
- package/dist/mcp-Cbuw_xss.js.map +0 -1
- package/dist/mcp-prompt-streaming-BU_kuur_.js.map +0 -1
- package/dist/mint-failure-BrleGqMd.js.map +0 -1
- package/dist/non-interactive-DcOjH2fw.js.map +0 -1
- package/dist/orchestrator-tools-DXwr8Sp3.js.map +0 -1
- package/dist/package-json-xt3eeyBI.js.map +0 -1
- package/dist/package-manager-DR23m5Jg.js +0 -290
- package/dist/package-manager-DR23m5Jg.js.map +0 -1
- package/dist/pi-mY8I2XkG.js.map +0 -1
- package/dist/playground-CDUUKLkC.js.map +0 -1
- package/dist/posthog-Hc_-9wrr.js.map +0 -1
- package/dist/provisioning-xfdjhFtA.js.map +0 -1
- package/dist/queue-tools-C8y_xZJi.js.map +0 -1
- package/dist/registry-DTmREJ-f.js.map +0 -1
- package/dist/security-Dw2oFJjP.js.map +0 -1
- package/dist/setup-utils-fjJTBhaB.js.map +0 -1
- package/dist/start-tui-UNe2xQ0U.js.map +0 -1
- package/dist/store-Bic4Cr3L.js.map +0 -1
- package/dist/subagent-Dz41vV9j.js.map +0 -1
- package/dist/task-5-fw_Vw3.js.map +0 -1
- package/dist/task-stream-dVzl6b_q.js.map +0 -1
- package/dist/tasks-D1c2z1aw.js.map +0 -1
- package/dist/telemetry-BRnxBRWK.js.map +0 -1
- package/dist/terminal-9bvRa4Qt.js.map +0 -1
- package/dist/tools-Dp6i9k70.js.map +0 -1
- package/dist/wizard-abort-CAcInAxg.js +0 -2
- package/dist/wizard-abort-lE6umflt.js.map +0 -1
- package/dist/wizard-session-CYvyYnti.js +0 -2
- package/dist/wizard-session-FSJCkTcP.js.map +0 -1
- package/dist/yara-hooks-BTNJ6MGW.js.map +0 -1
- package/dist/yara-hooks-CFY4pGcW.js +0 -2
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { n as __require } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { n as analytics } from "./analytics-
|
|
6
|
-
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
2
|
+
import { i as classifyAuthFailure } from "./errors-ddDE6MbA.js";
|
|
3
|
+
import { a as getLogFilePath, o as initLogFile, r as debug, s as logToFile, v as runtimeEnv } from "./debug-Cj-8vfXY.js";
|
|
4
|
+
import { Y as WIZARD_REMARK_EVENT_NAME, c as CONTEXT_MILL_URL, et as wizardUserAgentForProgram, o as AWS_SKILLS_BASE_URL } from "./constants-CuJfQEcC.js";
|
|
5
|
+
import { n as analytics } from "./analytics-VRYdebXW.js";
|
|
6
|
+
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-Cpn129A4.js";
|
|
7
|
+
import { t as registerCleanup } from "./wizard-abort-HDbP3YcS.js";
|
|
8
|
+
import { c as REMARK_INSTRUCTION, f as gatewayAuth, i as gatewayApiFor, l as RESUME_INSTRUCTION, n as buildGatewayModel, p as isPastRefresh, s as AgentSignals, u as buildWizardPropertiesBlob } from "./gateway-CVU1G0H3.js";
|
|
9
|
+
import { i as modelCapabilities, o as triageModelFor } from "./models-DnAY67Lg.js";
|
|
10
|
+
import { _ as coerceAuditChecks, h as AUDIT_CHECKS_FILE, l as prewarmYaraScanner, n as createPostToolUseYaraHooks, p as scanInstalledSkill, r as createPreToolUseYaraHooks } from "./yara-hooks-DCfROpZt.js";
|
|
11
|
+
import { l as buildOrchestratorTools, v as makeMutex, y as writeJsonAtomic } from "./queue-tools-B7_aCyd-.js";
|
|
11
12
|
import { createRequire } from "node:module";
|
|
12
13
|
import * as fs$1 from "fs";
|
|
13
14
|
import fs from "fs";
|
|
@@ -15,37 +16,60 @@ import path from "path";
|
|
|
15
16
|
import path$1 from "node:path";
|
|
16
17
|
import { spawnSync } from "node:child_process";
|
|
17
18
|
import { closeSync, constants, fchmodSync, lstatSync, openSync, renameSync, unlinkSync, writeSync } from "node:fs";
|
|
18
|
-
import { randomBytes } from "node:crypto";
|
|
19
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
19
20
|
import { z } from "zod";
|
|
21
|
+
import { randomUUID as randomUUID$1 } from "crypto";
|
|
20
22
|
import * as os from "os";
|
|
21
23
|
import { unzipSync } from "fflate";
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* Whether this run's OAuth grant is known to be dead.
|
|
26
|
-
*
|
|
27
|
-
* Process-global on purpose. A run has exactly one login, but the two sides of
|
|
28
|
-
* this fact are far apart: the pre-run refresh learns it in `authenticate.ts`,
|
|
29
|
-
* and the only consumer is the 401 handler inside the agent message loop, which
|
|
30
|
-
* holds no session. Threading it would mean a field on `AgentConfig` set at four
|
|
31
|
-
* `initializeAgent` call sites — and the session it would read from may be a
|
|
32
|
-
* shallow copy (`prepareRunSession`), so the value could be written to one
|
|
33
|
-
* object and read from another.
|
|
34
|
-
*
|
|
35
|
-
* A leaf module with no imports, so either side can depend on it without a cycle.
|
|
36
|
-
*/
|
|
37
|
-
let grantRevoked = false;
|
|
24
|
+
//#region src/agent/triage-provider.ts
|
|
25
|
+
const TRIAGE_MAX_TOKENS = 16384;
|
|
26
|
+
const TRIAGE_TIMEOUT_MS = 2e4;
|
|
38
27
|
/**
|
|
39
|
-
*
|
|
40
|
-
* the
|
|
41
|
-
*
|
|
28
|
+
* Triage provider for a harness. Auth is always explicit: every caller already
|
|
29
|
+
* holds the gateway url and the run's token, and reading them back out of
|
|
30
|
+
* ANTHROPIC_* made an unauthed provider silent — it returned undefined, the
|
|
31
|
+
* caller failed closed, and a clean first-party skill got deleted. A resolver
|
|
32
|
+
* is re-read on every call, so a run that re-mints mid-way scans with the
|
|
33
|
+
* current bearer rather than the one it started with.
|
|
42
34
|
*/
|
|
43
|
-
function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return
|
|
35
|
+
function createTriageLLMProvider(auth, harness) {
|
|
36
|
+
const resolveAuth = typeof auth === "function" ? auth : () => Promise.resolve(auth);
|
|
37
|
+
const modelId = triageModelFor(harness);
|
|
38
|
+
const { reasoning, thinkingLevel } = modelCapabilities(modelId);
|
|
39
|
+
logToFile(`[YARA] triage provider ready (model: ${modelId}, api: ${gatewayApiFor(modelId)})`);
|
|
40
|
+
return async (prompt) => {
|
|
41
|
+
const { completeSimple } = await import("@earendil-works/pi-ai");
|
|
42
|
+
const current = await resolveAuth();
|
|
43
|
+
const authToken = current.authToken;
|
|
44
|
+
const model = buildGatewayModel({
|
|
45
|
+
gatewayUrl: current.baseURL,
|
|
46
|
+
accessToken: authToken,
|
|
47
|
+
teamId: current.teamId,
|
|
48
|
+
wizardMetadata: current.wizardMetadata ?? {},
|
|
49
|
+
wizardFlags: current.wizardFlags ?? {},
|
|
50
|
+
modelId
|
|
51
|
+
});
|
|
52
|
+
const controller = new AbortController();
|
|
53
|
+
const timer = setTimeout(() => controller.abort(), TRIAGE_TIMEOUT_MS);
|
|
54
|
+
try {
|
|
55
|
+
const message = await completeSimple(model, { messages: [{
|
|
56
|
+
role: "user",
|
|
57
|
+
content: prompt,
|
|
58
|
+
timestamp: Date.now()
|
|
59
|
+
}] }, {
|
|
60
|
+
apiKey: authToken,
|
|
61
|
+
temperature: model.api === "anthropic-messages" ? 0 : void 0,
|
|
62
|
+
maxTokens: TRIAGE_MAX_TOKENS,
|
|
63
|
+
reasoning: reasoning && thinkingLevel !== "off" ? thinkingLevel : void 0,
|
|
64
|
+
signal: controller.signal
|
|
65
|
+
});
|
|
66
|
+
const text = message.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
67
|
+
if (message.stopReason === "error") logToFile(`[YARA] triage call failed on ${model.id}: ${message.errorMessage ?? "unknown"} — every flagged match will be acted on`);
|
|
68
|
+
return text;
|
|
69
|
+
} finally {
|
|
70
|
+
clearTimeout(timer);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
49
73
|
}
|
|
50
74
|
/** A scan retains at most this many distinct key names. */
|
|
51
75
|
const MAX_ENV_KEY_SET = 5e3;
|
|
@@ -172,7 +196,7 @@ function collectProjectEnvKeys(rootDir) {
|
|
|
172
196
|
return locations;
|
|
173
197
|
}
|
|
174
198
|
//#endregion
|
|
175
|
-
//#region src/utils/custom-headers.ts
|
|
199
|
+
//#region src/shared/utils/custom-headers.ts
|
|
176
200
|
/**
|
|
177
201
|
* Builds a list of custom headers for ANTHROPIC_CUSTOM_HEADERS.
|
|
178
202
|
*/
|
|
@@ -192,7 +216,7 @@ function createCustomHeaders() {
|
|
|
192
216
|
};
|
|
193
217
|
}
|
|
194
218
|
//#endregion
|
|
195
|
-
//#region src/
|
|
219
|
+
//#region src/agent/safe-tools.ts
|
|
196
220
|
const LINTING_TOOLS = [
|
|
197
221
|
"codespell",
|
|
198
222
|
"cspell",
|
|
@@ -330,7 +354,7 @@ const LINTING_TOOLS = [
|
|
|
330
354
|
"yamllint"
|
|
331
355
|
];
|
|
332
356
|
//#endregion
|
|
333
|
-
//#region src/
|
|
357
|
+
//#region src/agent/bash-fence.ts
|
|
334
358
|
/**
|
|
335
359
|
* Bash command fence: exact per-manager allowlists + shell-shape gates.
|
|
336
360
|
*
|
|
@@ -688,7 +712,7 @@ function evaluateBashCommand(rawCommand) {
|
|
|
688
712
|
return commandDecision(normalized);
|
|
689
713
|
}
|
|
690
714
|
//#endregion
|
|
691
|
-
//#region src/
|
|
715
|
+
//#region src/agent/wizard-ask-bridge.ts
|
|
692
716
|
/**
|
|
693
717
|
* WizardAskBridge — host-side promise broker for the `wizard_ask` MCP tool.
|
|
694
718
|
*
|
|
@@ -722,51 +746,78 @@ function isFullyCancelled(answers) {
|
|
|
722
746
|
}
|
|
723
747
|
function createWizardAskBridge(opts) {
|
|
724
748
|
const timeoutMs = opts.timeoutMs ?? 3e5;
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
opts.
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
const
|
|
745
|
-
const
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
749
|
+
const pendingQuestions = /* @__PURE__ */ new Map();
|
|
750
|
+
return {
|
|
751
|
+
getPendingQuestion: () => {
|
|
752
|
+
for (const pending of pendingQuestions.values()) return pending;
|
|
753
|
+
return null;
|
|
754
|
+
},
|
|
755
|
+
async request({ questions, subject }) {
|
|
756
|
+
if (opts.signal?.aborted) return {
|
|
757
|
+
answers: buildCancelledAnswers(questions),
|
|
758
|
+
timedOut: false
|
|
759
|
+
};
|
|
760
|
+
const pending = {
|
|
761
|
+
id: randomUUID$1(),
|
|
762
|
+
questions,
|
|
763
|
+
source: opts.getSource(),
|
|
764
|
+
richLinks: opts.richLinks ?? false,
|
|
765
|
+
askedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
766
|
+
};
|
|
767
|
+
pendingQuestions.set(pending.id, pending);
|
|
768
|
+
const startedAt = Date.now();
|
|
769
|
+
const controller = new AbortController();
|
|
770
|
+
let timer;
|
|
771
|
+
let timedOut = false;
|
|
772
|
+
let cancelForAbort;
|
|
773
|
+
const timeoutPromise = new Promise((resolve) => {
|
|
774
|
+
timer = setTimeout(() => {
|
|
775
|
+
timedOut = true;
|
|
776
|
+
resolve(buildCancelledAnswers(questions));
|
|
777
|
+
controller.abort();
|
|
778
|
+
}, timeoutMs);
|
|
752
779
|
});
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
780
|
+
const aborted = new Promise((resolve) => {
|
|
781
|
+
cancelForAbort = () => {
|
|
782
|
+
resolve(buildCancelledAnswers(questions));
|
|
783
|
+
controller.abort();
|
|
784
|
+
};
|
|
785
|
+
opts.signal?.addEventListener("abort", cancelForAbort, { once: true });
|
|
758
786
|
});
|
|
759
|
-
|
|
760
|
-
answers
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
787
|
+
try {
|
|
788
|
+
const answers = await Promise.race([
|
|
789
|
+
opts.showQuestion(pending, { signal: controller.signal }),
|
|
790
|
+
timeoutPromise,
|
|
791
|
+
aborted
|
|
792
|
+
]);
|
|
793
|
+
const durationMs = Date.now() - startedAt;
|
|
794
|
+
if (isFullyCancelled(answers)) analytics.wizardCapture("wizard_ask cancelled", {
|
|
795
|
+
source: pending.source,
|
|
796
|
+
subject,
|
|
797
|
+
question_count: questions.length,
|
|
798
|
+
duration_ms: durationMs,
|
|
799
|
+
timed_out: timedOut
|
|
800
|
+
});
|
|
801
|
+
else analytics.wizardCapture("wizard_ask answered", {
|
|
802
|
+
source: pending.source,
|
|
803
|
+
subject,
|
|
804
|
+
question_count: questions.length,
|
|
805
|
+
duration_ms: durationMs
|
|
806
|
+
});
|
|
807
|
+
return {
|
|
808
|
+
answers,
|
|
809
|
+
timedOut
|
|
810
|
+
};
|
|
811
|
+
} finally {
|
|
812
|
+
if (timer) clearTimeout(timer);
|
|
813
|
+
if (cancelForAbort) opts.signal?.removeEventListener("abort", cancelForAbort);
|
|
814
|
+
pendingQuestions.delete(pending.id);
|
|
815
|
+
}
|
|
765
816
|
}
|
|
766
|
-
}
|
|
817
|
+
};
|
|
767
818
|
}
|
|
768
819
|
//#endregion
|
|
769
|
-
//#region src/
|
|
820
|
+
//#region src/shared/fetch-retry.ts
|
|
770
821
|
/**
|
|
771
822
|
* One retry + failover policy for every critical-path fetch. GitHub is primary,
|
|
772
823
|
* AWS is the fallback. A status a retry can't heal (404, 403) spends no retry
|
|
@@ -879,13 +930,12 @@ async function fetchWithRetry(url, opts = {}) {
|
|
|
879
930
|
throw new Error(`fetch ${url} failed — ${failures.join(" | ")}`);
|
|
880
931
|
}
|
|
881
932
|
//#endregion
|
|
882
|
-
//#region src/
|
|
933
|
+
//#region src/shared/skill-menu.ts
|
|
883
934
|
/**
|
|
884
|
-
*
|
|
885
|
-
*
|
|
886
|
-
*
|
|
887
|
-
*
|
|
888
|
-
* cannot drift between harnesses.
|
|
935
|
+
* The skill menu: what context-mill publishes as `skill-menu.json` and how the
|
|
936
|
+
* wizard reads it. Skill-backed CLI commands, the family picker, the skill
|
|
937
|
+
* source screen and the agent's install path all resolve skills through this
|
|
938
|
+
* one fetch, so it lives in shared and depends on nothing in the agent.
|
|
889
939
|
*/
|
|
890
940
|
/** Expand a bundle entry into one entry per variant, so the menu reads the same whether a group ships bundled or as zips. */
|
|
891
941
|
function expandBundleEntry(entry) {
|
|
@@ -915,6 +965,15 @@ async function fetchSkillMenu(skillsBaseUrl, opts = {}) {
|
|
|
915
965
|
return null;
|
|
916
966
|
}
|
|
917
967
|
}
|
|
968
|
+
//#endregion
|
|
969
|
+
//#region src/agent/tools/tools.ts
|
|
970
|
+
/**
|
|
971
|
+
* Shared wizard-tool behavior — skill discovery/install, env-file helpers,
|
|
972
|
+
* the wizard_ask cap policy, secret-vault plumbing, and the audit ledger.
|
|
973
|
+
* One implementation consumed by both protocol facades: the MCP server
|
|
974
|
+
* (`./mcp`) and the pi-native tools (`harness/pi/tools.ts`) — tool behavior
|
|
975
|
+
* cannot drift between harnesses.
|
|
976
|
+
*/
|
|
918
977
|
/** Extract a zip buffer, refusing entries that escape destDir (zip-slip). */
|
|
919
978
|
function extractZipArchive(zip, destDir) {
|
|
920
979
|
const root = path.resolve(destDir);
|
|
@@ -1097,7 +1156,7 @@ const WIZARD_ASK_SUBJECT_DESCRIPTION = "Short, stable tag naming what this call
|
|
|
1097
1156
|
* server in `./mcp` and the pi-native mirror in `harness/pi/tools.ts`) so the
|
|
1098
1157
|
* batching and cancellation contract reads identically in both harnesses.
|
|
1099
1158
|
*/
|
|
1100
|
-
const WIZARD_ASK_TOOL_DESCRIPTION =
|
|
1159
|
+
const WIZARD_ASK_TOOL_DESCRIPTION = `Ask the user one or more structured questions and wait for their answers. Use this whenever you would otherwise inline a question in your text output. Batch every question about one subject into a single call (up to 12) rather than asking one at a time, and tag the call with \`subject\`. A subject needing more fields than one call carries — a connection form wider than the limit — is collected over consecutive calls reusing the same \`subject\`: that is expected, and is never a reason to abandon it for a link the user has to follow themselves. Walking a list — one call per data-warehouse source, one call per integration step — is expected and is never blocked, because the batching guard counts consecutive calls per subject. A fully cancelled or timed-out response does NOT count against the per-run cap, so nothing is wasted. When a field is not collected the result carries a \`cancelled\` object naming those question ids, whether the user dismissed the prompt or it timed out, and what to do next: read that instead of inspecting the answer values, and fall back gracefully (e.g. hand over a deep link) rather than re-asking.`;
|
|
1101
1160
|
/**
|
|
1102
1161
|
* Guidance returned with a `wizard_ask` result when the user dismissed the
|
|
1103
1162
|
* prompt. Shared by both harness facades, like the descriptions above.
|
|
@@ -1176,7 +1235,7 @@ function evaluateAskCap({ callCount, maxQuestions, subject, subjectRunLength, ad
|
|
|
1176
1235
|
reason: "adjacency",
|
|
1177
1236
|
subject,
|
|
1178
1237
|
subjectRunLength,
|
|
1179
|
-
message: `Not an error — this ask was not sent (a one-time nudge). You have sent ${subjectRunLength} wizard_ask calls in a row about the same subject (${subject === "(unspecified)" ? "they all declared no `subject`, so they count as one subject" : `they all used subject "${subject}"`}). Batch every question you still need for that subject into one call (up to
|
|
1238
|
+
message: `Not an error — this ask was not sent (a one-time nudge). You have sent ${subjectRunLength} wizard_ask calls in a row about the same subject (${subject === "(unspecified)" ? "they all declared no `subject`, so they count as one subject" : `they all used subject "${subject}"`}). Batch every question you still need for that subject into one call (up to 12 questions) and send wizard_ask again now. If your next questions are about something else — another data-warehouse source, another integration step — set a different \`subject\` on the call. Adjacency is counted per subject, so one call per source is never blocked, and you must not try to squeeze several sources into one 12-question call. Either way the next call is sent. Do not abandon the task, and do not fall back to browser setup because of this message.`
|
|
1180
1239
|
};
|
|
1181
1240
|
return { kind: "ok" };
|
|
1182
1241
|
}
|
|
@@ -1567,11 +1626,7 @@ const WIZARD_TOOL_NAMES = {
|
|
|
1567
1626
|
readHandoffs: `mcp__${SERVER_NAME}__read_handoffs`
|
|
1568
1627
|
};
|
|
1569
1628
|
//#endregion
|
|
1570
|
-
//#region src/
|
|
1571
|
-
/**
|
|
1572
|
-
* publish_handoff — the agent publishes the run's handoff doc (the report
|
|
1573
|
-
* markdown) in one explicit call, replacing the report file + watcher path.
|
|
1574
|
-
*/
|
|
1629
|
+
//#region src/agent/tools/handoff.ts
|
|
1575
1630
|
const MAX_HANDOFF_TEXT_CHARS = 64 * 1024;
|
|
1576
1631
|
const PUBLISH_HANDOFF_TOOL_NAME = "publish_handoff";
|
|
1577
1632
|
/** Shared between the MCP server and the pi facade so the contract can't drift. */
|
|
@@ -1637,7 +1692,7 @@ function writeHandoffFileAtomically(targetPath, text) {
|
|
|
1637
1692
|
};
|
|
1638
1693
|
}
|
|
1639
1694
|
}
|
|
1640
|
-
function publishHandoff(content) {
|
|
1695
|
+
function publishHandoff(content, emit) {
|
|
1641
1696
|
if (content.trim() === "") {
|
|
1642
1697
|
analytics.wizardCapture("handoff published", {
|
|
1643
1698
|
handoff_ok: false,
|
|
@@ -1650,7 +1705,10 @@ function publishHandoff(content) {
|
|
|
1650
1705
|
}
|
|
1651
1706
|
const truncated = content.length > MAX_HANDOFF_TEXT_CHARS;
|
|
1652
1707
|
const text = truncated ? content.slice(0, MAX_HANDOFF_TEXT_CHARS) : content;
|
|
1653
|
-
|
|
1708
|
+
emit?.({
|
|
1709
|
+
kind: "handoff",
|
|
1710
|
+
text
|
|
1711
|
+
});
|
|
1654
1712
|
const handoffOutputPath = runtimeEnv("POSTHOG_HANDOFF_OUTPUT_PATH");
|
|
1655
1713
|
let handoffOutputWritten;
|
|
1656
1714
|
let handoffOutputError;
|
|
@@ -1677,7 +1735,7 @@ function publishHandoff(content) {
|
|
|
1677
1735
|
};
|
|
1678
1736
|
}
|
|
1679
1737
|
//#endregion
|
|
1680
|
-
//#region src/
|
|
1738
|
+
//#region src/shared/secret-vault.ts
|
|
1681
1739
|
/**
|
|
1682
1740
|
* Session-scoped secret vault.
|
|
1683
1741
|
*
|
|
@@ -1697,7 +1755,7 @@ function createSecretVault() {
|
|
|
1697
1755
|
const store = /* @__PURE__ */ new Map();
|
|
1698
1756
|
return {
|
|
1699
1757
|
put(value, meta) {
|
|
1700
|
-
const ref = `${REF_PREFIX}${randomUUID()}`;
|
|
1758
|
+
const ref = `${REF_PREFIX}${randomUUID$1()}`;
|
|
1701
1759
|
store.set(ref, {
|
|
1702
1760
|
value,
|
|
1703
1761
|
meta: {
|
|
@@ -1724,7 +1782,7 @@ function createSecretVault() {
|
|
|
1724
1782
|
};
|
|
1725
1783
|
}
|
|
1726
1784
|
//#endregion
|
|
1727
|
-
//#region src/
|
|
1785
|
+
//#region src/agent/tools/mcp.ts
|
|
1728
1786
|
/**
|
|
1729
1787
|
* MCP facade over `./tools` — the unified in-process server the anthropic
|
|
1730
1788
|
* harness mounts. Declarations (zod schemas, descriptions) and the MCP result
|
|
@@ -1759,7 +1817,7 @@ async function getSDKModule$1() {
|
|
|
1759
1817
|
* Must be called asynchronously because the SDK is an ESM module loaded via dynamic import.
|
|
1760
1818
|
*/
|
|
1761
1819
|
async function createWizardToolsServer(options) {
|
|
1762
|
-
const { workingDirectory, detectPackageManager, skillsBaseUrl, askBridge, askMaxQuestions = 10, secretVault = createSecretVault(), orchestrator, triageProvider } = options;
|
|
1820
|
+
const { workingDirectory, detectPackageManager, skillsBaseUrl, askBridge, askMaxQuestions = 10, secretVault = createSecretVault(), orchestrator, triageProvider, emit } = options;
|
|
1763
1821
|
const { tool, createSdkMcpServer } = await getSDKModule$1();
|
|
1764
1822
|
const askAccounting = createAskAccounting(askMaxQuestions);
|
|
1765
1823
|
let cachedSkillMenu = {};
|
|
@@ -1961,7 +2019,7 @@ async function createWizardToolsServer(options) {
|
|
|
1961
2019
|
auditAddChecks,
|
|
1962
2020
|
auditResolveChecks,
|
|
1963
2021
|
tool("wizard_ask", WIZARD_ASK_TOOL_DESCRIPTION, {
|
|
1964
|
-
questions: z.array(askQuestionSchema).min(1).max(
|
|
2022
|
+
questions: z.array(askQuestionSchema).min(1).max(12),
|
|
1965
2023
|
subject: z.string().optional().describe(WIZARD_ASK_SUBJECT_DESCRIPTION)
|
|
1966
2024
|
}, async (args) => {
|
|
1967
2025
|
if (!askBridge) return {
|
|
@@ -2046,7 +2104,7 @@ async function createWizardToolsServer(options) {
|
|
|
2046
2104
|
}
|
|
2047
2105
|
}),
|
|
2048
2106
|
tool(PUBLISH_HANDOFF_TOOL_NAME, PUBLISH_HANDOFF_DESCRIPTION, { content: z.string().describe(PUBLISH_HANDOFF_CONTENT_DESCRIPTION) }, (args) => {
|
|
2049
|
-
const result = publishHandoff(args.content);
|
|
2107
|
+
const result = publishHandoff(args.content, emit);
|
|
2050
2108
|
logToFile(`publish_handoff: ${result.message}`);
|
|
2051
2109
|
return {
|
|
2052
2110
|
content: [{
|
|
@@ -2061,197 +2119,7 @@ async function createWizardToolsServer(options) {
|
|
|
2061
2119
|
});
|
|
2062
2120
|
}
|
|
2063
2121
|
//#endregion
|
|
2064
|
-
//#region src/
|
|
2065
|
-
/**
|
|
2066
|
-
* PostHog AI gateway provider spec for pi sessions, shared by the linear run
|
|
2067
|
-
* and the orchestrator's per-task runs so both speak to the gateway
|
|
2068
|
-
* identically: bearer auth, the wizard properties header, transport shape
|
|
2069
|
-
* inferred from the model id. The caller registers the spec on its own
|
|
2070
|
-
* (lazily imported, properly typed) pi ModelRegistry.
|
|
2071
|
-
*/
|
|
2072
|
-
/** Provider registered on the in-memory registry for this run. */
|
|
2073
|
-
const GATEWAY_PROVIDER = "posthog-gateway";
|
|
2074
|
-
/**
|
|
2075
|
-
* The gateway speaks two shapes on two endpoints: Anthropic models over
|
|
2076
|
-
* `anthropic-messages` (the SDK appends `/v1/messages`, so the base URL has no
|
|
2077
|
-
* `/v1`), and OpenAI-class models (`openai/gpt-5`, …) over an OpenAI shape at
|
|
2078
|
-
* `/v1/responses` or `/v1/chat/completions` (base URL keeps `/v1`). Infer the
|
|
2079
|
-
* shape from the model id so a pair's model selects the right transport.
|
|
2080
|
-
*
|
|
2081
|
-
* OpenAI models take the Responses API because OpenAI rejects function tools
|
|
2082
|
-
* combined with `reasoning_effort` on chat completions and every task sends both.
|
|
2083
|
-
*/
|
|
2084
|
-
function gatewayApiFor(modelId) {
|
|
2085
|
-
return modelId.startsWith("openai/") ? "openai-responses" : "anthropic-messages";
|
|
2086
|
-
}
|
|
2087
|
-
/**
|
|
2088
|
-
* Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path: one
|
|
2089
|
-
* `X-PostHog-Properties` JSON blob (Bedrock fallback is native, so no opt-in)
|
|
2090
|
-
* plus the 1M context beta, since pi otherwise runs at 200k and overflows on
|
|
2091
|
-
* larger projects (the post-run compaction failures).
|
|
2092
|
-
*/
|
|
2093
|
-
function buildGatewayHeaders(wizardMetadata, wizardFlags, teamId) {
|
|
2094
|
-
return {
|
|
2095
|
-
"anthropic-beta": "context-1m-2025-08-07",
|
|
2096
|
-
"X-PostHog-Properties": buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId)
|
|
2097
|
-
};
|
|
2098
|
-
}
|
|
2099
|
-
/**
|
|
2100
|
-
* One gateway model spec — the single description of how to reach a model on
|
|
2101
|
-
* the gateway. The provider spec below wraps it for pi's registry; one-shot
|
|
2102
|
-
* callers (scan triage) hand it straight to `completeSimple`.
|
|
2103
|
-
*/
|
|
2104
|
-
function buildGatewayModel(inputs) {
|
|
2105
|
-
const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId } = inputs;
|
|
2106
|
-
const api = gatewayApiFor(modelId);
|
|
2107
|
-
return {
|
|
2108
|
-
id: modelId,
|
|
2109
|
-
name: `${modelId} (PostHog Gateway)`,
|
|
2110
|
-
api,
|
|
2111
|
-
provider: GATEWAY_PROVIDER,
|
|
2112
|
-
baseUrl: api === "anthropic-messages" ? gatewayUrl : `${gatewayUrl}/v1`,
|
|
2113
|
-
reasoning: modelCapabilities(modelId).reasoning,
|
|
2114
|
-
input: ["text"],
|
|
2115
|
-
cost: {
|
|
2116
|
-
input: 0,
|
|
2117
|
-
output: 0,
|
|
2118
|
-
cacheRead: 0,
|
|
2119
|
-
cacheWrite: 0
|
|
2120
|
-
},
|
|
2121
|
-
contextWindow: 1e6,
|
|
2122
|
-
maxTokens: 64e3,
|
|
2123
|
-
headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId)
|
|
2124
|
-
};
|
|
2125
|
-
}
|
|
2126
|
-
/**
|
|
2127
|
-
* The provider object for `registry.registerProvider(GATEWAY_PROVIDER, …)`,
|
|
2128
|
-
* plus the derived traits the session setup needs (`caps.thinkingLevel`).
|
|
2129
|
-
*/
|
|
2130
|
-
function buildGatewayProvider(inputs) {
|
|
2131
|
-
const { gatewayUrl, accessToken, modelId, effort } = inputs;
|
|
2132
|
-
const api = gatewayApiFor(modelId);
|
|
2133
|
-
const tableCaps = modelCapabilities(modelId);
|
|
2134
|
-
const caps = effort && effort !== "off" && tableCaps.reasoning ? modelCapabilities(modelId, effort) : effort === "off" && tableCaps.reasoning ? {
|
|
2135
|
-
...tableCaps,
|
|
2136
|
-
thinkingLevel: "off"
|
|
2137
|
-
} : tableCaps;
|
|
2138
|
-
const model = buildGatewayModel(inputs);
|
|
2139
|
-
return {
|
|
2140
|
-
provider: {
|
|
2141
|
-
name: "PostHog Gateway",
|
|
2142
|
-
baseUrl: model.baseUrl,
|
|
2143
|
-
apiKey: accessToken,
|
|
2144
|
-
authHeader: true,
|
|
2145
|
-
api,
|
|
2146
|
-
headers: model.headers,
|
|
2147
|
-
models: [model]
|
|
2148
|
-
},
|
|
2149
|
-
api,
|
|
2150
|
-
caps,
|
|
2151
|
-
gatewayUrl,
|
|
2152
|
-
baseUrl: model.baseUrl
|
|
2153
|
-
};
|
|
2154
|
-
}
|
|
2155
|
-
/**
|
|
2156
|
-
* Whether a turn's error is the gateway rejecting the bearer. pi attaches the
|
|
2157
|
-
* SDK's own error to `diagnostics`, so its code decides when one is present.
|
|
2158
|
-
* The message match is the fallback for a turn that failed before pi built a
|
|
2159
|
-
* diagnostic, where the status survives only as prose.
|
|
2160
|
-
*/
|
|
2161
|
-
function isGatewayAuthRejection(turn) {
|
|
2162
|
-
const { errorMessage, diagnostics } = typeof turn === "string" ? {
|
|
2163
|
-
errorMessage: turn,
|
|
2164
|
-
diagnostics: void 0
|
|
2165
|
-
} : turn ?? {};
|
|
2166
|
-
for (const diagnostic of diagnostics ?? []) {
|
|
2167
|
-
const code = diagnostic.error?.code;
|
|
2168
|
-
if (code === 401 || code === "401") return true;
|
|
2169
|
-
if (/^authentication_?error$/i.test(diagnostic.error?.name ?? "")) return true;
|
|
2170
|
-
}
|
|
2171
|
-
return /\b401\b|authentication_error|unauthorized/i.test(errorMessage ?? "");
|
|
2172
|
-
}
|
|
2173
|
-
/**
|
|
2174
|
-
* Wraps a pi session's prompt(): when a turn ends on a 401 from a bearer past
|
|
2175
|
-
* its refresh instant, mint once, re-register the provider with the new
|
|
2176
|
-
* bearer (pi resolves the apiKey per request), and continue. A 401 on a fresh
|
|
2177
|
-
* bearer, or a second one, is left to the harness's normal failure path.
|
|
2178
|
-
*/
|
|
2179
|
-
function withGatewayRemint(opts) {
|
|
2180
|
-
let auth = opts.auth;
|
|
2181
|
-
let rejected = false;
|
|
2182
|
-
let reminted = false;
|
|
2183
|
-
return {
|
|
2184
|
-
noteAssistantTurn(message) {
|
|
2185
|
-
const turn = message;
|
|
2186
|
-
rejected = turn?.stopReason === "error" && isGatewayAuthRejection(turn);
|
|
2187
|
-
},
|
|
2188
|
-
async prompt(text) {
|
|
2189
|
-
rejected = false;
|
|
2190
|
-
await opts.session.prompt(text);
|
|
2191
|
-
if (!rejected || reminted || !isPastRefresh(auth)) return;
|
|
2192
|
-
reminted = true;
|
|
2193
|
-
auth = await opts.refreshAuth();
|
|
2194
|
-
opts.registry.registerProvider(GATEWAY_PROVIDER, buildGatewayProvider(opts.providerInputs(auth)).provider);
|
|
2195
|
-
opts.onRemint?.();
|
|
2196
|
-
rejected = false;
|
|
2197
|
-
const next = opts.continueText;
|
|
2198
|
-
await opts.session.prompt(typeof next === "function" ? next() : next);
|
|
2199
|
-
}
|
|
2200
|
-
};
|
|
2201
|
-
}
|
|
2202
|
-
//#endregion
|
|
2203
|
-
//#region src/lib/agent/triage-provider.ts
|
|
2204
|
-
const TRIAGE_MAX_TOKENS = 16384;
|
|
2205
|
-
const TRIAGE_TIMEOUT_MS = 2e4;
|
|
2206
|
-
/**
|
|
2207
|
-
* Triage provider for a harness. Auth is always explicit: every caller already
|
|
2208
|
-
* holds the gateway url and the run's token, and reading them back out of
|
|
2209
|
-
* ANTHROPIC_* made an unauthed provider silent — it returned undefined, the
|
|
2210
|
-
* caller failed closed, and a clean first-party skill got deleted. A resolver
|
|
2211
|
-
* is re-read on every call, so a run that re-mints mid-way scans with the
|
|
2212
|
-
* current bearer rather than the one it started with.
|
|
2213
|
-
*/
|
|
2214
|
-
function createTriageLLMProvider(auth, harness) {
|
|
2215
|
-
const resolveAuth = typeof auth === "function" ? auth : () => Promise.resolve(auth);
|
|
2216
|
-
const modelId = triageModelFor(harness);
|
|
2217
|
-
const { reasoning, thinkingLevel } = modelCapabilities(modelId);
|
|
2218
|
-
logToFile(`[YARA] triage provider ready (model: ${modelId}, api: ${gatewayApiFor(modelId)})`);
|
|
2219
|
-
return async (prompt) => {
|
|
2220
|
-
const { completeSimple } = await import("@earendil-works/pi-ai");
|
|
2221
|
-
const current = await resolveAuth();
|
|
2222
|
-
const authToken = current.authToken;
|
|
2223
|
-
const model = buildGatewayModel({
|
|
2224
|
-
gatewayUrl: current.baseURL,
|
|
2225
|
-
accessToken: authToken,
|
|
2226
|
-
teamId: current.teamId,
|
|
2227
|
-
wizardMetadata: current.wizardMetadata ?? {},
|
|
2228
|
-
wizardFlags: current.wizardFlags ?? {},
|
|
2229
|
-
modelId
|
|
2230
|
-
});
|
|
2231
|
-
const controller = new AbortController();
|
|
2232
|
-
const timer = setTimeout(() => controller.abort(), TRIAGE_TIMEOUT_MS);
|
|
2233
|
-
try {
|
|
2234
|
-
const message = await completeSimple(model, { messages: [{
|
|
2235
|
-
role: "user",
|
|
2236
|
-
content: prompt,
|
|
2237
|
-
timestamp: Date.now()
|
|
2238
|
-
}] }, {
|
|
2239
|
-
apiKey: authToken,
|
|
2240
|
-
temperature: model.api === "anthropic-messages" ? 0 : void 0,
|
|
2241
|
-
maxTokens: TRIAGE_MAX_TOKENS,
|
|
2242
|
-
reasoning: reasoning && thinkingLevel !== "off" ? thinkingLevel : void 0,
|
|
2243
|
-
signal: controller.signal
|
|
2244
|
-
});
|
|
2245
|
-
const text = message.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
2246
|
-
if (message.stopReason === "error") logToFile(`[YARA] triage call failed on ${model.id}: ${message.errorMessage ?? "unknown"} — every flagged match will be acted on`);
|
|
2247
|
-
return text;
|
|
2248
|
-
} finally {
|
|
2249
|
-
clearTimeout(timer);
|
|
2250
|
-
}
|
|
2251
|
-
};
|
|
2252
|
-
}
|
|
2253
|
-
//#endregion
|
|
2254
|
-
//#region src/lib/agent/commandments.ts
|
|
2122
|
+
//#region src/agent/commandments.ts
|
|
2255
2123
|
/**
|
|
2256
2124
|
* Commandments true for every run, whatever program, sequence, harness, or model
|
|
2257
2125
|
* it resolves to. Anything narrower belongs to its axis in
|
|
@@ -2284,7 +2152,7 @@ const WIZARD_COMMANDMENTS = [
|
|
|
2284
2152
|
].join("\n")
|
|
2285
2153
|
];
|
|
2286
2154
|
//#endregion
|
|
2287
|
-
//#region src/
|
|
2155
|
+
//#region src/agent/runner/harness/pi/runtime-notes.ts
|
|
2288
2156
|
const HEADER = ["## This runtime", "Below are important guidance on the harness constraints you are bound to. Follow them as commandments."];
|
|
2289
2157
|
const PARALLEL_CALLS = "- When you need several INDEPENDENT operations — reading or searching multiple files, creating several insights — issue them as multiple tool calls in a SINGLE turn. They run in parallel and save round-trips; doing them one-per-turn is much slower. Only sequence calls when one needs a previous call’s output.";
|
|
2290
2158
|
const EXPLORE = "- Explore with the `ls`, `find`, and `grep` tools (list a directory, find files by name, search file contents). `read` is for FILES only — reading a directory errors. NEVER inspect files through `bash`; `ls`, `find`, `cat`, `sed`, `head`, `xxd`, `python -c` and the like are all blocked. To see the exact bytes of a file (e.g. whitespace before a precise `edit`), use `read`.";
|
|
@@ -2342,7 +2210,7 @@ function piRuntimeNotes(sequence, caps) {
|
|
|
2342
2210
|
return notes.join("\n");
|
|
2343
2211
|
}
|
|
2344
2212
|
//#endregion
|
|
2345
|
-
//#region src/
|
|
2213
|
+
//#region src/agent/runner/switchboard/commandments.ts
|
|
2346
2214
|
/**
|
|
2347
2215
|
* LINEAR only. One session drives the whole run and holds the Task tools; an
|
|
2348
2216
|
* orchestrator task session holds none of them and reports through
|
|
@@ -2389,7 +2257,7 @@ function assembleCommandments(axes) {
|
|
|
2389
2257
|
].filter(Boolean).join("\n");
|
|
2390
2258
|
}
|
|
2391
2259
|
//#endregion
|
|
2392
|
-
//#region src/
|
|
2260
|
+
//#region src/shared/agent-phase.ts
|
|
2393
2261
|
/** Maps a Claude SDK tool name to the phase that tool implies. Returns null
|
|
2394
2262
|
* when the tool doesn't drive the visualizer (Task*, TodoWrite, etc.). */
|
|
2395
2263
|
function classifyToolToStage(toolName) {
|
|
@@ -2402,7 +2270,35 @@ function classifyToolToStage(toolName) {
|
|
|
2402
2270
|
return null;
|
|
2403
2271
|
}
|
|
2404
2272
|
//#endregion
|
|
2405
|
-
//#region src/
|
|
2273
|
+
//#region src/shared/auth-session-state.ts
|
|
2274
|
+
/**
|
|
2275
|
+
* Whether this run's OAuth grant is known to be dead.
|
|
2276
|
+
*
|
|
2277
|
+
* Process-global on purpose. A run has exactly one login, but the two sides of
|
|
2278
|
+
* this fact are far apart: the pre-run refresh learns it in `authenticate.ts`,
|
|
2279
|
+
* and the only consumer is the 401 handler inside the agent message loop, which
|
|
2280
|
+
* holds no session. Threading it would mean a field on `AgentConfig` set at four
|
|
2281
|
+
* `initializeAgent` call sites — and the session it would read from may be a
|
|
2282
|
+
* shallow copy (`prepareRunSession`), so the value could be written to one
|
|
2283
|
+
* object and read from another.
|
|
2284
|
+
*
|
|
2285
|
+
* A leaf module with no imports, so either side can depend on it without a cycle.
|
|
2286
|
+
*/
|
|
2287
|
+
let grantRevoked = false;
|
|
2288
|
+
/**
|
|
2289
|
+
* Record that the token endpoint permanently refused this grant. Not an abort:
|
|
2290
|
+
* the access token in hand may still have minutes of life, so the run continues
|
|
2291
|
+
* and this only decides what a later 401 gets blamed on.
|
|
2292
|
+
*/
|
|
2293
|
+
function markGrantRevoked() {
|
|
2294
|
+
grantRevoked = true;
|
|
2295
|
+
}
|
|
2296
|
+
/** True once a token refresh failed because the grant itself is gone. */
|
|
2297
|
+
function isGrantRevoked() {
|
|
2298
|
+
return grantRevoked;
|
|
2299
|
+
}
|
|
2300
|
+
//#endregion
|
|
2301
|
+
//#region src/agent/output-signals.ts
|
|
2406
2302
|
/**
|
|
2407
2303
|
* Parses the signal-bearing lines out of agent output and discards the rest.
|
|
2408
2304
|
*
|
|
@@ -2509,7 +2405,7 @@ var AgentOutputSignals = class {
|
|
|
2509
2405
|
}
|
|
2510
2406
|
};
|
|
2511
2407
|
//#endregion
|
|
2512
|
-
//#region src/
|
|
2408
|
+
//#region src/shared/agent-env-isolation.ts
|
|
2513
2409
|
/**
|
|
2514
2410
|
* Credential isolation for the Claude Agent SDK subprocess.
|
|
2515
2411
|
*
|
|
@@ -2573,6 +2469,7 @@ const BLOCKED_OFF_NAMESPACE_KEYS = new Set(["AWS_BEARER_TOKEN_BEDROCK"]);
|
|
|
2573
2469
|
const HOST_ONLY_ENV_KEYS = new Set([
|
|
2574
2470
|
"POSTHOG_HANDOFF_OUTPUT_PATH",
|
|
2575
2471
|
"POSTHOG_TASK_RUN_ID",
|
|
2472
|
+
"POSTHOG_WIZARD_RUN_ID",
|
|
2576
2473
|
"POSTHOG_TASK_ID"
|
|
2577
2474
|
]);
|
|
2578
2475
|
/**
|
|
@@ -2658,7 +2555,7 @@ function sanitizeAgentSubprocessEnv(env = process.env) {
|
|
|
2658
2555
|
return sanitized;
|
|
2659
2556
|
}
|
|
2660
2557
|
//#endregion
|
|
2661
|
-
//#region src/
|
|
2558
|
+
//#region src/shared/claude-settings.ts
|
|
2662
2559
|
/**
|
|
2663
2560
|
* Claude Code settings handling: conflict detection, backup/restore, and
|
|
2664
2561
|
* orphan recovery.
|
|
@@ -2889,7 +2786,7 @@ function recoverOrphanedSettingsBackups(workingDirectory) {
|
|
|
2889
2786
|
}
|
|
2890
2787
|
}
|
|
2891
2788
|
//#endregion
|
|
2892
|
-
//#region src/
|
|
2789
|
+
//#region src/agent/stored-login.ts
|
|
2893
2790
|
/**
|
|
2894
2791
|
* Detect a pre-existing Claude Code login on the machine.
|
|
2895
2792
|
*
|
|
@@ -2969,7 +2866,7 @@ function detectStoredClaudeLogin(homeDir = os.homedir(), platform = process.plat
|
|
|
2969
2866
|
};
|
|
2970
2867
|
}
|
|
2971
2868
|
//#endregion
|
|
2972
|
-
//#region src/
|
|
2869
|
+
//#region src/agent/agent-interface.ts
|
|
2973
2870
|
/**
|
|
2974
2871
|
* Shared agent interface for PostHog wizards
|
|
2975
2872
|
* Uses Claude Agent SDK directly with PostHog LLM gateway
|
|
@@ -3018,37 +2915,23 @@ function buildAuthErrorContext(workingDirectory, gatewayUrl, homeDir = os.homedi
|
|
|
3018
2915
|
};
|
|
3019
2916
|
}
|
|
3020
2917
|
/**
|
|
3021
|
-
* Create a stop hook callback that
|
|
3022
|
-
* then collects a remark, then allows stop.
|
|
2918
|
+
* Create a stop hook callback that collects a remark, then allows stop.
|
|
3023
2919
|
*
|
|
3024
|
-
*
|
|
3025
|
-
* Phase 1 —
|
|
3026
|
-
* Phase 2 —
|
|
3027
|
-
* Phase 3 — allow stop: return {}
|
|
2920
|
+
* Two-phase logic using closure state:
|
|
2921
|
+
* Phase 1 — collect remark (once): block with remark prompt
|
|
2922
|
+
* Phase 2 — allow stop: return {}
|
|
3028
2923
|
*/
|
|
3029
|
-
function createStopHook(
|
|
3030
|
-
let featureIndex = 0;
|
|
2924
|
+
function createStopHook(signals, requestRemark = true) {
|
|
3031
2925
|
let remarkRequested = false;
|
|
3032
2926
|
return (input) => {
|
|
3033
2927
|
logToFile("Stop hook triggered", {
|
|
3034
2928
|
stop_hook_active: input.stop_hook_active,
|
|
3035
|
-
|
|
3036
|
-
remarkRequested,
|
|
3037
|
-
queueLength: featureQueue.length
|
|
2929
|
+
remarkRequested
|
|
3038
2930
|
});
|
|
3039
2931
|
if (signals?.hasApiError()) {
|
|
3040
2932
|
logToFile("Stop hook: API error detected, allowing immediate stop");
|
|
3041
2933
|
return {};
|
|
3042
2934
|
}
|
|
3043
|
-
if (featureIndex < featureQueue.length) {
|
|
3044
|
-
const feature = featureQueue[featureIndex++];
|
|
3045
|
-
const prompt = ADDITIONAL_FEATURE_PROMPTS[feature];
|
|
3046
|
-
logToFile(`Stop hook: injecting feature prompt for ${feature}`);
|
|
3047
|
-
return {
|
|
3048
|
-
decision: "block",
|
|
3049
|
-
reason: prompt
|
|
3050
|
-
};
|
|
3051
|
-
}
|
|
3052
2935
|
if (requestRemark && !remarkRequested) {
|
|
3053
2936
|
remarkRequested = true;
|
|
3054
2937
|
logToFile("Stop hook: requesting reflection");
|
|
@@ -3061,6 +2944,7 @@ function createStopHook(featureQueue, signals, requestRemark = true) {
|
|
|
3061
2944
|
return {};
|
|
3062
2945
|
};
|
|
3063
2946
|
}
|
|
2947
|
+
const NO_PROGRESS = () => void 0;
|
|
3064
2948
|
/**
|
|
3065
2949
|
* Global identifiers attached to every LLM gateway trace for a run. They ride on
|
|
3066
2950
|
* each `$ai_generation` the gateway emits (in the `X-PostHog-Properties` blob
|
|
@@ -3113,6 +2997,10 @@ function buildAgentEnv(wizardMetadata, wizardFlags, teamId) {
|
|
|
3113
2997
|
* this guard is a belt-and-suspenders second line.
|
|
3114
2998
|
*/
|
|
3115
2999
|
function wizardCanUseTool(toolName, input, context = {}) {
|
|
3000
|
+
if (context.readOnly && !READ_ONLY_TOOLS.includes(toolName)) return {
|
|
3001
|
+
behavior: "deny",
|
|
3002
|
+
message: `Tool ${toolName} is disabled for read-only runs.`
|
|
3003
|
+
};
|
|
3116
3004
|
if (context.disallowedTools?.includes(toolName)) {
|
|
3117
3005
|
logToFile(`Denying disallowed tool: ${toolName}`);
|
|
3118
3006
|
return {
|
|
@@ -3188,9 +3076,10 @@ async function initializeAgent(config, options) {
|
|
|
3188
3076
|
initLogFile();
|
|
3189
3077
|
logToFile("Agent initialization starting");
|
|
3190
3078
|
logToFile("Install directory:", options.installDir);
|
|
3079
|
+
const emit = config.emit ?? NO_PROGRESS;
|
|
3191
3080
|
try {
|
|
3192
3081
|
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "true";
|
|
3193
|
-
const currentGatewayAuth = () => gatewayAuth(config.host, config.posthogApiKey, config.programId);
|
|
3082
|
+
const currentGatewayAuth = async () => gatewayAuth(config.host, await config.currentPosthogApiKey?.() ?? config.posthogApiKey, config.programId);
|
|
3194
3083
|
const auth = await currentGatewayAuth();
|
|
3195
3084
|
const gatewayUrl = auth.gatewayUrl;
|
|
3196
3085
|
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
|
|
@@ -3244,16 +3133,20 @@ async function initializeAgent(config, options) {
|
|
|
3244
3133
|
askBridge: config.askBridge,
|
|
3245
3134
|
askMaxQuestions: config.askMaxQuestions,
|
|
3246
3135
|
orchestrator: config.orchestrator,
|
|
3247
|
-
triageProvider
|
|
3136
|
+
triageProvider,
|
|
3137
|
+
emit: config.emit
|
|
3248
3138
|
});
|
|
3249
3139
|
const model = config.modelOverride ?? "claude-sonnet-5";
|
|
3250
3140
|
const agentRunConfig = {
|
|
3251
3141
|
workingDirectory: config.workingDirectory,
|
|
3252
3142
|
mcpServers,
|
|
3253
3143
|
model,
|
|
3144
|
+
outputFormat: config.outputFormat,
|
|
3254
3145
|
posthogApiKey: config.posthogApiKey,
|
|
3146
|
+
currentPosthogApiKey: config.currentPosthogApiKey,
|
|
3255
3147
|
wizardFlags: config.wizardFlags,
|
|
3256
3148
|
wizardMetadata: config.wizardMetadata,
|
|
3149
|
+
readOnly: config.readOnly,
|
|
3257
3150
|
allowedTools: config.allowedTools,
|
|
3258
3151
|
disallowedTools: config.disallowedTools,
|
|
3259
3152
|
getPendingQuestion: config.getPendingQuestion,
|
|
@@ -3263,7 +3156,8 @@ async function initializeAgent(config, options) {
|
|
|
3263
3156
|
gatewayAuth: auth,
|
|
3264
3157
|
refreshGatewayAuth: currentGatewayAuth,
|
|
3265
3158
|
program: config.integrationLabel,
|
|
3266
|
-
sequence: config.orchestrator ? "orchestrator" : "linear"
|
|
3159
|
+
sequence: config.orchestrator ? "orchestrator" : "linear",
|
|
3160
|
+
emit
|
|
3267
3161
|
};
|
|
3268
3162
|
logToFile("Agent config:", {
|
|
3269
3163
|
workingDirectory: agentRunConfig.workingDirectory,
|
|
@@ -3280,7 +3174,11 @@ async function initializeAgent(config, options) {
|
|
|
3280
3174
|
prewarmYaraScanner();
|
|
3281
3175
|
return agentRunConfig;
|
|
3282
3176
|
} catch (error) {
|
|
3283
|
-
|
|
3177
|
+
emit({
|
|
3178
|
+
kind: "log",
|
|
3179
|
+
level: "error",
|
|
3180
|
+
message: `Failed to initialize agent: ${error.message}`
|
|
3181
|
+
});
|
|
3284
3182
|
logToFile("Agent initialization error:", error);
|
|
3285
3183
|
debug("Agent initialization error:", error);
|
|
3286
3184
|
throw error;
|
|
@@ -3292,7 +3190,40 @@ async function initializeAgent(config, options) {
|
|
|
3292
3190
|
*
|
|
3293
3191
|
* @returns An object containing any error detected in the agent's output
|
|
3294
3192
|
*/
|
|
3193
|
+
function sdkErrorStatus(value) {
|
|
3194
|
+
if (typeof value === "number" && value >= 400 && value < 600) return value;
|
|
3195
|
+
if (typeof value === "string") {
|
|
3196
|
+
const match = value.match(/(?:^|\b)(4\d\d|5\d\d)(?:\b|$)/);
|
|
3197
|
+
return match ? Number(match[1]) : void 0;
|
|
3198
|
+
}
|
|
3199
|
+
if (value && typeof value === "object") {
|
|
3200
|
+
const record = value;
|
|
3201
|
+
return sdkErrorStatus(record.status) ?? sdkErrorStatus(record.statusCode) ?? sdkErrorStatus(record.code) ?? sdkErrorStatus(record.error);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
function sdkResultFailure(message) {
|
|
3205
|
+
if (message.subtype === "success" && message.is_error !== true) return void 0;
|
|
3206
|
+
const errors = Array.isArray(message.errors) ? message.errors : [];
|
|
3207
|
+
const detail = errors.map((error) => typeof error === "string" ? error : JSON.stringify(error)).join("; ") || (typeof message.result === "string" ? message.result : String(message.subtype ?? "SDK result failed"));
|
|
3208
|
+
const status = sdkErrorStatus(message.api_error_status) ?? sdkErrorStatus(message.status) ?? errors.map(sdkErrorStatus).find((code) => code !== void 0) ?? sdkErrorStatus(message.result);
|
|
3209
|
+
if (message.subtype === "error_max_structured_output_retries") return {
|
|
3210
|
+
kind: "failure",
|
|
3211
|
+
classification: "WIZARD_INVALID_STRUCTURED_OUTPUT",
|
|
3212
|
+
message: detail
|
|
3213
|
+
};
|
|
3214
|
+
return {
|
|
3215
|
+
kind: "failure",
|
|
3216
|
+
classification: status === 429 ? "WIZARD_RATE_LIMIT" : "WIZARD_API_ERROR",
|
|
3217
|
+
message: detail
|
|
3218
|
+
};
|
|
3219
|
+
}
|
|
3295
3220
|
async function runAgent(agentConfig, prompt, options, spinner, config, middleware) {
|
|
3221
|
+
if (agentConfig.signal?.aborted) return {
|
|
3222
|
+
kind: "abort",
|
|
3223
|
+
classification: "WIZARD_ABORT",
|
|
3224
|
+
message: "Agent run cancelled"
|
|
3225
|
+
};
|
|
3226
|
+
const emit = agentConfig.emit ?? NO_PROGRESS;
|
|
3296
3227
|
const { spinnerMessage = "Customizing your PostHog setup...", successMessage = "PostHog integration complete", errorMessage = "Integration failed", abortCases = [], emitStepEvents = false, resolveStepKey } = config ?? {};
|
|
3297
3228
|
logToFile("Starting agent run");
|
|
3298
3229
|
const { query } = await getSDKModule();
|
|
@@ -3306,6 +3237,8 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3306
3237
|
let receivedSuccessResult = false;
|
|
3307
3238
|
let loggedInitialContext = false;
|
|
3308
3239
|
let lastResultMessage = null;
|
|
3240
|
+
let terminalFailure;
|
|
3241
|
+
let assistantErrorStatus;
|
|
3309
3242
|
const tasks = /* @__PURE__ */ new Map();
|
|
3310
3243
|
let signalDone = () => void 0;
|
|
3311
3244
|
const createPromptStream = (text) => {
|
|
@@ -3350,23 +3283,36 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3350
3283
|
...config?.analyticsProperties
|
|
3351
3284
|
});
|
|
3352
3285
|
const totalCostUsd = Number(lastResultMessage?.total_cost_usd ?? 0);
|
|
3353
|
-
if (totalCostUsd > 0)
|
|
3286
|
+
if (totalCostUsd > 0) emit({
|
|
3287
|
+
kind: "finalCost",
|
|
3288
|
+
usd: totalCostUsd
|
|
3289
|
+
});
|
|
3354
3290
|
try {
|
|
3355
3291
|
middleware?.finalize(lastResultMessage, durationMs);
|
|
3356
3292
|
} catch (e) {
|
|
3357
3293
|
logToFile(`${AgentSignals.BENCHMARK} Middleware finalize error:`, e);
|
|
3358
3294
|
}
|
|
3359
3295
|
spinner.stop(successMessage);
|
|
3360
|
-
return {
|
|
3296
|
+
return {
|
|
3297
|
+
kind: "success",
|
|
3298
|
+
structuredOutput: lastResultMessage?.structured_output
|
|
3299
|
+
};
|
|
3361
3300
|
};
|
|
3362
3301
|
let abortController = new AbortController();
|
|
3302
|
+
const onExternalAbort = () => {
|
|
3303
|
+
abortController.abort();
|
|
3304
|
+
signalDone();
|
|
3305
|
+
};
|
|
3363
3306
|
let timedOut = false;
|
|
3364
3307
|
let abortReason = null;
|
|
3365
3308
|
let yaraViolationReason = null;
|
|
3366
3309
|
let sessionId;
|
|
3367
3310
|
let reminted = false;
|
|
3368
3311
|
let remintRequested = false;
|
|
3312
|
+
let authFailure;
|
|
3369
3313
|
const agentConfigDir = createIsolatedAgentConfigDir();
|
|
3314
|
+
agentConfig.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
3315
|
+
if (agentConfig.signal?.aborted) onExternalAbort();
|
|
3370
3316
|
const timeoutMs = config?.timeoutMs;
|
|
3371
3317
|
const timeoutId = timeoutMs ? setTimeout(() => {
|
|
3372
3318
|
if (receivedSuccessResult) return;
|
|
@@ -3376,7 +3322,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3376
3322
|
}, timeoutMs) : void 0;
|
|
3377
3323
|
try {
|
|
3378
3324
|
const disallow = new Set(agentConfig.disallowedTools ?? []);
|
|
3379
|
-
const allowedTools = [...BASE_ALLOWED_TOOLS, ...agentConfig.allowedTools ?? []].filter((t) => !disallow.has(t));
|
|
3325
|
+
const allowedTools = (agentConfig.readOnly ? READ_ONLY_TOOLS : [...BASE_ALLOWED_TOOLS, ...agentConfig.allowedTools ?? []]).filter((t) => !disallow.has(t));
|
|
3380
3326
|
const inheritedMcpServerNames = Object.keys(agentConfig.mcpServers);
|
|
3381
3327
|
const triageProvider = agentConfig.triageProvider;
|
|
3382
3328
|
const onYaraTerminate = (reason) => {
|
|
@@ -3399,18 +3345,19 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3399
3345
|
abortController,
|
|
3400
3346
|
resume,
|
|
3401
3347
|
model: agentConfig.model,
|
|
3348
|
+
outputFormat: agentConfig.outputFormat,
|
|
3402
3349
|
cwd: agentConfig.workingDirectory,
|
|
3403
|
-
permissionMode: "acceptEdits",
|
|
3350
|
+
permissionMode: agentConfig.readOnly ? "default" : "acceptEdits",
|
|
3404
3351
|
betas: ["context-1m-2025-08-07"],
|
|
3405
|
-
mcpServers: agentConfig.mcpServers,
|
|
3406
|
-
agents: { "general-purpose": {
|
|
3352
|
+
mcpServers: agentConfig.readOnly ? {} : agentConfig.mcpServers,
|
|
3353
|
+
agents: agentConfig.readOnly ? void 0 : { "general-purpose": {
|
|
3407
3354
|
description: "General-purpose subagent. Inherits the parent run's tools plus the PostHog and wizard-tools MCP servers, so it can call mcp__posthog-wizard__* directly instead of curling the REST API.",
|
|
3408
3355
|
prompt: "You are a general-purpose subagent for the PostHog wizard. Prefer the authenticated mcp__posthog-wizard__* MCP tools over raw HTTP — they are already authenticated for this project. Only fall back to other transports if no MCP tool covers the operation.",
|
|
3409
3356
|
mcpServers: inheritedMcpServerNames,
|
|
3410
3357
|
disallowedTools: agentConfig.disallowedTools ? [...agentConfig.disallowedTools] : void 0
|
|
3411
3358
|
} },
|
|
3412
|
-
settingSources: ["project"],
|
|
3413
|
-
skills: "all",
|
|
3359
|
+
settingSources: agentConfig.readOnly ? [] : ["project"],
|
|
3360
|
+
skills: agentConfig.readOnly ? [] : "all",
|
|
3414
3361
|
allowedTools,
|
|
3415
3362
|
sandbox: {
|
|
3416
3363
|
enabled: true,
|
|
@@ -3457,7 +3404,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3457
3404
|
CLAUDE_CODE_OAUTH_TOKEN: agentConfig.gatewayAuth.token,
|
|
3458
3405
|
CLAUDE_CONFIG_DIR: agentConfigDir,
|
|
3459
3406
|
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "true",
|
|
3460
|
-
POSTHOG_MCP_TOKEN: agentConfig.posthogApiKey,
|
|
3407
|
+
POSTHOG_MCP_TOKEN: await agentConfig.currentPosthogApiKey?.() ?? agentConfig.posthogApiKey,
|
|
3461
3408
|
MCP_CONNECTION_NONBLOCKING: "0",
|
|
3462
3409
|
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}, agentConfig.gatewayAuth.teamId)
|
|
3463
3410
|
},
|
|
@@ -3467,6 +3414,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3467
3414
|
input
|
|
3468
3415
|
});
|
|
3469
3416
|
const result = wizardCanUseTool(toolName, input, {
|
|
3417
|
+
readOnly: agentConfig.readOnly,
|
|
3470
3418
|
wizardAskPending: agentConfig.getPendingQuestion?.() != null,
|
|
3471
3419
|
disallowedTools: agentConfig.disallowedTools
|
|
3472
3420
|
});
|
|
@@ -3482,7 +3430,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3482
3430
|
harness: "anthropic"
|
|
3483
3431
|
})
|
|
3484
3432
|
},
|
|
3485
|
-
tools: {
|
|
3433
|
+
tools: agentConfig.readOnly ? [...READ_ONLY_TOOLS] : {
|
|
3486
3434
|
type: "preset",
|
|
3487
3435
|
preset: "claude_code"
|
|
3488
3436
|
},
|
|
@@ -3494,7 +3442,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3494
3442
|
PreToolUse: warlockDisabled ? [] : createPreToolUseYaraHooks(triageProvider, onYaraTerminate),
|
|
3495
3443
|
PostToolUse: warlockDisabled ? [] : createPostToolUseYaraHooks(triageProvider, onYaraTerminate),
|
|
3496
3444
|
Stop: [{
|
|
3497
|
-
hooks: [createStopHook(
|
|
3445
|
+
hooks: [createStopHook(signals, config?.requestRemark ?? true)],
|
|
3498
3446
|
timeout: 30
|
|
3499
3447
|
}]
|
|
3500
3448
|
}
|
|
@@ -3521,7 +3469,8 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3521
3469
|
loggedInitialContext = true;
|
|
3522
3470
|
}
|
|
3523
3471
|
agentConfig.capture?.captureFromAnthropicSDKMessage(message);
|
|
3524
|
-
handleSDKMessage(message, options, spinner, signals, receivedSuccessResult, tasks, agentConfig.suppressTaskRender ?? false, emitStepEvents, resolveStepKey);
|
|
3472
|
+
handleSDKMessage(message, options, spinner, signals, emit, receivedSuccessResult, tasks, agentConfig.suppressTaskRender ?? false, emitStepEvents, resolveStepKey);
|
|
3473
|
+
if (message.type === "assistant") assistantErrorStatus = sdkErrorStatus(message.error) ?? assistantErrorStatus;
|
|
3525
3474
|
if (abortCases.length > 0 && !abortReason && message.type === "assistant") {
|
|
3526
3475
|
const content = message.message?.content;
|
|
3527
3476
|
if (Array.isArray(content)) {
|
|
@@ -3537,9 +3486,9 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3537
3486
|
}
|
|
3538
3487
|
}
|
|
3539
3488
|
}
|
|
3540
|
-
if (message.type === "assistant" &&
|
|
3489
|
+
if (message.type === "assistant" && sdkErrorStatus(message.error) === 401 || message.type === "result" && (sdkErrorStatus(message.api_error_status) === 401 || sdkErrorStatus(message.status) === 401) || message.type === "result" && Array.isArray(message.errors) && message.errors.some((error) => sdkErrorStatus(error) === 401)) {
|
|
3541
3490
|
signalDone();
|
|
3542
|
-
if (agentConfig.refreshGatewayAuth && !reminted && isPastRefresh(agentConfig.gatewayAuth)) {
|
|
3491
|
+
if (agentConfig.refreshGatewayAuth && !reminted && isPastRefresh(agentConfig.gatewayAuth) && !agentConfig.signal?.aborted) {
|
|
3543
3492
|
logToFile("Agent error: 401 on an aged gateway bearer; re-minting");
|
|
3544
3493
|
remintRequested = true;
|
|
3545
3494
|
abortController.abort();
|
|
@@ -3560,27 +3509,33 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3560
3509
|
...authError,
|
|
3561
3510
|
sessionExpired
|
|
3562
3511
|
});
|
|
3563
|
-
|
|
3564
|
-
hasSettingsConflict: authError.hasSettingsConflict,
|
|
3565
|
-
conflicts: authError.conflicts,
|
|
3566
|
-
usingManagedLogin: authError.usingManagedLogin,
|
|
3567
|
-
credentialPlaces: authError.credentialPlaces,
|
|
3568
|
-
sessionExpired,
|
|
3569
|
-
logFilePath: getLogFilePath()
|
|
3570
|
-
});
|
|
3571
|
-
await wizardAbort({
|
|
3512
|
+
authFailure = {
|
|
3572
3513
|
code: authCode,
|
|
3573
3514
|
message: "Authentication failed (401)",
|
|
3574
|
-
|
|
3515
|
+
authErrorDetail: {
|
|
3516
|
+
hasSettingsConflict: authError.hasSettingsConflict,
|
|
3517
|
+
conflicts: authError.conflicts,
|
|
3518
|
+
usingManagedLogin: authError.usingManagedLogin,
|
|
3519
|
+
credentialPlaces: authError.credentialPlaces,
|
|
3520
|
+
sessionExpired,
|
|
3521
|
+
logFilePath: getLogFilePath()
|
|
3522
|
+
},
|
|
3523
|
+
detail: {
|
|
3575
3524
|
hasSettingsConflict: authError.hasSettingsConflict,
|
|
3576
3525
|
conflictSources: authError.conflictSources,
|
|
3577
3526
|
conflictKeys: authError.conflictKeys,
|
|
3527
|
+
conflicts: authError.conflicts,
|
|
3528
|
+
credentialPlaces: authError.credentialPlaces,
|
|
3529
|
+
sessionExpired,
|
|
3530
|
+
logFilePath: getLogFilePath(),
|
|
3578
3531
|
gatewayUrl: authError.gatewayUrl,
|
|
3579
3532
|
region: authError.region,
|
|
3580
3533
|
usingManagedLogin: authError.usingManagedLogin,
|
|
3581
3534
|
apiKeySource: authError.apiKeySource
|
|
3582
|
-
}
|
|
3583
|
-
}
|
|
3535
|
+
}
|
|
3536
|
+
};
|
|
3537
|
+
abortController.abort();
|
|
3538
|
+
break;
|
|
3584
3539
|
}
|
|
3585
3540
|
try {
|
|
3586
3541
|
middleware?.onMessage(message);
|
|
@@ -3591,66 +3546,112 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3591
3546
|
if (message.subtype === "success" && !message.is_error) {
|
|
3592
3547
|
receivedSuccessResult = true;
|
|
3593
3548
|
lastResultMessage = message;
|
|
3549
|
+
} else if (!receivedSuccessResult) {
|
|
3550
|
+
terminalFailure = sdkResultFailure(message);
|
|
3551
|
+
if (terminalFailure && assistantErrorStatus === 429) terminalFailure = {
|
|
3552
|
+
...terminalFailure,
|
|
3553
|
+
classification: "WIZARD_RATE_LIMIT"
|
|
3554
|
+
};
|
|
3594
3555
|
}
|
|
3595
3556
|
signalDone();
|
|
3596
3557
|
}
|
|
3597
3558
|
}
|
|
3598
3559
|
} catch (error) {
|
|
3599
3560
|
if (remintRequested) return "remint";
|
|
3561
|
+
if (authFailure) return "done";
|
|
3600
3562
|
throw error;
|
|
3601
3563
|
}
|
|
3602
3564
|
return remintRequested ? "remint" : "done";
|
|
3603
3565
|
};
|
|
3604
3566
|
const refreshGatewayAuth = agentConfig.refreshGatewayAuth;
|
|
3605
|
-
if (await runQuery() === "remint" && refreshGatewayAuth) {
|
|
3567
|
+
if (await runQuery() === "remint" && refreshGatewayAuth && !agentConfig.signal?.aborted) {
|
|
3606
3568
|
reminted = true;
|
|
3607
3569
|
remintRequested = false;
|
|
3608
3570
|
abortController = new AbortController();
|
|
3571
|
+
if (agentConfig.signal?.aborted) abortController.abort();
|
|
3609
3572
|
signals.forgetApiErrors();
|
|
3610
3573
|
spinner.message("Renewing the gateway token...");
|
|
3611
3574
|
const stale = agentConfig.gatewayAuth;
|
|
3612
3575
|
agentConfig.gatewayAuth = await refreshGatewayAuth();
|
|
3576
|
+
if (agentConfig.signal?.aborted) return {
|
|
3577
|
+
kind: "abort",
|
|
3578
|
+
classification: "WIZARD_ABORT",
|
|
3579
|
+
message: "Agent run cancelled"
|
|
3580
|
+
};
|
|
3613
3581
|
logToFile(`Gateway token renewed after a 401 (${Math.round((Date.now() - stale.refreshAtMs) / 1e3)}s past refresh); resuming session ${sessionId ?? "(none: fresh session)"}`);
|
|
3614
3582
|
analytics.wizardCapture("gateway token reminted", { resumed: sessionId !== void 0 });
|
|
3615
3583
|
spinner.message(spinnerMessage);
|
|
3616
3584
|
await runQuery(sessionId);
|
|
3617
3585
|
}
|
|
3586
|
+
if (authFailure) return {
|
|
3587
|
+
kind: "decided_failure",
|
|
3588
|
+
failure: authFailure
|
|
3589
|
+
};
|
|
3590
|
+
if (agentConfig.signal?.aborted) return {
|
|
3591
|
+
kind: "abort",
|
|
3592
|
+
classification: "WIZARD_ABORT",
|
|
3593
|
+
message: "Agent run cancelled"
|
|
3594
|
+
};
|
|
3618
3595
|
if (yaraViolationReason) {
|
|
3619
3596
|
logToFile("Agent error: YARA_VIOLATION");
|
|
3620
3597
|
spinner.stop("Security check stopped the setup");
|
|
3621
|
-
return {
|
|
3598
|
+
return {
|
|
3599
|
+
kind: "failure",
|
|
3600
|
+
classification: "WIZARD_YARA_VIOLATION"
|
|
3601
|
+
};
|
|
3622
3602
|
}
|
|
3623
3603
|
if (abortReason) {
|
|
3624
3604
|
spinner.stop("Wizard aborted");
|
|
3625
3605
|
return {
|
|
3626
|
-
|
|
3606
|
+
kind: "abort",
|
|
3607
|
+
classification: "WIZARD_ABORT",
|
|
3627
3608
|
message: abortReason
|
|
3628
3609
|
};
|
|
3629
3610
|
}
|
|
3611
|
+
if (agentConfig.signal?.aborted) {
|
|
3612
|
+
spinner.stop("Wizard aborted");
|
|
3613
|
+
return {
|
|
3614
|
+
kind: "abort",
|
|
3615
|
+
classification: "WIZARD_ABORT",
|
|
3616
|
+
message: "Agent run cancelled"
|
|
3617
|
+
};
|
|
3618
|
+
}
|
|
3630
3619
|
if (timedOut) {
|
|
3631
3620
|
spinner.stop("Agent run timed out");
|
|
3632
3621
|
return {
|
|
3633
|
-
|
|
3622
|
+
kind: "failure",
|
|
3623
|
+
classification: "WIZARD_AGENTIC_DETECTION_TIMEOUT",
|
|
3634
3624
|
message: `Agent run timed out after ${timeoutMs / 1e3}s`
|
|
3635
3625
|
};
|
|
3636
3626
|
}
|
|
3637
3627
|
if (signals.has("MCP_MISSING")) {
|
|
3638
3628
|
logToFile("Agent error: MCP_MISSING");
|
|
3639
3629
|
spinner.stop("Agent could not access PostHog MCP");
|
|
3640
|
-
return {
|
|
3630
|
+
return {
|
|
3631
|
+
kind: "failure",
|
|
3632
|
+
classification: "WIZARD_MCP_MISSING"
|
|
3633
|
+
};
|
|
3641
3634
|
}
|
|
3642
3635
|
if (signals.has("RESOURCE_MISSING")) {
|
|
3643
3636
|
logToFile("Agent error: RESOURCE_MISSING");
|
|
3644
3637
|
spinner.stop("Agent could not access setup resource");
|
|
3645
|
-
return {
|
|
3638
|
+
return {
|
|
3639
|
+
kind: "failure",
|
|
3640
|
+
classification: "WIZARD_RESOURCE_MISSING"
|
|
3641
|
+
};
|
|
3646
3642
|
}
|
|
3647
3643
|
if (receivedSuccessResult) return completeWithSuccess();
|
|
3644
|
+
if (terminalFailure) {
|
|
3645
|
+
spinner.stop(errorMessage);
|
|
3646
|
+
return terminalFailure;
|
|
3647
|
+
}
|
|
3648
3648
|
const apiErrorMessage = signals.apiErrorMessage() ?? "Unknown API error";
|
|
3649
3649
|
if (signals.hasApiErrorStatus(429)) {
|
|
3650
3650
|
logToFile("Agent error: RATE_LIMIT");
|
|
3651
3651
|
spinner.stop("Rate limit exceeded");
|
|
3652
3652
|
return {
|
|
3653
|
-
|
|
3653
|
+
kind: "failure",
|
|
3654
|
+
classification: "WIZARD_RATE_LIMIT",
|
|
3654
3655
|
message: apiErrorMessage
|
|
3655
3656
|
};
|
|
3656
3657
|
}
|
|
@@ -3658,65 +3659,99 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3658
3659
|
logToFile("Agent error: API_ERROR");
|
|
3659
3660
|
spinner.stop("API error occurred");
|
|
3660
3661
|
return {
|
|
3661
|
-
|
|
3662
|
+
kind: "failure",
|
|
3663
|
+
classification: "WIZARD_API_ERROR",
|
|
3662
3664
|
message: apiErrorMessage
|
|
3663
3665
|
};
|
|
3664
3666
|
}
|
|
3665
|
-
|
|
3667
|
+
spinner.stop(errorMessage);
|
|
3668
|
+
return {
|
|
3669
|
+
kind: "failure",
|
|
3670
|
+
classification: "WIZARD_API_ERROR",
|
|
3671
|
+
message: "SDK stream ended without a success result"
|
|
3672
|
+
};
|
|
3666
3673
|
} catch (error) {
|
|
3667
3674
|
signalDone();
|
|
3668
3675
|
if (yaraViolationReason) {
|
|
3669
3676
|
logToFile("Agent error: YARA_VIOLATION");
|
|
3670
3677
|
spinner.stop("Security check stopped the setup");
|
|
3671
|
-
return {
|
|
3678
|
+
return {
|
|
3679
|
+
kind: "failure",
|
|
3680
|
+
classification: "WIZARD_YARA_VIOLATION"
|
|
3681
|
+
};
|
|
3672
3682
|
}
|
|
3673
3683
|
if (abortReason) {
|
|
3674
3684
|
spinner.stop("Wizard aborted");
|
|
3675
3685
|
return {
|
|
3676
|
-
|
|
3686
|
+
kind: "abort",
|
|
3687
|
+
classification: "WIZARD_ABORT",
|
|
3677
3688
|
message: abortReason
|
|
3678
3689
|
};
|
|
3679
3690
|
}
|
|
3691
|
+
if (agentConfig.signal?.aborted) {
|
|
3692
|
+
spinner.stop("Wizard aborted");
|
|
3693
|
+
return {
|
|
3694
|
+
kind: "abort",
|
|
3695
|
+
classification: "WIZARD_ABORT",
|
|
3696
|
+
message: "Agent run cancelled"
|
|
3697
|
+
};
|
|
3698
|
+
}
|
|
3680
3699
|
if (receivedSuccessResult) return completeWithSuccess(error);
|
|
3681
3700
|
if (timedOut) {
|
|
3682
3701
|
spinner.stop("Agent run timed out");
|
|
3683
3702
|
return {
|
|
3684
|
-
|
|
3703
|
+
kind: "failure",
|
|
3704
|
+
classification: "WIZARD_AGENTIC_DETECTION_TIMEOUT",
|
|
3685
3705
|
message: `Agent run timed out after ${timeoutMs / 1e3}s`
|
|
3686
3706
|
};
|
|
3687
3707
|
}
|
|
3708
|
+
if (terminalFailure) {
|
|
3709
|
+
spinner.stop(errorMessage);
|
|
3710
|
+
return terminalFailure;
|
|
3711
|
+
}
|
|
3688
3712
|
const apiErrorMessage = signals.apiErrorMessage() ?? "Unknown API error";
|
|
3689
3713
|
if (signals.hasApiErrorStatus(429)) {
|
|
3690
3714
|
logToFile("Agent error (caught): RATE_LIMIT");
|
|
3691
3715
|
spinner.stop("Rate limit exceeded");
|
|
3692
3716
|
return {
|
|
3693
|
-
|
|
3694
|
-
|
|
3717
|
+
kind: "failure",
|
|
3718
|
+
classification: "WIZARD_RATE_LIMIT",
|
|
3719
|
+
message: apiErrorMessage,
|
|
3720
|
+
error: error instanceof Error ? error : void 0
|
|
3695
3721
|
};
|
|
3696
3722
|
}
|
|
3697
3723
|
if (signals.hasApiError()) {
|
|
3698
3724
|
logToFile("Agent error (caught): API_ERROR");
|
|
3699
3725
|
spinner.stop("API error occurred");
|
|
3700
3726
|
return {
|
|
3701
|
-
|
|
3702
|
-
|
|
3727
|
+
kind: "failure",
|
|
3728
|
+
classification: "WIZARD_API_ERROR",
|
|
3729
|
+
message: apiErrorMessage,
|
|
3730
|
+
error: error instanceof Error ? error : void 0
|
|
3703
3731
|
};
|
|
3704
3732
|
}
|
|
3705
3733
|
spinner.stop(errorMessage);
|
|
3706
|
-
|
|
3734
|
+
emit({
|
|
3735
|
+
kind: "log",
|
|
3736
|
+
level: "error",
|
|
3737
|
+
message: `Error: ${error.message}`
|
|
3738
|
+
});
|
|
3707
3739
|
logToFile("Agent run failed:", error);
|
|
3708
3740
|
debug("Full error:", error);
|
|
3709
3741
|
throw error;
|
|
3710
3742
|
} finally {
|
|
3743
|
+
agentConfig.signal?.removeEventListener("abort", onExternalAbort);
|
|
3711
3744
|
if (timeoutId) clearTimeout(timeoutId);
|
|
3712
|
-
if (!receivedSuccessResult) {
|
|
3745
|
+
if (!receivedSuccessResult && !authFailure) {
|
|
3713
3746
|
const durationMs = Date.now() - startTime;
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3747
|
+
try {
|
|
3748
|
+
analytics.wizardCapture("agent aborted", {
|
|
3749
|
+
duration_ms: durationMs,
|
|
3750
|
+
duration_seconds: Math.round(durationMs / 1e3),
|
|
3751
|
+
model: agentConfig.model,
|
|
3752
|
+
...config?.analyticsProperties
|
|
3753
|
+
});
|
|
3754
|
+
} catch {}
|
|
3720
3755
|
}
|
|
3721
3756
|
}
|
|
3722
3757
|
}
|
|
@@ -3750,6 +3785,11 @@ let TaskTool = /* @__PURE__ */ function(TaskTool) {
|
|
|
3750
3785
|
* init handler has to recognise this server in the SDK's status report.
|
|
3751
3786
|
*/
|
|
3752
3787
|
const POSTHOG_MCP_SERVER_NAME = "posthog-wizard";
|
|
3788
|
+
const READ_ONLY_TOOLS = [
|
|
3789
|
+
"Read",
|
|
3790
|
+
"Glob",
|
|
3791
|
+
"Grep"
|
|
3792
|
+
];
|
|
3753
3793
|
const BASE_ALLOWED_TOOLS = [
|
|
3754
3794
|
"Read",
|
|
3755
3795
|
"Write",
|
|
@@ -3761,10 +3801,18 @@ const BASE_ALLOWED_TOOLS = [
|
|
|
3761
3801
|
"ListMcpResourcesTool",
|
|
3762
3802
|
...Object.values(WIZARD_TOOL_NAMES)
|
|
3763
3803
|
];
|
|
3804
|
+
const taskSources = /* @__PURE__ */ new WeakMap();
|
|
3764
3805
|
function handleTaskCreate(block, store) {
|
|
3765
3806
|
const input = block.input;
|
|
3766
3807
|
if (!input?.subject) return;
|
|
3808
|
+
let source = taskSources.get(store.tasks);
|
|
3809
|
+
if (!source) {
|
|
3810
|
+
source = randomUUID();
|
|
3811
|
+
taskSources.set(store.tasks, source);
|
|
3812
|
+
}
|
|
3767
3813
|
store.tasks.set(block.id, {
|
|
3814
|
+
id: randomUUID(),
|
|
3815
|
+
source,
|
|
3768
3816
|
content: input.subject,
|
|
3769
3817
|
status: "pending",
|
|
3770
3818
|
activeForm: input.activeForm
|
|
@@ -3790,6 +3838,8 @@ function handleTaskUpdate(block, store) {
|
|
|
3790
3838
|
});
|
|
3791
3839
|
}
|
|
3792
3840
|
store.tasks.set(input.taskId, {
|
|
3841
|
+
id: existing.id,
|
|
3842
|
+
source: existing.source,
|
|
3793
3843
|
content: input.subject ?? existing.content,
|
|
3794
3844
|
status: input.status ?? existing.status,
|
|
3795
3845
|
activeForm: input.activeForm ?? existing.activeForm
|
|
@@ -3899,7 +3949,7 @@ function reportMcpSetup(message) {
|
|
|
3899
3949
|
mcp_servers: servers.map((s) => `${s.name}:${s.status}`).join(",")
|
|
3900
3950
|
});
|
|
3901
3951
|
}
|
|
3902
|
-
function handleSDKMessage(message, options, spinner, signals, receivedSuccessResult = false, tasks, suppressTaskRender = false, emitStepEvents = false, resolveStepKey) {
|
|
3952
|
+
function handleSDKMessage(message, options, spinner, signals, emit, receivedSuccessResult = false, tasks, suppressTaskRender = false, emitStepEvents = false, resolveStepKey) {
|
|
3903
3953
|
const STATUS_RANK = {
|
|
3904
3954
|
completed: 0,
|
|
3905
3955
|
in_progress: 1
|
|
@@ -3907,15 +3957,20 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3907
3957
|
const rank = (status) => STATUS_RANK[status] ?? 2;
|
|
3908
3958
|
const syncTasks = () => {
|
|
3909
3959
|
if (!tasks || suppressTaskRender) return;
|
|
3910
|
-
|
|
3911
|
-
|
|
3960
|
+
emit({
|
|
3961
|
+
kind: "tasks",
|
|
3962
|
+
tasks: Array.from(tasks.values()).sort((a, b) => rank(a.status) - rank(b.status)).map((t) => ({ ...t }))
|
|
3963
|
+
});
|
|
3912
3964
|
};
|
|
3913
3965
|
logToFile(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
|
|
3914
3966
|
if (options.debug) debug(`SDK Message type: ${message.type}`);
|
|
3915
3967
|
switch (message.type) {
|
|
3916
3968
|
case "assistant": {
|
|
3917
3969
|
const tokenUsageDelta = extractTokenUsageDelta(message);
|
|
3918
|
-
if (tokenUsageDelta)
|
|
3970
|
+
if (tokenUsageDelta) emit({
|
|
3971
|
+
kind: "usage",
|
|
3972
|
+
delta: tokenUsageDelta
|
|
3973
|
+
});
|
|
3919
3974
|
const content = message.message?.content;
|
|
3920
3975
|
if (Array.isArray(content)) for (const block of content) {
|
|
3921
3976
|
if (block.type === "text" && typeof block.text === "string") {
|
|
@@ -3924,15 +3979,26 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3924
3979
|
const statusMatch = block.text.match(statusRegex);
|
|
3925
3980
|
if (statusMatch) {
|
|
3926
3981
|
const statusText = statusMatch[1].trim();
|
|
3927
|
-
|
|
3982
|
+
emit({
|
|
3983
|
+
kind: "status",
|
|
3984
|
+
message: statusText
|
|
3985
|
+
});
|
|
3928
3986
|
spinner.message(statusText);
|
|
3929
3987
|
}
|
|
3930
3988
|
const dashboardRegex = new RegExp(`${AgentSignals.DASHBOARD_URL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*(\\S+)`, "m");
|
|
3931
3989
|
const dashboardMatch = block.text.match(dashboardRegex);
|
|
3932
|
-
if (dashboardMatch)
|
|
3990
|
+
if (dashboardMatch) emit({
|
|
3991
|
+
kind: "url",
|
|
3992
|
+
which: "dashboard",
|
|
3993
|
+
url: dashboardMatch[1].trim()
|
|
3994
|
+
});
|
|
3933
3995
|
const notebookRegex = new RegExp(`${AgentSignals.NOTEBOOK_URL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*(\\S+)`, "m");
|
|
3934
3996
|
const notebookMatch = block.text.match(notebookRegex);
|
|
3935
|
-
if (notebookMatch)
|
|
3997
|
+
if (notebookMatch) emit({
|
|
3998
|
+
kind: "url",
|
|
3999
|
+
which: "notebook",
|
|
4000
|
+
url: notebookMatch[1].trim()
|
|
4001
|
+
});
|
|
3936
4002
|
}
|
|
3937
4003
|
if (block.type === "tool_use" && tasks && Object.values(TaskTool).includes(block.name)) dispatchTaskToolUse(block, {
|
|
3938
4004
|
tasks,
|
|
@@ -3942,7 +4008,10 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3942
4008
|
});
|
|
3943
4009
|
if (block.type === "tool_use") {
|
|
3944
4010
|
const stage = classifyToolToStage(block.name);
|
|
3945
|
-
if (stage)
|
|
4011
|
+
if (stage) emit({
|
|
4012
|
+
kind: "stage",
|
|
4013
|
+
stage
|
|
4014
|
+
});
|
|
3946
4015
|
}
|
|
3947
4016
|
}
|
|
3948
4017
|
break;
|
|
@@ -3966,7 +4035,11 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3966
4035
|
logToFile("Agent result with error:", message.result);
|
|
3967
4036
|
if (typeof message.result === "string") signals.push(message.result);
|
|
3968
4037
|
if (message.errors && !receivedSuccessResult) for (const err of message.errors) {
|
|
3969
|
-
|
|
4038
|
+
emit({
|
|
4039
|
+
kind: "log",
|
|
4040
|
+
level: "error",
|
|
4041
|
+
message: `Error: ${err}`
|
|
4042
|
+
});
|
|
3970
4043
|
logToFile("ERROR:", err);
|
|
3971
4044
|
}
|
|
3972
4045
|
} else if (message.subtype === "success") {
|
|
@@ -3975,7 +4048,11 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3975
4048
|
} else {
|
|
3976
4049
|
logToFile("Agent result with error:", message.result);
|
|
3977
4050
|
if (message.errors && !receivedSuccessResult) for (const err of message.errors) {
|
|
3978
|
-
|
|
4051
|
+
emit({
|
|
4052
|
+
kind: "log",
|
|
4053
|
+
level: "error",
|
|
4054
|
+
message: `Error: ${err}`
|
|
4055
|
+
});
|
|
3979
4056
|
logToFile("ERROR:", err);
|
|
3980
4057
|
}
|
|
3981
4058
|
}
|
|
@@ -3998,6 +4075,6 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3998
4075
|
}
|
|
3999
4076
|
}
|
|
4000
4077
|
//#endregion
|
|
4001
|
-
export {
|
|
4078
|
+
export { vaultSensitiveAnswers as $, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as A, describeAskCancellation as B, AUDIT_ADD_CHECKS_PARAM_DESCRIPTION as C, AUDIT_SEED_CHECKS_PARAM_DESCRIPTION as D, AUDIT_SEED_CHECKS_DESCRIPTION as E, WIZARD_ASK_TOOL_DESCRIPTION as F, mergeEnvValues as G, ensureGitignoreCoverage as H, WIZARD_TOOL_NAMES as I, resolveAuditChecks as J, normaliseAskSubject as K, addAuditChecks as L, WIZARD_ASK_KIND_DESCRIPTION as M, WIZARD_ASK_SENSITIVE_DESCRIPTION as N, AUDIT_STATUSES as O, WIZARD_ASK_SUBJECT_DESCRIPTION as P, templateEnvWriteRefusal as Q, checkEnvKeys as R, AUDIT_ADD_CHECKS_DESCRIPTION as S, AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION as T, installSkillById as U, downloadSkill as V, legacyKeyNameRefusal as W, resolveEnvSecretRefs as X, resolveEnvPath as Y, seedAuditChecks as Z, createSecretVault as _, wizardCanUseTool as a, MAX_ENV_KEY_SET as at, PUBLISH_HANDOFF_TOOL_NAME as b, checkAllSettingsConflicts as c, toPromptSafeRelativePath as ct, restoreClaudeSettings as d, fetchSkillMenu as et, sanitizeAgentSubprocessEnv as f, assembleCommandments as g, markGrantRevoked as h, runAgent as i, isFullyCancelled as it, ENV_FILE_PATH_DESCRIPTION as j, CHECK_ENV_KEYS_DESCRIPTION as k, classifySettingsConflicts as l, createTriageLLMProvider as lt, isGrantRevoked as m, buildRunTags as n, LONGER_ASK_TIMEOUT_MS as nt, createIsolatedAgentConfigDir as o, isEnvFileName as ot, AgentOutputSignals as p, resolveAskQuestionKinds as q, initializeAgent as r, createWizardAskBridge as rt, backupAndFixClaudeSettings as s, parseEnvKeyNames as st, buildAgentEnv as t, fetchWithRetry as tt, recoverOrphanedSettingsBackups as u, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as v, AUDIT_RESOLVE_CHECKS_DESCRIPTION as w, publishHandoff as x, PUBLISH_HANDOFF_DESCRIPTION as y, createAskAccounting as z };
|
|
4002
4079
|
|
|
4003
|
-
//# sourceMappingURL=agent-interface-
|
|
4080
|
+
//# sourceMappingURL=agent-interface-BXvmAm4c.js.map
|