@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.
- package/dist/{add-mcp-server-to-clients-BiZmRLE6.js → add-mcp-server-to-clients-CNzZMSat.js} +5 -5
- package/dist/{add-mcp-server-to-clients-BiZmRLE6.js.map → add-mcp-server-to-clients-CNzZMSat.js.map} +1 -1
- package/dist/{agent-interface-CUaNjvqq.js → agent-interface-CF7GsdFf.js} +298 -158
- package/dist/agent-interface-CF7GsdFf.js.map +1 -0
- package/dist/{agent-runner-BuH7W62W.js → agent-runner-B0LTVFfw.js} +130 -598
- package/dist/agent-runner-B0LTVFfw.js.map +1 -0
- package/dist/{analytics-C_9Kh6J1.js → analytics-DQEuL6qS.js} +2 -2
- package/dist/{analytics-C_9Kh6J1.js.map → analytics-DQEuL6qS.js.map} +1 -1
- package/dist/analytics-YD3D38z2.js +2 -0
- package/dist/{api-Kgk7BFqo.js → api-uCMvDII5.js} +3 -3
- package/dist/{api-Kgk7BFqo.js.map → api-uCMvDII5.js.map} +1 -1
- package/dist/bin.js +69 -116
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-DoARcA-j.js → ci-install-Bow8-f0j.js} +4 -4
- package/dist/{ci-install-DoARcA-j.js.map → ci-install-Bow8-f0j.js.map} +1 -1
- package/dist/commandments-CyB7Icr1.js +42 -0
- package/dist/commandments-CyB7Icr1.js.map +1 -0
- package/dist/commandments-DguPfCX8.js +2 -0
- package/dist/{debug-CI0PLD6X.js → debug-BixHZmHv.js} +1 -1
- package/dist/{debug-DNEQR5DL.js → debug-DBmxx59Q.js} +42 -21
- package/dist/debug-DBmxx59Q.js.map +1 -0
- package/dist/{defaults-CeNThA-1.js → defaults-8zjNjGGi.js} +2 -2
- package/dist/defaults-8zjNjGGi.js.map +1 -0
- package/dist/{env-api-key-cjD4yfGT.js → env-api-key-AcC_tz8G.js} +1 -1
- package/dist/{env-api-key-cjD4yfGT.js.map → env-api-key-AcC_tz8G.js.map} +1 -1
- package/dist/{environment-D44UP2Nu.js → environment-kZtkp7eG.js} +3 -3
- package/dist/{environment-D44UP2Nu.js.map → environment-kZtkp7eG.js.map} +1 -1
- package/dist/{file-utils-C2PNKLhr.js → file-utils-BAhYy5vC.js} +2 -2
- package/dist/{file-utils-C2PNKLhr.js.map → file-utils-BAhYy5vC.js.map} +1 -1
- package/dist/file-watcher-BL-IRbR7.js +123 -0
- package/dist/file-watcher-BL-IRbR7.js.map +1 -0
- package/dist/{headless-ui-C3C0wWUi.js → headless-ui-DWmMyhaP.js} +5 -4
- package/dist/headless-ui-DWmMyhaP.js.map +1 -0
- package/dist/{interactive-k4xQiftO.js → interactive-Cyic0bGL.js} +2 -2
- package/dist/{interactive-k4xQiftO.js.map → interactive-Cyic0bGL.js.map} +1 -1
- package/dist/{mcp-CJn_ryMN.js → mcp-BSGmEWjt.js} +3 -3
- package/dist/mcp-BSGmEWjt.js.map +1 -0
- package/dist/{mcp-prompt-streaming-BB5nO--L.js → mcp-prompt-streaming-C227vG1X.js} +3 -3
- package/dist/{mcp-prompt-streaming-BB5nO--L.js.map → mcp-prompt-streaming-C227vG1X.js.map} +1 -1
- package/dist/{non-interactive-0x0Due8h.js → non-interactive-DQA9vn9f.js} +2 -2
- package/dist/{non-interactive-0x0Due8h.js.map → non-interactive-DQA9vn9f.js.map} +1 -1
- package/dist/orchestrator-tools-NuWONNkF.js +99 -0
- package/dist/orchestrator-tools-NuWONNkF.js.map +1 -0
- package/dist/{package-json-CDs1ZVKu.js → package-json-DCuoye-H.js} +1 -1
- package/dist/{package-json-CDs1ZVKu.js.map → package-json-DCuoye-H.js.map} +1 -1
- package/dist/{package-manager-CBRR4_i4.js → package-manager-DKtR3xzM.js} +2 -2
- package/dist/{package-manager-CBRR4_i4.js.map → package-manager-DKtR3xzM.js.map} +1 -1
- package/dist/pi-DJCln9jJ.js +603 -0
- package/dist/pi-DJCln9jJ.js.map +1 -0
- package/dist/{playground-CK617U6k.js → playground-CbEndzc8.js} +7 -8
- package/dist/{playground-CK617U6k.js.map → playground-CbEndzc8.js.map} +1 -1
- package/dist/{posthog-DwKlq0HM.js → posthog-DFyux4Vw.js} +1 -1
- package/dist/{posthog-DwKlq0HM.js.map → posthog-DFyux4Vw.js.map} +1 -1
- package/dist/{posthog-integration-qRjKkLcu.js → posthog-integration-dmWJZ8mj.js} +132 -27
- package/dist/posthog-integration-dmWJZ8mj.js.map +1 -0
- package/dist/{provisioning-BMXR8fS1.js → provisioning-CcxCry5p.js} +21 -14
- package/dist/provisioning-CcxCry5p.js.map +1 -0
- package/dist/queue-tools-Bw-AANLM.js +366 -0
- package/dist/queue-tools-Bw-AANLM.js.map +1 -0
- package/dist/{registry-CsUUdVCd.js → registry-D2V88NoC.js} +96 -18
- package/dist/registry-D2V88NoC.js.map +1 -0
- package/dist/{security-CIP3lpp6.js → security-DOtBCBvx.js} +4 -4
- package/dist/{security-CIP3lpp6.js.map → security-DOtBCBvx.js.map} +1 -1
- package/dist/{setup-utils-DkyEOBDx.js → setup-utils-Qp-u6BZk.js} +7 -7
- package/dist/{setup-utils-DkyEOBDx.js.map → setup-utils-Qp-u6BZk.js.map} +1 -1
- package/dist/{start-tui-CJlIgYjf.js → start-tui-DHa_9aiB.js} +429 -234
- package/dist/start-tui-DHa_9aiB.js.map +1 -0
- package/dist/{steps-CuNjxYsA.js → steps-D07HUQyE.js} +7 -7
- package/dist/{steps-CuNjxYsA.js.map → steps-D07HUQyE.js.map} +1 -1
- package/dist/{store-UKAJftq6.js → store-DSwsITKX.js} +30 -9
- package/dist/store-DSwsITKX.js.map +1 -0
- package/dist/{subagent-_syej145.js → subagent-Dk4K5MDa.js} +2 -2
- package/dist/{subagent-_syej145.js.map → subagent-Dk4K5MDa.js.map} +1 -1
- package/dist/task-CQnV9Qd2.js +305 -0
- package/dist/task-CQnV9Qd2.js.map +1 -0
- package/dist/{task-stream-Ne-9ZOnf.js → task-stream-B7qia9eW.js} +72 -7
- package/dist/task-stream-B7qia9eW.js.map +1 -0
- package/dist/{tasks-CUvCA1OY.js → tasks-C7BQp659.js} +2 -2
- package/dist/{tasks-CUvCA1OY.js.map → tasks-C7BQp659.js.map} +1 -1
- package/dist/{telemetry-DFYgJHH-.js → telemetry-DgahJGSx.js} +3 -3
- package/dist/{telemetry-DFYgJHH-.js.map → telemetry-DgahJGSx.js.map} +1 -1
- package/dist/{terminal-DLFgIxhg.js → terminal-Bb6tZkf-.js} +14 -14
- package/dist/terminal-Bb6tZkf-.js.map +1 -0
- package/dist/{tools-CNyhLqlK.js → tools-BJEvSUWN.js} +4 -4
- package/dist/{tools-CNyhLqlK.js.map → tools-BJEvSUWN.js.map} +1 -1
- package/dist/{types-y3HkjtSq.js → types-BRe_EzTW.js} +1 -1
- package/dist/{types-y3HkjtSq.js.map → types-BRe_EzTW.js.map} +1 -1
- package/dist/{wizard-abort-BM3pISoR.js → wizard-abort-BxtdkgI-.js} +4 -4
- package/dist/{wizard-abort-BM3pISoR.js.map → wizard-abort-BxtdkgI-.js.map} +1 -1
- package/dist/{wizard-abort-DCv08-op.js → wizard-abort-DpDmuCfA.js} +1 -1
- package/dist/{wizard-session-DXivb7kv.js → wizard-session-DWHe83uk.js} +1 -1
- package/dist/{wizard-session-BudcixsA.js → wizard-session-tp4Zdbwl.js} +3 -3
- package/dist/wizard-session-tp4Zdbwl.js.map +1 -0
- package/dist/{wizard-tools-BcuRxp1A.js → wizard-tools-Dg8o2lcH.js} +64 -387
- package/dist/wizard-tools-Dg8o2lcH.js.map +1 -0
- package/dist/yara-hooks-CncaWRuC.js +2 -0
- package/dist/{yara-hooks-GIs-R_g1.js → yara-hooks-pw86rZ8y.js} +4 -4
- package/dist/{yara-hooks-GIs-R_g1.js.map → yara-hooks-pw86rZ8y.js.map} +1 -1
- package/package.json +1 -1
- package/dist/agent-interface-CUaNjvqq.js.map +0 -1
- package/dist/agent-runner-BuH7W62W.js.map +0 -1
- package/dist/analytics-o-WJHD8Z.js +0 -2
- package/dist/debug-DNEQR5DL.js.map +0 -1
- package/dist/defaults-CeNThA-1.js.map +0 -1
- package/dist/headless-ui-C3C0wWUi.js.map +0 -1
- package/dist/mcp-CJn_ryMN.js.map +0 -1
- package/dist/posthog-integration-qRjKkLcu.js.map +0 -1
- package/dist/provisioning-BMXR8fS1.js.map +0 -1
- package/dist/registry-CsUUdVCd.js.map +0 -1
- package/dist/start-tui-CJlIgYjf.js.map +0 -1
- package/dist/store-UKAJftq6.js.map +0 -1
- package/dist/task-stream-Ne-9ZOnf.js.map +0 -1
- package/dist/terminal-DLFgIxhg.js.map +0 -1
- package/dist/wizard-session-BudcixsA.js.map +0 -1
- package/dist/wizard-tools-BcuRxp1A.js.map +0 -1
- package/dist/wizard-ui-WZ48rUgr.js +0 -15
- package/dist/wizard-ui-WZ48rUgr.js.map +0 -1
- package/dist/yara-hooks-DKbfESYf.js +0 -2
|
@@ -1,41 +1,12 @@
|
|
|
1
|
-
import { s as logToFile } from "./debug-
|
|
2
|
-
import { n as analytics } from "./analytics-
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
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/
|
|
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
|
-
*
|
|
349
|
-
*
|
|
350
|
-
*
|
|
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
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
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
|
-
|
|
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
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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
|
|
542
|
-
|
|
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
|
|
240
|
+
const data = await downloadWithRetry(skillEntry.downloadUrl);
|
|
564
241
|
step = "extract";
|
|
565
|
-
const fileCount = extractZipArchive(
|
|
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,
|
|
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-
|
|
783
|
+
//# sourceMappingURL=wizard-tools-Dg8o2lcH.js.map
|