@posthog/wizard 2.43.0 → 2.45.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 (118) hide show
  1. package/dist/{add-mcp-server-to-clients-BiZmRLE6.js → add-mcp-server-to-clients-CNzZMSat.js} +5 -5
  2. package/dist/{add-mcp-server-to-clients-BiZmRLE6.js.map → add-mcp-server-to-clients-CNzZMSat.js.map} +1 -1
  3. package/dist/{agent-interface-CUaNjvqq.js → agent-interface-CF7GsdFf.js} +298 -158
  4. package/dist/agent-interface-CF7GsdFf.js.map +1 -0
  5. package/dist/{agent-runner-BuH7W62W.js → agent-runner-B0LTVFfw.js} +130 -598
  6. package/dist/agent-runner-B0LTVFfw.js.map +1 -0
  7. package/dist/{analytics-C_9Kh6J1.js → analytics-DQEuL6qS.js} +2 -2
  8. package/dist/{analytics-C_9Kh6J1.js.map → analytics-DQEuL6qS.js.map} +1 -1
  9. package/dist/analytics-YD3D38z2.js +2 -0
  10. package/dist/{api-Kgk7BFqo.js → api-uCMvDII5.js} +3 -3
  11. package/dist/{api-Kgk7BFqo.js.map → api-uCMvDII5.js.map} +1 -1
  12. package/dist/bin.js +69 -116
  13. package/dist/bin.js.map +1 -1
  14. package/dist/{ci-install-DoARcA-j.js → ci-install-Bow8-f0j.js} +4 -4
  15. package/dist/{ci-install-DoARcA-j.js.map → ci-install-Bow8-f0j.js.map} +1 -1
  16. package/dist/commandments-CyB7Icr1.js +42 -0
  17. package/dist/commandments-CyB7Icr1.js.map +1 -0
  18. package/dist/commandments-DguPfCX8.js +2 -0
  19. package/dist/{debug-CI0PLD6X.js → debug-BixHZmHv.js} +1 -1
  20. package/dist/{debug-DNEQR5DL.js → debug-DBmxx59Q.js} +42 -21
  21. package/dist/debug-DBmxx59Q.js.map +1 -0
  22. package/dist/{defaults-CeNThA-1.js → defaults-8zjNjGGi.js} +2 -2
  23. package/dist/defaults-8zjNjGGi.js.map +1 -0
  24. package/dist/{env-api-key-cjD4yfGT.js → env-api-key-AcC_tz8G.js} +1 -1
  25. package/dist/{env-api-key-cjD4yfGT.js.map → env-api-key-AcC_tz8G.js.map} +1 -1
  26. package/dist/{environment-D44UP2Nu.js → environment-kZtkp7eG.js} +3 -3
  27. package/dist/{environment-D44UP2Nu.js.map → environment-kZtkp7eG.js.map} +1 -1
  28. package/dist/{file-utils-C2PNKLhr.js → file-utils-BAhYy5vC.js} +2 -2
  29. package/dist/{file-utils-C2PNKLhr.js.map → file-utils-BAhYy5vC.js.map} +1 -1
  30. package/dist/file-watcher-BL-IRbR7.js +123 -0
  31. package/dist/file-watcher-BL-IRbR7.js.map +1 -0
  32. package/dist/{headless-ui-C3C0wWUi.js → headless-ui-DWmMyhaP.js} +5 -4
  33. package/dist/headless-ui-DWmMyhaP.js.map +1 -0
  34. package/dist/{interactive-k4xQiftO.js → interactive-Cyic0bGL.js} +2 -2
  35. package/dist/{interactive-k4xQiftO.js.map → interactive-Cyic0bGL.js.map} +1 -1
  36. package/dist/{mcp-CJn_ryMN.js → mcp-BSGmEWjt.js} +3 -3
  37. package/dist/mcp-BSGmEWjt.js.map +1 -0
  38. package/dist/{mcp-prompt-streaming-BB5nO--L.js → mcp-prompt-streaming-C227vG1X.js} +3 -3
  39. package/dist/{mcp-prompt-streaming-BB5nO--L.js.map → mcp-prompt-streaming-C227vG1X.js.map} +1 -1
  40. package/dist/{non-interactive-0x0Due8h.js → non-interactive-DQA9vn9f.js} +2 -2
  41. package/dist/{non-interactive-0x0Due8h.js.map → non-interactive-DQA9vn9f.js.map} +1 -1
  42. package/dist/orchestrator-tools-NuWONNkF.js +99 -0
  43. package/dist/orchestrator-tools-NuWONNkF.js.map +1 -0
  44. package/dist/{package-json-CDs1ZVKu.js → package-json-DCuoye-H.js} +1 -1
  45. package/dist/{package-json-CDs1ZVKu.js.map → package-json-DCuoye-H.js.map} +1 -1
  46. package/dist/{package-manager-CBRR4_i4.js → package-manager-DKtR3xzM.js} +2 -2
  47. package/dist/{package-manager-CBRR4_i4.js.map → package-manager-DKtR3xzM.js.map} +1 -1
  48. package/dist/pi-DJCln9jJ.js +603 -0
  49. package/dist/pi-DJCln9jJ.js.map +1 -0
  50. package/dist/{playground-CK617U6k.js → playground-CbEndzc8.js} +7 -8
  51. package/dist/{playground-CK617U6k.js.map → playground-CbEndzc8.js.map} +1 -1
  52. package/dist/{posthog-DwKlq0HM.js → posthog-DFyux4Vw.js} +1 -1
  53. package/dist/{posthog-DwKlq0HM.js.map → posthog-DFyux4Vw.js.map} +1 -1
  54. package/dist/{posthog-integration-qRjKkLcu.js → posthog-integration-dmWJZ8mj.js} +132 -27
  55. package/dist/posthog-integration-dmWJZ8mj.js.map +1 -0
  56. package/dist/{provisioning-BMXR8fS1.js → provisioning-CcxCry5p.js} +21 -14
  57. package/dist/provisioning-CcxCry5p.js.map +1 -0
  58. package/dist/queue-tools-Bw-AANLM.js +366 -0
  59. package/dist/queue-tools-Bw-AANLM.js.map +1 -0
  60. package/dist/{registry-CsUUdVCd.js → registry-D2V88NoC.js} +96 -18
  61. package/dist/registry-D2V88NoC.js.map +1 -0
  62. package/dist/{security-CIP3lpp6.js → security-DOtBCBvx.js} +4 -4
  63. package/dist/{security-CIP3lpp6.js.map → security-DOtBCBvx.js.map} +1 -1
  64. package/dist/{setup-utils-DkyEOBDx.js → setup-utils-Qp-u6BZk.js} +7 -7
  65. package/dist/{setup-utils-DkyEOBDx.js.map → setup-utils-Qp-u6BZk.js.map} +1 -1
  66. package/dist/{start-tui-CJlIgYjf.js → start-tui-DHa_9aiB.js} +429 -234
  67. package/dist/start-tui-DHa_9aiB.js.map +1 -0
  68. package/dist/{steps-CuNjxYsA.js → steps-D07HUQyE.js} +7 -7
  69. package/dist/{steps-CuNjxYsA.js.map → steps-D07HUQyE.js.map} +1 -1
  70. package/dist/{store-UKAJftq6.js → store-DSwsITKX.js} +30 -9
  71. package/dist/store-DSwsITKX.js.map +1 -0
  72. package/dist/{subagent-_syej145.js → subagent-Dk4K5MDa.js} +2 -2
  73. package/dist/{subagent-_syej145.js.map → subagent-Dk4K5MDa.js.map} +1 -1
  74. package/dist/task-CQnV9Qd2.js +305 -0
  75. package/dist/task-CQnV9Qd2.js.map +1 -0
  76. package/dist/{task-stream-Ne-9ZOnf.js → task-stream-B7qia9eW.js} +72 -7
  77. package/dist/task-stream-B7qia9eW.js.map +1 -0
  78. package/dist/{tasks-CUvCA1OY.js → tasks-C7BQp659.js} +2 -2
  79. package/dist/{tasks-CUvCA1OY.js.map → tasks-C7BQp659.js.map} +1 -1
  80. package/dist/{telemetry-DFYgJHH-.js → telemetry-DgahJGSx.js} +3 -3
  81. package/dist/{telemetry-DFYgJHH-.js.map → telemetry-DgahJGSx.js.map} +1 -1
  82. package/dist/{terminal-DLFgIxhg.js → terminal-Bb6tZkf-.js} +14 -14
  83. package/dist/terminal-Bb6tZkf-.js.map +1 -0
  84. package/dist/{tools-CNyhLqlK.js → tools-BJEvSUWN.js} +4 -4
  85. package/dist/{tools-CNyhLqlK.js.map → tools-BJEvSUWN.js.map} +1 -1
  86. package/dist/{types-y3HkjtSq.js → types-BRe_EzTW.js} +1 -1
  87. package/dist/{types-y3HkjtSq.js.map → types-BRe_EzTW.js.map} +1 -1
  88. package/dist/{wizard-abort-BM3pISoR.js → wizard-abort-BxtdkgI-.js} +4 -4
  89. package/dist/{wizard-abort-BM3pISoR.js.map → wizard-abort-BxtdkgI-.js.map} +1 -1
  90. package/dist/{wizard-abort-DCv08-op.js → wizard-abort-DpDmuCfA.js} +1 -1
  91. package/dist/{wizard-session-DXivb7kv.js → wizard-session-DWHe83uk.js} +1 -1
  92. package/dist/{wizard-session-BudcixsA.js → wizard-session-tp4Zdbwl.js} +3 -3
  93. package/dist/wizard-session-tp4Zdbwl.js.map +1 -0
  94. package/dist/{wizard-tools-BcuRxp1A.js → wizard-tools-Dg8o2lcH.js} +64 -387
  95. package/dist/wizard-tools-Dg8o2lcH.js.map +1 -0
  96. package/dist/yara-hooks-CncaWRuC.js +2 -0
  97. package/dist/{yara-hooks-GIs-R_g1.js → yara-hooks-pw86rZ8y.js} +4 -4
  98. package/dist/{yara-hooks-GIs-R_g1.js.map → yara-hooks-pw86rZ8y.js.map} +1 -1
  99. package/package.json +1 -1
  100. package/dist/agent-interface-CUaNjvqq.js.map +0 -1
  101. package/dist/agent-runner-BuH7W62W.js.map +0 -1
  102. package/dist/analytics-o-WJHD8Z.js +0 -2
  103. package/dist/debug-DNEQR5DL.js.map +0 -1
  104. package/dist/defaults-CeNThA-1.js.map +0 -1
  105. package/dist/headless-ui-C3C0wWUi.js.map +0 -1
  106. package/dist/mcp-CJn_ryMN.js.map +0 -1
  107. package/dist/posthog-integration-qRjKkLcu.js.map +0 -1
  108. package/dist/provisioning-BMXR8fS1.js.map +0 -1
  109. package/dist/registry-CsUUdVCd.js.map +0 -1
  110. package/dist/start-tui-CJlIgYjf.js.map +0 -1
  111. package/dist/store-UKAJftq6.js.map +0 -1
  112. package/dist/task-stream-Ne-9ZOnf.js.map +0 -1
  113. package/dist/terminal-DLFgIxhg.js.map +0 -1
  114. package/dist/wizard-session-BudcixsA.js.map +0 -1
  115. package/dist/wizard-tools-BcuRxp1A.js.map +0 -1
  116. package/dist/wizard-ui-WZ48rUgr.js +0 -15
  117. package/dist/wizard-ui-WZ48rUgr.js.map +0 -1
  118. package/dist/yara-hooks-DKbfESYf.js +0 -2
