@posthog/wizard 2.37.0 → 2.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/{add-mcp-server-to-clients-CNn9br9l.js → add-mcp-server-to-clients-BB1_aH5M.js} +5 -5
  2. package/dist/{add-mcp-server-to-clients-CNn9br9l.js.map → add-mcp-server-to-clients-BB1_aH5M.js.map} +1 -1
  3. package/dist/{agent-interface-D8jnkEnB.js → agent-interface-kOuzXg84.js} +69 -1119
  4. package/dist/agent-interface-kOuzXg84.js.map +1 -0
  5. package/dist/{agent-runner-BxIYcxmA.js → agent-runner-DZhaiwD5.js} +2571 -1648
  6. package/dist/agent-runner-DZhaiwD5.js.map +1 -0
  7. package/dist/analytics-B1SC2jaf.js +2 -0
  8. package/dist/{analytics-Du8Z_3oX.js → analytics-Z_2kCTpB.js} +4 -3
  9. package/dist/{analytics-Du8Z_3oX.js.map → analytics-Z_2kCTpB.js.map} +1 -1
  10. package/dist/{api-BqKMQVhj.js → api-CwhOyprf.js} +3 -3
  11. package/dist/{api-BqKMQVhj.js.map → api-CwhOyprf.js.map} +1 -1
  12. package/dist/bin.js +64 -50
  13. package/dist/bin.js.map +1 -1
  14. package/dist/{ci-install-UlWb3u5t.js → ci-install-CWDY86uB.js} +4 -4
  15. package/dist/{ci-install-UlWb3u5t.js.map → ci-install-CWDY86uB.js.map} +1 -1
  16. package/dist/{debug-B4AH8Ahp.js → debug-BmdpjMub.js} +1 -1
  17. package/dist/{debug-CZwmzyDx.js → debug-CaRHQrDY.js} +91 -13
  18. package/dist/debug-CaRHQrDY.js.map +1 -0
  19. package/dist/{defaults-UswXMiTx.js → defaults-a0e6IRjP.js} +1 -1
  20. package/dist/{defaults-UswXMiTx.js.map → defaults-a0e6IRjP.js.map} +1 -1
  21. package/dist/{env-api-key-Db-mNPK2.js → env-api-key-DEl3LJBv.js} +1 -1
  22. package/dist/{env-api-key-Db-mNPK2.js.map → env-api-key-DEl3LJBv.js.map} +1 -1
  23. package/dist/{environment-BRXwshJO.js → environment-knibpXF2.js} +3 -3
  24. package/dist/{environment-BRXwshJO.js.map → environment-knibpXF2.js.map} +1 -1
  25. package/dist/{file-utils-D6CWLaOm.js → file-utils-DWYX_G1o.js} +2 -2
  26. package/dist/{file-utils-D6CWLaOm.js.map → file-utils-DWYX_G1o.js.map} +1 -1
  27. package/dist/{headless-ui-DvkogF0b.js → headless-ui-C4JCi9Zz.js} +2 -2
  28. package/dist/{headless-ui-DvkogF0b.js.map → headless-ui-C4JCi9Zz.js.map} +1 -1
  29. package/dist/{host-resolution-DrOzdKdY.js → host-resolution-C18FwVrM.js} +3 -3
  30. package/dist/{host-resolution-DrOzdKdY.js.map → host-resolution-C18FwVrM.js.map} +1 -1
  31. package/dist/{interactive-CXL8oJwb.js → interactive-46qgS-UA.js} +2 -2
  32. package/dist/{interactive-CXL8oJwb.js.map → interactive-46qgS-UA.js.map} +1 -1
  33. package/dist/mcp-QWL5Obf3.js +108 -0
  34. package/dist/mcp-QWL5Obf3.js.map +1 -0
  35. package/dist/{mcp-prompt-streaming-Dumivcgi.js → mcp-prompt-streaming-BpNkFksF.js} +5 -5
  36. package/dist/mcp-prompt-streaming-BpNkFksF.js.map +1 -0
  37. package/dist/{non-interactive-BI5b25U7.js → non-interactive-3_T1d0cj.js} +2 -2
  38. package/dist/{non-interactive-BI5b25U7.js.map → non-interactive-3_T1d0cj.js.map} +1 -1
  39. package/dist/{package-json-DCuoye-H.js → package-json-CDs1ZVKu.js} +1 -1
  40. package/dist/{package-json-DCuoye-H.js.map → package-json-CDs1ZVKu.js.map} +1 -1
  41. package/dist/{package-manager-9nhQBKAy.js → package-manager-C5VVQHQ-.js} +2 -2
  42. package/dist/{package-manager-9nhQBKAy.js.map → package-manager-C5VVQHQ-.js.map} +1 -1
  43. package/dist/{playground-DDYYs2ub.js → playground-CbzUpMuN.js} +783 -7
  44. package/dist/playground-CbzUpMuN.js.map +1 -0
  45. package/dist/{posthog-BrLFkaji.js → posthog-BESrI6-T.js} +1 -1
  46. package/dist/{posthog-BrLFkaji.js.map → posthog-BESrI6-T.js.map} +1 -1
  47. package/dist/{posthog-integration-Cx4RvC7E.js → posthog-integration-6vdi4wRB.js} +19 -18
  48. package/dist/posthog-integration-6vdi4wRB.js.map +1 -0
  49. package/dist/{provisioning-PosLaOt4.js → provisioning-DK0tS98H.js} +4 -4
  50. package/dist/{provisioning-PosLaOt4.js.map → provisioning-DK0tS98H.js.map} +1 -1
  51. package/dist/{registry-B43CNAAx.js → registry-DfXVjxsP.js} +5 -5
  52. package/dist/{registry-B43CNAAx.js.map → registry-DfXVjxsP.js.map} +1 -1
  53. package/dist/security-BMVH_bjk.js +431 -0
  54. package/dist/security-BMVH_bjk.js.map +1 -0
  55. package/dist/{setup-utils-CR8X8Fmf.js → setup-utils-v9I6PQyP.js} +192 -20
  56. package/dist/setup-utils-v9I6PQyP.js.map +1 -0
  57. package/dist/{start-tui-DeewAqJg.js → start-tui-CylEL6i_.js} +63 -38
  58. package/dist/start-tui-CylEL6i_.js.map +1 -0
  59. package/dist/{steps-CPvI-2Ms.js → steps-DQdpexNM.js} +7 -7
  60. package/dist/{steps-CPvI-2Ms.js.map → steps-DQdpexNM.js.map} +1 -1
  61. package/dist/{store-0uzey9Am.js → store-Db0X2V5D.js} +68 -6
  62. package/dist/store-Db0X2V5D.js.map +1 -0
  63. package/dist/subagent-Pk9jRXRf.js +108 -0
  64. package/dist/subagent-Pk9jRXRf.js.map +1 -0
  65. package/dist/{task-stream-DkbGqxZv.js → task-stream-rC4IEUHC.js} +3 -3
  66. package/dist/{task-stream-DkbGqxZv.js.map → task-stream-rC4IEUHC.js.map} +1 -1
  67. package/dist/tasks-B46phMJu.js +112 -0
  68. package/dist/tasks-B46phMJu.js.map +1 -0
  69. package/dist/{telemetry-DJNpvkYP.js → telemetry-BJAHymMq.js} +3 -3
  70. package/dist/{telemetry-DJNpvkYP.js.map → telemetry-BJAHymMq.js.map} +1 -1
  71. package/dist/{terminal-Bd6q58zn.js → terminal-BTQSAkC-.js} +143 -793
  72. package/dist/terminal-BTQSAkC-.js.map +1 -0
  73. package/dist/tools-C_m5knXt.js +122 -0
  74. package/dist/tools-C_m5knXt.js.map +1 -0
  75. package/dist/{urls-B1a2v93j.js → urls-BCmeQMIb.js} +2 -2
  76. package/dist/{urls-B1a2v93j.js.map → urls-BCmeQMIb.js.map} +1 -1
  77. package/dist/{wizard-abort-DyAGpw-u.js → wizard-abort-CMzW4LVM.js} +1 -1
  78. package/dist/{wizard-abort-BG8VNOI9.js → wizard-abort-DkngXmxN.js} +4 -4
  79. package/dist/{wizard-abort-BG8VNOI9.js.map → wizard-abort-DkngXmxN.js.map} +1 -1
  80. package/dist/{wizard-session-CqihOtk3.js → wizard-session-BoXAZEOf.js} +4 -1
  81. package/dist/wizard-session-BoXAZEOf.js.map +1 -0
  82. package/dist/{wizard-session-xzqycI7i.js → wizard-session-C8W_6X0j.js} +1 -1
  83. package/dist/wizard-tools-C8nVWLeI.js +1162 -0
  84. package/dist/wizard-tools-C8nVWLeI.js.map +1 -0
  85. package/dist/wizard-ui-WZ48rUgr.js.map +1 -1
  86. package/package.json +7 -2
  87. package/dist/agent-interface-D8jnkEnB.js.map +0 -1
  88. package/dist/agent-runner-BxIYcxmA.js.map +0 -1
  89. package/dist/debug-CZwmzyDx.js.map +0 -1
  90. package/dist/mcp-prompt-streaming-Dumivcgi.js.map +0 -1
  91. package/dist/playground-DDYYs2ub.js.map +0 -1
  92. package/dist/posthog-integration-Cx4RvC7E.js.map +0 -1
  93. package/dist/setup-utils-CR8X8Fmf.js.map +0 -1
  94. package/dist/start-tui-DeewAqJg.js.map +0 -1
  95. package/dist/store-0uzey9Am.js.map +0 -1
  96. package/dist/terminal-Bd6q58zn.js.map +0 -1
  97. package/dist/wizard-session-CqihOtk3.js.map +0 -1
