@posthog/wizard 2.24.1 → 2.25.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 (64) hide show
  1. package/dist/{AiOptInRequiredScreen-_33FOcVo.js → AiOptInRequiredScreen-C-D9tN6r.js} +20 -16
  2. package/dist/AiOptInRequiredScreen-C-D9tN6r.js.map +1 -0
  3. package/dist/{add-mcp-server-to-clients-CfwEQT_z.js → add-mcp-server-to-clients-t0xe8gn1.js} +4 -4
  4. package/dist/{add-mcp-server-to-clients-CfwEQT_z.js.map → add-mcp-server-to-clients-t0xe8gn1.js.map} +1 -1
  5. package/dist/{agent-interface-D1vtN6Wn.js → agent-interface-BsuUUPle.js} +403 -40
  6. package/dist/agent-interface-BsuUUPle.js.map +1 -0
  7. package/dist/{agent-runner-CBbkS0Ro.js → agent-runner-L_-kJ3y3.js} +624 -17
  8. package/dist/agent-runner-L_-kJ3y3.js.map +1 -0
  9. package/dist/{analytics-CUr82BDl.js → analytics-CDOujOSQ.js} +51 -17
  10. package/dist/analytics-CDOujOSQ.js.map +1 -0
  11. package/dist/{api-CI3Z74NG.js → api-DNS-L-1U.js} +3 -3
  12. package/dist/{api-CI3Z74NG.js.map → api-DNS-L-1U.js.map} +1 -1
  13. package/dist/bin.js +279 -33
  14. package/dist/bin.js.map +1 -1
  15. package/dist/{ci-install-D_kxNmbJ.js → ci-install-_9A7tL36.js} +4 -4
  16. package/dist/{ci-install-D_kxNmbJ.js.map → ci-install-_9A7tL36.js.map} +1 -1
  17. package/dist/{debug-DxA_f5QT.js → debug-BwC7UkGH.js} +16 -8
  18. package/dist/debug-BwC7UkGH.js.map +1 -0
  19. package/dist/{debug-zMvpNYb2.js → debug-CZQcMAJT.js} +1 -1
  20. package/dist/{environment-CyS37cmM.js → environment-DQPoj9sU.js} +3 -3
  21. package/dist/{environment-CyS37cmM.js.map → environment-DQPoj9sU.js.map} +1 -1
  22. package/dist/{interactive-CG6FFqSw.js → interactive-DT5dLd7N.js} +2 -2
  23. package/dist/{interactive-CG6FFqSw.js.map → interactive-DT5dLd7N.js.map} +1 -1
  24. package/dist/{mcp-prompt-streaming-DQz4FSb1.js → mcp-prompt-streaming-CBMr458Q.js} +7 -26
  25. package/dist/mcp-prompt-streaming-CBMr458Q.js.map +1 -0
  26. package/dist/{non-interactive-DWtHX3ZR.js → non-interactive-csP4yGdA.js} +2 -2
  27. package/dist/{non-interactive-DWtHX3ZR.js.map → non-interactive-csP4yGdA.js.map} +1 -1
  28. package/dist/{package-manager-BWUS4CP0.js → package-manager-CB4c2euf.js} +2 -2
  29. package/dist/{package-manager-BWUS4CP0.js.map → package-manager-CB4c2euf.js.map} +1 -1
  30. package/dist/{playground-D7AhMMF5.js → playground-C-lpKoKC.js} +5 -5
  31. package/dist/{playground-D7AhMMF5.js.map → playground-C-lpKoKC.js.map} +1 -1
  32. package/dist/{posthog-integration-DexZ2uHU.js → posthog-integration-BL8-vC0V.js} +11 -11
  33. package/dist/{posthog-integration-DexZ2uHU.js.map → posthog-integration-BL8-vC0V.js.map} +1 -1
  34. package/dist/{provisioning-9c-AQbsa.js → provisioning-DLOiFSM9.js} +3 -3
  35. package/dist/{provisioning-9c-AQbsa.js.map → provisioning-DLOiFSM9.js.map} +1 -1
  36. package/dist/{registry-CO7JVZyE.js → registry-BbRzCV5l.js} +4 -4
  37. package/dist/{registry-CO7JVZyE.js.map → registry-BbRzCV5l.js.map} +1 -1
  38. package/dist/{setup-utils-0U-_Md2G.js → setup-utils-D87CyNkw.js} +8 -8
  39. package/dist/{setup-utils-0U-_Md2G.js.map → setup-utils-D87CyNkw.js.map} +1 -1
  40. package/dist/smoke-test.sh +36 -1
  41. package/dist/{start-tui-WNb3ET14.js → start-tui-DnAG57vY.js} +13 -13
  42. package/dist/{start-tui-WNb3ET14.js.map → start-tui-DnAG57vY.js.map} +1 -1
  43. package/dist/{steps-BAUXDCC4.js → steps-JaxH6u0f.js} +6 -6
  44. package/dist/{steps-BAUXDCC4.js.map → steps-JaxH6u0f.js.map} +1 -1
  45. package/dist/{task-stream-CZawuzlz.js → task-stream-BQNSp0qR.js} +4 -3
  46. package/dist/task-stream-BQNSp0qR.js.map +1 -0
  47. package/dist/{telemetry-ycqCpNPr.js → telemetry-DL28cCwY.js} +3 -3
  48. package/dist/{telemetry-ycqCpNPr.js.map → telemetry-DL28cCwY.js.map} +1 -1
  49. package/dist/{urls-C8aJWvgh.js → urls-vkJ5c0ix.js} +2 -2
  50. package/dist/{urls-C8aJWvgh.js.map → urls-vkJ5c0ix.js.map} +1 -1
  51. package/dist/{wizard-abort-DWXyJdws.js → wizard-abort-BRXKRL4F.js} +1 -1
  52. package/dist/{wizard-abort-C6gRLxUE.js → wizard-abort-CLGgMAEe.js} +3 -3
  53. package/dist/{wizard-abort-C6gRLxUE.js.map → wizard-abort-CLGgMAEe.js.map} +1 -1
  54. package/dist/{wizard-ui-YdGFRyu_.js → wizard-ui-WZ48rUgr.js} +2 -1
  55. package/dist/wizard-ui-WZ48rUgr.js.map +1 -0
  56. package/package.json +1 -1
  57. package/dist/AiOptInRequiredScreen-_33FOcVo.js.map +0 -1
  58. package/dist/agent-interface-D1vtN6Wn.js.map +0 -1
  59. package/dist/agent-runner-CBbkS0Ro.js.map +0 -1
  60. package/dist/analytics-CUr82BDl.js.map +0 -1
  61. package/dist/debug-DxA_f5QT.js.map +0 -1
  62. package/dist/mcp-prompt-streaming-DQz4FSb1.js.map +0 -1
  63. package/dist/task-stream-CZawuzlz.js.map +0 -1
  64. package/dist/wizard-ui-YdGFRyu_.js.map +0 -1