@@ -1,41 +1,12 @@
1
- import { s as logToFile } from "./debug-DNEQR5DL.js";
2
- import { n as analytics } from "./analytics-C_9Kh6J1.js";
3
- import { a as coerceAuditChecks, t as AUDIT_CHECKS_FILE } from "./types-y3HkjtSq.js";
4
- import * as fs$1 from "fs";
1
+ import { s as logToFile } from "./debug-DBmxx59Q.js";
2
+ import { n as analytics } from "./analytics-DQEuL6qS.js";
3
+ import { c as makeMutex, i as buildOrchestratorTools, l as writeJsonAtomic } from "./queue-tools-Bw-AANLM.js";
4
+ import { a as coerceAuditChecks, t as AUDIT_CHECKS_FILE } from "./types-BRe_EzTW.js";
5
5
  import fs from "fs";
6
- import * as path$1 from "path";
7
6
  import path from "path";
8
7
  import { z } from "zod";
9
8
  import { unzipSync } from "fflate";
10
9
  import { randomUUID } from "crypto";
11
- //#region src/utils/atomic-ledger.ts
12
- /**
13
- * Small shared primitives for on-disk ledgers: an atomic JSON writer and a
14
- * single-chain async mutex. Used by the audit tools and by the orchestrator
15
- * queue. Lifted here so both share one implementation.
16
- */
17
- /**
18
- * Atomically write JSON: write to a `.tmp` file then rename over the target. The
19
- * rename bumps the file's mtime in one step, which is what a file watcher polls.
20
- */
21
- function writeJsonAtomic(targetPath, data) {
22
- const tmpPath = `${targetPath}.tmp`;
23
- fs$1.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf8");
24
- fs$1.renameSync(tmpPath, targetPath);
25
- }
26
- /**
27
- * A single async mutex. Serializes read-modify-write cycles so concurrent callers
28
- * (parallel task agents, audit tool calls) never interleave a mutation.
29
- */
30
- function makeMutex() {
31
- let chain = Promise.resolve();
32
- return async function run(fn) {
33
- const next = chain.then(() => fn());
34
- chain = next.catch(() => void 0);
35
- return next;
36
- };
37
- }
38
- //#endregion
39
10
  //#region src/lib/wizard-ask-bridge.ts
