@posthog/wizard 2.74.1 → 2.75.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 (115) hide show
  1. package/README.md +31 -17
  2. package/dist/README.md +10 -0
  3. package/dist/{add-mcp-server-to-clients-CBtInAoH.js → add-mcp-server-to-clients-CjfnPMbO.js} +5 -5
  4. package/dist/{add-mcp-server-to-clients-CBtInAoH.js.map → add-mcp-server-to-clients-CjfnPMbO.js.map} +1 -1
  5. package/dist/{agent-interface-lCIi_alS.js → agent-interface-BKLTDSyN.js} +144 -339
  6. package/dist/agent-interface-BKLTDSyN.js.map +1 -0
  7. package/dist/{agent-prompt-loader-CSxm81TM.js → agent-prompt-loader-DAagxT3p.js} +5 -5
  8. package/dist/{agent-prompt-loader-CSxm81TM.js.map → agent-prompt-loader-DAagxT3p.js.map} +1 -1
  9. package/dist/{agent-runner-DVrkOFDA.js → agent-runner-BkQontri.js} +133 -44
  10. package/dist/agent-runner-BkQontri.js.map +1 -0
  11. package/dist/{analytics-CeVMOExk.js → analytics-DSK0GXg1.js} +6 -4
  12. package/dist/analytics-DSK0GXg1.js.map +1 -0
  13. package/dist/analytics-yurAACt5.js +2 -0
  14. package/dist/{api-2nAofyKY.js → api-CwNulLDK.js} +3 -3
  15. package/dist/{api-2nAofyKY.js.map → api-CwNulLDK.js.map} +1 -1
  16. package/dist/bin.js +125 -4072
  17. package/dist/bin.js.map +1 -1
  18. package/dist/{bounded-fs-DmcmFPRq.js → bounded-fs-D85Tk3nS.js} +3 -3
  19. package/dist/{bounded-fs-DmcmFPRq.js.map → bounded-fs-D85Tk3nS.js.map} +1 -1
  20. package/dist/{ci-install-lwYLQ4Yw.js → ci-install-CQLi_a-r.js} +4 -4
  21. package/dist/{ci-install-lwYLQ4Yw.js.map → ci-install-CQLi_a-r.js.map} +1 -1
  22. package/dist/{debug-BvheXnxB.js → debug-CBmI5YUF.js} +1 -1
  23. package/dist/{debug-GxjVplPx.js → debug-DUmMVUHn.js} +3 -3
  24. package/dist/debug-DUmMVUHn.js.map +1 -0
  25. package/dist/{defaults-DI642M3n.js → defaults-DDDwYTN5.js} +1 -1
  26. package/dist/{defaults-DI642M3n.js.map → defaults-DDDwYTN5.js.map} +1 -1
  27. package/dist/{env-api-key-BMXH7_4u.js → env-api-key-CGC1Bqwq.js} +2 -2
  28. package/dist/{env-api-key-BMXH7_4u.js.map → env-api-key-CGC1Bqwq.js.map} +1 -1
  29. package/dist/{environment-C3nfPBu-.js → environment-DC4RDnzR.js} +4 -4
  30. package/dist/{environment-C3nfPBu-.js.map → environment-DC4RDnzR.js.map} +1 -1
  31. package/dist/{file-watcher-BGElIpJi.js → file-watcher-hafFFQib.js} +2 -2
  32. package/dist/{file-watcher-BGElIpJi.js.map → file-watcher-hafFFQib.js.map} +1 -1
  33. package/dist/gateway-session-Ctc2xaz7.js +271 -0
  34. package/dist/gateway-session-Ctc2xaz7.js.map +1 -0
  35. package/dist/gateway-session-zwwZAyTt.js +2 -0
  36. package/dist/{headless-ui-jkS2Dm_G.js → headless-ui-CQ46FOTh.js} +2 -2
  37. package/dist/{headless-ui-jkS2Dm_G.js.map → headless-ui-CQ46FOTh.js.map} +1 -1
  38. package/dist/{interactive-CrQWwMr2.js → interactive-5O4XQf59.js} +2 -2
  39. package/dist/{interactive-CrQWwMr2.js.map → interactive-5O4XQf59.js.map} +1 -1
  40. package/dist/{mcp-S3yX8Uz1.js → mcp-D0Dni4tL.js} +2 -2
  41. package/dist/{mcp-S3yX8Uz1.js.map → mcp-D0Dni4tL.js.map} +1 -1
  42. package/dist/{mcp-prompt-streaming-BvvCZBYa.js → mcp-prompt-streaming-DNCDeU51.js} +6 -5
  43. package/dist/{mcp-prompt-streaming-BvvCZBYa.js.map → mcp-prompt-streaming-DNCDeU51.js.map} +1 -1
  44. package/dist/mint-failure-CQqypC_v.js +5718 -0
  45. package/dist/mint-failure-CQqypC_v.js.map +1 -0
  46. package/dist/{non-interactive-B-MIn3vt.js → non-interactive-D5-lCBy6.js} +2 -2
  47. package/dist/{non-interactive-B-MIn3vt.js.map → non-interactive-D5-lCBy6.js.map} +1 -1
  48. package/dist/{orchestrator-tools-CefodRf2.js → orchestrator-tools-D8ZQS2DM.js} +5 -5
  49. package/dist/orchestrator-tools-D8ZQS2DM.js.map +1 -0
  50. package/dist/{package-manager-pB6S0gyu.js → package-manager-hyP-CPSZ.js} +2 -2
  51. package/dist/{package-manager-pB6S0gyu.js.map → package-manager-hyP-CPSZ.js.map} +1 -1
  52. package/dist/{pi-Dbw8VakI.js → pi-DARAk2I_.js} +35 -24
  53. package/dist/pi-DARAk2I_.js.map +1 -0
  54. package/dist/{playground-C7DwGktN.js → playground-Djabnagq.js} +8 -8
  55. package/dist/{playground-C7DwGktN.js.map → playground-Djabnagq.js.map} +1 -1
  56. package/dist/{posthog-B3RuLfxH.js → posthog-C3Sncfan.js} +2 -2
  57. package/dist/{posthog-B3RuLfxH.js.map → posthog-C3Sncfan.js.map} +1 -1
  58. package/dist/{provisioning-B4Lr3-aS.js → provisioning-B74q1uSQ.js} +3 -3
  59. package/dist/{provisioning-B4Lr3-aS.js.map → provisioning-B74q1uSQ.js.map} +1 -1
  60. package/dist/{queue-tools-BveMVXQm.js → queue-tools-FLMG8hcB.js} +17 -5
  61. package/dist/queue-tools-FLMG8hcB.js.map +1 -0
  62. package/dist/{registry-D8MIZ9kJ.js → registry-DZoReEU3.js} +5 -5
  63. package/dist/{registry-D8MIZ9kJ.js.map → registry-DZoReEU3.js.map} +1 -1
  64. package/dist/{security-B_Eo15wD.js → security-DiBFYwh7.js} +5 -5
  65. package/dist/{security-B_Eo15wD.js.map → security-DiBFYwh7.js.map} +1 -1
  66. package/dist/{setup-utils-D3OK2RE_.js → setup-utils-C3tsa6D6.js} +48 -9
  67. package/dist/setup-utils-C3tsa6D6.js.map +1 -0
  68. package/dist/smoke-test-ci.sh +9 -14
  69. package/dist/{start-tui-B7u962uh.js → start-tui-BXjJGNx2.js} +849 -115
  70. package/dist/start-tui-BXjJGNx2.js.map +1 -0
  71. package/dist/{steps-D4mHkYX4.js → steps-CeFanezY.js} +7 -7
  72. package/dist/{steps-D4mHkYX4.js.map → steps-CeFanezY.js.map} +1 -1
  73. package/dist/{store-Cn1VK6U0.js → store-DN_6FaoQ.js} +63 -10
  74. package/dist/store-DN_6FaoQ.js.map +1 -0
  75. package/dist/{subagent-1UEmD7bE.js → subagent-BzhCH9c3.js} +2 -2
  76. package/dist/{subagent-1UEmD7bE.js.map → subagent-BzhCH9c3.js.map} +1 -1
  77. package/dist/{task-DNHNZMO0.js → task-DZKmaWYF.js} +19 -22
  78. package/dist/task-DZKmaWYF.js.map +1 -0
  79. package/dist/{task-stream-BJrRzR9K.js → task-stream-h-b1nWdM.js} +5 -5
  80. package/dist/{task-stream-BJrRzR9K.js.map → task-stream-h-b1nWdM.js.map} +1 -1
  81. package/dist/{tasks-DSEJ8GZC.js → tasks-0Rb5AXpz.js} +2 -2
  82. package/dist/{tasks-DSEJ8GZC.js.map → tasks-0Rb5AXpz.js.map} +1 -1
  83. package/dist/{telemetry-DWkTy6TJ.js → telemetry-QpeVhVtU.js} +3 -3
  84. package/dist/{telemetry-DWkTy6TJ.js.map → telemetry-QpeVhVtU.js.map} +1 -1
  85. package/dist/{terminal-DNnNkvFu.js → terminal-dLoYiXsd.js} +20 -18
  86. package/dist/{terminal-DNnNkvFu.js.map → terminal-dLoYiXsd.js.map} +1 -1
  87. package/dist/{tools-HHK4XbnC.js → tools-DmwO0eBZ.js} +22 -16
  88. package/dist/tools-DmwO0eBZ.js.map +1 -0
  89. package/dist/{wizard-abort-BVmjqUAQ.js → wizard-abort-B0c5VDie.js} +4 -4
  90. package/dist/{wizard-abort-BVmjqUAQ.js.map → wizard-abort-B0c5VDie.js.map} +1 -1
  91. package/dist/{wizard-abort-CG_xzEFN.js → wizard-abort-C9Jbm-m7.js} +1 -1
  92. package/dist/{wizard-session-BWAQoi9q.js → wizard-session-CYvyYnti.js} +1 -1
  93. package/dist/{wizard-session-GdDN_aMS.js → wizard-session-FSJCkTcP.js} +9 -2
  94. package/dist/wizard-session-FSJCkTcP.js.map +1 -0
  95. package/dist/yara-hooks-B7prW1Ng.js +2 -0
  96. package/dist/{yara-hooks-qRkdjYiV.js → yara-hooks-uCiAIcqU.js} +4 -4
  97. package/dist/{yara-hooks-qRkdjYiV.js.map → yara-hooks-uCiAIcqU.js.map} +1 -1
  98. package/package.json +1 -1
  99. package/dist/agent-interface-lCIi_alS.js.map +0 -1
  100. package/dist/agent-runner-DVrkOFDA.js.map +0 -1
  101. package/dist/analytics-3H_AlflZ.js +0 -2
  102. package/dist/analytics-CeVMOExk.js.map +0 -1
  103. package/dist/debug-GxjVplPx.js.map +0 -1
  104. package/dist/orchestrator-tools-CefodRf2.js.map +0 -1
  105. package/dist/pi-Dbw8VakI.js.map +0 -1
  106. package/dist/posthog-integration-su2LXi3-.js +0 -1475
  107. package/dist/posthog-integration-su2LXi3-.js.map +0 -1
  108. package/dist/queue-tools-BveMVXQm.js.map +0 -1
  109. package/dist/setup-utils-D3OK2RE_.js.map +0 -1
  110. package/dist/start-tui-B7u962uh.js.map +0 -1
  111. package/dist/store-Cn1VK6U0.js.map +0 -1
  112. package/dist/task-DNHNZMO0.js.map +0 -1
  113. package/dist/tools-HHK4XbnC.js.map +0 -1
  114. package/dist/wizard-session-GdDN_aMS.js.map +0 -1
  115. package/dist/yara-hooks-BOMbtTOr.js +0 -2
