@posthog/wizard 2.76.1 → 2.78.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 +30 -15
- package/dist/README.md +16 -15
- package/dist/{add-mcp-server-to-clients-4yHaRvOo.js → add-mcp-server-to-clients-JMv8LP-O.js} +429 -114
- package/dist/add-mcp-server-to-clients-JMv8LP-O.js.map +1 -0
- package/dist/agent-bCZ3i3fh.js +3085 -0
- package/dist/agent-bCZ3i3fh.js.map +1 -0
- package/dist/{agent-interface-DPaPdIjS.js → agent-interface-BAOIHuXS.js} +452 -377
- package/dist/agent-interface-BAOIHuXS.js.map +1 -0
- package/dist/{agent-prompt-loader-BlhabNM2.js → agent-prompt-loader-7Pd4CfZO.js} +24 -8
- package/dist/agent-prompt-loader-7Pd4CfZO.js.map +1 -0
- package/dist/analytics-BcV-WCM4.js +2 -0
- package/dist/{analytics-DSVyjIVF.js → analytics-CHCZ_qUR.js} +10 -6
- package/dist/analytics-CHCZ_qUR.js.map +1 -0
- package/dist/{api-Ci0dZWLR.js → api-Diy_2fp8.js} +4 -17
- package/dist/api-Diy_2fp8.js.map +1 -0
- package/dist/bin.js +410 -68
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-FbZJ_vJ_.js → bounded-fs-Bx9zTe6m.js} +4 -4
- package/dist/bounded-fs-Bx9zTe6m.js.map +1 -0
- package/dist/check-screens.tsx +1 -1
- package/dist/{ci-install-CEVCqahf.js → ci-install-CDdQYsPe.js} +6 -5
- package/dist/ci-install-CDdQYsPe.js.map +1 -0
- package/dist/constants-jFI2SaE1.js +260 -0
- package/dist/constants-jFI2SaE1.js.map +1 -0
- package/dist/debug-Ch4BDOtD.js +171 -0
- package/dist/debug-Ch4BDOtD.js.map +1 -0
- package/dist/{debug-C6KWXbQi.js → debug-M2gV2iDq.js} +1 -1
- package/dist/{defaults-DulzMJpN.js → defaults-C6J7yL4O.js} +26 -3
- package/dist/defaults-C6J7yL4O.js.map +1 -0
- package/dist/endpoints-DCVbM06L.js +108 -0
- package/dist/endpoints-DCVbM06L.js.map +1 -0
- package/dist/{env-api-key-DwmkB3fm.js → env-api-key-Qx8NnYHm.js} +3 -3
- package/dist/env-api-key-Qx8NnYHm.js.map +1 -0
- package/dist/{environment-1wA7uwAS.js → environment-B07Bmxae.js} +6 -6
- package/dist/environment-B07Bmxae.js.map +1 -0
- package/dist/{errors--OqLxmWR.js → errors-CQ9kttJD.js} +30 -35
- package/dist/errors-CQ9kttJD.js.map +1 -0
- package/dist/{file-C3HGL1IM.js → file-BcLTjU16.js} +2 -2
- package/dist/{file-C3HGL1IM.js.map → file-BcLTjU16.js.map} +1 -1
- package/dist/{file-watcher-D8s0b-VT.js → file-watcher-DWc_bTs6.js} +2 -2
- package/dist/{file-watcher-D8s0b-VT.js.map → file-watcher-DWc_bTs6.js.map} +1 -1
- package/dist/{gateway-session-OqzCMpZ9.js → gateway-CjoShdLa.js} +175 -20
- package/dist/gateway-CjoShdLa.js.map +1 -0
- package/dist/generate-version.cjs +1 -1
- package/dist/{headless-ui-DRGWDg9Z.js → headless-ui-BFFmYC4v.js} +13 -2
- package/dist/headless-ui-BFFmYC4v.js.map +1 -0
- package/dist/{interactive-B6OlvhSf.js → interactive-D6zV7brJ.js} +2 -2
- package/dist/{interactive-B6OlvhSf.js.map → interactive-D6zV7brJ.js.map} +1 -1
- 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-_TwoMNbG.js +226 -0
- package/dist/logging-ui-_TwoMNbG.js.map +1 -0
- package/dist/mcp-DAgaoGk5.js +97 -0
- package/dist/mcp-DAgaoGk5.js.map +1 -0
- package/dist/{mcp-prompt-streaming-E1d8DJcX.js → mcp-prompt-streaming-I2U_X7BC.js} +7 -6
- package/dist/mcp-prompt-streaming-I2U_X7BC.js.map +1 -0
- package/dist/{mint-failure-C82j0RMC.js → mint-failure-D4nd2XmZ.js} +134 -48
- package/dist/mint-failure-D4nd2XmZ.js.map +1 -0
- package/dist/models-DDdBJKwT.js +83 -0
- package/dist/models-DDdBJKwT.js.map +1 -0
- package/dist/{non-interactive-DGT2H_n4.js → non-interactive-Dzow7YKY.js} +3 -3
- package/dist/non-interactive-Dzow7YKY.js.map +1 -0
- package/dist/oauth-session-DJ8h6GFa.js +74 -0
- package/dist/oauth-session-DJ8h6GFa.js.map +1 -0
- package/dist/{orchestrator-tools-BBBNV1z5.js → orchestrator-tools-szcdscwn.js} +5 -5
- package/dist/orchestrator-tools-szcdscwn.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-fG5fT50Y.js → pi-D3h5Ok0i.js} +329 -65
- package/dist/pi-D3h5Ok0i.js.map +1 -0
- package/dist/{playground-UFSHP-Yn.js → playground-5AB4WgNF.js} +18 -10
- package/dist/playground-5AB4WgNF.js.map +1 -0
- package/dist/{posthog-O9kKcnda.js → posthog-DNn574nW.js} +8 -3
- package/dist/posthog-DNn574nW.js.map +1 -0
- package/dist/{provisioning-B-tzjG4r.js → provisioning-B8uSqRZk.js} +6 -5
- package/dist/provisioning-B8uSqRZk.js.map +1 -0
- package/dist/{queue-tools-7Oso-fpt.js → queue-tools-9OOVx5TE.js} +11 -86
- package/dist/queue-tools-9OOVx5TE.js.map +1 -0
- package/dist/{registry-D1L5e-WQ.js → registry-8YG-kuXk.js} +265 -6
- package/dist/registry-8YG-kuXk.js.map +1 -0
- package/dist/run-agent-legacy-d7rWlzQR.js +3739 -0
- package/dist/run-agent-legacy-d7rWlzQR.js.map +1 -0
- package/dist/{security-n3-xdINN.js → security-Cg_4a7vB.js} +6 -6
- package/dist/security-Cg_4a7vB.js.map +1 -0
- package/dist/{setup-utils-Bj0gejEf.js → setup-utils-CmTCTPkX.js} +46 -18
- package/dist/setup-utils-CmTCTPkX.js.map +1 -0
- package/dist/smoke-test.sh +1 -1
- package/dist/{start-tui-BowrTPXm.js → start-tui-CB2PZs1x.js} +42 -48
- package/dist/start-tui-CB2PZs1x.js.map +1 -0
- package/dist/{steps-CpNTGu9N.js → steps-BZcXRJNY.js} +7 -7
- package/dist/{steps-CpNTGu9N.js.map → steps-BZcXRJNY.js.map} +1 -1
- package/dist/{store-CVkJKlny.js → store-UN7c-ASf.js} +18 -55
- package/dist/store-UN7c-ASf.js.map +1 -0
- package/dist/{subagent-SxmvfDfp.js → subagent-BofIDK-O.js} +8 -3
- package/dist/subagent-BofIDK-O.js.map +1 -0
- package/dist/{task-nF7Ry8ff.js → task-r9t1UhQP.js} +124 -36
- package/dist/task-r9t1UhQP.js.map +1 -0
- package/dist/{task-stream-C9BLiAhz.js → task-stream-CMUilu54.js} +45 -15
- package/dist/task-stream-CMUilu54.js.map +1 -0
- package/dist/{tasks-BEEVIBcT.js → tasks-Bbv_lOBG.js} +17 -13
- package/dist/tasks-Bbv_lOBG.js.map +1 -0
- package/dist/{telemetry-PD7bhcda.js → telemetry-D6ruCtnv.js} +5 -5
- package/dist/telemetry-D6ruCtnv.js.map +1 -0
- package/dist/{terminal-NhNl-BIA.js → terminal-DrGyci_a.js} +63 -94
- package/dist/terminal-DrGyci_a.js.map +1 -0
- package/dist/{tools-BBdpgcIf.js → tools-Dyfh9aCD.js} +11 -11
- package/dist/tools-Dyfh9aCD.js.map +1 -0
- package/dist/ui-BBVuTM1v.js +15 -0
- package/dist/ui-BBVuTM1v.js.map +1 -0
- package/dist/version-aXxpgRKx.js +6 -0
- package/dist/version-aXxpgRKx.js.map +1 -0
- package/dist/warlock-smoke-test.ts +2 -2
- package/dist/{wizard-abort-hqHF-9xD.js → wizard-abort-BBkiUxfS.js} +23 -20
- package/dist/wizard-abort-BBkiUxfS.js.map +1 -0
- package/dist/wizard-abort-BU4aLyvh.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-BaPKsm-B.js → yara-hooks-DCeMDd1o.js} +19 -68
- package/dist/yara-hooks-DCeMDd1o.js.map +1 -0
- package/dist/yara-hooks-DSGuCU9A.js +2 -0
- package/package.json +8 -1
- package/dist/add-mcp-server-to-clients-4yHaRvOo.js.map +0 -1
- package/dist/agent-interface-DPaPdIjS.js.map +0 -1
- package/dist/agent-prompt-loader-BlhabNM2.js.map +0 -1
- package/dist/agent-runner-JFwQQj2k.js +0 -6100
- package/dist/agent-runner-JFwQQj2k.js.map +0 -1
- package/dist/analytics-CcHoyhE_.js +0 -2
- package/dist/analytics-DSVyjIVF.js.map +0 -1
- package/dist/api-Ci0dZWLR.js.map +0 -1
- package/dist/bounded-fs-FbZJ_vJ_.js.map +0 -1
- package/dist/ci-install-CEVCqahf.js.map +0 -1
- package/dist/debug-DWYDVp0B.js +0 -750
- package/dist/debug-DWYDVp0B.js.map +0 -1
- package/dist/defaults-DulzMJpN.js.map +0 -1
- package/dist/env-api-key-DwmkB3fm.js.map +0 -1
- package/dist/environment-1wA7uwAS.js.map +0 -1
- package/dist/errors--OqLxmWR.js.map +0 -1
- package/dist/gateway-session-OqzCMpZ9.js.map +0 -1
- package/dist/gateway-session-s1xr8b48.js +0 -2
- package/dist/headless-ui-DRGWDg9Z.js.map +0 -1
- package/dist/local-dev-DPZiIPCK.js.map +0 -1
- package/dist/mcp-BprhJJ2c.js +0 -64
- package/dist/mcp-BprhJJ2c.js.map +0 -1
- package/dist/mcp-prompt-streaming-E1d8DJcX.js.map +0 -1
- package/dist/mint-failure-C82j0RMC.js.map +0 -1
- package/dist/non-interactive-DGT2H_n4.js.map +0 -1
- package/dist/orchestrator-tools-BBBNV1z5.js.map +0 -1
- package/dist/package-json-xt3eeyBI.js.map +0 -1
- package/dist/package-manager-DU3aVif4.js +0 -290
- package/dist/package-manager-DU3aVif4.js.map +0 -1
- package/dist/pi-fG5fT50Y.js.map +0 -1
- package/dist/playground-UFSHP-Yn.js.map +0 -1
- package/dist/posthog-O9kKcnda.js.map +0 -1
- package/dist/provisioning-B-tzjG4r.js.map +0 -1
- package/dist/queue-tools-7Oso-fpt.js.map +0 -1
- package/dist/registry-D1L5e-WQ.js.map +0 -1
- package/dist/security-n3-xdINN.js.map +0 -1
- package/dist/setup-utils-Bj0gejEf.js.map +0 -1
- package/dist/start-tui-BowrTPXm.js.map +0 -1
- package/dist/store-CVkJKlny.js.map +0 -1
- package/dist/subagent-SxmvfDfp.js.map +0 -1
- package/dist/task-nF7Ry8ff.js.map +0 -1
- package/dist/task-stream-C9BLiAhz.js.map +0 -1
- package/dist/tasks-BEEVIBcT.js.map +0 -1
- package/dist/telemetry-PD7bhcda.js.map +0 -1
- package/dist/terminal-NhNl-BIA.js.map +0 -1
- package/dist/tools-BBdpgcIf.js.map +0 -1
- package/dist/wizard-abort-D3YA1hXX.js +0 -2
- package/dist/wizard-abort-hqHF-9xD.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-BaPKsm-B.js.map +0 -1
- package/dist/yara-hooks-CwfQuEl3.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 { a as AgentSignals, c as classifyAuthFailure, o as REMARK_INSTRUCTION, s as RESUME_INSTRUCTION } from "./errors-CQ9kttJD.js";
|
|
3
|
+
import { a as getLogFilePath, o as initLogFile, r as debug, s as logToFile, v as runtimeEnv } from "./debug-Ch4BDOtD.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-jFI2SaE1.js";
|
|
5
|
+
import { n as analytics } from "./analytics-CHCZ_qUR.js";
|
|
6
|
+
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-Bx9zTe6m.js";
|
|
7
|
+
import { t as registerCleanup } from "./wizard-abort-BBkiUxfS.js";
|
|
8
|
+
import { i as gatewayApiFor, l as gatewayAuth, n as buildGatewayModel, s as buildWizardPropertiesBlob, u as isPastRefresh } from "./gateway-CjoShdLa.js";
|
|
9
|
+
import { i as modelCapabilities, o as triageModelFor } from "./models-DDdBJKwT.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-DCeMDd1o.js";
|
|
11
|
+
import { l as buildOrchestratorTools, v as makeMutex, y as writeJsonAtomic } from "./queue-tools-9OOVx5TE.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";
|
|
20
21
|
import * as os from "os";
|
|
21
22
|
import { unzipSync } from "fflate";
|
|
22
|
-
import { randomUUID } from "crypto";
|
|
23
|
-
//#region src/
|
|
24
|
-
|
|
25
|
-
|
|
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;
|
|
23
|
+
import { randomUUID as randomUUID$1 } from "crypto";
|
|
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);
|
|
@@ -966,6 +1025,7 @@ async function downloadSkill(skillEntry, installDir, { skillsRoot, triage }) {
|
|
|
966
1025
|
step = "extract";
|
|
967
1026
|
const fileCount = skillEntry.bundle ? extractBundle(JSON.parse(Buffer.from(data).toString("utf8")), skillDir, skillEntry.id) : extractZipArchive(data, skillDir);
|
|
968
1027
|
fs.writeFileSync(path.join(skillDir, ".posthog-wizard"), "");
|
|
1028
|
+
step = "scan";
|
|
969
1029
|
const poisonReason = await scanInstalledSkill(skillDir, triage);
|
|
970
1030
|
if (poisonReason) {
|
|
971
1031
|
fs.rmSync(skillDir, {
|
|
@@ -1096,7 +1156,7 @@ const WIZARD_ASK_SUBJECT_DESCRIPTION = "Short, stable tag naming what this call
|
|
|
1096
1156
|
* server in `./mcp` and the pi-native mirror in `harness/pi/tools.ts`) so the
|
|
1097
1157
|
* batching and cancellation contract reads identically in both harnesses.
|
|
1098
1158
|
*/
|
|
1099
|
-
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.`;
|
|
1100
1160
|
/**
|
|
1101
1161
|
* Guidance returned with a `wizard_ask` result when the user dismissed the
|
|
1102
1162
|
* prompt. Shared by both harness facades, like the descriptions above.
|
|
@@ -1175,7 +1235,7 @@ function evaluateAskCap({ callCount, maxQuestions, subject, subjectRunLength, ad
|
|
|
1175
1235
|
reason: "adjacency",
|
|
1176
1236
|
subject,
|
|
1177
1237
|
subjectRunLength,
|
|
1178
|
-
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.`
|
|
1179
1239
|
};
|
|
1180
1240
|
return { kind: "ok" };
|
|
1181
1241
|
}
|
|
@@ -1566,11 +1626,7 @@ const WIZARD_TOOL_NAMES = {
|
|
|
1566
1626
|
readHandoffs: `mcp__${SERVER_NAME}__read_handoffs`
|
|
1567
1627
|
};
|
|
1568
1628
|
//#endregion
|
|
1569
|
-
//#region src/
|
|
1570
|
-
/**
|
|
1571
|
-
* publish_handoff — the agent publishes the run's handoff doc (the report
|
|
1572
|
-
* markdown) in one explicit call, replacing the report file + watcher path.
|
|
1573
|
-
*/
|
|
1629
|
+
//#region src/agent/tools/handoff.ts
|
|
1574
1630
|
const MAX_HANDOFF_TEXT_CHARS = 64 * 1024;
|
|
1575
1631
|
const PUBLISH_HANDOFF_TOOL_NAME = "publish_handoff";
|
|
1576
1632
|
/** Shared between the MCP server and the pi facade so the contract can't drift. */
|
|
@@ -1636,7 +1692,7 @@ function writeHandoffFileAtomically(targetPath, text) {
|
|
|
1636
1692
|
};
|
|
1637
1693
|
}
|
|
1638
1694
|
}
|
|
1639
|
-
function publishHandoff(content) {
|
|
1695
|
+
function publishHandoff(content, emit) {
|
|
1640
1696
|
if (content.trim() === "") {
|
|
1641
1697
|
analytics.wizardCapture("handoff published", {
|
|
1642
1698
|
handoff_ok: false,
|
|
@@ -1649,7 +1705,10 @@ function publishHandoff(content) {
|
|
|
1649
1705
|
}
|
|
1650
1706
|
const truncated = content.length > MAX_HANDOFF_TEXT_CHARS;
|
|
1651
1707
|
const text = truncated ? content.slice(0, MAX_HANDOFF_TEXT_CHARS) : content;
|
|
1652
|
-
|
|
1708
|
+
emit?.({
|
|
1709
|
+
kind: "handoff",
|
|
1710
|
+
text
|
|
1711
|
+
});
|
|
1653
1712
|
const handoffOutputPath = runtimeEnv("POSTHOG_HANDOFF_OUTPUT_PATH");
|
|
1654
1713
|
let handoffOutputWritten;
|
|
1655
1714
|
let handoffOutputError;
|
|
@@ -1676,7 +1735,7 @@ function publishHandoff(content) {
|
|
|
1676
1735
|
};
|
|
1677
1736
|
}
|
|
1678
1737
|
//#endregion
|
|
1679
|
-
//#region src/
|
|
1738
|
+
//#region src/shared/secret-vault.ts
|
|
1680
1739
|
/**
|
|
1681
1740
|
* Session-scoped secret vault.
|
|
1682
1741
|
*
|
|
@@ -1696,7 +1755,7 @@ function createSecretVault() {
|
|
|
1696
1755
|
const store = /* @__PURE__ */ new Map();
|
|
1697
1756
|
return {
|
|
1698
1757
|
put(value, meta) {
|
|
1699
|
-
const ref = `${REF_PREFIX}${randomUUID()}`;
|
|
1758
|
+
const ref = `${REF_PREFIX}${randomUUID$1()}`;
|
|
1700
1759
|
store.set(ref, {
|
|
1701
1760
|
value,
|
|
1702
1761
|
meta: {
|
|
@@ -1723,7 +1782,7 @@ function createSecretVault() {
|
|
|
1723
1782
|
};
|
|
1724
1783
|
}
|
|
1725
1784
|
//#endregion
|
|
1726
|
-
//#region src/
|
|
1785
|
+
//#region src/agent/tools/mcp.ts
|
|
1727
1786
|
/**
|
|
1728
1787
|
* MCP facade over `./tools` — the unified in-process server the anthropic
|
|
1729
1788
|
* harness mounts. Declarations (zod schemas, descriptions) and the MCP result
|
|
@@ -1758,7 +1817,7 @@ async function getSDKModule$1() {
|
|
|
1758
1817
|
* Must be called asynchronously because the SDK is an ESM module loaded via dynamic import.
|
|
1759
1818
|
*/
|
|
1760
1819
|
async function createWizardToolsServer(options) {
|
|
1761
|
-
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;
|
|
1762
1821
|
const { tool, createSdkMcpServer } = await getSDKModule$1();
|
|
1763
1822
|
const askAccounting = createAskAccounting(askMaxQuestions);
|
|
1764
1823
|
let cachedSkillMenu = {};
|
|
@@ -1960,7 +2019,7 @@ async function createWizardToolsServer(options) {
|
|
|
1960
2019
|
auditAddChecks,
|
|
1961
2020
|
auditResolveChecks,
|
|
1962
2021
|
tool("wizard_ask", WIZARD_ASK_TOOL_DESCRIPTION, {
|
|
1963
|
-
questions: z.array(askQuestionSchema).min(1).max(
|
|
2022
|
+
questions: z.array(askQuestionSchema).min(1).max(12),
|
|
1964
2023
|
subject: z.string().optional().describe(WIZARD_ASK_SUBJECT_DESCRIPTION)
|
|
1965
2024
|
}, async (args) => {
|
|
1966
2025
|
if (!askBridge) return {
|
|
@@ -2045,7 +2104,7 @@ async function createWizardToolsServer(options) {
|
|
|
2045
2104
|
}
|
|
2046
2105
|
}),
|
|
2047
2106
|
tool(PUBLISH_HANDOFF_TOOL_NAME, PUBLISH_HANDOFF_DESCRIPTION, { content: z.string().describe(PUBLISH_HANDOFF_CONTENT_DESCRIPTION) }, (args) => {
|
|
2048
|
-
const result = publishHandoff(args.content);
|
|
2107
|
+
const result = publishHandoff(args.content, emit);
|
|
2049
2108
|
logToFile(`publish_handoff: ${result.message}`);
|
|
2050
2109
|
return {
|
|
2051
2110
|
content: [{
|
|
@@ -2060,197 +2119,7 @@ async function createWizardToolsServer(options) {
|
|
|
2060
2119
|
});
|
|
2061
2120
|
}
|
|
2062
2121
|
//#endregion
|
|
2063
|
-
//#region src/
|
|
2064
|
-
/**
|
|
2065
|
-
* PostHog AI gateway provider spec for pi sessions, shared by the linear run
|
|
2066
|
-
* and the orchestrator's per-task runs so both speak to the gateway
|
|
2067
|
-
* identically: bearer auth, the wizard properties header, transport shape
|
|
2068
|
-
* inferred from the model id. The caller registers the spec on its own
|
|
2069
|
-
* (lazily imported, properly typed) pi ModelRegistry.
|
|
2070
|
-
*/
|
|
2071
|
-
/** Provider registered on the in-memory registry for this run. */
|
|
2072
|
-
const GATEWAY_PROVIDER = "posthog-gateway";
|
|
2073
|
-
/**
|
|
2074
|
-
* The gateway speaks two shapes on two endpoints: Anthropic models over
|
|
2075
|
-
* `anthropic-messages` (the SDK appends `/v1/messages`, so the base URL has no
|
|
2076
|
-
* `/v1`), and OpenAI-class models (`openai/gpt-5`, …) over an OpenAI shape at
|
|
2077
|
-
* `/v1/responses` or `/v1/chat/completions` (base URL keeps `/v1`). Infer the
|
|
2078
|
-
* shape from the model id so a pair's model selects the right transport.
|
|
2079
|
-
*
|
|
2080
|
-
* OpenAI models take the Responses API because OpenAI rejects function tools
|
|
2081
|
-
* combined with `reasoning_effort` on chat completions and every task sends both.
|
|
2082
|
-
*/
|
|
2083
|
-
function gatewayApiFor(modelId) {
|
|
2084
|
-
return modelId.startsWith("openai/") ? "openai-responses" : "anthropic-messages";
|
|
2085
|
-
}
|
|
2086
|
-
/**
|
|
2087
|
-
* Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path: one
|
|
2088
|
-
* `X-PostHog-Properties` JSON blob (Bedrock fallback is native, so no opt-in)
|
|
2089
|
-
* plus the 1M context beta, since pi otherwise runs at 200k and overflows on
|
|
2090
|
-
* larger projects (the post-run compaction failures).
|
|
2091
|
-
*/
|
|
2092
|
-
function buildGatewayHeaders(wizardMetadata, wizardFlags, teamId) {
|
|
2093
|
-
return {
|
|
2094
|
-
"anthropic-beta": "context-1m-2025-08-07",
|
|
2095
|
-
"X-PostHog-Properties": buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId)
|
|
2096
|
-
};
|
|
2097
|
-
}
|
|
2098
|
-
/**
|
|
2099
|
-
* One gateway model spec — the single description of how to reach a model on
|
|
2100
|
-
* the gateway. The provider spec below wraps it for pi's registry; one-shot
|
|
2101
|
-
* callers (scan triage) hand it straight to `completeSimple`.
|
|
2102
|
-
*/
|
|
2103
|
-
function buildGatewayModel(inputs) {
|
|
2104
|
-
const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId } = inputs;
|
|
2105
|
-
const api = gatewayApiFor(modelId);
|
|
2106
|
-
return {
|
|
2107
|
-
id: modelId,
|
|
2108
|
-
name: `${modelId} (PostHog Gateway)`,
|
|
2109
|
-
api,
|
|
2110
|
-
provider: GATEWAY_PROVIDER,
|
|
2111
|
-
baseUrl: api === "anthropic-messages" ? gatewayUrl : `${gatewayUrl}/v1`,
|
|
2112
|
-
reasoning: modelCapabilities(modelId).reasoning,
|
|
2113
|
-
input: ["text"],
|
|
2114
|
-
cost: {
|
|
2115
|
-
input: 0,
|
|
2116
|
-
output: 0,
|
|
2117
|
-
cacheRead: 0,
|
|
2118
|
-
cacheWrite: 0
|
|
2119
|
-
},
|
|
2120
|
-
contextWindow: 1e6,
|
|
2121
|
-
maxTokens: 64e3,
|
|
2122
|
-
headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId)
|
|
2123
|
-
};
|
|
2124
|
-
}
|
|
2125
|
-
/**
|
|
2126
|
-
* The provider object for `registry.registerProvider(GATEWAY_PROVIDER, …)`,
|
|
2127
|
-
* plus the derived traits the session setup needs (`caps.thinkingLevel`).
|
|
2128
|
-
*/
|
|
2129
|
-
function buildGatewayProvider(inputs) {
|
|
2130
|
-
const { gatewayUrl, accessToken, modelId, effort } = inputs;
|
|
2131
|
-
const api = gatewayApiFor(modelId);
|
|
2132
|
-
const tableCaps = modelCapabilities(modelId);
|
|
2133
|
-
const caps = effort && effort !== "off" && tableCaps.reasoning ? modelCapabilities(modelId, effort) : effort === "off" && tableCaps.reasoning ? {
|
|
2134
|
-
...tableCaps,
|
|
2135
|
-
thinkingLevel: "off"
|
|
2136
|
-
} : tableCaps;
|
|
2137
|
-
const model = buildGatewayModel(inputs);
|
|
2138
|
-
return {
|
|
2139
|
-
provider: {
|
|
2140
|
-
name: "PostHog Gateway",
|
|
2141
|
-
baseUrl: model.baseUrl,
|
|
2142
|
-
apiKey: accessToken,
|
|
2143
|
-
authHeader: true,
|
|
2144
|
-
api,
|
|
2145
|
-
headers: model.headers,
|
|
2146
|
-
models: [model]
|
|
2147
|
-
},
|
|
2148
|
-
api,
|
|
2149
|
-
caps,
|
|
2150
|
-
gatewayUrl,
|
|
2151
|
-
baseUrl: model.baseUrl
|
|
2152
|
-
};
|
|
2153
|
-
}
|
|
2154
|
-
/**
|
|
2155
|
-
* Whether a turn's error is the gateway rejecting the bearer. pi attaches the
|
|
2156
|
-
* SDK's own error to `diagnostics`, so its code decides when one is present.
|
|
2157
|
-
* The message match is the fallback for a turn that failed before pi built a
|
|
2158
|
-
* diagnostic, where the status survives only as prose.
|
|
2159
|
-
*/
|
|
2160
|
-
function isGatewayAuthRejection(turn) {
|
|
2161
|
-
const { errorMessage, diagnostics } = typeof turn === "string" ? {
|
|
2162
|
-
errorMessage: turn,
|
|
2163
|
-
diagnostics: void 0
|
|
2164
|
-
} : turn ?? {};
|
|
2165
|
-
for (const diagnostic of diagnostics ?? []) {
|
|
2166
|
-
const code = diagnostic.error?.code;
|
|
2167
|
-
if (code === 401 || code === "401") return true;
|
|
2168
|
-
if (/^authentication_?error$/i.test(diagnostic.error?.name ?? "")) return true;
|
|
2169
|
-
}
|
|
2170
|
-
return /\b401\b|authentication_error|unauthorized/i.test(errorMessage ?? "");
|
|
2171
|
-
}
|
|
2172
|
-
/**
|
|
2173
|
-
* Wraps a pi session's prompt(): when a turn ends on a 401 from a bearer past
|
|
2174
|
-
* its refresh instant, mint once, re-register the provider with the new
|
|
2175
|
-
* bearer (pi resolves the apiKey per request), and continue. A 401 on a fresh
|
|
2176
|
-
* bearer, or a second one, is left to the harness's normal failure path.
|
|
2177
|
-
*/
|
|
2178
|
-
function withGatewayRemint(opts) {
|
|
2179
|
-
let auth = opts.auth;
|
|
2180
|
-
let rejected = false;
|
|
2181
|
-
let reminted = false;
|
|
2182
|
-
return {
|
|
2183
|
-
noteAssistantTurn(message) {
|
|
2184
|
-
const turn = message;
|
|
2185
|
-
rejected = turn?.stopReason === "error" && isGatewayAuthRejection(turn);
|
|
2186
|
-
},
|
|
2187
|
-
async prompt(text) {
|
|
2188
|
-
rejected = false;
|
|
2189
|
-
await opts.session.prompt(text);
|
|
2190
|
-
if (!rejected || reminted || !isPastRefresh(auth)) return;
|
|
2191
|
-
reminted = true;
|
|
2192
|
-
auth = await opts.refreshAuth();
|
|
2193
|
-
opts.registry.registerProvider(GATEWAY_PROVIDER, buildGatewayProvider(opts.providerInputs(auth)).provider);
|
|
2194
|
-
opts.onRemint?.();
|
|
2195
|
-
rejected = false;
|
|
2196
|
-
const next = opts.continueText;
|
|
2197
|
-
await opts.session.prompt(typeof next === "function" ? next() : next);
|
|
2198
|
-
}
|
|
2199
|
-
};
|
|
2200
|
-
}
|
|
2201
|
-
//#endregion
|
|
2202
|
-
//#region src/lib/agent/triage-provider.ts
|
|
2203
|
-
const TRIAGE_MAX_TOKENS = 16384;
|
|
2204
|
-
const TRIAGE_TIMEOUT_MS = 2e4;
|
|
2205
|
-
/**
|
|
2206
|
-
* Triage provider for a harness. Auth is always explicit: every caller already
|
|
2207
|
-
* holds the gateway url and the run's token, and reading them back out of
|
|
2208
|
-
* ANTHROPIC_* made an unauthed provider silent — it returned undefined, the
|
|
2209
|
-
* caller failed closed, and a clean first-party skill got deleted. A resolver
|
|
2210
|
-
* is re-read on every call, so a run that re-mints mid-way scans with the
|
|
2211
|
-
* current bearer rather than the one it started with.
|
|
2212
|
-
*/
|
|
2213
|
-
function createTriageLLMProvider(auth, harness) {
|
|
2214
|
-
const resolveAuth = typeof auth === "function" ? auth : () => Promise.resolve(auth);
|
|
2215
|
-
const modelId = triageModelFor(harness);
|
|
2216
|
-
const { reasoning, thinkingLevel } = modelCapabilities(modelId);
|
|
2217
|
-
logToFile(`[YARA] triage provider ready (model: ${modelId}, api: ${gatewayApiFor(modelId)})`);
|
|
2218
|
-
return async (prompt) => {
|
|
2219
|
-
const { completeSimple } = await import("@earendil-works/pi-ai");
|
|
2220
|
-
const current = await resolveAuth();
|
|
2221
|
-
const authToken = current.authToken;
|
|
2222
|
-
const model = buildGatewayModel({
|
|
2223
|
-
gatewayUrl: current.baseURL,
|
|
2224
|
-
accessToken: authToken,
|
|
2225
|
-
teamId: current.teamId,
|
|
2226
|
-
wizardMetadata: current.wizardMetadata ?? {},
|
|
2227
|
-
wizardFlags: current.wizardFlags ?? {},
|
|
2228
|
-
modelId
|
|
2229
|
-
});
|
|
2230
|
-
const controller = new AbortController();
|
|
2231
|
-
const timer = setTimeout(() => controller.abort(), TRIAGE_TIMEOUT_MS);
|
|
2232
|
-
try {
|
|
2233
|
-
const message = await completeSimple(model, { messages: [{
|
|
2234
|
-
role: "user",
|
|
2235
|
-
content: prompt,
|
|
2236
|
-
timestamp: Date.now()
|
|
2237
|
-
}] }, {
|
|
2238
|
-
apiKey: authToken,
|
|
2239
|
-
temperature: model.api === "anthropic-messages" ? 0 : void 0,
|
|
2240
|
-
maxTokens: TRIAGE_MAX_TOKENS,
|
|
2241
|
-
reasoning: reasoning && thinkingLevel !== "off" ? thinkingLevel : void 0,
|
|
2242
|
-
signal: controller.signal
|
|
2243
|
-
});
|
|
2244
|
-
const text = message.content.filter((c) => c.type === "text").map((c) => c.text).join("");
|
|
2245
|
-
if (message.stopReason === "error") logToFile(`[YARA] triage call failed on ${model.id}: ${message.errorMessage ?? "unknown"} — every flagged match will be acted on`);
|
|
2246
|
-
return text;
|
|
2247
|
-
} finally {
|
|
2248
|
-
clearTimeout(timer);
|
|
2249
|
-
}
|
|
2250
|
-
};
|
|
2251
|
-
}
|
|
2252
|
-
//#endregion
|
|
2253
|
-
//#region src/lib/agent/commandments.ts
|
|
2122
|
+
//#region src/agent/commandments.ts
|
|
2254
2123
|
/**
|
|
2255
2124
|
* Commandments true for every run, whatever program, sequence, harness, or model
|
|
2256
2125
|
* it resolves to. Anything narrower belongs to its axis in
|
|
@@ -2283,7 +2152,7 @@ const WIZARD_COMMANDMENTS = [
|
|
|
2283
2152
|
].join("\n")
|
|
2284
2153
|
];
|
|
2285
2154
|
//#endregion
|
|
2286
|
-
//#region src/
|
|
2155
|
+
//#region src/agent/runner/harness/pi/runtime-notes.ts
|
|
2287
2156
|
const HEADER = ["## This runtime", "Below are important guidance on the harness constraints you are bound to. Follow them as commandments."];
|
|
2288
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.";
|
|
2289
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`.";
|
|
@@ -2304,7 +2173,7 @@ const POSTHOG_MCP = "- The PostHog MCP is a SINGLE tool named `posthog_exec` tha
|
|
|
2304
2173
|
const DASHBOARD_STEP = "- For the dashboard step, drive it entirely through `posthog_exec`: create the dashboard first, then add each insight to it — `call dashboard-create {…}`, then a `call insight-create {…}` per insight. The JSON argument objects are the same ones the named tools took.";
|
|
2305
2174
|
/** LINEAR only: one pi session drives the whole flow and manages the run. */
|
|
2306
2175
|
const DONT_SPIRAL = "- If you get stuck on something outside your control — a package install that keeps failing, a command you are not permitted to run, or a fix outside the scope of this integration — do NOT spiral retrying it. Note it in the setup report for the user to resolve, and move on with the rest of the work.";
|
|
2307
|
-
const SKILL_MENU = "- Call `load_skill_menu` once
|
|
2176
|
+
const SKILL_MENU = "- Call `load_skill_menu` once per category needed by the workflow, then `install_skill` with the chosen ID. Reuse a category’s menu instead of loading it again.";
|
|
2308
2177
|
const SKILL_STEPS = "- Follow the skill's steps in order. Finish the SDK setup — install it, import it at the top of the module, and INITIALIZE it at the framework's entry point for every runtime the integration targets (typically both client and server) — BEFORE adding any event capture. A capture against an uninitialized SDK silently no-ops, so initialization comes first. If you're stuck and cannot install an SDK, add capture calls and add a clear note at the top of the integration report. Never guard a capture behind a runtime \"if the SDK happens to be installed\" check or a dynamic `require`; that ships an uninitialized SDK and no events fire. Do not jump ahead to the fix/revise step just to get a build passing.";
|
|
2309
2178
|
const VERIFY_WITH_BUILD = "- When the skill asks you to verify or revise, actually verify: if the project defines a build/typecheck/lint script, run it via bash and confirm the SDK imports and initializes. If it defines none, confirm by reading the files — do NOT shell out to ad-hoc checks like `node -e` or `python -c`; they are blocked. A file being written is not verification.";
|
|
2310
2179
|
const DISPATCH_AGENT = "- When you call `dispatch_agent`, make the prompt fully self-contained (exact paths, patterns, and the precise question) — the subagent can't see your context, is read-only, and can't dispatch further.";
|
|
@@ -2341,7 +2210,7 @@ function piRuntimeNotes(sequence, caps) {
|
|
|
2341
2210
|
return notes.join("\n");
|
|
2342
2211
|
}
|
|
2343
2212
|
//#endregion
|
|
2344
|
-
//#region src/
|
|
2213
|
+
//#region src/agent/runner/switchboard/commandments.ts
|
|
2345
2214
|
/**
|
|
2346
2215
|
* LINEAR only. One session drives the whole run and holds the Task tools; an
|
|
2347
2216
|
* orchestrator task session holds none of them and reports through
|
|
@@ -2388,7 +2257,7 @@ function assembleCommandments(axes) {
|
|
|
2388
2257
|
].filter(Boolean).join("\n");
|
|
2389
2258
|
}
|
|
2390
2259
|
//#endregion
|
|
2391
|
-
//#region src/
|
|
2260
|
+
//#region src/shared/agent-phase.ts
|
|
2392
2261
|
/** Maps a Claude SDK tool name to the phase that tool implies. Returns null
|
|
2393
2262
|
* when the tool doesn't drive the visualizer (Task*, TodoWrite, etc.). */
|
|
2394
2263
|
function classifyToolToStage(toolName) {
|
|
@@ -2401,7 +2270,35 @@ function classifyToolToStage(toolName) {
|
|
|
2401
2270
|
return null;
|
|
2402
2271
|
}
|
|
2403
2272
|
//#endregion
|
|
2404
|
-
//#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
|
|
2405
2302
|
/**
|
|
2406
2303
|
* Parses the signal-bearing lines out of agent output and discards the rest.
|
|
2407
2304
|
*
|
|
@@ -2508,7 +2405,7 @@ var AgentOutputSignals = class {
|
|
|
2508
2405
|
}
|
|
2509
2406
|
};
|
|
2510
2407
|
//#endregion
|
|
2511
|
-
//#region src/
|
|
2408
|
+
//#region src/agent/agent-env-isolation.ts
|
|
2512
2409
|
/**
|
|
2513
2410
|
* Credential isolation for the Claude Agent SDK subprocess.
|
|
2514
2411
|
*
|
|
@@ -2572,6 +2469,7 @@ const BLOCKED_OFF_NAMESPACE_KEYS = new Set(["AWS_BEARER_TOKEN_BEDROCK"]);
|
|
|
2572
2469
|
const HOST_ONLY_ENV_KEYS = new Set([
|
|
2573
2470
|
"POSTHOG_HANDOFF_OUTPUT_PATH",
|
|
2574
2471
|
"POSTHOG_TASK_RUN_ID",
|
|
2472
|
+
"POSTHOG_WIZARD_RUN_ID",
|
|
2575
2473
|
"POSTHOG_TASK_ID"
|
|
2576
2474
|
]);
|
|
2577
2475
|
/**
|
|
@@ -2657,7 +2555,7 @@ function sanitizeAgentSubprocessEnv(env = process.env) {
|
|
|
2657
2555
|
return sanitized;
|
|
2658
2556
|
}
|
|
2659
2557
|
//#endregion
|
|
2660
|
-
//#region src/
|
|
2558
|
+
//#region src/shared/claude-settings.ts
|
|
2661
2559
|
/**
|
|
2662
2560
|
* Claude Code settings handling: conflict detection, backup/restore, and
|
|
2663
2561
|
* orphan recovery.
|
|
@@ -2888,7 +2786,7 @@ function recoverOrphanedSettingsBackups(workingDirectory) {
|
|
|
2888
2786
|
}
|
|
2889
2787
|
}
|
|
2890
2788
|
//#endregion
|
|
2891
|
-
//#region src/
|
|
2789
|
+
//#region src/agent/stored-login.ts
|
|
2892
2790
|
/**
|
|
2893
2791
|
* Detect a pre-existing Claude Code login on the machine.
|
|
2894
2792
|
*
|
|
@@ -2968,7 +2866,7 @@ function detectStoredClaudeLogin(homeDir = os.homedir(), platform = process.plat
|
|
|
2968
2866
|
};
|
|
2969
2867
|
}
|
|
2970
2868
|
//#endregion
|
|
2971
|
-
//#region src/
|
|
2869
|
+
//#region src/agent/agent-interface.ts
|
|
2972
2870
|
/**
|
|
2973
2871
|
* Shared agent interface for PostHog wizards
|
|
2974
2872
|
* Uses Claude Agent SDK directly with PostHog LLM gateway
|
|
@@ -3017,37 +2915,23 @@ function buildAuthErrorContext(workingDirectory, gatewayUrl, homeDir = os.homedi
|
|
|
3017
2915
|
};
|
|
3018
2916
|
}
|
|
3019
2917
|
/**
|
|
3020
|
-
* Create a stop hook callback that
|
|
3021
|
-
* then collects a remark, then allows stop.
|
|
2918
|
+
* Create a stop hook callback that collects a remark, then allows stop.
|
|
3022
2919
|
*
|
|
3023
|
-
*
|
|
3024
|
-
* Phase 1 —
|
|
3025
|
-
* Phase 2 —
|
|
3026
|
-
* 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 {}
|
|
3027
2923
|
*/
|
|
3028
|
-
function createStopHook(
|
|
3029
|
-
let featureIndex = 0;
|
|
2924
|
+
function createStopHook(signals, requestRemark = true) {
|
|
3030
2925
|
let remarkRequested = false;
|
|
3031
2926
|
return (input) => {
|
|
3032
2927
|
logToFile("Stop hook triggered", {
|
|
3033
2928
|
stop_hook_active: input.stop_hook_active,
|
|
3034
|
-
|
|
3035
|
-
remarkRequested,
|
|
3036
|
-
queueLength: featureQueue.length
|
|
2929
|
+
remarkRequested
|
|
3037
2930
|
});
|
|
3038
2931
|
if (signals?.hasApiError()) {
|
|
3039
2932
|
logToFile("Stop hook: API error detected, allowing immediate stop");
|
|
3040
2933
|
return {};
|
|
3041
2934
|
}
|
|
3042
|
-
if (featureIndex < featureQueue.length) {
|
|
3043
|
-
const feature = featureQueue[featureIndex++];
|
|
3044
|
-
const prompt = ADDITIONAL_FEATURE_PROMPTS[feature];
|
|
3045
|
-
logToFile(`Stop hook: injecting feature prompt for ${feature}`);
|
|
3046
|
-
return {
|
|
3047
|
-
decision: "block",
|
|
3048
|
-
reason: prompt
|
|
3049
|
-
};
|
|
3050
|
-
}
|
|
3051
2935
|
if (requestRemark && !remarkRequested) {
|
|
3052
2936
|
remarkRequested = true;
|
|
3053
2937
|
logToFile("Stop hook: requesting reflection");
|
|
@@ -3060,6 +2944,7 @@ function createStopHook(featureQueue, signals, requestRemark = true) {
|
|
|
3060
2944
|
return {};
|
|
3061
2945
|
};
|
|
3062
2946
|
}
|
|
2947
|
+
const NO_PROGRESS = () => void 0;
|
|
3063
2948
|
/**
|
|
3064
2949
|
* Global identifiers attached to every LLM gateway trace for a run. They ride on
|
|
3065
2950
|
* each `$ai_generation` the gateway emits (in the `X-PostHog-Properties` blob
|
|
@@ -3187,9 +3072,10 @@ async function initializeAgent(config, options) {
|
|
|
3187
3072
|
initLogFile();
|
|
3188
3073
|
logToFile("Agent initialization starting");
|
|
3189
3074
|
logToFile("Install directory:", options.installDir);
|
|
3075
|
+
const emit = config.emit ?? NO_PROGRESS;
|
|
3190
3076
|
try {
|
|
3191
3077
|
process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "true";
|
|
3192
|
-
const currentGatewayAuth = () => gatewayAuth(config.host, config.posthogApiKey, config.programId);
|
|
3078
|
+
const currentGatewayAuth = async () => gatewayAuth(config.host, await config.currentPosthogApiKey?.() ?? config.posthogApiKey, config.programId);
|
|
3193
3079
|
const auth = await currentGatewayAuth();
|
|
3194
3080
|
const gatewayUrl = auth.gatewayUrl;
|
|
3195
3081
|
process.env.ANTHROPIC_BASE_URL = gatewayUrl;
|
|
@@ -3243,7 +3129,8 @@ async function initializeAgent(config, options) {
|
|
|
3243
3129
|
askBridge: config.askBridge,
|
|
3244
3130
|
askMaxQuestions: config.askMaxQuestions,
|
|
3245
3131
|
orchestrator: config.orchestrator,
|
|
3246
|
-
triageProvider
|
|
3132
|
+
triageProvider,
|
|
3133
|
+
emit: config.emit
|
|
3247
3134
|
});
|
|
3248
3135
|
const model = config.modelOverride ?? "claude-sonnet-5";
|
|
3249
3136
|
const agentRunConfig = {
|
|
@@ -3251,6 +3138,7 @@ async function initializeAgent(config, options) {
|
|
|
3251
3138
|
mcpServers,
|
|
3252
3139
|
model,
|
|
3253
3140
|
posthogApiKey: config.posthogApiKey,
|
|
3141
|
+
currentPosthogApiKey: config.currentPosthogApiKey,
|
|
3254
3142
|
wizardFlags: config.wizardFlags,
|
|
3255
3143
|
wizardMetadata: config.wizardMetadata,
|
|
3256
3144
|
allowedTools: config.allowedTools,
|
|
@@ -3262,7 +3150,8 @@ async function initializeAgent(config, options) {
|
|
|
3262
3150
|
gatewayAuth: auth,
|
|
3263
3151
|
refreshGatewayAuth: currentGatewayAuth,
|
|
3264
3152
|
program: config.integrationLabel,
|
|
3265
|
-
sequence: config.orchestrator ? "orchestrator" : "linear"
|
|
3153
|
+
sequence: config.orchestrator ? "orchestrator" : "linear",
|
|
3154
|
+
emit
|
|
3266
3155
|
};
|
|
3267
3156
|
logToFile("Agent config:", {
|
|
3268
3157
|
workingDirectory: agentRunConfig.workingDirectory,
|
|
@@ -3279,7 +3168,11 @@ async function initializeAgent(config, options) {
|
|
|
3279
3168
|
prewarmYaraScanner();
|
|
3280
3169
|
return agentRunConfig;
|
|
3281
3170
|
} catch (error) {
|
|
3282
|
-
|
|
3171
|
+
emit({
|
|
3172
|
+
kind: "log",
|
|
3173
|
+
level: "error",
|
|
3174
|
+
message: `Failed to initialize agent: ${error.message}`
|
|
3175
|
+
});
|
|
3283
3176
|
logToFile("Agent initialization error:", error);
|
|
3284
3177
|
debug("Agent initialization error:", error);
|
|
3285
3178
|
throw error;
|
|
@@ -3291,7 +3184,34 @@ async function initializeAgent(config, options) {
|
|
|
3291
3184
|
*
|
|
3292
3185
|
* @returns An object containing any error detected in the agent's output
|
|
3293
3186
|
*/
|
|
3187
|
+
function sdkErrorStatus(value) {
|
|
3188
|
+
if (typeof value === "number" && value >= 400 && value < 600) return value;
|
|
3189
|
+
if (typeof value === "string") {
|
|
3190
|
+
const match = value.match(/(?:^|\b)(4\d\d|5\d\d)(?:\b|$)/);
|
|
3191
|
+
return match ? Number(match[1]) : void 0;
|
|
3192
|
+
}
|
|
3193
|
+
if (value && typeof value === "object") {
|
|
3194
|
+
const record = value;
|
|
3195
|
+
return sdkErrorStatus(record.status) ?? sdkErrorStatus(record.statusCode) ?? sdkErrorStatus(record.code) ?? sdkErrorStatus(record.error);
|
|
3196
|
+
}
|
|
3197
|
+
}
|
|
3198
|
+
function sdkResultFailure(message) {
|
|
3199
|
+
if (message.subtype === "success" && message.is_error !== true) return void 0;
|
|
3200
|
+
const errors = Array.isArray(message.errors) ? message.errors : [];
|
|
3201
|
+
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"));
|
|
3202
|
+
return {
|
|
3203
|
+
kind: "failure",
|
|
3204
|
+
classification: (sdkErrorStatus(message.api_error_status) ?? sdkErrorStatus(message.status) ?? errors.map(sdkErrorStatus).find((code) => code !== void 0) ?? sdkErrorStatus(message.result)) === 429 ? "WIZARD_RATE_LIMIT" : "WIZARD_API_ERROR",
|
|
3205
|
+
message: detail
|
|
3206
|
+
};
|
|
3207
|
+
}
|
|
3294
3208
|
async function runAgent(agentConfig, prompt, options, spinner, config, middleware) {
|
|
3209
|
+
if (agentConfig.signal?.aborted) return {
|
|
3210
|
+
kind: "abort",
|
|
3211
|
+
classification: "WIZARD_ABORT",
|
|
3212
|
+
message: "Agent run cancelled"
|
|
3213
|
+
};
|
|
3214
|
+
const emit = agentConfig.emit ?? NO_PROGRESS;
|
|
3295
3215
|
const { spinnerMessage = "Customizing your PostHog setup...", successMessage = "PostHog integration complete", errorMessage = "Integration failed", abortCases = [], emitStepEvents = false, resolveStepKey } = config ?? {};
|
|
3296
3216
|
logToFile("Starting agent run");
|
|
3297
3217
|
const { query } = await getSDKModule();
|
|
@@ -3305,6 +3225,8 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3305
3225
|
let receivedSuccessResult = false;
|
|
3306
3226
|
let loggedInitialContext = false;
|
|
3307
3227
|
let lastResultMessage = null;
|
|
3228
|
+
let terminalFailure;
|
|
3229
|
+
let assistantErrorStatus;
|
|
3308
3230
|
const tasks = /* @__PURE__ */ new Map();
|
|
3309
3231
|
let signalDone = () => void 0;
|
|
3310
3232
|
const createPromptStream = (text) => {
|
|
@@ -3349,22 +3271,40 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3349
3271
|
...config?.analyticsProperties
|
|
3350
3272
|
});
|
|
3351
3273
|
const totalCostUsd = Number(lastResultMessage?.total_cost_usd ?? 0);
|
|
3352
|
-
if (totalCostUsd > 0)
|
|
3274
|
+
if (totalCostUsd > 0) emit({
|
|
3275
|
+
kind: "finalCost",
|
|
3276
|
+
usd: totalCostUsd
|
|
3277
|
+
});
|
|
3353
3278
|
try {
|
|
3354
3279
|
middleware?.finalize(lastResultMessage, durationMs);
|
|
3355
3280
|
} catch (e) {
|
|
3356
3281
|
logToFile(`${AgentSignals.BENCHMARK} Middleware finalize error:`, e);
|
|
3357
3282
|
}
|
|
3358
3283
|
spinner.stop(successMessage);
|
|
3359
|
-
return {};
|
|
3284
|
+
return { kind: "success" };
|
|
3360
3285
|
};
|
|
3361
3286
|
let abortController = new AbortController();
|
|
3287
|
+
const onExternalAbort = () => {
|
|
3288
|
+
abortController.abort();
|
|
3289
|
+
signalDone();
|
|
3290
|
+
};
|
|
3291
|
+
let timedOut = false;
|
|
3362
3292
|
let abortReason = null;
|
|
3363
3293
|
let yaraViolationReason = null;
|
|
3364
3294
|
let sessionId;
|
|
3365
3295
|
let reminted = false;
|
|
3366
3296
|
let remintRequested = false;
|
|
3297
|
+
let authFailure;
|
|
3367
3298
|
const agentConfigDir = createIsolatedAgentConfigDir();
|
|
3299
|
+
agentConfig.signal?.addEventListener("abort", onExternalAbort, { once: true });
|
|
3300
|
+
if (agentConfig.signal?.aborted) onExternalAbort();
|
|
3301
|
+
const timeoutMs = config?.timeoutMs;
|
|
3302
|
+
const timeoutId = timeoutMs ? setTimeout(() => {
|
|
3303
|
+
if (receivedSuccessResult) return;
|
|
3304
|
+
timedOut = true;
|
|
3305
|
+
signalDone();
|
|
3306
|
+
abortController.abort();
|
|
3307
|
+
}, timeoutMs) : void 0;
|
|
3368
3308
|
try {
|
|
3369
3309
|
const disallow = new Set(agentConfig.disallowedTools ?? []);
|
|
3370
3310
|
const allowedTools = [...BASE_ALLOWED_TOOLS, ...agentConfig.allowedTools ?? []].filter((t) => !disallow.has(t));
|
|
@@ -3448,7 +3388,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3448
3388
|
CLAUDE_CODE_OAUTH_TOKEN: agentConfig.gatewayAuth.token,
|
|
3449
3389
|
CLAUDE_CONFIG_DIR: agentConfigDir,
|
|
3450
3390
|
CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "true",
|
|
3451
|
-
POSTHOG_MCP_TOKEN: agentConfig.posthogApiKey,
|
|
3391
|
+
POSTHOG_MCP_TOKEN: await agentConfig.currentPosthogApiKey?.() ?? agentConfig.posthogApiKey,
|
|
3452
3392
|
MCP_CONNECTION_NONBLOCKING: "0",
|
|
3453
3393
|
ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}, agentConfig.gatewayAuth.teamId)
|
|
3454
3394
|
},
|
|
@@ -3485,7 +3425,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3485
3425
|
PreToolUse: warlockDisabled ? [] : createPreToolUseYaraHooks(triageProvider, onYaraTerminate),
|
|
3486
3426
|
PostToolUse: warlockDisabled ? [] : createPostToolUseYaraHooks(triageProvider, onYaraTerminate),
|
|
3487
3427
|
Stop: [{
|
|
3488
|
-
hooks: [createStopHook(
|
|
3428
|
+
hooks: [createStopHook(signals, config?.requestRemark ?? true)],
|
|
3489
3429
|
timeout: 30
|
|
3490
3430
|
}]
|
|
3491
3431
|
}
|
|
@@ -3512,7 +3452,8 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3512
3452
|
loggedInitialContext = true;
|
|
3513
3453
|
}
|
|
3514
3454
|
agentConfig.capture?.captureFromAnthropicSDKMessage(message);
|
|
3515
|
-
handleSDKMessage(message, options, spinner, signals, receivedSuccessResult, tasks, agentConfig.suppressTaskRender ?? false, emitStepEvents, resolveStepKey);
|
|
3455
|
+
handleSDKMessage(message, options, spinner, signals, emit, receivedSuccessResult, tasks, agentConfig.suppressTaskRender ?? false, emitStepEvents, resolveStepKey);
|
|
3456
|
+
if (message.type === "assistant") assistantErrorStatus = sdkErrorStatus(message.error) ?? assistantErrorStatus;
|
|
3516
3457
|
if (abortCases.length > 0 && !abortReason && message.type === "assistant") {
|
|
3517
3458
|
const content = message.message?.content;
|
|
3518
3459
|
if (Array.isArray(content)) {
|
|
@@ -3528,9 +3469,9 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3528
3469
|
}
|
|
3529
3470
|
}
|
|
3530
3471
|
}
|
|
3531
|
-
if (message.type === "assistant" &&
|
|
3472
|
+
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)) {
|
|
3532
3473
|
signalDone();
|
|
3533
|
-
if (agentConfig.refreshGatewayAuth && !reminted && isPastRefresh(agentConfig.gatewayAuth)) {
|
|
3474
|
+
if (agentConfig.refreshGatewayAuth && !reminted && isPastRefresh(agentConfig.gatewayAuth) && !agentConfig.signal?.aborted) {
|
|
3534
3475
|
logToFile("Agent error: 401 on an aged gateway bearer; re-minting");
|
|
3535
3476
|
remintRequested = true;
|
|
3536
3477
|
abortController.abort();
|
|
@@ -3551,27 +3492,33 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3551
3492
|
...authError,
|
|
3552
3493
|
sessionExpired
|
|
3553
3494
|
});
|
|
3554
|
-
|
|
3555
|
-
hasSettingsConflict: authError.hasSettingsConflict,
|
|
3556
|
-
conflicts: authError.conflicts,
|
|
3557
|
-
usingManagedLogin: authError.usingManagedLogin,
|
|
3558
|
-
credentialPlaces: authError.credentialPlaces,
|
|
3559
|
-
sessionExpired,
|
|
3560
|
-
logFilePath: getLogFilePath()
|
|
3561
|
-
});
|
|
3562
|
-
await wizardAbort({
|
|
3495
|
+
authFailure = {
|
|
3563
3496
|
code: authCode,
|
|
3564
3497
|
message: "Authentication failed (401)",
|
|
3565
|
-
|
|
3498
|
+
authErrorDetail: {
|
|
3499
|
+
hasSettingsConflict: authError.hasSettingsConflict,
|
|
3500
|
+
conflicts: authError.conflicts,
|
|
3501
|
+
usingManagedLogin: authError.usingManagedLogin,
|
|
3502
|
+
credentialPlaces: authError.credentialPlaces,
|
|
3503
|
+
sessionExpired,
|
|
3504
|
+
logFilePath: getLogFilePath()
|
|
3505
|
+
},
|
|
3506
|
+
detail: {
|
|
3566
3507
|
hasSettingsConflict: authError.hasSettingsConflict,
|
|
3567
3508
|
conflictSources: authError.conflictSources,
|
|
3568
3509
|
conflictKeys: authError.conflictKeys,
|
|
3510
|
+
conflicts: authError.conflicts,
|
|
3511
|
+
credentialPlaces: authError.credentialPlaces,
|
|
3512
|
+
sessionExpired,
|
|
3513
|
+
logFilePath: getLogFilePath(),
|
|
3569
3514
|
gatewayUrl: authError.gatewayUrl,
|
|
3570
3515
|
region: authError.region,
|
|
3571
3516
|
usingManagedLogin: authError.usingManagedLogin,
|
|
3572
3517
|
apiKeySource: authError.apiKeySource
|
|
3573
|
-
}
|
|
3574
|
-
}
|
|
3518
|
+
}
|
|
3519
|
+
};
|
|
3520
|
+
abortController.abort();
|
|
3521
|
+
break;
|
|
3575
3522
|
}
|
|
3576
3523
|
try {
|
|
3577
3524
|
middleware?.onMessage(message);
|
|
@@ -3582,59 +3529,112 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3582
3529
|
if (message.subtype === "success" && !message.is_error) {
|
|
3583
3530
|
receivedSuccessResult = true;
|
|
3584
3531
|
lastResultMessage = message;
|
|
3532
|
+
} else if (!receivedSuccessResult) {
|
|
3533
|
+
terminalFailure = sdkResultFailure(message);
|
|
3534
|
+
if (terminalFailure && assistantErrorStatus === 429) terminalFailure = {
|
|
3535
|
+
...terminalFailure,
|
|
3536
|
+
classification: "WIZARD_RATE_LIMIT"
|
|
3537
|
+
};
|
|
3585
3538
|
}
|
|
3586
3539
|
signalDone();
|
|
3587
3540
|
}
|
|
3588
3541
|
}
|
|
3589
3542
|
} catch (error) {
|
|
3590
3543
|
if (remintRequested) return "remint";
|
|
3544
|
+
if (authFailure) return "done";
|
|
3591
3545
|
throw error;
|
|
3592
3546
|
}
|
|
3593
3547
|
return remintRequested ? "remint" : "done";
|
|
3594
3548
|
};
|
|
3595
3549
|
const refreshGatewayAuth = agentConfig.refreshGatewayAuth;
|
|
3596
|
-
if (await runQuery() === "remint" && refreshGatewayAuth) {
|
|
3550
|
+
if (await runQuery() === "remint" && refreshGatewayAuth && !agentConfig.signal?.aborted) {
|
|
3597
3551
|
reminted = true;
|
|
3598
3552
|
remintRequested = false;
|
|
3599
3553
|
abortController = new AbortController();
|
|
3554
|
+
if (agentConfig.signal?.aborted) abortController.abort();
|
|
3600
3555
|
signals.forgetApiErrors();
|
|
3601
3556
|
spinner.message("Renewing the gateway token...");
|
|
3602
3557
|
const stale = agentConfig.gatewayAuth;
|
|
3603
3558
|
agentConfig.gatewayAuth = await refreshGatewayAuth();
|
|
3559
|
+
if (agentConfig.signal?.aborted) return {
|
|
3560
|
+
kind: "abort",
|
|
3561
|
+
classification: "WIZARD_ABORT",
|
|
3562
|
+
message: "Agent run cancelled"
|
|
3563
|
+
};
|
|
3604
3564
|
logToFile(`Gateway token renewed after a 401 (${Math.round((Date.now() - stale.refreshAtMs) / 1e3)}s past refresh); resuming session ${sessionId ?? "(none: fresh session)"}`);
|
|
3605
3565
|
analytics.wizardCapture("gateway token reminted", { resumed: sessionId !== void 0 });
|
|
3606
3566
|
spinner.message(spinnerMessage);
|
|
3607
3567
|
await runQuery(sessionId);
|
|
3608
3568
|
}
|
|
3569
|
+
if (authFailure) return {
|
|
3570
|
+
kind: "decided_failure",
|
|
3571
|
+
failure: authFailure
|
|
3572
|
+
};
|
|
3573
|
+
if (agentConfig.signal?.aborted) return {
|
|
3574
|
+
kind: "abort",
|
|
3575
|
+
classification: "WIZARD_ABORT",
|
|
3576
|
+
message: "Agent run cancelled"
|
|
3577
|
+
};
|
|
3609
3578
|
if (yaraViolationReason) {
|
|
3610
3579
|
logToFile("Agent error: YARA_VIOLATION");
|
|
3611
3580
|
spinner.stop("Security check stopped the setup");
|
|
3612
|
-
return {
|
|
3581
|
+
return {
|
|
3582
|
+
kind: "failure",
|
|
3583
|
+
classification: "WIZARD_YARA_VIOLATION"
|
|
3584
|
+
};
|
|
3613
3585
|
}
|
|
3614
3586
|
if (abortReason) {
|
|
3615
3587
|
spinner.stop("Wizard aborted");
|
|
3616
3588
|
return {
|
|
3617
|
-
|
|
3589
|
+
kind: "abort",
|
|
3590
|
+
classification: "WIZARD_ABORT",
|
|
3618
3591
|
message: abortReason
|
|
3619
3592
|
};
|
|
3620
3593
|
}
|
|
3594
|
+
if (agentConfig.signal?.aborted) {
|
|
3595
|
+
spinner.stop("Wizard aborted");
|
|
3596
|
+
return {
|
|
3597
|
+
kind: "abort",
|
|
3598
|
+
classification: "WIZARD_ABORT",
|
|
3599
|
+
message: "Agent run cancelled"
|
|
3600
|
+
};
|
|
3601
|
+
}
|
|
3602
|
+
if (timedOut) {
|
|
3603
|
+
spinner.stop("Agent run timed out");
|
|
3604
|
+
return {
|
|
3605
|
+
kind: "failure",
|
|
3606
|
+
classification: "WIZARD_AGENTIC_DETECTION_TIMEOUT",
|
|
3607
|
+
message: `Agent run timed out after ${timeoutMs / 1e3}s`
|
|
3608
|
+
};
|
|
3609
|
+
}
|
|
3621
3610
|
if (signals.has("MCP_MISSING")) {
|
|
3622
3611
|
logToFile("Agent error: MCP_MISSING");
|
|
3623
3612
|
spinner.stop("Agent could not access PostHog MCP");
|
|
3624
|
-
return {
|
|
3613
|
+
return {
|
|
3614
|
+
kind: "failure",
|
|
3615
|
+
classification: "WIZARD_MCP_MISSING"
|
|
3616
|
+
};
|
|
3625
3617
|
}
|
|
3626
3618
|
if (signals.has("RESOURCE_MISSING")) {
|
|
3627
3619
|
logToFile("Agent error: RESOURCE_MISSING");
|
|
3628
3620
|
spinner.stop("Agent could not access setup resource");
|
|
3629
|
-
return {
|
|
3621
|
+
return {
|
|
3622
|
+
kind: "failure",
|
|
3623
|
+
classification: "WIZARD_RESOURCE_MISSING"
|
|
3624
|
+
};
|
|
3630
3625
|
}
|
|
3631
3626
|
if (receivedSuccessResult) return completeWithSuccess();
|
|
3627
|
+
if (terminalFailure) {
|
|
3628
|
+
spinner.stop(errorMessage);
|
|
3629
|
+
return terminalFailure;
|
|
3630
|
+
}
|
|
3632
3631
|
const apiErrorMessage = signals.apiErrorMessage() ?? "Unknown API error";
|
|
3633
3632
|
if (signals.hasApiErrorStatus(429)) {
|
|
3634
3633
|
logToFile("Agent error: RATE_LIMIT");
|
|
3635
3634
|
spinner.stop("Rate limit exceeded");
|
|
3636
3635
|
return {
|
|
3637
|
-
|
|
3636
|
+
kind: "failure",
|
|
3637
|
+
classification: "WIZARD_RATE_LIMIT",
|
|
3638
3638
|
message: apiErrorMessage
|
|
3639
3639
|
};
|
|
3640
3640
|
}
|
|
@@ -3642,57 +3642,95 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3642
3642
|
logToFile("Agent error: API_ERROR");
|
|
3643
3643
|
spinner.stop("API error occurred");
|
|
3644
3644
|
return {
|
|
3645
|
-
|
|
3645
|
+
kind: "failure",
|
|
3646
|
+
classification: "WIZARD_API_ERROR",
|
|
3646
3647
|
message: apiErrorMessage
|
|
3647
3648
|
};
|
|
3648
3649
|
}
|
|
3649
|
-
|
|
3650
|
+
spinner.stop(errorMessage);
|
|
3651
|
+
return {
|
|
3652
|
+
kind: "failure",
|
|
3653
|
+
classification: "WIZARD_API_ERROR",
|
|
3654
|
+
message: "SDK stream ended without a success result"
|
|
3655
|
+
};
|
|
3650
3656
|
} catch (error) {
|
|
3651
3657
|
signalDone();
|
|
3652
3658
|
if (yaraViolationReason) {
|
|
3653
3659
|
logToFile("Agent error: YARA_VIOLATION");
|
|
3654
3660
|
spinner.stop("Security check stopped the setup");
|
|
3655
|
-
return {
|
|
3661
|
+
return {
|
|
3662
|
+
kind: "failure",
|
|
3663
|
+
classification: "WIZARD_YARA_VIOLATION"
|
|
3664
|
+
};
|
|
3656
3665
|
}
|
|
3657
3666
|
if (abortReason) {
|
|
3658
3667
|
spinner.stop("Wizard aborted");
|
|
3659
3668
|
return {
|
|
3660
|
-
|
|
3669
|
+
kind: "abort",
|
|
3670
|
+
classification: "WIZARD_ABORT",
|
|
3661
3671
|
message: abortReason
|
|
3662
3672
|
};
|
|
3663
3673
|
}
|
|
3674
|
+
if (agentConfig.signal?.aborted) {
|
|
3675
|
+
spinner.stop("Wizard aborted");
|
|
3676
|
+
return {
|
|
3677
|
+
kind: "abort",
|
|
3678
|
+
classification: "WIZARD_ABORT",
|
|
3679
|
+
message: "Agent run cancelled"
|
|
3680
|
+
};
|
|
3681
|
+
}
|
|
3664
3682
|
if (receivedSuccessResult) return completeWithSuccess(error);
|
|
3683
|
+
if (timedOut) {
|
|
3684
|
+
spinner.stop("Agent run timed out");
|
|
3685
|
+
return {
|
|
3686
|
+
kind: "failure",
|
|
3687
|
+
classification: "WIZARD_AGENTIC_DETECTION_TIMEOUT",
|
|
3688
|
+
message: `Agent run timed out after ${timeoutMs / 1e3}s`
|
|
3689
|
+
};
|
|
3690
|
+
}
|
|
3665
3691
|
const apiErrorMessage = signals.apiErrorMessage() ?? "Unknown API error";
|
|
3666
3692
|
if (signals.hasApiErrorStatus(429)) {
|
|
3667
3693
|
logToFile("Agent error (caught): RATE_LIMIT");
|
|
3668
3694
|
spinner.stop("Rate limit exceeded");
|
|
3669
3695
|
return {
|
|
3670
|
-
|
|
3671
|
-
|
|
3696
|
+
kind: "failure",
|
|
3697
|
+
classification: "WIZARD_RATE_LIMIT",
|
|
3698
|
+
message: apiErrorMessage,
|
|
3699
|
+
error: error instanceof Error ? error : void 0
|
|
3672
3700
|
};
|
|
3673
3701
|
}
|
|
3674
3702
|
if (signals.hasApiError()) {
|
|
3675
3703
|
logToFile("Agent error (caught): API_ERROR");
|
|
3676
3704
|
spinner.stop("API error occurred");
|
|
3677
3705
|
return {
|
|
3678
|
-
|
|
3679
|
-
|
|
3706
|
+
kind: "failure",
|
|
3707
|
+
classification: "WIZARD_API_ERROR",
|
|
3708
|
+
message: apiErrorMessage,
|
|
3709
|
+
error: error instanceof Error ? error : void 0
|
|
3680
3710
|
};
|
|
3681
3711
|
}
|
|
3682
3712
|
spinner.stop(errorMessage);
|
|
3683
|
-
|
|
3713
|
+
emit({
|
|
3714
|
+
kind: "log",
|
|
3715
|
+
level: "error",
|
|
3716
|
+
message: `Error: ${error.message}`
|
|
3717
|
+
});
|
|
3684
3718
|
logToFile("Agent run failed:", error);
|
|
3685
3719
|
debug("Full error:", error);
|
|
3686
3720
|
throw error;
|
|
3687
3721
|
} finally {
|
|
3688
|
-
|
|
3722
|
+
agentConfig.signal?.removeEventListener("abort", onExternalAbort);
|
|
3723
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
3724
|
+
if (!receivedSuccessResult && !authFailure) {
|
|
3689
3725
|
const durationMs = Date.now() - startTime;
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3726
|
+
try {
|
|
3727
|
+
analytics.wizardCapture("agent aborted", {
|
|
3728
|
+
duration_ms: durationMs,
|
|
3729
|
+
duration_seconds: Math.round(durationMs / 1e3),
|
|
3730
|
+
model: agentConfig.model,
|
|
3731
|
+
...config?.analyticsProperties
|
|
3732
|
+
});
|
|
3733
|
+
} catch {}
|
|
3696
3734
|
}
|
|
3697
3735
|
}
|
|
3698
3736
|
}
|
|
@@ -3737,10 +3775,18 @@ const BASE_ALLOWED_TOOLS = [
|
|
|
3737
3775
|
"ListMcpResourcesTool",
|
|
3738
3776
|
...Object.values(WIZARD_TOOL_NAMES)
|
|
3739
3777
|
];
|
|
3778
|
+
const taskSources = /* @__PURE__ */ new WeakMap();
|
|
3740
3779
|
function handleTaskCreate(block, store) {
|
|
3741
3780
|
const input = block.input;
|
|
3742
3781
|
if (!input?.subject) return;
|
|
3782
|
+
let source = taskSources.get(store.tasks);
|
|
3783
|
+
if (!source) {
|
|
3784
|
+
source = randomUUID();
|
|
3785
|
+
taskSources.set(store.tasks, source);
|
|
3786
|
+
}
|
|
3743
3787
|
store.tasks.set(block.id, {
|
|
3788
|
+
id: randomUUID(),
|
|
3789
|
+
source,
|
|
3744
3790
|
content: input.subject,
|
|
3745
3791
|
status: "pending",
|
|
3746
3792
|
activeForm: input.activeForm
|
|
@@ -3766,6 +3812,8 @@ function handleTaskUpdate(block, store) {
|
|
|
3766
3812
|
});
|
|
3767
3813
|
}
|
|
3768
3814
|
store.tasks.set(input.taskId, {
|
|
3815
|
+
id: existing.id,
|
|
3816
|
+
source: existing.source,
|
|
3769
3817
|
content: input.subject ?? existing.content,
|
|
3770
3818
|
status: input.status ?? existing.status,
|
|
3771
3819
|
activeForm: input.activeForm ?? existing.activeForm
|
|
@@ -3875,7 +3923,7 @@ function reportMcpSetup(message) {
|
|
|
3875
3923
|
mcp_servers: servers.map((s) => `${s.name}:${s.status}`).join(",")
|
|
3876
3924
|
});
|
|
3877
3925
|
}
|
|
3878
|
-
function handleSDKMessage(message, options, spinner, signals, receivedSuccessResult = false, tasks, suppressTaskRender = false, emitStepEvents = false, resolveStepKey) {
|
|
3926
|
+
function handleSDKMessage(message, options, spinner, signals, emit, receivedSuccessResult = false, tasks, suppressTaskRender = false, emitStepEvents = false, resolveStepKey) {
|
|
3879
3927
|
const STATUS_RANK = {
|
|
3880
3928
|
completed: 0,
|
|
3881
3929
|
in_progress: 1
|
|
@@ -3883,15 +3931,20 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3883
3931
|
const rank = (status) => STATUS_RANK[status] ?? 2;
|
|
3884
3932
|
const syncTasks = () => {
|
|
3885
3933
|
if (!tasks || suppressTaskRender) return;
|
|
3886
|
-
|
|
3887
|
-
|
|
3934
|
+
emit({
|
|
3935
|
+
kind: "tasks",
|
|
3936
|
+
tasks: Array.from(tasks.values()).sort((a, b) => rank(a.status) - rank(b.status)).map((t) => ({ ...t }))
|
|
3937
|
+
});
|
|
3888
3938
|
};
|
|
3889
3939
|
logToFile(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
|
|
3890
3940
|
if (options.debug) debug(`SDK Message type: ${message.type}`);
|
|
3891
3941
|
switch (message.type) {
|
|
3892
3942
|
case "assistant": {
|
|
3893
3943
|
const tokenUsageDelta = extractTokenUsageDelta(message);
|
|
3894
|
-
if (tokenUsageDelta)
|
|
3944
|
+
if (tokenUsageDelta) emit({
|
|
3945
|
+
kind: "usage",
|
|
3946
|
+
delta: tokenUsageDelta
|
|
3947
|
+
});
|
|
3895
3948
|
const content = message.message?.content;
|
|
3896
3949
|
if (Array.isArray(content)) for (const block of content) {
|
|
3897
3950
|
if (block.type === "text" && typeof block.text === "string") {
|
|
@@ -3900,15 +3953,26 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3900
3953
|
const statusMatch = block.text.match(statusRegex);
|
|
3901
3954
|
if (statusMatch) {
|
|
3902
3955
|
const statusText = statusMatch[1].trim();
|
|
3903
|
-
|
|
3956
|
+
emit({
|
|
3957
|
+
kind: "status",
|
|
3958
|
+
message: statusText
|
|
3959
|
+
});
|
|
3904
3960
|
spinner.message(statusText);
|
|
3905
3961
|
}
|
|
3906
3962
|
const dashboardRegex = new RegExp(`${AgentSignals.DASHBOARD_URL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*(\\S+)`, "m");
|
|
3907
3963
|
const dashboardMatch = block.text.match(dashboardRegex);
|
|
3908
|
-
if (dashboardMatch)
|
|
3964
|
+
if (dashboardMatch) emit({
|
|
3965
|
+
kind: "url",
|
|
3966
|
+
which: "dashboard",
|
|
3967
|
+
url: dashboardMatch[1].trim()
|
|
3968
|
+
});
|
|
3909
3969
|
const notebookRegex = new RegExp(`${AgentSignals.NOTEBOOK_URL.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*(\\S+)`, "m");
|
|
3910
3970
|
const notebookMatch = block.text.match(notebookRegex);
|
|
3911
|
-
if (notebookMatch)
|
|
3971
|
+
if (notebookMatch) emit({
|
|
3972
|
+
kind: "url",
|
|
3973
|
+
which: "notebook",
|
|
3974
|
+
url: notebookMatch[1].trim()
|
|
3975
|
+
});
|
|
3912
3976
|
}
|
|
3913
3977
|
if (block.type === "tool_use" && tasks && Object.values(TaskTool).includes(block.name)) dispatchTaskToolUse(block, {
|
|
3914
3978
|
tasks,
|
|
@@ -3918,7 +3982,10 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3918
3982
|
});
|
|
3919
3983
|
if (block.type === "tool_use") {
|
|
3920
3984
|
const stage = classifyToolToStage(block.name);
|
|
3921
|
-
if (stage)
|
|
3985
|
+
if (stage) emit({
|
|
3986
|
+
kind: "stage",
|
|
3987
|
+
stage
|
|
3988
|
+
});
|
|
3922
3989
|
}
|
|
3923
3990
|
}
|
|
3924
3991
|
break;
|
|
@@ -3942,7 +4009,11 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3942
4009
|
logToFile("Agent result with error:", message.result);
|
|
3943
4010
|
if (typeof message.result === "string") signals.push(message.result);
|
|
3944
4011
|
if (message.errors && !receivedSuccessResult) for (const err of message.errors) {
|
|
3945
|
-
|
|
4012
|
+
emit({
|
|
4013
|
+
kind: "log",
|
|
4014
|
+
level: "error",
|
|
4015
|
+
message: `Error: ${err}`
|
|
4016
|
+
});
|
|
3946
4017
|
logToFile("ERROR:", err);
|
|
3947
4018
|
}
|
|
3948
4019
|
} else if (message.subtype === "success") {
|
|
@@ -3951,7 +4022,11 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3951
4022
|
} else {
|
|
3952
4023
|
logToFile("Agent result with error:", message.result);
|
|
3953
4024
|
if (message.errors && !receivedSuccessResult) for (const err of message.errors) {
|
|
3954
|
-
|
|
4025
|
+
emit({
|
|
4026
|
+
kind: "log",
|
|
4027
|
+
level: "error",
|
|
4028
|
+
message: `Error: ${err}`
|
|
4029
|
+
});
|
|
3955
4030
|
logToFile("ERROR:", err);
|
|
3956
4031
|
}
|
|
3957
4032
|
}
|
|
@@ -3974,6 +4049,6 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
|
|
|
3974
4049
|
}
|
|
3975
4050
|
}
|
|
3976
4051
|
//#endregion
|
|
3977
|
-
export {
|
|
4052
|
+
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 };
|
|
3978
4053
|
|
|
3979
|
-
//# sourceMappingURL=agent-interface-
|
|
4054
|
+
//# sourceMappingURL=agent-interface-BAOIHuXS.js.map
|