@posthog/wizard 2.44.0 → 2.46.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/README.md +5 -1
- package/dist/{add-mcp-server-to-clients-D5qsqCkj.js → add-mcp-server-to-clients-Bv2CBSil.js} +53 -6
- package/dist/add-mcp-server-to-clients-Bv2CBSil.js.map +1 -0
- package/dist/{agent-interface-BvTxWiol.js → agent-interface-B8roB2UP.js} +1122 -157
- package/dist/agent-interface-B8roB2UP.js.map +1 -0
- package/dist/{agent-runner-BF6_f8Qh.js → agent-runner-CV3qh_2p.js} +298 -610
- package/dist/agent-runner-CV3qh_2p.js.map +1 -0
- package/dist/analytics-D7vUZgzf.js +2 -0
- package/dist/{analytics-DSlQuwOT.js → analytics-k76OWsl0.js} +20 -6
- package/dist/analytics-k76OWsl0.js.map +1 -0
- package/dist/{api-BXduJZrw.js → api-CmIWcW-U.js} +3 -3
- package/dist/{api-BXduJZrw.js.map → api-CmIWcW-U.js.map} +1 -1
- package/dist/bin.js +242 -1043
- package/dist/bin.js.map +1 -1
- package/dist/{ci-install-GirEJqu2.js → ci-install-CNEJxdHf.js} +4 -4
- package/dist/{ci-install-GirEJqu2.js.map → ci-install-CNEJxdHf.js.map} +1 -1
- package/dist/commandments-DSNrOeOC.js +42 -0
- package/dist/commandments-DSNrOeOC.js.map +1 -0
- package/dist/commandments-qTW7pwaT.js +2 -0
- package/dist/{debug-BOFxiVVs.js → debug-BwIo7nwn.js} +1 -1
- package/dist/{debug-DXfQFmcM.js → debug-C9HmIrwx.js} +36 -6
- package/dist/debug-C9HmIrwx.js.map +1 -0
- package/dist/{defaults-BWLIffh5.js → defaults-CtWMmC8s.js} +1 -1
- package/dist/{defaults-BWLIffh5.js.map → defaults-CtWMmC8s.js.map} +1 -1
- package/dist/{env-api-key-cjD4yfGT.js → env-api-key-C3LzH8Lr.js} +1 -1
- package/dist/{env-api-key-cjD4yfGT.js.map → env-api-key-C3LzH8Lr.js.map} +1 -1
- package/dist/{environment-F1yw21dG.js → environment-NJykOp33.js} +3 -3
- package/dist/{environment-F1yw21dG.js.map → environment-NJykOp33.js.map} +1 -1
- package/dist/{file-utils-D-7YfJ7A.js → file-utils-CLMcNIKi.js} +2 -2
- package/dist/{file-utils-D-7YfJ7A.js.map → file-utils-CLMcNIKi.js.map} +1 -1
- package/dist/file-watcher-CBDCNQVV.js +123 -0
- package/dist/file-watcher-CBDCNQVV.js.map +1 -0
- package/dist/{headless-ui-Dni0gPND.js → headless-ui-B3QKxbz8.js} +5 -4
- package/dist/headless-ui-B3QKxbz8.js.map +1 -0
- package/dist/{interactive-Bmi82rsO.js → interactive-CIJRex02.js} +2 -2
- package/dist/{interactive-Bmi82rsO.js.map → interactive-CIJRex02.js.map} +1 -1
- package/dist/{mcp-prompt-streaming-AtntLsJ8.js → mcp-prompt-streaming-D6OgW3lC.js} +3 -3
- package/dist/{mcp-prompt-streaming-AtntLsJ8.js.map → mcp-prompt-streaming-D6OgW3lC.js.map} +1 -1
- package/dist/{mcp-xKRDnrcq.js → mcp-qTjKHqXN.js} +3 -3
- package/dist/mcp-qTjKHqXN.js.map +1 -0
- package/dist/{non-interactive-BIHqcW8g.js → non-interactive-8Eypq_h-.js} +2 -2
- package/dist/{non-interactive-BIHqcW8g.js.map → non-interactive-8Eypq_h-.js.map} +1 -1
- package/dist/orchestrator-tools-DVXOV-kz.js +99 -0
- package/dist/orchestrator-tools-DVXOV-kz.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-C6R_zpML.js → package-manager-CAD9Uklp.js} +2 -2
- package/dist/{package-manager-C6R_zpML.js.map → package-manager-CAD9Uklp.js.map} +1 -1
- package/dist/pi-C9iHv5uG.js +619 -0
- package/dist/pi-C9iHv5uG.js.map +1 -0
- package/dist/{playground-DwL36I2u.js → playground-C-9Q3ETa.js} +8 -9
- package/dist/{playground-DwL36I2u.js.map → playground-C-9Q3ETa.js.map} +1 -1
- package/dist/{posthog-DwKlq0HM.js → posthog-DZZbziJ1.js} +1 -1
- package/dist/{posthog-DwKlq0HM.js.map → posthog-DZZbziJ1.js.map} +1 -1
- package/dist/{posthog-integration-BhLKCFsI.js → posthog-integration-Do997QON.js} +2206 -112
- package/dist/posthog-integration-Do997QON.js.map +1 -0
- package/dist/{provisioning-jVZm2E-A.js → provisioning-DpqnGk3z.js} +3 -3
- package/dist/{provisioning-jVZm2E-A.js.map → provisioning-DpqnGk3z.js.map} +1 -1
- package/dist/queue-tools-CTUgbOU8.js +366 -0
- package/dist/queue-tools-CTUgbOU8.js.map +1 -0
- package/dist/{registry-DcoBCMQR.js → registry-DT58jEYr.js} +96 -18
- package/dist/registry-DT58jEYr.js.map +1 -0
- package/dist/{security-jxjVsOpd.js → security-CTigdAWm.js} +10 -8
- package/dist/security-CTigdAWm.js.map +1 -0
- package/dist/{setup-utils-BQCl28D8.js → setup-utils-Cb5uACEO.js} +31 -9
- package/dist/setup-utils-Cb5uACEO.js.map +1 -0
- package/dist/{start-tui-DgSKFMVh.js → start-tui-Cwc-PFma.js} +37 -92
- package/dist/start-tui-Cwc-PFma.js.map +1 -0
- package/dist/{steps-erepgD0V.js → steps-DyEKYM4I.js} +7 -7
- package/dist/{steps-erepgD0V.js.map → steps-DyEKYM4I.js.map} +1 -1
- package/dist/{store-C79GoHCQ.js → store-4sj-vWr5.js} +5 -6
- package/dist/store-4sj-vWr5.js.map +1 -0
- package/dist/{subagent-aDlD_Ltz.js → subagent-D8_yDgCB.js} +2 -2
- package/dist/{subagent-aDlD_Ltz.js.map → subagent-D8_yDgCB.js.map} +1 -1
- package/dist/task-D8Y8pkzd.js +304 -0
- package/dist/task-D8Y8pkzd.js.map +1 -0
- package/dist/{task-stream-0Pk0tPBN.js → task-stream-DQT3vjwS.js} +72 -7
- package/dist/task-stream-DQT3vjwS.js.map +1 -0
- package/dist/{tasks-ZkrluXCa.js → tasks-D2WKssA5.js} +2 -2
- package/dist/{tasks-ZkrluXCa.js.map → tasks-D2WKssA5.js.map} +1 -1
- package/dist/{telemetry-DZShaH-y.js → telemetry-CYr4HgS2.js} +3 -3
- package/dist/{telemetry-DZShaH-y.js.map → telemetry-CYr4HgS2.js.map} +1 -1
- package/dist/{terminal-CEhufbJ4.js → terminal-1RfyHQC2.js} +13 -13
- package/dist/{terminal-CEhufbJ4.js.map → terminal-1RfyHQC2.js.map} +1 -1
- package/dist/tools-DQCUOQZX.js +199 -0
- package/dist/tools-DQCUOQZX.js.map +1 -0
- package/dist/{wizard-abort-UCm4Pd5m.js → wizard-abort-D_-v1zvS.js} +1 -1
- package/dist/{wizard-abort-C14PzXZ8.js → wizard-abort-FuyIaI_0.js} +4 -4
- package/dist/{wizard-abort-C14PzXZ8.js.map → wizard-abort-FuyIaI_0.js.map} +1 -1
- package/dist/{wizard-session-C5lZPPEc.js → wizard-session-DWHe83uk.js} +1 -1
- package/dist/{wizard-session-BAZql11N.js → wizard-session-tp4Zdbwl.js} +1 -1
- package/dist/{wizard-session-BAZql11N.js.map → wizard-session-tp4Zdbwl.js.map} +1 -1
- package/dist/yara-hooks-6gNnPFPo.js +2 -0
- package/dist/{yara-hooks-CPH8N4yz.js → yara-hooks-DdYRRxfH.js} +82 -21
- package/dist/yara-hooks-DdYRRxfH.js.map +1 -0
- package/package.json +1 -1
- package/dist/add-mcp-server-to-clients-D5qsqCkj.js.map +0 -1
- package/dist/agent-interface-BvTxWiol.js.map +0 -1
- package/dist/agent-runner-BF6_f8Qh.js.map +0 -1
- package/dist/analytics-C7Xx6csw.js +0 -2
- package/dist/analytics-DSlQuwOT.js.map +0 -1
- package/dist/debug-DXfQFmcM.js.map +0 -1
- package/dist/headless-ui-Dni0gPND.js.map +0 -1
- package/dist/mcp-xKRDnrcq.js.map +0 -1
- package/dist/posthog-integration-BhLKCFsI.js.map +0 -1
- package/dist/registry-DcoBCMQR.js.map +0 -1
- package/dist/security-jxjVsOpd.js.map +0 -1
- package/dist/setup-utils-BQCl28D8.js.map +0 -1
- package/dist/start-tui-DgSKFMVh.js.map +0 -1
- package/dist/store-C79GoHCQ.js.map +0 -1
- package/dist/task-stream-0Pk0tPBN.js.map +0 -1
- package/dist/tools-BIPMan6l.js +0 -122
- package/dist/tools-BIPMan6l.js.map +0 -1
- package/dist/types-y3HkjtSq.js +0 -46
- package/dist/types-y3HkjtSq.js.map +0 -1
- package/dist/wizard-tools-B7SLjCic.js +0 -1106
- package/dist/wizard-tools-B7SLjCic.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-CPH8N4yz.js.map +0 -1
- package/dist/yara-hooks-VZlj4Lib.js +0 -2
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { n as analytics } from "./analytics-k76OWsl0.js";
|
|
2
|
+
import * as fs$1 from "fs";
|
|
3
|
+
import * as path$1 from "path";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { randomUUID } from "crypto";
|
|
6
|
+
//#region src/utils/atomic-ledger.ts
|
|
7
|
+
/**
|
|
8
|
+
* Small shared primitives for on-disk ledgers: an atomic JSON writer and a
|
|
9
|
+
* single-chain async mutex. Used by the audit tools and by the orchestrator
|
|
10
|
+
* queue. Lifted here so both share one implementation.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Atomically write JSON: write to a `.tmp` file then rename over the target. The
|
|
14
|
+
* rename bumps the file's mtime in one step, which is what a file watcher polls.
|
|
15
|
+
*/
|
|
16
|
+
function writeJsonAtomic(targetPath, data) {
|
|
17
|
+
const tmpPath = `${targetPath}.tmp`;
|
|
18
|
+
fs$1.writeFileSync(tmpPath, JSON.stringify(data, null, 2), "utf8");
|
|
19
|
+
fs$1.renameSync(tmpPath, targetPath);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* A single async mutex. Serializes read-modify-write cycles so concurrent callers
|
|
23
|
+
* (parallel task agents, audit tool calls) never interleave a mutation.
|
|
24
|
+
*/
|
|
25
|
+
function makeMutex() {
|
|
26
|
+
let chain = Promise.resolve();
|
|
27
|
+
return async function run(fn) {
|
|
28
|
+
const next = chain.then(() => fn());
|
|
29
|
+
chain = next.catch(() => void 0);
|
|
30
|
+
return next;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/lib/agent/runner/sequence/orchestrator/queue.ts
|
|
35
|
+
/**
|
|
36
|
+
* The orchestrator task queue.
|
|
37
|
+
*
|
|
38
|
+
* In memory, synchronous, single-owner: one Node process drives the run, so
|
|
39
|
+
* there is no locking. The queue imposes no execution policy — `nextRunnable`
|
|
40
|
+
* returns every pending task whose dependencies are satisfied, and how many of
|
|
41
|
+
* those run at once is decided by the task graph, not the queue.
|
|
42
|
+
*
|
|
43
|
+
* Every transition rewrites `<installDir>/.posthog-wizard-cache/queue.json`, a
|
|
44
|
+
* small file holding the whole queue, handoffs included. It is the run's log
|
|
45
|
+
* and the report's source. The whole cache folder is run-scoped and wiped when
|
|
46
|
+
* the run ends.
|
|
47
|
+
*/
|
|
48
|
+
const TaskStatus = {
|
|
49
|
+
Pending: "pending",
|
|
50
|
+
Running: "running",
|
|
51
|
+
Done: "done",
|
|
52
|
+
Skipped: "skipped",
|
|
53
|
+
Failed: "failed"
|
|
54
|
+
};
|
|
55
|
+
const QUEUE_DIR_NAME = ".posthog-wizard-cache";
|
|
56
|
+
const DEFAULT_MAX_ATTEMPTS = 2;
|
|
57
|
+
function nowIso() {
|
|
58
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
59
|
+
}
|
|
60
|
+
/** Dropped in the cache folder so an orphaned copy explains itself. */
|
|
61
|
+
const DELETE_ME_FILE = ".DELETE-ME.md";
|
|
62
|
+
const DELETE_ME_BODY = `# Safe to delete
|
|
63
|
+
|
|
64
|
+
This folder contains run artifacts from the PostHog Wizard. This should have
|
|
65
|
+
been deleted if the Wizard has finished running. If this wasn't deleted for
|
|
66
|
+
some reason, you can safely delete the entire \`${QUEUE_DIR_NAME}/\` folder.
|
|
67
|
+
`;
|
|
68
|
+
var QueueStore = class {
|
|
69
|
+
tasks = [];
|
|
70
|
+
onTransition;
|
|
71
|
+
runId;
|
|
72
|
+
queuePath;
|
|
73
|
+
constructor(installDir, runId, opts) {
|
|
74
|
+
this.onTransition = opts?.onTransition;
|
|
75
|
+
this.runId = runId;
|
|
76
|
+
const dir = path$1.join(installDir, QUEUE_DIR_NAME);
|
|
77
|
+
this.queuePath = path$1.join(dir, "queue.json");
|
|
78
|
+
fs$1.mkdirSync(dir, { recursive: true });
|
|
79
|
+
fs$1.writeFileSync(path$1.join(dir, DELETE_ME_FILE), DELETE_ME_BODY);
|
|
80
|
+
}
|
|
81
|
+
list() {
|
|
82
|
+
return this.tasks;
|
|
83
|
+
}
|
|
84
|
+
get(id) {
|
|
85
|
+
return this.tasks.find((t) => t.id === id);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Every pending task whose dependencies are all satisfied (`done` or
|
|
89
|
+
* `skipped`). A skipped dependency does not block downstream work.
|
|
90
|
+
*/
|
|
91
|
+
nextRunnable() {
|
|
92
|
+
const doneIds = new Set(this.tasks.filter((t) => t.status === TaskStatus.Done || t.status === TaskStatus.Skipped).map((t) => t.id));
|
|
93
|
+
return this.tasks.filter((t) => t.status === TaskStatus.Pending && t.dependsOn.every((d) => doneIds.has(d)));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* True when no task is running and none can be started. Either everything
|
|
97
|
+
* is terminal, or the only pending tasks are blocked by a failed dependency.
|
|
98
|
+
*/
|
|
99
|
+
isDrained() {
|
|
100
|
+
if (this.tasks.some((t) => t.status === TaskStatus.Running)) return false;
|
|
101
|
+
return this.nextRunnable().length === 0;
|
|
102
|
+
}
|
|
103
|
+
summary() {
|
|
104
|
+
const counts = {
|
|
105
|
+
[TaskStatus.Pending]: 0,
|
|
106
|
+
[TaskStatus.Running]: 0,
|
|
107
|
+
[TaskStatus.Done]: 0,
|
|
108
|
+
[TaskStatus.Skipped]: 0,
|
|
109
|
+
[TaskStatus.Failed]: 0
|
|
110
|
+
};
|
|
111
|
+
for (const t of this.tasks) counts[t.status] += 1;
|
|
112
|
+
return {
|
|
113
|
+
...counts,
|
|
114
|
+
total: this.tasks.length
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
readHandoff(id) {
|
|
118
|
+
return this.get(id)?.handoff ?? null;
|
|
119
|
+
}
|
|
120
|
+
/** Handoffs of completed tasks of a given type, oldest first. */
|
|
121
|
+
readHandoffsByType(type) {
|
|
122
|
+
return this.tasks.filter((t) => t.type === type && t.handoff).map((t) => t.handoff);
|
|
123
|
+
}
|
|
124
|
+
enqueue(input) {
|
|
125
|
+
const task = {
|
|
126
|
+
id: randomUUID(),
|
|
127
|
+
type: input.type,
|
|
128
|
+
label: input.label,
|
|
129
|
+
status: TaskStatus.Pending,
|
|
130
|
+
dependsOn: input.dependsOn ?? [],
|
|
131
|
+
inputs: input.inputs ?? {},
|
|
132
|
+
model: input.model,
|
|
133
|
+
attempts: 0,
|
|
134
|
+
maxAttempts: input.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,
|
|
135
|
+
enqueuedBy: input.enqueuedBy ?? "orchestrator",
|
|
136
|
+
createdAt: nowIso()
|
|
137
|
+
};
|
|
138
|
+
this.tasks.push(task);
|
|
139
|
+
this.reflect();
|
|
140
|
+
this.notify("enqueue", task);
|
|
141
|
+
return task;
|
|
142
|
+
}
|
|
143
|
+
start(id) {
|
|
144
|
+
const t = this.require(id);
|
|
145
|
+
t.status = TaskStatus.Running;
|
|
146
|
+
t.startedAt = nowIso();
|
|
147
|
+
t.attempts += 1;
|
|
148
|
+
this.reflect();
|
|
149
|
+
this.notify("start", t);
|
|
150
|
+
return t;
|
|
151
|
+
}
|
|
152
|
+
complete(id, handoff) {
|
|
153
|
+
return this.finish(id, TaskStatus.Done, handoff);
|
|
154
|
+
}
|
|
155
|
+
/** Terminal: the agent could not do the task. Not done, not failed. */
|
|
156
|
+
skip(id, handoff) {
|
|
157
|
+
return this.finish(id, TaskStatus.Skipped, handoff);
|
|
158
|
+
}
|
|
159
|
+
fail(id, error, handoff) {
|
|
160
|
+
const t = this.require(id);
|
|
161
|
+
t.error = error;
|
|
162
|
+
return this.finish(id, TaskStatus.Failed, handoff);
|
|
163
|
+
}
|
|
164
|
+
/** Put a failed/running task back to pending for a retry within the run. */
|
|
165
|
+
requeue(id) {
|
|
166
|
+
const t = this.require(id);
|
|
167
|
+
t.status = TaskStatus.Pending;
|
|
168
|
+
t.startedAt = void 0;
|
|
169
|
+
t.finishedAt = void 0;
|
|
170
|
+
this.reflect();
|
|
171
|
+
this.notify("requeue", t);
|
|
172
|
+
return t;
|
|
173
|
+
}
|
|
174
|
+
finish(id, status, handoff) {
|
|
175
|
+
const t = this.require(id);
|
|
176
|
+
if (handoff) t.handoff = handoff;
|
|
177
|
+
t.status = status;
|
|
178
|
+
t.finishedAt = nowIso();
|
|
179
|
+
this.reflect();
|
|
180
|
+
this.notify(status === TaskStatus.Done ? "complete" : status === TaskStatus.Skipped ? "skip" : "fail", t);
|
|
181
|
+
return t;
|
|
182
|
+
}
|
|
183
|
+
reflect() {
|
|
184
|
+
const file = {
|
|
185
|
+
version: 1,
|
|
186
|
+
runId: this.runId,
|
|
187
|
+
tasks: this.tasks
|
|
188
|
+
};
|
|
189
|
+
writeJsonAtomic(this.queuePath, file);
|
|
190
|
+
}
|
|
191
|
+
notify(event, task) {
|
|
192
|
+
try {
|
|
193
|
+
this.onTransition?.(event, task);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
analytics.captureException(error instanceof Error ? error : new Error(String(error)), {
|
|
196
|
+
step: "orchestrator_queue_listener",
|
|
197
|
+
event
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
require(id) {
|
|
202
|
+
const t = this.get(id);
|
|
203
|
+
if (!t) throw new Error(`No task ${id} in the queue`);
|
|
204
|
+
return t;
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region src/lib/agent/runner/sequence/orchestrator/queue-tools.ts
|
|
209
|
+
/**
|
|
210
|
+
* Orchestrator MCP tools, registered into the existing `wizard-tools` server when
|
|
211
|
+
* a queue is present. They let the orchestrator agent and task agents grow the
|
|
212
|
+
* queue, report completion with a structured handoff, and read prior handoffs.
|
|
213
|
+
*
|
|
214
|
+
* The guard logic and the apply functions are plain, exported, and unit-tested.
|
|
215
|
+
* `buildOrchestratorTools` wraps them in the SDK `tool()` shape.
|
|
216
|
+
*/
|
|
217
|
+
function stableStringify(value) {
|
|
218
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
219
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
220
|
+
return `{${Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`).join(",")}}`;
|
|
221
|
+
}
|
|
222
|
+
function dedupKey(type, inputs) {
|
|
223
|
+
return `${type}::${stableStringify(inputs)}`;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* A backstop on total queue size. Tasks can enqueue tasks, so a misbehaving
|
|
227
|
+
* type could grow the queue without bound. Keeping the graph small is the job
|
|
228
|
+
* of good agent and skill design, not this number — it only stops a runaway.
|
|
229
|
+
* The real flow is ~9 tasks, so this sits well clear of it.
|
|
230
|
+
*/
|
|
231
|
+
const MAX_QUEUE_TASKS = 30;
|
|
232
|
+
/**
|
|
233
|
+
* Validate an enqueue. Structural checks only — a real type, real dependencies,
|
|
234
|
+
* not a literal duplicate, and not past the runaway backstop. How much runs,
|
|
235
|
+
* and in what shape, is the task graph's business, not a knob's.
|
|
236
|
+
*/
|
|
237
|
+
function checkEnqueueGuards(ctx, args) {
|
|
238
|
+
const tasks = ctx.store.list();
|
|
239
|
+
if (tasks.length >= MAX_QUEUE_TASKS) return {
|
|
240
|
+
ok: false,
|
|
241
|
+
guard: "queue-full",
|
|
242
|
+
message: `The queue already holds ${tasks.length} tasks (cap ${MAX_QUEUE_TASKS}). Refine the existing tasks rather than adding more.`
|
|
243
|
+
};
|
|
244
|
+
if (!ctx.validTypes.includes(args.type)) return {
|
|
245
|
+
ok: false,
|
|
246
|
+
guard: "unknown-type",
|
|
247
|
+
message: `Unknown task type "${args.type}". Valid types: ${ctx.validTypes.join(", ")}.`
|
|
248
|
+
};
|
|
249
|
+
for (const dep of args.dependsOn ?? []) if (!ctx.store.get(dep)) return {
|
|
250
|
+
ok: false,
|
|
251
|
+
guard: "unknown-dep",
|
|
252
|
+
message: `Dependency "${dep}" is not a known task id.`
|
|
253
|
+
};
|
|
254
|
+
const key = dedupKey(args.type, args.inputs ?? {});
|
|
255
|
+
if (tasks.some((t) => t.status !== TaskStatus.Failed && dedupKey(t.type, t.inputs) === key)) return {
|
|
256
|
+
ok: false,
|
|
257
|
+
guard: "dedup",
|
|
258
|
+
message: `A "${args.type}" task with these inputs already exists.`
|
|
259
|
+
};
|
|
260
|
+
return { ok: true };
|
|
261
|
+
}
|
|
262
|
+
function applyEnqueue(ctx, args) {
|
|
263
|
+
const guard = checkEnqueueGuards(ctx, args);
|
|
264
|
+
if (!guard.ok) return guard;
|
|
265
|
+
return {
|
|
266
|
+
ok: true,
|
|
267
|
+
task: ctx.store.enqueue({
|
|
268
|
+
type: args.type,
|
|
269
|
+
label: args.label,
|
|
270
|
+
inputs: args.inputs ?? {},
|
|
271
|
+
dependsOn: args.dependsOn ?? [],
|
|
272
|
+
model: args.model,
|
|
273
|
+
enqueuedBy: ctx.currentTaskId ?? "orchestrator"
|
|
274
|
+
})
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function applyComplete(ctx, args) {
|
|
278
|
+
const id = ctx.currentTaskId;
|
|
279
|
+
if (!id) return {
|
|
280
|
+
ok: false,
|
|
281
|
+
message: "complete_task can only be called by a running task agent."
|
|
282
|
+
};
|
|
283
|
+
if (args.status === TaskStatus.Failed) ctx.store.fail(id, {
|
|
284
|
+
type: "self-reported",
|
|
285
|
+
message: args.handoff.forNextAgent
|
|
286
|
+
}, args.handoff);
|
|
287
|
+
else if (args.status === TaskStatus.Skipped) ctx.store.skip(id, args.handoff);
|
|
288
|
+
else ctx.store.complete(id, args.handoff);
|
|
289
|
+
return { ok: true };
|
|
290
|
+
}
|
|
291
|
+
function applyReadHandoffs(ctx, args) {
|
|
292
|
+
if (args.taskId) {
|
|
293
|
+
const h = ctx.store.readHandoff(args.taskId);
|
|
294
|
+
return h ? [h] : [];
|
|
295
|
+
}
|
|
296
|
+
if (args.type) return ctx.store.readHandoffsByType(args.type);
|
|
297
|
+
const currentId = ctx.currentTaskId;
|
|
298
|
+
const current = currentId ? ctx.store.get(currentId) : void 0;
|
|
299
|
+
if (!current) return [];
|
|
300
|
+
return current.dependsOn.map((depId) => ctx.store.readHandoff(depId)).filter((h) => h !== null);
|
|
301
|
+
}
|
|
302
|
+
const HANDOFF_SHAPE = {
|
|
303
|
+
goals: z.string().describe("What this task was asked to achieve."),
|
|
304
|
+
did: z.string().describe("What you actually did."),
|
|
305
|
+
forNextAgent: z.string().describe("What the next agent should know."),
|
|
306
|
+
filesTouched: z.array(z.string()).optional(),
|
|
307
|
+
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.")
|
|
308
|
+
};
|
|
309
|
+
function textResult(text, isError = false) {
|
|
310
|
+
return {
|
|
311
|
+
isError,
|
|
312
|
+
content: [{
|
|
313
|
+
type: "text",
|
|
314
|
+
text
|
|
315
|
+
}]
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Build the orchestrator tools in the SDK `tool()` shape. Called from
|
|
320
|
+
* createWizardToolsServer only when a queue context is present.
|
|
321
|
+
*/
|
|
322
|
+
function buildOrchestratorTools(tool, ctx) {
|
|
323
|
+
return [
|
|
324
|
+
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.", {
|
|
325
|
+
type: z.string().describe(`The task type. One of: ${ctx.validTypes.join(", ")}.`),
|
|
326
|
+
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."),
|
|
327
|
+
inputs: z.record(z.unknown()).optional(),
|
|
328
|
+
dependsOn: z.array(z.string()).optional().describe("Task ids that must be done before this task runs."),
|
|
329
|
+
model: z.string().optional(),
|
|
330
|
+
reason: z.string().describe("One line on why this task is needed.")
|
|
331
|
+
}, ((args) => {
|
|
332
|
+
const res = applyEnqueue(ctx, args);
|
|
333
|
+
if (!res.ok) {
|
|
334
|
+
analytics.wizardCapture("orchestrator guard tripped", {
|
|
335
|
+
guard: res.guard,
|
|
336
|
+
type: args.type
|
|
337
|
+
});
|
|
338
|
+
return textResult(res.message, true);
|
|
339
|
+
}
|
|
340
|
+
return textResult(JSON.stringify({ id: res.task.id }));
|
|
341
|
+
})),
|
|
342
|
+
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'.", {
|
|
343
|
+
status: z.enum([
|
|
344
|
+
"done",
|
|
345
|
+
"failed",
|
|
346
|
+
"skipped"
|
|
347
|
+
]),
|
|
348
|
+
handoff: z.object(HANDOFF_SHAPE)
|
|
349
|
+
}, ((args) => {
|
|
350
|
+
const res = applyComplete(ctx, args);
|
|
351
|
+
if (!res.ok) return textResult(res.message, true);
|
|
352
|
+
return textResult("ok");
|
|
353
|
+
})),
|
|
354
|
+
tool("read_handoffs", "Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.", {
|
|
355
|
+
type: z.string().optional(),
|
|
356
|
+
taskId: z.string().optional()
|
|
357
|
+
}, ((args) => {
|
|
358
|
+
const handoffs = applyReadHandoffs(ctx, args);
|
|
359
|
+
return textResult(JSON.stringify(handoffs, null, 2));
|
|
360
|
+
}))
|
|
361
|
+
];
|
|
362
|
+
}
|
|
363
|
+
//#endregion
|
|
364
|
+
export { QUEUE_DIR_NAME as a, makeMutex as c, buildOrchestratorTools as i, writeJsonAtomic as l, applyEnqueue as n, QueueStore as o, applyReadHandoffs as r, TaskStatus as s, applyComplete as t };
|
|
365
|
+
|
|
366
|
+
//# sourceMappingURL=queue-tools-CTUgbOU8.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-tools-CTUgbOU8.js","names":["path"],"sources":["../src/utils/atomic-ledger.ts","../src/lib/agent/runner/sequence/orchestrator/queue.ts","../src/lib/agent/runner/sequence/orchestrator/queue-tools.ts"],"sourcesContent":["/**\n * Small shared primitives for on-disk ledgers: an atomic JSON writer and a\n * single-chain async mutex. Used by the audit tools and by the orchestrator\n * queue. Lifted here so both share one implementation.\n */\nimport * as fs from 'fs';\n\n/**\n * Atomically write JSON: write to a `.tmp` file then rename over the target. The\n * rename bumps the file's mtime in one step, which is what a file watcher polls.\n */\nexport function writeJsonAtomic(targetPath: string, data: unknown): void {\n const tmpPath = `${targetPath}.tmp`;\n fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), 'utf8');\n fs.renameSync(tmpPath, targetPath);\n}\n\n/**\n * A single async mutex. Serializes read-modify-write cycles so concurrent callers\n * (parallel task agents, audit tool calls) never interleave a mutation.\n */\nexport function makeMutex() {\n let chain: Promise<unknown> = Promise.resolve();\n return async function run<T>(fn: () => Promise<T> | T): Promise<T> {\n const next = chain.then(() => fn());\n chain = next.catch(() => undefined);\n return next;\n };\n}\n","/**\n * The orchestrator task queue.\n *\n * In memory, synchronous, single-owner: one Node process drives the run, so\n * there is no locking. The queue imposes no execution policy — `nextRunnable`\n * returns every pending task whose dependencies are satisfied, and how many of\n * those run at once is decided by the task graph, not the queue.\n *\n * Every transition rewrites `<installDir>/.posthog-wizard-cache/queue.json`, a\n * small file holding the whole queue, handoffs included. It is the run's log\n * and the report's source. The whole cache folder is run-scoped and wiped when\n * the run ends.\n */\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport { randomUUID } from 'crypto';\nimport { writeJsonAtomic } from '@utils/atomic-ledger';\nimport { analytics } from '@utils/analytics';\n\nexport const TaskStatus = {\n Pending: 'pending',\n Running: 'running',\n Done: 'done',\n Skipped: 'skipped',\n Failed: 'failed',\n} as const;\n\nexport type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus];\n\nexport interface QueuedTask {\n id: string;\n type: string;\n /** Human-readable label for the TUI, set by the enqueuing agent. */\n label?: string;\n status: TaskStatus;\n /**\n * Ids of tasks that must finish before this one runs. Ids are generated at\n * enqueue and dependsOn is never mutated, so a task can only depend on tasks\n * created before it — the graph is a DAG by construction, cycles cannot\n * form. Unknown ids are rejected by the enqueue_task guard.\n */\n dependsOn: string[];\n inputs: Record<string, unknown>;\n model?: string;\n attempts: number;\n maxAttempts: number;\n /** The structured handoff the task reported on completion. */\n handoff?: TaskHandoff;\n /** 'orchestrator' for seeded tasks, or the id of the task that enqueued this one. */\n enqueuedBy: string;\n createdAt: string;\n startedAt?: string;\n finishedAt?: string;\n error?: { type: string; message: string };\n}\n\nexport interface QueueFile {\n version: 1;\n runId: string;\n tasks: QueuedTask[];\n}\n\n/** The structured handoff a task leaves for the next agent. */\nexport interface TaskHandoff {\n goals: string;\n did: string;\n forNextAgent: string;\n filesTouched?: string[];\n /** A one-line summary of any unresolved conflict, surfaced in the outro. */\n conflict?: string;\n}\n\nexport interface EnqueueInput {\n type: string;\n label?: string;\n inputs?: Record<string, unknown>;\n dependsOn?: string[];\n model?: string;\n maxAttempts?: number;\n enqueuedBy?: string;\n}\n\nexport const QUEUE_DIR_NAME = '.posthog-wizard-cache';\nconst DEFAULT_MAX_ATTEMPTS = 2;\n\nfunction nowIso(): string {\n return new Date().toISOString();\n}\n\n/** Dropped in the cache folder so an orphaned copy explains itself. */\nconst DELETE_ME_FILE = '.DELETE-ME.md';\nconst DELETE_ME_BODY = `# Safe to delete\n\nThis folder contains run artifacts from the PostHog Wizard. This should have\nbeen deleted if the Wizard has finished running. If this wasn't deleted for\nsome reason, you can safely delete the entire \\`${QUEUE_DIR_NAME}/\\` folder.\n`;\n\n/** Every queue transition, in the order it is reflected. */\nexport type TransitionEvent =\n | 'enqueue'\n | 'start'\n | 'complete'\n | 'skip'\n | 'fail'\n | 'requeue';\n\nexport interface QueueStoreOptions {\n /**\n * Called on every transition with the task's post-transition state. The\n * runner uses it for telemetry; the store itself stays analytics-free.\n * Listener errors are reported but cannot break a transition.\n */\n onTransition?: (event: TransitionEvent, task: QueuedTask) => void;\n}\n\nexport class QueueStore {\n private tasks: QueuedTask[] = [];\n private readonly onTransition?: (\n event: TransitionEvent,\n task: QueuedTask,\n ) => void;\n\n readonly runId: string;\n readonly queuePath: string;\n\n constructor(installDir: string, runId: string, opts?: QueueStoreOptions) {\n this.onTransition = opts?.onTransition;\n this.runId = runId;\n const dir = path.join(installDir, QUEUE_DIR_NAME);\n this.queuePath = path.join(dir, 'queue.json');\n fs.mkdirSync(dir, { recursive: true });\n fs.writeFileSync(path.join(dir, DELETE_ME_FILE), DELETE_ME_BODY);\n }\n\n // ── Reads ───────────────────────────────────────────────────────────\n\n list(): readonly QueuedTask[] {\n return this.tasks;\n }\n\n get(id: string): QueuedTask | undefined {\n return this.tasks.find((t) => t.id === id);\n }\n\n /**\n * Every pending task whose dependencies are all satisfied (`done` or\n * `skipped`). A skipped dependency does not block downstream work.\n */\n nextRunnable(): QueuedTask[] {\n const doneIds = new Set(\n this.tasks\n .filter(\n (t) =>\n t.status === TaskStatus.Done || t.status === TaskStatus.Skipped,\n )\n .map((t) => t.id),\n );\n return this.tasks.filter(\n (t) =>\n t.status === TaskStatus.Pending &&\n t.dependsOn.every((d) => doneIds.has(d)),\n );\n }\n\n /**\n * True when no task is running and none can be started. Either everything\n * is terminal, or the only pending tasks are blocked by a failed dependency.\n */\n isDrained(): boolean {\n if (this.tasks.some((t) => t.status === TaskStatus.Running)) return false;\n return this.nextRunnable().length === 0;\n }\n\n summary(): Record<TaskStatus, number> & { total: number } {\n const counts: Record<TaskStatus, number> = {\n [TaskStatus.Pending]: 0,\n [TaskStatus.Running]: 0,\n [TaskStatus.Done]: 0,\n [TaskStatus.Skipped]: 0,\n [TaskStatus.Failed]: 0,\n };\n for (const t of this.tasks) counts[t.status] += 1;\n return { ...counts, total: this.tasks.length };\n }\n\n readHandoff(id: string): TaskHandoff | null {\n return this.get(id)?.handoff ?? null;\n }\n\n /** Handoffs of completed tasks of a given type, oldest first. */\n readHandoffsByType(type: string): TaskHandoff[] {\n return this.tasks\n .filter((t) => t.type === type && t.handoff)\n .map((t) => t.handoff as TaskHandoff);\n }\n\n // ── Transitions (each one reflected to queue.json) ──────────────────\n\n enqueue(input: EnqueueInput): QueuedTask {\n const task: QueuedTask = {\n id: randomUUID(),\n type: input.type,\n label: input.label,\n status: TaskStatus.Pending,\n dependsOn: input.dependsOn ?? [],\n inputs: input.inputs ?? {},\n model: input.model,\n attempts: 0,\n maxAttempts: input.maxAttempts ?? DEFAULT_MAX_ATTEMPTS,\n enqueuedBy: input.enqueuedBy ?? 'orchestrator',\n createdAt: nowIso(),\n };\n this.tasks.push(task);\n this.reflect();\n this.notify('enqueue', task);\n return task;\n }\n\n start(id: string): QueuedTask {\n const t = this.require(id);\n t.status = TaskStatus.Running;\n t.startedAt = nowIso();\n t.attempts += 1;\n this.reflect();\n this.notify('start', t);\n return t;\n }\n\n complete(id: string, handoff?: TaskHandoff): QueuedTask {\n return this.finish(id, TaskStatus.Done, handoff);\n }\n\n /** Terminal: the agent could not do the task. Not done, not failed. */\n skip(id: string, handoff?: TaskHandoff): QueuedTask {\n return this.finish(id, TaskStatus.Skipped, handoff);\n }\n\n fail(\n id: string,\n error: { type: string; message: string },\n handoff?: TaskHandoff,\n ): QueuedTask {\n const t = this.require(id);\n t.error = error;\n return this.finish(id, TaskStatus.Failed, handoff);\n }\n\n /** Put a failed/running task back to pending for a retry within the run. */\n requeue(id: string): QueuedTask {\n const t = this.require(id);\n t.status = TaskStatus.Pending;\n t.startedAt = undefined;\n t.finishedAt = undefined;\n this.reflect();\n this.notify('requeue', t);\n return t;\n }\n\n // ── Internals ───────────────────────────────────────────────────────\n\n private finish(\n id: string,\n status: 'done' | 'skipped' | 'failed',\n handoff?: TaskHandoff,\n ): QueuedTask {\n const t = this.require(id);\n if (handoff) t.handoff = handoff;\n t.status = status;\n t.finishedAt = nowIso();\n this.reflect();\n this.notify(\n status === TaskStatus.Done\n ? 'complete'\n : status === TaskStatus.Skipped\n ? 'skip'\n : 'fail',\n t,\n );\n return t;\n }\n\n private reflect(): void {\n const file: QueueFile = {\n version: 1,\n runId: this.runId,\n tasks: this.tasks,\n };\n writeJsonAtomic(this.queuePath, file);\n }\n\n private notify(event: TransitionEvent, task: QueuedTask): void {\n try {\n this.onTransition?.(event, task);\n } catch (error) {\n // A listener must never break a transition, but its failure is a bug.\n analytics.captureException(\n error instanceof Error ? error : new Error(String(error)),\n { step: 'orchestrator_queue_listener', event },\n );\n }\n }\n\n private require(id: string): QueuedTask {\n const t = this.get(id);\n if (!t) throw new Error(`No task ${id} in the queue`);\n return t;\n }\n}\n","/**\n * Orchestrator MCP tools, registered into the existing `wizard-tools` server when\n * a queue is present. They let the orchestrator agent and task agents grow the\n * queue, report completion with a structured handoff, and read prior handoffs.\n *\n * The guard logic and the apply functions are plain, exported, and unit-tested.\n * `buildOrchestratorTools` wraps them in the SDK `tool()` shape.\n */\nimport { z } from 'zod';\nimport { analytics } from '@utils/analytics';\nimport {\n TaskStatus,\n type QueueStore,\n type QueuedTask,\n type TaskHandoff,\n} from './queue';\n\nexport interface OrchestratorToolsContext {\n store: QueueStore;\n /** Task types the registry knows about. enqueue_task rejects anything else. */\n validTypes: readonly string[];\n /**\n * The id of the task this tool server is bound to. Each task agent gets its\n * own wizard-tools server, so attribution holds when independent tasks run\n * in parallel. Absent for the seed, which is not a task.\n */\n currentTaskId?: string;\n}\n\nexport interface EnqueueArgs {\n type: string;\n label?: string;\n inputs?: Record<string, unknown>;\n dependsOn?: string[];\n model?: string;\n reason: string;\n}\n\nexport type GuardResult =\n | { ok: true }\n | { ok: false; guard: string; message: string };\n\nfunction stableStringify(value: unknown): string {\n if (value === null || typeof value !== 'object') return JSON.stringify(value);\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`;\n const entries = Object.entries(value as Record<string, unknown>).sort(\n ([a], [b]) => a.localeCompare(b),\n );\n return `{${entries\n .map(([k, v]) => `${JSON.stringify(k)}:${stableStringify(v)}`)\n .join(',')}}`;\n}\n\nfunction dedupKey(type: string, inputs: Record<string, unknown>): string {\n return `${type}::${stableStringify(inputs)}`;\n}\n\n/**\n * A backstop on total queue size. Tasks can enqueue tasks, so a misbehaving\n * type could grow the queue without bound. Keeping the graph small is the job\n * of good agent and skill design, not this number — it only stops a runaway.\n * The real flow is ~9 tasks, so this sits well clear of it.\n */\nconst MAX_QUEUE_TASKS = 30;\n\n/**\n * Validate an enqueue. Structural checks only — a real type, real dependencies,\n * not a literal duplicate, and not past the runaway backstop. How much runs,\n * and in what shape, is the task graph's business, not a knob's.\n */\nexport function checkEnqueueGuards(\n ctx: OrchestratorToolsContext,\n args: EnqueueArgs,\n): GuardResult {\n const tasks = ctx.store.list();\n\n if (tasks.length >= MAX_QUEUE_TASKS) {\n return {\n ok: false,\n guard: 'queue-full',\n message: `The queue already holds ${tasks.length} tasks (cap ${MAX_QUEUE_TASKS}). Refine the existing tasks rather than adding more.`,\n };\n }\n\n if (!ctx.validTypes.includes(args.type)) {\n return {\n ok: false,\n guard: 'unknown-type',\n message: `Unknown task type \"${\n args.type\n }\". Valid types: ${ctx.validTypes.join(', ')}.`,\n };\n }\n\n for (const dep of args.dependsOn ?? []) {\n if (!ctx.store.get(dep)) {\n return {\n ok: false,\n guard: 'unknown-dep',\n message: `Dependency \"${dep}\" is not a known task id.`,\n };\n }\n }\n\n const key = dedupKey(args.type, args.inputs ?? {});\n if (\n tasks.some(\n (t) =>\n t.status !== TaskStatus.Failed && dedupKey(t.type, t.inputs) === key,\n )\n ) {\n return {\n ok: false,\n guard: 'dedup',\n message: `A \"${args.type}\" task with these inputs already exists.`,\n };\n }\n\n return { ok: true };\n}\n\nexport type EnqueueResult =\n | { ok: true; task: QueuedTask }\n | { ok: false; guard: string; message: string };\n\nexport function applyEnqueue(\n ctx: OrchestratorToolsContext,\n args: EnqueueArgs,\n): EnqueueResult {\n const guard = checkEnqueueGuards(ctx, args);\n if (!guard.ok) return guard;\n\n const task = ctx.store.enqueue({\n type: args.type,\n label: args.label,\n inputs: args.inputs ?? {},\n dependsOn: args.dependsOn ?? [],\n model: args.model,\n enqueuedBy: ctx.currentTaskId ?? 'orchestrator',\n });\n return { ok: true, task };\n}\n\nexport type CompleteResult = { ok: true } | { ok: false; message: string };\n\nexport function applyComplete(\n ctx: OrchestratorToolsContext,\n args: { status: 'done' | 'failed' | 'skipped'; handoff: TaskHandoff },\n): CompleteResult {\n const id = ctx.currentTaskId;\n if (!id) {\n return {\n ok: false,\n message: 'complete_task can only be called by a running task agent.',\n };\n }\n if (args.status === TaskStatus.Failed) {\n ctx.store.fail(\n id,\n { type: 'self-reported', message: args.handoff.forNextAgent },\n args.handoff,\n );\n } else if (args.status === TaskStatus.Skipped) {\n ctx.store.skip(id, args.handoff);\n } else {\n ctx.store.complete(id, args.handoff);\n }\n return { ok: true };\n}\n\nexport function applyReadHandoffs(\n ctx: OrchestratorToolsContext,\n args: { type?: string; taskId?: string },\n): TaskHandoff[] {\n if (args.taskId) {\n const h = ctx.store.readHandoff(args.taskId);\n return h ? [h] : [];\n }\n if (args.type) {\n return ctx.store.readHandoffsByType(args.type);\n }\n // No filter: every handoff of a dependency of the current task.\n const currentId = ctx.currentTaskId;\n const current = currentId ? ctx.store.get(currentId) : undefined;\n if (!current) return [];\n return current.dependsOn\n .map((depId) => ctx.store.readHandoff(depId))\n .filter((h): h is TaskHandoff => h !== null);\n}\n\nconst HANDOFF_SHAPE = {\n goals: z.string().describe('What this task was asked to achieve.'),\n did: z.string().describe('What you actually did.'),\n forNextAgent: z.string().describe('What the next agent should know.'),\n filesTouched: z.array(z.string()).optional(),\n conflict: z\n .string()\n .optional()\n .describe(\n '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.',\n ),\n};\n\ntype SdkTool = (\n name: string,\n description: string,\n // The SDK accepts a plain object of zod fields as the schema.\n schema: Record<string, z.ZodTypeAny>,\n handler: (args: never) => unknown,\n) => unknown;\n\nfunction textResult(text: string, isError = false) {\n return { isError, content: [{ type: 'text' as const, text }] };\n}\n\n/**\n * Build the orchestrator tools in the SDK `tool()` shape. Called from\n * createWizardToolsServer only when a queue context is present.\n */\nexport function buildOrchestratorTools(\n tool: SdkTool,\n ctx: OrchestratorToolsContext,\n): unknown[] {\n const enqueueTask = tool(\n 'enqueue_task',\n '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.',\n {\n type: z\n .string()\n .describe(`The task type. One of: ${ctx.validTypes.join(', ')}.`),\n label: z\n .string()\n .optional()\n .describe(\n '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.',\n ),\n inputs: z.record(z.unknown()).optional(),\n dependsOn: z\n .array(z.string())\n .optional()\n .describe('Task ids that must be done before this task runs.'),\n model: z.string().optional(),\n reason: z.string().describe('One line on why this task is needed.'),\n },\n ((args: EnqueueArgs) => {\n const res = applyEnqueue(ctx, args);\n if (!res.ok) {\n analytics.wizardCapture('orchestrator guard tripped', {\n guard: res.guard,\n type: args.type,\n });\n return textResult(res.message, true);\n }\n return textResult(JSON.stringify({ id: res.task.id }));\n }) as (args: never) => unknown,\n );\n\n const completeTask = tool(\n 'complete_task',\n \"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'.\",\n {\n status: z.enum(['done', 'failed', 'skipped']),\n handoff: z.object(HANDOFF_SHAPE),\n },\n ((args: {\n status: 'done' | 'failed' | 'skipped';\n handoff: TaskHandoff;\n }) => {\n const res = applyComplete(ctx, args);\n if (!res.ok) return textResult(res.message, true);\n return textResult('ok');\n }) as (args: never) => unknown,\n );\n\n const readHandoffs = tool(\n 'read_handoffs',\n 'Read structured handoffs from earlier tasks. With no argument, returns the handoffs of your dependencies.',\n {\n type: z.string().optional(),\n taskId: z.string().optional(),\n },\n ((args: { type?: string; taskId?: string }) => {\n const handoffs = applyReadHandoffs(ctx, args);\n return textResult(JSON.stringify(handoffs, null, 2));\n }) as (args: never) => unknown,\n );\n\n return [enqueueTask, completeTask, readHandoffs];\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { t as __exportAll } from "./rolldown-runtime-B_-DWIq7.js";
|
|
2
|
-
import { f as getUI } from "./debug-
|
|
3
|
-
import { a as createVersionBucket, c as detectAllPackageManagers, i as tryGetPackageJson } from "./setup-utils-
|
|
4
|
-
import { n as getInstalledPackageVersion, r as hasDeclaredDependency, t as getDeclaredVersion } from "./package-json-
|
|
5
|
-
import { a as gradlePackageManager, c as getPackageManagerName$1, i as detectPythonPackageManagers, l as getPythonVersion, n as composerPackageManager, o as swiftPackageManager, r as detectNodePackageManagers, s as detectPackageManager$1, t as bundlerPackageManager, u as getPythonVersionBucket } from "./package-manager-
|
|
2
|
+
import { f as getUI } from "./debug-C9HmIrwx.js";
|
|
3
|
+
import { a as createVersionBucket, c as detectAllPackageManagers, i as tryGetPackageJson } from "./setup-utils-Cb5uACEO.js";
|
|
4
|
+
import { n as getInstalledPackageVersion, r as hasDeclaredDependency, t as getDeclaredVersion } from "./package-json-DCuoye-H.js";
|
|
5
|
+
import { a as gradlePackageManager, c as getPackageManagerName$1, i as detectPythonPackageManagers, l as getPythonVersion, n as composerPackageManager, o as swiftPackageManager, r as detectNodePackageManagers, s as detectPackageManager$1, t as bundlerPackageManager, u as getPythonVersionBucket } from "./package-manager-CAD9Uklp.js";
|
|
6
6
|
import * as semver from "semver";
|
|
7
7
|
import { major, minVersion } from "semver";
|
|
8
8
|
import path from "path";
|
|
@@ -10,19 +10,6 @@ import * as path$1 from "node:path";
|
|
|
10
10
|
import * as fs$1 from "node:fs";
|
|
11
11
|
import fg from "fast-glob";
|
|
12
12
|
import fs from "fs/promises";
|
|
13
|
-
//#region src/lib/framework-config.ts
|
|
14
|
-
/**
|
|
15
|
-
* Default package installation instruction used when frameworks don't
|
|
16
|
-
* provide their own. Frameworks with specific needs (e.g., Swift SPM,
|
|
17
|
-
* Composer) override this in their config.
|
|
18
|
-
*/
|
|
19
|
-
const DEFAULT_PACKAGE_INSTALLATION = "Use the detect_package_manager tool to determine the package manager. Do not manually edit package.json; the package manager handles it automatically.";
|
|
20
|
-
const PYTHON_PACKAGE_INSTALLATION = "Use the detect_package_manager tool to determine the package manager. If the detected tool manages dependencies directly (e.g. uv add, poetry add), use it — it will update the manifest automatically. If using pip, you must also add the dependency to requirements.txt or the appropriate manifest file.";
|
|
21
|
-
/**
|
|
22
|
-
* Shared spinner message for all frameworks
|
|
23
|
-
*/
|
|
24
|
-
const SPINNER_MESSAGE = "Writing your PostHog setup with events, error capture and more...";
|
|
25
|
-
//#endregion
|
|
26
13
|
//#region src/frameworks/nextjs/utils.ts
|
|
27
14
|
const getNextJsVersionBucket = createVersionBucket();
|
|
28
15
|
const IGNORE_PATTERNS$9 = [
|
|
@@ -810,6 +797,19 @@ const ASTRO_AGENT_CONFIG = {
|
|
|
810
797
|
}
|
|
811
798
|
};
|
|
812
799
|
//#endregion
|
|
800
|
+
//#region src/lib/framework-config.ts
|
|
801
|
+
/**
|
|
802
|
+
* Default package installation instruction used when frameworks don't
|
|
803
|
+
* provide their own. Frameworks with specific needs (e.g., Swift SPM,
|
|
804
|
+
* Composer) override this in their config.
|
|
805
|
+
*/
|
|
806
|
+
const DEFAULT_PACKAGE_INSTALLATION = "Use the detect_package_manager tool to determine the package manager. Do not manually edit package.json; the package manager handles it automatically.";
|
|
807
|
+
const PYTHON_PACKAGE_INSTALLATION = "Use the detect_package_manager tool to determine the package manager. If the detected tool manages dependencies directly (e.g. uv add, poetry add), use it — it will update the manifest automatically. If using pip, you must also add the dependency to requirements.txt or the appropriate manifest file.";
|
|
808
|
+
/**
|
|
809
|
+
* Shared spinner message for all frameworks
|
|
810
|
+
*/
|
|
811
|
+
const SPINNER_MESSAGE = "Writing your PostHog setup with events, error capture and more...";
|
|
812
|
+
//#endregion
|
|
813
813
|
//#region src/frameworks/django/utils.ts
|
|
814
814
|
const IGNORE_PATTERNS$5 = [
|
|
815
815
|
"**/node_modules/**",
|
|
@@ -2071,6 +2071,83 @@ const SWIFT_AGENT_CONFIG = {
|
|
|
2071
2071
|
}
|
|
2072
2072
|
};
|
|
2073
2073
|
//#endregion
|
|
2074
|
+
//#region src/frameworks/kmp/kmp-wizard-agent.ts
|
|
2075
|
+
const KMP_AGENT_CONFIG = {
|
|
2076
|
+
metadata: {
|
|
2077
|
+
name: "Kotlin Multiplatform",
|
|
2078
|
+
integration: "kmp",
|
|
2079
|
+
beta: true,
|
|
2080
|
+
docsUrl: "https://posthog.com/docs/libraries/kmp",
|
|
2081
|
+
preRunNotice: "The PostHog Kotlin Multiplatform SDK is in early access (0.x pre-release). The API may change between minor versions."
|
|
2082
|
+
},
|
|
2083
|
+
detection: {
|
|
2084
|
+
packageName: "posthog-kmp",
|
|
2085
|
+
packageDisplayName: "Kotlin Multiplatform",
|
|
2086
|
+
usesPackageJson: false,
|
|
2087
|
+
getVersion: () => void 0,
|
|
2088
|
+
detectPackageManager: gradlePackageManager,
|
|
2089
|
+
detect: async (options) => {
|
|
2090
|
+
const { installDir } = options;
|
|
2091
|
+
const buildFiles = await fg(["**/build.gradle", "**/build.gradle.kts"], {
|
|
2092
|
+
cwd: installDir,
|
|
2093
|
+
ignore: [
|
|
2094
|
+
"**/build/**",
|
|
2095
|
+
"**/node_modules/**",
|
|
2096
|
+
"**/.gradle/**"
|
|
2097
|
+
]
|
|
2098
|
+
});
|
|
2099
|
+
for (const file of buildFiles) {
|
|
2100
|
+
const content = fs$1.readFileSync(path$1.join(installDir, file), "utf-8");
|
|
2101
|
+
if (content.includes("kotlin(\"multiplatform\")") || content.includes("org.jetbrains.kotlin.multiplatform") || content.includes("kotlin-multiplatform")) return true;
|
|
2102
|
+
}
|
|
2103
|
+
return (await fg("**/src/commonMain", {
|
|
2104
|
+
cwd: installDir,
|
|
2105
|
+
onlyDirectories: true,
|
|
2106
|
+
ignore: [
|
|
2107
|
+
"**/build/**",
|
|
2108
|
+
"**/node_modules/**",
|
|
2109
|
+
"**/.gradle/**"
|
|
2110
|
+
]
|
|
2111
|
+
})).length > 0;
|
|
2112
|
+
}
|
|
2113
|
+
},
|
|
2114
|
+
environment: {
|
|
2115
|
+
uploadToHosting: false,
|
|
2116
|
+
getEnvVars: (apiKey, host) => ({
|
|
2117
|
+
POSTHOG_PROJECT_TOKEN: apiKey,
|
|
2118
|
+
POSTHOG_HOST: host
|
|
2119
|
+
})
|
|
2120
|
+
},
|
|
2121
|
+
analytics: { getTags: () => ({}) },
|
|
2122
|
+
prompts: {
|
|
2123
|
+
projectTypeDetection: "This is a Kotlin Multiplatform (KMP) project. Look for a build.gradle.kts (or build.gradle) that applies the Kotlin Multiplatform plugin (kotlin(\"multiplatform\") or org.jetbrains.kotlin.multiplatform) and a shared module with a src/commonMain source set.",
|
|
2124
|
+
packageInstallation: "Add the PostHog KMP SDK to the shared module's commonMain dependencies in build.gradle.kts: within the kotlin { sourceSets { ... } } block, add implementation(\"com.posthog:posthog-kmp:<VERSION>\") to commonMain.dependencies. Match the existing dependency format (Groovy vs Kotlin DSL).",
|
|
2125
|
+
getAdditionalContextLines: () => [
|
|
2126
|
+
"Framework docs ID: kmp (use posthog://docs/frameworks/kmp for documentation)",
|
|
2127
|
+
"Initialize once, early in the app lifecycle, from shared code. All PostHog APIs live in the com.posthog.kmp package.",
|
|
2128
|
+
"Setup call: PostHog.setup(config = PostHogConfig(apiKey = \"<POSTHOG_PROJECT_TOKEN>\", host = \"<POSTHOG_HOST>\"), context = PostHogContext())",
|
|
2129
|
+
"PostHogContext is platform-specific: on Android pass the Application via PostHogContext(application); on iOS and Web use the no-argument PostHogContext().",
|
|
2130
|
+
"Imports: com.posthog.kmp.PostHog, com.posthog.kmp.PostHogConfig, com.posthog.kmp.PostHogContext."
|
|
2131
|
+
]
|
|
2132
|
+
},
|
|
2133
|
+
ui: {
|
|
2134
|
+
successMessage: "PostHog integration complete",
|
|
2135
|
+
estimatedDurationMinutes: 5,
|
|
2136
|
+
getOutroChanges: () => [
|
|
2137
|
+
"Analyzed your Kotlin Multiplatform project structure",
|
|
2138
|
+
"Added the PostHog KMP SDK to your shared module",
|
|
2139
|
+
"Configured PostHog initialization in your shared code",
|
|
2140
|
+
"Added event capture and user identification"
|
|
2141
|
+
],
|
|
2142
|
+
getOutroNextSteps: () => [
|
|
2143
|
+
"Wire up the platform-specific PostHogContext for each target (Android/iOS/Web)",
|
|
2144
|
+
"Build and run your app to see PostHog in action",
|
|
2145
|
+
"Visit your PostHog dashboard to see incoming events",
|
|
2146
|
+
"Check out the PostHog KMP docs for feature flags, session replay, and more"
|
|
2147
|
+
]
|
|
2148
|
+
}
|
|
2149
|
+
};
|
|
2150
|
+
//#endregion
|
|
2074
2151
|
//#region src/frameworks/android/utils.ts
|
|
2075
2152
|
const IGNORE_PATTERNS$2 = [
|
|
2076
2153
|
"**/build/**",
|
|
@@ -2898,6 +2975,7 @@ const FRAMEWORK_REGISTRY = {
|
|
|
2898
2975
|
["fastapi"]: FASTAPI_AGENT_CONFIG,
|
|
2899
2976
|
["laravel"]: LARAVEL_AGENT_CONFIG,
|
|
2900
2977
|
["sveltekit"]: SVELTEKIT_AGENT_CONFIG,
|
|
2978
|
+
["kmp"]: KMP_AGENT_CONFIG,
|
|
2901
2979
|
["swift"]: SWIFT_AGENT_CONFIG,
|
|
2902
2980
|
["android"]: ANDROID_AGENT_CONFIG,
|
|
2903
2981
|
["rails"]: RAILS_AGENT_CONFIG,
|
|
@@ -2909,4 +2987,4 @@ const FRAMEWORK_REGISTRY = {
|
|
|
2909
2987
|
//#endregion
|
|
2910
2988
|
export { SPINNER_MESSAGE as i, registry_exports as n, DEFAULT_PACKAGE_INSTALLATION as r, FRAMEWORK_REGISTRY as t };
|
|
2911
2989
|
|
|
2912
|
-
//# sourceMappingURL=registry-
|
|
2990
|
+
//# sourceMappingURL=registry-DT58jEYr.js.map
|