@@ -1,18 +1,47 @@
1
1
  import { n as __require } from "./rolldown-runtime-B_-DWIq7.js";
2
- import { F as POSTHOG_FLAG_HEADER_PREFIX, X as WIZARD_VARIANTS, Y as WIZARD_USER_AGENT, Z as WIZARD_VARIANT_FLAG_KEY, a as getLogFilePath, f as skillTmpPath, o as initLogFile, p as getUI, q as WIZARD_REMARK_EVENT_NAME, r as debug, s as logToFile, u as WIZARD_YARA_REPORT_FILE, z as POSTHOG_PROPERTY_HEADER_PREFIX } from "./debug-DxA_f5QT.js";
3
- import { t as analytics } from "./analytics-CUr82BDl.js";
4
- import { i as getLlmGatewayUrlFromHost } from "./urls-C8aJWvgh.js";
2
+ import { F as POSTHOG_FLAG_HEADER_PREFIX, J as WIZARD_REMARK_EVENT_NAME, K as WIZARD_ORCHESTRATOR_FLAG_KEY, Q as WIZARD_VARIANT_FLAG_KEY, X as WIZARD_USER_AGENT, Z as WIZARD_VARIANTS, a as getLogFilePath, f as skillTmpPath, o as initLogFile, p as getUI, r as debug, s as logToFile, u as WIZARD_YARA_REPORT_FILE, z as POSTHOG_PROPERTY_HEADER_PREFIX } from "./debug-BwC7UkGH.js";
3
+ import { t as analytics } from "./analytics-CDOujOSQ.js";
4
+ import { i as getLlmGatewayUrlFromHost } from "./urls-vkJ5c0ix.js";
5
5
  import { n as ADDITIONAL_FEATURE_PROMPTS } from "./wizard-session-G3VWD6hv.js";
6
- import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-C6gRLxUE.js";
6
+ import { i as wizardAbort, n as registerCleanup, t as WizardError } from "./wizard-abort-CLGgMAEe.js";
7
7
  import { createRequire } from "node:module";
8
8
  import * as fs$1 from "fs";
9
9
  import fs from "fs";
10
+ import * as path$1 from "path";
10
11
  import path from "path";
11
12
  import { z } from "zod";
12
13
  import fg from "fast-glob";
13
14
  import { execFileSync } from "child_process";
14
15
  import { randomUUID } from "crypto";
15
16
  import * as os from "os";