@@ -1,12 +1,13 @@
1
1
  import { n as __require } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { c as RESUME_INSTRUCTION, d as ErrorCodes, l as classifyAuthFailure, o as AgentSignals, s as REMARK_INSTRUCTION } from "./errors--OqLxmWR.js";
3
- import { E as AWS_SKILLS_BASE_URL, O as CONTEXT_MILL_URL, a as getLogFilePath, bt as runtimeEnv, f as getUI, mt as wizardUserAgentForProgram, o as initLogFile, r as debug, s as logToFile, ut as WIZARD_REMARK_EVENT_NAME, y as checkLlmGatewayHealth } from "./debug-GxjVplPx.js";
4
- import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-GdDN_aMS.js";
5
- import { n as analytics } from "./analytics-CeVMOExk.js";
6
- import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-DmcmFPRq.js";
7
- import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-BVmjqUAQ.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-qRkdjYiV.js";
9
- import { S as writeJsonAtomic, b as triageModelFor, c as buildOrchestratorTools, v as modelCapabilities, x as makeMutex } from "./queue-tools-BveMVXQm.js";
2
+ import { c as RESUME_INSTRUCTION, l as classifyAuthFailure, o as AgentSignals, s as REMARK_INSTRUCTION } from "./errors--OqLxmWR.js";
3
+ import { E as AWS_SKILLS_BASE_URL, O as CONTEXT_MILL_URL, a as getLogFilePath, bt as runtimeEnv, f as getUI, mt as wizardUserAgentForProgram, o as initLogFile, r as debug, s as logToFile, ut as WIZARD_REMARK_EVENT_NAME } from "./debug-DUmMVUHn.js";
4
+ import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-FSJCkTcP.js";
5
+ import { n as analytics } from "./analytics-DSK0GXg1.js";
6
+ import { a as safeReadFile, i as readProjectFile, o as walkProjectFiles } from "./bounded-fs-D85Tk3nS.js";
7
+ import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-B0c5VDie.js";
8
+ import { o as gatewayAuth, r as buildWizardPropertiesBlob, s as isPastRefresh } from "./gateway-session-Ctc2xaz7.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-uCiAIcqU.js";
10
+ import { C as writeJsonAtomic, S as makeMutex, l as buildOrchestratorTools, x as triageModelFor, y as modelCapabilities } from "./queue-tools-FLMG8hcB.js";
10
11
  import { createRequire } from "node:module";