40
11
  /**
41
12
  * WizardAskBridge — host-side promise broker for the `wizard_ask` MCP tool.
@@ -146,334 +117,32 @@ function createSecretVault() {
146
117
  };
147
118
  }
148
119
  //#endregion
149
- //#region src/lib/agent/runner/sequence/orchestrator/queue.ts
150
- /**
151
- * The orchestrator task queue.
152
- *
153
- * In memory, synchronous, single-owner: one Node process drives the run, so
154
- * there is no locking. The queue imposes no execution policy — `nextRunnable`
155
- * returns every pending task whose dependencies are satisfied, and how many of
156
- * those run at once is decided by the task graph, not the queue.
157
- *
158
- * Every transition rewrites `<installDir>/.posthog-wizard-cache/queue.json`, a
159
- * small file holding the whole queue, handoffs included. It is the run's log
160
- * and the report's source. The whole cache folder is run-scoped and wiped when
161
- * the run ends.
162
- */
163
- const TaskStatus = {
164
- Pending: "pending",
165
- Running: "running",
166
- Done: "done",
167
- Skipped: "skipped",
168
- Failed: "failed"
169
- };
170
- const QUEUE_DIR_NAME = ".posthog-wizard-cache";
171
- const DEFAULT_MAX_ATTEMPTS = 2;
172
- function nowIso() {
173
- return (/* @__PURE__ */ new Date()).toISOString();
174
- }
175
- /** Dropped in the cache folder so an orphaned copy explains itself. */
176
- const DELETE_ME_FILE = ".DELETE-ME.md";
177
- const DELETE_ME_BODY = `# Safe to delete
178
-
179
- This folder contains run artifacts from the PostHog Wizard. This should have
180
- been deleted if the Wizard has finished running. If this wasn't deleted for
181
- some reason, you can safely delete the entire \`${QUEUE_DIR_NAME}/\` folder.
182
- `;
183
- var QueueStore = class {
184
- tasks = [];
185
- onTransition;
186
- runId;
187
- queuePath;
188
- constructor(installDir, runId, opts) {
189
- this.onTransition = opts?.onTransition;
190
- this.runId = runId;
191
- const dir = path$1.join(installDir, QUEUE_DIR_NAME);
192
- this.queuePath = path$1.join(dir, "queue.json");
193
- fs$1.mkdirSync(dir, { recursive: true });
194
- fs$1.writeFileSync(path$1.join(dir, DELETE_ME_FILE), DELETE_ME_BODY);
195
- }
196
- list() {
197
- return this.tasks;
198
- }
199
- get(id) {
200
- return this.tasks.find((t) => t.id === id);
201
- }
202
- /**
203
- * Every pending task whose dependencies are all satisfied (`done` or
204
- * `skipped`). A skipped dependency does not block downstream work.
205
- */
206
- nextRunnable() {
207
- const doneIds = new Set(this.tasks.filter((t) => t.status === TaskStatus.Done || t.status === TaskStatus.Skipped).map((t) => t.id));
208
- return this.tasks.filter((t) => t.status === TaskStatus.Pending && t.dependsOn.every((d) => doneIds.has(d)));
209
- }
210
- /**
211
- * True when no task is running and none can be started. Either everything
212
- * is terminal, or the only pending tasks are blocked by a failed dependency.
213
- */
214
- isDrained() {
215
- if (this.tasks.some((t) => t.status === TaskStatus.Running)) return false;
216
- return this.nextRunnable().length === 0;
217
- }
218
- summary() {
219
- const counts = {
220
- [TaskStatus.Pending]: 0,
221
- [TaskStatus.Running]: 0,
222
- [TaskStatus.Done]: 0,
223
- [TaskStatus.Skipped]: 0,
224
- [TaskStatus.Failed]: 0
225
- };
226
- for (const t of this.tasks) counts[t.status] += 1;
227
- return {
228
- ...counts,
229
- total: this.tasks.length
230
- };
231
- }
232
- readHandoff(id) {
233
- return this.get(id)?.handoff ?? null;
234
- }
235
- /** Handoffs of completed tasks of a given type, oldest first. */
236
- readHandoffsByType(type) {
237
- return this.tasks.filter((t) => t.type === type && t.handoff).map((t) => t.handoff);
238
- }
239
- enqueue(input) {
240
- const task = {
241
- id: randomUUID(),
242
- type: input.type,
243
- label: input.label,
244
- status: TaskStatus.Pending,
245
- dependsOn: input.dependsOn ?? [],
246
- inputs: input.inputs ?? {},
247
- model: input.model,
248
- attempts: 0,
249
- maxAttempts: input.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,
250
- enqueuedBy: input.enqueuedBy ?? "orchestrator",
251
- createdAt: nowIso()
252
- };
253
- this.tasks.push(task);
254
- this.reflect();
255
- this.notify("enqueue", task);
256
- return task;
257
- }
258
- start(id) {
259
- const t = this.require(id);
260
- t.status = TaskStatus.Running;
261
- t.startedAt = nowIso();
262
- t.attempts += 1;
263
- this.reflect();
264
- this.notify("start", t);
265
- return t;
266
- }
267
- complete(id, handoff) {
268
- return this.finish(id, TaskStatus.Done, handoff);
269
- }
270
- /** Terminal: the agent could not do the task. Not done, not failed. */
271
- skip(id, handoff) {
272
- return this.finish(id, TaskStatus.Skipped, handoff);
273
- }
274
- fail(id, error, handoff) {
275
- const t = this.require(id);
276
- t.error = error;
277
- return this.finish(id, TaskStatus.Failed, handoff);
278
- }
279
- /** Put a failed/running task back to pending for a retry within the run. */
280
- requeue(id) {
281
- const t = this.require(id);
282
- t.status = TaskStatus.Pending;
283
- t.startedAt = void 0;
284
- t.finishedAt = void 0;
285
- this.reflect();
286
- this.notify("requeue", t);
287
- return t;
288
- }
289
- finish(id, status, handoff) {
290
- const t = this.require(id);
291
- if (handoff) t.handoff = handoff;
292
- t.status = status;
293
- t.finishedAt = nowIso();
294
- this.reflect();
295
- this.notify(status === TaskStatus.Done ? "complete" : status === TaskStatus.Skipped ? "skip" : "fail", t);
296
- return t;
297
- }
298
- reflect() {
299
- const file = {
300
- version: 1,
301
- runId: this.runId,
302
- tasks: this.tasks
303
- };
304
- writeJsonAtomic(this.queuePath, file);
305
- }
306
- notify(event, task) {
307
- try {
308
- this.onTransition?.(event, task);
309
- } catch (error) {
310
- analytics.captureException(error instanceof Error ? error : new Error(String(error)), {
311
- step: "orchestrator_queue_listener",
312
- event
313
- });
314
- }
315
- }
316
- require(id) {
317
- const t = this.get(id);
318
- if (!t) throw new Error(`No task ${id} in the queue`);
319
- return t;
320
- }
321
- };
322
- //#endregion
323
- //#region src/lib/agent/runner/sequence/orchestrator/queue-tools.ts
324
- /**
325
- * Orchestrator MCP tools, registered into the existing `wizard-tools` server when
326
- * a queue is present. They let the orchestrator agent and task agents grow the
327
- * queue, report completion with a structured handoff, and read prior handoffs.
328
- *
329
- * The guard logic and the apply functions are plain, exported, and unit-tested.
330
- * `buildOrchestratorTools` wraps them in the SDK `tool()` shape.
331
- */
332
- function stableStringify(value) {
333
- if (value === null || typeof value !== "object") return JSON.stringify(value);
334
- if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
335
- return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
336
- }
337
- function dedupKey(type, inputs) {
338
- return `${type}::${stableStringify(inputs)}`;
339
- }
340
- /**
341
- * A backstop on total queue size. Tasks can enqueue tasks, so a misbehaving
342
- * type could grow the queue without bound. Keeping the graph small is the job
343
- * of good agent and skill design, not this number — it only stops a runaway.
344
- * The real flow is ~9 tasks, so this sits well clear of it.
345
- */
346
- const MAX_QUEUE_TASKS = 30;
120
+ //#region src/lib/fetch-retry.ts
347
121
  /**
348
- * Validate an enqueue. Structural checks only — a real type, real dependencies,
349
- * not a literal duplicate, and not past the runaway backstop. How much runs,
350
- * and in what shape, is the task graph's business, not a knob's.
122
+ * Retry wrapper for fetching from the skills/agents server (GitHub releases in
123
+ * production). GitHub releases blips transiently, so every fetch on the run's
124
+ * critical path — skill menu, skill zips, agent menu, agent prompt bodies —
125
+ * goes through here rather than a bare `fetch`.
351
126
  */