17
+ //#region src/utils/atomic-ledger.ts
18
+ /**
19
+ * Small shared primitives for on-disk ledgers: an atomic JSON writer and a
20
+ * single-chain async mutex. Used by the audit tools and by the orchestrator
21
+ * queue. Lifted here so both share one implementation.
22
+ */
23
+ /**
24
+ * Atomically write JSON: write to a `.tmp` file then rename over the target. The
25
+ * rename bumps the file's mtime in one step, which is what a file watcher polls.
26
+ */
27
+ function writeJsonAtomic(targetPath, data) {
28
+ const tmpPath = `${targetPath}.tmp`;
29
+ fs$1.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf8");
30
+ fs$1.renameSync(tmpPath, targetPath);
31
+ }
32
+ /**
33
+ * A single async mutex. Serializes read-modify-write cycles so concurrent callers
34
+ * (parallel task agents, audit tool calls) never interleave a mutation.
35
+ */
36
+ function makeMutex() {
37
+ let chain = Promise.resolve();
38
+ return async function run(fn) {
39
+ const next = chain.then(() => fn());
40
+ chain = next.catch(() => void 0);
41
+ return next;
42
+ };
43
+ }
44
+ //#endregion
16
45
  //#region src/lib/programs/audit/types.ts
17
46
  /** Single source of truth for status glyph + color across audit views. */
18
47
  const AUDIT_SEVERITY_STYLE = {
@@ -103,6 +132,336 @@ function createSecretVault() {
103
132
  };
104
133
  }
105
134
  //#endregion
