@posthog/wizard 2.66.0 → 2.68.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/dist/{add-mcp-server-to-clients-DWDEuDUR.js → add-mcp-server-to-clients-y0swAr9I.js} +25 -25
  2. package/dist/{add-mcp-server-to-clients-DWDEuDUR.js.map → add-mcp-server-to-clients-y0swAr9I.js.map} +1 -1
  3. package/dist/{agent-interface-D3MNaDp3.js → agent-interface-CaEptZuu.js} +404 -73
  4. package/dist/agent-interface-CaEptZuu.js.map +1 -0
  5. package/dist/{agent-prompt-loader-D8Bajo-L.js → agent-prompt-loader-DZHc9tIG.js} +5 -5
  6. package/dist/{agent-prompt-loader-D8Bajo-L.js.map → agent-prompt-loader-DZHc9tIG.js.map} +1 -1
  7. package/dist/{agent-runner-DEeMqJxy.js → agent-runner-Do5kyhPo.js} +85 -39
  8. package/dist/agent-runner-Do5kyhPo.js.map +1 -0
  9. package/dist/analytics-BNCWoTKa.js +2 -0
  10. package/dist/{analytics-D8JNuPAT.js → analytics-tF06lcmE.js} +2 -2
  11. package/dist/{analytics-D8JNuPAT.js.map → analytics-tF06lcmE.js.map} +1 -1
  12. package/dist/{api-CemGgyBv.js → api-D7-8R4xx.js} +3 -3
  13. package/dist/{api-CemGgyBv.js.map → api-D7-8R4xx.js.map} +1 -1
  14. package/dist/bin.js +200 -85
  15. package/dist/bin.js.map +1 -1
  16. package/dist/{bounded-fs-C6OjqZst.js → bounded-fs-BwuqKpBH.js} +3 -3
  17. package/dist/{bounded-fs-C6OjqZst.js.map → bounded-fs-BwuqKpBH.js.map} +1 -1
  18. package/dist/{ci-install-DIB2n4Ju.js → ci-install-CrqqhXAw.js} +18 -9
  19. package/dist/ci-install-CrqqhXAw.js.map +1 -0
  20. package/dist/{debug-H-GTKvvU.js → debug-CWn7PsPd.js} +1 -1
  21. package/dist/{debug-BKqv-yfT.js → debug-aA5dm2MR.js} +4 -4
  22. package/dist/debug-aA5dm2MR.js.map +1 -0
  23. package/dist/{defaults-BHhXrX9F.js → defaults-DI642M3n.js} +1 -1
  24. package/dist/{defaults-BHhXrX9F.js.map → defaults-DI642M3n.js.map} +1 -1
  25. package/dist/{env-api-key-CzHDwfV2.js → env-api-key-CwkRyrgi.js} +2 -2
  26. package/dist/{env-api-key-CzHDwfV2.js.map → env-api-key-CwkRyrgi.js.map} +1 -1
  27. package/dist/environment-BGUJxuvj.js +44 -0
  28. package/dist/environment-BGUJxuvj.js.map +1 -0
  29. package/dist/errors-BHervYGs.js +156 -0
  30. package/dist/errors-BHervYGs.js.map +1 -0
  31. package/dist/{file-watcher-Cr-4tA-e.js → file-watcher-Cn7tD95m.js} +2 -2
  32. package/dist/{file-watcher-Cr-4tA-e.js.map → file-watcher-Cn7tD95m.js.map} +1 -1
  33. package/dist/{headless-ui-DT3Db1bk.js → headless-ui-DtIYZNVv.js} +2 -2
  34. package/dist/{headless-ui-DT3Db1bk.js.map → headless-ui-DtIYZNVv.js.map} +1 -1
  35. package/dist/{interactive-D3LdFxZG.js → interactive-BRB6w6KG.js} +2 -2
  36. package/dist/{interactive-D3LdFxZG.js.map → interactive-BRB6w6KG.js.map} +1 -1
  37. package/dist/{local-dev-BN6NKQ0B.js → local-dev-DPZiIPCK.js} +1 -1
  38. package/dist/{local-dev-BN6NKQ0B.js.map → local-dev-DPZiIPCK.js.map} +1 -1
  39. package/dist/{mcp-BjckYQmP.js → mcp-BXdSTZe6.js} +2 -2
  40. package/dist/{mcp-BjckYQmP.js.map → mcp-BXdSTZe6.js.map} +1 -1
  41. package/dist/{mcp-prompt-streaming--sRErHKv.js → mcp-prompt-streaming-DhOT15Jj.js} +13 -12
  42. package/dist/mcp-prompt-streaming-DhOT15Jj.js.map +1 -0
  43. package/dist/{non-interactive-CNoYoEZp.js → non-interactive-ezilF3PY.js} +7 -2
  44. package/dist/non-interactive-ezilF3PY.js.map +1 -0
  45. package/dist/{orchestrator-tools-8bGyDDhn.js → orchestrator-tools-D82843t_.js} +3 -3
  46. package/dist/{orchestrator-tools-8bGyDDhn.js.map → orchestrator-tools-D82843t_.js.map} +1 -1
  47. package/dist/{package-json-D0DCWpe5.js → package-json-GEU2VZlS.js} +1 -1
  48. package/dist/{package-json-D0DCWpe5.js.map → package-json-GEU2VZlS.js.map} +1 -1
  49. package/dist/{package-manager-BQDHm7ER.js → package-manager-BPoVLj7W.js} +4 -4
  50. package/dist/package-manager-BPoVLj7W.js.map +1 -0
  51. package/dist/{pi-W-4RUPFY.js → pi-CKyt4bcu.js} +17 -13
  52. package/dist/pi-CKyt4bcu.js.map +1 -0
  53. package/dist/{playground-uHHgZChe.js → playground-Dnyb4jLu.js} +7 -7
  54. package/dist/{playground-uHHgZChe.js.map → playground-Dnyb4jLu.js.map} +1 -1
  55. package/dist/{posthog-ChzdlmCs.js → posthog-BHyJiU05.js} +2 -2
  56. package/dist/{posthog-ChzdlmCs.js.map → posthog-BHyJiU05.js.map} +1 -1
  57. package/dist/{posthog-integration-LxEBGkoe.js → posthog-integration-DJX4qTDQ.js} +22 -17
  58. package/dist/posthog-integration-DJX4qTDQ.js.map +1 -0
  59. package/dist/{provisioning-BHTl91OZ.js → provisioning-DEEt9xl4.js} +3 -3
  60. package/dist/{provisioning-BHTl91OZ.js.map → provisioning-DEEt9xl4.js.map} +1 -1
  61. package/dist/{queue-tools-DABh1Ssc.js → queue-tools-i_TmeI02.js} +3 -3
  62. package/dist/{queue-tools-DABh1Ssc.js.map → queue-tools-i_TmeI02.js.map} +1 -1
  63. package/dist/{registry-CxNpCNAj.js → registry-CbXqxcX0.js} +81 -81
  64. package/dist/{registry-CxNpCNAj.js.map → registry-CbXqxcX0.js.map} +1 -1
  65. package/dist/{security-B4jU_-7q.js → security-DZ1rkONB.js} +21 -9
  66. package/dist/security-DZ1rkONB.js.map +1 -0
  67. package/dist/{setup-utils-aWZEdfwh.js → setup-utils-BLKhAx6g.js} +13 -13
  68. package/dist/{setup-utils-aWZEdfwh.js.map → setup-utils-BLKhAx6g.js.map} +1 -1
  69. package/dist/{start-tui-BQH4mQIZ.js → start-tui-D1MqJVT1.js} +33 -23
  70. package/dist/start-tui-D1MqJVT1.js.map +1 -0
  71. package/dist/{steps-5HAqjUvn.js → steps-Dsw-zBET.js} +7 -7
  72. package/dist/{steps-5HAqjUvn.js.map → steps-Dsw-zBET.js.map} +1 -1
  73. package/dist/{store-P_7zUfbj.js → store-OGBMWp3H.js} +5 -5
  74. package/dist/{store-P_7zUfbj.js.map → store-OGBMWp3H.js.map} +1 -1
  75. package/dist/{subagent-uGPDXPfS.js → subagent-DrnKYgvu.js} +2 -2
  76. package/dist/{subagent-uGPDXPfS.js.map → subagent-DrnKYgvu.js.map} +1 -1
  77. package/dist/{task-oh8OAnvR.js → task-DyvLyDsO.js} +18 -14
  78. package/dist/task-DyvLyDsO.js.map +1 -0
  79. package/dist/{task-stream-jUARpyB5.js → task-stream-CLXzeuPO.js} +16 -9
  80. package/dist/task-stream-CLXzeuPO.js.map +1 -0
  81. package/dist/{tasks-2mu3lAvm.js → tasks-D77GNdOU.js} +2 -2
  82. package/dist/{tasks-2mu3lAvm.js.map → tasks-D77GNdOU.js.map} +1 -1
  83. package/dist/{telemetry-BllPiBKw.js → telemetry-wp-z9LXH.js} +3 -3
  84. package/dist/{telemetry-BllPiBKw.js.map → telemetry-wp-z9LXH.js.map} +1 -1
  85. package/dist/{terminal-aWQrDy8s.js → terminal-D9j4wbpD.js} +13 -13
  86. package/dist/{terminal-aWQrDy8s.js.map → terminal-D9j4wbpD.js.map} +1 -1
  87. package/dist/{tools-u8TaJFqa.js → tools-D0r4e-Vu.js} +10 -7
  88. package/dist/tools-D0r4e-Vu.js.map +1 -0
  89. package/dist/wizard-abort-Bv87YVSp.js +71 -0
  90. package/dist/wizard-abort-Bv87YVSp.js.map +1 -0
  91. package/dist/{wizard-abort-pFFH7dcx.js → wizard-abort-oazJA1Jb.js} +1 -1
  92. package/dist/{wizard-session-DTyLMPsX.js → wizard-session-C_7r3-rO.js} +3 -2
  93. package/dist/wizard-session-C_7r3-rO.js.map +1 -0
  94. package/dist/{wizard-session-Cw7-_OcZ.js → wizard-session-D1KQqUml.js} +1 -1
  95. package/dist/yara-hooks-Bl-FeANN.js +2 -0
  96. package/dist/{yara-hooks-BXDBIOBq.js → yara-hooks-DeonKbE_.js} +57 -8
  97. package/dist/yara-hooks-DeonKbE_.js.map +1 -0
  98. package/package.json +1 -1
  99. package/dist/agent-interface-D3MNaDp3.js.map +0 -1
  100. package/dist/agent-runner-DEeMqJxy.js.map +0 -1
  101. package/dist/analytics-DN3Kzf7H.js +0 -2
  102. package/dist/ci-install-DIB2n4Ju.js.map +0 -1
  103. package/dist/debug-BKqv-yfT.js.map +0 -1
  104. package/dist/environment-Cl-fIQku.js +0 -22
  105. package/dist/environment-Cl-fIQku.js.map +0 -1
  106. package/dist/mcp-prompt-streaming--sRErHKv.js.map +0 -1
  107. package/dist/non-interactive-CNoYoEZp.js.map +0 -1
  108. package/dist/package-manager-BQDHm7ER.js.map +0 -1
  109. package/dist/pi-W-4RUPFY.js.map +0 -1
  110. package/dist/posthog-integration-LxEBGkoe.js.map +0 -1
  111. package/dist/security-B4jU_-7q.js.map +0 -1
  112. package/dist/start-tui-BQH4mQIZ.js.map +0 -1
  113. package/dist/task-oh8OAnvR.js.map +0 -1
  114. package/dist/task-stream-jUARpyB5.js.map +0 -1
  115. package/dist/tools-u8TaJFqa.js.map +0 -1
  116. package/dist/wizard-abort-D9jiMkZA.js +0 -49
  117. package/dist/wizard-abort-D9jiMkZA.js.map +0 -1
  118. package/dist/wizard-session-DTyLMPsX.js.map +0 -1
  119. package/dist/yara-hooks-BXDBIOBq.js.map +0 -1
  120. package/dist/yara-hooks-i2jOabhI.js +0 -2
