@posthog/wizard 2.80.0 → 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-m4CCPX4f.js → PickerMenu-BGGeYqd-.js} +104 -4
- package/dist/PickerMenu-BGGeYqd-.js.map +1 -0
- package/dist/README.md +9 -6
- package/dist/{agent-interface-CzyCmp7q.js → agent-interface-CemBvTAA.js} +115 -346
- package/dist/agent-interface-CemBvTAA.js.map +1 -0
- package/dist/{agent-prompt-loader-4wMxlYSX.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-C3Dc4LFl.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-CC_NDtoP.js → bounded-fs-CAsuF6al.js} +3 -3
- package/dist/{bounded-fs-CC_NDtoP.js.map → bounded-fs-CAsuF6al.js.map} +1 -1
- package/dist/{ci-install-DfcAMhlu.js → ci-install-CEYE02t-.js} +21 -25
- 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-DyARf5TF.js → debug-BfQPD2Hg.js} +18 -52
- package/dist/debug-BfQPD2Hg.js.map +1 -0
- package/dist/{defaults-DpfMnH2q.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-BmjYUSua.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-DVSb7kXb.js → host-resolution-D8GhEVoX.js} +4 -4
- package/dist/{host-resolution-DVSb7kXb.js.map → host-resolution-D8GhEVoX.js.map} +1 -1
- package/dist/install-Bw8tvDvS.js +2 -0
- package/dist/{install-Bk5TNk27.js → install-paPCzPHI.js} +26 -93
- 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/{links-9LWZPSCq.js → links-Cyj6v8kg.js} +3 -3
- package/dist/{links-9LWZPSCq.js.map → links-Cyj6v8kg.js.map} +1 -1
- package/dist/{main-DKPjFHEV.js → main-0p-YxUNa.js} +204 -469
- package/dist/main-0p-YxUNa.js.map +1 -0
- package/dist/{mcp-Co8VRF62.js → mcp-D3Z5MXhA.js} +3 -4
- package/dist/{mcp-Co8VRF62.js.map → mcp-D3Z5MXhA.js.map} +1 -1
- package/dist/mcp-install-smoke-test.ts +2 -2
- package/dist/{mcp-prompt-streaming-ljCVoQ9I.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-Dba8ITeo.js → models-D1SnCzvl.js} +2 -2
- package/dist/{models-Dba8ITeo.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-D-RfcVmr.js → oauth-session-Dde79Ycm.js} +3 -3
- package/dist/{oauth-session-D-RfcVmr.js.map → oauth-session-Dde79Ycm.js.map} +1 -1
- package/dist/{orchestrator-tools-CVJ1F9Ub.js → orchestrator-tools-BSNhzzkT.js} +3 -3
- package/dist/{orchestrator-tools-CVJ1F9Ub.js.map → orchestrator-tools-BSNhzzkT.js.map} +1 -1
- package/dist/{package-json-Cowya9-3.js → package-json-2UrhE6kP.js} +1 -1
- package/dist/{package-json-Cowya9-3.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-B5YTBRDv.js → pi-cM_4Gd_9.js} +16 -18
- 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-CLhuKqXH.js → provisioning-JbJtq7hq.js} +4 -5
- package/dist/{provisioning-CLhuKqXH.js.map → provisioning-JbJtq7hq.js.map} +1 -1
- package/dist/{queue-tools-knnPQP0e.js → queue-tools-BIZSJyt6.js} +6 -8
- 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-BvdSFDuM.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-BLsCfHmQ.js → start-playground-DL4mVEUx.js} +43 -34
- package/dist/start-playground-DL4mVEUx.js.map +1 -0
- package/dist/{subagent-D_Sqak94.js → subagent-CnFvAq6E.js} +3 -3
- package/dist/{subagent-D_Sqak94.js.map → subagent-CnFvAq6E.js.map} +1 -1
- package/dist/{task-DiTI6Sak.js → task-BOScSm4W.js} +16 -17
- package/dist/task-BOScSm4W.js.map +1 -0
- package/dist/{tasks-ChZ_F1YP.js → tasks-BfJhVky2.js} +1 -1
- package/dist/tasks-BfJhVky2.js.map +1 -0
- package/dist/{telemetry-BNKsDxNS.js → telemetry-CP4rGicd.js} +2 -2
- package/dist/{telemetry-BNKsDxNS.js.map → telemetry-CP4rGicd.js.map} +1 -1
- 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-C8LQ8QFz.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-Hc28zVc_.js → upload-step-CEacB2RV.js} +14 -16
- package/dist/upload-step-CEacB2RV.js.map +1 -0
- package/dist/{urls-BI4kJ4qQ.js → urls-BDELGZHq.js} +2 -2
- package/dist/{urls-BI4kJ4qQ.js.map → urls-BDELGZHq.js.map} +1 -1
- package/dist/warlock-smoke-test.ts +1 -2
- package/dist/{wizard-abort-DBKtfnBR.js → wizard-abort-D3-75KyV.js} +40 -33
- package/dist/wizard-abort-D3-75KyV.js.map +1 -0
- package/dist/yara-hooks-CZ1tKxy_.js +2 -0
- package/dist/{yara-hooks-C3L6lBij.js → yara-hooks-D8YDyX7o.js} +283 -21
- package/dist/yara-hooks-D8YDyX7o.js.map +1 -0
- package/package.json +6 -6
- package/dist/PickerMenu-m4CCPX4f.js.map +0 -1
- package/dist/agent-BkBbVuNq.js +0 -3189
- package/dist/agent-BkBbVuNq.js.map +0 -1
- package/dist/agent-QGK2YzlX.js +0 -6
- package/dist/agent-interface-CzyCmp7q.js.map +0 -1
- package/dist/agent-prompt-loader-4wMxlYSX.js.map +0 -1
- package/dist/analytics-B6q5PN7a.js +0 -301
- package/dist/analytics-B6q5PN7a.js.map +0 -1
- package/dist/analytics-BXtfK9o7.js +0 -2
- package/dist/api-C3Dc4LFl.js.map +0 -1
- package/dist/api-yNjrfZs2.js +0 -2
- package/dist/check-screens.tsx +0 -190
- package/dist/ci-install-DfcAMhlu.js.map +0 -1
- package/dist/constants-DO4X70po.js +0 -260
- package/dist/constants-DO4X70po.js.map +0 -1
- package/dist/debug-BueK5mRR.js +0 -2
- package/dist/debug-DyARf5TF.js.map +0 -1
- package/dist/defaults-DpfMnH2q.js.map +0 -1
- package/dist/endpoints-D-4KxZiB.js +0 -108
- package/dist/endpoints-D-4KxZiB.js.map +0 -1
- package/dist/env-api-key-CHGLe0iz.js +0 -2
- package/dist/env-api-key-COf0U-Au.js +0 -17
- package/dist/env-api-key-COf0U-Au.js.map +0 -1
- package/dist/environment-DrLaSsA8.js +0 -39
- package/dist/environment-DrLaSsA8.js.map +0 -1
- package/dist/environment-hBj7ngmO.js +0 -2
- package/dist/file-CVA9ocIC.js +0 -60
- package/dist/file-CVA9ocIC.js.map +0 -1
- package/dist/file-CmoKK_Pp.js +0 -2
- package/dist/file-watcher-C3Su8vXm.js +0 -123
- package/dist/file-watcher-C3Su8vXm.js.map +0 -1
- package/dist/gateway-BmjYUSua.js.map +0 -1
- package/dist/headless-ui-CUbv12Yx.js +0 -44
- package/dist/headless-ui-CUbv12Yx.js.map +0 -1
- package/dist/install-Bk5TNk27.js.map +0 -1
- package/dist/install-F4wm3RSl.js +0 -2
- package/dist/interactive-C5LNvDj6.js +0 -11
- package/dist/interactive-C5LNvDj6.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-p6XKVmTx.js +0 -226
- package/dist/logging-ui-p6XKVmTx.js.map +0 -1
- package/dist/main-DKPjFHEV.js.map +0 -1
- package/dist/mcp-prompt-streaming-ljCVoQ9I.js.map +0 -1
- package/dist/mint-failure-C0HyvEwO.js +0 -6403
- package/dist/mint-failure-C0HyvEwO.js.map +0 -1
- package/dist/non-interactive-CLMJrj_7.js +0 -18
- package/dist/non-interactive-CLMJrj_7.js.map +0 -1
- package/dist/package-json--ppioh2F.js +0 -2
- package/dist/pi-B5YTBRDv.js.map +0 -1
- package/dist/playground-BLsCfHmQ.js.map +0 -1
- package/dist/posthog-B2E0hpZt.js +0 -2
- package/dist/posthog-B42rt_1S.js +0 -124
- package/dist/posthog-B42rt_1S.js.map +0 -1
- package/dist/project-data--L-WZyvj.js +0 -2
- package/dist/project-data-BO9IXn9y.js +0 -1131
- package/dist/project-data-BO9IXn9y.js.map +0 -1
- package/dist/provisioning-C01REIU2.js +0 -2
- package/dist/queue-tools-knnPQP0e.js.map +0 -1
- package/dist/registry-B3rC5U4b.js +0 -3464
- package/dist/registry-B3rC5U4b.js.map +0 -1
- package/dist/registry-BamsM7J9.js +0 -2
- package/dist/run-agent-legacy-CwUmPfQF.js +0 -2
- package/dist/run-agent-legacy-DWBajsMh.js +0 -3467
- package/dist/run-agent-legacy-DWBajsMh.js.map +0 -1
- package/dist/runners-D1PqqpjA.js +0 -834
- package/dist/runners-D1PqqpjA.js.map +0 -1
- package/dist/security-BvdSFDuM.js.map +0 -1
- package/dist/setup-utils-ChXXTi1m.js +0 -301
- package/dist/setup-utils-ChXXTi1m.js.map +0 -1
- package/dist/start-tui-DicLfgsj.js +0 -6964
- package/dist/start-tui-DicLfgsj.js.map +0 -1
- package/dist/steps-Hc28zVc_.js.map +0 -1
- package/dist/store-COCO6U0P.js +0 -5
- package/dist/store-D3509G87.js +0 -1030
- package/dist/store-D3509G87.js.map +0 -1
- package/dist/task-DiTI6Sak.js.map +0 -1
- package/dist/task-status-CmrrR7zo.js +0 -16
- package/dist/task-status-CmrrR7zo.js.map +0 -1
- package/dist/task-stream-BckhG_cB.js +0 -363
- package/dist/task-stream-BckhG_cB.js.map +0 -1
- package/dist/tasks-ChZ_F1YP.js.map +0 -1
- package/dist/terminal-PK9bCLRi.js +0 -7222
- package/dist/terminal-PK9bCLRi.js.map +0 -1
- package/dist/tools-C8LQ8QFz.js.map +0 -1
- package/dist/ui-tPNpM6vj.js +0 -15
- package/dist/ui-tPNpM6vj.js.map +0 -1
- package/dist/version-5_ydHkM6.js +0 -6
- package/dist/version-5_ydHkM6.js.map +0 -1
- package/dist/wizard-abort-BVjqLyeA.js +0 -3
- package/dist/wizard-abort-DBKtfnBR.js.map +0 -1
- package/dist/wizard-session-B7BHnay0.js +0 -2
- package/dist/wizard-session-BYw6LzpS.js +0 -133
- package/dist/wizard-session-BYw6LzpS.js.map +0 -1
- package/dist/yara-hooks-C3L6lBij.js.map +0 -1
- package/dist/yara-hooks-CF_IsoaA.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-C3L6lBij.js";
|
|
10
|
-
import { l as buildOrchestratorTools, v as makeMutex, y as writeJsonAtomic } from "./queue-tools-knnPQP0e.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";
|
|
@@ -15,14 +13,10 @@ import path from "path";
|
|
|
15
13
|
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
|
-
import { randomUUID } from "crypto";
|
|
19
|
-
import { randomBytes, randomUUID as randomUUID$1 } from "node:crypto";
|
|
16
|
+
import { randomBytes, randomUUID } from "node:crypto";
|
|
20
17
|
import * as os from "os";
|
|
21
|
-
import {
|
|
18
|
+
import { randomUUID as randomUUID$1 } from "crypto";
|
|
22
19
|
import { z } from "zod";
|
|
23
|
-
//#region \0rolldown/runtime.js
|
|
24
|
-
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
25
|
-
//#endregion
|
|
26
20
|
//#region src/agent/triage-provider.ts
|
|
27
21
|
const TRIAGE_MAX_TOKENS = 16384;
|
|
28
22
|
const TRIAGE_TIMEOUT_MS = 2e4;
|
|
@@ -73,40 +67,19 @@ function createTriageLLMProvider(auth, harness) {
|
|
|
73
67
|
}
|
|
74
68
|
};
|
|
75
69
|
}
|
|
76
|
-
//#endregion
|
|
77
|
-
//#region src/shared/ask-policy.ts
|
|
78
|
-
/**
|
|
79
|
-
* Decide whether the `wizard_ask` overlay should be wired for this run.
|
|
80
|
-
* Disabled in non-interactive modes (CI, signup) — there's no human to
|
|
81
|
-
* answer. Per-program disabling is done by adding WIZARD_ASK_TOOL_NAME to
|
|
82
|
-
* the program's `disallowedTools` so the SDK rejects calls outright.
|
|
83
|
-
* Extracted so the policy can be unit-tested directly.
|
|
84
|
-
*
|
|
85
|
-
* `e2eAsk` is the one escape hatch. The e2e harness runs a `ci`
|
|
86
|
-
* session, but it does have an answerer — the driver loop answers each
|
|
87
|
-
* `wizard_ask` batch from the program's e2e profile. Without the flag the
|
|
88
|
-
* agent-in-the-loop layer (the ask bridge in both sequence arms, and the
|
|
89
|
-
* orchestrator's seeded warehouse task) stays unreachable from a test.
|
|
90
|
-
*
|
|
91
|
-
* Only the e2e TUI host sets the flag, from the `E2E_ASK` env var. No CLI flag
|
|
92
|
-
* populates it, so plain `--ci` and `--signup` runs behave exactly as before.
|
|
93
|
-
*/
|
|
94
|
-
function shouldDisableAsk(flags) {
|
|
95
|
-
return (flags.ci || flags.signup) && !flags.e2eAsk;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* The longer per-question timeout, for asks that send the user on an errand —
|
|
99
|
-
* open a database console, mint a restricted API key. The default above is
|
|
100
|
-
* sized for a question answerable from memory and expires long before an
|
|
101
|
-
* errand is done.
|
|
102
|
-
*/
|
|
103
|
-
const LONGER_ASK_TIMEOUT_MS = 1200 * 1e3;
|
|
104
70
|
/** A scan retains at most this many distinct key names. */
|
|
105
71
|
const MAX_ENV_KEY_SET = 5e3;
|
|
106
72
|
/** Files whose names start with `.env` carry env keys (`.env.local`, `.env.production`, …). */
|
|
107
73
|
function isEnvFileName(name) {
|
|
108
74
|
return name.startsWith(".env");
|
|
109
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
|
+
];
|
|
110
83
|
/**
|
|
111
84
|
* Committed template files: `.env.example` and its conventional siblings. They
|
|
112
85
|
* document the keys a project expects and hold placeholders, not credentials,
|
|
@@ -120,7 +93,7 @@ function isEnvFileName(name) {
|
|
|
120
93
|
* key, not a project that has it.
|
|
121
94
|
*/
|
|
122
95
|
function isTemplateEnvFileName(name) {
|
|
123
|
-
return
|
|
96
|
+
return TEMPLATE_ENV_FILE_NAMES.includes(name);
|
|
124
97
|
}
|
|
125
98
|
/**
|
|
126
99
|
* Extract KEY NAMES from a dotenv file's content. Values are intentionally
|
|
@@ -742,18 +715,46 @@ function evaluateBashCommand(rawCommand) {
|
|
|
742
715
|
return commandDecision(normalized);
|
|
743
716
|
}
|
|
744
717
|
//#endregion
|
|
718
|
+
//#region src/shared/ask-policy.ts
|
|
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.
|
|
725
|
+
*
|
|
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.
|
|
731
|
+
*
|
|
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.
|
|
734
|
+
*/
|
|
735
|
+
function shouldDisableAsk(flags) {
|
|
736
|
+
return (flags.ci || flags.signup) && !flags.e2eAsk;
|
|
737
|
+
}
|
|
738
|
+
/**
|
|
739
|
+
* The longer per-question timeout, for asks that send the user on an errand —
|
|
740
|
+
* open a database console, mint a restricted API key. The default above is
|
|
741
|
+
* sized for a question answerable from memory and expires long before an
|
|
742
|
+
* errand is done.
|
|
743
|
+
*/
|
|
744
|
+
const LONGER_ASK_TIMEOUT_MS = 1200 * 1e3;
|
|
745
|
+
//#endregion
|
|
745
746
|
//#region src/agent/wizard-ask-bridge.ts
|
|
746
747
|
/**
|
|
747
748
|
* WizardAskBridge — host-side promise broker for the `wizard_ask` MCP tool.
|
|
748
749
|
*
|
|
749
|
-
* The `wizard_ask` tool needs to (a)
|
|
750
|
-
*
|
|
751
|
-
*
|
|
752
|
-
*
|
|
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.
|
|
753
754
|
*
|
|
754
|
-
* The bridge is the seam:
|
|
755
|
-
*
|
|
756
|
-
*
|
|
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`).
|
|
757
758
|
*/
|
|
758
759
|
/** Sentinel returned for unanswered fields on cancellation or timeout. */
|
|
759
760
|
const CANCELLED_SENTINEL = "__cancelled__";
|
|
@@ -781,7 +782,7 @@ function createWizardAskBridge(opts) {
|
|
|
781
782
|
timedOut: false
|
|
782
783
|
};
|
|
783
784
|
const pending = {
|
|
784
|
-
id: randomUUID(),
|
|
785
|
+
id: randomUUID$1(),
|
|
785
786
|
questions,
|
|
786
787
|
source: opts.getSource(),
|
|
787
788
|
richLinks: opts.richLinks ?? false,
|
|
@@ -855,277 +856,6 @@ function createWizardAskBridge(opts) {
|
|
|
855
856
|
}
|
|
856
857
|
};
|
|
857
858
|
}
|
|
858
|
-
//#endregion
|
|
859
|
-
//#region src/shared/fetch-retry.ts
|
|
860
|
-
/**
|
|
861
|
-
* One retry + failover policy for every critical-path fetch. GitHub is primary,
|
|
862
|
-
* AWS is the fallback. A status a retry can't heal (404, 403) spends no retry
|
|
863
|
-
* budget at the origin that returned it — but it still costs the other origin
|
|
864
|
-
* one try, because the two are published separately and GitHub 403s expired
|
|
865
|
-
* asset redirects and blocked regions where the asset is present.
|
|
866
|
-
*/
|
|
867
|
-
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
868
|
-
const DEFAULT_MAX_ATTEMPTS = 3;
|
|
869
|
-
const DEFAULT_BACKOFF_MS = 500;
|
|
870
|
-
const GITHUB_LATEST_PREFIX = `${CONTEXT_MILL_URL}/releases/latest/download/`;
|
|
871
|
-
const GITHUB_PINNED_PREFIX = `${CONTEXT_MILL_URL}/releases/download/`;
|
|
872
|
-
/** Version-pinned URLs name their own prefix, so they need the host alone. */
|
|
873
|
-
const AWS_ORIGIN = new URL(AWS_SKILLS_BASE_URL).origin;
|
|
874
|
-
function sleep(ms) {
|
|
875
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
876
|
-
}
|
|
877
|
-
/**
|
|
878
|
-
* Maps a context-mill release URL onto AWS; null when there is no second origin.
|
|
879
|
-
*
|
|
880
|
-
* .../releases/latest/download/x.zip -> <aws>/latest/x.zip
|
|
881
|
-
* .../releases/download/v1.50.0/x.zip -> <aws>/v1.50.0/x.zip
|
|
882
|
-
*/
|
|
883
|
-
function awsUrlFor(url) {
|
|
884
|
-
if (url.startsWith(GITHUB_LATEST_PREFIX)) return `${AWS_SKILLS_BASE_URL}/${url.slice(GITHUB_LATEST_PREFIX.length)}`;
|
|
885
|
-
if (url.startsWith(GITHUB_PINNED_PREFIX)) return `${AWS_ORIGIN}/${url.slice(GITHUB_PINNED_PREFIX.length)}`;
|
|
886
|
-
return null;
|
|
887
|
-
}
|
|
888
|
-
/** Sticky: without it every asset re-pays GitHub's retry budget during an outage. */
|
|
889
|
-
let preferredOrigin = "github";
|
|
890
|
-
/** A response status that retrying can't fix; propagates past the retry loop. */
|
|
891
|
-
var NonRetryableFetchError = class extends Error {};
|
|
892
|
-
/**
|
|
893
|
-
* 5xx are transient; 408 (request timeout) and 429 (rate limit) explicitly ask
|
|
894
|
-
* to retry. Every other 4xx is a client error a retry won't heal (404 missing
|
|
895
|
-
* skill, 403 bad token) — retrying only burns the backoff before failing.
|
|
896
|
-
*/
|
|
897
|
-
function isRetryableStatus(status) {
|
|
898
|
-
return status >= 500 || status === 408 || status === 429;
|
|
899
|
-
}
|
|
900
|
-
function messageOf(err) {
|
|
901
|
-
return err instanceof Error ? err.message : String(err);
|
|
902
|
-
}
|
|
903
|
-
/** Try one origin to exhaustion. */
|
|
904
|
-
async function fetchOrigin(url, opts) {
|
|
905
|
-
const failures = [];
|
|
906
|
-
for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) try {
|
|
907
|
-
const resp = await opts.fetchImpl(url, { signal: AbortSignal.timeout(opts.timeoutMs) });
|
|
908
|
-
if (resp.ok) return resp;
|
|
909
|
-
const msg = `HTTP ${resp.status} ${resp.statusText}`.trim();
|
|
910
|
-
if (!isRetryableStatus(resp.status)) throw new NonRetryableFetchError(msg);
|
|
911
|
-
throw new Error(msg);
|
|
912
|
-
} catch (err) {
|
|
913
|
-
if (err instanceof NonRetryableFetchError) throw err;
|
|
914
|
-
failures.push(`attempt ${attempt}: ${messageOf(err)}`);
|
|
915
|
-
if (attempt < opts.maxAttempts) await opts.sleepImpl(opts.backoffMs * 2 ** (attempt - 1));
|
|
916
|
-
}
|
|
917
|
-
throw new Error(failures.join("; "));
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* Retry with backoff, then fail over. Throws once every origin is exhausted.
|
|
921
|
-
*/
|
|
922
|
-
async function fetchWithRetry(url, opts = {}) {
|
|
923
|
-
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;
|
|
924
|
-
const originOpts = {
|
|
925
|
-
fetchImpl,
|
|
926
|
-
sleepImpl,
|
|
927
|
-
timeoutMs,
|
|
928
|
-
maxAttempts,
|
|
929
|
-
backoffMs
|
|
930
|
-
};
|
|
931
|
-
const awsUrl = failover ? awsUrlFor(url) : null;
|
|
932
|
-
if (!awsUrl) try {
|
|
933
|
-
return await fetchOrigin(url, originOpts);
|
|
934
|
-
} catch (err) {
|
|
935
|
-
throw new Error(`fetch ${url} failed — ${messageOf(err)}`);
|
|
936
|
-
}
|
|
937
|
-
const order = preferredOrigin === "aws" ? [{
|
|
938
|
-
origin: "aws",
|
|
939
|
-
target: awsUrl
|
|
940
|
-
}, {
|
|
941
|
-
origin: "github",
|
|
942
|
-
target: url
|
|
943
|
-
}] : [{
|
|
944
|
-
origin: "github",
|
|
945
|
-
target: url
|
|
946
|
-
}, {
|
|
947
|
-
origin: "aws",
|
|
948
|
-
target: awsUrl
|
|
949
|
-
}];
|
|
950
|
-
const failures = [];
|
|
951
|
-
for (const [index, candidate] of order.entries()) try {
|
|
952
|
-
const resp = await fetchOrigin(candidate.target, originOpts);
|
|
953
|
-
if (candidate.origin !== preferredOrigin) {
|
|
954
|
-
preferredOrigin = candidate.origin;
|
|
955
|
-
logToFile(`fetchWithRetry: failed over to ${candidate.origin}`);
|
|
956
|
-
onEvent("skills fetch failed over", {
|
|
957
|
-
origin: candidate.origin,
|
|
958
|
-
url: candidate.target
|
|
959
|
-
});
|
|
960
|
-
}
|
|
961
|
-
return resp;
|
|
962
|
-
} catch (err) {
|
|
963
|
-
failures.push(`${candidate.origin}: ${messageOf(err)}`);
|
|
964
|
-
if (index === order.length - 1) onEvent("skills fetch failed", {
|
|
965
|
-
url,
|
|
966
|
-
failures: failures.length
|
|
967
|
-
});
|
|
968
|
-
}
|
|
969
|
-
throw new Error(`fetch ${url} failed — ${failures.join(" | ")}`);
|
|
970
|
-
}
|
|
971
|
-
//#endregion
|
|
972
|
-
//#region src/shared/skill-menu.ts
|
|
973
|
-
/**
|
|
974
|
-
* The skill menu: what context-mill publishes as `skill-menu.json` and how the
|
|
975
|
-
* wizard reads it. Skill-backed CLI commands, the family picker, the skill
|
|
976
|
-
* source screen and the agent's install path all resolve skills through this
|
|
977
|
-
* one fetch, so it lives in shared and depends on nothing in the agent.
|
|
978
|
-
*/
|
|
979
|
-
/** Expand a bundle entry into one entry per variant, so the menu reads the same whether a group ships bundled or as zips. */
|
|
980
|
-
function expandBundleEntry(entry) {
|
|
981
|
-
if (!entry.bundle || !entry.variants) return [entry];
|
|
982
|
-
return entry.variants.map((variant) => ({
|
|
983
|
-
...variant,
|
|
984
|
-
name: entry.name,
|
|
985
|
-
group: entry.group,
|
|
986
|
-
bundle: true,
|
|
987
|
-
downloadUrl: entry.downloadUrl
|
|
988
|
-
}));
|
|
989
|
-
}
|
|
990
|
-
/**
|
|
991
|
-
* Fetch the skill menu from the skills server.
|
|
992
|
-
* Returns parsed data on success, `null` on failure.
|
|
993
|
-
*/
|
|
994
|
-
async function fetchSkillMenu(skillsBaseUrl, opts = {}) {
|
|
995
|
-
const menuUrl = `${skillsBaseUrl}/skill-menu.json`;
|
|
996
|
-
try {
|
|
997
|
-
logToFile(`fetchSkillMenu: fetching from ${menuUrl}`);
|
|
998
|
-
const data = await (await fetchWithRetry(menuUrl, opts)).json();
|
|
999
|
-
for (const [category, entries] of Object.entries(data.categories)) data.categories[category] = entries.flatMap(expandBundleEntry);
|
|
1000
|
-
logToFile(`fetchSkillMenu: loaded (${Object.keys(data.categories).length} categories)`);
|
|
1001
|
-
return data;
|
|
1002
|
-
} catch (err) {
|
|
1003
|
-
logToFile(`fetchSkillMenu: error: ${err.message}`);
|
|
1004
|
-
return null;
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
//#endregion
|
|
1008
|
-
//#region src/agent/tools/tools.ts
|
|
1009
|
-
/**
|
|
1010
|
-
* Shared wizard-tool behavior — skill discovery/install, env-file helpers,
|
|
1011
|
-
* the wizard_ask cap policy, secret-vault plumbing, and the audit ledger.
|
|
1012
|
-
* One implementation consumed by both protocol facades: the MCP server
|
|
1013
|
-
* (`./mcp`) and the pi-native tools (`harness/pi/tools.ts`) — tool behavior
|
|
1014
|
-
* cannot drift between harnesses.
|
|
1015
|
-
*/
|
|
1016
|
-
/** Extract a zip buffer, refusing entries that escape destDir (zip-slip). */
|
|
1017
|
-
function extractZipArchive(zip, destDir) {
|
|
1018
|
-
const root = path.resolve(destDir);
|
|
1019
|
-
let written = 0;
|
|
1020
|
-
for (const [entryPath, data] of Object.entries(unzipSync(zip))) {
|
|
1021
|
-
const target = path.resolve(root, entryPath);
|
|
1022
|
-
if (target !== root && !target.startsWith(root + path.sep)) throw new Error(`zip entry escapes destination: ${entryPath}`);
|
|
1023
|
-
if (entryPath.endsWith("/")) {
|
|
1024
|
-
fs.mkdirSync(target, { recursive: true });
|
|
1025
|
-
continue;
|
|
1026
|
-
}
|
|
1027
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
1028
|
-
fs.writeFileSync(target, data);
|
|
1029
|
-
written++;
|
|
1030
|
-
}
|
|
1031
|
-
return written;
|
|
1032
|
-
}
|
|
1033
|
-
/** Unpack the one variant this entry names out of a bundle; the rest is noise and never hits disk. */
|
|
1034
|
-
function extractBundle(bundle, destDir, entryId) {
|
|
1035
|
-
if (typeof bundle?.id !== "string" || typeof bundle?.variants !== "object" || bundle.variants === null) throw new Error("malformed bundle: expected { id, variants }");
|
|
1036
|
-
const files = bundle.variants[entryId.slice(bundle.id.length + 1)];
|
|
1037
|
-
if (!files) throw new Error(`bundle ${bundle.id} has no variant "${entryId}"`);
|
|
1038
|
-
const root = path.resolve(destDir);
|
|
1039
|
-
let written = 0;
|
|
1040
|
-
for (const [entryPath, contents] of Object.entries(files)) {
|
|
1041
|
-
const target = path.resolve(root, entryPath);
|
|
1042
|
-
if (target !== root && !target.startsWith(root + path.sep)) throw new Error(`bundle entry escapes destination: ${entryPath}`);
|
|
1043
|
-
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
1044
|
-
fs.writeFileSync(target, contents);
|
|
1045
|
-
written++;
|
|
1046
|
-
}
|
|
1047
|
-
return written;
|
|
1048
|
-
}
|
|
1049
|
-
/** Download a URL to a buffer, retrying transient failures with backoff. */
|
|
1050
|
-
async function downloadWithRetry(url, opts = {}) {
|
|
1051
|
-
const resp = await fetchWithRetry(url, opts);
|
|
1052
|
-
return new Uint8Array(await resp.arrayBuffer());
|
|
1053
|
-
}
|
|
1054
|
-
/**
|
|
1055
|
-
* Download and extract a skill.
|
|
1056
|
-
* By default installs to `<installDir>/.claude/skills/<id>/`.
|
|
1057
|
-
*/
|
|
1058
|
-
async function downloadSkill(skillEntry, installDir, { skillsRoot, triage }) {
|
|
1059
|
-
const skillDir = skillsRoot ? path.join(installDir, skillsRoot, skillEntry.id) : path.join(installDir, ".claude", "skills", skillEntry.id);
|
|
1060
|
-
let step = "download";
|
|
1061
|
-
try {
|
|
1062
|
-
fs.mkdirSync(skillDir, { recursive: true });
|
|
1063
|
-
const data = await downloadWithRetry(skillEntry.downloadUrl);
|
|
1064
|
-
step = "extract";
|
|
1065
|
-
const fileCount = skillEntry.bundle ? extractBundle(JSON.parse(Buffer.from(data).toString("utf8")), skillDir, skillEntry.id) : extractZipArchive(data, skillDir);
|
|
1066
|
-
fs.writeFileSync(path.join(skillDir, ".posthog-wizard"), "");
|
|
1067
|
-
step = "scan";
|
|
1068
|
-
const poisonReason = await scanInstalledSkill(skillDir, triage);
|
|
1069
|
-
if (poisonReason) {
|
|
1070
|
-
fs.rmSync(skillDir, {
|
|
1071
|
-
recursive: true,
|
|
1072
|
-
force: true
|
|
1073
|
-
});
|
|
1074
|
-
logToFile(`downloadSkill: ${poisonReason}`);
|
|
1075
|
-
analytics.wizardCapture("skill install failed", {
|
|
1076
|
-
skill_id: skillEntry.id,
|
|
1077
|
-
step: "scan",
|
|
1078
|
-
platform: process.platform,
|
|
1079
|
-
error: poisonReason.slice(0, 500)
|
|
1080
|
-
});
|
|
1081
|
-
return {
|
|
1082
|
-
success: false,
|
|
1083
|
-
error: poisonReason
|
|
1084
|
-
};
|
|
1085
|
-
}
|
|
1086
|
-
logToFile(`downloadSkill: installed ${skillEntry.id} from ${skillEntry.downloadUrl} (${fileCount} files)`);
|
|
1087
|
-
analytics.wizardCapture("skill installed", {
|
|
1088
|
-
skill_id: skillEntry.id,
|
|
1089
|
-
platform: process.platform
|
|
1090
|
-
});
|
|
1091
|
-
return { success: true };
|
|
1092
|
-
} catch (err) {
|
|
1093
|
-
logToFile(`downloadSkill: error: ${err.message}`);
|
|
1094
|
-
analytics.wizardCapture("skill install failed", {
|
|
1095
|
-
skill_id: skillEntry.id,
|
|
1096
|
-
step,
|
|
1097
|
-
platform: process.platform,
|
|
1098
|
-
error: String(err.message).slice(0, 500)
|
|
1099
|
-
});
|
|
1100
|
-
return {
|
|
1101
|
-
success: false,
|
|
1102
|
-
error: err.message
|
|
1103
|
-
};
|
|
1104
|
-
}
|
|
1105
|
-
}
|
|
1106
|
-
/**
|
|
1107
|
-
* High-level "install a skill by ID" helper. Fetches the skill menu,
|
|
1108
|
-
* finds the skill, downloads and extracts it. Programs should use this
|
|
1109
|
-
* instead of composing fetchSkillMenu + downloadSkill themselves.
|
|
1110
|
-
*/
|
|
1111
|
-
async function installSkillById(skillId, installDir, skillsBaseUrl, options) {
|
|
1112
|
-
const menu = await fetchSkillMenu(skillsBaseUrl);
|
|
1113
|
-
if (!menu) return { kind: "menu-fetch-failed" };
|
|
1114
|
-
const skill = Object.values(menu.categories).flat().find((s) => s.id === skillId);
|
|
1115
|
-
if (!skill) return {
|
|
1116
|
-
kind: "skill-not-found",
|
|
1117
|
-
skillId
|
|
1118
|
-
};
|
|
1119
|
-
const result = await downloadSkill(skill, installDir, options);
|
|
1120
|
-
if (!result.success) return {
|
|
1121
|
-
kind: "download-failed",
|
|
1122
|
-
message: result.error ?? "unknown"
|
|
1123
|
-
};
|
|
1124
|
-
return {
|
|
1125
|
-
kind: "ok",
|
|
1126
|
-
path: options.skillsRoot ? `${options.skillsRoot}/${skillId}` : `.claude/skills/${skillId}`
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
859
|
/** Subject recorded for a `wizard_ask` call that declares none. */
|
|
1130
860
|
const ASK_SUBJECT_UNSPECIFIED = "(unspecified)";
|
|
1131
861
|
/** Longest subject we keep; anything longer is truncated, never rejected. */
|
|
@@ -1804,7 +1534,7 @@ function createSecretVault() {
|
|
|
1804
1534
|
const store = /* @__PURE__ */ new Map();
|
|
1805
1535
|
return {
|
|
1806
1536
|
put(value, meta) {
|
|
1807
|
-
const ref = `${REF_PREFIX}${randomUUID()}`;
|
|
1537
|
+
const ref = `${REF_PREFIX}${randomUUID$1()}`;
|
|
1808
1538
|
store.set(ref, {
|
|
1809
1539
|
value,
|
|
1810
1540
|
meta: {
|
|
@@ -1980,7 +1710,7 @@ async function createWizardToolsServer(options) {
|
|
|
1980
1710
|
}],
|
|
1981
1711
|
isError: true
|
|
1982
1712
|
};
|
|
1983
|
-
const result = await downloadSkill(skill, workingDirectory, {
|
|
1713
|
+
const result = await downloadSkill(skill, workingDirectory, { scan: (dir) => scanInstalledSkill(dir, triageProvider) });
|
|
1984
1714
|
if (result.success) return { content: [{
|
|
1985
1715
|
type: "text",
|
|
1986
1716
|
text: `Skill installed to .claude/skills/${args.skillId}/`
|
|
@@ -2197,7 +1927,8 @@ const WIZARD_COMMANDMENTS = [
|
|
|
2197
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\"`).",
|
|
2198
1928
|
" - Use a kebab-case slug of the question label as `id` (e.g., \"Tech stack\" → `tech-stack`, \"Show frequency\" → `show-frequency`).",
|
|
2199
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.",
|
|
2200
|
-
"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."
|
|
2201
1932
|
].join("\n")
|
|
2202
1933
|
];
|
|
2203
1934
|
//#endregion
|
|
@@ -2454,6 +2185,25 @@ var AgentOutputSignals = class {
|
|
|
2454
2185
|
}
|
|
2455
2186
|
};
|
|
2456
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
|
|
2457
2207
|
//#region src/shared/agent-env-isolation.ts
|
|
2458
2208
|
/**
|
|
2459
2209
|
* Credential isolation for the Claude Agent SDK subprocess.
|
|
@@ -2609,7 +2359,7 @@ function sanitizeAgentSubprocessEnv(env = process.env) {
|
|
|
2609
2359
|
* Claude Code settings handling: conflict detection, backup/restore, and
|
|
2610
2360
|
* orphan recovery.
|
|
2611
2361
|
*
|
|
2612
|
-
* Lives apart from agent-interface so
|
|
2362
|
+
* Lives apart from agent-interface so main.ts can run orphan recovery at
|
|
2613
2363
|
* process start without dragging in the agent stack (wizard-tools, yara
|
|
2614
2364
|
* hooks, the SDK loader).
|
|
2615
2365
|
*/
|
|
@@ -2817,7 +2567,7 @@ function restoreClaudeSettings(workingDirectory) {
|
|
|
2817
2567
|
* skips restore, so the user's settings stay silently gone. Detect that exact
|
|
2818
2568
|
* state (backup present, original absent) and put the original back.
|
|
2819
2569
|
*
|
|
2820
|
-
* Runs once per process, from
|
|
2570
|
+
* Runs once per process, from main.ts, before anything reads Claude settings —
|
|
2821
2571
|
* conflict detection must see the user's real settings file, and a recovery
|
|
2822
2572
|
* any later would resurface the conflicting overrides after the backup step
|
|
2823
2573
|
* already moved them aside.
|
|
@@ -2930,7 +2680,7 @@ async function getSDKModule() {
|
|
|
2930
2680
|
* This ensures we use the SDK's bundled version rather than the user's installed Claude Code.
|
|
2931
2681
|
*/
|
|
2932
2682
|
function getClaudeCodeExecutablePath() {
|
|
2933
|
-
const sdkPackagePath =
|
|
2683
|
+
const sdkPackagePath = createRequire(import.meta.url).resolve("@anthropic-ai/claude-agent-sdk");
|
|
2934
2684
|
return path.join(path.dirname(sdkPackagePath), "cli.js");
|
|
2935
2685
|
}
|
|
2936
2686
|
/** Region implied by the resolved gateway URL, for telemetry and display. */
|
|
@@ -3034,6 +2784,15 @@ function buildAgentEnv(wizardMetadata, wizardFlags, teamId) {
|
|
|
3034
2784
|
logToFile("ANTHROPIC_CUSTOM_HEADERS", encoded);
|
|
3035
2785
|
return encoded;
|
|
3036
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
|
+
}
|
|
3037
2796
|
/**
|
|
3038
2797
|
* Permission hook that allows only safe commands. Bash commands are gated by
|
|
3039
2798
|
* the exact per-manager fence in bash-fence.ts (install/build/typecheck/lint
|
|
@@ -3101,14 +2860,14 @@ function wizardCanUseTool(toolName, input, context = {}) {
|
|
|
3101
2860
|
const decision = evaluateBashCommand(command);
|
|
3102
2861
|
if (decision.allowed) {
|
|
3103
2862
|
logToFile(`Allowing bash command: ${command}`);
|
|
3104
|
-
|
|
2863
|
+
context.onDebug?.(`Allowing bash command: ${command}`);
|
|
3105
2864
|
return {
|
|
3106
2865
|
behavior: "allow",
|
|
3107
2866
|
updatedInput: input
|
|
3108
2867
|
};
|
|
3109
2868
|
}
|
|
3110
2869
|
logToFile(`Denying bash command (${decision.analyticsReason}): ${command}`);
|
|
3111
|
-
|
|
2870
|
+
context.onDebug?.(`Denying bash command (${decision.analyticsReason}): ${command}`);
|
|
3112
2871
|
analytics.wizardCapture("bash denied", {
|
|
3113
2872
|
reason: decision.analyticsReason,
|
|
3114
2873
|
command
|
|
@@ -3214,7 +2973,7 @@ async function initializeAgent(config, options) {
|
|
|
3214
2973
|
gatewayUrl,
|
|
3215
2974
|
apiKeyPresent: !!config.posthogApiKey
|
|
3216
2975
|
});
|
|
3217
|
-
|
|
2976
|
+
debugLine(emit, options, "Agent config:", {
|
|
3218
2977
|
workingDirectory: agentRunConfig.workingDirectory,
|
|
3219
2978
|
posthogMcpUrl: config.posthogMcpUrl,
|
|
3220
2979
|
gatewayUrl,
|
|
@@ -3229,7 +2988,7 @@ async function initializeAgent(config, options) {
|
|
|
3229
2988
|
message: `Failed to initialize agent: ${error.message}`
|
|
3230
2989
|
});
|
|
3231
2990
|
logToFile("Agent initialization error:", error);
|
|
3232
|
-
|
|
2991
|
+
debugLine(emit, options, "Agent initialization error:", error);
|
|
3233
2992
|
throw error;
|
|
3234
2993
|
}
|
|
3235
2994
|
}
|
|
@@ -3371,7 +3130,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3371
3130
|
}, timeoutMs) : void 0;
|
|
3372
3131
|
try {
|
|
3373
3132
|
const disallow = new Set(agentConfig.disallowedTools ?? []);
|
|
3374
|
-
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));
|
|
3375
3134
|
const inheritedMcpServerNames = Object.keys(agentConfig.mcpServers);
|
|
3376
3135
|
const triageProvider = agentConfig.triageProvider;
|
|
3377
3136
|
const onYaraTerminate = (reason) => {
|
|
@@ -3406,6 +3165,10 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3406
3165
|
disallowedTools: agentConfig.disallowedTools ? [...agentConfig.disallowedTools] : void 0
|
|
3407
3166
|
} },
|
|
3408
3167
|
settingSources: agentConfig.readOnly ? [] : ["project"],
|
|
3168
|
+
settings: {
|
|
3169
|
+
disableAllHooks: true,
|
|
3170
|
+
permissions: { deny: [...ENV_FILE_DENY_RULES] }
|
|
3171
|
+
},
|
|
3409
3172
|
skills: agentConfig.readOnly ? [] : "all",
|
|
3410
3173
|
allowedTools,
|
|
3411
3174
|
sandbox: {
|
|
@@ -3465,7 +3228,8 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3465
3228
|
const result = wizardCanUseTool(toolName, input, {
|
|
3466
3229
|
readOnly: agentConfig.readOnly,
|
|
3467
3230
|
wizardAskPending: agentConfig.getPendingQuestion?.() != null,
|
|
3468
|
-
disallowedTools: agentConfig.disallowedTools
|
|
3231
|
+
disallowedTools: agentConfig.disallowedTools,
|
|
3232
|
+
onDebug: (line) => debugLine(emit, options, line)
|
|
3469
3233
|
});
|
|
3470
3234
|
logToFile("canUseTool result:", result);
|
|
3471
3235
|
return Promise.resolve(result);
|
|
@@ -3485,7 +3249,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3485
3249
|
},
|
|
3486
3250
|
stderr: (data) => {
|
|
3487
3251
|
logToFile("CLI stderr:", data);
|
|
3488
|
-
|
|
3252
|
+
debugLine(emit, options, "CLI stderr:", data);
|
|
3489
3253
|
},
|
|
3490
3254
|
hooks: {
|
|
3491
3255
|
PreToolUse: warlockDisabled ? [] : createPreToolUseYaraHooks(triageProvider, onYaraTerminate),
|
|
@@ -3786,7 +3550,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
|
|
|
3786
3550
|
message: `Error: ${error.message}`
|
|
3787
3551
|
});
|
|
3788
3552
|
logToFile("Agent run failed:", error);
|
|
3789
|
-
|
|
3553
|
+
debugLine(emit, options, "Full error:", error);
|
|
3790
3554
|
throw error;
|
|
3791
3555
|
} finally {
|
|
3792
3556
|
agentConfig.signal?.removeEventListener("abort", onExternalAbort);
|
|
@@ -3839,12 +3603,17 @@ const READ_ONLY_TOOLS = [
|
|
|
3839
3603
|
"Glob",
|
|
3840
3604
|
"Grep"
|
|
3841
3605
|
];
|
|
3842
|
-
|
|
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([
|
|
3843
3610
|
"Read",
|
|
3844
3611
|
"Write",
|
|
3845
3612
|
"Edit",
|
|
3613
|
+
"Grep"
|
|
3614
|
+
]);
|
|
3615
|
+
const BASE_ALLOWED_TOOLS = [
|
|
3846
3616
|
"Glob",
|
|
3847
|
-
"Grep",
|
|
3848
3617
|
"Bash",
|
|
3849
3618
|
...Object.values(TaskTool),
|
|
3850
3619
|
"ListMcpResourcesTool",
|
|
@@ -3856,11 +3625,11 @@ function handleTaskCreate(block, store) {
|
|
|
3856
3625
|
if (!input?.subject) return;
|
|
3857
3626
|
let source = taskSources.get(store.tasks);
|
|
3858
3627
|
if (!source) {
|
|
3859
|
-
source = randomUUID
|
|
3628
|
+
source = randomUUID();
|
|
3860
3629
|
taskSources.set(store.tasks, source);
|
|
3861
3630
|
}
|
|
3862
3631
|
store.tasks.set(block.id, {
|
|
3863
|
-
id: randomUUID
|
|
3632
|
+
id: randomUUID(),
|
|
3864
3633
|
source,
|
|
3865
3634
|
content: input.subject,
|
|
3866
3635
|
status: "pending",
|
|
@@ -4012,7 +3781,7 @@ function handleSDKMessage(message, options, spinner, signals, emit, receivedSucc
|
|
|
4012
3781
|
});
|
|
4013
3782
|
};
|
|
4014
3783
|
logToFile(`SDK Message: ${message.type}`, JSON.stringify(message, null, 2));
|
|
4015
|
-
|
|
3784
|
+
debugLine(emit, options, `SDK Message type: ${message.type}`);
|
|
4016
3785
|
switch (message.type) {
|
|
4017
3786
|
case "assistant": {
|
|
4018
3787
|
const tokenUsageDelta = extractTokenUsageDelta(message);
|
|
@@ -4119,11 +3888,11 @@ function handleSDKMessage(message, options, spinner, signals, emit, receivedSucc
|
|
|
4119
3888
|
}
|
|
4120
3889
|
break;
|
|
4121
3890
|
default:
|
|
4122
|
-
|
|
3891
|
+
debugLine(emit, options, `Unhandled message type: ${message.type}`);
|
|
4123
3892
|
break;
|
|
4124
3893
|
}
|
|
4125
3894
|
}
|
|
4126
3895
|
//#endregion
|
|
4127
|
-
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 };
|
|
4128
3897
|
|
|
4129
|
-
//# sourceMappingURL=agent-interface-
|
|
3898
|
+
//# sourceMappingURL=agent-interface-CemBvTAA.js.map
|