135
+ //#region src/lib/programs/orchestrator/queue.ts
136
+ /**
137
+ * The orchestrator task queue.
138
+ *
139
+ * In memory, synchronous, single-owner: one Node process drives the run, so
140
+ * there is no locking. The queue imposes no execution policy — `nextRunnable`
141
+ * returns every pending task whose dependencies are satisfied, and how many of
142
+ * those run at once is decided by the task graph, not the queue.
143
+ *
144
+ * Every transition rewrites `<installDir>/.posthog-wizard-cache/queue.json`, a
145
+ * small file holding the whole queue, handoffs included. It is the run's log
146
+ * and the report's source. The whole cache folder is run-scoped and wiped when
147
+ * the run ends.
148
+ */
149
+ const TaskStatus = {
150
+ Pending: "pending",
151
+ Running: "running",
152
+ Done: "done",
153
+ Skipped: "skipped",
154
+ Failed: "failed"
155
+ };
156
+ const QUEUE_DIR_NAME = ".posthog-wizard-cache";
157
+ const DEFAULT_MAX_ATTEMPTS = 2;
158
+ function nowIso() {
159
+ return (/* @__PURE__ */ new Date()).toISOString();
160
+ }
161
+ /** Dropped in the cache folder so an orphaned copy explains itself. */
162
+ const DELETE_ME_FILE = ".DELETE-ME.md";
163
+ const DELETE_ME_BODY = `# Safe to delete
164
+
165
+ This folder contains run artifacts from the PostHog Wizard. This should have
166
+ been deleted if the Wizard has finished running. If this wasn't deleted for
167
+ some reason, you can safely delete the entire \`${QUEUE_DIR_NAME}/\` folder.
168
+ `;
169
+ var QueueStore = class {
170
+ tasks = [];
171
+ onTransition;
172
+ runId;
173
+ queuePath;
174
+ constructor(installDir, runId, opts) {
175
+ this.onTransition = opts?.onTransition;
176
+ this.runId = runId;
177
+ const dir = path$1.join(installDir, QUEUE_DIR_NAME);
178
+ this.queuePath = path$1.join(dir, "queue.json");
179
+ fs$1.mkdirSync(dir, { recursive: true });
180
+ fs$1.writeFileSync(path$1.join(dir, DELETE_ME_FILE), DELETE_ME_BODY);
181
+ }
182
+ list() {
183
+ return this.tasks;
184
+ }
185
+ get(id) {
186
+ return this.tasks.find((t) => t.id === id);
187
+ }
188
+ /**
189
+ * Every pending task whose dependencies are all satisfied (`done` or
190
+ * `skipped`). A skipped dependency does not block downstream work.
191
+ */
192
+ nextRunnable() {
193
+ const doneIds = new Set(this.tasks.filter((t) => t.status === TaskStatus.Done || t.status === TaskStatus.Skipped).map((t) => t.id));
194
+ return this.tasks.filter((t) => t.status === TaskStatus.Pending && t.dependsOn.every((d) => doneIds.has(d)));
195
+ }
196
+ /**
197
+ * True when no task is running and none can be started. Either everything
198
+ * is terminal, or the only pending tasks are blocked by a failed dependency.
199
+ */
200
+ isDrained() {
201
+ if (this.tasks.some((t) => t.status === TaskStatus.Running)) return false;
202
+ return this.nextRunnable().length === 0;
203
+ }
204
+ summary() {
205
+ const counts = {
206
+ [TaskStatus.Pending]: 0,
207
+ [TaskStatus.Running]: 0,
208
+ [TaskStatus.Done]: 0,
209
+ [TaskStatus.Skipped]: 0,
210
+ [TaskStatus.Failed]: 0
211
+ };
212
+ for (const t of this.tasks) counts[t.status] += 1;
213
+ return {
214
+ ...counts,
215
+ total: this.tasks.length
216
+ };
217
+ }
218
+ readHandoff(id) {
219
+ return this.get(id)?.handoff ?? null;
220
+ }
221
+ /** Handoffs of completed tasks of a given type, oldest first. */
222
+ readHandoffsByType(type) {
223
+ return this.tasks.filter((t) => t.type === type && t.handoff).map((t) => t.handoff);
224
+ }
225
+ enqueue(input) {
226
+ const task = {
227
+ id: randomUUID(),
228
+ type: input.type,
229
+ label: input.label,
230
+ status: TaskStatus.Pending,
231
+ dependsOn: input.dependsOn ?? [],
232
+ inputs: input.inputs ?? {},
233
+ model: input.model,
234
+ attempts: 0,
235
+ maxAttempts: input.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,
236
+ enqueuedBy: input.enqueuedBy ?? "orchestrator",
237
+ createdAt: nowIso()
238
+ };
239
+ this.tasks.push(task);
240
+ this.reflect();
241
+ this.notify("enqueue", task);
242
+ return task;
243
+ }
244
+ start(id) {
245
+ const t = this.require(id);
246
+ t.status = TaskStatus.Running;
247
+ t.startedAt = nowIso();
248
+ t.attempts += 1;
249
+ this.reflect();
250
+ this.notify("start", t);
251
+ return t;
252
+ }
253
+ complete(id, handoff) {
254
+ return this.finish(id, TaskStatus.Done, handoff);
255
+ }
256
+ /** Terminal: the agent could not do the task. Not done, not failed. */
257
+ skip(id, handoff) {
258
+ return this.finish(id, TaskStatus.Skipped, handoff);
259
+ }
260
+ fail(id, error, handoff) {
261
+ const t = this.require(id);
262
+ t.error = error;
263
+ return this.finish(id, TaskStatus.Failed, handoff);
264
+ }
265
+ /** Put a failed/running task back to pending for a retry within the run. */
266
+ requeue(id) {
267
+ const t = this.require(id);
268
+ t.status = TaskStatus.Pending;
269
+ t.startedAt = void 0;
270
+ t.finishedAt = void 0;
271
+ this.reflect();
272
+ this.notify("requeue", t);
273
+ return t;
274
+ }
275
+ finish(id, status, handoff) {
276
+ const t = this.require(id);
277
+ if (handoff) t.handoff = handoff;
278
+ t.status = status;
279
+ t.finishedAt = nowIso();
280
+ this.reflect();
281
+ this.notify(status === TaskStatus.Done ? "complete" : status === TaskStatus.Skipped ? "skip" : "fail", t);
282
+ return t;
283
+ }
284
+ reflect() {
285
+ const file = {
286
+ version: 1,
287
+ runId: this.runId,
288
+ tasks: this.tasks
289
+ };
290
+ writeJsonAtomic(this.queuePath, file);
291
+ }
292
+ notify(event, task) {
293
+ try {
294
+ this.onTransition?.(event, task);
295
+ } catch (error) {
296
+ analytics.captureException(error instanceof Error ? error : new Error(String(error)), {
297
+ step: "orchestrator_queue_listener",
298
+ event
299
+ });
300
+ }
301
+ }
302
+ require(id) {
303
+ const t = this.get(id);
304
+ if (!t) throw new Error(`No task ${id} in the queue`);
305
+ return t;
306
+ }
307
+ };
308
+ //#endregion
309
+ //#region src/lib/programs/orchestrator/queue-tools.ts
310
+ /**
311
+ * Orchestrator MCP tools, registered into the existing `wizard-tools` server when
312
+ * a queue is present. They let the orchestrator agent and task agents grow the
313
+ * queue, report completion with a structured handoff, and read prior handoffs.
314
+ *
315
+ * The guard logic and the apply functions are plain, exported, and unit-tested.
316
+ * `buildOrchestratorTools` wraps them in the SDK `tool()` shape.
317
+ */
318
+ function stableStringify(value) {
319
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
320
+ if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
321
+ return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
322
+ }
323
+ function dedupKey(type, inputs) {
324
+ return `${type}::${stableStringify(inputs)}`;
325
+ }
326
+ /**
327
+ * A backstop on total queue size. Tasks can enqueue tasks, so a misbehaving
328
+ * type could grow the queue without bound. Keeping the graph small is the job
329
+ * of good agent and skill design, not this number — it only stops a runaway.
330
+ * The real flow is ~9 tasks, so this sits well clear of it.
331
+ */
332
+ const MAX_QUEUE_TASKS = 30;
333
+ /**
334
+ * Validate an enqueue. Structural checks only — a real type, real dependencies,
335
+ * not a literal duplicate, and not past the runaway backstop. How much runs,
336
+ * and in what shape, is the task graph's business, not a knob's.
337
+ */
338
+ function checkEnqueueGuards(ctx, args) {
339
+ const tasks = ctx.store.list();
340
+ if (tasks.length >= MAX_QUEUE_TASKS) return {
341
+ ok: false,
342
+ guard: "queue-full",
343
+ message: `The queue already holds ${tasks.length} tasks (cap ${MAX_QUEUE_TASKS}). Refine the existing tasks rather than adding more.`
344
+ };
345
+ if (!ctx.validTypes.includes(args.type)) return {
346
+ ok: false,
347
+ guard: "unknown-type",
348
+ message: `Unknown task type "${args.type}". Valid types: ${ctx.validTypes.join(", ")}.`
349
+ };
350
+ for (const dep of args.dependsOn ?? []) if (!ctx.store.get(dep)) return {
351
+ ok: false,
352
+ guard: "unknown-dep",
353
+ message: `Dependency "${dep}" is not a known task id.`
354
+ };
355
+ const key = dedupKey(args.type, args.inputs ?? {});
356
+ if (tasks.some((t) => t.status !== TaskStatus.Failed && dedupKey(t.type, t.inputs) === key)) return {
357
+ ok: false,
358
+ guard: "dedup",
359
+ message: `A "${args.type}" task with these inputs already exists.`
360
+ };
361
+ return { ok: true };
362
+ }
363
+ function applyEnqueue(ctx, args) {
364
+ const guard = checkEnqueueGuards(ctx, args);
365
+ if (!guard.ok) return guard;
366
+ return {
367
+ ok: true,
368
+ task: ctx.store.enqueue({
369
+ type: args.type,
370
+ label: args.label,
371
+ inputs: args.inputs ?? {},
372
+ dependsOn: args.dependsOn ?? [],
373
+ model: args.model,
374
+ enqueuedBy: ctx.currentTaskId ?? "orchestrator"
375
+ })
376
+ };
377
+ }
378
+ function applyComplete(ctx, args) {
379
+ const id = ctx.currentTaskId;
380
+ if (!id) return {
381
+ ok: false,
382
+ message: "complete_task can only be called by a running task agent."
383
+ };
384
+ if (args.status === TaskStatus.Failed) ctx.store.fail(id, {
385
+ type: "self-reported",
386
+ message: args.handoff.forNextAgent
387
+ }, args.handoff);
388
+ else if (args.status === TaskStatus.Skipped) ctx.store.skip(id, args.handoff);
389
+ else ctx.store.complete(id, args.handoff);
390
+ return { ok: true };
391
+ }
392
+ function applyReadHandoffs(ctx, args) {
393
+ if (args.taskId) {
394
+ const h = ctx.store.readHandoff(args.taskId);
395
+ return h ? [h] : [];
396
+ }
397
+ if (args.type) return ctx.store.readHandoffsByType(args.type);
398
+ const currentId = ctx.currentTaskId;
399
+ const current = currentId ? ctx.store.get(currentId) : void 0;
400
+ if (!current) return [];
401
+ return current.dependsOn.map((depId) => ctx.store.readHandoff(depId)).filter((h) => h !== null);
402
+ }
403
+ const HANDOFF_SHAPE = {
404
+ goals: z.string().describe("What this task was asked to achieve."),
405
+ did: z.string().describe("What you actually did."),
406
+ forNextAgent: z.string().describe("What the next agent should know."),
407
+ filesTouched: z.array(z.string()).optional(),
408
+ 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.")
409
+ };
410
+ function textResult(text, isError = false) {
411
+ return {
412
+ isError,
413
+ content: [{
414
+ type: "text",
415
+ text
416
+ }]
417
+ };
418
+ }
419
+ /**
420
+ * Build the orchestrator tools in the SDK `tool()` shape. Called from
421
+ * createWizardToolsServer only when a queue context is present.
422
+ */
423
+ function buildOrchestratorTools(tool, ctx) {
424
+ return [
425
+ 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.", {
426
+ type: z.string().describe(`The task type. One of: ${ctx.validTypes.join(", ")}.`),
427
+ 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."),
428
+ inputs: z.record(z.unknown()).optional(),
429
+ dependsOn: z.array(z.string()).optional().describe("Task ids that must be done before this task runs."),
430
+ model: z.string().optional(),
431
+ reason: z.string().describe("One line on why this task is needed.")
432
+ }, ((args) => {
433
+ const res = applyEnqueue(ctx, args);
434
+ if (!res.ok) {
435
+ analytics.wizardCapture("orchestrator guard tripped", {
436
+ guard: res.guard,
437
+ type: args.type
438
+ });
439
+ return textResult(res.message, true);
440
+ }
441
+ return textResult(JSON.stringify({ id: res.task.id }));
442
+ })),
443
+ 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'.", {
444
+ status: z.enum([
445
+ "done",
446
+ "failed",
447
+ "skipped"
448
+ ]),
449
+ handoff: z.object(HANDOFF_SHAPE)
450
+ }, ((args) => {
451
+ const res = applyComplete(ctx, args);
452
+ if (!res.ok) return textResult(res.message, true);
453
+ return textResult("ok");
454
+ })),
455
+ tool("read_handoffs", "Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.", {
456
+ type: z.string().optional(),
457
+ taskId: z.string().optional()
458
+ }, ((args) => {
459
+ const handoffs = applyReadHandoffs(ctx, args);
460
+ return textResult(JSON.stringify(handoffs, null, 2));
461
+ }))
462
+ ];
463
+ }
464
+ //#endregion
106
465
  //#region src/lib/wizard-tools.ts