@@ -1,20 +1,243 @@
1
1
  import { n as __require } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { G as POSTHOG_FLAG_HEADER_PREFIX, J as POSTHOG_PROPERTY_HEADER_PREFIX, a as getLogFilePath, dt as WIZARD_REMARK_EVENT_NAME, f as getUI, ht as wizardUserAgentForProgram, o as initLogFile, r as debug, s as logToFile, xt as runtimeEnv } from "./debug-BKqv-yfT.js";
3
- import { n as analytics } from "./analytics-D8JNuPAT.js";
4
- import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-C6OjqZst.js";
5
- import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-DTyLMPsX.js";
6
- import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-D9jiMkZA.js";
7
- import { _ as modelCapabilities, m as writeJsonAtomic, o as buildOrchestratorTools, p as makeMutex, y as triageModelFor } from "./queue-tools-DABh1Ssc.js";
8
- import { b as coerceAuditChecks, g as AUDIT_CHECKS_FILE, l as prewarmYaraScanner, n as createPostToolUseYaraHooks, p as scanInstalledSkill, r as createPreToolUseYaraHooks } from "./yara-hooks-BXDBIOBq.js";
2
+ import { a as AgentSignals, o as REMARK_INSTRUCTION, s as classifyAuthFailure } from "./errors-BHervYGs.js";
3
+ import { G as POSTHOG_FLAG_HEADER_PREFIX, J as POSTHOG_PROPERTY_HEADER_PREFIX, a as getLogFilePath, dt as WIZARD_REMARK_EVENT_NAME, f as getUI, ht as wizardUserAgentForProgram, o as initLogFile, r as debug, s as logToFile, xt as runtimeEnv } from "./debug-aA5dm2MR.js";
4
+ import { n as analytics } from "./analytics-tF06lcmE.js";
5
+ import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-BwuqKpBH.js";
6
+ import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-C_7r3-rO.js";
7
+ import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-Bv87YVSp.js";
8
+ import { _ as modelCapabilities, m as writeJsonAtomic, o as buildOrchestratorTools, p as makeMutex, y as triageModelFor } from "./queue-tools-i_TmeI02.js";
9
+ import { b as coerceAuditChecks, g as AUDIT_CHECKS_FILE, l as prewarmYaraScanner, n as createPostToolUseYaraHooks, p as scanInstalledSkill, r as createPreToolUseYaraHooks } from "./yara-hooks-DeonKbE_.js";
9
10
  import { createRequire } from "node:module";