11
12
  import * as fs$1 from "fs";
12
13
  import fs from "fs";
@@ -191,303 +192,6 @@ function createCustomHeaders() {
191
192
  };
192
193
  }
193
194
  //#endregion
194
- //#region src/lib/legacy-gateway.ts
195
- let enabled = false;
196
- /** Only the `--ci` runner turns this on. */
197
- function setLegacyGatewayFallback(on) {
198
- enabled = on;
199
- }
200
- /** Legacy auth when the fallback is on and the mint cannot serve this credential (401, or 404 without the endpoint). */
201
- function legacyGatewayAuth(host, accessToken, mintStatus) {
202
- if (!enabled || mintStatus !== 401 && mintStatus !== 404) return void 0;
203
- return {
204
- gatewayUrl: legacyGatewayUrl(host),
205
- token: accessToken,
206
- legacy: true,
207
- refreshAtMs: Number.POSITIVE_INFINITY
208
- };
209
- }
210
- function legacyGatewayUrl(host) {
211
- const { hostname } = new URL(host.apiHost);
212
- if (hostname === "host.docker.internal") return "http://host.docker.internal:3308/wizard";
213
- if (hostname === "localhost" || hostname === "127.0.0.1") return "http://localhost:3308/wizard";
214
- return `https://gateway.${host.region}.posthog.com/wizard`;
215
- }
216
- /** The legacy gateway reads per-key metadata and flag headers and needs an explicit Bedrock opt-in. */
217
- function legacyGatewayHeaders(wizardMetadata, wizardFlags) {
218
- const headers = { "x-posthog-use-bedrock-fallback": "true" };
219
- for (const [key, value] of Object.entries(wizardMetadata)) headers[key.startsWith("X-POSTHOG-PROPERTY-") ? key : `X-POSTHOG-PROPERTY-${key}`] = value;
220
- for (const [flagKey, variant] of Object.entries(wizardFlags)) {
221
- if (!flagKey.toLowerCase().startsWith("wizard")) continue;
222
- headers[`X-POSTHOG-FLAG-${flagKey.toUpperCase()}`] = variant;
223
- }
224
- return headers;
225
- }
226
- //#endregion
227
- //#region src/lib/gateway-session.ts
228
- /**
229
- * Gateway auth for a wizard run: a `phe_` scoped token the backend mints, with
230
- * pinned attribution, a spend cap and an expiry.
231
- *
232
- * Every mint failure throws, since a silent downgrade would spend uncapped,
233
- * unattributed money to hide an outage. The CI-only exception lives in
234
- * legacy-gateway.ts.
235
- */
236
- let cached = null;
237
- /**
238
- * Shared so concurrent callers mint once. The orchestrator starts every runnable
239
- * task at once, and each would otherwise take its own token and its own cap.
240
- */
241
- let inFlight = null;
242
- /**
243
- * Adoption floor. The anthropic subprocess holds its credential until a 401
244
- * forces a re-mint, so a token below this would churn mints.
245
- */
246
- const MIN_USABLE_TTL_MS = 120 * 1e3;
247
- /** Re-resolve at this fraction of the token's life, leaving a usable remainder. */
248
- const REFRESH_AT_FRACTION = .8;
249
- const MINT_TIMEOUT_MS = 2e4;
250
- /** Longer than any refusal the mint writes; a body past this is not a message. */
251
- const MAX_REFUSAL_DETAIL_LENGTH = 500;
252
- /** Outcomes are short snake_case labels; anything longer is not one. */
253
- const MAX_REFUSAL_OUTCOME_LENGTH = 64;
254
- /** Resolve this run's gateway auth, minting and re-minting near expiry. */
255
- async function gatewayAuth(host, accessToken, program) {
256
- const key = `${host.apiHost}\n${accessToken}\n${program ?? ""}`;
257
- if (cached && cached.key === key && Date.now() < cached.staleAtMs) return cached.auth;
258
- if (inFlight && inFlight.key === key) return inFlight.promise;
259
- const promise = resolveGatewayAuth(host, accessToken, key, program);
260
- inFlight = {
261
- key,
262
- promise
263
- };
264
- try {
265
- return await promise;
266
- } finally {
267
- if (inFlight?.promise === promise) inFlight = null;
268
- }
269
- }
270
- async function resolveGatewayAuth(host, accessToken, key, program) {
271
- if (!program) {
272
- logToFile("[gateway] run has no program id; failing the run");
273
- throw new GatewayMintFailed("this run has no program to attribute its spend to");
274
- }
275
- let minted;
276
- try {
277
- minted = await mintGatewayToken(host, accessToken, program);
278
- } catch (e) {
279
- if (!(e instanceof GatewayMintRefused)) throw e;
280
- const legacy = legacyGatewayAuth(host, accessToken, e.status);
281
- if (!legacy) throw e;
282
- logToFile(`[gateway] mint refused this credential (HTTP ${e.status}); CI run staying on the legacy gateway`);
283
- cached = {
284
- key,
285
- auth: legacy,
286
- staleAtMs: legacy.refreshAtMs
287
- };
288
- return legacy;
289
- }
290
- if ((await checkLlmGatewayHealth(minted.gatewayUrl)).status !== "healthy") throw new WizardError("The PostHog AI gateway is unavailable. Please try again later.", void 0, ErrorCodes.EnvServiceOutage);
291
- const expiresAtMs = Date.parse(minted.expiresAt);
292
- const ttlMs = expiresAtMs - Date.now();
293
- if (!Number.isFinite(expiresAtMs) || ttlMs < MIN_USABLE_TTL_MS) {
294
- logToFile(`[gateway] mint returned a token with ${ttlMs}ms of life; failing the run`);
295
- throw new GatewayMintFailed(`the PostHog gateway issued a token with ${ttlMs}ms of life`);
296
- }
297
- const staleAtMs = Date.now() + ttlMs * REFRESH_AT_FRACTION;
298
- logToFile(`[gateway] minted a scoped token: program=${program} team=${minted.teamId ?? "unknown"} ttl=${Math.round(ttlMs / 1e3)}s url=${minted.gatewayUrl}`);
299
- const auth = {
300
- gatewayUrl: minted.gatewayUrl,
301
- token: minted.token,
302
- teamId: minted.teamId,
303
- refreshAtMs: staleAtMs
304
- };
305
- cached = {
306
- key,
307
- auth,
308
- staleAtMs
309
- };
310
- return auth;
311
- }
312
- /** Whether a 401 on this bearer may be age (past its refresh instant) rather than a bad credential. */
313
- function isPastRefresh(auth, now = Date.now()) {
314
- return now >= auth.refreshAtMs;
315
- }
316
- /**
317
- * Whether a server-supplied origin may receive a bearer and prompt content:
318
- * https (loopback excepted), and either a posthog.com host or the one the run
319
- * authenticated against.
320
- */
321
- function isTrustedGatewayUrl(value, apiHost) {
322
- let url;
323
- try {
324
- url = new URL(value);
325
- } catch {
326
- return false;
327
- }
328
- if (url.pathname !== "/" || url.search || url.hash || url.username || url.password) return false;
329
- if (url.hostname === "localhost" || url.hostname === "127.0.0.1" || url.hostname === "host.docker.internal") return true;
330
- if (url.protocol !== "https:") return false;
331
- if (url.hostname.endsWith(".posthog.com")) return true;
332
- try {
333
- return url.hostname === new URL(apiHost).hostname;
334
- } catch {
335
- return false;
336
- }
337
- }
338
- /**
339
- * A deliberate refusal from the mint endpoint, as opposed to the mint being
340
- * unavailable. Thrown so the run stops instead of proceeding without the
341
- * controls the refusal was enforcing. A WizardError, so the runners print its
342
- * message as-is and `wizardAbort` resolves its code.
343
- */
344
- var GatewayMintRefused = class extends WizardError {
345
- status;
346
- /** The backend's refusal outcome (`blocked`, `throttled`, ...), when it sent one. */
347
- outcome;
348
- constructor(status, message, outcome) {
349
- super(message, {
350
- status,
351
- outcome
352
- }, ErrorCodes.GatewayMintRefused);
353
- this.name = "GatewayMintRefused";
354
- this.status = status;
355
- this.outcome = outcome;
356
- }
357
- };
358
- /**
359
- * The mint could not produce a usable credential: unreachable, a 5xx, or a
360
- * response the client cannot use.
361
- */
362
- var GatewayMintFailed = class extends WizardError {
363
- constructor(message) {
364
- super(message, void 0, ErrorCodes.GatewayMintFailed);
365
- this.name = "GatewayMintFailed";
366
- }
367
- };
368
- /**
369
- * Whether a mint status means "refused this run" rather than "not available".
370
- * 429 the daily run limit, 403 revoked project access, 400 a login covering
371
- * more than one project, 401 a credential the mint does not accept, 404 an
372
- * instance without the mint endpoint.
373
- */
374
- function isMintRefusal(status) {
375
- return status === 400 || status === 401 || status === 403 || status === 404 || status === 429;
376
- }
377
- /**
378
- * The server's own reason for a refusal, when it sent one. DRF answers every
379
- * refusal as `{"detail": "...", "code": "<outcome>"}`; the blocklist's detail
380
- * names the contact address, which the fixed messages below cannot. `code` is
381
- * the backend's own label for the refusal (`outcome` on older backends) and
382
- * rides the client event.
383
- */
384
- function cleanRefusalText(value) {
385
- if (typeof value !== "string") return "";
386
- return value.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").trim();
387
- }
388
- async function readRefusal(resp) {
389
- try {
390
- const body = await resp.json();
391
- const detail = cleanRefusalText(body?.detail);
392
- const outcome = cleanRefusalText(body?.code) || cleanRefusalText(body?.outcome);
393
- return {
394
- detail: detail.length > 0 && detail.length <= MAX_REFUSAL_DETAIL_LENGTH ? detail : void 0,
395
- outcome: outcome.length > 0 && outcome.length <= MAX_REFUSAL_OUTCOME_LENGTH ? outcome : void 0
396
- };
397
- } catch {
398
- return {};
399
- }
400
- }
401
- function mintRefusalMessage(status, detail) {
402
- if (detail) return detail;
403
- switch (status) {
404
- case 429: return "This wizard program has used its daily run limit. Try again tomorrow.";
405
- case 403: return "Your access to this project has changed. Re-authenticate and try again.";
406
- case 400: return "Your PostHog login must cover exactly one project. Re-authenticate and try again.";
407
- case 401: return "PostHog did not accept this login. Re-authenticate with `npx @posthog/wizard@latest`.";
408
- case 404: return "This PostHog instance does not issue gateway tokens. Upgrade with `npx @posthog/wizard@latest` and try again.";
409
- default: return "The PostHog gateway refused this run.";
410
- }
411
- }
412
- async function mintGatewayToken(host, accessToken, program) {
413
- try {
414
- const resp = await fetch(`${host.apiHost}/api/wizard/gateway_token/`, {
415
- method: "POST",
416
- headers: {
417
- Authorization: `Bearer ${accessToken}`,
418
- "Content-Type": "application/json"
419
- },
420
- body: JSON.stringify({
421
- program,
422
- reads_refusal_reason: true
423
- }),
424
- signal: AbortSignal.timeout(MINT_TIMEOUT_MS)
425
- });
426
- if (!resp.ok) {
427
- if (isMintRefusal(resp.status)) {
428
- const refusal = await readRefusal(resp);
429
- logToFile(`[gateway] mint refused with HTTP ${resp.status} (${refusal.outcome ?? "no outcome"}); failing the run`);
430
- analytics.wizardCapture("gateway mint refused", {
431
- status: resp.status,
432
- outcome: refusal.outcome,
433
- program
434
- });
435
- throw new GatewayMintRefused(resp.status, mintRefusalMessage(resp.status, refusal.detail), refusal.outcome);
436
- }
437
- logToFile(`[gateway] mint failed with HTTP ${resp.status}; failing the run`);
438
- throw new GatewayMintFailed(`the PostHog gateway could not issue a token (HTTP ${resp.status})`);
439
- }
440
- const body = await resp.json();
441
- if (!body.token) {
442
- logToFile("[gateway] mint response omitted token; failing the run");
443
- throw new GatewayMintFailed("mint response omitted token");
444
- }
445
- if (!body.expires_at) {
446
- logToFile("[gateway] mint response omitted expires_at; failing the run");
447
- throw new GatewayMintFailed("mint response omitted expires_at");
448
- }
449
- if (!body.gateway_url) {
450
- logToFile("[gateway] mint response omitted gateway_url; failing the run");
451
- throw new GatewayMintFailed("mint response omitted gateway_url");
452
- }
453
- if (!isTrustedGatewayUrl(body.gateway_url, host.apiHost)) {
454
- logToFile("[gateway] mint returned an untrusted gateway url; failing the run");
455
- throw new GatewayMintFailed("mint returned an untrusted gateway url");
456
- }
457
- return {
458
- token: body.token,
459
- expiresAt: body.expires_at,
460
- gatewayUrl: body.gateway_url.replace(/\/+$/, ""),
461
- teamId: body.team_id
462
- };
463
- } catch (e) {
464
- if (e instanceof GatewayMintRefused || e instanceof GatewayMintFailed) throw e;
465
- logToFile(`[gateway] mint transport failure (${String(e)}); failing the run`);
466
- throw new GatewayMintFailed(`could not reach the PostHog gateway (${String(e)})`);
467
- }
468
- }
469
- /**
470
- * The v2 run-metadata carrier: one JSON blob for the `X-PostHog-Properties`
471
- * header. Plain keys only, since the gateway strips `$`-prefixed keys as reserved,
472
- * so feature-flag variants land as `wizard_flag_<key>` instead of the legacy
473
- * `$feature/<key>` (dashboards keying on `$feature/wizard-*` read the new key
474
- * post-cutover).
475
- */
476
- function buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId) {
477
- const props = { ai_product: "wizard" };
478
- if (teamId !== void 0) props.team_id = teamId;
479
- for (const [key, value] of Object.entries(wizardMetadata)) props[stripPropertyPrefix(key)] = value;
480
- for (const [flagKey, variant] of Object.entries(wizardFlags)) {
481
- if (!flagKey.toLowerCase().startsWith("wizard")) continue;
482
- props[`wizard_flag_${flagKey.toLowerCase()}`] = variant;
483
- }
484
- return JSON.stringify(props);
485
- }
486
- const LEGACY_PROPERTY_PREFIX = "X-POSTHOG-PROPERTY-";
487
- function stripPropertyPrefix(key) {
488
- return key.toUpperCase().startsWith(LEGACY_PROPERTY_PREFIX) ? key.slice(19).toLowerCase() : key;
489
- }
490
- //#endregion
491
195
  //#region src/lib/safe-tools.ts