107
466
  /**
108
467
  * Unified in-process MCP server for the PostHog wizard.
@@ -292,14 +651,9 @@ const auditUpdateSchema = z.object({
292
651
  file: z.string().optional(),
293
652
  details: z.string().optional()
294
653
  });
295
- /**
296
- * Atomically write JSON: write to .tmp then rename. The rename is what bumps
297
- * the file's mtime, which is what the UI's file watcher polls on.
298
- */
654
+ /** Atomically write the audit ledger. Thin typed wrapper over writeJsonAtomic. */
299
655
  function writeLedgerAtomic(targetPath, checks) {
300
- const tmpPath = `${targetPath}.tmp`;
301
- fs.writeFileSync(tmpPath, JSON.stringify(checks, null, 2), "utf8");
302
- fs.renameSync(tmpPath, targetPath);
656
+ writeJsonAtomic(targetPath, checks);
303
657
  }
304
658
  /**
305
659
  * Apply a batch of patches to the ledger by id. Returns the new array and the
@@ -375,25 +729,13 @@ function appendAuditChecksToLedger(targetPath, additions) {
375
729
  added: additions.length
376
730
  };
377
731
  }
378
- /**
379
- * Single async mutex shared by audit tools — guarantees a read-modify-write
380
- * cycle on the ledger is atomic across concurrent tool calls (e.g. future subagents).
381
- */
382
- function makeMutex() {
383
- let chain = Promise.resolve();
384
- return async function run(fn) {
385
- const next = chain.then(() => fn());
386
- chain = next.catch(() => void 0);
387
- return next;
388
- };
389
- }
390
732
  const SERVER_NAME = "wizard-tools";