10
11
  import * as fs$1 from "fs";
11
12
  import fs from "fs";
12
13
  import path from "path";
14
+ import path$1 from "node:path";
13
15
  import { spawnSync } from "node:child_process";
16
+ import { closeSync, constants, fchmodSync, lstatSync, openSync, renameSync, unlinkSync, writeSync } from "node:fs";
17
+ import { randomBytes } from "node:crypto";
14
18
  import { z } from "zod";
15
19
  import * as os from "os";
16
20
  import { unzipSync } from "fflate";
17
21
  import { randomUUID } from "crypto";
22
+ //#region src/lib/gateway-session.ts
23
+ /**
24
+ * Gateway auth for a wizard run: a `phe_` scoped token the backend mints, with
25
+ * pinned attribution, a spend cap and an expiry.
26
+ *
27
+ * A 404 resolves to the legacy posture (OAuth token, Python gateway); every
28
+ * other failure throws, because the legacy path enforces none of those, so a
29
+ * silent downgrade spends unattributed money to hide an outage.
30
+ */
31
+ let cached = null;
32
+ /**
33
+ * Shared so concurrent callers mint once. The orchestrator starts every runnable
34
+ * task at once, and each would otherwise take its own token and its own cap.
35
+ */
36
+ let inFlight = null;
37
+ /**
38
+ * Adoption floor. The anthropic subprocess holds its credential for the whole
39
+ * session, so a token below this 401s mid-run.
40
+ */
41
+ const MIN_USABLE_TTL_MS = 120 * 1e3;
42
+ /** Re-resolve at this fraction of the token's life, leaving a usable remainder. */
43
+ const REFRESH_AT_FRACTION = .8;
44
+ /** How long a legacy fallback sticks before the mint endpoint is retried. */
45
+ const LEGACY_RETRY_MS = 600 * 1e3;
46
+ const MINT_TIMEOUT_MS = 2e4;
47
+ /** Resolve this run's gateway auth, minting and re-minting near expiry. */
48
+ async function gatewayAuth(host, accessToken, program) {
49
+ const key = `${host.apiHost}\n${accessToken}\n${program ?? ""}`;
50
+ if (cached && cached.key === key && Date.now() < cached.staleAtMs) return cached.auth;
51
+ if (inFlight && inFlight.key === key) return inFlight.promise;
52
+ const promise = resolveGatewayAuth(host, accessToken, key, program);
53
+ inFlight = {
54
+ key,
55
+ promise
56
+ };
57
+ try {
58
+ return await promise;
59
+ } finally {
60
+ if (inFlight?.promise === promise) inFlight = null;
61
+ }
62
+ }
63
+ async function resolveGatewayAuth(host, accessToken, key, program) {
64
+ if (!program) {
65
+ logToFile("[gateway] run has no program id; failing the run");
66
+ throw new GatewayMintFailed("this run has no program to attribute its spend to");
67
+ }
68
+ const minted = await mintGatewayToken(host, accessToken, program);
69
+ if (!minted) {
70
+ const auth = legacyAuth(host, accessToken);
71
+ cached = {
72
+ key,
73
+ auth,
74
+ staleAtMs: Date.now() + LEGACY_RETRY_MS
75
+ };
76
+ return auth;
77
+ }
78
+ const expiresAtMs = Date.parse(minted.expiresAt);
79
+ const ttlMs = expiresAtMs - Date.now();
80
+ if (!Number.isFinite(expiresAtMs) || ttlMs < MIN_USABLE_TTL_MS) {
81
+ logToFile(`[gateway] mint returned a token with ${ttlMs}ms of life; failing the run`);
82
+ throw new GatewayMintFailed(`the PostHog gateway issued a token with ${ttlMs}ms of life`);
83
+ }
84
+ const staleAtMs = Date.now() + ttlMs * REFRESH_AT_FRACTION;
85
+ const auth = {
86
+ gatewayUrl: minted.gatewayUrl,
87
+ token: minted.token,
88
+ edition: "v2",
89
+ teamId: minted.teamId
90
+ };
91
+ cached = {
92
+ key,
93
+ auth,
94
+ staleAtMs
95
+ };
96
+ return auth;
97
+ }
98
+ /** The legacy posture: the user's OAuth token against the Python gateway. */
99
+ function legacyAuth(host, accessToken) {
100
+ return {
101
+ gatewayUrl: host.gatewayUrl,
102
+ token: accessToken,
103
+ edition: "legacy"
104
+ };
105
+ }
106
+ /**
107
+ * Whether a server-supplied origin may receive a bearer and prompt content:
108
+ * https (loopback excepted), and either a posthog.com host or the one the run
109
+ * authenticated against.
110
+ */
111
+ function isTrustedGatewayUrl(value, apiHost) {
112
+ let url;
113
+ try {
114
+ url = new URL(value);
115
+ } catch {
116
+ return false;
117
+ }
118
+ if (url.pathname !== "/" || url.search || url.hash || url.username || url.password) return false;
119
+ if (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "host.docker.internal") return true;
120
+ if (url.protocol !== "https:") return false;
121
+ if (url.hostname.endsWith(".posthog.com")) return true;
122
+ try {
123
+ return url.hostname === new URL(apiHost).hostname;
124
+ } catch {
125
+ return false;
126
+ }
127
+ }
128
+ /**
129
+ * A deliberate refusal from the mint endpoint, as opposed to the mint being
130
+ * unavailable. Thrown rather than folded into the legacy fallback, so the run
131
+ * stops instead of proceeding without the controls the refusal was enforcing.
132
+ */
133
+ var GatewayMintRefused = class extends Error {
134
+ status;
135
+ constructor(status, message) {
136
+ super(message);
137
+ this.name = "GatewayMintRefused";
138
+ this.status = status;
139
+ }
140
+ };
141
+ /**
142
+ * The mint could not produce a usable credential: unreachable, a 5xx, or a
143
+ * response the client cannot use.
144
+ */
145
+ var GatewayMintFailed = class extends Error {
146
+ constructor(message) {
147
+ super(message);
148
+ this.name = "GatewayMintFailed";
149
+ }
150
+ };
151
+ /**
152
+ * Whether a mint status means "refused this run" rather than "not available".
153
+ * 429 is the daily run limit, 403 revoked project access, 401 a credential that
154
+ * may not mint. Only 404 falls back; it is the rollout switch.
155
+ */
156
+ function isMintRefusal(status) {
157
+ return status === 400 || status === 401 || status === 403 || status === 429;
158
+ }
159
+ function mintRefusalMessage(status) {
160
+ switch (status) {
161
+ case 429: return "This wizard program has used its daily run limit. Try again tomorrow.";
162
+ case 403: return "Your access to this project has changed. Re-authenticate and try again.";
163
+ case 400: return "Your PostHog login must cover exactly one project. Re-authenticate and try again.";
164
+ default: return "The wizard could not authenticate to the PostHog gateway.";
165
+ }
166
+ }
167
+ async function mintGatewayToken(host, accessToken, program) {
168
+ try {
169
+ const resp = await fetch(`${host.apiHost}/api/wizard/gateway_token/`, {
170
+ method: "POST",
171
+ headers: {
172
+ Authorization: `Bearer ${accessToken}`,
173
+ "Content-Type": "application/json"
174
+ },
175
+ body: JSON.stringify({ program }),
176
+ signal: AbortSignal.timeout(MINT_TIMEOUT_MS)
177
+ });
178
+ if (!resp.ok) {
179
+ if (isMintRefusal(resp.status)) {
180
+ logToFile(`[gateway] mint refused with HTTP ${resp.status}; failing the run`);
181
+ throw new GatewayMintRefused(resp.status, mintRefusalMessage(resp.status));
182
+ }
183
+ if (resp.status === 404) {
184
+ logToFile("[gateway] mint not enabled for this org; staying on the existing gateway");
185
+ return null;
186
+ }
187
+ logToFile(`[gateway] mint failed with HTTP ${resp.status}; failing the run`);
188
+ throw new GatewayMintFailed(`the PostHog gateway could not issue a token (HTTP ${resp.status})`);
189
+ }
190
+ const body = await resp.json();
191
+ if (!body.token) {
192
+ logToFile("[gateway] mint response omitted token; failing the run");
193
+ throw new GatewayMintFailed("mint response omitted token");
194
+ }
195
+ if (!body.expires_at) {
196
+ logToFile("[gateway] mint response omitted expires_at; failing the run");
197
+ throw new GatewayMintFailed("mint response omitted expires_at");
198
+ }
199
+ if (!body.gateway_url) {
200
+ logToFile("[gateway] mint response omitted gateway_url; failing the run");
201
+ throw new GatewayMintFailed("mint response omitted gateway_url");
202
+ }
203
+ if (!isTrustedGatewayUrl(body.gateway_url, host.apiHost)) {
204
+ logToFile("[gateway] mint returned an untrusted gateway url; failing the run");
205
+ throw new GatewayMintFailed("mint returned an untrusted gateway url");
206
+ }
207
+ return {
208
+ token: body.token,
209
+ expiresAt: body.expires_at,
210
+ gatewayUrl: body.gateway_url.replace(/\/+$/, ""),
211
+ teamId: body.team_id
212
+ };
213
+ } catch (e) {
214
+ if (e instanceof GatewayMintRefused || e instanceof GatewayMintFailed) throw e;
215
+ logToFile(`[gateway] mint transport failure (${String(e)}); failing the run`);
216
+ throw new GatewayMintFailed(`could not reach the PostHog gateway (${String(e)})`);
217
+ }
218
+ }
219
+ /**
220
+ * The v2 run-metadata carrier: one JSON blob for the `X-PostHog-Properties`
221
+ * header. Plain keys only, since the gateway strips `$`-prefixed keys as reserved,
222
+ * so feature-flag variants land as `wizard_flag_<key>` instead of the legacy
223
+ * `$feature/<key>` (dashboards keying on `$feature/wizard-*` read the new key
224
+ * post-cutover).
225
+ */
226
+ function buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId) {
227
+ const props = {};
228
+ if (teamId !== void 0) props.team_id = teamId;
229
+ for (const [key, value] of Object.entries(wizardMetadata)) props[stripPropertyPrefix(key)] = value;
230
+ for (const [flagKey, variant] of Object.entries(wizardFlags)) {
231
+ if (!flagKey.toLowerCase().startsWith("wizard")) continue;
232
+ props[`wizard_flag_${flagKey.toLowerCase()}`] = variant;
233
+ }
234
+ return JSON.stringify(props);
235
+ }
236
+ const LEGACY_PROPERTY_PREFIX = "X-POSTHOG-PROPERTY-";
237
+ function stripPropertyPrefix(key) {
238
+ return key.toUpperCase().startsWith(LEGACY_PROPERTY_PREFIX) ? key.slice(19).toLowerCase() : key;
239
+ }
240
+ //#endregion
18
241
  //#region src/lib/agent/runner/harness/pi/gateway.ts
