@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.
Files changed (227) hide show
  1. package/README.md +187 -57
  2. package/dist/{PickerMenu-dG5DQCZA.js → PickerMenu-BGGeYqd-.js} +112 -12
  3. package/dist/PickerMenu-BGGeYqd-.js.map +1 -0
  4. package/dist/README.md +9 -6
  5. package/dist/{agent-interface-FkbaBJwz.js → agent-interface-CemBvTAA.js} +130 -324
  6. package/dist/agent-interface-CemBvTAA.js.map +1 -0
  7. package/dist/{agent-prompt-loader-D0weQ-7k.js → agent-prompt-loader-DPnj6SwU.js} +6 -5
  8. package/dist/agent-prompt-loader-DPnj6SwU.js.map +1 -0
  9. package/dist/analytics-B3ROGuIr.js +2 -0
  10. package/dist/analytics-D21z3E5l.js +732 -0
  11. package/dist/analytics-D21z3E5l.js.map +1 -0
  12. package/dist/{api-CrbCIQOz.js → api-DtGIqQ2U.js} +2 -3
  13. package/dist/api-DtGIqQ2U.js.map +1 -0
  14. package/dist/api-IhROOQNv.js +2 -0
  15. package/dist/api-key-login-OEntFvu5.js +2 -0
  16. package/dist/api-key-login-h3E2G3zu.js +55 -0
  17. package/dist/api-key-login-h3E2G3zu.js.map +1 -0
  18. package/dist/bin.js +2 -2
  19. package/dist/bin.js.map +1 -1
  20. package/dist/{bounded-fs-vAq-T-K7.js → bounded-fs-CAsuF6al.js} +3 -3
  21. package/dist/{bounded-fs-vAq-T-K7.js.map → bounded-fs-CAsuF6al.js.map} +1 -1
  22. package/dist/{ci-install-COcV8SY2.js → ci-install-CEYE02t-.js} +22 -26
  23. package/dist/ci-install-CEYE02t-.js.map +1 -0
  24. package/dist/console-log-O828zyiq.js +32 -0
  25. package/dist/console-log-O828zyiq.js.map +1 -0
  26. package/dist/{debug-kAHwWGg7.js → debug-BfQPD2Hg.js} +18 -52
  27. package/dist/debug-BfQPD2Hg.js.map +1 -0
  28. package/dist/{defaults-a9TelDhJ.js → defaults-DDVl3tKN.js} +2 -51
  29. package/dist/defaults-DDVl3tKN.js.map +1 -0
  30. package/dist/{emit-BSetXzDV.js → emit-RfAewcWv.js} +1 -1
  31. package/dist/{emit-BSetXzDV.js.map → emit-RfAewcWv.js.map} +1 -1
  32. package/dist/{errors-C2domSkK.js → errors-CHrJzAZb.js} +4 -4
  33. package/dist/{errors-C2domSkK.js.map → errors-CHrJzAZb.js.map} +1 -1
  34. package/dist/family-picker-BKs-tTyu.js +46 -0
  35. package/dist/family-picker-BKs-tTyu.js.map +1 -0
  36. package/dist/{gateway-C9-GlLO9.js → gateway-D3gIlR6b.js} +122 -11
  37. package/dist/gateway-D3gIlR6b.js.map +1 -0
  38. package/dist/headless-BJjhP0SI.js +10 -0
  39. package/dist/headless-BJjhP0SI.js.map +1 -0
  40. package/dist/headless-DIX68UUA.js +3 -0
  41. package/dist/host-resolution-D8GhEVoX.js +114 -0
  42. package/dist/host-resolution-D8GhEVoX.js.map +1 -0
  43. package/dist/install-Bw8tvDvS.js +2 -0
  44. package/dist/{add-mcp-server-to-clients-DIaTRWMY.js → install-paPCzPHI.js} +34 -100
  45. package/dist/install-paPCzPHI.js.map +1 -0
  46. package/dist/interactive-tdxZKWax.js +11 -0
  47. package/dist/interactive-tdxZKWax.js.map +1 -0
  48. package/dist/{telemetry-B7zJdRmA.js → links-Cyj6v8kg.js} +4 -13
  49. package/dist/links-Cyj6v8kg.js.map +1 -0
  50. package/dist/{main-CgKxbwMP.js → main-0p-YxUNa.js} +233 -490
  51. package/dist/main-0p-YxUNa.js.map +1 -0
  52. package/dist/{mcp-DnAyW0-w.js → mcp-D3Z5MXhA.js} +3 -4
  53. package/dist/{mcp-DnAyW0-w.js.map → mcp-D3Z5MXhA.js.map} +1 -1
  54. package/dist/mcp-install-smoke-test.ts +2 -2
  55. package/dist/{mcp-prompt-streaming-DDWQ-FCA.js → mcp-prompt-streaming-COVbWnHt.js} +12 -12
  56. package/dist/mcp-prompt-streaming-COVbWnHt.js.map +1 -0
  57. package/dist/mode-label-DB3ol_sj.js +9 -0
  58. package/dist/mode-label-DB3ol_sj.js.map +1 -0
  59. package/dist/{models-WcwUnSKb.js → models-D1SnCzvl.js} +2 -2
  60. package/dist/{models-WcwUnSKb.js.map → models-D1SnCzvl.js.map} +1 -1
  61. package/dist/non-interactive-DxRBc73O.js +18 -0
  62. package/dist/non-interactive-DxRBc73O.js.map +1 -0
  63. package/dist/{oauth-session-DYM2Hrl2.js → oauth-session-Dde79Ycm.js} +3 -3
  64. package/dist/{oauth-session-DYM2Hrl2.js.map → oauth-session-Dde79Ycm.js.map} +1 -1
  65. package/dist/{orchestrator-tools-DbgNBFGA.js → orchestrator-tools-BSNhzzkT.js} +3 -3
  66. package/dist/{orchestrator-tools-DbgNBFGA.js.map → orchestrator-tools-BSNhzzkT.js.map} +1 -1
  67. package/dist/{package-json-Atg34fa4.js → package-json-2UrhE6kP.js} +1 -1
  68. package/dist/{package-json-Atg34fa4.js.map → package-json-2UrhE6kP.js.map} +1 -1
  69. package/dist/package-json-Dblip2_X.js +2 -0
  70. package/dist/package-manager-BRXlXo0p.js +105 -0
  71. package/dist/package-manager-BRXlXo0p.js.map +1 -0
  72. package/dist/{pi-8KsYsPmM.js → pi-cM_4Gd_9.js} +19 -20
  73. package/dist/pi-cM_4Gd_9.js.map +1 -0
  74. package/dist/playground-DTKy0XHT.js +12 -0
  75. package/dist/playground-DTKy0XHT.js.map +1 -0
  76. package/dist/posthog-integration-bwHwE87a.js +10291 -0
  77. package/dist/posthog-integration-bwHwE87a.js.map +1 -0
  78. package/dist/programs-BhtyA3lE.js +3 -0
  79. package/dist/programs-SeT1qNik.js +5348 -0
  80. package/dist/programs-SeT1qNik.js.map +1 -0
  81. package/dist/provisioning-BcXfeCMc.js +2 -0
  82. package/dist/{provisioning-Bo2NRxFz.js → provisioning-JbJtq7hq.js} +5 -67
  83. package/dist/provisioning-JbJtq7hq.js.map +1 -0
  84. package/dist/{queue-tools-C8mXOh7e.js → queue-tools-BIZSJyt6.js} +7 -9
  85. package/dist/queue-tools-BIZSJyt6.js.map +1 -0
  86. package/dist/results-DtKICAdz.js +55 -0
  87. package/dist/results-DtKICAdz.js.map +1 -0
  88. package/dist/run-CDurA5tO.js +248 -0
  89. package/dist/run-CDurA5tO.js.map +1 -0
  90. package/dist/run-DDCvLILJ.js +246 -0
  91. package/dist/run-DDCvLILJ.js.map +1 -0
  92. package/dist/run-tool-CTq9OOdT.js +2 -0
  93. package/dist/run-tool-DML8JJvt.js +2420 -0
  94. package/dist/run-tool-DML8JJvt.js.map +1 -0
  95. package/dist/runners-Dhu4pZTN.js +253 -0
  96. package/dist/runners-Dhu4pZTN.js.map +1 -0
  97. package/dist/{security-C71pkwqH.js → security-DEH8Rn0_.js} +5 -5
  98. package/dist/security-DEH8Rn0_.js.map +1 -0
  99. package/dist/setup-utils-C5-WM-hS.js +118 -0
  100. package/dist/setup-utils-C5-WM-hS.js.map +1 -0
  101. package/dist/smoke-test.sh +1 -1
  102. package/dist/{playground-BlYRBMj7.js → start-playground-DL4mVEUx.js} +63 -54
  103. package/dist/start-playground-DL4mVEUx.js.map +1 -0
  104. package/dist/{subagent-D1TrTchE.js → subagent-CnFvAq6E.js} +3 -3
  105. package/dist/{subagent-D1TrTchE.js.map → subagent-CnFvAq6E.js.map} +1 -1
  106. package/dist/{task-DqRlQBfs.js → task-BOScSm4W.js} +17 -18
  107. package/dist/task-BOScSm4W.js.map +1 -0
  108. package/dist/{tasks-ChWufsdO.js → tasks-BfJhVky2.js} +1 -1
  109. package/dist/tasks-BfJhVky2.js.map +1 -0
  110. package/dist/telemetry-CP4rGicd.js +13 -0
  111. package/dist/telemetry-CP4rGicd.js.map +1 -0
  112. package/dist/terminal-J3OD3dN0.js +16162 -0
  113. package/dist/terminal-J3OD3dN0.js.map +1 -0
  114. package/dist/tools-CCMV3DmB.js +544 -0
  115. package/dist/tools-CCMV3DmB.js.map +1 -0
  116. package/dist/{tools-CkJ2y9Wt.js → tools-Cz8tDptL.js} +9 -9
  117. package/dist/tools-Cz8tDptL.js.map +1 -0
  118. package/dist/tui-BUZ2PWqN.js +2 -0
  119. package/dist/tui-Csf7VJxt.js +25 -0
  120. package/dist/tui-Csf7VJxt.js.map +1 -0
  121. package/dist/{steps-BPcg3_3Q.js → upload-step-CEacB2RV.js} +17 -19
  122. package/dist/upload-step-CEacB2RV.js.map +1 -0
  123. package/dist/urls-BDELGZHq.js +67 -0
  124. package/dist/urls-BDELGZHq.js.map +1 -0
  125. package/dist/warlock-smoke-test.ts +1 -2
  126. package/dist/{wizard-abort-BPdv07np.js → wizard-abort-D3-75KyV.js} +41 -32
  127. package/dist/wizard-abort-D3-75KyV.js.map +1 -0
  128. package/dist/yara-hooks-CZ1tKxy_.js +2 -0
  129. package/dist/{yara-hooks-BnxejtXK.js → yara-hooks-D8YDyX7o.js} +283 -21
  130. package/dist/yara-hooks-D8YDyX7o.js.map +1 -0
  131. package/package.json +7 -8
  132. package/dist/PickerMenu-dG5DQCZA.js.map +0 -1
  133. package/dist/add-mcp-server-to-clients-DIaTRWMY.js.map +0 -1
  134. package/dist/add-mcp-server-to-clients-artmN7mz.js +0 -2
  135. package/dist/agent-BEjARD2a.js +0 -6
  136. package/dist/agent-BWFhuLgo.js +0 -3178
  137. package/dist/agent-BWFhuLgo.js.map +0 -1
  138. package/dist/agent-interface-FkbaBJwz.js.map +0 -1
  139. package/dist/agent-prompt-loader-D0weQ-7k.js.map +0 -1
  140. package/dist/analytics-DFtbRjYh.js +0 -2
  141. package/dist/analytics-DXK1gc12.js +0 -301
  142. package/dist/analytics-DXK1gc12.js.map +0 -1
  143. package/dist/api-Cm9UtKZh.js +0 -2
  144. package/dist/api-CrbCIQOz.js.map +0 -1
  145. package/dist/check-screens.tsx +0 -190
  146. package/dist/ci-install-COcV8SY2.js.map +0 -1
  147. package/dist/constants-DHCBSfnx.js +0 -260
  148. package/dist/constants-DHCBSfnx.js.map +0 -1
  149. package/dist/debug-BuYHGr6_.js +0 -2
  150. package/dist/debug-kAHwWGg7.js.map +0 -1
  151. package/dist/defaults-a9TelDhJ.js.map +0 -1
  152. package/dist/endpoints-BVMYm9F4.js +0 -108
  153. package/dist/endpoints-BVMYm9F4.js.map +0 -1
  154. package/dist/env-api-key-BP-NFFXt.js +0 -17
  155. package/dist/env-api-key-BP-NFFXt.js.map +0 -1
  156. package/dist/env-api-key-CaWEDj_9.js +0 -2
  157. package/dist/environment-BATlQxcQ.js +0 -39
  158. package/dist/environment-BATlQxcQ.js.map +0 -1
  159. package/dist/environment-CwD8OPYj.js +0 -2
  160. package/dist/file-C5JMsyR1.js +0 -2
  161. package/dist/file-DcRKycV8.js +0 -60
  162. package/dist/file-DcRKycV8.js.map +0 -1
  163. package/dist/file-watcher-Brq2nnHV.js +0 -123
  164. package/dist/file-watcher-Brq2nnHV.js.map +0 -1
  165. package/dist/gateway-C9-GlLO9.js.map +0 -1
  166. package/dist/headless-ui-CqI2gXlD.js +0 -44
  167. package/dist/headless-ui-CqI2gXlD.js.map +0 -1
  168. package/dist/interactive-B_Ti_CsS.js +0 -11
  169. package/dist/interactive-B_Ti_CsS.js.map +0 -1
  170. package/dist/local-dev-McsurOC-.js +0 -135
  171. package/dist/local-dev-McsurOC-.js.map +0 -1
  172. package/dist/logging-ui-Dza4D0MK.js +0 -226
  173. package/dist/logging-ui-Dza4D0MK.js.map +0 -1
  174. package/dist/main-CgKxbwMP.js.map +0 -1
  175. package/dist/mcp-prompt-streaming-DDWQ-FCA.js.map +0 -1
  176. package/dist/mint-failure-u8xQKNOn.js +0 -6392
  177. package/dist/mint-failure-u8xQKNOn.js.map +0 -1
  178. package/dist/non-interactive-DyVC1AGc.js +0 -18
  179. package/dist/non-interactive-DyVC1AGc.js.map +0 -1
  180. package/dist/package-json-D8Ga03tK.js +0 -2
  181. package/dist/pi-8KsYsPmM.js.map +0 -1
  182. package/dist/playground-BlYRBMj7.js.map +0 -1
  183. package/dist/posthog-Bt0Aplb8.js +0 -124
  184. package/dist/posthog-Bt0Aplb8.js.map +0 -1
  185. package/dist/posthog-CUgCEhH0.js +0 -2
  186. package/dist/provisioning-Bo2NRxFz.js.map +0 -1
  187. package/dist/provisioning-OGFGlzf7.js +0 -2
  188. package/dist/queue-tools-C8mXOh7e.js.map +0 -1
  189. package/dist/registry-C06e_x-p.js +0 -2
  190. package/dist/registry-CD5RQt38.js +0 -3464
  191. package/dist/registry-CD5RQt38.js.map +0 -1
  192. package/dist/run-agent-legacy-ChacZImU.js +0 -2
  193. package/dist/run-agent-legacy-DOlM6DQu.js +0 -3540
  194. package/dist/run-agent-legacy-DOlM6DQu.js.map +0 -1
  195. package/dist/runners-ov3EXF1n.js +0 -834
  196. package/dist/runners-ov3EXF1n.js.map +0 -1
  197. package/dist/security-C71pkwqH.js.map +0 -1
  198. package/dist/setup-utils-B26Lf2yF.js +0 -1512
  199. package/dist/setup-utils-B26Lf2yF.js.map +0 -1
  200. package/dist/setup-utils-CVS86NYR.js +0 -2
  201. package/dist/start-tui-Bo2L0bar.js +0 -6962
  202. package/dist/start-tui-Bo2L0bar.js.map +0 -1
  203. package/dist/steps-BPcg3_3Q.js.map +0 -1
  204. package/dist/store-BTzcvRGT.js +0 -992
  205. package/dist/store-BTzcvRGT.js.map +0 -1
  206. package/dist/store-BpqySPXm.js +0 -5
  207. package/dist/task-DqRlQBfs.js.map +0 -1
  208. package/dist/task-stream-Bw6JaLCX.js +0 -363
  209. package/dist/task-stream-Bw6JaLCX.js.map +0 -1
  210. package/dist/tasks-ChWufsdO.js.map +0 -1
  211. package/dist/telemetry-B7zJdRmA.js.map +0 -1
  212. package/dist/terminal-zgkEfoCL.js +0 -7196
  213. package/dist/terminal-zgkEfoCL.js.map +0 -1
  214. package/dist/tools-CkJ2y9Wt.js.map +0 -1
  215. package/dist/ui-Q6-RvERF.js +0 -15
  216. package/dist/ui-Q6-RvERF.js.map +0 -1
  217. package/dist/version-CHhJjz_H.js +0 -6
  218. package/dist/version-CHhJjz_H.js.map +0 -1
  219. package/dist/wizard-abort-BPdv07np.js.map +0 -1
  220. package/dist/wizard-abort-Br1qMDNa.js +0 -3
  221. package/dist/wizard-session-2w4Ru-Wz.js +0 -131
  222. package/dist/wizard-session-2w4Ru-Wz.js.map +0 -1
  223. package/dist/wizard-session-DGaUHOF3.js +0 -2
  224. package/dist/wizard-ui-DVqrYaOM.js +0 -16
  225. package/dist/wizard-ui-DVqrYaOM.js.map +0 -1
  226. package/dist/yara-hooks-BnxejtXK.js.map +0 -1
  227. package/dist/yara-hooks-DSuExwb4.js +0 -2
