@posthog/wizard 2.24.0 → 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.
- package/dist/{AiOptInRequiredScreen-DPn1CCeD.js → AiOptInRequiredScreen-C-D9tN6r.js} +156 -124
- package/dist/AiOptInRequiredScreen-C-D9tN6r.js.map +1 -0
- package/dist/{add-mcp-server-to-clients-BU8Owthq.js → add-mcp-server-to-clients-t0xe8gn1.js} +4 -4
- package/dist/{add-mcp-server-to-clients-BU8Owthq.js.map → add-mcp-server-to-clients-t0xe8gn1.js.map} +1 -1
- package/dist/{agent-interface-CysYcZl5.js → agent-interface-BsuUUPle.js} +403 -40
- package/dist/agent-interface-BsuUUPle.js.map +1 -0
- package/dist/{agent-runner-Br0OxBxd.js → agent-runner-L_-kJ3y3.js} +624 -17
- package/dist/agent-runner-L_-kJ3y3.js.map +1 -0
- package/dist/{analytics-BOWrR4qd.js → analytics-CDOujOSQ.js} +51 -17
- package/dist/analytics-CDOujOSQ.js.map +1 -0
- package/dist/{api-RXTR8yZo.js → api-DNS-L-1U.js} +3 -3
- package/dist/{api-RXTR8yZo.js.map → api-DNS-L-1U.js.map} +1 -1
- package/dist/bin.js +291 -75
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-BscZ60Ec.js → ci-install-_9A7tL36.js} +4 -4
- package/dist/{ci-install-BscZ60Ec.js.map → ci-install-_9A7tL36.js.map} +1 -1
- package/dist/{debug-BUdVZP84.js → debug-BwC7UkGH.js} +16 -8
- package/dist/debug-BwC7UkGH.js.map +1 -0
- package/dist/{debug-BgH07S-e.js → debug-CZQcMAJT.js} +1 -1
- package/dist/{environment-G0Hv6_JI.js → environment-DQPoj9sU.js} +3 -3
- package/dist/{environment-G0Hv6_JI.js.map → environment-DQPoj9sU.js.map} +1 -1
- package/dist/{interactive-fh2iyewb.js → interactive-DT5dLd7N.js} +2 -2
- package/dist/{interactive-fh2iyewb.js.map → interactive-DT5dLd7N.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-DUtbxnNy.js → mcp-prompt-streaming-CBMr458Q.js} +7 -26
- package/dist/mcp-prompt-streaming-CBMr458Q.js.map +1 -0
- package/dist/{non-interactive-BfqXlY8R.js → non-interactive-csP4yGdA.js} +2 -2
- package/dist/{non-interactive-BfqXlY8R.js.map → non-interactive-csP4yGdA.js.map} +1 -1
- package/dist/{package-manager-Ca1maxU-.js → package-manager-CB4c2euf.js} +2 -2
- package/dist/{package-manager-Ca1maxU-.js.map → package-manager-CB4c2euf.js.map} +1 -1
- package/dist/{playground-4sqLVVJL.js → playground-C-lpKoKC.js} +9 -15
- package/dist/playground-C-lpKoKC.js.map +1 -0
- package/dist/{posthog-integration-Bz3HWkHn.js → posthog-integration-BL8-vC0V.js} +18 -18
- package/dist/{posthog-integration-Bz3HWkHn.js.map → posthog-integration-BL8-vC0V.js.map} +1 -1
- package/dist/{provisioning-CgwvlsIl.js → provisioning-DLOiFSM9.js} +3 -3
- package/dist/{provisioning-CgwvlsIl.js.map → provisioning-DLOiFSM9.js.map} +1 -1
- package/dist/{registry-CEnQVctL.js → registry-BbRzCV5l.js} +4 -4
- package/dist/{registry-CEnQVctL.js.map → registry-BbRzCV5l.js.map} +1 -1
- package/dist/{setup-utils-Doh69vo4.js → setup-utils-D87CyNkw.js} +8 -8
- package/dist/{setup-utils-Doh69vo4.js.map → setup-utils-D87CyNkw.js.map} +1 -1
- package/dist/smoke-test.sh +36 -1
- package/dist/{start-tui-CywbSvZE.js → start-tui-DnAG57vY.js} +16 -20
- package/dist/start-tui-DnAG57vY.js.map +1 -0
- package/dist/{steps-DJojDYQ-.js → steps-JaxH6u0f.js} +6 -6
- package/dist/{steps-DJojDYQ-.js.map → steps-JaxH6u0f.js.map} +1 -1
- package/dist/{task-stream-CZawuzlz.js → task-stream-BQNSp0qR.js} +4 -3
- package/dist/task-stream-BQNSp0qR.js.map +1 -0
- package/dist/{telemetry-8zMpaIuK.js → telemetry-DL28cCwY.js} +3 -3
- package/dist/{telemetry-8zMpaIuK.js.map → telemetry-DL28cCwY.js.map} +1 -1
- package/dist/{urls-BUfvQmU4.js → urls-vkJ5c0ix.js} +2 -2
- package/dist/{urls-BUfvQmU4.js.map → urls-vkJ5c0ix.js.map} +1 -1
- package/dist/{wizard-abort-Ni-mKJ58.js → wizard-abort-BRXKRL4F.js} +1 -1
- package/dist/{wizard-abort-BdGW4Tvi.js → wizard-abort-CLGgMAEe.js} +3 -3
- package/dist/{wizard-abort-BdGW4Tvi.js.map → wizard-abort-CLGgMAEe.js.map} +1 -1
- package/dist/{wizard-ui-YdGFRyu_.js → wizard-ui-WZ48rUgr.js} +2 -1
- package/dist/wizard-ui-WZ48rUgr.js.map +1 -0
- package/package.json +1 -1
- package/dist/AiOptInRequiredScreen-DPn1CCeD.js.map +0 -1
- package/dist/agent-interface-CysYcZl5.js.map +0 -1
- package/dist/agent-runner-Br0OxBxd.js.map +0 -1
- package/dist/analytics-BOWrR4qd.js.map +0 -1
- package/dist/debug-BUdVZP84.js.map +0 -1
- package/dist/mcp-prompt-streaming-DUtbxnNy.js.map +0 -1
- package/dist/playground-4sqLVVJL.js.map +0 -1
- package/dist/start-tui-CywbSvZE.js.map +0 -1
- package/dist/task-stream-CZawuzlz.js.map +0 -1
- 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,
|
|
3
|
-
import { t as analytics } from "./analytics-
|
|
4
|
-
import { i as getLlmGatewayUrlFromHost } from "./urls-
|
|
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-
|
|
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
|
-
|
|
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 {
|
|
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-
|
|
2954
|
+
//# sourceMappingURL=agent-interface-BsuUUPle.js.map
|