19
242
  /**
20
243
  * PostHog LLM gateway provider spec for pi sessions — shared by the linear run
@@ -36,15 +259,20 @@ function gatewayApiFor(modelId) {
36
259
  return modelId.startsWith("openai/") ? "openai-completions" : "anthropic-messages";
37
260
  }
38
261
  /**
39
- * Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path: always
40
- * the Bedrock-fallback header, plus wizard metadata (`X-POSTHOG-PROPERTY-*`) and
41
- * wizard feature flags (`X-POSTHOG-FLAG-*`).
262
+ * Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path. The
263
+ * shape follows the gateway edition: legacy sends per-key metadata/flag
264
+ * headers plus the explicit Bedrock-fallback opt-in; v2 (the Go ai-gateway)
265
+ * takes one `X-PostHog-Properties` JSON blob and falls back natively. The 1M
266
+ * context beta rides both, since pi otherwise runs at 200k and overflows on larger
267
+ * projects (the post-run compaction failures).
42
268
  */
43
- function buildGatewayHeaders(wizardMetadata, wizardFlags) {
44
- const headers = {
45
- "x-posthog-use-bedrock-fallback": "true",
46
- "anthropic-beta": "context-1m-2025-08-07"
47
- };
269
+ function buildGatewayHeaders(wizardMetadata, wizardFlags, edition = "legacy", teamId) {
270
+ const headers = { "anthropic-beta": "context-1m-2025-08-07" };
271
+ if (edition === "v2") {
272
+ headers["X-PostHog-Properties"] = buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId);
273
+ return headers;
274
+ }
275
+ headers["x-posthog-use-bedrock-fallback"] = "true";
48
276
  for (const [key, value] of Object.entries(wizardMetadata)) {
49
277
  const name = key.startsWith("X-POSTHOG-PROPERTY-") ? key : `${POSTHOG_PROPERTY_HEADER_PREFIX}${key}`;
50
278
  headers[name] = value;
@@ -61,7 +289,7 @@ function buildGatewayHeaders(wizardMetadata, wizardFlags) {
61
289
  * callers (scan triage) hand it straight to `completeSimple`.
62
290
  */
63
291
  function buildGatewayModel(inputs) {
64
- const { gatewayUrl, wizardMetadata, wizardFlags, modelId } = inputs;
292
+ const { gatewayUrl, wizardMetadata, wizardFlags, modelId, edition, teamId } = inputs;
65
293
  const api = gatewayApiFor(modelId);
66
294
  return {
67
295
  id: modelId,
@@ -79,7 +307,7 @@ function buildGatewayModel(inputs) {
79
307
  },
80
308
  contextWindow: 1e6,
81
309
  maxTokens: 64e3,
82
- headers: buildGatewayHeaders(wizardMetadata, wizardFlags)
310
+ headers: buildGatewayHeaders(wizardMetadata, wizardFlags, edition, teamId)
83
311
  };
84
312
  }
85
313
  /**
@@ -90,9 +318,9 @@ function buildGatewayProvider(inputs) {
90
318
  const { gatewayUrl, accessToken, modelId, effort } = inputs;
91
319
  const api = gatewayApiFor(modelId);
92
320
  const tableCaps = modelCapabilities(modelId);
93
- const caps = effort && tableCaps.reasoning ? {
321
+ const caps = effort && effort !== "off" && tableCaps.reasoning ? modelCapabilities(modelId, effort) : effort === "off" && tableCaps.reasoning ? {
94
322
  ...tableCaps,
95
- thinkingLevel: effort
323
+ thinkingLevel: "off"
96
324
  } : tableCaps;
97
325
  const model = buildGatewayModel(inputs);
98
326
  return {
@@ -127,6 +355,8 @@ function createTriageLLMProvider(auth, harness) {
127
355
  const model = buildGatewayModel({
128
356
  gatewayUrl: baseURL,
129
357
  accessToken: authToken,
358
+ edition: auth.edition,
359
+ teamId: auth.teamId,
130
360
  wizardMetadata: auth?.wizardMetadata ?? {},
131
361
  wizardFlags: auth?.wizardFlags ?? {},
132
362
  modelId
@@ -832,7 +1062,7 @@ function isFullyCancelled(answers) {
832
1062
  }
833
1063
  function createWizardAskBridge(opts) {
834
1064
  const timeoutMs = opts.timeoutMs ?? 3e5;
835
- return { async request({ questions }) {
1065
+ return { async request({ questions, subject }) {
836
1066
  const pending = {
837
1067
  id: randomUUID(),
838
1068
  questions,
@@ -853,12 +1083,14 @@ function createWizardAskBridge(opts) {
853
1083
  const durationMs = Date.now() - startedAt;
854
1084
  if (isFullyCancelled(answers)) analytics.wizardCapture("wizard_ask cancelled", {
855
1085
  source: pending.source,
1086
+ subject,
856
1087
  question_count: questions.length,
857
1088
  duration_ms: durationMs,
858
1089
  timed_out: durationMs >= timeoutMs
859
1090
  });
860
1091
  else analytics.wizardCapture("wizard_ask answered", {
861
1092
  source: pending.source,
1093
+ subject,
862
1094
  question_count: questions.length,
863
1095
  duration_ms: durationMs
864
1096
  });
@@ -1462,8 +1694,68 @@ const WIZARD_TOOL_NAMES = {
1462
1694
  const MAX_HANDOFF_TEXT_CHARS = 64 * 1024;
1463
1695
  const PUBLISH_HANDOFF_TOOL_NAME = "publish_handoff";
1464
1696
  /** Shared between the MCP server and the pi facade so the contract can't drift. */
1465
- const PUBLISH_HANDOFF_DESCRIPTION = "Publish the handoff document — the full markdown report of what this run did — to the wizard session. Call it exactly once, at the end of the run, passing the complete report as `content`. This call is the only way the report reaches the user; do not write the report to a file instead.";
1697
+ const PUBLISH_HANDOFF_DESCRIPTION = "Publish the handoff document — the full markdown report of what this run did — to the wizard session. Call it exactly once, at the end of the run, passing the complete report as `content`. This call is the required way to deliver the report to the user; do not write the report to a file yourself.";
1466
1698
  const PUBLISH_HANDOFF_CONTENT_DESCRIPTION = "The complete handoff report as markdown, starting with an H1 heading.";
1699
+ /**
1700
+ * Write the handoff report to the host-designated `targetPath`.
1701
+ *
1702
+ * The destination comes from the host (`POSTHOG_HANDOFF_OUTPUT_PATH`,
1703
+ * process-env only — the agent can neither set nor see it) while the bytes come
1704
+ * from the agent, so the write is treated as a trust-boundary crossing:
1705
+ * - relative paths are refused (a relative destination would silently resolve
1706
+ * against whatever CWD the wizard happens to run in);
1707
+ * - a pre-existing non-regular destination (symlink, directory, FIFO, device)
1708
+ * is refused, so a primed symlink can't redirect the write at another file;
1709
+ * - content lands in a unique sibling temp file opened with O_NOFOLLOW |
1710
+ * O_EXCL and is then rename()d over the destination — atomic for a polling
1711
+ * reader, and rename replaces the *link* rather than following it;
1712
+ * - the final file is chmod'd to 0o600 even when the host pre-created it with
1713
+ * looser permissions (the report quotes the user's code).
1714
+ *
1715
+ * `reason` is safe to surface to the agent (it names no path); `detail` carries
1716
+ * the specifics for the local log only.
1717
+ */
1718
+ function writeHandoffFileAtomically(targetPath, text) {
1719
+ if (!path$1.isAbsolute(targetPath)) return {
1720
+ ok: false,
1721
+ reason: "destination is not an absolute path",
1722
+ detail: `relative destination refused: ${targetPath}`
1723
+ };
1724
+ let stat;
1725
+ try {
1726
+ stat = lstatSync(targetPath);
1727
+ } catch {
1728
+ stat = void 0;
1729
+ }
1730
+ if (stat && !stat.isFile()) return {
1731
+ ok: false,
1732
+ reason: "destination is not a regular file",
1733
+ detail: `non-regular destination refused: ${targetPath}`
1734
+ };
1735
+ const tmpPath = `${targetPath}.tmp-${process.pid}-${randomBytes(6).toString("hex")}`;
1736
+ let fd;
1737
+ try {
1738
+ fd = openSync(tmpPath, constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW | constants.O_EXCL, 384);
1739
+ writeSync(fd, text, null, "utf8");
1740
+ fchmodSync(fd, 384);
1741
+ closeSync(fd);
1742
+ fd = void 0;
1743
+ renameSync(tmpPath, targetPath);
1744
+ return { ok: true };
1745
+ } catch (err) {
1746
+ if (fd !== void 0) try {
1747
+ closeSync(fd);
1748
+ } catch {}
1749
+ try {
1750
+ unlinkSync(tmpPath);
1751
+ } catch {}
1752
+ return {
1753
+ ok: false,
1754
+ reason: (typeof err === "object" && err !== null && "code" in err ? String(err.code) : void 0) ?? "write error",
1755
+ detail: err instanceof Error ? err.message : String(err)
1756
+ };
1757
+ }
1758
+ }
1467
1759
  function publishHandoff(content) {
1468
1760
  if (content.trim() === "") {
1469
1761
  analytics.wizardCapture("handoff published", {
@@ -1478,14 +1770,29 @@ function publishHandoff(content) {
1478
1770
  const truncated = content.length > MAX_HANDOFF_TEXT_CHARS;
1479
1771
  const text = truncated ? content.slice(0, MAX_HANDOFF_TEXT_CHARS) : content;
1480
1772
  getUI().setHandoffText(text);
1773
+ const handoffOutputPath = runtimeEnv("POSTHOG_HANDOFF_OUTPUT_PATH");
1774
+ let handoffOutputWritten;
1775
+ let handoffOutputError;
1776
+ if (handoffOutputPath) {
1777
+ const write = writeHandoffFileAtomically(handoffOutputPath, text);
1778
+ handoffOutputWritten = write.ok;
1779
+ if (!write.ok) {
1780
+ handoffOutputError = write.reason;
1781
+ logToFile(`[publish_handoff] host output write failed (${write.reason}): ${write.detail}`);
1782
+ }
1783
+ }
1481
1784
  analytics.wizardCapture("handoff published", {
1482
1785
  handoff_ok: true,
1483
1786
  handoff_chars: text.length,
1484
- handoff_truncated: truncated
1787
+ handoff_truncated: truncated,
1788
+ handoff_output_written: handoffOutputWritten
1485
1789
  });
1790
+ const notes = [];
1791
+ if (truncated) notes.push("truncated to the 64 KB limit");
1792
+ if (handoffOutputError) notes.push(`host output write failed: ${handoffOutputError}`);
1486
1793
  return {
1487
1794
  ok: true,
1488
- message: `Handoff published (${text.length} chars${truncated ? ", truncated to the 64 KB limit" : ""}).`
1795
+ message: `Handoff published (${text.length} chars${notes.length > 0 ? `, ${notes.join("; ")}` : ""}).`
1489
1796
  };
1490
1797
  }
1491
1798
  //#endregion
@@ -1847,7 +2154,10 @@ async function createWizardToolsServer(options) {
1847
2154
  }
1848
2155
  askAccounting.record(args.subject);
1849
2156
  try {
1850
- const answers = await askBridge.request({ questions: args.questions });
2157
+ const answers = await askBridge.request({
2158
+ questions: args.questions,
2159
+ subject: normaliseAskSubject(args.subject)
2160
+ });
1851
2161
  if (isFullyCancelled(answers)) askAccounting.refund(args.subject);
1852
2162
  const sanitised = vaultSensitiveAnswers(args.questions, answers, secretVault);
1853
2163
  logToFile(`wizard_ask: resolved ${Object.keys(answers).length} answer(s) for ${args.questions.length} question(s)`);
@@ -2032,31 +2342,6 @@ function classifyToolToStage(toolName) {
2032
2342
  return null;
2033
2343
  }
2034
2344
  //#endregion
2035
- //#region src/lib/agent/signals.ts
2036
- /**
2037
- * Agent signal vocabulary — the marker strings the agent emits and the error
2038
- * taxonomy the runner returns. Kept as a dependency-free leaf module so both
2039
- * `agent-interface.ts` and `output-signals.ts` can import it without a cycle.
2040
- */
2041
- const AgentSignals = {
2042
- STATUS: "[STATUS]",
2043
- ERROR_MCP_MISSING: "[ERROR-MCP-MISSING]",
2044
- ERROR_RESOURCE_MISSING: "[ERROR-RESOURCE-MISSING]",
2045
- SKILL_INSTALL_FAILED: "[SKILL-INSTALL-FAILED]",
2046
- ABORT: "[ABORT]",
2047
- WIZARD_REMARK: "[WIZARD-REMARK]",
2048
- BENCHMARK: "[BENCHMARK]",
2049
- DASHBOARD_URL: "[DASHBOARD_URL]",
2050
- NOTEBOOK_URL: "[NOTEBOOK_URL]"
2051
- };
2052
- /**
2053
- * End-of-run reflection ask, shared by both harnesses so remarks are
2054
- * comparable. The format clause comes FIRST and nothing trails the marker —
2055
- * literal models (gpt-5-mini) echo whatever text follows it. The parser also
2056
- * drops remarks that quote this instruction (see AgentOutputSignals.remark).
2057
- */
2058
- const REMARK_INSTRUCTION = `Reply with a single line that starts with ${AgentSignals.WIZARD_REMARK} and no other lines. In that line, state briefly what information or guidance would have been useful to have in the integration prompt or documentation for this run — specifically anything that would have prevented tool failures, erroneous edits, or other wasted turns.`;
2059
- //#endregion
2060
2345
  //#region src/lib/agent/output-signals.ts
2061
2346
  /**
2062
2347
  * Parses the signal-bearing lines out of agent output and discards the rest.
@@ -2196,6 +2481,32 @@ const PROVIDER_ENV_NAMESPACE = /^(ANTHROPIC_|CLAUDE_CODE_)/;
2196
2481
  */
2197
2482
  const BLOCKED_OFF_NAMESPACE_KEYS = new Set(["AWS_BEARER_TOKEN_BEDROCK"]);
2198
2483
  /**
2484
+ * Host-orchestration values read only by the wizard process itself (via
2485
+ * `runtimeEnv` in src/env.ts). None of them is ever consumed by the spawned
2486
+ * agent subprocess — the `publish_handoff` MCP tool executes in the wizard's
2487
+ * own process — so the subprocess only ever loses attack surface:
2488
+ *
2489
+ * - `POSTHOG_HANDOFF_OUTPUT_PATH` names the host file the wizard writes the
2490
+ * agent's handoff report to. Handing it to the subprocess tells a
2491
+ * (prompt-injected) agent exactly which file its own report content lands
2492
+ * in, turning the write into a pre-plantable symlink/same-UID overwrite
2493
+ * target. The write itself refuses symlinks, but the agent has no business
2494
+ * knowing the destination at all.
2495
+ * - `POSTHOG_TASK_RUN_ID` / `POSTHOG_TASK_ID` identify the sandbox run and are
2496
+ * read by the wizard's analytics only; they let the agent fingerprint the
2497
+ * run directory where the handoff path typically sits.
2498
+ *
2499
+ * Deliberately NOT stripped: `POSTHOG_API_KEY` / `POSTHOG_HOST` — pre-existing
2500
+ * passthrough that the agent may rely on when writing the user's project key
2501
+ * into the project's own .env. Changing that disposition is a separate,
2502
+ * deliberate decision, not part of this hardening.
2503
+ */
2504
+ const HOST_ONLY_ENV_KEYS = new Set([
2505
+ "POSTHOG_HANDOFF_OUTPUT_PATH",
2506
+ "POSTHOG_TASK_RUN_ID",
2507
+ "POSTHOG_TASK_ID"
2508
+ ]);
2509
+ /**
2199
2510
  * Credential / routing knobs that, set in an on-disk Claude **settings** `env`
2200
2511
  * block, redirect the binary. A settings file is applied by the binary itself,
2201
2512
  * so the subprocess-env strip below cannot remove it — `claude-settings.ts`
@@ -2255,10 +2566,11 @@ const BLOCKED_AGENT_ENV_PATTERNS = [/^CLAUDE_CODE_SKIP_.+_AUTH$/, /^ANTHROPIC_.+
2255
2566
  /**
2256
2567
  * True if `key` must NOT be inherited by the agent subprocess: anything in the
2257
2568
  * provider namespace (the wizard re-injects its own values at the spawn site),
2258
- * plus the lone off-namespace credential.
2569
+ * the lone off-namespace credential, and host-only orchestration values the
2570
+ * subprocess never reads.
2259
2571
  */
2260
2572
  function isBlockedAgentEnvKey(key) {
2261
- return PROVIDER_ENV_NAMESPACE.test(key) || BLOCKED_OFF_NAMESPACE_KEYS.has(key);
2573
+ return PROVIDER_ENV_NAMESPACE.test(key) || BLOCKED_OFF_NAMESPACE_KEYS.has(key) || HOST_ONLY_ENV_KEYS.has(key);
2262
2574
  }
2263
2575
  /**
2264
2576
  * Return a copy of `env` with the entire model-provider namespace removed, so
@@ -2693,17 +3005,23 @@ function isWarlockDisabled() {
2693
3005
  return runtimeEnv("POSTHOG_WIZARD_WARLOCK_DISABLED") === "true";
2694
3006
  }
2695
3007
  /**
2696
- * Build env for the SDK subprocess: process.env plus ANTHROPIC_CUSTOM_HEADERS, which always
2697
- * includes `x-posthog-use-bedrock-fallback: true` so the LLM gateway falls back to Bedrock on
2698
- * Anthropic 5xx, plus any wizard metadata/flags.
3008
+ * Build env for the SDK subprocess: process.env plus ANTHROPIC_CUSTOM_HEADERS.
3009
+ * The header shape follows the gateway edition. Legacy (Python gateway):
3010
+ * per-key `X-POSTHOG-PROPERTY-*`/`X-POSTHOG-FLAG-*` plus the explicit
3011
+ * `x-posthog-use-bedrock-fallback` opt-in. v2 (Go ai-gateway): one
3012
+ * `X-PostHog-Properties` JSON blob. Bedrock fallback is native there, and
3013
+ * per-key metadata headers are not read.
2699
3014
  */
2700
- function buildAgentEnv(wizardMetadata, wizardFlags) {
3015
+ function buildAgentEnv(wizardMetadata, wizardFlags, auth) {
2701
3016
  const headers = createCustomHeaders();
2702
- headers.add("x-posthog-use-bedrock-fallback", "true");
2703
- for (const [key, value] of Object.entries(wizardMetadata)) headers.add(key.startsWith("X-POSTHOG-PROPERTY-") ? key : `${POSTHOG_PROPERTY_HEADER_PREFIX}${key}`, value);
2704
- for (const [flagKey, variant] of Object.entries(wizardFlags)) {
2705
- if (!flagKey.toLowerCase().startsWith("wizard")) continue;
2706
- headers.addFlag(flagKey, variant);
3017
+ if (auth?.edition === "v2") headers.add("X-PostHog-Properties", buildWizardPropertiesBlob(wizardMetadata, wizardFlags, auth.teamId));
3018
+ else {
3019
+ headers.add("x-posthog-use-bedrock-fallback", "true");
3020
+ for (const [key, value] of Object.entries(wizardMetadata)) headers.add(key.startsWith("X-POSTHOG-PROPERTY-") ? key : `${POSTHOG_PROPERTY_HEADER_PREFIX}${key}`, value);
3021
+ for (const [flagKey, variant] of Object.entries(wizardFlags)) {
3022
+ if (!flagKey.toLowerCase().startsWith("wizard")) continue;
3023
+ headers.addFlag(flagKey, variant);
3024
+ }
2707
3025
  }
2708
3026
  const encoded = headers.encode();
2709
3027
  logToFile("ANTHROPIC_CUSTOM_HEADERS", encoded);
@@ -2798,13 +3116,17 @@ async function initializeAgent(config, options) {
2798
3116
  logToFile("Install directory:", options.installDir);
2799
3117
  try {
2800
3118
  process.env.CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS = "true";
2801
- const gatewayUrl = config.host.gatewayUrl;
3119
+ const auth = await gatewayAuth(config.host, config.posthogApiKey, config.programId);
3120
+ const gatewayUrl = auth.gatewayUrl;
2802
3121
  process.env.ANTHROPIC_BASE_URL = gatewayUrl;
2803
- process.env.ANTHROPIC_AUTH_TOKEN = config.posthogApiKey;
2804
- process.env.CLAUDE_CODE_OAUTH_TOKEN = config.posthogApiKey;
3122
+ process.env.ANTHROPIC_AUTH_TOKEN = auth.token;
3123
+ process.env.CLAUDE_CODE_OAUTH_TOKEN = auth.token;
3124
+ logToFile("Gateway edition:", auth.edition);
2805
3125
  const triageProvider = createTriageLLMProvider({
2806
3126
  baseURL: gatewayUrl,
2807
- authToken: config.posthogApiKey,
3127
+ authToken: auth.token,
3128
+ edition: auth.edition,
3129
+ teamId: auth.teamId,
2808
3130
  wizardMetadata: {
2809
3131
  ...config.wizardMetadata ?? {},
2810
3132
  call_type: "yara-triage"
@@ -2861,6 +3183,7 @@ async function initializeAgent(config, options) {
2861
3183
  suppressTaskRender: !!config.orchestrator,
2862
3184
  capture: config.capture,
2863
3185
  triageProvider,
3186
+ gatewayAuth: auth,
2864
3187
  program: config.integrationLabel,
2865
3188
  sequence: config.orchestrator ? "orchestrator" : "linear"
2866
3189
  };
@@ -3034,13 +3357,13 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
3034
3357
  },
3035
3358
  env: {
3036
3359
  ...sanitizeAgentSubprocessEnv(process.env),
3037
- ANTHROPIC_BASE_URL: process.env.ANTHROPIC_BASE_URL,
3038
- ANTHROPIC_AUTH_TOKEN: process.env.ANTHROPIC_AUTH_TOKEN,
3039
- CLAUDE_CODE_OAUTH_TOKEN: process.env.CLAUDE_CODE_OAUTH_TOKEN,
3360
+ ANTHROPIC_BASE_URL: agentConfig.gatewayAuth.gatewayUrl,
3361
+ ANTHROPIC_AUTH_TOKEN: agentConfig.gatewayAuth.token,
3362
+ CLAUDE_CODE_OAUTH_TOKEN: agentConfig.gatewayAuth.token,
3040
3363
  CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "true",
3041
3364
  POSTHOG_MCP_TOKEN: agentConfig.posthogApiKey,
3042
3365
  MCP_CONNECTION_NONBLOCKING: "0",
3043
- ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {})
3366
+ ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}, agentConfig.gatewayAuth)
3044
3367
  },
3045
3368
  canUseTool: (toolName, input) => {
3046
3369
  logToFile("canUseTool called:", {
@@ -3072,7 +3395,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
3072
3395
  if (options.debug) debug("CLI stderr:", data);
3073
3396
  },
3074
3397
  hooks: {
3075
- PreToolUse: warlockDisabled ? [] : createPreToolUseYaraHooks(triageProvider),
3398
+ PreToolUse: warlockDisabled ? [] : createPreToolUseYaraHooks(triageProvider, onYaraTerminate),
3076
3399
  PostToolUse: warlockDisabled ? [] : createPostToolUseYaraHooks(triageProvider, onYaraTerminate),
3077
3400
  Stop: [{
3078
3401
  hooks: [createStopHook(config?.additionalFeatureQueue ?? [], signals, config?.requestRemark ?? true)],
@@ -3119,7 +3442,14 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
3119
3442
  if (message.type === "assistant" && signals.hasApiErrorStatus(401)) {
3120
3443
  signalDone();
3121
3444
  spinner.stop("Authentication failed");
3122
- const authError = buildAuthErrorContext(options.installDir, process.env.ANTHROPIC_BASE_URL ?? "", os.homedir(), signals.apiKeySource);
3445
+ const authError = buildAuthErrorContext(options.installDir, agentConfig.gatewayAuth.gatewayUrl, os.homedir(), signals.apiKeySource);
3446
+ const authCode = classifyAuthFailure({
3447
+ hasSettingsConflict: authError.hasSettingsConflict,
3448
+ usingManagedLogin: authError.usingManagedLogin,
3449
+ apiKey: options.apiKey,
3450
+ gatewayRegion: authError.region,
3451
+ sessionRegion: options.cloudRegion
3452
+ });
3123
3453
  logToFile("Agent error: 401, showing auth error screen", authError);
3124
3454
  getUI().showAuthError({
3125
3455
  hasSettingsConflict: authError.hasSettingsConflict,
@@ -3129,6 +3459,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
3129
3459
  logFilePath: getLogFilePath()
3130
3460
  });
3131
3461
  await wizardAbort({
3462
+ code: authCode,
3132
3463
  message: "Authentication failed (401)",
3133
3464
  error: new WizardError("Authentication failed", {
3134
3465
  hasSettingsConflict: authError.hasSettingsConflict,
@@ -3138,7 +3469,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
3138
3469
  region: authError.region,
3139
3470
  usingManagedLogin: authError.usingManagedLogin,
3140
3471
  apiKeySource: authError.apiKeySource
3141
- })
3472
+ }, authCode)
3142
3473
  });
3143
3474
  }
3144
3475
  try {
@@ -3483,6 +3814,6 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
3483
3814
  }
3484
3815
  }
3485
3816
  //#endregion
3486
- export { downloadSkill as A, isFullyCancelled as B, ENV_FILE_PATH_DESCRIPTION as C, WIZARD_TOOL_NAMES as D, WIZARD_ASK_TOOL_DESCRIPTION as E, resolveEnvSecretRefs as F, createTriageLLMProvider as G, isEnvFileName as H, templateEnvWriteRefusal as I, GATEWAY_PROVIDER as K, vaultSensitiveAnswers as L, installSkillById as M, mergeEnvValues as N, checkEnvKeys as O, resolveEnvPath as P, fetchWithRetry as R, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as S, WIZARD_ASK_SUBJECT_DESCRIPTION as T, parseEnvKeyNames as U, MAX_ENV_KEY_SET as V, toPromptSafeRelativePath as W, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as _, wizardCanUseTool as a, publishHandoff as b, classifySettingsConflicts as c, sanitizeAgentSubprocessEnv as d, AgentOutputSignals as f, createSecretVault as g, assembleCommandments as h, runAgent as i, fetchSkillMenu as j, createAskAccounting as k, recoverOrphanedSettingsBackups as l, REMARK_INSTRUCTION as m, buildRunTags as n, backupAndFixClaudeSettings as o, AgentSignals as p, buildGatewayProvider as q, initializeAgent as r, checkAllSettingsConflicts as s, buildAgentEnv as t, restoreClaudeSettings as u, PUBLISH_HANDOFF_DESCRIPTION as v, WIZARD_ASK_SENSITIVE_DESCRIPTION as w, CHECK_ENV_KEYS_DESCRIPTION as x, PUBLISH_HANDOFF_TOOL_NAME as y, createWizardAskBridge as z };
3817
+ export { installSkillById as A, MAX_ENV_KEY_SET as B, WIZARD_ASK_SUBJECT_DESCRIPTION as C, createAskAccounting as D, checkEnvKeys as E, templateEnvWriteRefusal as F, GATEWAY_PROVIDER as G, parseEnvKeyNames as H, vaultSensitiveAnswers as I, buildGatewayProvider as K, fetchWithRetry as L, normaliseAskSubject as M, resolveEnvPath as N, downloadSkill as O, resolveEnvSecretRefs as P, createWizardAskBridge as R, WIZARD_ASK_SENSITIVE_DESCRIPTION as S, WIZARD_TOOL_NAMES as T, toPromptSafeRelativePath as U, isEnvFileName as V, createTriageLLMProvider as W, PUBLISH_HANDOFF_TOOL_NAME as _, wizardCanUseTool as a, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as b, classifySettingsConflicts as c, sanitizeAgentSubprocessEnv as d, AgentOutputSignals as f, PUBLISH_HANDOFF_DESCRIPTION as g, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as h, runAgent as i, mergeEnvValues as j, fetchSkillMenu as k, recoverOrphanedSettingsBackups as l, createSecretVault as m, buildRunTags as n, backupAndFixClaudeSettings as o, assembleCommandments as p, gatewayAuth as q, initializeAgent as r, checkAllSettingsConflicts as s, buildAgentEnv as t, restoreClaudeSettings as u, publishHandoff as v, WIZARD_ASK_TOOL_DESCRIPTION as w, ENV_FILE_PATH_DESCRIPTION as x, CHECK_ENV_KEYS_DESCRIPTION as y, isFullyCancelled as z };
3487
3818
 
3488
- //# sourceMappingURL=agent-interface-D3MNaDp3.js.map
3819
+ //# sourceMappingURL=agent-interface-CaEptZuu.js.map