391
733
  /**
392
734
  * Create the unified in-process MCP server with all wizard tools.
393
735
  * Must be called asynchronously because the SDK is an ESM module loaded via dynamic import.
394
736
  */
395
737
  async function createWizardToolsServer(options) {
396
- const { workingDirectory, detectPackageManager, skillsBaseUrl, askBridge, askMaxQuestions = 10, secretVault = createSecretVault() } = options;
738
+ const { workingDirectory, detectPackageManager, skillsBaseUrl, askBridge, askMaxQuestions = 10, secretVault = createSecretVault(), orchestrator } = options;
397
739
  const { tool, createSdkMcpServer } = await getSDKModule$1();
398
740
  let askCallCount = 0;
399
741
  let cachedSkillMenu = {};
@@ -673,7 +1015,8 @@ async function createWizardToolsServer(options) {
673
1015
  isError: true
674
1016
  };
675
1017
  }
676
- })
1018
+ }),
1019
+ ...orchestrator ? buildOrchestratorTools(tool, orchestrator) : []
677
1020
  ]
678
1021
  });
679
1022
  }
@@ -687,7 +1030,10 @@ const WIZARD_TOOL_NAMES = {
687
1030
  auditSeedChecks: `mcp__${SERVER_NAME}__audit_seed_checks`,
688
1031
  auditAddChecks: `mcp__${SERVER_NAME}__audit_add_checks`,
689
1032
  auditResolveChecks: `mcp__${SERVER_NAME}__audit_resolve_checks`,
690
- wizardAsk: `mcp__${SERVER_NAME}__wizard_ask`
1033
+ wizardAsk: `mcp__${SERVER_NAME}__wizard_ask`,
1034
+ enqueueTask: `mcp__${SERVER_NAME}__enqueue_task`,
1035
+ completeTask: `mcp__${SERVER_NAME}__complete_task`,
1036
+ readHandoffs: `mcp__${SERVER_NAME}__read_handoffs`
691
1037
  };