@@ -1,21 +1,18 @@
1
1
  import { n as __require } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { B as POSTHOG_PROPERTY_HEADER_PREFIX, L as POSTHOG_FLAG_HEADER_PREFIX, Y as WIZARD_REMARK_EVENT_NAME, Z as WIZARD_USER_AGENT, a as getLogFilePath, f as skillTmpPath, nt as runtimeEnv, o as initLogFile, p as getUI, q as WIZARD_ORCHESTRATOR_FLAG_KEY, r as debug, s as logToFile, u as WIZARD_YARA_REPORT_FILE } from "./debug-CZwmzyDx.js";
3
- import { t as analytics } from "./analytics-Du8Z_3oX.js";
4
- import { t as HostResolution } from "./host-resolution-DrOzdKdY.js";
5
- import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-CqihOtk3.js";
6
- import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-BG8VNOI9.js";
2
+ import { G as POSTHOG_PROPERTY_HEADER_PREFIX, H as POSTHOG_FLAG_HEADER_PREFIX, a as getLogFilePath, ct as WIZARD_USER_AGENT, mt as runtimeEnv, nt as WIZARD_ORCHESTRATOR_FLAG_KEY, o as initLogFile, ot as WIZARD_REMARK_EVENT_NAME, p as getUI, r as debug, s as logToFile, u as WIZARD_YARA_REPORT_FILE } from "./debug-CaRHQrDY.js";
3
+ import { n as analytics } from "./analytics-Z_2kCTpB.js";
4
+ import { t as HostResolution } from "./host-resolution-C18FwVrM.js";
5
+ import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-BoXAZEOf.js";
6
+ import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-DkngXmxN.js";
7
+ import { h as AUDIT_REPORT_FILE, n as createWizardToolsServer, t as WIZARD_TOOL_NAMES } from "./wizard-tools-C8nVWLeI.js";
7
8
  import { createRequire } from "node:module";
8
9
  import * as fs$1 from "fs";
9
10
  import fs from "fs";
10
- import * as path$1 from "path";
11
11
  import path from "path";
12
12
  import { spawnSync } from "node:child_process";
13
13
  import axios from "axios";
14
- import { z } from "zod";
15
14
  import fg from "fast-glob";
16
15
  import * as os from "os";
17
- import { execFileSync } from "child_process";
18
- import { randomUUID } from "crypto";
19
16
  //#region src/utils/custom-headers.ts
