@posthog/wizard 2.79.1 → 2.80.1
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 +187 -57
- package/dist/{PickerMenu-dG5DQCZA.js → PickerMenu-BGGeYqd-.js} +112 -12
- package/dist/PickerMenu-BGGeYqd-.js.map +1 -0
- package/dist/README.md +9 -6
- package/dist/{agent-interface-FkbaBJwz.js → agent-interface-CemBvTAA.js} +130 -324
- package/dist/agent-interface-CemBvTAA.js.map +1 -0
- package/dist/{agent-prompt-loader-D0weQ-7k.js → agent-prompt-loader-DPnj6SwU.js} +6 -5
- package/dist/agent-prompt-loader-DPnj6SwU.js.map +1 -0
- package/dist/analytics-B3ROGuIr.js +2 -0
- package/dist/analytics-D21z3E5l.js +732 -0
- package/dist/analytics-D21z3E5l.js.map +1 -0
- package/dist/{api-CrbCIQOz.js → api-DtGIqQ2U.js} +2 -3
- package/dist/api-DtGIqQ2U.js.map +1 -0
- package/dist/api-IhROOQNv.js +2 -0
- package/dist/api-key-login-OEntFvu5.js +2 -0
- package/dist/api-key-login-h3E2G3zu.js +55 -0
- package/dist/api-key-login-h3E2G3zu.js.map +1 -0
- package/dist/bin.js +2 -2
- package/dist/bin.js.map +1 -1
- package/dist/{bounded-fs-vAq-T-K7.js → bounded-fs-CAsuF6al.js} +3 -3
- package/dist/{bounded-fs-vAq-T-K7.js.map → bounded-fs-CAsuF6al.js.map} +1 -1
- package/dist/{ci-install-COcV8SY2.js → ci-install-CEYE02t-.js} +22 -26
- package/dist/ci-install-CEYE02t-.js.map +1 -0
- package/dist/console-log-O828zyiq.js +32 -0
- package/dist/console-log-O828zyiq.js.map +1 -0
- package/dist/{debug-kAHwWGg7.js → debug-BfQPD2Hg.js} +18 -52
- package/dist/debug-BfQPD2Hg.js.map +1 -0
- package/dist/{defaults-a9TelDhJ.js → defaults-DDVl3tKN.js} +2 -51
- package/dist/defaults-DDVl3tKN.js.map +1 -0
- package/dist/{emit-BSetXzDV.js → emit-RfAewcWv.js} +1 -1
- package/dist/{emit-BSetXzDV.js.map → emit-RfAewcWv.js.map} +1 -1
- package/dist/{errors-C2domSkK.js → errors-CHrJzAZb.js} +4 -4
- package/dist/{errors-C2domSkK.js.map → errors-CHrJzAZb.js.map} +1 -1
- package/dist/family-picker-BKs-tTyu.js +46 -0
- package/dist/family-picker-BKs-tTyu.js.map +1 -0
- package/dist/{gateway-C9-GlLO9.js → gateway-D3gIlR6b.js} +122 -11
- package/dist/gateway-D3gIlR6b.js.map +1 -0
- package/dist/headless-BJjhP0SI.js +10 -0
- package/dist/headless-BJjhP0SI.js.map +1 -0
- package/dist/headless-DIX68UUA.js +3 -0
- package/dist/host-resolution-D8GhEVoX.js +114 -0
- package/dist/host-resolution-D8GhEVoX.js.map +1 -0
- package/dist/install-Bw8tvDvS.js +2 -0
- package/dist/{add-mcp-server-to-clients-DIaTRWMY.js → install-paPCzPHI.js} +34 -100
- package/dist/install-paPCzPHI.js.map +1 -0
- package/dist/interactive-tdxZKWax.js +11 -0
- package/dist/interactive-tdxZKWax.js.map +1 -0
- package/dist/{telemetry-B7zJdRmA.js → links-Cyj6v8kg.js} +4 -13
- package/dist/links-Cyj6v8kg.js.map +1 -0
- package/dist/{main-CgKxbwMP.js → main-0p-YxUNa.js} +233 -490
- package/dist/main-0p-YxUNa.js.map +1 -0
- package/dist/{mcp-DnAyW0-w.js → mcp-D3Z5MXhA.js} +3 -4
- package/dist/{mcp-DnAyW0-w.js.map → mcp-D3Z5MXhA.js.map} +1 -1
- package/dist/mcp-install-smoke-test.ts +2 -2
- package/dist/{mcp-prompt-streaming-DDWQ-FCA.js → mcp-prompt-streaming-COVbWnHt.js} +12 -12
- package/dist/mcp-prompt-streaming-COVbWnHt.js.map +1 -0
- package/dist/mode-label-DB3ol_sj.js +9 -0
- package/dist/mode-label-DB3ol_sj.js.map +1 -0
- package/dist/{models-WcwUnSKb.js → models-D1SnCzvl.js} +2 -2
- package/dist/{models-WcwUnSKb.js.map → models-D1SnCzvl.js.map} +1 -1
- package/dist/non-interactive-DxRBc73O.js +18 -0
- package/dist/non-interactive-DxRBc73O.js.map +1 -0
- package/dist/{oauth-session-DYM2Hrl2.js → oauth-session-Dde79Ycm.js} +3 -3
- package/dist/{oauth-session-DYM2Hrl2.js.map → oauth-session-Dde79Ycm.js.map} +1 -1
- package/dist/{orchestrator-tools-DbgNBFGA.js → orchestrator-tools-BSNhzzkT.js} +3 -3
- package/dist/{orchestrator-tools-DbgNBFGA.js.map → orchestrator-tools-BSNhzzkT.js.map} +1 -1
- package/dist/{package-json-Atg34fa4.js → package-json-2UrhE6kP.js} +1 -1
- package/dist/{package-json-Atg34fa4.js.map → package-json-2UrhE6kP.js.map} +1 -1
- package/dist/package-json-Dblip2_X.js +2 -0
- package/dist/package-manager-BRXlXo0p.js +105 -0
- package/dist/package-manager-BRXlXo0p.js.map +1 -0
- package/dist/{pi-8KsYsPmM.js → pi-cM_4Gd_9.js} +19 -20
- package/dist/pi-cM_4Gd_9.js.map +1 -0
- package/dist/playground-DTKy0XHT.js +12 -0
- package/dist/playground-DTKy0XHT.js.map +1 -0
- package/dist/posthog-integration-bwHwE87a.js +10291 -0
- package/dist/posthog-integration-bwHwE87a.js.map +1 -0
- package/dist/programs-BhtyA3lE.js +3 -0
- package/dist/programs-SeT1qNik.js +5348 -0
- package/dist/programs-SeT1qNik.js.map +1 -0
- package/dist/provisioning-BcXfeCMc.js +2 -0
- package/dist/{provisioning-Bo2NRxFz.js → provisioning-JbJtq7hq.js} +5 -67
- package/dist/provisioning-JbJtq7hq.js.map +1 -0
- package/dist/{queue-tools-C8mXOh7e.js → queue-tools-BIZSJyt6.js} +7 -9
- package/dist/queue-tools-BIZSJyt6.js.map +1 -0
- package/dist/results-DtKICAdz.js +55 -0
- package/dist/results-DtKICAdz.js.map +1 -0
- package/dist/run-CDurA5tO.js +248 -0
- package/dist/run-CDurA5tO.js.map +1 -0
- package/dist/run-DDCvLILJ.js +246 -0
- package/dist/run-DDCvLILJ.js.map +1 -0
- package/dist/run-tool-CTq9OOdT.js +2 -0
- package/dist/run-tool-DML8JJvt.js +2420 -0
- package/dist/run-tool-DML8JJvt.js.map +1 -0
- package/dist/runners-Dhu4pZTN.js +253 -0
- package/dist/runners-Dhu4pZTN.js.map +1 -0
- package/dist/{security-C71pkwqH.js → security-DEH8Rn0_.js} +5 -5
- package/dist/security-DEH8Rn0_.js.map +1 -0
- package/dist/setup-utils-C5-WM-hS.js +118 -0
- package/dist/setup-utils-C5-WM-hS.js.map +1 -0
- package/dist/smoke-test.sh +1 -1
- package/dist/{playground-BlYRBMj7.js → start-playground-DL4mVEUx.js} +63 -54
- package/dist/start-playground-DL4mVEUx.js.map +1 -0
- package/dist/{subagent-D1TrTchE.js → subagent-CnFvAq6E.js} +3 -3
- package/dist/{subagent-D1TrTchE.js.map → subagent-CnFvAq6E.js.map} +1 -1
- package/dist/{task-DqRlQBfs.js → task-BOScSm4W.js} +17 -18
- package/dist/task-BOScSm4W.js.map +1 -0
- package/dist/{tasks-ChWufsdO.js → tasks-BfJhVky2.js} +1 -1
- package/dist/tasks-BfJhVky2.js.map +1 -0
- package/dist/telemetry-CP4rGicd.js +13 -0
- package/dist/telemetry-CP4rGicd.js.map +1 -0
- package/dist/terminal-J3OD3dN0.js +16162 -0
- package/dist/terminal-J3OD3dN0.js.map +1 -0
- package/dist/tools-CCMV3DmB.js +544 -0
- package/dist/tools-CCMV3DmB.js.map +1 -0
- package/dist/{tools-CkJ2y9Wt.js → tools-Cz8tDptL.js} +9 -9
- package/dist/tools-Cz8tDptL.js.map +1 -0
- package/dist/tui-BUZ2PWqN.js +2 -0
- package/dist/tui-Csf7VJxt.js +25 -0
- package/dist/tui-Csf7VJxt.js.map +1 -0
- package/dist/{steps-BPcg3_3Q.js → upload-step-CEacB2RV.js} +17 -19
- package/dist/upload-step-CEacB2RV.js.map +1 -0
- package/dist/urls-BDELGZHq.js +67 -0
- package/dist/urls-BDELGZHq.js.map +1 -0
- package/dist/warlock-smoke-test.ts +1 -2
- package/dist/{wizard-abort-BPdv07np.js → wizard-abort-D3-75KyV.js} +41 -32
- package/dist/wizard-abort-D3-75KyV.js.map +1 -0
- package/dist/yara-hooks-CZ1tKxy_.js +2 -0
- package/dist/{yara-hooks-BnxejtXK.js → yara-hooks-D8YDyX7o.js} +283 -21
- package/dist/yara-hooks-D8YDyX7o.js.map +1 -0
- package/package.json +7 -8
- package/dist/PickerMenu-dG5DQCZA.js.map +0 -1
- package/dist/add-mcp-server-to-clients-DIaTRWMY.js.map +0 -1
- package/dist/add-mcp-server-to-clients-artmN7mz.js +0 -2
- package/dist/agent-BEjARD2a.js +0 -6
- package/dist/agent-BWFhuLgo.js +0 -3178
- package/dist/agent-BWFhuLgo.js.map +0 -1
- package/dist/agent-interface-FkbaBJwz.js.map +0 -1
- package/dist/agent-prompt-loader-D0weQ-7k.js.map +0 -1
- package/dist/analytics-DFtbRjYh.js +0 -2
- package/dist/analytics-DXK1gc12.js +0 -301
- package/dist/analytics-DXK1gc12.js.map +0 -1
- package/dist/api-Cm9UtKZh.js +0 -2
- package/dist/api-CrbCIQOz.js.map +0 -1
- package/dist/check-screens.tsx +0 -190
- package/dist/ci-install-COcV8SY2.js.map +0 -1
- package/dist/constants-DHCBSfnx.js +0 -260
- package/dist/constants-DHCBSfnx.js.map +0 -1
- package/dist/debug-BuYHGr6_.js +0 -2
- package/dist/debug-kAHwWGg7.js.map +0 -1
- package/dist/defaults-a9TelDhJ.js.map +0 -1
- package/dist/endpoints-BVMYm9F4.js +0 -108
- package/dist/endpoints-BVMYm9F4.js.map +0 -1
- package/dist/env-api-key-BP-NFFXt.js +0 -17
- package/dist/env-api-key-BP-NFFXt.js.map +0 -1
- package/dist/env-api-key-CaWEDj_9.js +0 -2
- package/dist/environment-BATlQxcQ.js +0 -39
- package/dist/environment-BATlQxcQ.js.map +0 -1
- package/dist/environment-CwD8OPYj.js +0 -2
- package/dist/file-C5JMsyR1.js +0 -2
- package/dist/file-DcRKycV8.js +0 -60
- package/dist/file-DcRKycV8.js.map +0 -1
- package/dist/file-watcher-Brq2nnHV.js +0 -123
- package/dist/file-watcher-Brq2nnHV.js.map +0 -1
- package/dist/gateway-C9-GlLO9.js.map +0 -1
- package/dist/headless-ui-CqI2gXlD.js +0 -44
- package/dist/headless-ui-CqI2gXlD.js.map +0 -1
- package/dist/interactive-B_Ti_CsS.js +0 -11
- package/dist/interactive-B_Ti_CsS.js.map +0 -1
- package/dist/local-dev-McsurOC-.js +0 -135
- package/dist/local-dev-McsurOC-.js.map +0 -1
- package/dist/logging-ui-Dza4D0MK.js +0 -226
- package/dist/logging-ui-Dza4D0MK.js.map +0 -1
- package/dist/main-CgKxbwMP.js.map +0 -1
- package/dist/mcp-prompt-streaming-DDWQ-FCA.js.map +0 -1
- package/dist/mint-failure-u8xQKNOn.js +0 -6392
- package/dist/mint-failure-u8xQKNOn.js.map +0 -1
- package/dist/non-interactive-DyVC1AGc.js +0 -18
- package/dist/non-interactive-DyVC1AGc.js.map +0 -1
- package/dist/package-json-D8Ga03tK.js +0 -2
- package/dist/pi-8KsYsPmM.js.map +0 -1
- package/dist/playground-BlYRBMj7.js.map +0 -1
- package/dist/posthog-Bt0Aplb8.js +0 -124
- package/dist/posthog-Bt0Aplb8.js.map +0 -1
- package/dist/posthog-CUgCEhH0.js +0 -2
- package/dist/provisioning-Bo2NRxFz.js.map +0 -1
- package/dist/provisioning-OGFGlzf7.js +0 -2
- package/dist/queue-tools-C8mXOh7e.js.map +0 -1
- package/dist/registry-C06e_x-p.js +0 -2
- package/dist/registry-CD5RQt38.js +0 -3464
- package/dist/registry-CD5RQt38.js.map +0 -1
- package/dist/run-agent-legacy-ChacZImU.js +0 -2
- package/dist/run-agent-legacy-DOlM6DQu.js +0 -3540
- package/dist/run-agent-legacy-DOlM6DQu.js.map +0 -1
- package/dist/runners-ov3EXF1n.js +0 -834
- package/dist/runners-ov3EXF1n.js.map +0 -1
- package/dist/security-C71pkwqH.js.map +0 -1
- package/dist/setup-utils-B26Lf2yF.js +0 -1512
- package/dist/setup-utils-B26Lf2yF.js.map +0 -1
- package/dist/setup-utils-CVS86NYR.js +0 -2
- package/dist/start-tui-Bo2L0bar.js +0 -6962
- package/dist/start-tui-Bo2L0bar.js.map +0 -1
- package/dist/steps-BPcg3_3Q.js.map +0 -1
- package/dist/store-BTzcvRGT.js +0 -992
- package/dist/store-BTzcvRGT.js.map +0 -1
- package/dist/store-BpqySPXm.js +0 -5
- package/dist/task-DqRlQBfs.js.map +0 -1
- package/dist/task-stream-Bw6JaLCX.js +0 -363
- package/dist/task-stream-Bw6JaLCX.js.map +0 -1
- package/dist/tasks-ChWufsdO.js.map +0 -1
- package/dist/telemetry-B7zJdRmA.js.map +0 -1
- package/dist/terminal-zgkEfoCL.js +0 -7196
- package/dist/terminal-zgkEfoCL.js.map +0 -1
- package/dist/tools-CkJ2y9Wt.js.map +0 -1
- package/dist/ui-Q6-RvERF.js +0 -15
- package/dist/ui-Q6-RvERF.js.map +0 -1
- package/dist/version-CHhJjz_H.js +0 -6
- package/dist/version-CHhJjz_H.js.map +0 -1
- package/dist/wizard-abort-BPdv07np.js.map +0 -1
- package/dist/wizard-abort-Br1qMDNa.js +0 -3
- package/dist/wizard-session-2w4Ru-Wz.js +0 -131
- package/dist/wizard-session-2w4Ru-Wz.js.map +0 -1
- package/dist/wizard-session-DGaUHOF3.js +0 -2
- package/dist/wizard-ui-DVqrYaOM.js +0 -16
- package/dist/wizard-ui-DVqrYaOM.js.map +0 -1
- package/dist/yara-hooks-BnxejtXK.js.map +0 -1
- package/dist/yara-hooks-DSuExwb4.js +0 -2
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { i as
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import { _ as coerceAuditChecks, h as AUDIT_CHECKS_FILE, l as prewarmYaraScanner, n as createPostToolUseYaraHooks, p as scanInstalledSkill, r as createPreToolUseYaraHooks } from "./yara-hooks-BnxejtXK.js";
|
|
10
|
-
import { l as buildOrchestratorTools, v as makeMutex, y as writeJsonAtomic } from "./queue-tools-C8mXOh7e.js";
|
|
1
|
+
import { a as initLogFile, i as getLogFilePath, o as logToFile, r as formatLogLine, v as runtimeEnv } from "./debug-BfQPD2Hg.js";
|
|
2
|
+
import { $ as WIZARD_REMARK_EVENT_NAME, it as wizardUserAgentForProgram, l as AWS_SKILLS_BASE_URL, n as analytics } from "./analytics-D21z3E5l.js";
|
|
3
|
+
import { i as classifyAuthFailure } from "./errors-CHrJzAZb.js";
|
|
4
|
+
import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-CAsuF6al.js";
|
|
5
|
+
import { c as REMARK_INSTRUCTION, d as gatewayAuth, f as isPastRefresh, i as gatewayApiFor, l as RESUME_INSTRUCTION, n as buildGatewayModel, s as AgentSignals, u as buildWizardPropertiesBlob } from "./gateway-D3gIlR6b.js";
|
|
6
|
+
import { i as modelCapabilities, o as triageModelFor } from "./models-D1SnCzvl.js";
|
|
7
|
+
import { _ as makeMutex, l as buildOrchestratorTools, v as writeJsonAtomic } from "./queue-tools-BIZSJyt6.js";
|
|
8
|
+
import { C as coerceAuditChecks, _ as downloadSkill, l as prewarmYaraScanner, n as createPostToolUseYaraHooks, p as scanInstalledSkill, r as createPreToolUseYaraHooks, x as AUDIT_CHECKS_FILE, y as fetchSkillMenu } from "./yara-hooks-D8YDyX7o.js";
|
|
11
9
|
import { createRequire } from "node:module";
|
|
12
10
|
import * as fs$1 from "fs";
|
|
13
11
|
import fs from "fs";
|
|
@@ -16,13 +14,9 @@ import path$1 from "node:path";
|
|
|
16
14
|
import { spawnSync } from "node:child_process";
|
|
17
15
|
import { closeSync, constants, fchmodSync, lstatSync, openSync, renameSync, unlinkSync, writeSync } from "node:fs";
|
|
18
16
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
19
|
-
import { z } from "zod";
|
|
20
|
-
import { randomUUID as randomUUID$1 } from "crypto";
|
|
21
17
|
import * as os from "os";
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
25
|
-
//#endregion
|
|
18
|
+
import { randomUUID as randomUUID$1 } from "crypto";
|
|
19
|
+
import { z } from "zod";
|
|
26
20
|
//#region src/agent/triage-provider.ts
|
|
27
21
|
const TRIAGE_MAX_TOKENS = 16384;
|
|
28
22
|
const TRIAGE_TIMEOUT_MS = 2e4;
|
|
@@ -79,6 +73,13 @@ const MAX_ENV_KEY_SET = 5e3;
|
|
|
79
73
|
function isEnvFileName(name) {
|
|
80
74
|
return name.startsWith(".env");
|
|
81
75
|
}
|
|
76
|
+
/** Committed template names; see {@link isTemplateEnvFileName}. */
|
|
77
|
+
const TEMPLATE_ENV_FILE_NAMES = [
|
|
78
|
+
".env.example",
|
|
79
|
+
".env.sample",
|
|
80
|
+
".env.template",
|
|
81
|
+
".env.dist"
|
|
82
|
+
];
|
|
82
83
|
/**
|
|
83
84
|
* Committed template files: `.env.example` and its conventional siblings. They
|
|
84
85
|
* document the keys a project expects and hold placeholders, not credentials,
|
|
@@ -92,7 +93,7 @@ function isEnvFileName(name) {
|
|
|
92
93
|
* key, not a project that has it.
|
|
93
94
|
*/
|
|
94
95
|
function isTemplateEnvFileName(name) {
|
|
95
|
-
return
|
|
96
|
+
return TEMPLATE_ENV_FILE_NAMES.includes(name);
|
|
96
97
|
}
|
|
97
98
|
/**
|
|
98
99
|
* Extract KEY NAMES from a dotenv file's content. Values are intentionally
|
|
@@ -714,21 +715,26 @@ function evaluateBashCommand(rawCommand) {
|
|
|
714
715
|
return commandDecision(normalized);
|
|
715
716
|
}
|
|
716
717
|
//#endregion
|
|
717
|
-
//#region src/
|
|
718
|
+
//#region src/shared/ask-policy.ts
|
|
718
719
|
/**
|
|
719
|
-
*
|
|
720
|
+
* Decide whether the `wizard_ask` overlay should be wired for this run.
|
|
721
|
+
* Disabled in non-interactive modes (CI, signup) — there's no human to
|
|
722
|
+
* answer. Per-program disabling is done by adding WIZARD_ASK_TOOL_NAME to
|
|
723
|
+
* the program's `disallowedTools` so the SDK rejects calls outright.
|
|
724
|
+
* Extracted so the policy can be unit-tested directly.
|
|
720
725
|
*
|
|
721
|
-
*
|
|
722
|
-
* session
|
|
723
|
-
*
|
|
724
|
-
*
|
|
726
|
+
* `e2eAsk` is the one escape hatch. The e2e harness runs a `ci`
|
|
727
|
+
* session, but it does have an answerer — the driver loop answers each
|
|
728
|
+
* `wizard_ask` batch from the program's e2e profile. Without the flag the
|
|
729
|
+
* agent-in-the-loop layer (the ask bridge in both sequence arms, and the
|
|
730
|
+
* orchestrator's seeded warehouse task) stays unreachable from a test.
|
|
725
731
|
*
|
|
726
|
-
*
|
|
727
|
-
* and `
|
|
728
|
-
* both the session and `getUI()`.
|
|
732
|
+
* Only the e2e TUI host sets the flag, from the `E2E_ASK` env var. No CLI flag
|
|
733
|
+
* populates it, so plain `--ci` and `--signup` runs behave exactly as before.
|
|
729
734
|
*/
|
|
730
|
-
|
|
731
|
-
|
|
735
|
+
function shouldDisableAsk(flags) {
|
|
736
|
+
return (flags.ci || flags.signup) && !flags.e2eAsk;
|
|
737
|
+
}
|
|
732
738
|
/**
|
|
733
739
|
* The longer per-question timeout, for asks that send the user on an errand —
|
|
734
740
|
* open a database console, mint a restricted API key. The default above is
|
|
@@ -736,6 +742,22 @@ const CANCELLED_SENTINEL = "__cancelled__";
|
|
|
736
742
|
* errand is done.
|
|
737
743
|
*/
|
|
738
744
|
const LONGER_ASK_TIMEOUT_MS = 1200 * 1e3;
|
|
745
|
+
//#endregion
|
|
746
|
+
//#region src/agent/wizard-ask-bridge.ts
|
|
747
|
+
/**
|
|
748
|
+
* WizardAskBridge — host-side promise broker for the `wizard_ask` MCP tool.
|
|
749
|
+
*
|
|
750
|
+
* The `wizard_ask` tool needs to (a) know the run's skill id, used as the
|
|
751
|
+
* analytics `source`, and (b) put questions to whoever answers them. Wiring
|
|
752
|
+
* the tools directly to either would couple our pure-data MCP server to its
|
|
753
|
+
* host.
|
|
754
|
+
*
|
|
755
|
+
* The bridge is the seam: the wizard tools depend on this interface, and
|
|
756
|
+
* the runner builds an implementation over the caller's `AgentInteraction`
|
|
757
|
+
* (see `runner/shared/ask.ts`).
|
|
758
|
+
*/
|
|
759
|
+
/** Sentinel returned for unanswered fields on cancellation or timeout. */
|
|
760
|
+
const CANCELLED_SENTINEL = "__cancelled__";
|
|
739
761
|
function buildCancelledAnswers(questions) {
|
|
740
762
|
const out = {};
|
|
741
763
|
for (const q of questions) out[q.id] = CANCELLED_SENTINEL;
|
|
@@ -771,13 +793,21 @@ function createWizardAskBridge(opts) {
|
|
|
771
793
|
const controller = new AbortController();
|
|
772
794
|
let timer;
|
|
773
795
|
let timedOut = false;
|
|
796
|
+
let settled = false;
|
|
797
|
+
let answeredCount = 0;
|
|
774
798
|
let cancelForAbort;
|
|
799
|
+
let armTimeout = () => void 0;
|
|
775
800
|
const timeoutPromise = new Promise((resolve) => {
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
801
|
+
armTimeout = () => {
|
|
802
|
+
if (settled) return;
|
|
803
|
+
if (timer) clearTimeout(timer);
|
|
804
|
+
timer = setTimeout(() => {
|
|
805
|
+
timedOut = true;
|
|
806
|
+
resolve(buildCancelledAnswers(questions));
|
|
807
|
+
controller.abort();
|
|
808
|
+
}, timeoutMs);
|
|
809
|
+
};
|
|
810
|
+
armTimeout();
|
|
781
811
|
});
|
|
782
812
|
const aborted = new Promise((resolve) => {
|
|
783
813
|
cancelForAbort = () => {
|
|
@@ -788,7 +818,13 @@ function createWizardAskBridge(opts) {
|
|
|
788
818
|
});
|
|
789
819
|
try {
|
|
790
820
|
const answers = await Promise.race([
|
|
791
|
-
opts.showQuestion(pending, {
|
|
821
|
+
opts.showQuestion(pending, {
|
|
822
|
+
signal: controller.signal,
|
|
823
|
+
onAnswer: () => {
|
|
824
|
+
answeredCount += 1;
|
|
825
|
+
armTimeout();
|
|
826
|
+
}
|
|
827
|
+
}),
|
|
792
828
|
timeoutPromise,
|
|
793
829
|
aborted
|
|
794
830
|
]);
|
|
@@ -797,6 +833,7 @@ function createWizardAskBridge(opts) {
|
|
|
797
833
|
source: pending.source,
|
|
798
834
|
subject,
|
|
799
835
|
question_count: questions.length,
|
|
836
|
+
questions_answered: answeredCount,
|
|
800
837
|
duration_ms: durationMs,
|
|
801
838
|
timed_out: timedOut
|
|
802
839
|
});
|
|
@@ -811,6 +848,7 @@ function createWizardAskBridge(opts) {
|
|
|
811
848
|
timedOut
|
|
812
849
|
};
|
|
813
850
|
} finally {
|
|
851
|
+
settled = true;
|
|
814
852
|
if (timer) clearTimeout(timer);
|
|
815
853
|
if (cancelForAbort) opts.signal?.removeEventListener("abort", cancelForAbort);
|
|
816
854
|
pendingQuestions.delete(pending.id);
|
|
@@ -818,277 +856,6 @@ function createWizardAskBridge(opts) {
|
|
|
818
856
|
}
|
|
819
857
|
};
|
|
820
858
|
}
|
|
821
|
-
//#endregion
|
|
822
|
-
//#region src/shared/fetch-retry.ts
|
|
823
|
-
/**
|
|
824
|
-
* One retry + failover policy for every critical-path fetch. GitHub is primary,
|
|
825
|
-
* AWS is the fallback. A status a retry can't heal (404, 403) spends no retry
|
|
826
|
-
* budget at the origin that returned it — but it still costs the other origin
|
|
827
|
-
* one try, because the two are published separately and GitHub 403s expired
|
|
828
|
-
* asset redirects and blocked regions where the asset is present.
|
|
829
|
-
*/
|
|
830
|
-
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
831
|
-
const DEFAULT_MAX_ATTEMPTS = 3;
|
|
832
|
-
const DEFAULT_BACKOFF_MS = 500;
|
|
833
|
-
const GITHUB_LATEST_PREFIX = `${CONTEXT_MILL_URL}/releases/latest/download/`;
|
|
834
|
-
const GITHUB_PINNED_PREFIX = `${CONTEXT_MILL_URL}/releases/download/`;
|
|
835
|
-
/** Version-pinned URLs name their own prefix, so they need the host alone. */
|
|
836
|
-
const AWS_ORIGIN = new URL(AWS_SKILLS_BASE_URL).origin;
|
|
837
|
-
function sleep(ms) {
|
|
838
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
839
|
-
}
|
|
840
|
-
/**
|
|
841
|
-
* Maps a context-mill release URL onto AWS; null when there is no second origin.
|
|
842
|
-
*
|
|
843
|
-
* .../releases/latest/download/x.zip -> <aws>/latest/x.zip
|
|
844
|
-
* .../releases/download/v1.50.0/x.zip -> <aws>/v1.50.0/x.zip
|
|
845
|
-
*/
|
|
846
|
-
function awsUrlFor(url) {
|
|
847
|
-
if (url.startsWith(GITHUB_LATEST_PREFIX)) return `${AWS_SKILLS_BASE_URL}/${url.slice(GITHUB_LATEST_PREFIX.length)}`;
|
|
848
|
-
if (url.startsWith(GITHUB_PINNED_PREFIX)) return `${AWS_ORIGIN}/${url.slice(GITHUB_PINNED_PREFIX.length)}`;
|
|
849
|
-
return null;
|
|
850
|
-
}
|
|
851
|
-
/** Sticky: without it every asset re-pays GitHub's retry budget during an outage. */
|
|
852
|
-
let preferredOrigin = "github";
|
|
853
|
-
/** A response status that retrying can't fix; propagates past the retry loop. */
|
|
854
|
-
var NonRetryableFetchError = class extends Error {};
|
|
855
|
-
/**
|
|
856
|
-
* 5xx are transient; 408 (request timeout) and 429 (rate limit) explicitly ask
|
|
857
|
-
* to retry. Every other 4xx is a client error a retry won't heal (404 missing
|
|
858
|
-
* skill, 403 bad token) — retrying only burns the backoff before failing.
|
|
859
|
-
*/
|
|
860
|
-
function isRetryableStatus(status) {
|
|
861
|
-
return status >= 500 || status === 408 || status === 429;
|
|
862
|
-
}
|
|
863
|
-
function messageOf(err) {
|
|
864
|
-
return err instanceof Error ? err.message : String(err);
|
|
865
|
-
}
|
|
866
|
-
/** Try one origin to exhaustion. */
|
|
867
|
-
async function fetchOrigin(url, opts) {
|
|
868
|
-
const failures = [];
|
|
869
|
-
for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) try {
|
|
870
|
-
const resp = await opts.fetchImpl(url, { signal: AbortSignal.timeout(opts.timeoutMs) });
|
|
871
|
-
if (resp.ok) return resp;
|
|
872
|
-
const msg = `HTTP ${resp.status} ${resp.statusText}`.trim();
|
|
873
|
-
if (!isRetryableStatus(resp.status)) throw new NonRetryableFetchError(msg);
|
|
874
|
-
throw new Error(msg);
|
|
875
|
-
} catch (err) {
|
|
876
|
-
if (err instanceof NonRetryableFetchError) throw err;
|
|
877
|
-
failures.push(`attempt ${attempt}: ${messageOf(err)}`);
|
|
878
|
-
if (attempt < opts.maxAttempts) await opts.sleepImpl(opts.backoffMs * 2 ** (attempt - 1));
|
|
879
|
-
}
|
|
880
|
-
throw new Error(failures.join("; "));
|
|
881
|
-
}
|
|
882
|
-
/**
|
|
883
|
-
* Retry with backoff, then fail over. Throws once every origin is exhausted.
|
|
884
|
-
*/
|
|
885
|
-
async function fetchWithRetry(url, opts = {}) {
|
|
886
|
-
const { fetchImpl = fetch, sleepImpl = sleep, timeoutMs = DEFAULT_TIMEOUT_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS, backoffMs = DEFAULT_BACKOFF_MS, failover = true, onEvent = (event, props) => analytics.wizardCapture(event, props) } = opts;
|
|
887
|
-
const originOpts = {
|
|
888
|
-
fetchImpl,
|
|
889
|
-
sleepImpl,
|
|
890
|
-
timeoutMs,
|
|
891
|
-
maxAttempts,
|
|
892
|
-
backoffMs
|
|
893
|
-
};
|
|
894
|
-
const awsUrl = failover ? awsUrlFor(url) : null;
|
|
895
|
-
if (!awsUrl) try {
|
|
896
|
-
return await fetchOrigin(url, originOpts);
|
|
897
|
-
} catch (err) {
|
|
898
|
-
throw new Error(`fetch ${url} failed — ${messageOf(err)}`);
|
|
899
|
-
}
|
|
900
|
-
const order = preferredOrigin === "aws" ? [{
|
|
901
|
-
origin: "aws",
|
|
902
|
-
target: awsUrl
|
|
903
|
-
}, {
|
|
904
|
-
origin: "github",
|
|
905
|
-
target: url
|
|
906
|
-
}] : [{
|
|
907
|
-
origin: "github",
|
|
908
|
-
target: url
|
|
909
|
-
}, {
|
|
910
|
-
origin: "aws",
|
|
911
|
-
target: awsUrl
|
|
912
|
-
}];
|
|
913
|
-
const failures = [];
|
|
914
|
-
for (const [index, candidate] of order.entries()) try {
|
|
915
|
-
const resp = await fetchOrigin(candidate.target, originOpts);
|
|
916
|
-
if (candidate.origin !== preferredOrigin) {
|
|
917
|
-
preferredOrigin = candidate.origin;
|
|
918
|
-
logToFile(`fetchWithRetry: failed over to ${candidate.origin}`);
|
|
919
|
-
onEvent("skills fetch failed over", {
|
|
920
|
-
origin: candidate.origin,
|
|
921
|
-
url: candidate.target
|
|
922
|
-
});
|
|
923
|
-
}
|
|
924
|
-
return resp;
|
|
925
|
-
} catch (err) {
|
|
926
|
-
failures.push(`${candidate.origin}: ${messageOf(err)}`);
|
|
927
|
-
if (index === order.length - 1) onEvent("skills fetch failed", {
|
|
928
|
-
url,
|
|
929
|
-
failures: failures.length
|
|
930
|
-
});
|
|
931
|
-
}
|
|
932
|
-
throw new Error(`fetch ${url} failed — ${failures.join(" | ")}`);
|
|
933
|
-
}
|
|
934
|
-
//#endregion
|
|
935
|
-
//#region src/shared/skill-menu.ts
|
|
936
|
-
/**
|
|
937
|
-
* The skill menu: what context-mill publishes as `skill-menu.json` and how the
|
|
938
|
-
* wizard reads it. Skill-backed CLI commands, the family picker, the skill
|
|
939
|
-
* source screen and the agent's install path all resolve skills through this
|
|
940
|
-
* one fetch, so it lives in shared and depends on nothing in the agent.
|
|
941
|
-
*/
|
|
942
|
-
/** Expand a bundle entry into one entry per variant, so the menu reads the same whether a group ships bundled or as zips. */
|
|
943
|
-
function expandBundleEntry(entry) {
|
|
944
|
-
if (!entry.bundle || !entry.variants) return [entry];
|
|
945
|
-
return entry.variants.map((variant) => ({
|
|
946
|
-
...variant,
|
|
947
|
-
name: entry.name,
|
|
948
|
-
group: entry.group,
|
|
949
|
-
bundle: true,
|
|
950
|
-
downloadUrl: entry.downloadUrl
|
|
951
|
-
}));
|
|
952
|
-
}
|
|
953
|
-
/**
|
|
954
|
-
* Fetch the skill menu from the skills server.
|
|
955
|
-
* Returns parsed data on success, `null` on failure.
|
|
956
|
-
*/
|
|
957
|
-
async function fetchSkillMenu(skillsBaseUrl, opts = {}) {
|
|
958
|
-
const menuUrl = `${skillsBaseUrl}/skill-menu.json`;
|
|
959
|
-
try {
|
|
960
|
-
logToFile(`fetchSkillMenu: fetching from ${menuUrl}`);
|
|
961
|
-
const data = await (await fetchWithRetry(menuUrl, opts)).json();
|
|
962
|
-
for (const [category, entries] of Object.entries(data.categories)) data.categories[category] = entries.flatMap(expandBundleEntry);
|
|
963
|
-
logToFile(`fetchSkillMenu: loaded (${Object.keys(data.categories).length} categories)`);
|
|
964
|
-
return data;
|
|
965
|
-
} catch (err) {
|
|
966
|
-
logToFile(`fetchSkillMenu: error: ${err.message}`);
|
|
967
|
-
return null;
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
//#endregion
|
|
971
|
-
//#region src/agent/tools/tools.ts
|
|
972
|
-
/**
|
|
973
|
-
* Shared wizard-tool behavior — skill discovery/install, env-file helpers,
|
|
974
|
-
* the wizard_ask cap policy, secret-vault plumbing, and the audit ledger.
|
|
975
|
-
* One implementation consumed by both protocol facades: the MCP server
|
|
976
|
-
* (`./mcp`) and the pi-native tools (`harness/pi/tools.ts`) — tool behavior
|
|
977
|
-
* cannot drift between harnesses.
|
|
978
|
-
*/
|
|
979
|
-
/** Extract a zip buffer, refusing entries that escape destDir (zip-slip). */
|
|
980
|
-
function extractZipArchive(zip, destDir) {
|
|
981
|
-
const root = path.resolve(destDir);
|
|
982
|
-
let written = 0;
|
|
983
|
-
for (const [entryPath, data] of Object.entries(unzipSync(zip))) {
|
|
984
|
-
const target = path.resolve(root, entryPath);
|
|
985
|
-
if (target !== root && !target.startsWith(root + path.sep)) throw new Error(`zip entry escapes destination: ${entryPath}`);
|
|
986
|
-
if (entryPath.endsWith("/")) {
|
|
987
|
-
fs.mkdirSync(target, { recursive: true });
|
|
988
|
-
continue;
|
|
989
|
-
}
|
|
990
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
991
|
-
fs.writeFileSync(target, data);
|
|
992
|
-
written++;
|
|
993
|
-
}
|
|
994
|
-
return written;
|
|
995
|
-
}
|
|
996
|
-
/** Unpack the one variant this entry names out of a bundle; the rest is noise and never hits disk. */
|
|
997
|
-
function extractBundle(bundle, destDir, entryId) {
|
|
998
|
-
if (typeof bundle?.id !== "string" || typeof bundle?.variants !== "object" || bundle.variants === null) throw new Error("malformed bundle: expected { id, variants }");
|
|
999
|
-
const files = bundle.variants[entryId.slice(bundle.id.length + 1)];
|
|
1000
|
-
if (!files) throw new Error(`bundle ${bundle.id} has no variant "${entryId}"`);
|
|
1001
|
-
const root = path.resolve(destDir);
|
|
1002
|
-
let written = 0;
|
|
1003
|
-
for (const [entryPath, contents] of Object.entries(files)) {
|
|
1004
|
-
const target = path.resolve(root, entryPath);
|
|
1005
|
-
if (target !== root && !target.startsWith(root + path.sep)) throw new Error(`bundle entry escapes destination: ${entryPath}`);
|
|
1006
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
1007
|
-
fs.writeFileSync(target, contents);
|
|
1008
|
-
written++;
|
|
1009
|
-
}
|
|
1010
|
-
return written;
|
|
1011
|
-
}
|
|
1012
|
-
/** Download a URL to a buffer, retrying transient failures with backoff. */
|
|
1013
|
-
async function downloadWithRetry(url, opts = {}) {
|
|
1014
|
-
const resp = await fetchWithRetry(url, opts);
|
|
1015
|
-
return new Uint8Array(await resp.arrayBuffer());
|
|
1016
|
-
}
|
|
1017
|
-
/**
|
|
1018
|
-
* Download and extract a skill.
|
|
1019
|
-
* By default installs to `<installDir>/.claude/skills/<id>/`.
|
|
1020
|
-
*/
|
|
1021
|
-
async function downloadSkill(skillEntry, installDir, { skillsRoot, triage }) {
|
|
1022
|
-
const skillDir = skillsRoot ? path.join(installDir, skillsRoot, skillEntry.id) : path.join(installDir, ".claude", "skills", skillEntry.id);
|
|
1023
|
-
let step = "download";
|
|
1024
|
-
try {
|
|
1025
|
-
fs.mkdirSync(skillDir, { recursive: true });
|
|
1026
|
-
const data = await downloadWithRetry(skillEntry.downloadUrl);
|
|
1027
|
-
step = "extract";
|
|
1028
|
-
const fileCount = skillEntry.bundle ? extractBundle(JSON.parse(Buffer.from(data).toString("utf8")), skillDir, skillEntry.id) : extractZipArchive(data, skillDir);
|
|
1029
|
-
fs.writeFileSync(path.join(skillDir, ".posthog-wizard"), "");
|
|
1030
|
-
step = "scan";
|
|
1031
|
-
const poisonReason = await scanInstalledSkill(skillDir, triage);
|
|
1032
|
-
if (poisonReason) {
|
|
1033
|
-
fs.rmSync(skillDir, {
|
|
1034
|
-
recursive: true,
|
|
1035
|
-
force: true
|
|
1036
|
-
});
|
|
1037
|
-
logToFile(`downloadSkill: ${poisonReason}`);
|
|
1038
|
-
analytics.wizardCapture("skill install failed", {
|
|
1039
|
-
skill_id: skillEntry.id,
|
|
1040
|
-
step: "scan",
|
|
1041
|
-
platform: process.platform,
|
|
1042
|
-
error: poisonReason.slice(0, 500)
|
|
1043
|
-
});
|
|
1044
|
-
return {
|
|
1045
|
-
success: false,
|
|
1046
|
-
error: poisonReason
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
logToFile(`downloadSkill: installed ${skillEntry.id} from ${skillEntry.downloadUrl} (${fileCount} files)`);
|
|
1050
|
-
analytics.wizardCapture("skill installed", {
|
|
1051
|
-
skill_id: skillEntry.id,
|
|
1052
|
-
platform: process.platform
|
|
1053
|
-
});
|
|
1054
|
-
return { success: true };
|
|
1055
|
-
} catch (err) {
|
|
1056
|
-
logToFile(`downloadSkill: error: ${err.message}`);
|
|
1057
|
-
analytics.wizardCapture("skill install failed", {
|
|
1058
|
-
skill_id: skillEntry.id,
|
|
1059
|
-
step,
|
|
1060
|
-
platform: process.platform,
|
|
1061
|
-
error: String(err.message).slice(0, 500)
|
|
1062
|
-
});
|
|
1063
|
-
return {
|
|
1064
|
-
success: false,
|
|
1065
|
-
error: err.message
|
|
1066
|
-
};
|
|
1067
|
-
}
|
|
1068
|
-
}
|
|
1069
|
-
/**
|
|
1070
|
-
* High-level "install a skill by ID" helper. Fetches the skill menu,
|
|
1071
|
-
* finds the skill, downloads and extracts it. Programs should use this
|
|
1072
|
-
* instead of composing fetchSkillMenu + downloadSkill themselves.
|
|
1073
|
-
*/
|
|
1074
|
-
async function installSkillById(skillId, installDir, skillsBaseUrl, options) {
|
|
1075
|
-
const menu = await fetchSkillMenu(skillsBaseUrl);
|
|
1076
|
-
if (!menu) return { kind: "menu-fetch-failed" };
|
|
1077
|
-
const skill = Object.values(menu.categories).flat().find((s) => s.id === skillId);
|
|
1078
|
-
if (!skill) return {
|
|
1079
|
-
kind: "skill-not-found",
|
|
1080
|
-
skillId
|
|
1081
|
-
};
|
|
1082
|
-
const result = await downloadSkill(skill, installDir, options);
|
|
1083
|
-
if (!result.success) return {
|
|
1084
|
-
kind: "download-failed",
|
|
1085
|
-
message: result.error ?? "unknown"
|
|
1086
|
-
};
|
|
1087
|
-
return {
|
|
1088
|
-
kind: "ok",
|
|
1089
|
-
path: options.skillsRoot ? `${options.skillsRoot}/${skillId}` : `.claude/skills/${skillId}`
|
|
1090
|
-
};
|
|
1091
|
-
}
|
|
1092
859
|
/** Subject recorded for a `wizard_ask` call that declares none. */
|
|
1093
860
|
const ASK_SUBJECT_UNSPECIFIED = "(unspecified)";
|
|
1094
861
|
/** Longest subject we keep; anything longer is truncated, never rejected. */
|
|
@@ -1943,7 +1710,7 @@ async function createWizardToolsServer(options) {
|
|
|
1943
1710
|
}],
|
|
1944
1711
|
isError: true
|
|
1945
1712
|
};
|
|
1946
|
-
const result = await downloadSkill(skill, workingDirectory, {
|
|
1713
|
+
const result = await downloadSkill(skill, workingDirectory, { scan: (dir) => scanInstalledSkill(dir, triageProvider) });
|
|
1947
1714
|
if (result.success) return { content: [{
|
|
1948
1715
|
type: "text",
|
|
1949
1716
|
text: `Skill installed to .claude/skills/${args.skillId}/`
|
|
@@ -2160,7 +1927,8 @@ const WIZARD_COMMANDMENTS = [
|
|
|
2160
1927
|
" - For `single` and `multi`, extract the alternatives from the prose into `options` as `{ label, value }` pairs. Use the human phrase as `label` and a lowercase-hyphenated form as `value` (e.g., `label: \"Vanilla JS\"`, `value: \"vanilla-js\"`).",
|
|
2161
1928
|
" - Use a kebab-case slug of the question label as `id` (e.g., \"Tech stack\" → `tech-stack`, \"Show frequency\" → `show-frequency`).",
|
|
2162
1929
|
" - Do not invent fields the schema does not define (no `source`, `category`, `priority`, etc.) — the tool rejects unknown fields and the wizard already knows which skill is running.",
|
|
2163
|
-
"After `wizard_ask` returns, use the answers directly — do not re-ask in text
|
|
1930
|
+
"After `wizard_ask` returns, use the answers directly — do not re-ask in text, and do not call `wizard_ask` again to confirm a field the user already answered.",
|
|
1931
|
+
"Correcting a rejected value is the one exception, and it is expected: when whatever you handed an answer to rejects it — a connection that fails, a host or key the API calls invalid, a permission error — ask again for only the fields that were wrong, reuse the same `subject`, and say what was rejected and what a valid value looks like. A value the user could fix in one keystroke is never a reason to abandon the step for a link they have to follow themselves. Stop after a couple of attempts on one subject. A dismissed or timed-out ask is not this case — the result names the fields it did not collect and why, and that is a decline, so fall back instead of re-asking."
|
|
2164
1932
|
].join("\n")
|
|
2165
1933
|
];
|
|
2166
1934
|
//#endregion
|
|
@@ -2417,6 +2185,25 @@ var AgentOutputSignals = class {
|
|
|
2417
2185
|
}
|
|
2418
2186
|
};
|
|
2419
2187
|
//#endregion
|
|
2188
|
+
//#region src/shared/utils/cleanup.ts
|
|
2189
|
+
/** Synchronous work to run before the process exits, such as removing a temp file. */
|
|
2190
|
+
const cleanupFns = [];
|
|
2191
|
+
/** Register `fn` to run on exit; returns a function that unregisters it. */
|
|
2192
|
+
function registerCleanup(fn) {
|
|
2193
|
+
cleanupFns.push(fn);
|
|
2194
|
+
return () => {
|
|
2195
|
+
const index = cleanupFns.indexOf(fn);
|
|
2196
|
+
if (index !== -1) cleanupFns.splice(index, 1);
|
|
2197
|
+
};
|
|
2198
|
+
}
|
|
2199
|
+
/** Runs all registered cleanup functions and drains the array. */
|
|
2200
|
+
function runCleanups() {
|
|
2201
|
+
const fns = cleanupFns.splice(0);
|
|
2202
|
+
for (const fn of fns) try {
|
|
2203
|
+
fn();
|
|
2204
|
+
} catch {}
|
|
2205
|
+
}
|
|
2206
|
+
//#endregion
|
|
2420
2207
|
//#region src/shared/agent-env-isolation.ts
|
|
2421
2208
|
/**
|
|
2422
2209
|
* Credential isolation for the Claude Agent SDK subprocess.
|
|
@@ -2572,7 +2359,7 @@ function sanitizeAgentSubprocessEnv(env = process.env) {
|
|
|
2572
2359
|
* Claude Code settings handling: conflict detection, backup/restore, and
|
|
2573
2360
|
* orphan recovery.
|
|
2574
2361
|
*
|
|
2575
|
-
* Lives apart from agent-interface so
|
|
2362
|
+
* Lives apart from agent-interface so main.ts can run orphan recovery at
|
|
2576
2363
|
* process start without dragging in the agent stack (wizard-tools, yara
|
|
2577
2364
|
* hooks, the SDK loader).
|
|
2578
2365
|
*/
|
|
@@ -2780,7 +2567,7 @@ function restoreClaudeSettings(workingDirectory) {
|
|
|
2780
2567
|
* skips restore, so the user's settings stay silently gone. Detect that exact
|
|
2781
2568
|
* state (backup present, original absent) and put the original back.
|
|
2782
2569
|
*
|
|
2783
|
-
* Runs once per process, from
|
|
2570
|
+
* Runs once per process, from main.ts, before anything reads Claude settings —
|
|
2784
2571
|
* conflict detection must see the user's real settings file, and a recovery
|
|
2785
2572
|
* any later would resurface the conflicting overrides after the backup step
|
|
2786
2573
|
* already moved them aside.
|
|
@@ -2893,7 +2680,7 @@ async function getSDKModule() {
|
|
|
2893
2680
|
* This ensures we use the SDK's bundled version rather than the user's installed Claude Code.
|
|
2894
2681
|
*/
|
|
2895
2682
|
function getClaudeCodeExecutablePath() {
|
|
2896
|
-
const sdkPackagePath =
|
|
2683
|
+
const sdkPackagePath = createRequire(import.meta.url).resolve("@anthropic-ai/claude-agent-sdk");
|
|
2897
2684
|
return path.join(path.dirname(sdkPackagePath), "cli.js");
|
|
2898
2685
|
}
|
|
2899
2686
|
/** Region implied by the resolved gateway URL, for telemetry and display. */
|
|
@@ -2997,6 +2784,15 @@ function buildAgentEnv(wizardMetadata, wizardFlags, teamId) {
|
|
|
2997
2784
|
logToFile("ANTHROPIC_CUSTOM_HEADERS", encoded);
|
|
2998
2785
|
return encoded;
|
|
2999
2786
|
}
|
|
2787
|
+
/** A debug run's diagnostic line, as info log progress; a run without `debug` emits nothing. */
|
|
2788
|
+
function debugLine(emit, options, ...args) {
|
|
2789
|
+
if (!options.debug) return;
|
|
2790
|
+
emit({
|
|
2791
|
+
kind: "log",
|
|
2792
|
+
level: "info",
|
|
2793
|
+
message: formatLogLine(...args)
|
|
2794
|
+
});
|
|
2795
|
+
}
|
|
3000
2796
|
/**
|
|
3001
2797
|
* Permission hook that allows only safe commands. Bash commands are gated by
|
|
3002
2798
|
* the exact per-manager fence in bash-fence.ts (install/build/typecheck/lint
|
|
@@ -3064,14 +2860,14 @@ function wizardCanUseTool(toolName, input, context = {}) {
|
|
|
3064
2860
|
const decision = evaluateBashCommand(command);
|
|
3065
2861
|
if (decision.allowed) {
|
|
3066
2862
|
logToFile(`Allowing bash command: ${command}`);
|
|
3067
|
-
|
|
2863
|
+
context.onDebug?.(`Allowing bash command: ${command}`);
|
|
3068
2864
|
return {
|
|
3069
2865
|
behavior: "allow",
|
|
3070
2866
|
updatedInput: input
|
|
3071
2867
|
};
|
|
3072
2868
|
}
|
|
3073
2869
|
logToFile(`Denying bash command (${decision.analyticsReason}): ${command}`);
|
|
3074
|
-
|
|
2870
|
+
context.onDebug?.(`Denying bash command (${decision.analyticsReason}): ${command}`);
|
|
3075
2871
|
analytics.wizardCapture("bash denied", {
|
|
3076
2872
|
reason: decision.analyticsReason,
|
|
3077
2873
|
command
|
|
@@ -3177,7 +2973,7 @@ async function initializeAgent(config, options) {
|
|
|
3177
2973
|
gatewayUrl,
|
|
3178
2974
|
apiKeyPresent: !!config.posthogApiKey
|
|
3179
2975
|
});
|
|
3180
|
-
|
|
2976
|
+
debugLine(emit, options, "Agent config:", {
|
|
3181
2977
|
workingDirectory: agentRunConfig.workingDirectory,
|
|
3182
2978
|
posthogMcpUrl: config.posthogMcpUrl,
|
|
3183
2979
|
gatewayUrl,
|
|
@@ -3192,7 +2988,7 @@ async function initializeAgent(config, options) {
|
|
|
3192
2988
|
message: `Failed to initialize agent: ${error.message}`
|
|
3193
2989
|
});
|
|
3194
2990
|
logToFile("Agent initialization error:", error);
|
|
3195
|
-
|
|
2991
|
+
debugLine(emit, options, "Agent initialization error:", error);
|
|
3196
2992
|
throw error;
|
|
3197
2993
|
}
|
|
3198
2994
|
}
|
|
@@ -3334,7 +3130,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3334
3130
|
}, timeoutMs) : void 0;
|
|
3335
3131
|
try {
|
|
3336
3132
|
const disallow = new Set(agentConfig.disallowedTools ?? []);
|
|
3337
|
-
const allowedTools = (agentConfig.readOnly ? READ_ONLY_TOOLS : [...BASE_ALLOWED_TOOLS, ...agentConfig.allowedTools ?? []]).filter((t) => !disallow.has(t));
|
|
3133
|
+
const allowedTools = (agentConfig.readOnly ? READ_ONLY_TOOLS : [...BASE_ALLOWED_TOOLS, ...agentConfig.allowedTools ?? []]).filter((t) => !disallow.has(t) && !CAN_USE_TOOL_FILE_TOOLS.has(t));
|
|
3338
3134
|
const inheritedMcpServerNames = Object.keys(agentConfig.mcpServers);
|
|
3339
3135
|
const triageProvider = agentConfig.triageProvider;
|
|
3340
3136
|
const onYaraTerminate = (reason) => {
|
|
@@ -3369,6 +3165,10 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3369
3165
|
disallowedTools: agentConfig.disallowedTools ? [...agentConfig.disallowedTools] : void 0
|
|
3370
3166
|
} },
|
|
3371
3167
|
settingSources: agentConfig.readOnly ? [] : ["project"],
|
|
3168
|
+
settings: {
|
|
3169
|
+
disableAllHooks: true,
|
|
3170
|
+
permissions: { deny: [...ENV_FILE_DENY_RULES] }
|
|
3171
|
+
},
|
|
3372
3172
|
skills: agentConfig.readOnly ? [] : "all",
|
|
3373
3173
|
allowedTools,
|
|
3374
3174
|
sandbox: {
|
|
@@ -3428,7 +3228,8 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3428
3228
|
const result = wizardCanUseTool(toolName, input, {
|
|
3429
3229
|
readOnly: agentConfig.readOnly,
|
|
3430
3230
|
wizardAskPending: agentConfig.getPendingQuestion?.() != null,
|
|
3431
|
-
disallowedTools: agentConfig.disallowedTools
|
|
3231
|
+
disallowedTools: agentConfig.disallowedTools,
|
|
3232
|
+
onDebug: (line) => debugLine(emit, options, line)
|
|
3432
3233
|
});
|
|
3433
3234
|
logToFile("canUseTool result:", result);
|
|
3434
3235
|
return Promise.resolve(result);
|
|
@@ -3448,7 +3249,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3448
3249
|
},
|
|
3449
3250
|
stderr: (data) => {
|
|
3450
3251
|
logToFile("CLI stderr:", data);
|
|
3451
|
-
|
|
3252
|
+
debugLine(emit, options, "CLI stderr:", data);
|
|
3452
3253
|
},
|
|
3453
3254
|
hooks: {
|
|
3454
3255
|
PreToolUse: warlockDisabled ? [] : createPreToolUseYaraHooks(triageProvider, onYaraTerminate),
|
|
@@ -3749,7 +3550,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3749
3550
|
message: `Error: ${error.message}`
|
|
3750
3551
|
});
|
|
3751
3552
|
logToFile("Agent run failed:", error);
|
|
3752
|
-
|
|
3553
|
+
debugLine(emit, options, "Full error:", error);
|
|
3753
3554
|
throw error;
|
|
3754
3555
|
} finally {
|
|
3755
3556
|
agentConfig.signal?.removeEventListener("abort", onExternalAbort);
|
|
@@ -3802,12 +3603,17 @@ const READ_ONLY_TOOLS = [
|
|
|
3802
3603
|
"Glob",
|
|
3803
3604
|
"Grep"
|
|
3804
3605
|
];
|
|
3805
|
-
|
|
3606
|
+
/** wizardCanUseTool's env-file rule as SDK deny rules for the project; outside it, canUseTool sees the file tools. */
|
|
3607
|
+
const ENV_FILE_DENY_RULES = ["Read", "Edit"].flatMap((tool) => [`${tool}(.env*)`, ...TEMPLATE_ENV_FILE_NAMES.map((name) => `${tool}(!${name})`)]);
|
|
3608
|
+
/** The SDK approves these itself inside the project; allowing them would hide calls outside it from canUseTool. */
|
|
3609
|
+
const CAN_USE_TOOL_FILE_TOOLS = new Set([
|
|
3806
3610
|
"Read",
|
|
3807
3611
|
"Write",
|
|
3808
3612
|
"Edit",
|
|
3613
|
+
"Grep"
|
|
3614
|
+
]);
|
|
3615
|
+
const BASE_ALLOWED_TOOLS = [
|
|
3809
3616
|
"Glob",
|
|
3810
|
-
"Grep",
|
|
3811
3617
|
"Bash",
|
|
3812
3618
|
...Object.values(TaskTool),
|
|
3813
3619
|
"ListMcpResourcesTool",
|
|
@@ -3975,7 +3781,7 @@ function handleSDKMessage(message, options, spinner, signals, emit, receivedSucc
|
|
|
3975
3781
|
});
|
|
3976
3782
|
};
|
|
3977
3783
|
logToFile(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
|
|
3978
|
-
|
|
3784
|
+
debugLine(emit, options, `SDK Message type: ${message.type}`);
|
|
3979
3785
|
switch (message.type) {
|
|
3980
3786
|
case "assistant": {
|
|
3981
3787
|
const tokenUsageDelta = extractTokenUsageDelta(message);
|
|
@@ -4082,11 +3888,11 @@ function handleSDKMessage(message, options, spinner, signals, emit, receivedSucc
|
|
|
4082
3888
|
}
|
|
4083
3889
|
break;
|
|
4084
3890
|
default:
|
|
4085
|
-
|
|
3891
|
+
debugLine(emit, options, `Unhandled message type: ${message.type}`);
|
|
4086
3892
|
break;
|
|
4087
3893
|
}
|
|
4088
3894
|
}
|
|
4089
3895
|
//#endregion
|
|
4090
|
-
export { vaultSensitiveAnswers as $,
|
|
3896
|
+
export { vaultSensitiveAnswers as $, AUDIT_STATUSES as A, checkEnvKeys as B, publishHandoff as C, AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION as D, AUDIT_RESOLVE_CHECKS_DESCRIPTION as E, WIZARD_ASK_SENSITIVE_DESCRIPTION as F, mergeEnvValues as G, describeAskCancellation as H, WIZARD_ASK_SUBJECT_DESCRIPTION as I, resolveAuditChecks as J, normaliseAskSubject as K, WIZARD_ASK_TOOL_DESCRIPTION as L, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as M, ENV_FILE_PATH_DESCRIPTION as N, AUDIT_SEED_CHECKS_DESCRIPTION as O, WIZARD_ASK_KIND_DESCRIPTION as P, templateEnvWriteRefusal as Q, WIZARD_TOOL_NAMES as R, PUBLISH_HANDOFF_TOOL_NAME as S, AUDIT_ADD_CHECKS_PARAM_DESCRIPTION as T, ensureGitignoreCoverage as U, createAskAccounting as V, legacyKeyNameRefusal as W, resolveEnvSecretRefs as X, resolveEnvPath as Y, seedAuditChecks as Z, markGrantRevoked as _, wizardCanUseTool as a, isEnvFileName as at, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as b, checkAllSettingsConflicts as c, createTriageLLMProvider as ct, restoreClaudeSettings as d, createWizardAskBridge as et, sanitizeAgentSubprocessEnv as f, isGrantRevoked as g, AgentOutputSignals as h, runAgent as i, MAX_ENV_KEY_SET as it, CHECK_ENV_KEYS_DESCRIPTION as j, AUDIT_SEED_CHECKS_PARAM_DESCRIPTION as k, classifySettingsConflicts as l, runCleanups as m, buildRunTags as n, LONGER_ASK_TIMEOUT_MS as nt, createIsolatedAgentConfigDir as o, parseEnvKeyNames as ot, registerCleanup as p, resolveAskQuestionKinds as q, initializeAgent as r, shouldDisableAsk as rt, backupAndFixClaudeSettings as s, toPromptSafeRelativePath as st, buildAgentEnv as t, isFullyCancelled as tt, recoverOrphanedSettingsBackups as u, assembleCommandments as v, AUDIT_ADD_CHECKS_DESCRIPTION as w, PUBLISH_HANDOFF_DESCRIPTION as x, createSecretVault as y, addAuditChecks as z };
|
|
4091
3897
|
|
|
4092
|
-
//# sourceMappingURL=agent-interface-
|
|
3898
|
+
//# sourceMappingURL=agent-interface-CemBvTAA.js.map
|