692
1038
  //#endregion
693
1039
  //#region src/utils/custom-headers.ts
@@ -1761,7 +2107,7 @@ function buildAuthErrorContext(workingDirectory, gatewayUrl, homeDir = os.homedi
1761
2107
  * Phase 2 — collect remark (once): block with remark prompt
1762
2108
  * Phase 3 — allow stop: return {}
1763
2109
  */
1764
- function createStopHook(featureQueue, signals) {
2110
+ function createStopHook(featureQueue, signals, requestRemark = true) {
1765
2111
  let featureIndex = 0;
1766
2112
  let remarkRequested = false;
1767
2113
  return (input) => {
@@ -1784,7 +2130,7 @@ function createStopHook(featureQueue, signals) {
1784
2130
  reason: prompt
1785
2131
  };
1786
2132
  }
1787
- if (!remarkRequested) {
2133
+ if (requestRemark && !remarkRequested) {
1788
2134
  remarkRequested = true;
1789
2135
  logToFile("Stop hook: requesting reflection");
1790
2136
  return {
@@ -1805,6 +2151,14 @@ function buildWizardMetadata(flags = {}) {
1805
2151
  return { ...(variantKey && WIZARD_VARIANTS[variantKey]) ?? WIZARD_VARIANTS["base"] };
1806
2152
  }
1807
2153
  /**
2154
+ * Whether this run uses the experimental task-queue orchestrator. Gated by the
2155
+ * boolean `wizard-orchestrator` feature flag, targeted to the user in the wizard's
2156
+ * analytics project.
2157
+ */
2158
+ function isOrchestratorEnabled(flags = {}) {
2159
+ return flags[WIZARD_ORCHESTRATOR_FLAG_KEY] === "true";
2160
+ }
2161
+ /**
1808
2162
  * Build env for the SDK subprocess: process.env plus ANTHROPIC_CUSTOM_HEADERS, which always
1809
2163
  * includes `x-posthog-use-bedrock-fallback: true` so the LLM gateway falls back to Bedrock on
1810
2164
  * Anthropic 5xx, plus any wizard metadata/flags.
@@ -2008,7 +2362,6 @@ async function initializeAgent(config, options) {
2008
2362
  initLogFile();
2009
2363
  logToFile("Agent initialization starting");
2010
2364
  logToFile("Install directory:", options.installDir);
2011
- getUI().log.step("Initializing Claude agent...");
2012
2365
  try {
2013
2366
  const gatewayUrl = getLlmGatewayUrlFromHost(config.posthogApiHost);
2014
2367
  process.env.ANTHROPIC_BASE_URL = gatewayUrl;
@@ -2038,7 +2391,8 @@ async function initializeAgent(config, options) {
2038
2391
  detectPackageManager: config.detectPackageManager,
2039
2392
  skillsBaseUrl: config.skillsBaseUrl,
2040
2393
  askBridge: config.askBridge,
2041
- askMaxQuestions: config.askMaxQuestions
2394
+ askMaxQuestions: config.askMaxQuestions,
2395
+ orchestrator: config.orchestrator
2042
2396
  });
2043
2397
  const agentRunConfig = {
2044
2398
  workingDirectory: config.workingDirectory,
@@ -2062,8 +2416,6 @@ async function initializeAgent(config, options) {
2062
2416
  gatewayUrl,
2063
2417
  apiKeyPresent: !!config.posthogApiKey
2064
2418
  });
2065
- getUI().log.step(`Verbose logs: ${getLogFilePath()}`);
2066
- getUI().log.success("Agent initialized. Let's get cooking!");
2067
2419
  return agentRunConfig;
2068
2420
  } catch (error) {
2069
2421
  getUI().log.error(`Failed to initialize agent: ${error.message}`);
@@ -2130,9 +2482,18 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
2130
2482
  } else logToFile(`Agent run completed in ${durationSeconds}s`);
2131
2483
  const remark = signals.remark();
2132
2484
  if (remark) analytics.capture(WIZARD_REMARK_EVENT_NAME, { remark });
2485
+ const usage = lastResultMessage?.usage;
2133
2486
  analytics.wizardCapture("agent completed", {
2134
2487
  duration_ms: durationMs,
2135
- duration_seconds: durationSeconds
2488
+ duration_seconds: durationSeconds,
2489
+ model: agentConfig.model,
2490
+ num_turns: lastResultMessage?.num_turns,
2491
+ total_cost_usd: lastResultMessage?.total_cost_usd,
2492
+ input_tokens: usage?.input_tokens,
2493
+ output_tokens: usage?.output_tokens,
2494
+ cache_creation_input_tokens: usage?.cache_creation_input_tokens,
2495
+ cache_read_input_tokens: usage?.cache_read_input_tokens,
2496
+ ...config?.analyticsProperties
2136
2497
  });
2137
2498
  try {
2138
2499
  middleware?.finalize(lastResultMessage, durationMs);
@@ -2239,7 +2600,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
2239
2600
  PreToolUse: createPreToolUseYaraHooks(),
2240
2601
  PostToolUse: createPostToolUseYaraHooks(),
2241
2602
  Stop: [{
2242
- hooks: [createStopHook(config?.additionalFeatureQueue ?? [], signals)],
2603
+ hooks: [createStopHook(config?.additionalFeatureQueue ?? [], signals, config?.requestRemark ?? true)],
2243
2604
  timeout: 30
2244
2605
  }]
2245
2606
  }
@@ -2263,7 +2624,7 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
2263
2624
  }
2264
2625
  loggedInitialContext = true;
2265
2626
  }
2266
- handleSDKMessage(message, options, spinner, signals, receivedSuccessResult, tasks);
2627
+ handleSDKMessage(message, options, spinner, signals, receivedSuccessResult, tasks, isOrchestratorEnabled(agentConfig.wizardFlags ?? {}));
2267
2628
  if (abortCases.length > 0 && !abortReason && message.type === "assistant") {
2268
2629
  const content = message.message?.content;
2269
2630
  if (Array.isArray(content)) {
@@ -2390,7 +2751,9 @@ async function runAgent(agentConfig, prompt, options, spinner, config, middlewar
2390
2751
  const durationMs = Date.now() - startTime;
2391
2752
  analytics.wizardCapture("agent aborted", {
2392
2753
  duration_ms: durationMs,
2393
- duration_seconds: Math.round(durationMs / 1e3)
2754
+ duration_seconds: Math.round(durationMs / 1e3),
2755
+ model: agentConfig.model,
2756
+ ...config?.analyticsProperties
2394
2757
  });
2395
2758
  }
2396
2759
  }
@@ -2500,14 +2863,14 @@ function extractTaskIdFromResult(content) {
2500
2863
  }
2501
2864
  }
2502
2865
  }
2503
- function handleSDKMessage(message, options, spinner, signals, receivedSuccessResult = false, tasks) {
2866
+ function handleSDKMessage(message, options, spinner, signals, receivedSuccessResult = false, tasks, suppressTaskRender = false) {
2504
2867
  const STATUS_RANK = {
2505
2868
  completed: 0,
2506
2869
  in_progress: 1
2507
2870
  };
2508
2871
  const rank = (status) => STATUS_RANK[status] ?? 2;
2509
2872
  const syncTasks = () => {
2510
- if (!tasks) return;
2873
+ if (!tasks || suppressTaskRender) return;
2511
2874
  const sorted = Array.from(tasks.values()).sort((a, b) => rank(a.status) - rank(b.status));
2512
2875
  getUI().syncTodos(sorted);
2513
2876
  };
@@ -2586,6 +2949,6 @@ function handleSDKMessage(message, options, spinner, signals, receivedSuccessRes
2586
2949
  }
2587
2950
  }
2588
2951
  //#endregion
2589
- export { AUDIT_CHECKS_KEY as _, backupAndFixClaudeSettings as a, coerceAuditChecks as b, restoreClaudeSettings as c, writeScanReport as d, WIZARD_TOOL_NAMES as f, AUDIT_CHECKS_FILE as g, installSkillById as h, runAgent as i, AgentSignals as l, fetchSkillMenu as m, buildWizardMetadata as n, checkAllSettingsConflicts as o, downloadSkill as p, initializeAgent as r, recoverOrphanedSettingsBackups as s, buildAgentEnv as t, formatScanReport as u, AUDIT_REPORT_FILE as v, getAuditChecks as x, AUDIT_SEVERITY_STYLE as y };
2952
+ export { AUDIT_SEVERITY_STYLE as C, AUDIT_REPORT_FILE as S, getAuditChecks as T, QUEUE_DIR_NAME as _, runAgent as a, AUDIT_CHECKS_FILE as b, recoverOrphanedSettingsBackups as c, formatScanReport as d, writeScanReport as f, installSkillById as g, fetchSkillMenu as h, isOrchestratorEnabled as i, restoreClaudeSettings as l, downloadSkill as m, buildWizardMetadata as n, backupAndFixClaudeSettings as o, WIZARD_TOOL_NAMES as p, initializeAgent as r, checkAllSettingsConflicts as s, buildAgentEnv as t, AgentSignals as u, QueueStore as v, coerceAuditChecks as w, AUDIT_CHECKS_KEY as x, TaskStatus as y };
2590
2953
 
2591
- //# sourceMappingURL=agent-interface-D1vtN6Wn.js.map
2954
+ //# sourceMappingURL=agent-interface-BsuUUPle.js.map