20
17
  /**
21
18
  * Builds a list of custom headers for ANTHROPIC_CUSTOM_HEADERS.
@@ -180,1101 +177,6 @@ const LINTING_TOOLS = [
180
177
  "yamllint"
181
178
  ];
182
179
  //#endregion
183
- //#region src/utils/atomic-ledger.ts
184
- /**
185
- * Small shared primitives for on-disk ledgers: an atomic JSON writer and a
186
- * single-chain async mutex. Used by the audit tools and by the orchestrator
187
- * queue. Lifted here so both share one implementation.
188
- */
189
- /**
190
- * Atomically write JSON: write to a `.tmp` file then rename over the target. The
191
- * rename bumps the file's mtime in one step, which is what a file watcher polls.
192
- */
193
- function writeJsonAtomic(targetPath, data) {
194
- const tmpPath = `${targetPath}.tmp`;
195
- fs$1.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf8");
196
- fs$1.renameSync(tmpPath, targetPath);
197
- }
198
- /**
199
- * A single async mutex. Serializes read-modify-write cycles so concurrent callers
200
- * (parallel task agents, audit tool calls) never interleave a mutation.
201
- */
202
- function makeMutex() {
203
- let chain = Promise.resolve();
204
- return async function run(fn) {
205
- const next = chain.then(() => fn());
206
- chain = next.catch(() => void 0);
207
- return next;
208
- };
209
- }
210
- //#endregion
211
- //#region src/lib/programs/audit/types.ts
212
- /** Single source of truth for status glyph + color across audit views. */
213
- const AUDIT_SEVERITY_STYLE = {
214
- pending: {
215
- glyph: "◌",
216
- color: "gray"
217
- },
218
- pass: {
219
- glyph: "✔",
220
- color: "green"
221
- },
222
- error: {
223
- glyph: "✘",
224
- color: "red"
225
- },
226
- warning: {
227
- glyph: "⚠",
228
- color: "yellow"
229
- },
230
- suggestion: {
231
- glyph: "•",
232
- color: "cyan"
233
- }
234
- };
235
- const AUDIT_CHECKS_FILE = ".posthog-audit-checks.json";
236
- const AUDIT_REPORT_FILE = "posthog-audit-report.md";
237
- const AUDIT_CHECKS_KEY = "auditChecks";
238
- function getAuditChecks(session) {
239
- const raw = session.frameworkContext[AUDIT_CHECKS_KEY];
240
- return Array.isArray(raw) ? raw : [];
241
- }
242
- /**
243
- * Read the audit checks ledger off disk. Validation lives at write time —
244
- * every writer (`audit_seed_checks` / `audit_add_checks` / `audit_resolve_checks`
245
- * MCP tools, `seedAuditLedger`) zod-parses entries before the atomic write,
246
- * so by the time the file watcher fires we trust the shape and only guard
247
- * against the file not being a JSON array (corrupted / hand-edited / not yet
248
- * seeded).
249
- */
250
- function coerceAuditChecks(parsed) {
251
- return Array.isArray(parsed) ? parsed : [];
252
- }
253
- //#endregion
254
- //#region src/lib/wizard-ask-bridge.ts
255
- /**
256
- * WizardAskBridge — host-side promise broker for the `wizard_ask` MCP tool.
257
- *
258
- * The `wizard_ask` tool needs to (a) read information from the wizard
259
- * session (the active skill id, used as the analytics `source`) and
260
- * (b) drive the TUI overlay. Wiring `wizard-tools.ts` directly to either
261
- * would couple our pure-data MCP server to the runtime UI layer.
262
- *
263
- * The bridge is the seam: `wizard-tools.ts` depends on this interface,
264
- * and `agent-runner.ts` constructs an implementation that knows about
265
- * both the session and `getUI()`.
266
- */
267
- /** Sentinel returned for unanswered fields on cancellation or timeout. */
268
- const CANCELLED_SENTINEL = "__cancelled__";
269
- function buildCancelledAnswers(questions) {
270
- const out = {};
271
- for (const q of questions) out[q.id] = CANCELLED_SENTINEL;
272
- return out;
273
- }
274
- function isFullyCancelled(answers) {
275
- const values = Object.values(answers);
276
- if (values.length === 0) return false;
277
- return values.every((v) => v === CANCELLED_SENTINEL);
278
- }
279
- function createWizardAskBridge(opts) {
280
- const timeoutMs = opts.timeoutMs ?? 3e5;
281
- return { async request({ questions }) {
282
- const pending = {
283
- id: randomUUID(),
284
- questions,
285
- source: opts.getSource(),
286
- richLinks: opts.richLinks ?? false
287
- };
288
- const startedAt = Date.now();
289
- let timer;
290
- const timeoutPromise = new Promise((resolve) => {
291
- timer = setTimeout(() => {
292
- resolve(buildCancelledAnswers(questions));
293
- }, timeoutMs);
294
- });
295
- try {
296
- const answers = await Promise.race([opts.showQuestion(pending), timeoutPromise]);
297
- const durationMs = Date.now() - startedAt;
298
- if (isFullyCancelled(answers)) analytics.wizardCapture("wizard_ask cancelled", {
299
- source: pending.source,
300
- question_count: questions.length,
301
- duration_ms: durationMs,
302
- timed_out: durationMs >= timeoutMs
303
- });
304
- else analytics.wizardCapture("wizard_ask answered", {
305
- source: pending.source,
306
- question_count: questions.length,
307
- duration_ms: durationMs
308
- });
309
- return answers;
310
- } finally {
311
- if (timer) clearTimeout(timer);
312
- }
313
- } };
314
- }
315
- //#endregion
316
- //#region src/lib/secret-vault.ts
317
- /**
318
- * Session-scoped secret vault.
319
- *
320
- * Tools that handle sensitive values (personal API keys pasted by the user
321
- * or minted by the wizard, OAuth tokens, etc.) store them here and return
322
- * an opaque `secret:<uuid>` ref to the agent. The agent passes the ref
323
- * around to subsequent tools — `set_env_values` resolves it host-side
324
- * before writing — but the raw value never enters the LLM conversation.
325
- *
326
- * The vault is created once per `createWizardToolsServer` call and lives
327
- * for the duration of a single wizard run. There is no persistence and
328
- * no cross-session sharing; refs minted in one run cannot be resolved in
329
- * another.
330
- */
331
- const REF_PREFIX = "secret:";
332
- function createSecretVault() {
333
- const store = /* @__PURE__ */ new Map();
334
- return {
335
- put(value, meta) {
336
- const ref = `${REF_PREFIX}${randomUUID()}`;
337
- store.set(ref, {
338
- value,
339
- meta: {
340
- ref,
341
- label: meta.label,
342
- source: meta.source,
343
- createdAt: Date.now()
344
- }
345
- });
346
- return ref;
347
- },
348
- get(ref) {
349
- return store.get(ref)?.value;
350
- },
351
- has(ref) {
352
- return store.has(ref);
353
- },
354
- list() {
355
- return [...store.values()].map((s) => s.meta);
356
- },
357
- clear() {
358
- store.clear();
359
- }
360
- };
361
- }
362
- //#endregion
363
- //#region src/lib/agent/runner/orchestrator/queue.ts
364
- /**
365
- * The orchestrator task queue.
366
- *
367
- * In memory, synchronous, single-owner: one Node process drives the run, so
368
- * there is no locking. The queue imposes no execution policy — `nextRunnable`
369
- * returns every pending task whose dependencies are satisfied, and how many of
370
- * those run at once is decided by the task graph, not the queue.
371
- *
372
- * Every transition rewrites `<installDir>/.posthog-wizard-cache/queue.json`, a
373
- * small file holding the whole queue, handoffs included. It is the run's log
374
- * and the report's source. The whole cache folder is run-scoped and wiped when
375
- * the run ends.
376
- */
377
- const TaskStatus = {
378
- Pending: "pending",
379
- Running: "running",
380
- Done: "done",
381
- Skipped: "skipped",
382
- Failed: "failed"
383
- };
384
- const QUEUE_DIR_NAME = ".posthog-wizard-cache";
385
- const DEFAULT_MAX_ATTEMPTS = 2;
386
- function nowIso() {
387
- return (/* @__PURE__ */ new Date()).toISOString();
388
- }
389
- /** Dropped in the cache folder so an orphaned copy explains itself. */
390
- const DELETE_ME_FILE = ".DELETE-ME.md";
391
- const DELETE_ME_BODY = `# Safe to delete
392
-
393
- This folder contains run artifacts from the PostHog Wizard. This should have
394
- been deleted if the Wizard has finished running. If this wasn't deleted for
395
- some reason, you can safely delete the entire \`${QUEUE_DIR_NAME}/\` folder.
396
- `;
397
- var QueueStore = class {
398
- tasks = [];
399
- onTransition;
400
- runId;
401
- queuePath;
402
- constructor(installDir, runId, opts) {
403
- this.onTransition = opts?.onTransition;
404
- this.runId = runId;
405
- const dir = path$1.join(installDir, QUEUE_DIR_NAME);
406
- this.queuePath = path$1.join(dir, "queue.json");
407
- fs$1.mkdirSync(dir, { recursive: true });
408
- fs$1.writeFileSync(path$1.join(dir, DELETE_ME_FILE), DELETE_ME_BODY);
409
- }
410
- list() {
411
- return this.tasks;
412
- }
413
- get(id) {
414
- return this.tasks.find((t) => t.id === id);
415
- }
416
- /**
417
- * Every pending task whose dependencies are all satisfied (`done` or
418
- * `skipped`). A skipped dependency does not block downstream work.
419
- */
420
- nextRunnable() {
421
- const doneIds = new Set(this.tasks.filter((t) => t.status === TaskStatus.Done || t.status === TaskStatus.Skipped).map((t) => t.id));
422
- return this.tasks.filter((t) => t.status === TaskStatus.Pending && t.dependsOn.every((d) => doneIds.has(d)));
423
- }
424
- /**
425
- * True when no task is running and none can be started. Either everything
426
- * is terminal, or the only pending tasks are blocked by a failed dependency.
427
- */
428
- isDrained() {
429
- if (this.tasks.some((t) => t.status === TaskStatus.Running)) return false;
430
- return this.nextRunnable().length === 0;
431
- }
432
- summary() {
433
- const counts = {
434
- [TaskStatus.Pending]: 0,
435
- [TaskStatus.Running]: 0,
436
- [TaskStatus.Done]: 0,
437
- [TaskStatus.Skipped]: 0,
438
- [TaskStatus.Failed]: 0
439
- };
440
- for (const t of this.tasks) counts[t.status] += 1;
441
- return {
442
- ...counts,
443
- total: this.tasks.length
444
- };
445
- }
446
- readHandoff(id) {
447
- return this.get(id)?.handoff ?? null;
448
- }
449
- /** Handoffs of completed tasks of a given type, oldest first. */
450
- readHandoffsByType(type) {
451
- return this.tasks.filter((t) => t.type === type && t.handoff).map((t) => t.handoff);
452
- }
453
- enqueue(input) {
454
- const task = {
455
- id: randomUUID(),
456
- type: input.type,
457
- label: input.label,
458
- status: TaskStatus.Pending,
459
- dependsOn: input.dependsOn ?? [],
460
- inputs: input.inputs ?? {},
461
- model: input.model,
462
- attempts: 0,
463
- maxAttempts: input.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,
464
- enqueuedBy: input.enqueuedBy ?? "orchestrator",
465
- createdAt: nowIso()
466
- };
467
- this.tasks.push(task);
468
- this.reflect();
469
- this.notify("enqueue", task);
470
- return task;
471
- }
472
- start(id) {
473
- const t = this.require(id);
474
- t.status = TaskStatus.Running;
475
- t.startedAt = nowIso();
476
- t.attempts += 1;
477
- this.reflect();
478
- this.notify("start", t);
479
- return t;
480
- }
481
- complete(id, handoff) {
482
- return this.finish(id, TaskStatus.Done, handoff);
483
- }
484
- /** Terminal: the agent could not do the task. Not done, not failed. */
485
- skip(id, handoff) {
486
- return this.finish(id, TaskStatus.Skipped, handoff);
487
- }
488
- fail(id, error, handoff) {
489
- const t = this.require(id);
490
- t.error = error;
491
- return this.finish(id, TaskStatus.Failed, handoff);
492
- }
493
- /** Put a failed/running task back to pending for a retry within the run. */
494
- requeue(id) {
495
- const t = this.require(id);
496
- t.status = TaskStatus.Pending;
497
- t.startedAt = void 0;
498
- t.finishedAt = void 0;
499
- this.reflect();
500
- this.notify("requeue", t);
501
- return t;
502
- }
503
- finish(id, status, handoff) {
504
- const t = this.require(id);
505
- if (handoff) t.handoff = handoff;
506
- t.status = status;
507
- t.finishedAt = nowIso();
508
- this.reflect();
509
- this.notify(status === TaskStatus.Done ? "complete" : status === TaskStatus.Skipped ? "skip" : "fail", t);
510
- return t;
511
- }
512
- reflect() {
513
- const file = {
514
- version: 1,
515
- runId: this.runId,
516
- tasks: this.tasks
517
- };
518
- writeJsonAtomic(this.queuePath, file);
519
- }
520
- notify(event, task) {
521
- try {
522
- this.onTransition?.(event, task);
523
- } catch (error) {
524
- analytics.captureException(error instanceof Error ? error : new Error(String(error)), {
525
- step: "orchestrator_queue_listener",
526
- event
527
- });
528
- }
529
- }
530
- require(id) {
531
- const t = this.get(id);
532
- if (!t) throw new Error(`No task ${id} in the queue`);
533
- return t;
534
- }
535
- };
536
- //#endregion
537
- //#region src/lib/agent/runner/orchestrator/queue-tools.ts
538
- /**
539
- * Orchestrator MCP tools, registered into the existing `wizard-tools` server when
540
- * a queue is present. They let the orchestrator agent and task agents grow the
541
- * queue, report completion with a structured handoff, and read prior handoffs.
542
- *
543
- * The guard logic and the apply functions are plain, exported, and unit-tested.
544
- * `buildOrchestratorTools` wraps them in the SDK `tool()` shape.
545
- */
546
- function stableStringify(value) {
547
- if (value === null || typeof value !== "object") return JSON.stringify(value);
548
- if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
549
- return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
550
- }
551
- function dedupKey(type, inputs) {
552
- return `${type}::${stableStringify(inputs)}`;
553
- }
554
- /**
555
- * A backstop on total queue size. Tasks can enqueue tasks, so a misbehaving
556
- * type could grow the queue without bound. Keeping the graph small is the job
557
- * of good agent and skill design, not this number — it only stops a runaway.
558
- * The real flow is ~9 tasks, so this sits well clear of it.
559
- */
560
- const MAX_QUEUE_TASKS = 30;
561
- /**
562
- * Validate an enqueue. Structural checks only — a real type, real dependencies,
563
- * not a literal duplicate, and not past the runaway backstop. How much runs,
564
- * and in what shape, is the task graph's business, not a knob's.
565
- */
566
- function checkEnqueueGuards(ctx, args) {
567
- const tasks = ctx.store.list();
568
- if (tasks.length >= MAX_QUEUE_TASKS) return {
569
- ok: false,
570
- guard: "queue-full",
571
- message: `The queue already holds ${tasks.length} tasks (cap ${MAX_QUEUE_TASKS}). Refine the existing tasks rather than adding more.`
572
- };
573
- if (!ctx.validTypes.includes(args.type)) return {
574
- ok: false,
575
- guard: "unknown-type",
576
- message: `Unknown task type "${args.type}". Valid types: ${ctx.validTypes.join(", ")}.`
577
- };
578
- for (const dep of args.dependsOn ?? []) if (!ctx.store.get(dep)) return {
579
- ok: false,
580
- guard: "unknown-dep",
581
- message: `Dependency "${dep}" is not a known task id.`
582
- };
583
- const key = dedupKey(args.type, args.inputs ?? {});
584
- if (tasks.some((t) => t.status !== TaskStatus.Failed && dedupKey(t.type, t.inputs) === key)) return {
585
- ok: false,
586
- guard: "dedup",
587
- message: `A "${args.type}" task with these inputs already exists.`
588
- };
589
- return { ok: true };
590
- }
591
- function applyEnqueue(ctx, args) {
592
- const guard = checkEnqueueGuards(ctx, args);
593
- if (!guard.ok) return guard;
594
- return {
595
- ok: true,
596
- task: ctx.store.enqueue({
597
- type: args.type,
598
- label: args.label,
599
- inputs: args.inputs ?? {},
600
- dependsOn: args.dependsOn ?? [],
601
- model: args.model,
602
- enqueuedBy: ctx.currentTaskId ?? "orchestrator"
603
- })
604
- };
605
- }
606
- function applyComplete(ctx, args) {
607
- const id = ctx.currentTaskId;
608
- if (!id) return {
609
- ok: false,
610
- message: "complete_task can only be called by a running task agent."
611
- };
612
- if (args.status === TaskStatus.Failed) ctx.store.fail(id, {
613
- type: "self-reported",
614
- message: args.handoff.forNextAgent
615
- }, args.handoff);
616
- else if (args.status === TaskStatus.Skipped) ctx.store.skip(id, args.handoff);
617
- else ctx.store.complete(id, args.handoff);
618
- return { ok: true };
619
- }
620
- function applyReadHandoffs(ctx, args) {
621
- if (args.taskId) {
622
- const h = ctx.store.readHandoff(args.taskId);
623
- return h ? [h] : [];
624
- }
625
- if (args.type) return ctx.store.readHandoffsByType(args.type);
626
- const currentId = ctx.currentTaskId;
627
- const current = currentId ? ctx.store.get(currentId) : void 0;
628
- if (!current) return [];
629
- return current.dependsOn.map((depId) => ctx.store.readHandoff(depId)).filter((h) => h !== null);
630
- }
631
- const HANDOFF_SHAPE = {
632
- goals: z.string().describe("What this task was asked to achieve."),
633
- did: z.string().describe("What you actually did."),
634
- forNextAgent: z.string().describe("What the next agent should know."),
635
- filesTouched: z.array(z.string()).optional(),
636
- conflict: z.string().optional().describe("A one-line summary of any conflict you could not cleanly resolve (e.g. a dependency or build conflict). Put full detail in your work; this line is surfaced to the user.")
637
- };
638
- function textResult(text, isError = false) {
639
- return {
640
- isError,
641
- content: [{
642
- type: "text",
643
- text
644
- }]
645
- };
646
- }
647
- /**
648
- * Build the orchestrator tools in the SDK `tool()` shape. Called from
649
- * createWizardToolsServer only when a queue context is present.
650
- */
651
- function buildOrchestratorTools(tool, ctx) {
652
- return [
653
- tool("enqueue_task", "Add a task to the orchestrator queue. Use it to seed work and to enqueue follow-up work you discover. Keep tasks small and discrete.", {
654
- type: z.string().describe(`The task type. One of: ${ctx.validTypes.join(", ")}.`),
655
- label: z.string().optional().describe("A short label for the UI — the action in a few words (e.g. \"Add the PostHog SDK\", \"Initialize PostHog\"). Leave out file names, class names, and other specifics."),
656
- inputs: z.record(z.unknown()).optional(),
657
- dependsOn: z.array(z.string()).optional().describe("Task ids that must be done before this task runs."),
658
- model: z.string().optional(),
659
- reason: z.string().describe("One line on why this task is needed.")
660
- }, ((args) => {
661
- const res = applyEnqueue(ctx, args);
662
- if (!res.ok) {
663
- analytics.wizardCapture("orchestrator guard tripped", {
664
- guard: res.guard,
665
- type: args.type
666
- });
667
- return textResult(res.message, true);
668
- }
669
- return textResult(JSON.stringify({ id: res.task.id }));
670
- })),
671
- tool("complete_task", "Report the outcome of your task. Always call this exactly once when you finish, with a structured handoff for the next agent. Use status 'skipped' when the task does not apply to this project and you cannot do it (say why in the handoff) — not 'done'.", {
672
- status: z.enum([
673
- "done",
674
- "failed",
675
- "skipped"
676
- ]),
677
- handoff: z.object(HANDOFF_SHAPE)
678
- }, ((args) => {
679
- const res = applyComplete(ctx, args);
680
- if (!res.ok) return textResult(res.message, true);
681
- return textResult("ok");
682
- })),
683
- tool("read_handoffs", "Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.", {
684
- type: z.string().optional(),
685
- taskId: z.string().optional()
686
- }, ((args) => {
687
- const handoffs = applyReadHandoffs(ctx, args);
688
- return textResult(JSON.stringify(handoffs, null, 2));
689
- }))
690
- ];
691
- }
692
- //#endregion
693
- //#region src/lib/wizard-tools.ts
694
- /**
695
- * Unified in-process MCP server for the PostHog wizard.
696
- *
697
- * Provides tools that run locally (secret values never leave the machine):
698
- * - check_env_keys: Check which env var keys exist in a .env file
699
- * - set_env_values: Create/update env vars in a .env file
700
- * - detect_package_manager: Detect the project's package manager(s)
701
- * - load_skill_menu / install_skill: Skill installation
702
- * - audit_seed_checks / audit_add_checks / audit_resolve_checks: Audit ledger ownership
703
- */
704
- let _sdkModule$1 = null;
705
- async function getSDKModule$1() {
706
- if (!_sdkModule$1) _sdkModule$1 = await import("@anthropic-ai/claude-agent-sdk");
707
- return _sdkModule$1;
708
- }
709
- /**
710
- * Fetch the skill menu from the skills server.
711
- * Returns parsed data on success, `null` on failure.
712
- */
713
- async function fetchSkillMenu(skillsBaseUrl) {
714
- try {
715
- const menuUrl = `${skillsBaseUrl}/skill-menu.json`;
716
- logToFile(`fetchSkillMenu: fetching from ${menuUrl}`);
717
- const resp = await fetch(menuUrl);
718
- if (resp.ok) {
719
- const data = await resp.json();
720
- logToFile(`fetchSkillMenu: loaded (${Object.keys(data.categories).length} categories)`);
721
- return data;
722
- }
723
- logToFile(`fetchSkillMenu: failed with HTTP ${resp.status}`);
724
- return null;
725
- } catch (err) {
726
- logToFile(`fetchSkillMenu: error: ${err.message}`);
727
- return null;
728
- }
729
- }
730
- /**
731
- * Download and extract a skill.
732
- * By default installs to `<installDir>/.claude/skills/<id>/`.
733
- * Pass `skillsRoot` to override the base directory (e.g. `.posthog/skills`).
734
- */
735
- function downloadSkill(skillEntry, installDir, skillsRoot) {
736
- const skillDir = skillsRoot ? path.join(installDir, skillsRoot, skillEntry.id) : path.join(installDir, ".claude", "skills", skillEntry.id);
737
- const tmpFile = skillTmpPath(skillEntry.id);
738
- try {
739
- fs.mkdirSync(skillDir, { recursive: true });
740
- execFileSync("curl", [
741
- "-sL",
742
- skillEntry.downloadUrl,
743
- "-o",
744
- tmpFile
745
- ], { timeout: 3e4 });
746
- execFileSync("unzip", [
747
- "-o",
748
- tmpFile,
749
- "-d",
750
- skillDir
751
- ], { timeout: 3e4 });
752
- fs.writeFileSync(path.join(skillDir, ".posthog-wizard"), "");
753
- try {
754
- fs.unlinkSync(tmpFile);
755
- } catch {}
756
- logToFile(`downloadSkill: installed ${skillEntry.id} from ${skillEntry.downloadUrl}`);
757
- return { success: true };
758
- } catch (err) {
759
- logToFile(`downloadSkill: error: ${err.message}`);
760
- return {
761
- success: false,
762
- error: err.message
763
- };
764
- }
765
- }
766
- /**
767
- * High-level "install a skill by ID" helper. Fetches the skill menu,
768
- * finds the skill, downloads and extracts it. Programs should use this
769
- * instead of composing fetchSkillMenu + downloadSkill themselves.
770
- */
771
- async function installSkillById(skillId, installDir, skillsBaseUrl, skillsRoot) {
772
- const menu = await fetchSkillMenu(skillsBaseUrl);
773
- if (!menu) return { kind: "menu-fetch-failed" };
774
- const skill = Object.values(menu.categories).flat().find((s) => s.id === skillId);
775
- if (!skill) return {
776
- kind: "skill-not-found",
777
- skillId
778
- };
779
- const result = downloadSkill(skill, installDir, skillsRoot);
780
- if (!result.success) return {
781
- kind: "download-failed",
782
- message: result.error ?? "unknown"
783
- };
784
- return {
785
- kind: "ok",
786
- path: skillsRoot ? `${skillsRoot}/${skillId}` : `.claude/skills/${skillId}`
787
- };
788
- }
789
- /**
790
- * Pure decision function for the wizard_ask caps. Returns whether the
791
- * upcoming call should proceed and, if not, the error message to surface
792
- * to the agent. Extracted so the policy can be unit-tested without
793
- * spinning up an MCP server.
794
- *
795
- * The adjacency nudge fires exactly once per run (the caller records it
796
- * via `adjacencyNudged`) — flows that legitimately need several
797
- * sequential, answer-dependent asks then proceed up to `maxQuestions`.
798
- * Without the flag the rejected call would never advance the counter and
799
- * every later call would be rejected, making caps above the threshold
800
- * unreachable.
801
- */
802
- function evaluateAskCap(callCount, maxQuestions, adjacencyNudged = false) {
803
- if (callCount >= maxQuestions) return {
804
- kind: "capped",
805
- reason: "max_questions",
806
- message: `Error: wizard_ask cap reached (${maxQuestions} calls in this run). Proceed with sensible defaults using the answers you already have, or emit [ABORT] requirements-incomplete.`
807
- };
808
- if (!adjacencyNudged && callCount >= 3) return {
809
- kind: "capped",
810
- reason: "adjacency",
811
- message: `Error: too many wizard_ask calls in a row (${callCount} so far). Batch the remaining questions into a single call — the schema accepts up to 8 questions per invocation. If the remaining questions truly depend on earlier answers, ask again and they will go through.`
812
- };
813
- return { kind: "ok" };
814
- }
815
- /**
816
- * Resolve filePath relative to workingDirectory, rejecting path traversal.
817
- */
818
- function resolveEnvPath(workingDirectory, filePath) {
819
- const resolved = path.resolve(workingDirectory, filePath);
820
- if (!resolved.startsWith(workingDirectory + path.sep) && resolved !== workingDirectory) throw new Error(`Path traversal rejected: "${filePath}" resolves outside working directory`);
821
- return resolved;
822
- }
823
- /**
824
- * Ensure the given env file basename is covered by .gitignore in the working directory.
825
- * Creates .gitignore if it doesn't exist; appends the entry if missing.
826
- */
827
- function ensureGitignoreCoverage(workingDirectory, envFileName) {
828
- const gitignorePath = path.join(workingDirectory, ".gitignore");
829
- if (fs.existsSync(gitignorePath)) {
830
- const content = fs.readFileSync(gitignorePath, "utf8");
831
- if (content.split("\n").some((line) => line.trim() === envFileName)) return;
832
- const newContent = content.endsWith("\n") ? `${content}${envFileName}\n` : `${content}\n${envFileName}\n`;
833
- fs.writeFileSync(gitignorePath, newContent, "utf8");
834
- } else fs.writeFileSync(gitignorePath, `${envFileName}\n`, "utf8");
835
- }
836
- /**
837
- * Parse a .env file's content and return the set of defined key names.
838
- */
839
- function parseEnvKeys(content) {
840
- const keys = /* @__PURE__ */ new Set();
841
- for (const line of content.split("\n")) {
842
- const match = line.match(/^\s*([A-Za-z_][A-Za-z0-9_]*)\s*=/);
843
- if (match) keys.add(match[1]);
844
- }
845
- return keys;
846
- }
847
- /**
848
- * Merge key-value pairs into existing .env content.
849
- * Updates existing keys in-place, appends new keys at the end.
850
- */
851
- function mergeEnvValues(content, values) {
852
- let result = content;
853
- const updatedKeys = /* @__PURE__ */ new Set();
854
- for (const [key, value] of Object.entries(values)) {
855
- const regex = new RegExp(`^(\\s*${key}\\s*=).*$`, "m");
856
- if (regex.test(result)) {
857
- result = result.replace(regex, `$1${value}`);
858
- updatedKeys.add(key);
859
- }
860
- }
861
- const newKeys = Object.entries(values).filter(([key]) => !updatedKeys.has(key));
862
- if (newKeys.length > 0) {
863
- if (result.length > 0 && !result.endsWith("\n")) result += "\n";
864
- for (const [key, value] of newKeys) result += `${key}=${value}\n`;
865
- }
866
- return result;
867
- }
868
- const AUDIT_STATUSES = [
869
- "pending",
870
- "pass",
871
- "error",
872
- "warning",
873
- "suggestion"
874
- ];
875
- const auditCheckSchema = z.object({
876
- id: z.string().min(1),
877
- area: z.string().min(1),
878
- label: z.string().min(1),
879
- status: z.enum(AUDIT_STATUSES),
880
- file: z.string().optional(),
881
- details: z.string().optional()
882
- });
883
- const auditUpdateSchema = z.object({
884
- id: z.string().min(1),
885
- status: z.enum(AUDIT_STATUSES),
886
- file: z.string().optional(),
887
- details: z.string().optional()
888
- });
889
- /** Atomically write the audit ledger. Thin typed wrapper over writeJsonAtomic. */
890
- function writeLedgerAtomic(targetPath, checks) {
891
- writeJsonAtomic(targetPath, checks);
892
- }
893
- /**
894
- * Apply a batch of patches to the ledger by id. Returns the new array and the
895
- * list of update ids that didn't match any existing check.
896
- */
897
- function applyAuditUpdates(current, updates) {
898
- const byId = new Map(current.map((c) => [c.id, c]));
899
- const unknown = [];
900
- for (const u of updates) {
901
- const existing = byId.get(u.id);
902
- if (!existing) {
903
- unknown.push(u.id);
904
- continue;
905
- }
906
- byId.set(u.id, {
907
- ...existing,
908
- status: u.status,
909
- ...u.file !== void 0 ? { file: u.file } : {},
910
- ...u.details !== void 0 ? { details: u.details } : {}
911
- });
912
- }
913
- return {
914
- next: current.map((c) => byId.get(c.id) ?? c),
915
- unknown
916
- };
917
- }
918
- /**
919
- * Append new checks to a seeded ledger. Duplicate ids are reported without
920
- * mutating the current ledger, including duplicates inside the additions.
921
- */
922
- function applyAuditAdditions(current, additions) {
923
- const existingIds = new Set(current.map((c) => c.id));
924
- const additionIds = /* @__PURE__ */ new Set();
925
- const duplicates = [];
926
- for (const check of additions) {
927
- if (existingIds.has(check.id) || additionIds.has(check.id)) {
928
- duplicates.push(check.id);
929
- continue;
930
- }
931
- additionIds.add(check.id);
932
- }
933
- if (duplicates.length > 0) return {
934
- next: current,
935
- duplicates
936
- };
937
- return {
938
- next: [...current, ...additions],
939
- duplicates: []
940
- };
941
- }
942
- function readLedger(targetPath) {
943
- if (!fs.existsSync(targetPath)) return [];
944
- try {
945
- return coerceAuditChecks(JSON.parse(fs.readFileSync(targetPath, "utf8")));
946
- } catch {
947
- return [];
948
- }
949
- }
950
- function appendAuditChecksToLedger(targetPath, additions) {
951
- if (!fs.existsSync(targetPath)) return {
952
- ok: false,
953
- reason: "missing-ledger"
954
- };
955
- const { next, duplicates } = applyAuditAdditions(readLedger(targetPath), additions);
956
- if (duplicates.length > 0) return {
957
- ok: false,
958
- reason: "duplicate-ids",
959
- ids: duplicates
960
- };
961
- writeLedgerAtomic(targetPath, next);
962
- return {
963
- ok: true,
964
- added: additions.length
965
- };
966
- }
967
- const SERVER_NAME = "wizard-tools";
968
- /**
969
- * Create the unified in-process MCP server with all wizard tools.
970
- * Must be called asynchronously because the SDK is an ESM module loaded via dynamic import.
971
- */
972
- async function createWizardToolsServer(options) {
973
- const { workingDirectory, detectPackageManager, skillsBaseUrl, askBridge, askMaxQuestions = 10, secretVault = createSecretVault(), orchestrator } = options;
974
- const { tool, createSdkMcpServer } = await getSDKModule$1();
975
- let askCallCount = 0;
976
- let askAdjacencyNudged = false;
977
- let cachedSkillMenu = {};
978
- let categoryNames = ["integration"];
979
- const menu = await fetchSkillMenu(skillsBaseUrl);
980
- if (menu) cachedSkillMenu = menu.categories;
981
- const keys = Object.keys(cachedSkillMenu);
982
- if (keys.length > 0) categoryNames = keys;
983
- const checkEnvKeys = tool("check_env_keys", "Check which environment variable keys are present or missing in a .env file. Never reveals values.", {
984
- filePath: z.string().describe("Path to the .env file, relative to the project root"),
985
- keys: z.array(z.string()).describe("Environment variable key names to check")
986
- }, (args) => {
987
- const resolved = resolveEnvPath(workingDirectory, args.filePath);
988
- logToFile(`check_env_keys: ${resolved}, keys: ${args.keys.join(", ")}`);
989
- const existingKeys = fs.existsSync(resolved) ? parseEnvKeys(fs.readFileSync(resolved, "utf8")) : /* @__PURE__ */ new Set();
990
- const results = {};
991
- for (const key of args.keys) results[key] = existingKeys.has(key) ? "present" : "missing";
992
- return { content: [{
993
- type: "text",
994
- text: JSON.stringify(results, null, 2)
995
- }] };
996
- });
997
- const setEnvValues = tool("set_env_values", "Create or update environment variable keys in a .env file. Creates the file if it does not exist. Ensures .gitignore coverage. Each value can be either a literal string or a secret reference of the form `{ \"secretRef\": \"secret:...\" }` returned by another tool (e.g. wizard_ask). Secret references are resolved locally — the actual value is written to the file but never returned to the agent.", {
998
- filePath: z.string().describe("Path to the .env file, relative to the project root"),
999
- 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)")
1000
- }, (args) => {
1001
- const forbidden = Object.keys(args.values).find((k) => k.toUpperCase() === "POSTHOG_KEY");
1002
- if (forbidden) return {
1003
- content: [{
1004
- type: "text",
1005
- 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).`
1006
- }],
1007
- isError: true
1008
- };
1009
- const resolvedValues = {};
1010
- const resolvedRefKeys = [];
1011
- for (const [key, val] of Object.entries(args.values)) if (typeof val === "string") resolvedValues[key] = val;
1012
- else {
1013
- const secret = secretVault.get(val.secretRef);
1014
- if (secret === void 0) return {
1015
- content: [{
1016
- type: "text",
1017
- text: `Error: secret reference "${val.secretRef}" for key "${key}" is not known to the vault. The ref may have expired, been minted in a different run, or been mistyped.`
1018
- }],
1019
- isError: true
1020
- };
1021
- resolvedValues[key] = secret;
1022
- resolvedRefKeys.push(key);
1023
- }
1024
- const resolved = resolveEnvPath(workingDirectory, args.filePath);
1025
- logToFile(`set_env_values: ${resolved}, keys: ${Object.keys(resolvedValues).join(", ")}${resolvedRefKeys.length > 0 ? ` (secret refs: ${resolvedRefKeys.join(", ")})` : ""}`);
1026
- const content = mergeEnvValues(fs.existsSync(resolved) ? fs.readFileSync(resolved, "utf8") : "", resolvedValues);
1027
- const dir = path.dirname(resolved);
1028
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
1029
- fs.writeFileSync(resolved, content, "utf8");
1030
- ensureGitignoreCoverage(workingDirectory, path.basename(resolved));
1031
- return { content: [{
1032
- type: "text",
1033
- text: `Updated ${Object.keys(args.values).length} key(s) in ${args.filePath}`
1034
- }] };
1035
- });
1036
- const detectPM = tool("detect_package_manager", "Detect which package manager(s) the project uses. Returns the name, install command, and run command for each detected package manager. Call this before running any install commands.", {}, async () => {
1037
- logToFile(`detect_package_manager: scanning ${workingDirectory}`);
1038
- const result = await detectPackageManager(workingDirectory);
1039
- logToFile(`detect_package_manager: detected ${result.detected.length} package manager(s)`);
1040
- return { content: [{
1041
- type: "text",
1042
- text: JSON.stringify(result, null, 2)
1043
- }] };
1044
- });
1045
- const loadSkillMenu = tool("load_skill_menu", "Load available PostHog skills for a category. Returns skill IDs and names. Call this first, then use install_skill with the chosen ID.", { category: z.enum(categoryNames).describe("Skill category") }, (args) => {
1046
- const skills = cachedSkillMenu[args.category];
1047
- if (!skills || skills.length === 0) return {
1048
- content: [{
1049
- type: "text",
1050
- text: `No skills found for category "${args.category}".`
1051
- }],
1052
- isError: true
1053
- };
1054
- const menuText = skills.map((s) => `- ${s.id}: ${s.name}`).join("\n");
1055
- logToFile(`load_skill_menu: returning ${skills.length} skills for "${args.category}"`);
1056
- return { content: [{
1057
- type: "text",
1058
- text: menuText
1059
- }] };
1060
- });
1061
- const installSkill = tool("install_skill", "Download and install a PostHog skill by ID. Call load_skill_menu first to see available skills. Extracts the skill to .claude/skills/<skillId>/.", { skillId: z.string().describe("Skill ID from the skill menu (e.g., \"integration-nextjs-app-router\")") }, (args) => {
1062
- if (!/^[a-z0-9][a-z0-9_-]*$/.test(args.skillId)) return {
1063
- content: [{
1064
- type: "text",
1065
- text: "Error: skillId must be lowercase alphanumeric with hyphens."
1066
- }],
1067
- isError: true
1068
- };
1069
- const skill = Object.values(cachedSkillMenu).flat().find((s) => s.id === args.skillId);
1070
- if (!skill) return {
1071
- content: [{
1072
- type: "text",
1073
- text: `Error: skill "${args.skillId}" not found. Use load_skill_menu to see available skills.`
1074
- }],
1075
- isError: true
1076
- };
1077
- const result = downloadSkill(skill, workingDirectory);
1078
- if (result.success) return { content: [{
1079
- type: "text",
1080
- text: `Skill installed to .claude/skills/${args.skillId}/`
1081
- }] };
1082
- else return {
1083
- content: [{
1084
- type: "text",
1085
- text: `Error installing skill: ${result.error}`
1086
- }],
1087
- isError: true
1088
- };
1089
- });
1090
- const auditLedgerPath = path.join(workingDirectory, AUDIT_CHECKS_FILE);
1091
- const auditMutex = makeMutex();
1092
- const auditSeedChecks = tool("audit_seed_checks", "Seed the audit ledger at .posthog-audit-checks.json with the full set of pending checks. Call this once at the start of the audit. Atomically replaces any existing ledger.", { checks: z.array(auditCheckSchema).describe("Full pending checklist to write to the ledger") }, async (args) => {
1093
- return auditMutex(() => {
1094
- writeLedgerAtomic(auditLedgerPath, args.checks);
1095
- logToFile(`audit_seed_checks: wrote ${args.checks.length} entries`);
1096
- return { content: [{
1097
- type: "text",
1098
- text: `Seeded ${args.checks.length} audit checks.`
1099
- }] };
1100
- });
1101
- });
1102
- const auditAddChecks = tool("audit_add_checks", "Append one or more pending checks to the existing audit ledger at .posthog-audit-checks.json. Call audit_seed_checks first. Atomically rejects duplicate ids without changing the ledger.", { checks: z.array(auditCheckSchema).min(1).describe("Additional checks to append to the existing ledger") }, async (args) => {
1103
- return auditMutex(() => {
1104
- const result = appendAuditChecksToLedger(auditLedgerPath, args.checks);
1105
- if (!result.ok) {
1106
- if (result.reason === "missing-ledger") return {
1107
- content: [{
1108
- type: "text",
1109
- text: "Error: audit ledger does not exist. Run audit_seed_checks first."
1110
- }],
1111
- isError: true
1112
- };
1113
- return {
1114
- content: [{
1115
- type: "text",
1116
- text: `Error: duplicate check id(s): ${result.ids.join(", ")}. Check ids must be unique.`
1117
- }],
1118
- isError: true
1119
- };
1120
- }
1121
- logToFile(`audit_add_checks: added ${result.added} entries`);
1122
- return { content: [{
1123
- type: "text",
1124
- text: `Added ${result.added} audit check(s).`
1125
- }] };
1126
- });
1127
- });
1128
- const auditResolveChecks = tool("audit_resolve_checks", "Resolve one or more audit checks by id. Patches each entry's status (and optional file/details) and writes the ledger back atomically. Concurrent calls serialize.", { updates: z.array(auditUpdateSchema).min(1).describe("Patches to apply, keyed by check id") }, async (args) => {
1129
- return auditMutex(() => {
1130
- const { next, unknown } = applyAuditUpdates(readLedger(auditLedgerPath), args.updates);
1131
- if (unknown.length > 0) return {
1132
- content: [{
1133
- type: "text",
1134
- text: `Error: unknown check id(s): ${unknown.join(", ")}. Run audit_seed_checks first or check the id.`
1135
- }],
1136
- isError: true
1137
- };
1138
- writeLedgerAtomic(auditLedgerPath, next);
1139
- logToFile(`audit_resolve_checks: applied ${args.updates.length} update(s)`);
1140
- return { content: [{
1141
- type: "text",
1142
- text: `Resolved ${args.updates.length} check(s).`
1143
- }] };
1144
- });
1145
- });
1146
- const askQuestionSchema = z.object({
1147
- id: z.string().min(1).describe("Stable key for the answer in the response map"),
1148
- prompt: z.string().min(1).describe("Question text shown to the user"),
1149
- kind: z.enum([
1150
- "single",
1151
- "multi",
1152
- "text"
1153
- ]).describe("'single' = pick one option, 'multi' = pick any, 'text' = free-form single-line answer"),
1154
- options: z.array(z.object({
1155
- label: z.string(),
1156
- value: z.string(),
1157
- description: z.string().optional().describe("Optional secondary line shown dimmed and wrapped beneath the label (multi-select only). Use when a choice needs more than a title — e.g. what a custom scout watches and what makes it speak up.")
1158
- })).optional().describe("Required for kind=single|multi; ignored for kind=text"),
1159
- required: z.boolean().optional().describe("Defaults to true"),
1160
- sensitive: z.boolean().optional().describe("Only valid for kind='text'. When true, the user's answer is stored in the wizard's secret vault and returned to you as { secretRef: 'secret:...' } instead of the raw string. Use for API keys, tokens, and any other secret the user types in. The secretRef is only resolved by wizard-tools that accept it (e.g. set_env_values) — it is NOT resolved when passed to other MCP tools (e.g. PostHog data-warehouse tools), which will reject it. For a secret that must reach another tool, write it to the env with set_env_values first, or use that tool's own credential-reference flow.")
1161
- });
1162
- return createSdkMcpServer({
1163
- name: SERVER_NAME,
1164
- version: "1.0.0",
1165
- tools: [
1166
- checkEnvKeys,
1167
- setEnvValues,
1168
- detectPM,
1169
- loadSkillMenu,
1170
- installSkill,
1171
- auditSeedChecks,
1172
- auditAddChecks,
1173
- auditResolveChecks,
1174
- tool("wizard_ask", "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 related questions into a single call (up to 8) rather than asking one at a time; sequential calls are fine when later questions genuinely depend on earlier answers. 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.", { questions: z.array(askQuestionSchema).min(1).max(8) }, async (args) => {
1175
- if (!askBridge) return {
1176
- content: [{
1177
- type: "text",
1178
- text: "Error: wizard_ask is not available in this environment (CI / non-interactive). Proceed with sensible defaults or emit [ABORT] requirements-incomplete."
1179
- }],
1180
- isError: true
1181
- };
1182
- const capDecision = evaluateAskCap(askCallCount, askMaxQuestions, askAdjacencyNudged);
1183
- if (capDecision.kind === "capped") {
1184
- if (capDecision.reason === "adjacency") askAdjacencyNudged = true;
1185
- analytics.wizardCapture("wizard_ask capped", {
1186
- reason: capDecision.reason,
1187
- call_count: askCallCount,
1188
- max_questions: askMaxQuestions
1189
- });
1190
- return {
1191
- content: [{
1192
- type: "text",
1193
- text: capDecision.message
1194
- }],
1195
- isError: true
1196
- };
1197
- }
1198
- for (const q of args.questions) {
1199
- if ((q.kind === "single" || q.kind === "multi") && (!q.options || q.options.length === 0)) return {
1200
- content: [{
1201
- type: "text",
1202
- text: `Error: question "${q.id}" has kind="${q.kind}" but no options. Provide at least one { label, value } option, or change kind to "text".`
1203
- }],
1204
- isError: true
1205
- };
1206
- if (q.sensitive && q.kind !== "text") return {
1207
- content: [{
1208
- type: "text",
1209
- text: `Error: question "${q.id}" sets sensitive=true but kind="${q.kind}". Only kind="text" answers can be vaulted as secrets.`
1210
- }],
1211
- isError: true
1212
- };
1213
- }
1214
- const ids = /* @__PURE__ */ new Set();
1215
- for (const q of args.questions) {
1216
- if (ids.has(q.id)) return {
1217
- content: [{
1218
- type: "text",
1219
- text: `Error: duplicate question id "${q.id}". Each question must have a unique id.`
1220
- }],
1221
- isError: true
1222
- };
1223
- ids.add(q.id);
1224
- }
1225
- askCallCount += 1;
1226
- try {
1227
- const answers = await askBridge.request({ questions: args.questions });
1228
- if (isFullyCancelled(answers)) askCallCount -= 1;
1229
- const sensitiveById = new Map(args.questions.filter((q) => q.sensitive).map((q) => [q.id, q.prompt]));
1230
- const sanitised = {};
1231
- for (const [id, answer] of Object.entries(answers)) {
1232
- const label = sensitiveById.get(id);
1233
- if (label !== void 0 && typeof answer === "string" && answer !== "__cancelled__") {
1234
- const ref = secretVault.put(answer, {
1235
- label,
1236
- source: "wizard_ask"
1237
- });
1238
- sanitised[id] = { secretRef: ref };
1239
- logToFile(`wizard_ask: vaulted answer for "${id}" as ${ref}`);
1240
- } else sanitised[id] = answer;
1241
- }
1242
- logToFile(`wizard_ask: resolved ${Object.keys(answers).length} answer(s) for ${args.questions.length} question(s)`);
1243
- return { content: [{
1244
- type: "text",
1245
- text: JSON.stringify({ answers: sanitised }, null, 2)
1246
- }] };
1247
- } catch (err) {
1248
- logToFile(`wizard_ask: error: ${err?.message ?? err}`);
1249
- return {
1250
- content: [{
1251
- type: "text",
1252
- text: `Error: wizard_ask failed: ${err?.message ?? String(err)}`
1253
- }],
1254
- isError: true
1255
- };
1256
- }
1257
- }),
1258
- ...orchestrator ? buildOrchestratorTools(tool, orchestrator) : []
1259
- ]
1260
- });
1261
- }
1262
- /** Tool names exposed by the wizard-tools server, keyed for selective use. */
1263
- const WIZARD_TOOL_NAMES = {
1264
- checkEnvKeys: `mcp__${SERVER_NAME}__check_env_keys`,
1265
- setEnvValues: `mcp__${SERVER_NAME}__set_env_values`,
1266
- detectPackageManager: `mcp__${SERVER_NAME}__detect_package_manager`,
1267
- loadSkillMenu: `mcp__${SERVER_NAME}__load_skill_menu`,
1268
- installSkill: `mcp__${SERVER_NAME}__install_skill`,
1269
- auditSeedChecks: `mcp__${SERVER_NAME}__audit_seed_checks`,
1270
- auditAddChecks: `mcp__${SERVER_NAME}__audit_add_checks`,
1271
- auditResolveChecks: `mcp__${SERVER_NAME}__audit_resolve_checks`,
1272
- wizardAsk: `mcp__${SERVER_NAME}__wizard_ask`,
1273
- enqueueTask: `mcp__${SERVER_NAME}__enqueue_task`,
1274
- completeTask: `mcp__${SERVER_NAME}__complete_task`,
1275
- readHandoffs: `mcp__${SERVER_NAME}__read_handoffs`
1276
- };
1277
- //#endregion
1278
180
  //#region src/lib/skill-install.ts
1279
181
  /**
1280
182
  * Check if command is a PostHog skill installation from MCP.
@@ -1386,6 +288,23 @@ function recordMatch(phase, tool, match, action) {
1386
288
  triageReason: triage?.reason
1387
289
  });
1388
290
  }
291
+ /**
292
+ * Scan bookkeeping for harnesses that run a scanner outside these hooks (pi):
293
+ * counts the scan and routes violations through `recordMatch`, so they reach
294
+ * the run log, per-match telemetry, and the end-of-run scan report.
295
+ */
296
+ function recordExternalScan(phase, tool, violations, action) {
297
+ recordScan();
298
+ for (const v of violations) recordMatch(phase, tool, {
299
+ rule: v.rule,
300
+ metadata: {
301
+ severity: v.severity,
302
+ category: v.category,
303
+ description: v.description
304
+ },
305
+ matchedStrings: []
306
+ }, action);
307
+ }
1389
308
  /** Format the scan report summary. Returns null if no scans occurred */
1390
309
  function formatScanReport() {
1391
310
  if (scanCount === 0) return null;
@@ -1917,10 +836,10 @@ const WIZARD_COMMANDMENTS = [
1917
836
  "Never hallucinate a PostHog project token, host, or any other secret. Always use the real values that have been configured for this project (for example via environment variables).",
1918
837
  "Never write API keys, access tokens, or other secrets directly into source code. Always reference environment variables instead, and rely on the wizard-tools MCP server (check_env_keys / set_env_values) to create or update .env files.",
1919
838
  "Always use the detect_package_manager tool from the wizard-tools MCP server to determine the package manager. Do not guess based on lockfiles or hard-code npm, yarn, pnpm, bun, pip, etc.",
1920
- "When installing packages, start the installation as a background task and then continue with other work. Do not block waiting for installs to finish unless explicitly instructed.",
1921
839
  "Before writing to any file, you MUST read that exact file immediately beforehand using the Read tool, even if you have already read it earlier in the run. This avoids tool failures and stale edits.",
1922
840
  "Treat feature flags, custom properties, and event names as part of an analytics contract. Prefer reusing existing names and patterns in the project. When you must introduce new ones, make them clear, descriptive, and consistent with existing conventions, and avoid scattering the same flag or property across many unrelated callsites.",
1923
841
  "Keep PostHog data capture at its defaults unless the user explicitly asks otherwise. Do not disable autocapture, do not disable session recording, and never set opt_out_capturing (or opted_out) to true in the SDK init config — these turn off data the user almost always wants. Note: posthog.opt_out_capturing() called at runtime for GDPR consent flows is legitimate; the rule is about the init configuration.",
842
+ "Never put personally identifiable information — emails, full or partial names, phone numbers, physical or IP addresses, or other user-entered PII — in capture() event properties. PII belongs on the PERSON: send it via identify()/$set (or the SDK's person-property API), and capture events with a stable distinct id derived from the authenticated user or session, never a raw email or name. This holds for every SDK, client and server.",
1924
843
  "Prefer minimal, targeted edits that achieve the requested behavior while preserving existing structure and style. Avoid large refactors, broad reformatting, or unrelated changes unless explicitly requested.",
1925
844
  "Do not spawn subagents unless explicitly instructed to do so.",
1926
845
  "Create tasks as soon as you understand the work you are going to carry out. Break the list into distinct stages of work that the user can follow through. Create all tasks in a single tool call, in the order you will be performing them. Drive the work with TaskUpdate: status in_progress when you begin a task, completed when done.",
@@ -1971,6 +890,13 @@ const AgentSignals = {
1971
890
  DASHBOARD_URL: "[DASHBOARD_URL]",
1972
891
  NOTEBOOK_URL: "[NOTEBOOK_URL]"
1973
892
  };
893
+ /**
894
+ * End-of-run reflection ask, shared by both harnesses so remarks are
895
+ * comparable. The format clause comes FIRST and nothing trails the marker —
896
+ * literal models (gpt-5-mini) echo whatever text follows it. The parser also
897
+ * drops remarks that quote this instruction (see AgentOutputSignals.remark).
898
+ */
899
+ 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.`;
1974
900
  //#endregion
1975
901
  //#region src/lib/agent/output-signals.ts
1976
902
  /**
@@ -2048,8 +974,12 @@ var AgentOutputSignals = class {
2048
974
  }
2049
975
  /** Text after the single `[WIZARD-REMARK]` marker, trimmed, or undefined. */
2050
976
  remark() {
2051
- const re = new RegExp(`${OUTPUT_SIGNALS.WIZARD_REMARK.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*(.+?)(?:\\n|$)`, "s");
2052
- return this.text.match(re)?.[1]?.trim() || void 0;
977
+ const re = new RegExp(`${OUTPUT_SIGNALS.WIZARD_REMARK.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\s*(.+?)(?:\\n|$)`, "gs");
978
+ let match;
979
+ while ((match = re.exec(this.text)) !== null) {
980
+ const text = match[1]?.trim();
981
+ if (text && !REMARK_INSTRUCTION.includes(text)) return text;
982
+ }
2053
983
  }
2054
984
  };
2055
985
  //#endregion
@@ -2555,7 +1485,7 @@ function createStopHook(featureQueue, signals, requestRemark = true) {
2555
1485
  logToFile("Stop hook: requesting reflection");
2556
1486
  return {
2557
1487
  decision: "block",
2558
- reason: `Before concluding, provide a brief remark about what information or guidance would have been useful to have in the integration prompt or documentation for this run. Specifically cite anything that would have prevented tool failures, erroneous edits, or other wasted turns. Format your response exactly as: ${AgentSignals.WIZARD_REMARK} Your remark here`
1488
+ reason: REMARK_INSTRUCTION
2559
1489
  };
2560
1490
  }
2561
1491
  logToFile("Stop hook: allowing stop");
@@ -2590,14 +1520,6 @@ function isWarlockDisabled(flags = {}) {
2590
1520
  return flags["wizard-warlock-disabled"] === "true" || runtimeEnv("POSTHOG_WIZARD_WARLOCK_DISABLED") === "true";
2591
1521
  }
2592
1522
  /**
2593
- * Whether this run uses the experimental task-queue orchestrator. Gated by the
2594
- * boolean `wizard-orchestrator` feature flag, targeted to the user in the wizard's
2595
- * analytics project.
2596
- */
2597
- function isOrchestratorEnabled(flags = {}) {
2598
- return flags[WIZARD_ORCHESTRATOR_FLAG_KEY] === "true";
2599
- }
2600
- /**
2601
1523
  * Build env for the SDK subprocess: process.env plus ANTHROPIC_CUSTOM_HEADERS, which always
2602
1524
  * includes `x-posthog-use-bedrock-fallback: true` so the LLM gateway falls back to Bedrock on
2603
1525
  * Anthropic 5xx, plus any wizard metadata/flags.
@@ -2661,6 +1583,7 @@ function matchesAllowedPrefix(command) {
2661
1583
  if (parts.length === 0 || !PACKAGE_MANAGERS.includes(parts[0])) return false;
2662
1584
  let scriptIndex = 1;
2663
1585
  if (parts[scriptIndex] === "run" || parts[scriptIndex] === "exec") scriptIndex++;
1586
+ if (parts[scriptIndex] === "i") return true;
2664
1587
  const scriptPart = parts.slice(scriptIndex).join(" ");
2665
1588
  return SAFE_SCRIPTS.some((safe) => scriptPart.startsWith(safe)) || LINTING_TOOLS.some((tool) => scriptPart.startsWith(tool));
2666
1589
  }
@@ -2932,6 +1855,8 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
2932
1855
  cache_read_input_tokens: usage?.cache_read_input_tokens,
2933
1856
  ...config?.analyticsProperties
2934
1857
  });
1858
+ const totalCostUsd = Number(lastResultMessage?.total_cost_usd ?? 0);
1859
+ if (totalCostUsd > 0) getUI().setFinalTokenCostUsd(totalCostUsd);
2935
1860
  try {
2936
1861
  middleware?.finalize(lastResultMessage, durationMs);
2937
1862
  } catch (e) {
@@ -3078,7 +2003,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
3078
2003
  }
3079
2004
  loggedInitialContext = true;
3080
2005
  }
3081
- handleSDKMessage(message, options, spinner, signals, receivedSuccessResult, tasks, isOrchestratorEnabled(agentConfig.wizardFlags ?? {}), emitStepEvents);
2006
+ handleSDKMessage(message, options, spinner, signals, receivedSuccessResult, tasks, (agentConfig.wizardFlags ?? {})[WIZARD_ORCHESTRATOR_FLAG_KEY] === "true", emitStepEvents);
3082
2007
  if (abortCases.length > 0 && !abortReason && message.type === "assistant") {
3083
2008
  const content = message.message?.content;
3084
2009
  if (Array.isArray(content)) {
@@ -3338,6 +2263,29 @@ function extractTaskIdFromResult(content) {
3338
2263
  }
3339
2264
  }
3340
2265
  }
2266
+ /**
2267
+ * Extracts a `TokenUsageDelta` for the hidden Ctrl+T token/cost HUD from an
2268
+ * SDK assistant message, or `null` when the message carries no usage (e.g.
2269
+ * a duplicate/retried turn). `message.message` is a BetaMessage (the raw
2270
+ * Anthropic API response), which carries `model` alongside `usage` — read
2271
+ * per turn, not from the run's nominal model, since a subagent dispatched
2272
+ * via the Agent tool can genuinely run on a different model than the main
2273
+ * session.
2274
+ */
2275
+ function extractTokenUsageDelta(message) {
2276
+ const apiMessage = message.message;
2277
+ const usage = apiMessage?.usage;
2278
+ if (!usage) return null;
2279
+ return {
2280
+ inputTokens: Number(usage.input_tokens ?? 0),
2281
+ outputTokens: Number(usage.output_tokens ?? 0),
2282
+ cacheReadTokens: Number(usage.cache_read_input_tokens ?? 0),
2283
+ cacheCreationTokens: Number(usage.cache_creation_input_tokens ?? 0),
2284
+ cacheCreation5m: Number(usage.cache_creation?.ephemeral_5m_input_tokens ?? 0),
2285
+ cacheCreation1h: Number(usage.cache_creation?.ephemeral_1h_input_tokens ?? 0),
2286
+ model: apiMessage?.model
2287
+ };
2288
+ }
3341
2289
  function handleSDKMessage(message, options, spinner, signals, receivedSuccessResult = false, tasks, suppressTaskRender = false, emitStepEvents = false) {
3342
2290
  const STATUS_RANK = {
3343
2291
  completed: 0,
@@ -3353,6 +2301,8 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
3353
2301
  if (options.debug) debug(`SDK Message type: ${message.type}`);
3354
2302
  switch (message.type) {
3355
2303
  case "assistant": {
2304
+ const tokenUsageDelta = extractTokenUsageDelta(message);
2305
+ if (tokenUsageDelta) getUI().addTokenUsage(tokenUsageDelta);
3356
2306
  const content = message.message?.content;
3357
2307
  if (Array.isArray(content)) for (const block of content) {
3358
2308
  if (block.type === "text" && typeof block.text === "string") {
@@ -3433,6 +2383,6 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
3433
2383
  }
3434
2384
  }
3435
2385
  //#endregion
3436
- export { AUDIT_SEVERITY_STYLE as A, QUEUE_DIR_NAME as C, AUDIT_CHECKS_FILE as D, createWizardAskBridge as E, getAuditChecks as M, AUDIT_CHECKS_KEY as O, installSkillById as S, TaskStatus as T, EVENT_PLAN_FILE as _, runAgent as a, downloadSkill as b, classifySettingsConflicts as c, sanitizeAgentSubprocessEnv as d, AgentSignals as f, writeScanReport as g, formatYaraAbortMessage as h, isOrchestratorEnabled as i, coerceAuditChecks as j, AUDIT_REPORT_FILE as k, recoverOrphanedSettingsBackups as l, formatScanReport as m, buildRunTags as n, backupAndFixClaudeSettings as o, flushScanReport as p, initializeAgent as r, checkAllSettingsConflicts as s, buildAgentEnv as t, restoreClaudeSettings as u, SETUP_REPORT_FILE as v, QueueStore as w, fetchSkillMenu as x, WIZARD_TOOL_NAMES as y };
2386
+ export { SETUP_REPORT_FILE as C, EVENT_PLAN_FILE as S, formatScanReport as _, wizardCanUseTool as a, recordExternalScan as b, classifySettingsConflicts as c, sanitizeAgentSubprocessEnv as d, AgentOutputSignals as f, flushScanReport as g, getWizardCommandments as h, runAgent as i, recoverOrphanedSettingsBackups as l, REMARK_INSTRUCTION as m, buildRunTags as n, backupAndFixClaudeSettings as o, AgentSignals as p, initializeAgent as r, checkAllSettingsConflicts as s, buildAgentEnv as t, restoreClaudeSettings as u, formatYaraAbortMessage as v, writeScanReport as x, isWizardDocumentationPath as y };
3437
2387
 
3438
- //# sourceMappingURL=agent-interface-D8jnkEnB.js.map
2388
+ //# sourceMappingURL=agent-interface-kOuzXg84.js.map