@posthog/wizard 2.52.1 → 2.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/dist/{add-mcp-server-to-clients-C7P4_dhF.js → add-mcp-server-to-clients-B3TcwTT5.js} +5 -5
  2. package/dist/{add-mcp-server-to-clients-C7P4_dhF.js.map → add-mcp-server-to-clients-B3TcwTT5.js.map} +1 -1
  3. package/dist/{agent-interface-oqI_K3-4.js → agent-interface-CLvG6Rk9.js} +338 -28
  4. package/dist/agent-interface-CLvG6Rk9.js.map +1 -0
  5. package/dist/{agent-prompt-loader-DwFFfuZ4.js → agent-prompt-loader-Baqm1JMD.js} +5 -5
  6. package/dist/{agent-prompt-loader-DwFFfuZ4.js.map → agent-prompt-loader-Baqm1JMD.js.map} +1 -1
  7. package/dist/{agent-runner-CunYPDzL.js → agent-runner-D6zGTJqn.js} +179 -145
  8. package/dist/agent-runner-D6zGTJqn.js.map +1 -0
  9. package/dist/analytics-BBJE4hIu.js +2 -0
  10. package/dist/{analytics-DsXLkDwE.js → analytics-D7hsukY7.js} +5 -2
  11. package/dist/analytics-D7hsukY7.js.map +1 -0
  12. package/dist/{api-Dpnv0jVL.js → api-BSq9hLu5.js} +3 -3
  13. package/dist/{api-Dpnv0jVL.js.map → api-BSq9hLu5.js.map} +1 -1
  14. package/dist/bin.js +329 -190
  15. package/dist/bin.js.map +1 -1
  16. package/dist/{bounded-fs-bvlHO1PM.js → bounded-fs-Cq960M-V.js} +3 -3
  17. package/dist/{bounded-fs-bvlHO1PM.js.map → bounded-fs-Cq960M-V.js.map} +1 -1
  18. package/dist/{ci-install-BLSCzEZs.js → ci-install-w-mywB9x.js} +5 -5
  19. package/dist/{ci-install-BLSCzEZs.js.map → ci-install-w-mywB9x.js.map} +1 -1
  20. package/dist/{debug-D-lnRFLU.js → debug-CX6ZqL9r.js} +1 -1
  21. package/dist/{debug-BH67OSPW.js → debug-CbgLkSCY.js} +19 -10
  22. package/dist/debug-CbgLkSCY.js.map +1 -0
  23. package/dist/{defaults-DAE9_QMn.js → defaults-BWLIffh5.js} +1 -1
  24. package/dist/{defaults-DAE9_QMn.js.map → defaults-BWLIffh5.js.map} +1 -1
  25. package/dist/{env-api-key-DDVkPQmo.js → env-api-key-cjD4yfGT.js} +1 -1
  26. package/dist/{env-api-key-DDVkPQmo.js.map → env-api-key-cjD4yfGT.js.map} +1 -1
  27. package/dist/{environment-CPPBK-08.js → environment-BWuaOExh.js} +4 -4
  28. package/dist/{environment-CPPBK-08.js.map → environment-BWuaOExh.js.map} +1 -1
  29. package/dist/{file-watcher-Dgbe0xK9.js → file-watcher-D9tgVBkp.js} +2 -2
  30. package/dist/{file-watcher-Dgbe0xK9.js.map → file-watcher-D9tgVBkp.js.map} +1 -1
  31. package/dist/{headless-ui-BJbByiLj.js → headless-ui-rH97E35y.js} +2 -2
  32. package/dist/{headless-ui-BJbByiLj.js.map → headless-ui-rH97E35y.js.map} +1 -1
  33. package/dist/{interactive-ClJi6jV4.js → interactive-D-MVMdBl.js} +3 -3
  34. package/dist/{interactive-ClJi6jV4.js.map → interactive-D-MVMdBl.js.map} +1 -1
  35. package/dist/{mcp-C5pjmTsm.js → mcp-jKHwa45f.js} +2 -2
  36. package/dist/{mcp-C5pjmTsm.js.map → mcp-jKHwa45f.js.map} +1 -1
  37. package/dist/{mcp-prompt-streaming-BFDtuwJN.js → mcp-prompt-streaming-DxDftNHb.js} +5 -4
  38. package/dist/{mcp-prompt-streaming-BFDtuwJN.js.map → mcp-prompt-streaming-DxDftNHb.js.map} +1 -1
  39. package/dist/{non-interactive-C3DW7sGO.js → non-interactive-eXT2_WCR.js} +2 -2
  40. package/dist/{non-interactive-C3DW7sGO.js.map → non-interactive-eXT2_WCR.js.map} +1 -1
  41. package/dist/{orchestrator-tools-S88ycFO0.js → orchestrator-tools-CsXrPhsd.js} +3 -3
  42. package/dist/{orchestrator-tools-S88ycFO0.js.map → orchestrator-tools-CsXrPhsd.js.map} +1 -1
  43. package/dist/{package-manager-De6lmm9s.js → package-manager-CASp14jY.js} +2 -2
  44. package/dist/{package-manager-De6lmm9s.js.map → package-manager-CASp14jY.js.map} +1 -1
  45. package/dist/pi-CfdqOKDI.js +611 -0
  46. package/dist/pi-CfdqOKDI.js.map +1 -0
  47. package/dist/{playground-B4yTvjn4.js → playground-DuBvnGkP.js} +354 -19
  48. package/dist/playground-DuBvnGkP.js.map +1 -0
  49. package/dist/{posthog-mgz-FQlS.js → posthog-DDLIrku0.js} +1 -1
  50. package/dist/{posthog-mgz-FQlS.js.map → posthog-DDLIrku0.js.map} +1 -1
  51. package/dist/{posthog-integration-BA2aFHGz.js → posthog-integration-Dy5cNPaa.js} +16 -16
  52. package/dist/{posthog-integration-BA2aFHGz.js.map → posthog-integration-Dy5cNPaa.js.map} +1 -1
  53. package/dist/{provisioning-CtC0Ekeq.js → provisioning-CS6fQriR.js} +3 -3
  54. package/dist/{provisioning-CtC0Ekeq.js.map → provisioning-CS6fQriR.js.map} +1 -1
  55. package/dist/{queue-tools-DXg_5old.js → queue-tools-ai7gCWyU.js} +45 -32
  56. package/dist/queue-tools-ai7gCWyU.js.map +1 -0
  57. package/dist/{registry-B6ubVKTJ.js → registry-D0hx_-KP.js} +5 -5
  58. package/dist/{registry-B6ubVKTJ.js.map → registry-D0hx_-KP.js.map} +1 -1
  59. package/dist/{security-np5qnEMM.js → security-BNqgFjYh.js} +5 -5
  60. package/dist/security-BNqgFjYh.js.map +1 -0
  61. package/dist/{setup-utils-QwrY_J01.js → setup-utils-6qyTDNyd.js} +8 -8
  62. package/dist/{setup-utils-QwrY_J01.js.map → setup-utils-6qyTDNyd.js.map} +1 -1
  63. package/dist/{start-tui-DHEtMtnm.js → start-tui-DNkm-n-4.js} +36 -22
  64. package/dist/start-tui-DNkm-n-4.js.map +1 -0
  65. package/dist/{steps-ehGnaz9V.js → steps-CqHAVc8R.js} +7 -7
  66. package/dist/{steps-ehGnaz9V.js.map → steps-CqHAVc8R.js.map} +1 -1
  67. package/dist/{store-Cp_jvnNp.js → store-sIaF89XA.js} +6 -6
  68. package/dist/{store-Cp_jvnNp.js.map → store-sIaF89XA.js.map} +1 -1
  69. package/dist/{subagent-B9GiHZVj.js → subagent-CKNbRtfQ.js} +2 -2
  70. package/dist/{subagent-B9GiHZVj.js.map → subagent-CKNbRtfQ.js.map} +1 -1
  71. package/dist/{task-CmWToh2Q.js → task-DwzRxORh.js} +33 -23
  72. package/dist/task-DwzRxORh.js.map +1 -0
  73. package/dist/{task-stream-4I08S7A6.js → task-stream-BdJV-usk.js} +27 -6
  74. package/dist/task-stream-BdJV-usk.js.map +1 -0
  75. package/dist/{tasks-C6CfAC-D.js → tasks-yqJVuTvc.js} +2 -2
  76. package/dist/{tasks-C6CfAC-D.js.map → tasks-yqJVuTvc.js.map} +1 -1
  77. package/dist/{telemetry-3fcP3zSF.js → telemetry-UBL5MQtw.js} +3 -3
  78. package/dist/{telemetry-3fcP3zSF.js.map → telemetry-UBL5MQtw.js.map} +1 -1
  79. package/dist/{terminal-D4A6Hmkf.js → terminal-vo5Zl7j1.js} +807 -63
  80. package/dist/terminal-vo5Zl7j1.js.map +1 -0
  81. package/dist/{tools-pH2CNwNX.js → tools-Br8lP29r.js} +8 -10
  82. package/dist/tools-Br8lP29r.js.map +1 -0
  83. package/dist/warlock-smoke-test.ts +177 -1
  84. package/dist/{wizard-abort-BEBAXmPp.js → wizard-abort-BRsd7-aB.js} +1 -1
  85. package/dist/{wizard-abort-BbsBpCCV.js → wizard-abort-FIC6lKCs.js} +4 -4
  86. package/dist/{wizard-abort-BbsBpCCV.js.map → wizard-abort-FIC6lKCs.js.map} +1 -1
  87. package/dist/{wizard-session-BAZql11N.js → wizard-session-CwgR5y3-.js} +2 -1
  88. package/dist/wizard-session-CwgR5y3-.js.map +1 -0
  89. package/dist/{wizard-session-C5lZPPEc.js → wizard-session-DsK16SGs.js} +1 -1
  90. package/dist/yara-hooks--QA2Cwjv.js +2 -0
  91. package/dist/{yara-hooks-BGBQ4IcA.js → yara-hooks-DxpCD72V.js} +39 -83
  92. package/dist/yara-hooks-DxpCD72V.js.map +1 -0
  93. package/package.json +2 -1
  94. package/dist/agent-interface-oqI_K3-4.js.map +0 -1
  95. package/dist/agent-runner-CunYPDzL.js.map +0 -1
  96. package/dist/analytics-DsXLkDwE.js.map +0 -1
  97. package/dist/analytics-agQIoFg6.js +0 -2
  98. package/dist/commandments-BagyrYRW.js +0 -2
  99. package/dist/commandments-DiMtIz1o.js +0 -42
  100. package/dist/commandments-DiMtIz1o.js.map +0 -1
  101. package/dist/debug-BH67OSPW.js.map +0 -1
  102. package/dist/pi-BOCjsfgo.js +0 -575
  103. package/dist/pi-BOCjsfgo.js.map +0 -1
  104. package/dist/playground-B4yTvjn4.js.map +0 -1
  105. package/dist/queue-tools-DXg_5old.js.map +0 -1
  106. package/dist/security-np5qnEMM.js.map +0 -1
  107. package/dist/start-tui-DHEtMtnm.js.map +0 -1
  108. package/dist/task-CmWToh2Q.js.map +0 -1
  109. package/dist/task-stream-4I08S7A6.js.map +0 -1
  110. package/dist/terminal-D4A6Hmkf.js.map +0 -1
  111. package/dist/tools-pH2CNwNX.js.map +0 -1
  112. package/dist/wizard-session-BAZql11N.js.map +0 -1
  113. package/dist/yara-hooks-BGBQ4IcA.js.map +0 -1
  114. package/dist/yara-hooks-BfhKhlIT.js +0 -2