352
- function checkEnqueueGuards(ctx, args) {
353
- const tasks = ctx.store.list();
354
- if (tasks.length >= MAX_QUEUE_TASKS) return {
355
- ok: false,
356
- guard: "queue-full",
357
- message: `The queue already holds ${tasks.length} tasks (cap ${MAX_QUEUE_TASKS}). Refine the existing tasks rather than adding more.`
358
- };
359
- if (!ctx.validTypes.includes(args.type)) return {
360
- ok: false,
361
- guard: "unknown-type",
362
- message: `Unknown task type "${args.type}". Valid types: ${ctx.validTypes.join(", ")}.`
363
- };
364
- for (const dep of args.dependsOn ?? []) if (!ctx.store.get(dep)) return {
365
- ok: false,
366
- guard: "unknown-dep",
367
- message: `Dependency "${dep}" is not a known task id.`
368
- };
369
- const key = dedupKey(args.type, args.inputs ?? {});
370
- if (tasks.some((t) => t.status !== TaskStatus.Failed && dedupKey(t.type, t.inputs) === key)) return {
371
- ok: false,
372
- guard: "dedup",
373
- message: `A "${args.type}" task with these inputs already exists.`
374
- };
375
- return { ok: true };
376
- }
377
- function applyEnqueue(ctx, args) {
378
- const guard = checkEnqueueGuards(ctx, args);
379
- if (!guard.ok) return guard;
380
- return {
381
- ok: true,
382
- task: ctx.store.enqueue({
383
- type: args.type,
384
- label: args.label,
385
- inputs: args.inputs ?? {},
386
- dependsOn: args.dependsOn ?? [],
387
- model: args.model,
388
- enqueuedBy: ctx.currentTaskId ?? "orchestrator"
389
- })
390
- };
391
- }
392
- function applyComplete(ctx, args) {
393
- const id = ctx.currentTaskId;
394
- if (!id) return {
395
- ok: false,
396
- message: "complete_task can only be called by a running task agent."
397
- };
398
- if (args.status === TaskStatus.Failed) ctx.store.fail(id, {
399
- type: "self-reported",
400
- message: args.handoff.forNextAgent
401
- }, args.handoff);
402
- else if (args.status === TaskStatus.Skipped) ctx.store.skip(id, args.handoff);
403
- else ctx.store.complete(id, args.handoff);
404
- return { ok: true };
127
+ const DEFAULT_TIMEOUT_MS = 6e4;
128
+ const DEFAULT_MAX_ATTEMPTS = 3;
129
+ const DEFAULT_BACKOFF_MS = 500;
130
+ function sleep(ms) {
131
+ return new Promise((resolve) => setTimeout(resolve, ms));
405
132
  }
406
- function applyReadHandoffs(ctx, args) {
407
- if (args.taskId) {
408
- const h = ctx.store.readHandoff(args.taskId);
409
- return h ? [h] : [];
133
+ /** Fetch a URL, retrying transient failures (network error or non-ok HTTP) with backoff. */
134
+ async function fetchWithRetry(url, opts = {}) {
135
+ const { fetchImpl = fetch, sleepImpl = sleep, timeoutMs = DEFAULT_TIMEOUT_MS, maxAttempts = DEFAULT_MAX_ATTEMPTS, backoffMs = DEFAULT_BACKOFF_MS } = opts;
136
+ const failures = [];
137
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
138
+ const resp = await fetchImpl(url, { signal: AbortSignal.timeout(timeoutMs) });
139
+ if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
140
+ return resp;
141
+ } catch (err) {
142
+ failures.push(`attempt ${attempt}: ${err.message}`);
143
+ if (attempt < maxAttempts) await sleepImpl(backoffMs * 2 ** (attempt - 1));
410
144
  }
411
- if (args.type) return ctx.store.readHandoffsByType(args.type);
412
- const currentId = ctx.currentTaskId;
413
- const current = currentId ? ctx.store.get(currentId) : void 0;
414
- if (!current) return [];
415
- return current.dependsOn.map((depId) => ctx.store.readHandoff(depId)).filter((h) => h !== null);
416
- }
417
- const HANDOFF_SHAPE = {
418
- goals: z.string().describe("What this task was asked to achieve."),
419
- did: z.string().describe("What you actually did."),
420
- forNextAgent: z.string().describe("What the next agent should know."),
421
- filesTouched: z.array(z.string()).optional(),
422
- 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.")
423
- };
424
- function textResult(text, isError = false) {
425
- return {
426
- isError,
427
- content: [{
428
- type: "text",
429
- text
430
- }]
431
- };
432
- }
433
- /**
434
- * Build the orchestrator tools in the SDK `tool()` shape. Called from
435
- * createWizardToolsServer only when a queue context is present.
436
- */
437
- function buildOrchestratorTools(tool, ctx) {
438
- return [
439
- 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.", {
440
- type: z.string().describe(`The task type. One of: ${ctx.validTypes.join(", ")}.`),
441
- 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."),
442
- inputs: z.record(z.unknown()).optional(),
443
- dependsOn: z.array(z.string()).optional().describe("Task ids that must be done before this task runs."),
444
- model: z.string().optional(),
445
- reason: z.string().describe("One line on why this task is needed.")
446
- }, ((args) => {
447
- const res = applyEnqueue(ctx, args);
448
- if (!res.ok) {
449
- analytics.wizardCapture("orchestrator guard tripped", {
450
- guard: res.guard,
451
- type: args.type
452
- });
453
- return textResult(res.message, true);
454
- }
455
- return textResult(JSON.stringify({ id: res.task.id }));
456
- })),
457
- 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'.", {
458
- status: z.enum([
459
- "done",
460
- "failed",
461
- "skipped"
462
- ]),
463
- handoff: z.object(HANDOFF_SHAPE)
464
- }, ((args) => {
465
- const res = applyComplete(ctx, args);
466
- if (!res.ok) return textResult(res.message, true);
467
- return textResult("ok");
468
- })),
469
- tool("read_handoffs", "Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.", {
470
- type: z.string().optional(),
471
- taskId: z.string().optional()
472
- }, ((args) => {
473
- const handoffs = applyReadHandoffs(ctx, args);
474
- return textResult(JSON.stringify(handoffs, null, 2));
475
- }))
476
- ];
145
+ throw new Error(`fetch ${url} failed — ${failures.join("; ")}`);
477
146
  }