492
196
  const LINTING_TOOLS = [
493
197
  "codespell",
@@ -999,6 +703,13 @@ function evaluateBashCommand(rawCommand) {
999
703
  */
1000
704
  /** Sentinel returned for unanswered fields on cancellation or timeout. */
1001
705
  const CANCELLED_SENTINEL = "__cancelled__";
706
+ /**
707
+ * The longer per-question timeout, for asks that send the user on an errand —
708
+ * open a database console, mint a restricted API key. The default above is
709
+ * sized for a question answerable from memory and expires long before an
710
+ * errand is done.
711
+ */
712
+ const LONGER_ASK_TIMEOUT_MS = 1200 * 1e3;
1002
713
  function buildCancelledAnswers(questions) {
1003
714
  const out = {};
1004
715
  for (const q of questions) out[q.id] = CANCELLED_SENTINEL;
@@ -1021,8 +732,10 @@ function createWizardAskBridge(opts) {
1021
732
  };
1022
733
  const startedAt = Date.now();
1023
734
  let timer;
735
+ let timedOut = false;
1024
736
  const timeoutPromise = new Promise((resolve) => {
1025
737
  timer = setTimeout(() => {
738
+ timedOut = true;
1026
739
  opts.cancelQuestion?.();
1027
740
  resolve(buildCancelledAnswers(questions));
1028
741
  }, timeoutMs);
@@ -1035,7 +748,7 @@ function createWizardAskBridge(opts) {
1035
748
  subject,
1036
749
  question_count: questions.length,
1037
750
  duration_ms: durationMs,
1038
- timed_out: durationMs >= timeoutMs
751
+ timed_out: timedOut
1039
752
  });
1040
753
  else analytics.wizardCapture("wizard_ask answered", {
1041
754
  source: pending.source,
@@ -1043,7 +756,10 @@ function createWizardAskBridge(opts) {
1043
756
  question_count: questions.length,
1044
757
  duration_ms: durationMs
1045
758
  });
1046
- return answers;
759
+ return {
760
+ answers,
761
+ timedOut
762
+ };
1047
763
  } finally {
1048
764
  if (timer) clearTimeout(timer);
1049
765
  }
@@ -1327,6 +1043,31 @@ function normaliseAskSubject(subject) {
1327
1043
  return trimmed.slice(0, ASK_SUBJECT_MAX_LENGTH);
1328
1044
  }
1329
1045
  /**
1046
+ * The `wizard_ask` `kind` field description, shared by both harness facades so
1047
+ * the inferred default cannot drift between them.
1048
+ */
1049
+ const WIZARD_ASK_KIND_DESCRIPTION = "'single' = pick one option, 'multi' = pick any, 'text' = free-form single-line answer. Optional: omit it and the kind follows the question — 'single' when you pass options, 'text' when you do not, which is what a credential question wants.";
1050
+ /**
1051
+ * Fill in the `kind` of every question that arrived without one.
1052
+ *
1053
+ * The field used to be required, and both harnesses validate a call before this
1054
+ * handler sees it — pi against the typebox schema, the MCP SDK against the zod
1055
+ * one — so a call that omitted it was rejected upstream and the agent spent a
1056
+ * turn recovering from a validation error rather than asking its question.
1057
+ * Accepting the omission costs nothing, because `options` already says which
1058
+ * kind was meant, and a question carrying none is free text — which is what a
1059
+ * credential question wants, and the case an agent is most likely to send bare.
1060
+ *
1061
+ * Options imply `single`, never `multi`: omitting `kind` expresses no intent to
1062
+ * accept more than one answer.
1063
+ */
1064
+ function resolveAskQuestionKinds(questions) {
1065
+ return questions.map((q) => ({
1066
+ ...q,
1067
+ kind: q.kind ?? (q.options && q.options.length > 0 ? "single" : "text")
1068
+ }));
1069
+ }
1070
+ /**
1330
1071
  * The `wizard_ask` `sensitive` field description, shared by both harness facades
1331
1072
  * (the zod schema in `./mcp` and the typebox mirror in `harness/pi/tools.ts`) so
1332
1073
  * the secret-handling guidance cannot drift between them — the same discipline
@@ -1355,7 +1096,43 @@ const WIZARD_ASK_SUBJECT_DESCRIPTION = "Short, stable tag naming what this call
1355
1096
  * server in `./mcp` and the pi-native mirror in `harness/pi/tools.ts`) so the
1356
1097
  * batching and cancellation contract reads identically in both harnesses.
1357
1098
  */
1358
- const WIZARD_ASK_TOOL_DESCRIPTION = "Ask the user one or more structured questions and wait for their answers. Use this whenever you would otherwise inline a question in your text output. Batch every question about one subject into a single call (up to 8) rather than asking one at a time, and tag the call with `subject`. Walking a list — one call per data-warehouse source, one call per integration step — is expected and is never blocked, because the batching guard counts consecutive calls per subject. A fully cancelled or timed-out response does NOT count against the per-run cap — treat it as \"the user declined\" and fall back gracefully (e.g. hand over a deep link) without worrying about a wasted call.";
1099
+ const WIZARD_ASK_TOOL_DESCRIPTION = "Ask the user one or more structured questions and wait for their answers. Use this whenever you would otherwise inline a question in your text output. Batch every question about one subject into a single call (up to 8) rather than asking one at a time, and tag the call with `subject`. Walking a list — one call per data-warehouse source, one call per integration step — is expected and is never blocked, because the batching guard counts consecutive calls per subject. A fully cancelled or timed-out response does NOT count against the per-run cap, so nothing is wasted. When a field is not collected the result carries a `cancelled` object naming those question ids, whether the user dismissed the prompt or it timed out, and what to do next: read that instead of inspecting the answer values, and fall back gracefully (e.g. hand over a deep link) rather than re-asking.";
1100
+ /**
1101
+ * Guidance returned with a `wizard_ask` result when the user dismissed the
1102
+ * prompt. Shared by both harness facades, like the descriptions above.
1103
+ *
1104
+ * Deliberately says nothing about how the caller reports its own outcome:
1105
+ * `wizard_ask` serves programs with no task queue as well as the orchestrator's
1106
+ * seeded ones, so the note covers the ask and only the ask.
1107
+ */
1108
+ const ASK_CANCELLED_NOTE = "The user dismissed this prompt, so none of these fields were collected. Read it as a decline for this subject: do not re-ask the same questions. Fall back to a route that needs no answer from them (for example, hand them a link to finish it themselves) and carry on with the rest of your work. Asking about a different subject is still fine.";
1109
+ /**
1110
+ * Guidance returned with a `wizard_ask` result when the prompt timed out.
1111
+ *
1112
+ * A timeout is not one decline: it says nobody is reading the terminal, and
1113
+ * every later prompt in the run will end the same way after the same wait.
1114
+ * Naming that is the difference between falling back once and stopping the run
1115
+ * behind one unattended prompt per remaining item.
1116
+ */
1117
+ const ASK_TIMED_OUT_NOTE = "This prompt timed out with no answer, so the user is most likely away from the terminal. Read it as a decline, and expect any further prompt in this run to time out the same way after the same wait: stop asking and finish without them — hand over links for everything still outstanding — rather than opening another prompt.";
1118
+ /**
1119
+ * Describe an ask's cancelled fields, or `undefined` when every question was
1120
+ * answered. `timedOut` comes from the ask bridge — it is the only thing that
1121
+ * tells a dismissed prompt from an unattended one.
1122
+ */
1123
+ function describeAskCancellation(answers, timedOut) {
1124
+ const questionIds = Object.entries(answers).filter(([, value]) => value === CANCELLED_SENTINEL).map(([id]) => id);
1125
+ if (questionIds.length === 0) return void 0;
1126
+ return timedOut ? {
1127
+ reason: "timed-out",
1128
+ questionIds,
1129
+ note: ASK_TIMED_OUT_NOTE
1130
+ } : {
1131
+ reason: "user-cancelled",
1132
+ questionIds,
1133
+ note: ASK_CANCELLED_NOTE
1134
+ };
1135
+ }
1359
1136
  /**
1360
1137
  * Pure decision function for the wizard_ask caps. Returns whether the
1361
1138
  * upcoming call should proceed and, if not, the message to surface to the
@@ -1538,6 +1315,34 @@ function templateEnvWriteRefusal(resolvedPath) {
1538
1315
  if (!isTemplateEnvFileName(name)) return null;
1539
1316
  return `Error: "${name}" is a committed template that documents key names, so it is not a valid target for set_env_values — a credential written there would be published with the repository. Write to .env or .env.local instead (it is created if missing). If you only mean to document the key name, edit the template directly.`;
1540
1317
  }
1318
+ /** Whole-word, so `NEXT_PUBLIC_POSTHOG_KEY` (`_` is a word character) does not count. */
1319
+ const LEGACY_KEY_USE = /\bPOSTHOG_KEY\b/;
1320
+ /** Files where a project reads or defines an env var: source, config, env, shell and build files. */
1321
+ const LEGACY_KEY_SCAN_FILE = /^(\.env.*|Dockerfile.*|Makefile|Procfile|package\.json|app\.json|eas\.json|.*\.[cm]?[jt]sx?|.*\.(vue|svelte|astro|py|rb|php|go|rs|exs?|java|kts?|swift|dart|cs|ya?ml|toml|sh|bash|gradle|properties|xcconfig|plist))$/;
1322
+ function projectReadsLegacyKey(workingDirectory) {
1323
+ let found = false;
1324
+ walkProjectFiles(workingDirectory, (name, fullPath) => {
1325
+ if (found || !LEGACY_KEY_SCAN_FILE.test(name)) return;
1326
+ const content = readProjectFile(fullPath);
1327
+ if (content !== null && LEGACY_KEY_USE.test(content)) found = true;
1328
+ }, 6);
1329
+ return found;
1330
+ }
1331
+ /**
1332
+ * `set_env_values`' refusal for the legacy `POSTHOG_KEY` name, or null. Shared
1333
+ * by both facades so the two cannot disagree about it.
1334
+ *
1335
+ * `POSTHOG_KEY` is the old name for the project token, so a new project gets
1336
+ * the canonical one (e.g. NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN). A project whose
1337
+ * code already reads `POSTHOG_KEY` keeps it: refusing there forces a rename of
1338
+ * working code, and every deploy step and CI secret that still passes the old
1339
+ * name then starts the app with an empty token.
1340
+ */
1341
+ function legacyKeyNameRefusal(workingDirectory, keys) {
1342
+ const key = keys.find((k) => k.toUpperCase() === "POSTHOG_KEY");
1343
+ if (!key || projectReadsLegacyKey(workingDirectory)) return null;
1344
+ return `Error: "${key}" is not a valid PostHog env var name. Use the key name from your framework's integration guide (e.g. NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN). POSTHOG_KEY is accepted only when the project already reads it.`;
1345
+ }
1541
1346
  /**
1542
1347
  * Escape a key before it is interpolated into the match regex below. The key
1543
1348
  * comes from the agent, and a stray metacharacter would otherwise build a
@@ -1935,11 +1740,11 @@ async function createWizardToolsServer(options) {
1935
1740
  filePath: z.string().describe(ENV_FILE_PATH_DESCRIPTION),
1936
1741
  values: z.record(z.string(), z.union([z.string(), z.object({ secretRef: z.string() })])).describe("Key → (literal string OR { secretRef } pointing to a vaulted secret)")
1937
1742
  }, (args) => {
1938
- const forbidden = Object.keys(args.values).find((k) => k.toUpperCase() === "POSTHOG_KEY");
1939
- if (forbidden) return {
1743
+ const keyRefusal = legacyKeyNameRefusal(workingDirectory, Object.keys(args.values));
1744
+ if (keyRefusal) return {
1940
1745
  content: [{
1941
1746
  type: "text",
1942
- text: `Error: "${forbidden}" is not a valid PostHog env var name. Use the project-specific key name from your framework's integration guide (e.g. NEXT_PUBLIC_POSTHOG_PROJECT_TOKEN).`
1747
+ text: keyRefusal
1943
1748
  }],
1944
1749
  isError: true
1945
1750
  };
@@ -2110,7 +1915,7 @@ async function createWizardToolsServer(options) {
2110
1915
  "single",
2111
1916
  "multi",
2112
1917
  "text"
2113
- ]).describe("'single' = pick one option, 'multi' = pick any, 'text' = free-form single-line answer"),
1918
+ ]).optional().describe(WIZARD_ASK_KIND_DESCRIPTION),
2114
1919
  options: z.array(z.object({
2115
1920
  label: z.string(),
2116
1921
  value: z.string(),
@@ -2159,7 +1964,8 @@ async function createWizardToolsServer(options) {
2159
1964
  isError: capDecision.reason !== "adjacency"
2160
1965
  };
2161
1966
  }
2162
- for (const q of args.questions) {
1967
+ const questions = resolveAskQuestionKinds(args.questions);
1968
+ for (const q of questions) {
2163
1969
  if ((q.kind === "single" || q.kind === "multi") && (!q.options || q.options.length === 0)) return {
2164
1970
  content: [{
2165
1971
  type: "text",
@@ -2176,7 +1982,7 @@ async function createWizardToolsServer(options) {
2176
1982
  };
2177
1983
  }
2178
1984
  const ids = /* @__PURE__ */ new Set();
2179
- for (const q of args.questions) {
1985
+ for (const q of questions) {
2180
1986
  if (ids.has(q.id)) return {
2181
1987
  content: [{
2182
1988
  type: "text",
@@ -2188,16 +1994,20 @@ async function createWizardToolsServer(options) {
2188
1994
  }
2189
1995
  askAccounting.record(args.subject);
2190
1996
  try {
2191
- const answers = await askBridge.request({
2192
- questions: args.questions,
1997
+ const { answers, timedOut } = await askBridge.request({
1998
+ questions,
2193
1999
  subject: normaliseAskSubject(args.subject)
2194
2000
  });
2195
2001
  if (isFullyCancelled(answers)) askAccounting.refund(args.subject);
2196
- const sanitised = vaultSensitiveAnswers(args.questions, answers, secretVault);
2197
- logToFile(`wizard_ask: resolved ${Object.keys(answers).length} answer(s) for ${args.questions.length} question(s)`);
2002
+ const sanitised = vaultSensitiveAnswers(questions, answers, secretVault);
2003
+ const cancelled = describeAskCancellation(sanitised, timedOut);
2004
+ logToFile(`wizard_ask: resolved ${Object.keys(answers).length} answer(s) for ${args.questions.length} question(s)${cancelled ? `, cancelled: ${cancelled.reason}` : ""}`);
2198
2005
  return { content: [{
2199
2006
  type: "text",
2200
- text: JSON.stringify({ answers: sanitised }, null, 2)
2007
+ text: JSON.stringify({
2008
+ answers: sanitised,
2009
+ ...cancelled ? { cancelled } : {}
2010
+ }, null, 2)
2201
2011
  }] };
2202
2012
  } catch (err) {
2203
2013
  askAccounting.refund(args.subject);
@@ -2247,9 +2057,8 @@ const GATEWAY_PROVIDER = "posthog-gateway";
2247
2057
  * OpenAI models take the Responses API because OpenAI rejects function tools
2248
2058
  * combined with `reasoning_effort` on chat completions and every task sends both.
2249
2059
  */
2250
- function gatewayApiFor(modelId, legacy) {
2251
- if (!modelId.startsWith("openai/")) return "anthropic-messages";
2252
- return legacy ? "openai-completions" : "openai-responses";
2060
+ function gatewayApiFor(modelId) {
2061
+ return modelId.startsWith("openai/") ? "openai-responses" : "anthropic-messages";
2253
2062
  }
2254
2063
  /**
2255
2064
  * Gateway HTTP headers, mirroring `buildAgentEnv` on the anthropic path: one
@@ -2257,10 +2066,10 @@ function gatewayApiFor(modelId, legacy) {
2257
2066
  * plus the 1M context beta, since pi otherwise runs at 200k and overflows on
2258
2067
  * larger projects (the post-run compaction failures).
2259
2068
  */
2260
- function buildGatewayHeaders(wizardMetadata, wizardFlags, teamId, legacy) {
2069
+ function buildGatewayHeaders(wizardMetadata, wizardFlags, teamId) {
2261
2070
  return {
2262
2071
  "anthropic-beta": "context-1m-2025-08-07",
2263
- ...legacy ? legacyGatewayHeaders(wizardMetadata, wizardFlags) : { "X-PostHog-Properties": buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId) }
2072
+ "X-PostHog-Properties": buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId)
2264
2073
  };
2265
2074
  }
2266
2075
  /**
@@ -2269,8 +2078,8 @@ function buildGatewayHeaders(wizardMetadata, wizardFlags, teamId, legacy) {
2269
2078
  * callers (scan triage) hand it straight to `completeSimple`.
2270
2079
  */
2271
2080
  function buildGatewayModel(inputs) {
2272
- const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId, legacy } = inputs;
2273
- const api = gatewayApiFor(modelId, legacy);
2081
+ const { gatewayUrl, wizardMetadata, wizardFlags, modelId, teamId } = inputs;
2082
+ const api = gatewayApiFor(modelId);
2274
2083
  return {
2275
2084
  id: modelId,
2276
2085
  name: `${modelId} (PostHog Gateway)`,
@@ -2287,7 +2096,7 @@ function buildGatewayModel(inputs) {
2287
2096
  },
2288
2097
  contextWindow: 1e6,
2289
2098
  maxTokens: 64e3,
2290
- headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId, legacy)
2099
+ headers: buildGatewayHeaders(wizardMetadata, wizardFlags, teamId)
2291
2100
  };
2292
2101
  }
2293
2102
  /**
@@ -2295,8 +2104,8 @@ function buildGatewayModel(inputs) {
2295
2104
  * plus the derived traits the session setup needs (`caps.thinkingLevel`).
2296
2105
  */
2297
2106
  function buildGatewayProvider(inputs) {
2298
- const { gatewayUrl, accessToken, modelId, effort, legacy } = inputs;
2299
- const api = gatewayApiFor(modelId, legacy);
2107
+ const { gatewayUrl, accessToken, modelId, effort } = inputs;
2108
+ const api = gatewayApiFor(modelId);
2300
2109
  const tableCaps = modelCapabilities(modelId);
2301
2110
  const caps = effort && effort !== "off" && tableCaps.reasoning ? modelCapabilities(modelId, effort) : effort === "off" && tableCaps.reasoning ? {
2302
2111
  ...tableCaps,
@@ -2391,7 +2200,6 @@ function createTriageLLMProvider(auth, harness) {
2391
2200
  gatewayUrl: current.baseURL,
2392
2201
  accessToken: authToken,
2393
2202
  teamId: current.teamId,
2394
- legacy: current.legacy,
2395
2203
  wizardMetadata: current.wizardMetadata ?? {},
2396
2204
  wizardFlags: current.wizardFlags ?? {},
2397
2205
  modelId
@@ -3260,13 +3068,11 @@ function isWarlockDisabled() {
3260
3068
  /**
3261
3069
  * Build ANTHROPIC_CUSTOM_HEADERS for the SDK subprocess: the run's metadata and
3262
3070
  * flags as one `X-PostHog-Properties` JSON blob. Bedrock fallback is native to
3263
- * the gateway, so there is no opt-in header. The CI fallback sends the legacy
3264
- * gateway's shape instead.
3071
+ * the gateway, so there is no opt-in header.
3265
3072
  */
3266
- function buildAgentEnv(wizardMetadata, wizardFlags, auth) {
3073
+ function buildAgentEnv(wizardMetadata, wizardFlags, teamId) {
3267
3074
  const headers = createCustomHeaders();
3268
- const shaped = auth.legacy ? legacyGatewayHeaders(wizardMetadata, wizardFlags) : { "X-PostHog-Properties": buildWizardPropertiesBlob(wizardMetadata, wizardFlags, auth.teamId) };
3269
- for (const [key, value] of Object.entries(shaped)) headers.add(key, value);
3075
+ headers.add("X-PostHog-Properties", buildWizardPropertiesBlob(wizardMetadata, wizardFlags, teamId));
3270
3076
  const encoded = headers.encode();
3271
3077
  logToFile("ANTHROPIC_CUSTOM_HEADERS", encoded);
3272
3078
  return encoded;
@@ -3376,7 +3182,6 @@ async function initializeAgent(config, options) {
3376
3182
  baseURL: current.gatewayUrl,
3377
3183
  authToken: current.token,
3378
3184
  teamId: current.teamId,
3379
- legacy: current.legacy,
3380
3185
  wizardMetadata: triageMetadata,
3381
3186
  wizardFlags: config.wizardFlags ?? {}
3382
3187
  };
@@ -3622,7 +3427,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
3622
3427
  CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS: "true",
3623
3428
  POSTHOG_MCP_TOKEN: agentConfig.posthogApiKey,
3624
3429
  MCP_CONNECTION_NONBLOCKING: "0",
3625
- ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}, agentConfig.gatewayAuth)
3430
+ ANTHROPIC_CUSTOM_HEADERS: buildAgentEnv(agentConfig.wizardMetadata ?? {}, agentConfig.wizardFlags ?? {}, agentConfig.gatewayAuth.teamId)
3626
3431
  },
3627
3432
  canUseTool: (toolName, input) => {
3628
3433
  logToFile("canUseTool called:", {
@@ -4146,6 +3951,6 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
4146
3951
  }
4147
3952
  }
4148
3953
  //#endregion
4149
- export { WIZARD_TOOL_NAMES as A, templateEnvWriteRefusal as B, publishHandoff as C, WIZARD_ASK_SENSITIVE_DESCRIPTION as D, ENV_FILE_PATH_DESCRIPTION as E, installSkillById as F, gatewayAuth as G, fetchWithRetry as H, mergeEnvValues as I, isEnvFileName as J, setLegacyGatewayFallback as K, normaliseAskSubject as L, createAskAccounting as M, downloadSkill as N, WIZARD_ASK_SUBJECT_DESCRIPTION as O, fetchSkillMenu as P, resolveEnvPath as R, PUBLISH_HANDOFF_TOOL_NAME as S, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as T, createWizardAskBridge as U, vaultSensitiveAnswers as V, isFullyCancelled as W, toPromptSafeRelativePath as X, parseEnvKeyNames as Y, markGrantRevoked as Z, buildGatewayProvider as _, wizardCanUseTool as a, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as b, checkAllSettingsConflicts as c, restoreClaudeSettings as d, sanitizeAgentSubprocessEnv as f, GATEWAY_PROVIDER as g, createTriageLLMProvider as h, runAgent as i, checkEnvKeys as j, WIZARD_ASK_TOOL_DESCRIPTION as k, classifySettingsConflicts as l, assembleCommandments as m, buildRunTags as n, createIsolatedAgentConfigDir as o, AgentOutputSignals as p, MAX_ENV_KEY_SET as q, initializeAgent as r, backupAndFixClaudeSettings as s, buildAgentEnv as t, recoverOrphanedSettingsBackups as u, withGatewayRemint as v, CHECK_ENV_KEYS_DESCRIPTION as w, PUBLISH_HANDOFF_DESCRIPTION as x, createSecretVault as y, resolveEnvSecretRefs as z };
3954
+ export { parseEnvKeyNames as $, WIZARD_ASK_TOOL_DESCRIPTION as A, mergeEnvValues as B, publishHandoff as C, WIZARD_ASK_KIND_DESCRIPTION as D, ENV_FILE_PATH_DESCRIPTION as E, downloadSkill as F, templateEnvWriteRefusal as G, resolveAskQuestionKinds as H, ensureGitignoreCoverage as I, LONGER_ASK_TIMEOUT_MS as J, vaultSensitiveAnswers as K, fetchSkillMenu as L, checkEnvKeys as M, createAskAccounting as N, WIZARD_ASK_SENSITIVE_DESCRIPTION as O, describeAskCancellation as P, isEnvFileName as Q, installSkillById as R, PUBLISH_HANDOFF_TOOL_NAME as S, CHECK_ENV_KEYS_FILE_PATH_DESCRIPTION as T, resolveEnvPath as U, normaliseAskSubject as V, resolveEnvSecretRefs as W, isFullyCancelled as X, createWizardAskBridge as Y, MAX_ENV_KEY_SET as Z, buildGatewayProvider as _, wizardCanUseTool as a, PUBLISH_HANDOFF_CONTENT_DESCRIPTION as b, checkAllSettingsConflicts as c, restoreClaudeSettings as d, toPromptSafeRelativePath as et, sanitizeAgentSubprocessEnv as f, GATEWAY_PROVIDER as g, createTriageLLMProvider as h, runAgent as i, WIZARD_TOOL_NAMES as j, WIZARD_ASK_SUBJECT_DESCRIPTION as k, classifySettingsConflicts as l, assembleCommandments as m, buildRunTags as n, createIsolatedAgentConfigDir as o, AgentOutputSignals as p, fetchWithRetry as q, initializeAgent as r, backupAndFixClaudeSettings as s, buildAgentEnv as t, markGrantRevoked as tt, recoverOrphanedSettingsBackups as u, withGatewayRemint as v, CHECK_ENV_KEYS_DESCRIPTION as w, PUBLISH_HANDOFF_DESCRIPTION as x, createSecretVault as y, legacyKeyNameRefusal as z };
4150
3955
 
4151
- //# sourceMappingURL=agent-interface-lCIi_alS.js.map
3956
+ //# sourceMappingURL=agent-interface-BKLTDSyN.js.map