@@ -0,0 +1,611 @@
1
+ import { a as getLogFilePath, f as getUI, ft as WIZARD_USER_AGENT, ht as VERSION, s as logToFile, ut as WIZARD_REMARK_EVENT_NAME } from "./debug-CbgLkSCY.js";
2
+ import { n as analytics } from "./analytics-D7hsukY7.js";
3
+ import { M as GATEWAY_PROVIDER, N as buildGatewayProvider, f as AgentOutputSignals, h as assembleCommandments, m as REMARK_INSTRUCTION, p as AgentSignals } from "./agent-interface-CLvG6Rk9.js";
4
+ import fs from "fs";
5
+ import path from "path";
6
+ //#region src/lib/agent/aio-capture.ts
7
+ /**
8
+ * aio-capture — mirror wizard LLM calls into the authenticated project's
9
+ * AI Observability tab as `$ai_generation` events. Gated on `--capture-aio`
10
+ * (dev/test builds only); returns a no-op instance when disabled so the
11
+ * wire-in points stay a no-op with zero overhead.
12
+ *
13
+ * The wizard's LLM calls happen inside subprocesses we don't own (the
14
+ * claude-agent-sdk CLI on the anthropic path, pi's own runtime on pi), so we
15
+ * can't wrap the client with `posthog-node`'s `wrapAnthropic`. Instead, each
16
+ * harness surfaces assistant turns on the way back — the SDK message stream
17
+ * on anthropic, `agentSession.subscribe(message_end)` on pi — and this module
18
+ * composes an `$ai_generation` event from either shape.
19
+ *
20
+ * For the Conversation tab in AIO to render anything, each generation needs
21
+ * `$ai_input` (the messages the model saw when it produced this turn). The
22
+ * initial prompt is passed to the SDK subprocess and never echoed back on
23
+ * the stream, so callers must hand it to `setInitialPrompt` before the run
24
+ * starts. From there we track user/assistant turns as they flow through the
25
+ * stream, snapshotting the running conversation into each generation's
26
+ * `$ai_input` and firing `$ai_input_state` / `$ai_output_state` on the
27
+ * terminal `$ai_trace` event.
28
+ *
29
+ * POSTs are fire-and-forget: failures are debug-logged and never surfaced to
30
+ * the main agent flow. Losing an AIO event must never break a run.
31
+ */
32
+ const noop = (_) => void 0;
33
+ const NOOP = {
34
+ setInitialPrompt: noop,
35
+ captureFromAnthropicSDKMessage: noop,
36
+ captureFromPiMessageEndEvent: noop
37
+ };
38
+ function createAioCapture(args) {
39
+ if (!args.enabled || !args.projectApiKey || !args.apiHost) return NOOP;
40
+ const { projectApiKey, apiHost, runTags } = args;
41
+ const distinctId = `wizard-cli-${VERSION}`;
42
+ const captureUrl = `${apiHost.replace(/\/$/, "")}/capture/`;
43
+ const runStartAt = Date.now();
44
+ let prevTurnAt = runStartAt;
45
+ let traceEnded = false;
46
+ let initialPrompt;
47
+ let conversation = [];
48
+ let lastAssistantContent;
49
+ const postEvent = (event, properties) => {
50
+ const body = {
51
+ api_key: projectApiKey,
52
+ event,
53
+ distinct_id: distinctId,
54
+ properties: {
55
+ $ai_trace_id: runTags.run_id ?? "",
56
+ ...runTags,
57
+ ...properties
58
+ },
59
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
60
+ };
61
+ fetch(captureUrl, {
62
+ method: "POST",
63
+ headers: { "Content-Type": "application/json" },
64
+ body: JSON.stringify(body)
65
+ }).then((res) => {
66
+ if (!res.ok) logToFile(`[aio-capture] POST failed status=${res.status}`);
67
+ }).catch((err) => {
68
+ logToFile(`[aio-capture] POST error: ${err instanceof Error ? err.message : String(err)}`);
69
+ });
70
+ };
71
+ const postGeneration = (turn) => {
72
+ postEvent("$ai_generation", {
73
+ $ai_provider: turn.provider,
74
+ $ai_model: turn.model,
75
+ $ai_input: turn.input,
76
+ $ai_output_choices: turn.outputChoices,
77
+ $ai_input_tokens: turn.inputTokens ?? 0,
78
+ $ai_output_tokens: turn.outputTokens ?? 0,
79
+ $ai_cache_read_input_tokens: turn.cacheReadTokens ?? 0,
80
+ $ai_cache_creation_input_tokens: turn.cacheCreationTokens ?? 0,
81
+ $ai_latency: turn.latencyMs / 1e3,
82
+ $ai_generation_id: turn.generationId ?? "",
83
+ $ai_is_error: turn.isError
84
+ });
85
+ };
86
+ const sendTraceEnd = (opts) => {
87
+ if (traceEnded) return;
88
+ traceEnded = true;
89
+ postEvent("$ai_trace", {
90
+ $ai_span_name: runTags.program_id ?? "wizard-run",
91
+ $ai_latency: (Date.now() - runStartAt) / 1e3,
92
+ $ai_is_error: opts.isError,
93
+ $ai_input_state: initialPrompt ? [{
94
+ role: "user",
95
+ content: [{
96
+ type: "text",
97
+ text: initialPrompt
98
+ }]
99
+ }] : [],
100
+ $ai_output_state: lastAssistantContent ?? []
101
+ });
102
+ };
103
+ const anthropicAssistantTurn = (msg) => {
104
+ const m = msg;
105
+ if (m?.type !== "assistant" || !m.message) return null;
106
+ const now = Date.now();
107
+ const latencyMs = now - prevTurnAt;
108
+ prevTurnAt = now;
109
+ return {
110
+ provider: "anthropic",
111
+ model: m.message.model ?? "unknown",
112
+ input: [...conversation],
113
+ outputChoices: Array.isArray(m.message.content) ? m.message.content : [],
114
+ inputTokens: m.message.usage?.input_tokens,
115
+ outputTokens: m.message.usage?.output_tokens,
116
+ cacheReadTokens: m.message.usage?.cache_read_input_tokens,
117
+ cacheCreationTokens: m.message.usage?.cache_creation_input_tokens,
118
+ latencyMs,
119
+ generationId: m.message.id,
120
+ isError: false
121
+ };
122
+ };
123
+ const piAssistantTurn = (event) => {
124
+ const e = event;
125
+ if (e?.type !== "message_end" || e.message?.role !== "assistant") return null;
126
+ const now = Date.now();
127
+ const latencyMs = now - prevTurnAt;
128
+ prevTurnAt = now;
129
+ return {
130
+ provider: "anthropic",
131
+ model: e.message.model ?? "unknown",
132
+ input: [...conversation],
133
+ outputChoices: Array.isArray(e.message.content) ? e.message.content : [],
134
+ inputTokens: e.message.usage?.input_tokens,
135
+ outputTokens: e.message.usage?.output_tokens,
136
+ cacheReadTokens: e.message.usage?.cache_read_input_tokens,
137
+ cacheCreationTokens: e.message.usage?.cache_creation_input_tokens,
138
+ latencyMs,
139
+ generationId: e.message.id,
140
+ isError: false
141
+ };
142
+ };
143
+ return {
144
+ setInitialPrompt(prompt) {
145
+ initialPrompt = prompt;
146
+ conversation = [{
147
+ role: "user",
148
+ content: [{
149
+ type: "text",
150
+ text: prompt
151
+ }]
152
+ }];
153
+ lastAssistantContent = void 0;
154
+ },
155
+ captureFromAnthropicSDKMessage(msg) {
156
+ try {
157
+ const m = msg;
158
+ if (m?.type === "user" && m.message) conversation.push({
159
+ role: "user",
160
+ content: m.message.content ?? []
161
+ });
162
+ const turn = anthropicAssistantTurn(msg);
163
+ if (turn) {
164
+ postGeneration(turn);
165
+ conversation.push({
166
+ role: "assistant",
167
+ content: turn.outputChoices
168
+ });
169
+ lastAssistantContent = turn.outputChoices;
170
+ }
171
+ if (m?.type === "result") sendTraceEnd({ isError: !!m.is_error });
172
+ } catch (err) {
173
+ logToFile(`[aio-capture] anthropic compose failed: ${err instanceof Error ? err.message : String(err)}`);
174
+ }
175
+ },
176
+ captureFromPiMessageEndEvent(event) {
177
+ try {
178
+ const e = event;
179
+ if (e?.type === "message_end" && e.message?.role === "user" && e.message) conversation.push({
180
+ role: "user",
181
+ content: e.message.content ?? []
182
+ });
183
+ const turn = piAssistantTurn(event);
184
+ if (turn) {
185
+ postGeneration(turn);
186
+ conversation.push({
187
+ role: "assistant",
188
+ content: turn.outputChoices
189
+ });
190
+ lastAssistantContent = turn.outputChoices;
191
+ }
192
+ if (e?.type === "agent_end" && !e.willRetry) sendTraceEnd({ isError: false });
193
+ } catch (err) {
194
+ logToFile(`[aio-capture] pi compose failed: ${err instanceof Error ? err.message : String(err)}`);
195
+ }
196
+ }
197
+ };
198
+ }
199
+ //#endregion
200
+ //#region src/lib/agent/runner/harness/pi/completion.ts
201
+ /** Which completion guard should fail a pi run, or undefined for a clean finish. */
202
+ function completionFailure(args) {
203
+ if (args.toolCalls === 0) return "WIZARD_NO_PROGRESS";
204
+ if (args.openTasks) return "WIZARD_INCOMPLETE_TASKS";
205
+ }
206
+ //#endregion
207
+ //#region src/lib/agent/runner/harness/pi/index.ts
208
+ /**
209
+ * The `pi` backend — the challenger. Drives pi.dev's coding agent
210
+ * (`@earendil-works/pi-coding-agent`) against the PostHog LLM gateway, behind
211
+ * `wizard-orchestrator`. It owns the agent loop and model transport; prompt
212
+ * assembly, error routing, and the outro stay in `linear.ts`, shared with the
213
+ * `anthropic` control.
214
+ *
215
+ * Transport: the gateway is registered as an `anthropic-messages` provider
216
+ * (same protocol the claude-agent-sdk path uses), bearer auth, Bedrock-fallback
217
+ * + wizard metadata/flag headers, model id matched to `anthropic` for a clean
218
+ * A/B. Security parity (canUseTool + YARA) and skills/MCP discovery are
219
+ * follow-ups (#525, #524 skills) — v1 uses pi's built-in coding tools.
220
+ */
221
+ /** Injects the MCP server `instructions` pi-mcp-adapter drops (project env, skill steer, tool domains) into the system prompt, falling back to a bootstrap-derived project block when the warm-connect captured none. */
222
+ function piMcpContext(boot, instructions) {
223
+ if (instructions) return [
224
+ "",
225
+ "## PostHog MCP server",
226
+ instructions
227
+ ].join("\n");
228
+ return [
229
+ "",
230
+ "## PostHog project",
231
+ "Your `posthog_exec` calls run against this project:",
232
+ `- Project: ${boot.project?.name ? `${boot.project.name} (id ${boot.credentials.projectId})` : `id ${boot.credentials.projectId}`}`,
233
+ `- Host: ${boot.credentials.host.apiHost}`,
234
+ `- Region: ${boot.credentials.host.region}`
235
+ ].join("\n");
236
+ }
237
+ /**
238
+ * The ONLY environment variables pi's tool subprocesses (bash → npm/pip/…) are
239
+ * allowed to see. Everything else — every secret (POSTHOG_PERSONAL_API_KEY,
240
+ * ANTHROPIC_*, AWS_*), every ambient credential, the parent process's whole env
241
+ * — is dropped before a child is spawned. pi's own gateway auth is programmatic
242
+ * (the access token never lives in env), so a minimal env costs the agent
243
+ * nothing while closing the leak that exposed the key before. Kept to what a
244
+ * package manager genuinely needs to run.
245
+ */
246
+ const ALLOWED_SUBPROCESS_ENV_KEYS = [
247
+ "PATH",
248
+ "HOME",
249
+ "SHELL",
250
+ "USER",
251
+ "LOGNAME",
252
+ "TMPDIR",
253
+ "TMP",
254
+ "TEMP",
255
+ "TERM",
256
+ "LANG",
257
+ "LC_ALL",
258
+ "LC_CTYPE",
259
+ "NODE_EXTRA_CA_CERTS",
260
+ "SSL_CERT_FILE",
261
+ "SSL_CERT_DIR",
262
+ "HTTP_PROXY",
263
+ "HTTPS_PROXY",
264
+ "NO_PROXY",
265
+ "http_proxy",
266
+ "https_proxy",
267
+ "no_proxy"
268
+ ];
269
+ /** A fresh subprocess env holding only the allowlisted keys present in process.env. */
270
+ function buildScrubbedEnv() {
271
+ const env = {};
272
+ for (const key of ALLOWED_SUBPROCESS_ENV_KEYS) {
273
+ const value = process.env[key];
274
+ if (value !== void 0) env[key] = value;
275
+ }
276
+ return env;
277
+ }
278
+ /**
279
+ * Tag a tool with an execution mode (mutates + returns it). Read-only tools are
280
+ * `parallel` so a single turn that batches independent reads/searches runs them
281
+ * at once; mutating/install tools are `sequential` so a batch never races writes
282
+ * or concurrent installs. pi-agent-core runs a batch in parallel only when no
283
+ * tool in it is `sequential`.
284
+ */
285
+ function withMode(tool, mode) {
286
+ tool.executionMode = mode;
287
+ return tool;
288
+ }
289
+ /** Pull plain text out of a pi AgentMessage (content is text/image blocks). */
290
+ function extractText(message) {
291
+ const content = message?.content;
292
+ if (typeof content === "string") return content;
293
+ if (Array.isArray(content)) return content.filter((c) => {
294
+ const block = c;
295
+ return block?.type === "text" && typeof block.text === "string";
296
+ }).map((c) => c.text).join("");
297
+ return "";
298
+ }
299
+ /**
300
+ * Surface `[DASHBOARD_URL]` / `[NOTEBOOK_URL]` markers the agent prints (after
301
+ * the MCP creates them) into the outro link, mirroring the anthropic path's
302
+ * signal parsing (#9). The marker carries the URL the MCP returned.
303
+ */
304
+ function applyOutroMarkers(textBlock) {
305
+ const markers = [[AgentSignals.DASHBOARD_URL, (url) => getUI().setDashboardUrl(url)], [AgentSignals.NOTEBOOK_URL, (url) => getUI().setNotebookUrl(url)]];
306
+ for (const [marker, apply] of markers) {
307
+ const idx = textBlock.indexOf(marker);
308
+ if (idx === -1) continue;
309
+ const url = textBlock.slice(idx + marker.length).trim().split(/\s/)[0];
310
+ if (url) apply(url);
311
+ }
312
+ }
313
+ /**
314
+ * The text of the last `[STATUS] …` line in a block, if any. Last wins so the
315
+ * spinner shows the most recent action when a turn prints several.
316
+ */
317
+ function lastStatusLine(textBlock) {
318
+ let status;
319
+ for (const line of textBlock.split("\n")) {
320
+ const idx = line.indexOf(AgentSignals.STATUS);
321
+ if (idx !== -1) status = line.slice(idx + AgentSignals.STATUS.length).trim();
322
+ }
323
+ return status || void 0;
324
+ }
325
+ /** Cap on completion-guard re-prompts while tasks remain open (see the run loop). */
326
+ const MAX_CONTINUE_NUDGES = 20;
327
+ /** Nudge re-sent when the agent stops early with tasks still open. */
328
+ const CONTINUE_INSTRUCTION = "You still have open tasks in your list (not all are marked `completed`). Do not stop — pick up the next `in_progress` or `pending` task and keep working until every task is `completed`. Continue now.";
329
+ /** True while any task in the store is not yet `completed`. */
330
+ function hasOpenTasks(store) {
331
+ for (const t of store.values()) if (t.status !== "completed") return true;
332
+ return false;
333
+ }
334
+ const piBackend = {
335
+ name: "pi",
336
+ async run(inputs) {
337
+ const { session, boot, prompt, spinner, config, programConfig } = inputs;
338
+ const modelId = inputs.model;
339
+ const capture = createAioCapture({
340
+ enabled: session.captureAio,
341
+ projectApiKey: boot.credentials.projectApiKey,
342
+ apiHost: boot.credentials.host.apiHost,
343
+ runTags: boot.wizardMetadata
344
+ });
345
+ getUI().log.step("Initializing Wizard agent...");
346
+ getUI().log.step(`Verbose logs: ${getLogFilePath()}`);
347
+ getUI().log.success("Agent initialized. Let's get cooking!");
348
+ spinner.start(config.spinnerMessage ?? "Customizing your PostHog setup...");
349
+ const startTime = Date.now();
350
+ const signals = new AgentOutputSignals();
351
+ let assistantTurns = 0;
352
+ let toolCalls = 0;
353
+ const runDurations = () => {
354
+ const durationMs = Date.now() - startTime;
355
+ return {
356
+ duration_ms: durationMs,
357
+ duration_seconds: Math.round(durationMs / 1e3)
358
+ };
359
+ };
360
+ const captureAborted = () => analytics.wizardCapture("agent aborted", {
361
+ ...runDurations(),
362
+ model: modelId
363
+ });
364
+ try {
365
+ const { createAgentSession, DefaultResourceLoader, SessionManager, AuthStorage, ModelRegistry, getAgentDir, createLsToolDefinition, createFindToolDefinition, createGrepToolDefinition, createBashToolDefinition, createReadToolDefinition, createEditToolDefinition, createWriteToolDefinition } = await import("@earendil-works/pi-coding-agent");
366
+ const { provider, caps } = buildGatewayProvider({
367
+ gatewayUrl: boot.credentials.host.gatewayUrl,
368
+ accessToken: boot.credentials.accessToken,
369
+ wizardMetadata: boot.wizardMetadata,
370
+ wizardFlags: boot.wizardFlags,
371
+ modelId,
372
+ effort: inputs.thinkingLevel
373
+ });
374
+ const registry = ModelRegistry.inMemory(AuthStorage.create());
375
+ registry.registerProvider(GATEWAY_PROVIDER, provider);
376
+ const model = registry.find(GATEWAY_PROVIDER, modelId);
377
+ if (!model) return {
378
+ error: "WIZARD_API_ERROR",
379
+ message: "pi: gateway model could not be resolved"
380
+ };
381
+ const askState = { pending: false };
382
+ const { createSecurityExtension } = await import("./security-BNqgFjYh.js");
383
+ const security = createSecurityExtension({
384
+ disallowedTools: programConfig.disallowedTools,
385
+ getWizardAskPending: () => askState.pending,
386
+ triageProvider: boot.triageProvider,
387
+ workingDirectory: session.installDir
388
+ });
389
+ const { prewarmYaraScanner } = await import("./yara-hooks--QA2Cwjv.js");
390
+ prewarmYaraScanner();
391
+ const extensionFactories = [security.factory];
392
+ let mcpCleanup;
393
+ let mcpInstructions;
394
+ try {
395
+ const { setupPostHogMcp, fetchInstructions } = await import("./mcp-jKHwa45f.js");
396
+ const instructionsPromise = fetchInstructions(boot.credentials.host.mcpUrl, boot.credentials.accessToken, WIZARD_USER_AGENT);
397
+ const mcp = await setupPostHogMcp({
398
+ mcpUrl: boot.credentials.host.mcpUrl,
399
+ accessToken: boot.credentials.accessToken,
400
+ userAgent: WIZARD_USER_AGENT
401
+ });
402
+ extensionFactories.push(mcp.extensionFactory);
403
+ mcpCleanup = mcp.cleanup;
404
+ mcpInstructions = await instructionsPromise;
405
+ } catch (err) {
406
+ logToFile(`[pi] PostHog MCP setup skipped: ${String(err)}`);
407
+ analytics.wizardCapture("mcp setup failed", {
408
+ harness: "pi",
409
+ scope: "run",
410
+ error: String(err).slice(0, 300)
411
+ });
412
+ }
413
+ const resourceLoader = new DefaultResourceLoader({
414
+ cwd: session.installDir,
415
+ agentDir: getAgentDir(),
416
+ systemPrompt: assembleCommandments({
417
+ program: programConfig.id,
418
+ sequence: "linear",
419
+ harness: "pi",
420
+ caps: {
421
+ bash: true,
422
+ posthogMcp: true
423
+ }
424
+ }) + "\n" + piMcpContext(boot, mcpInstructions),
425
+ noExtensions: true,
426
+ noSkills: true,
427
+ noContextFiles: true,
428
+ noPromptTemplates: true,
429
+ noThemes: true,
430
+ extensionFactories
431
+ });
432
+ await resourceLoader.reload();
433
+ const { createWizardPiTools } = await import("./tools-Br8lP29r.js");
434
+ const { createWizardPiTaskTools } = await import("./tasks-yqJVuTvc.js");
435
+ const { createDispatchAgentTool } = await import("./subagent-CKNbRtfQ.js");
436
+ const wizardTaskTools = createWizardPiTaskTools();
437
+ const scrubbedBash = withMode(createBashToolDefinition(session.installDir, { spawnHook: (ctx) => ({
438
+ ...ctx,
439
+ env: buildScrubbedEnv()
440
+ }) }), "sequential");
441
+ const customTools = [
442
+ withMode(createReadToolDefinition(session.installDir), "parallel"),
443
+ withMode(createEditToolDefinition(session.installDir), "sequential"),
444
+ withMode(createWriteToolDefinition(session.installDir), "sequential"),
445
+ scrubbedBash,
446
+ withMode(createLsToolDefinition(session.installDir), "parallel"),
447
+ withMode(createFindToolDefinition(session.installDir), "parallel"),
448
+ withMode(createGrepToolDefinition(session.installDir), "parallel"),
449
+ ...createWizardPiTools({
450
+ workingDirectory: session.installDir,
451
+ skillsBaseUrl: boot.skillsBaseUrl,
452
+ triageProvider: boot.triageProvider,
453
+ detectPackageManager: config.detectPackageManager,
454
+ askBridge: inputs.askBridge,
455
+ maxQuestions: config.maxQuestions,
456
+ onAskPendingChange: (pending) => {
457
+ askState.pending = pending;
458
+ },
459
+ disallowedTools: programConfig.disallowedTools
460
+ }),
461
+ ...wizardTaskTools.tools,
462
+ createDispatchAgentTool({
463
+ model,
464
+ modelRegistry: registry,
465
+ cwd: session.installDir,
466
+ agentDir: getAgentDir(),
467
+ securityFactory: security.factory,
468
+ bashTool: scrubbedBash,
469
+ sdk: {
470
+ createAgentSession,
471
+ DefaultResourceLoader,
472
+ SessionManager
473
+ }
474
+ })
475
+ ];
476
+ const { session: agentSession } = await createAgentSession({
477
+ model,
478
+ modelRegistry: registry,
479
+ thinkingLevel: caps.thinkingLevel,
480
+ cwd: session.installDir,
481
+ sessionManager: SessionManager.inMemory(session.installDir),
482
+ resourceLoader,
483
+ noTools: "builtin",
484
+ customTools
485
+ });
486
+ await agentSession.bindExtensions({});
487
+ const unsubscribe = agentSession.subscribe((event) => {
488
+ capture.captureFromPiMessageEndEvent(event);
489
+ switch (event.type) {
490
+ case "message_end": {
491
+ if (event.message?.role !== "assistant") break;
492
+ assistantTurns += 1;
493
+ const assistant = extractText(event.message).trim();
494
+ if (assistant) {
495
+ logToFile(`[pi] assistant: ${assistant.slice(0, 1e3)}`);
496
+ applyOutroMarkers(assistant);
497
+ const statusText = lastStatusLine(assistant);
498
+ if (statusText) {
499
+ getUI().pushStatus(statusText);
500
+ spinner.message(statusText);
501
+ }
502
+ for (const line of assistant.split("\n")) signals.push(line);
503
+ }
504
+ break;
505
+ }
506
+ case "tool_execution_start": {
507
+ toolCalls += 1;
508
+ const args = JSON.stringify(event.args ?? {}).slice(0, 200);
509
+ logToFile(`[pi] → ${event.toolName} ${args}`);
510
+ break;
511
+ }
512
+ case "tool_execution_end":
513
+ logToFile(`[pi] ${event.isError ? "✗" : "←"} ${event.toolName}: ${typeof event.result === "string" ? event.result : JSON.stringify(event.result ?? "")}`);
514
+ break;
515
+ case "agent_end":
516
+ logToFile(`[pi] agent_end (willRetry=${String(event.willRetry)})`);
517
+ break;
518
+ default: break;
519
+ }
520
+ });
521
+ capture.setInitialPrompt(prompt);
522
+ try {
523
+ await agentSession.prompt(prompt);
524
+ let continueNudges = 0;
525
+ while (continueNudges < MAX_CONTINUE_NUDGES && !security.state.criticalViolation && hasOpenTasks(wizardTaskTools.store)) {
526
+ continueNudges += 1;
527
+ logToFile(`[pi] completion guard: tasks still open, nudge ${continueNudges}/${MAX_CONTINUE_NUDGES}`);
528
+ await agentSession.prompt(CONTINUE_INSTRUCTION);
529
+ }
530
+ if (!security.state.criticalViolation) try {
531
+ await agentSession.prompt(REMARK_INSTRUCTION);
532
+ } catch (err) {
533
+ logToFile(`[pi] remark request failed: ${String(err)}`);
534
+ }
535
+ } finally {
536
+ unsubscribe();
537
+ mcpCleanup?.();
538
+ }
539
+ if (security.state.criticalViolation) {
540
+ spinner.stop("Security violation detected");
541
+ logToFile(`[pi] terminated: YARA violation (blocked ${security.state.blockedCount} call(s))`);
542
+ captureAborted();
543
+ return { error: "WIZARD_YARA_VIOLATION" };
544
+ }
545
+ const openTasks = hasOpenTasks(wizardTaskTools.store);
546
+ const failure = completionFailure({
547
+ toolCalls,
548
+ openTasks
549
+ });
550
+ if (failure === "WIZARD_NO_PROGRESS") {
551
+ spinner.stop("Agent made no changes");
552
+ logToFile(`[pi] no progress: ${assistantTurns} assistant turn(s), 0 tool calls`);
553
+ analytics.wizardCapture("agent no progress", { assistant_turns: assistantTurns });
554
+ captureAborted();
555
+ return { error: failure };
556
+ }
557
+ if (failure === "WIZARD_INCOMPLETE_TASKS") {
558
+ spinner.stop("Agent stopped before finishing");
559
+ logToFile("[pi] incomplete: tasks left open");
560
+ analytics.wizardCapture("agent incomplete tasks", { open_tasks: true });
561
+ captureAborted();
562
+ return { error: failure };
563
+ }
564
+ const remark = signals.remark();
565
+ if (remark) analytics.capture(WIZARD_REMARK_EVENT_NAME, { remark });
566
+ const skillFailure = signals.skillInstallFailure();
567
+ if (skillFailure !== void 0) analytics.wizardCapture("agent continued without skill", { detail: skillFailure });
568
+ try {
569
+ const planFile = path.join(session.installDir, ".posthog-events.json");
570
+ if (fs.existsSync(planFile)) await fs.promises.rm(planFile);
571
+ } catch (err) {
572
+ logToFile(`[pi] .posthog-events.json cleanup skipped: ${String(err)}`);
573
+ }
574
+ const stats = agentSession.getSessionStats();
575
+ analytics.wizardCapture("agent completed", {
576
+ ...runDurations(),
577
+ model: modelId,
578
+ num_turns: assistantTurns,
579
+ input_tokens: stats.tokens.input,
580
+ output_tokens: stats.tokens.output,
581
+ cache_creation_input_tokens: stats.tokens.cacheWrite,
582
+ cache_read_input_tokens: stats.tokens.cacheRead
583
+ });
584
+ spinner.stop(config.successMessage ?? "PostHog integration complete");
585
+ return {};
586
+ } catch (err) {
587
+ const message = err instanceof Error ? err.message : String(err);
588
+ logToFile(`[pi] run error: ${message}`);
589
+ spinner.stop(config.errorMessage ?? `${config.integrationLabel} failed`);
590
+ getUI().log.error(`pi backend error: ${message}`);
591
+ captureAborted();
592
+ const lower = message.toLowerCase();
593
+ if (lower.includes("rate limit") || lower.includes("429")) return {
594
+ error: "WIZARD_RATE_LIMIT",
595
+ message
596
+ };
597
+ return {
598
+ error: "WIZARD_API_ERROR",
599
+ message
600
+ };
601
+ }
602
+ },
603
+ async runTask(inputs) {
604
+ const { runPiTask } = await import("./task-DwzRxORh.js");
605
+ return runPiTask(inputs);
606
+ }
607
+ };
608
+ //#endregion
609
+ export { piBackend as a, lastStatusLine as i, buildScrubbedEnv as n, withMode as o, extractText as r, createAioCapture as s, applyOutroMarkers as t };
610
+
611
+ //# sourceMappingURL=pi-CfdqOKDI.js.map