478
147
  //#endregion
479
148
  //#region src/lib/wizard-tools.ts
@@ -492,22 +161,29 @@ async function getSDKModule() {
492
161
  if (!_sdkModule) _sdkModule = await import("@anthropic-ai/claude-agent-sdk");
493
162
  return _sdkModule;
494
163
  }
164
+ /** Expand a bundle entry into one entry per variant, so the menu reads the same whether a group ships bundled or as zips. */
165
+ function expandBundleEntry(entry) {
166
+ if (!entry.bundle || !entry.variants) return [entry];
167
+ return entry.variants.map((variant) => ({
168
+ ...variant,
169
+ name: entry.name,
170
+ group: entry.group,
171
+ bundle: true,
172
+ downloadUrl: entry.downloadUrl
173
+ }));
174
+ }
495
175
  /**
496
176
  * Fetch the skill menu from the skills server.
497
177
  * Returns parsed data on success, `null` on failure.
498
178
  */
499
- async function fetchSkillMenu(skillsBaseUrl) {
179
+ async function fetchSkillMenu(skillsBaseUrl, opts = {}) {
180
+ const menuUrl = `${skillsBaseUrl}/skill-menu.json`;
500
181
  try {
501
- const menuUrl = `${skillsBaseUrl}/skill-menu.json`;
502
182
  logToFile(`fetchSkillMenu: fetching from ${menuUrl}`);
503
- const resp = await fetch(menuUrl);
504
- if (resp.ok) {
505
- const data = await resp.json();
506
- logToFile(`fetchSkillMenu: loaded (${Object.keys(data.categories).length} categories)`);
507
- return data;
508
- }
509
- logToFile(`fetchSkillMenu: failed with HTTP ${resp.status}`);
510
- return null;
183
+ const data = await (await fetchWithRetry(menuUrl, opts)).json();
184
+ for (const [category, entries] of Object.entries(data.categories)) data.categories[category] = entries.flatMap(expandBundleEntry);
185
+ logToFile(`fetchSkillMenu: loaded (${Object.keys(data.categories).length} categories)`);
186
+ return data;
511
187
  } catch (err) {
512
188
  logToFile(`fetchSkillMenu: error: ${err.message}`);
513
189
  return null;
@@ -530,25 +206,26 @@ function extractZipArchive(zip, destDir) {
530
206
  }
531
207
  return written;
532
208
  }
533
- const DOWNLOAD_TIMEOUT_MS = 6e4;
534
- const DOWNLOAD_MAX_ATTEMPTS = 3;
535
- const DOWNLOAD_BACKOFF_MS = 500;
536
- function sleep(ms) {
537
- return new Promise((resolve) => setTimeout(resolve, ms));
209
+ /** Unpack the one variant this entry names out of a bundle; the rest is noise and never hits disk. */
210
+ function extractBundle(bundle, destDir, entryId) {
211
+ if (typeof bundle?.id !== "string" || typeof bundle?.variants !== "object" || bundle.variants === null) throw new Error("malformed bundle: expected { id, variants }");
212
+ const files = bundle.variants[entryId.slice(bundle.id.length + 1)];
213
+ if (!files) throw new Error(`bundle ${bundle.id} has no variant "${entryId}"`);
214
+ const root = path.resolve(destDir);
215
+ let written = 0;
216
+ for (const [entryPath, contents] of Object.entries(files)) {
217
+ const target = path.resolve(root, entryPath);
218
+ if (target !== root && !target.startsWith(root + path.sep)) throw new Error(`bundle entry escapes destination: ${entryPath}`);
219
+ fs.mkdirSync(path.dirname(target), { recursive: true });
220
+ fs.writeFileSync(target, contents);
221
+ written++;
222
+ }
223
+ return written;
538
224
  }
539
225
  /** Download a URL to a buffer, retrying transient failures with backoff. */
540
226
  async function downloadWithRetry(url, opts = {}) {
541
- const { fetchImpl = fetch, sleepImpl = sleep, timeoutMs = DOWNLOAD_TIMEOUT_MS, maxAttempts = DOWNLOAD_MAX_ATTEMPTS, backoffMs = DOWNLOAD_BACKOFF_MS } = opts;
542
- const failures = [];
543
- for (let attempt = 1; attempt <= maxAttempts; attempt++) try {
544
- const resp = await fetchImpl(url, { signal: AbortSignal.timeout(timeoutMs) });
545
- if (!resp.ok) throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
546
- return new Uint8Array(await resp.arrayBuffer());
547
- } catch (err) {
548
- failures.push(`attempt ${attempt}: ${err.message}`);
549
- if (attempt < maxAttempts) await sleepImpl(backoffMs * 2 ** (attempt - 1));
550
- }
551
- throw new Error(`download failed — ${failures.join("; ")}`);
227
+ const resp = await fetchWithRetry(url, opts);
228
+ return new Uint8Array(await resp.arrayBuffer());
552
229
  }
553
230
  /**
554
231
  * Download and extract a skill.
@@ -560,9 +237,9 @@ async function downloadSkill(skillEntry, installDir, skillsRoot) {
560
237
  let step = "download";
561
238
  try {
562
239
  fs.mkdirSync(skillDir, { recursive: true });
563
- const zip = await downloadWithRetry(skillEntry.downloadUrl);
240
+ const data = await downloadWithRetry(skillEntry.downloadUrl);
564
241
  step = "extract";
565
- const fileCount = extractZipArchive(zip, skillDir);
242
+ const fileCount = skillEntry.bundle ? extractBundle(JSON.parse(Buffer.from(data).toString("utf8")), skillDir, skillEntry.id) : extractZipArchive(data, skillDir);
566
243
  fs.writeFileSync(path.join(skillDir, ".posthog-wizard"), "");
567
244
  logToFile(`downloadSkill: installed ${skillEntry.id} from ${skillEntry.downloadUrl} (${fileCount} files)`);
568
245
  return { success: true };
@@ -1101,6 +778,6 @@ const WIZARD_TOOL_NAMES = {
1101
778
  readHandoffs: `mcp__${SERVER_NAME}__read_handoffs`
1102
779
  };
1103
780
  //#endregion
1104
- export { installSkillById as a, resolveEnvPath as c, TaskStatus as d, createWizardAskBridge as f, fetchSkillMenu as i, QUEUE_DIR_NAME as l, createWizardToolsServer as n, mergeEnvValues as o, downloadSkill as r, parseEnvKeys as s, WIZARD_TOOL_NAMES as t, QueueStore as u };
781
+ export { installSkillById as a, resolveEnvPath as c, fetchSkillMenu as i, fetchWithRetry as l, createWizardToolsServer as n, mergeEnvValues as o, downloadSkill as r, parseEnvKeys as s, WIZARD_TOOL_NAMES as t, createWizardAskBridge as u };
1105
782
 
1106
- //# sourceMappingURL=wizard-tools-BcuRxp1A.js.map
783
+ //# sourceMappingURL=wizard-tools-Dg8o2lcH.js.map