@@ -1,13 +1,11 @@
1
- import { a as getLogFilePath, o as initLogFile, r as debug, s as logToFile, v as runtimeEnv } from "./debug-kAHwWGg7.js";
2
- import { Y as WIZARD_REMARK_EVENT_NAME, c as CONTEXT_MILL_URL, et as wizardUserAgentForProgram, o as AWS_SKILLS_BASE_URL } from "./constants-DHCBSfnx.js";
3
- import { n as analytics } from "./analytics-DXK1gc12.js";
4
- import { i as classifyAuthFailure } from "./errors-C2domSkK.js";
5
- import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-vAq-T-K7.js";
6
- import { t as registerCleanup } from "./wizard-abort-BPdv07np.js";
7
- import { c as REMARK_INSTRUCTION, f as gatewayAuth, i as gatewayApiFor, l as RESUME_INSTRUCTION, n as buildGatewayModel, p as isPastRefresh, s as AgentSignals, u as buildWizardPropertiesBlob } from "./gateway-C9-GlLO9.js";
8
- import { i as modelCapabilities, o as triageModelFor } from "./models-WcwUnSKb.js";
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 { unzipSync } from "fflate";
23
- //#region \0rolldown/runtime.js
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 /^\.env\.(example|sample|template|dist)$/.test(name);
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/agent/wizard-ask-bridge.ts
718
+ //#region src/shared/ask-policy.ts
718
719
  /**
719
- * WizardAskBridge — host-side promise broker for the `wizard_ask` MCP tool.
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
- * The `wizard_ask` tool needs to (a) read information from the wizard
722
- * session (the active skill id, used as the analytics `source`) and
723
- * (b) drive the TUI overlay. Wiring `wizard-tools.ts` directly to either
724
- * would couple our pure-data MCP server to the runtime UI layer.
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
- * The bridge is the seam: `wizard-tools.ts` depends on this interface,
727
- * and `agent-runner.ts` constructs an implementation that knows about
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
- /** Sentinel returned for unanswered fields on cancellation or timeout. */
731
- const CANCELLED_SENTINEL = "__cancelled__";
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
- timer = setTimeout(() => {
777
- timedOut = true;
778
- resolve(buildCancelledAnswers(questions));
779
- controller.abort();
780
- }, timeoutMs);
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, { signal: controller.signal }),
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, { triage: triageProvider });
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 or call `wizard_ask` again for the same fields."
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 bin.ts can run orphan recovery at
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 bin.ts, before anything reads Claude settings —
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 = (typeof __require !== "undefined" ? __require : createRequire(process.argv[1] ?? `${process.cwd()}/`)).resolve("@anthropic-ai/claude-agent-sdk");
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
- debug(`Allowing bash command: ${command}`);
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
- debug(`Denying bash command (${decision.analyticsReason}): ${command}`);
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
- if (options.debug) debug("Agent config:", {
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
- debug("Agent initialization error:", error);
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
- if (options.debug) debug("CLI stderr:", data);
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
- debug("Full error:", error);
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
- const BASE_ALLOWED_TOOLS = [
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
- if (options.debug) debug(`SDK Message type: ${message.type}`);
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
- if (options.debug) debug(`Unhandled message type: ${message.type}`);
3891
+ debugLine(emit, options, `Unhandled message type: ${message.type}`);
4086
3892
  break;
4087
3893
  }
4088
3894
  }
4089
3895
  //#endregion
4090
- export { vaultSensitiveAnswers as $, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as A, describeAskCancellation as B, AUDIT_ADD_CHECKS_PARAM_DESCRIPTION as C, AUDIT_SEED_CHECKS_PARAM_DESCRIPTION as D, AUDIT_SEED_CHECKS_DESCRIPTION as E, WIZARD_ASK_TOOL_DESCRIPTION as F, mergeEnvValues as G, ensureGitignoreCoverage as H, WIZARD_TOOL_NAMES as I, resolveAuditChecks as J, normaliseAskSubject as K, addAuditChecks as L, WIZARD_ASK_KIND_DESCRIPTION as M, WIZARD_ASK_SENSITIVE_DESCRIPTION as N, AUDIT_STATUSES as O, WIZARD_ASK_SUBJECT_DESCRIPTION as P, templateEnvWriteRefusal as Q, checkEnvKeys as R, AUDIT_ADD_CHECKS_DESCRIPTION as S, AUDIT_RESOLVE_CHECKS_PARAM_DESCRIPTION as T, installSkillById as U, downloadSkill as V, legacyKeyNameRefusal as W, resolveEnvSecretRefs as X, resolveEnvPath as Y, seedAuditChecks as Z, createSecretVault as _, wizardCanUseTool as a, MAX_ENV_KEY_SET as at, PUBLISH_HANDOFF_TOOL_NAME as b, checkAllSettingsConflicts as c, toPromptSafeRelativePath as ct, restoreClaudeSettings as d, fetchSkillMenu as et, sanitizeAgentSubprocessEnv as f, assembleCommandments as g, markGrantRevoked as h, runAgent as i, isFullyCancelled as it, ENV_FILE_PATH_DESCRIPTION as j, CHECK_ENV_KEYS_DESCRIPTION as k, classifySettingsConflicts as l, createTriageLLMProvider as lt, isGrantRevoked as m, buildRunTags as n, LONGER_ASK_TIMEOUT_MS as nt, createIsolatedAgentConfigDir as o, isEnvFileName as ot, AgentOutputSignals as p, resolveAskQuestionKinds as q, initializeAgent as r, createWizardAskBridge as rt, backupAndFixClaudeSettings as s, parseEnvKeyNames as st, buildAgentEnv as t, fetchWithRetry as tt, recoverOrphanedSettingsBackups as u, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as v, AUDIT_RESOLVE_CHECKS_DESCRIPTION as w, publishHandoff as x, PUBLISH_HANDOFF_DESCRIPTION as y, createAskAccounting as z };
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-FkbaBJwz.js.map
3898
+ //# sourceMappingURL=agent-interface-CemBvTAA.js.map