prismalens 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/dist/bin/prismalens.js +39 -50
  2. package/dist/chunk-2Z7QZSIS.js +20 -0
  3. package/dist/chunk-5BT3XQOG.js +2990 -0
  4. package/dist/chunk-6N4PHBII.js +30 -0
  5. package/dist/chunk-CTKCK7QT.js +387 -0
  6. package/dist/chunk-CVSS5JPC.js +130 -0
  7. package/dist/chunk-HPE5CTO4.js +22 -0
  8. package/dist/chunk-PTBCAI34.js +34 -0
  9. package/dist/chunk-PVQVFRIV.js +452 -0
  10. package/dist/chunk-QDK5PAI3.js +155 -0
  11. package/dist/chunk-SSEIMBQ2.js +204 -0
  12. package/dist/chunk-TGP6QTFO.js +156 -0
  13. package/dist/chunk-V6M6ISKI.js +161 -0
  14. package/dist/chunk-XH6DIKTA.js +83 -0
  15. package/dist/src/cli/auth.js +112 -101
  16. package/dist/src/cli/doctor.js +184 -187
  17. package/dist/src/cli/flags.js +6 -32
  18. package/dist/src/cli/grouping.js +16 -227
  19. package/dist/src/cli/init.js +54 -48
  20. package/dist/src/cli/investigate.js +23 -465
  21. package/dist/src/cli/listen.js +550 -286
  22. package/dist/src/cli/report.js +70 -67
  23. package/dist/src/cli/serve.js +260 -30
  24. package/dist/src/cli/status.js +87 -86
  25. package/package.json +16 -7
  26. package/dist/bin/prismalens.d.ts +0 -3
  27. package/dist/bin/prismalens.d.ts.map +0 -1
  28. package/dist/bin/prismalens.js.map +0 -1
  29. package/dist/src/cli/auth.d.ts +0 -3
  30. package/dist/src/cli/auth.d.ts.map +0 -1
  31. package/dist/src/cli/auth.js.map +0 -1
  32. package/dist/src/cli/doctor.d.ts +0 -18
  33. package/dist/src/cli/doctor.d.ts.map +0 -1
  34. package/dist/src/cli/doctor.js.map +0 -1
  35. package/dist/src/cli/flags.d.ts +0 -2
  36. package/dist/src/cli/flags.d.ts.map +0 -1
  37. package/dist/src/cli/flags.js.map +0 -1
  38. package/dist/src/cli/grouping.d.ts +0 -18
  39. package/dist/src/cli/grouping.d.ts.map +0 -1
  40. package/dist/src/cli/grouping.js.map +0 -1
  41. package/dist/src/cli/init.d.ts +0 -3
  42. package/dist/src/cli/init.d.ts.map +0 -1
  43. package/dist/src/cli/init.js.map +0 -1
  44. package/dist/src/cli/investigate.d.ts +0 -115
  45. package/dist/src/cli/investigate.d.ts.map +0 -1
  46. package/dist/src/cli/investigate.js.map +0 -1
  47. package/dist/src/cli/listen.d.ts +0 -56
  48. package/dist/src/cli/listen.d.ts.map +0 -1
  49. package/dist/src/cli/listen.js.map +0 -1
  50. package/dist/src/cli/report.d.ts +0 -24
  51. package/dist/src/cli/report.d.ts.map +0 -1
  52. package/dist/src/cli/report.js.map +0 -1
  53. package/dist/src/cli/serve.d.ts +0 -3
  54. package/dist/src/cli/serve.d.ts.map +0 -1
  55. package/dist/src/cli/serve.js.map +0 -1
  56. package/dist/src/cli/status.d.ts +0 -19
  57. package/dist/src/cli/status.d.ts.map +0 -1
  58. package/dist/src/cli/status.js.map +0 -1
  59. package/dist/src/config/loader.d.ts +0 -22
  60. package/dist/src/config/loader.d.ts.map +0 -1
  61. package/dist/src/config/loader.js +0 -195
  62. package/dist/src/config/loader.js.map +0 -1
  63. package/dist/src/config/schema.d.ts +0 -465
  64. package/dist/src/config/schema.d.ts.map +0 -1
  65. package/dist/src/config/schema.js +0 -219
  66. package/dist/src/config/schema.js.map +0 -1
  67. package/dist/src/core/caps.d.ts +0 -36
  68. package/dist/src/core/caps.d.ts.map +0 -1
  69. package/dist/src/core/caps.js +0 -36
  70. package/dist/src/core/caps.js.map +0 -1
  71. package/dist/src/core/db.d.ts +0 -3
  72. package/dist/src/core/db.d.ts.map +0 -1
  73. package/dist/src/core/db.js +0 -105
  74. package/dist/src/core/db.js.map +0 -1
  75. package/dist/src/core/detect-repo.d.ts +0 -4
  76. package/dist/src/core/detect-repo.d.ts.map +0 -1
  77. package/dist/src/core/detect-repo.js +0 -28
  78. package/dist/src/core/detect-repo.js.map +0 -1
  79. package/dist/src/core/file-session-store.d.ts +0 -10
  80. package/dist/src/core/file-session-store.d.ts.map +0 -1
  81. package/dist/src/core/file-session-store.js +0 -34
  82. package/dist/src/core/file-session-store.js.map +0 -1
  83. package/dist/src/core/parse-stdin.d.ts +0 -2
  84. package/dist/src/core/parse-stdin.d.ts.map +0 -1
  85. package/dist/src/core/parse-stdin.js +0 -21
  86. package/dist/src/core/parse-stdin.js.map +0 -1
  87. package/dist/src/core/run-investigation.d.ts +0 -54
  88. package/dist/src/core/run-investigation.d.ts.map +0 -1
  89. package/dist/src/core/run-investigation.js +0 -202
  90. package/dist/src/core/run-investigation.js.map +0 -1
  91. package/dist/src/core/session.d.ts +0 -63
  92. package/dist/src/core/session.d.ts.map +0 -1
  93. package/dist/src/core/session.js +0 -45
  94. package/dist/src/core/session.js.map +0 -1
  95. package/dist/src/core/slack-notify.d.ts +0 -9
  96. package/dist/src/core/slack-notify.d.ts.map +0 -1
  97. package/dist/src/core/slack-notify.js +0 -57
  98. package/dist/src/core/slack-notify.js.map +0 -1
  99. package/dist/src/core/sqlite-session-store.d.ts +0 -39
  100. package/dist/src/core/sqlite-session-store.d.ts.map +0 -1
  101. package/dist/src/core/sqlite-session-store.js +0 -239
  102. package/dist/src/core/sqlite-session-store.js.map +0 -1
  103. package/dist/src/http/server.d.ts +0 -31
  104. package/dist/src/http/server.d.ts.map +0 -1
  105. package/dist/src/http/server.js +0 -164
  106. package/dist/src/http/server.js.map +0 -1
  107. package/dist/src/jsonrpc/server.d.ts +0 -44
  108. package/dist/src/jsonrpc/server.d.ts.map +0 -1
  109. package/dist/src/jsonrpc/server.js +0 -267
  110. package/dist/src/jsonrpc/server.js.map +0 -1
  111. package/dist/src/jsonrpc/types.d.ts +0 -12
  112. package/dist/src/jsonrpc/types.d.ts.map +0 -1
  113. package/dist/src/jsonrpc/types.js +0 -4
  114. package/dist/src/jsonrpc/types.js.map +0 -1
  115. package/dist/src/version.d.ts +0 -8
  116. package/dist/src/version.d.ts.map +0 -1
  117. package/dist/src/version.js +0 -27
  118. package/dist/src/version.js.map +0 -1
@@ -0,0 +1,2990 @@
1
+ import {
2
+ getDefaultModel
3
+ } from "./chunk-XH6DIKTA.js";
4
+
5
+ // ../@prismalens/config/dist/providers/harness.js
6
+ var HARNESS_IDS = ["deepagents", "claude-code", "codex"];
7
+ var HARNESS_REGISTRY = {
8
+ deepagents: {
9
+ id: "deepagents",
10
+ label: "deepagents (ACP)",
11
+ binary: "deepagents-acp",
12
+ transport: "acp",
13
+ modelPrefix: "openai:",
14
+ readOnlyFidelity: "cooperative",
15
+ readOnlyMechanism: "ACP session/request_permission auto-approved (prompt-only); OS enforcement arrives with the Sandbox port (ADR-0020/B.1)",
16
+ implemented: true
17
+ },
18
+ "claude-code": {
19
+ id: "claude-code",
20
+ label: "Claude Code (Agent SDK)",
21
+ binary: "claude",
22
+ transport: "agent-sdk",
23
+ modelPrefix: null,
24
+ readOnlyFidelity: "enforced",
25
+ // The reported mechanism is DERIVED from readOnlyDeny — no hand-typed tool list
26
+ // here to drift from what the runner enforces (ADR-0017 Amendment 2).
27
+ readOnlyMechanism: "Agent SDK disallowedTools + permissionMode",
28
+ readOnlyDeny: ["Edit", "Write", "MultiEdit", "NotebookEdit"],
29
+ implemented: true
30
+ },
31
+ codex: {
32
+ id: "codex",
33
+ label: "Codex",
34
+ binary: "codex",
35
+ transport: "subprocess-jsonl",
36
+ modelPrefix: null,
37
+ readOnlyFidelity: "enforced",
38
+ readOnlyMechanism: "OS sandbox (seccomp/landlock) \u2014 not yet wired",
39
+ implemented: false
40
+ }
41
+ };
42
+ var HARNESS_BINARY = {
43
+ deepagents: HARNESS_REGISTRY.deepagents.binary,
44
+ "claude-code": HARNESS_REGISTRY["claude-code"].binary,
45
+ codex: HARNESS_REGISTRY.codex.binary
46
+ };
47
+ var PERMISSION_MODES = [
48
+ "read-only",
49
+ "supervised",
50
+ "auto",
51
+ "dangerous"
52
+ ];
53
+ function resolvePermissionOutcome(harnessId, mode) {
54
+ const registry = HARNESS_REGISTRY[harnessId];
55
+ if (mode === "read-only" || mode === "supervised") {
56
+ const mechanism = registry.readOnlyDeny?.length ? `disallowedTools deny-list: ${registry.readOnlyDeny.join(", ")}` : registry.readOnlyMechanism;
57
+ return { mode, fidelity: registry.readOnlyFidelity, mechanism };
58
+ }
59
+ return {
60
+ mode,
61
+ fidelity: "advisory",
62
+ mechanism: mode === "dangerous" ? "full access \u2014 no restrictions applied" : "writes auto-accepted \u2014 no read-only floor"
63
+ };
64
+ }
65
+
66
+ // ../@prismalens/config/dist/model.js
67
+ import { createAnthropic } from "@ai-sdk/anthropic";
68
+ import { createGoogle } from "@ai-sdk/google";
69
+ import { createGroq } from "@ai-sdk/groq";
70
+ import { createOpenAI } from "@ai-sdk/openai";
71
+ import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
72
+ import { APICallError, generateText } from "ai";
73
+ function resolveModel(providerId, model, creds = {}) {
74
+ const { apiKey, baseURL } = creds;
75
+ switch (providerId) {
76
+ case "anthropic":
77
+ return createAnthropic({ apiKey, ...baseURL ? { baseURL } : {} })(model);
78
+ case "openai":
79
+ return createOpenAI({ apiKey, ...baseURL ? { baseURL } : {} })(model);
80
+ case "google":
81
+ return createGoogle({ apiKey })(model);
82
+ case "groq":
83
+ return createGroq({ apiKey })(model);
84
+ case "ollama":
85
+ case "custom": {
86
+ if (!baseURL) {
87
+ throw new Error(`Provider "${providerId}" is OpenAI-compatible and requires a baseURL.`);
88
+ }
89
+ return createOpenAICompatible({
90
+ name: providerId,
91
+ baseURL,
92
+ ...apiKey ? { apiKey } : {}
93
+ })(model);
94
+ }
95
+ default: {
96
+ const unreachable = providerId;
97
+ throw new Error(`Unknown LLM provider: ${String(unreachable)}`);
98
+ }
99
+ }
100
+ }
101
+ async function pingModel(providerId, model, creds = {}, timeoutMs = 1e4) {
102
+ const resolvedModel = model ?? getDefaultModel(providerId);
103
+ if (!resolvedModel) {
104
+ return {
105
+ success: false,
106
+ error: `No model specified and provider "${providerId}" has no default model.`
107
+ };
108
+ }
109
+ try {
110
+ await generateText({
111
+ model: resolveModel(providerId, resolvedModel, creds),
112
+ prompt: "ping",
113
+ maxOutputTokens: 1,
114
+ abortSignal: AbortSignal.timeout(timeoutMs)
115
+ });
116
+ return { success: true };
117
+ } catch (err) {
118
+ return { success: false, error: describePingError(err) };
119
+ }
120
+ }
121
+ function describePingError(err) {
122
+ if (APICallError.isInstance(err)) {
123
+ const status = err.statusCode;
124
+ if (status === 401 || status === 403)
125
+ return "Invalid or unauthorized API key.";
126
+ if (status === 404)
127
+ return "Model or endpoint not found.";
128
+ if (status === 429)
129
+ return "Rate limited \u2014 try again shortly.";
130
+ if (status && status >= 500)
131
+ return `Provider error (${status}).`;
132
+ return err.message || `Provider returned ${status ?? "an error"}.`;
133
+ }
134
+ return err instanceof Error ? err.message : "Connection failed";
135
+ }
136
+
137
+ // ../@prismalens/engine/dist/sandbox/e2b.js
138
+ import { EventEmitter } from "node:events";
139
+ import { createRequire } from "node:module";
140
+ import { PassThrough, Writable } from "node:stream";
141
+ function loadE2b() {
142
+ const require2 = createRequire(import.meta.url);
143
+ return require2("e2b");
144
+ }
145
+ var DEFAULT_TEMPLATE = "base";
146
+ function shellQuote(token) {
147
+ return `'${token.replaceAll("'", `'\\''`)}'`;
148
+ }
149
+ function definedEnv(env) {
150
+ const out = {};
151
+ for (const [key, value] of Object.entries(env ?? {})) {
152
+ if (value !== void 0)
153
+ out[key] = value;
154
+ }
155
+ return out;
156
+ }
157
+ var E2bStdin = class extends Writable {
158
+ handle = null;
159
+ buffered = [];
160
+ endBuffered = false;
161
+ chain = Promise.resolve();
162
+ _write(chunk, _enc, cb) {
163
+ if (this.handle)
164
+ this.forward(Buffer.from(chunk));
165
+ else
166
+ this.buffered.push(Buffer.from(chunk));
167
+ cb();
168
+ }
169
+ _final(cb) {
170
+ if (this.handle)
171
+ this.closeRemote();
172
+ else
173
+ this.endBuffered = true;
174
+ cb();
175
+ }
176
+ /** Bind the resolved handle: replay buffered writes in order, then any pending EOF. */
177
+ attach(handle) {
178
+ this.handle = handle;
179
+ for (const chunk of this.buffered)
180
+ this.forward(chunk);
181
+ this.buffered.length = 0;
182
+ if (this.endBuffered)
183
+ this.closeRemote();
184
+ }
185
+ forward(chunk) {
186
+ const handle = this.handle;
187
+ if (!handle)
188
+ return;
189
+ this.chain = this.chain.then(() => handle.sendStdin(chunk).catch(() => {
190
+ }));
191
+ }
192
+ closeRemote() {
193
+ const handle = this.handle;
194
+ if (!handle)
195
+ return;
196
+ this.chain = this.chain.then(() => handle.closeStdin().catch(() => {
197
+ }));
198
+ }
199
+ };
200
+ var E2bSandboxProcess = class extends EventEmitter {
201
+ stdin;
202
+ stdout;
203
+ stderr;
204
+ killed = false;
205
+ timedOut = false;
206
+ appliedLimits;
207
+ stdoutPass;
208
+ stderrPass;
209
+ handle = null;
210
+ settled = false;
211
+ outputEnded = false;
212
+ deadline = null;
213
+ constructor(limits) {
214
+ super();
215
+ this.stdin = new E2bStdin();
216
+ this.stdoutPass = new PassThrough();
217
+ this.stderrPass = new PassThrough();
218
+ this.stdout = this.stdoutPass;
219
+ this.stderr = this.stderrPass;
220
+ const applied = {};
221
+ if (limits?.wallClockMs && limits.wallClockMs > 0) {
222
+ applied.wallClockMs = limits.wallClockMs;
223
+ this.deadline = setTimeout(() => {
224
+ this.timedOut = true;
225
+ this.kill("SIGKILL");
226
+ }, limits.wallClockMs);
227
+ this.deadline.unref();
228
+ }
229
+ this.appliedLimits = applied;
230
+ }
231
+ /** Push a remote-stdout chunk to the readable the ACP readline drains. */
232
+ pushStdout(data) {
233
+ if (!this.outputEnded)
234
+ this.stdoutPass.write(data);
235
+ }
236
+ /** Push a remote-stderr chunk to the readable the ACP client tails for diagnostics. */
237
+ pushStderr(data) {
238
+ if (!this.outputEnded)
239
+ this.stderrPass.write(data);
240
+ }
241
+ /** Bind the resolved remote command handle to the stdio forwarders. */
242
+ attach(handle) {
243
+ this.handle = handle;
244
+ if (this.killed) {
245
+ void handle.kill().catch(() => {
246
+ });
247
+ return;
248
+ }
249
+ this.stdin.attach(handle);
250
+ }
251
+ /** Terminal: the remote command exited — end the streams and emit `close`. */
252
+ closeWith(code) {
253
+ this.settle(() => this.emit("close", code, null));
254
+ }
255
+ /**
256
+ * Terminal: the VM/command failed to start — emit `error` and ONLY `error` (like
257
+ * node's failed-spawn path, which never reaches `close`). Consumers must treat
258
+ * `error` as terminal on its own — the ACP runner does (its error handler calls
259
+ * finish()); a consumer waiting solely on `close` would hang on this path.
260
+ * A failure that arrives AFTER an explicit kill is the kill's own consequence, so it
261
+ * degrades to a clean `close` rather than a spurious error.
262
+ */
263
+ failWith(err) {
264
+ if (this.killed) {
265
+ this.closeWith(null);
266
+ return;
267
+ }
268
+ this.settle(() => this.emit("error", err));
269
+ }
270
+ kill(_signal) {
271
+ this.killed = true;
272
+ if (this.stdin.writable)
273
+ this.stdin.end();
274
+ if (this.handle)
275
+ void this.handle.kill().catch(() => {
276
+ });
277
+ return true;
278
+ }
279
+ settle(emit) {
280
+ if (this.settled)
281
+ return;
282
+ this.settled = true;
283
+ if (this.deadline) {
284
+ clearTimeout(this.deadline);
285
+ this.deadline = null;
286
+ }
287
+ this.endOutput();
288
+ emit();
289
+ }
290
+ endOutput() {
291
+ if (this.outputEnded)
292
+ return;
293
+ this.outputEnded = true;
294
+ this.stdoutPass.end();
295
+ this.stderrPass.end();
296
+ }
297
+ };
298
+ function createE2bSandbox(options = {}) {
299
+ let e2b;
300
+ try {
301
+ e2b = options.loader ? options.loader() : loadE2b();
302
+ } catch {
303
+ throw new Error("e2b sandbox unavailable: could not resolve the 'e2b' package. Install it (`npm i e2b`) or select a different sandbox mode (--sandbox process|srt).");
304
+ }
305
+ const apiKey = options.apiKey ?? process.env.E2B_API_KEY;
306
+ if (!apiKey) {
307
+ throw new Error("e2b sandbox unavailable: E2B_API_KEY is not set. Export E2B_API_KEY (https://e2b.dev/dashboard) or select a different sandbox mode (--sandbox process|srt).");
308
+ }
309
+ const template = options.template ?? process.env.E2B_TEMPLATE ?? DEFAULT_TEMPLATE;
310
+ const allowed = options.allowedDomains ?? [];
311
+ const network = allowed.length > 0 ? { network: { allowOut: allowed } } : { allowInternetAccess: false };
312
+ const children = /* @__PURE__ */ new Set();
313
+ let vmPromise = null;
314
+ let vm = null;
315
+ const VM_LIFETIME_HEADROOM_MS = 6e4;
316
+ const ensureVm = (minLifetimeMs) => {
317
+ if (!vmPromise) {
318
+ const needed = minLifetimeMs !== void 0 ? minLifetimeMs + VM_LIFETIME_HEADROOM_MS : void 0;
319
+ const timeoutMs = options.timeoutMs !== void 0 || needed !== void 0 ? Math.max(options.timeoutMs ?? 0, needed ?? 0) : void 0;
320
+ vmPromise = e2b.Sandbox.create(template, {
321
+ apiKey,
322
+ ...timeoutMs !== void 0 ? { timeoutMs } : {},
323
+ ...network
324
+ }).then((created) => {
325
+ vm = created;
326
+ return created;
327
+ });
328
+ }
329
+ return vmPromise;
330
+ };
331
+ return {
332
+ id: "e2b",
333
+ fidelity: "enforced",
334
+ spawn(command, args, spawnOptions) {
335
+ const proc = new E2bSandboxProcess(spawnOptions.limits);
336
+ children.add(proc);
337
+ proc.on("close", () => children.delete(proc));
338
+ const commandLine = [command, ...args].map(shellQuote).join(" ");
339
+ const envs = definedEnv(spawnOptions.env);
340
+ void (async () => {
341
+ try {
342
+ const sandbox = await ensureVm(spawnOptions.limits?.wallClockMs);
343
+ const handle = await sandbox.commands.run(commandLine, {
344
+ background: true,
345
+ stdin: true,
346
+ cwd: spawnOptions.cwd,
347
+ envs,
348
+ onStdout: (d) => proc.pushStdout(d),
349
+ onStderr: (d) => proc.pushStderr(d)
350
+ });
351
+ proc.attach(handle);
352
+ handle.wait().then((res) => proc.closeWith(res.exitCode ?? null), (err) => {
353
+ const code = err.exitCode;
354
+ if (typeof code === "number")
355
+ proc.closeWith(code);
356
+ else
357
+ proc.failWith(err instanceof Error ? err : new Error(String(err)));
358
+ });
359
+ } catch (err) {
360
+ proc.failWith(err instanceof Error ? err : new Error(String(err)));
361
+ }
362
+ })();
363
+ return proc;
364
+ },
365
+ async destroy() {
366
+ for (const child of children) {
367
+ if (!child.killed)
368
+ child.kill();
369
+ }
370
+ children.clear();
371
+ if (vmPromise) {
372
+ try {
373
+ const sandbox = vm ?? await vmPromise;
374
+ await sandbox.kill();
375
+ } catch {
376
+ }
377
+ vmPromise = null;
378
+ vm = null;
379
+ }
380
+ }
381
+ };
382
+ }
383
+
384
+ // ../@prismalens/engine/dist/sandbox/process-floor.js
385
+ import { spawn } from "node:child_process";
386
+ var SAFE_ENV_ALLOWLIST = [
387
+ "PATH",
388
+ "HOME",
389
+ "USER",
390
+ "LOGNAME",
391
+ "SHELL",
392
+ "LANG",
393
+ "LC_ALL",
394
+ "LC_CTYPE",
395
+ "TERM",
396
+ "TMPDIR",
397
+ "TZ",
398
+ "PWD"
399
+ ];
400
+ function buildFloorEnv(extra) {
401
+ const env = {};
402
+ for (const key of SAFE_ENV_ALLOWLIST) {
403
+ const value = process.env[key];
404
+ if (value !== void 0)
405
+ env[key] = value;
406
+ }
407
+ for (const [key, value] of Object.entries(extra ?? {})) {
408
+ if (value !== void 0)
409
+ env[key] = value;
410
+ }
411
+ return env;
412
+ }
413
+ function withLimits(child, limits, enforced = {}) {
414
+ const applied = { ...enforced };
415
+ const proc = child;
416
+ proc.timedOut = false;
417
+ if (limits?.wallClockMs && limits.wallClockMs > 0) {
418
+ applied.wallClockMs = limits.wallClockMs;
419
+ const timer = setTimeout(() => {
420
+ proc.timedOut = true;
421
+ proc.kill("SIGKILL");
422
+ }, limits.wallClockMs);
423
+ timer.unref();
424
+ child.on("close", () => clearTimeout(timer));
425
+ }
426
+ proc.appliedLimits = applied;
427
+ return proc;
428
+ }
429
+ function createProcessFloorSandbox() {
430
+ const children = /* @__PURE__ */ new Set();
431
+ return {
432
+ id: "process-floor",
433
+ fidelity: "cooperative",
434
+ spawn(command, args, options) {
435
+ const child = spawn(command, args, {
436
+ cwd: options.cwd,
437
+ env: buildFloorEnv(options.env),
438
+ stdio: ["pipe", "pipe", "pipe"]
439
+ });
440
+ const proc = withLimits(child, options.limits);
441
+ children.add(proc);
442
+ proc.on("close", () => children.delete(proc));
443
+ return proc;
444
+ },
445
+ async destroy() {
446
+ for (const child of children) {
447
+ if (!child.killed)
448
+ child.kill();
449
+ }
450
+ children.clear();
451
+ }
452
+ };
453
+ }
454
+
455
+ // ../@prismalens/engine/dist/sandbox/srt.js
456
+ import { spawn as spawn2 } from "node:child_process";
457
+ import { accessSync, constants, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
458
+ import { createRequire as createRequire2 } from "node:module";
459
+ import { tmpdir } from "node:os";
460
+ import { delimiter, dirname, join } from "node:path";
461
+ function resolveSrtPackageEntry() {
462
+ try {
463
+ const require2 = createRequire2(import.meta.url);
464
+ const pkgJsonPath = require2.resolve("@anthropic-ai/sandbox-runtime/package.json");
465
+ const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
466
+ const bin = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.srt;
467
+ if (!bin)
468
+ return null;
469
+ const cliPath = join(dirname(pkgJsonPath), bin);
470
+ accessSync(cliPath, constants.R_OK);
471
+ return { command: process.execPath, prefixArgs: [cliPath] };
472
+ } catch {
473
+ return null;
474
+ }
475
+ }
476
+ function resolveSrtBinaryOnPath() {
477
+ const pathVar = process.env.PATH;
478
+ if (!pathVar)
479
+ return null;
480
+ for (const dir of pathVar.split(delimiter)) {
481
+ if (!dir)
482
+ continue;
483
+ const candidate = join(dir, "srt");
484
+ try {
485
+ accessSync(candidate, constants.X_OK);
486
+ return { command: candidate, prefixArgs: [] };
487
+ } catch {
488
+ }
489
+ }
490
+ return null;
491
+ }
492
+ function resolveSrtEntry() {
493
+ return resolveSrtPackageEntry() ?? resolveSrtBinaryOnPath();
494
+ }
495
+ function isSrtAvailable() {
496
+ return resolveSrtEntry() !== null;
497
+ }
498
+ var systemdRunPath;
499
+ function resolveSystemdRun() {
500
+ if (systemdRunPath !== void 0)
501
+ return systemdRunPath;
502
+ systemdRunPath = null;
503
+ const pathVar = process.env.PATH;
504
+ if (pathVar) {
505
+ for (const dir of pathVar.split(delimiter)) {
506
+ if (!dir)
507
+ continue;
508
+ const candidate = join(dir, "systemd-run");
509
+ try {
510
+ accessSync(candidate, constants.X_OK);
511
+ systemdRunPath = candidate;
512
+ break;
513
+ } catch {
514
+ }
515
+ }
516
+ }
517
+ return systemdRunPath;
518
+ }
519
+ function memoryMaxArg(memoryMb) {
520
+ if (!memoryMb || memoryMb <= 0)
521
+ return null;
522
+ return `MemoryMax=${Math.round(memoryMb)}M`;
523
+ }
524
+ function cpuQuotaArg(cpuCores) {
525
+ if (!cpuCores || cpuCores <= 0)
526
+ return null;
527
+ return `CPUQuota=${Math.round(cpuCores * 100)}%`;
528
+ }
529
+ function writeSrtSettings(allowedDomains) {
530
+ const settingsDir = mkdtempSync(join(tmpdir(), "pl-srt-"));
531
+ const settingsPath = join(settingsDir, "srt-settings.json");
532
+ writeFileSync(settingsPath, JSON.stringify({
533
+ network: {
534
+ allowedDomains,
535
+ deniedDomains: [],
536
+ // Hard-deny non-allowlisted hosts regardless of any ask-callback: srt
537
+ // only guarantees denial when strictAllowlist is set (its CLI happens
538
+ // to run without an ask callback today, but "enforced" must not hinge
539
+ // on that implementation detail — an interactive prompt would also
540
+ // wedge our piped JSON-RPC stdin).
541
+ strictAllowlist: true
542
+ },
543
+ filesystem: { denyRead: [], allowWrite: ["."], denyWrite: [] }
544
+ }));
545
+ return { settingsDir, settingsPath };
546
+ }
547
+ var SRT_EGRESS_WATCHDOG_MS = 15e3;
548
+ function runEgressProbeWithWatchdog(spawnChild, timeoutMs = SRT_EGRESS_WATCHDOG_MS) {
549
+ return new Promise((resolveCode) => {
550
+ let settled = false;
551
+ let timer;
552
+ const finish = (code) => {
553
+ if (settled)
554
+ return;
555
+ settled = true;
556
+ if (timer)
557
+ clearTimeout(timer);
558
+ resolveCode(code);
559
+ };
560
+ let child;
561
+ try {
562
+ child = spawnChild(finish);
563
+ } catch {
564
+ finish("");
565
+ return;
566
+ }
567
+ timer = setTimeout(() => {
568
+ try {
569
+ child.kill("SIGKILL");
570
+ } catch {
571
+ }
572
+ finish("");
573
+ }, timeoutMs);
574
+ timer.unref?.();
575
+ });
576
+ }
577
+ function defaultSrtEgressRunner(targetUrl) {
578
+ const entry = resolveSrtEntry();
579
+ if (!entry)
580
+ return Promise.resolve("");
581
+ let hostname;
582
+ try {
583
+ hostname = new URL(targetUrl).hostname;
584
+ } catch {
585
+ return Promise.resolve("");
586
+ }
587
+ const { settingsDir, settingsPath } = writeSrtSettings([hostname]);
588
+ const srtArgv = [
589
+ ...entry.prefixArgs,
590
+ "--settings",
591
+ settingsPath,
592
+ "--",
593
+ "curl",
594
+ "-sS",
595
+ "-o",
596
+ "/dev/null",
597
+ "-w",
598
+ "%{http_code}",
599
+ "--max-time",
600
+ "8",
601
+ targetUrl
602
+ ];
603
+ return runEgressProbeWithWatchdog((finish) => {
604
+ const child = spawn2(entry.command, srtArgv, {
605
+ env: buildFloorEnv(),
606
+ stdio: ["ignore", "pipe", "ignore"]
607
+ });
608
+ const chunks = [];
609
+ child.stdout.on("data", (d) => chunks.push(d));
610
+ child.on("error", () => finish(""));
611
+ child.on("close", () => finish(Buffer.concat(chunks).toString().trim()));
612
+ return child;
613
+ }).finally(() => {
614
+ try {
615
+ rmSync(settingsDir, { recursive: true, force: true });
616
+ } catch {
617
+ }
618
+ });
619
+ }
620
+ var SRT_EGRESS_UNHEALTHY_TTL_MS = 5 * 6e4;
621
+ var egressProbeCache = /* @__PURE__ */ new Map();
622
+ async function probeSrtEgress(targetUrl, opts = {}) {
623
+ const now = opts.now ?? Date.now;
624
+ const cached = egressProbeCache.get(targetUrl);
625
+ if (cached !== void 0 && (cached.expiresAt === void 0 || now() < cached.expiresAt)) {
626
+ return cached.healthy;
627
+ }
628
+ let healthy = false;
629
+ try {
630
+ const code = (await (opts.runner ?? defaultSrtEgressRunner)(targetUrl)).trim();
631
+ healthy = /^\d{3}$/.test(code) && code !== "000";
632
+ } catch {
633
+ healthy = false;
634
+ }
635
+ egressProbeCache.set(targetUrl, healthy ? { healthy: true } : { healthy: false, expiresAt: now() + SRT_EGRESS_UNHEALTHY_TTL_MS });
636
+ return healthy;
637
+ }
638
+ function createSrtSandbox(options = {}) {
639
+ const entry = resolveSrtEntry();
640
+ if (!entry) {
641
+ throw new Error("srt sandbox unavailable: could not resolve '@anthropic-ai/sandbox-runtime' or an `srt` binary on PATH. Install it (`npm i -g @anthropic-ai/sandbox-runtime`) or select a different sandbox mode (--sandbox process).");
642
+ }
643
+ const { settingsDir, settingsPath } = writeSrtSettings(options.allowedDomains ?? []);
644
+ const children = /* @__PURE__ */ new Set();
645
+ return {
646
+ id: "srt",
647
+ fidelity: "enforced",
648
+ spawn(command, args, spawnOptions) {
649
+ const srtArgv = [
650
+ ...entry.prefixArgs,
651
+ "--settings",
652
+ settingsPath,
653
+ "--",
654
+ command,
655
+ ...args
656
+ ];
657
+ const memArg = memoryMaxArg(spawnOptions.limits?.memoryMb);
658
+ const cpuArg = cpuQuotaArg(spawnOptions.limits?.cpuCores);
659
+ const systemdRun = memArg || cpuArg ? resolveSystemdRun() : null;
660
+ const enforced = {};
661
+ let spawnCommand = entry.command;
662
+ let spawnArgs = srtArgv;
663
+ if (systemdRun) {
664
+ const props = [];
665
+ if (memArg) {
666
+ props.push("-p", memArg);
667
+ enforced.memoryMb = spawnOptions.limits?.memoryMb;
668
+ }
669
+ if (cpuArg) {
670
+ props.push("-p", cpuArg);
671
+ enforced.cpuCores = spawnOptions.limits?.cpuCores;
672
+ }
673
+ spawnCommand = systemdRun;
674
+ spawnArgs = [
675
+ "--user",
676
+ "--scope",
677
+ "--quiet",
678
+ ...props,
679
+ "--",
680
+ entry.command,
681
+ ...srtArgv
682
+ ];
683
+ }
684
+ const child = spawn2(spawnCommand, spawnArgs, {
685
+ cwd: spawnOptions.cwd,
686
+ env: buildFloorEnv(spawnOptions.env),
687
+ stdio: ["pipe", "pipe", "pipe"]
688
+ });
689
+ const proc = withLimits(child, spawnOptions.limits, enforced);
690
+ children.add(proc);
691
+ proc.on("close", () => children.delete(proc));
692
+ return proc;
693
+ },
694
+ async destroy() {
695
+ for (const child of children) {
696
+ if (!child.killed)
697
+ child.kill();
698
+ }
699
+ children.clear();
700
+ try {
701
+ rmSync(settingsDir, { recursive: true, force: true });
702
+ } catch {
703
+ }
704
+ }
705
+ };
706
+ }
707
+
708
+ // ../@prismalens/engine/dist/sandbox/wsl.js
709
+ import { readFile } from "node:fs/promises";
710
+ async function detectWsl() {
711
+ if (process.platform !== "linux")
712
+ return false;
713
+ if (process.env.WSL_DISTRO_NAME)
714
+ return true;
715
+ const version = await readFile("/proc/version", "utf8").catch(() => "");
716
+ return /microsoft/i.test(version);
717
+ }
718
+
719
+ // ../@prismalens/engine/dist/sandbox/select.js
720
+ var SANDBOX_MODES = ["auto", "process", "srt", "e2b"];
721
+ function floorSelection(requested, degradeReason) {
722
+ const sandbox = createProcessFloorSandbox();
723
+ return { sandbox, requested, actual: sandbox.id, degradeReason };
724
+ }
725
+ async function resolveSandbox(mode, options = {}) {
726
+ switch (mode) {
727
+ case "process": {
728
+ const sandbox = createProcessFloorSandbox();
729
+ return { sandbox, requested: mode, actual: sandbox.id };
730
+ }
731
+ case "srt": {
732
+ const sandbox = createSrtSandbox(options);
733
+ return { sandbox, requested: mode, actual: sandbox.id };
734
+ }
735
+ case "e2b": {
736
+ const sandbox = createE2bSandbox(options);
737
+ return { sandbox, requested: mode, actual: sandbox.id };
738
+ }
739
+ case "auto": {
740
+ if (!isSrtAvailable()) {
741
+ return floorSelection(mode, "srt unavailable");
742
+ }
743
+ if (options.probeUrl === void 0) {
744
+ return floorSelection(mode, "no egress allowlist derivable from config \u2014 an enforced zero-egress boundary would starve the harness (its own model endpoint included); set telemetry endpoints or force --sandbox srt");
745
+ }
746
+ if (await (options.wslDetector ?? detectWsl)()) {
747
+ return {
748
+ ...floorSelection(mode, "WSL detected \u2014 srt's egress bridge is unreliable under WSL, so auto uses the process floor without probing; force --sandbox srt to override"),
749
+ degradeExpected: true
750
+ };
751
+ }
752
+ const healthy = await probeSrtEgress(options.probeUrl, options.egressRunner ? { runner: options.egressRunner } : {});
753
+ if (healthy) {
754
+ const sandbox = createSrtSandbox(options);
755
+ return { sandbox, requested: mode, actual: sandbox.id };
756
+ }
757
+ return floorSelection(mode, "srt egress bridge unhealthy \u2014 WSL mirrored networking? Using the process floor");
758
+ }
759
+ }
760
+ }
761
+
762
+ // ../@prismalens/engine/dist/supervisor/conductor.js
763
+ import { randomUUID as randomUUID2 } from "node:crypto";
764
+
765
+ // ../@prismalens/engine/dist/supervisor/investigate.js
766
+ import { randomUUID } from "node:crypto";
767
+
768
+ // ../@prismalens/engine/dist/runner/acp-client.js
769
+ import { createInterface } from "node:readline";
770
+ var autoAllowReadOnly = (req) => {
771
+ const allow = req.options.find((o) => o.kind === "allow_once") ?? req.options.find((o) => (o.kind ?? "").startsWith("allow")) ?? req.options[0];
772
+ return allow ? { optionId: allow.optionId } : { reject: true };
773
+ };
774
+ var DEFAULT_COMMAND = "deepagents-acp";
775
+ var DEFAULT_MODEL = "openai:gpt-oss:120b";
776
+ function buildAcpArgs(model, config) {
777
+ const args = ["-m", model, "-w", config.cwd];
778
+ const native = config.native ?? {};
779
+ const strings = (v) => Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
780
+ args.push(...strings(native.args));
781
+ return args;
782
+ }
783
+ var DEFAULT_INIT_TIMEOUT_MS = 3e4;
784
+ var DEFAULT_PROMPT_TIMEOUT_MS = 18e4;
785
+ var STDERR_TAIL = 500;
786
+ function jsonRpcErrorText(error) {
787
+ const head = error.message ?? `ACP error ${error.code}`;
788
+ if (error.data === void 0)
789
+ return head;
790
+ const data = typeof error.data === "string" ? error.data : JSON.stringify(error.data);
791
+ return `${head} \u2014 ${data.slice(0, 500)}`;
792
+ }
793
+ async function* runAcpBranch(config) {
794
+ const command = config.command ?? DEFAULT_COMMAND;
795
+ const model = config.model ?? DEFAULT_MODEL;
796
+ const args = config.args ?? buildAcpArgs(model, config);
797
+ const permission = config.permission ?? autoAllowReadOnly;
798
+ const initTimeout = config.initTimeoutMs ?? DEFAULT_INIT_TIMEOUT_MS;
799
+ const promptTimeout = config.promptTimeoutMs ?? DEFAULT_PROMPT_TIMEOUT_MS;
800
+ const sandbox = config.sandbox ?? createProcessFloorSandbox();
801
+ const ownsSandbox = config.sandbox === void 0;
802
+ const child = sandbox.spawn(command, args, {
803
+ cwd: config.cwd,
804
+ env: config.env,
805
+ ...config.limits ? { limits: config.limits } : {}
806
+ });
807
+ const queue = [];
808
+ let wake = null;
809
+ let finished = false;
810
+ const stderrChunks = [];
811
+ const pending = /* @__PURE__ */ new Map();
812
+ let nextId = 1;
813
+ const pushItem = (item) => {
814
+ queue.push(item);
815
+ wake?.();
816
+ wake = null;
817
+ };
818
+ const finish = () => {
819
+ finished = true;
820
+ wake?.();
821
+ wake = null;
822
+ };
823
+ const send = (obj) => {
824
+ if (child.stdin.writable)
825
+ child.stdin.write(`${JSON.stringify(obj)}
826
+ `);
827
+ };
828
+ const request = (method, params, timeoutMs) => new Promise((resolve, reject) => {
829
+ const id = nextId++;
830
+ const timer = setTimeout(() => {
831
+ if (pending.delete(id)) {
832
+ reject(new Error(`ACP ${method} timed out after ${timeoutMs}ms`));
833
+ }
834
+ }, timeoutMs);
835
+ pending.set(id, {
836
+ resolve: (result) => {
837
+ clearTimeout(timer);
838
+ resolve(result);
839
+ },
840
+ reject: (err) => {
841
+ clearTimeout(timer);
842
+ reject(err);
843
+ }
844
+ });
845
+ send({ jsonrpc: "2.0", id, method, params });
846
+ });
847
+ const answerPermission = (msg) => {
848
+ const params = msg.params ?? {};
849
+ const options = params.options ?? [];
850
+ const decision = permission({
851
+ options,
852
+ toolCall: params.toolCall
853
+ });
854
+ if ("optionId" in decision) {
855
+ send({
856
+ jsonrpc: "2.0",
857
+ id: msg.id,
858
+ result: {
859
+ outcome: { outcome: "selected", optionId: decision.optionId }
860
+ }
861
+ });
862
+ return;
863
+ }
864
+ const reject = options.find((o) => (o.kind ?? "").startsWith("reject"));
865
+ send({
866
+ jsonrpc: "2.0",
867
+ id: msg.id,
868
+ result: reject ? { outcome: { outcome: "selected", optionId: reject.optionId } } : { outcome: { outcome: "cancelled" } }
869
+ });
870
+ };
871
+ const handleServerRequest = (msg) => {
872
+ const method = msg.method ?? "";
873
+ if (method === "session/request_permission") {
874
+ answerPermission(msg);
875
+ } else if (method.startsWith("fs/")) {
876
+ send({
877
+ jsonrpc: "2.0",
878
+ id: msg.id,
879
+ error: { code: -32601, message: "fs capability not offered" }
880
+ });
881
+ } else {
882
+ send({ jsonrpc: "2.0", id: msg.id, result: {} });
883
+ }
884
+ };
885
+ const rl = createInterface({ input: child.stdout });
886
+ rl.on("line", (raw) => {
887
+ const line = raw.trim();
888
+ if (!line)
889
+ return;
890
+ let msg;
891
+ try {
892
+ msg = JSON.parse(line);
893
+ } catch {
894
+ return;
895
+ }
896
+ if (msg.id !== void 0 && msg.method) {
897
+ handleServerRequest(msg);
898
+ } else if (msg.id !== void 0) {
899
+ const p = pending.get(msg.id);
900
+ if (p) {
901
+ pending.delete(msg.id);
902
+ if (msg.error) {
903
+ p.reject(new Error(jsonRpcErrorText(msg.error)));
904
+ } else {
905
+ p.resolve(msg.result);
906
+ }
907
+ }
908
+ } else if (msg.method === "session/update") {
909
+ const update = msg.params?.update;
910
+ if (update && typeof update === "object") {
911
+ pushItem({ kind: "update", update });
912
+ }
913
+ }
914
+ });
915
+ child.stderr.on("data", (d) => stderrChunks.push(d.toString()));
916
+ child.on("error", (err) => {
917
+ pushItem({
918
+ kind: "error",
919
+ message: `failed to start ${command}: ${err.message}`
920
+ });
921
+ finish();
922
+ });
923
+ child.on("close", (code, signal) => {
924
+ if (finished)
925
+ return;
926
+ const tail = stderrChunks.join("").trim().slice(-STDERR_TAIL);
927
+ const message = child.timedOut ? `harness exceeded its wall-clock limit (${config.limits?.wallClockMs}ms) and was killed${tail ? `: ${tail}` : ""}` : `harness exited early (code=${code} signal=${signal})${tail ? `: ${tail}` : ""}`;
928
+ pushItem({ kind: "error", message });
929
+ finish();
930
+ });
931
+ try {
932
+ await request("initialize", {
933
+ protocolVersion: 1,
934
+ clientCapabilities: {
935
+ fs: { readTextFile: false, writeTextFile: false }
936
+ }
937
+ }, initTimeout);
938
+ const sessionResult = await request("session/new", { cwd: config.cwd, mcpServers: config.mcpServers ?? [] }, initTimeout);
939
+ const sessionId = sessionResult?.sessionId;
940
+ if (!sessionId)
941
+ throw new Error("ACP session/new returned no sessionId");
942
+ request("session/prompt", { sessionId, prompt: [{ type: "text", text: config.prompt }] }, promptTimeout).then((res) => {
943
+ const stopReason = res?.stopReason;
944
+ pushItem({ kind: "done", stopReason: stopReason ?? "end_turn" });
945
+ finish();
946
+ }).catch((err) => {
947
+ pushItem({
948
+ kind: "error",
949
+ message: err instanceof Error ? err.message : String(err)
950
+ });
951
+ finish();
952
+ });
953
+ while (true) {
954
+ while (queue.length > 0) {
955
+ const item = queue.shift();
956
+ if (item)
957
+ yield item;
958
+ }
959
+ if (finished)
960
+ break;
961
+ await new Promise((r) => {
962
+ wake = r;
963
+ });
964
+ }
965
+ while (queue.length > 0) {
966
+ const item = queue.shift();
967
+ if (item)
968
+ yield item;
969
+ }
970
+ } catch (err) {
971
+ yield {
972
+ kind: "error",
973
+ message: err instanceof Error ? err.message : String(err)
974
+ };
975
+ } finally {
976
+ rl.close();
977
+ for (const p of pending.values())
978
+ p.reject(new Error("ACP client closing"));
979
+ pending.clear();
980
+ if (!child.killed)
981
+ child.kill();
982
+ if (ownsSandbox)
983
+ await sandbox.destroy();
984
+ }
985
+ }
986
+
987
+ // ../@prismalens/engine/dist/adapter/acp-adapter.js
988
+ var DEFAULT_PREVIEW_LIMIT = 4e3;
989
+ var AcpAdapter = class {
990
+ ctx;
991
+ seqCounter = 0;
992
+ now;
993
+ previewLimit;
994
+ /** Assistant text deltas accumulated since the last flush. */
995
+ pendingText = "";
996
+ /** tool_call metadata kept to enrich the later tool_call_update (paired by id). */
997
+ toolMeta = /* @__PURE__ */ new Map();
998
+ constructor(ctx) {
999
+ this.ctx = ctx;
1000
+ this.now = ctx.now ?? (() => /* @__PURE__ */ new Date());
1001
+ this.previewLimit = ctx.previewLimit ?? DEFAULT_PREVIEW_LIMIT;
1002
+ }
1003
+ /**
1004
+ * Map one ACP `update` to zero-or-one canonical event. Returns null for updates
1005
+ * we don't surface (thought chunks, plan, mode/command updates) and for
1006
+ * non-terminal tool progress frames (text deltas are accumulated, not emitted).
1007
+ */
1008
+ normalize(u) {
1009
+ switch (u.sessionUpdate) {
1010
+ case "agent_message_chunk":
1011
+ this.pendingText += flattenAcpContent(u.content);
1012
+ return null;
1013
+ case "tool_call":
1014
+ return this.toolCall(u);
1015
+ case "tool_call_update":
1016
+ return this.toolResult(u);
1017
+ default:
1018
+ return null;
1019
+ }
1020
+ }
1021
+ /**
1022
+ * Flush any accumulated assistant text as a text-only `agent_step`. Call before
1023
+ * a terminal event so a pure-text turn (no tool call) is not lost.
1024
+ */
1025
+ flushText() {
1026
+ if (this.pendingText.length === 0)
1027
+ return null;
1028
+ const text = this.pendingText;
1029
+ this.pendingText = "";
1030
+ return { kind: "agent_step", ...this.base(), text, toolCalls: [] };
1031
+ }
1032
+ /** Terminal: a branch finished. Emitted by the runner, not the harness stream. */
1033
+ branchDone(reason) {
1034
+ return { kind: "branch_done", ...this.base(), reason };
1035
+ }
1036
+ /** Terminal: a branch failed. */
1037
+ error(message) {
1038
+ return { kind: "error", ...this.base(), message };
1039
+ }
1040
+ /** Terminal: the run-level reduced report. */
1041
+ report(report) {
1042
+ return {
1043
+ kind: "report",
1044
+ runId: this.ctx.runId,
1045
+ seq: this.nextSeq(),
1046
+ ts: this.now().toISOString(),
1047
+ report
1048
+ };
1049
+ }
1050
+ // --- internals ---
1051
+ toolCall(u) {
1052
+ const toolCallId = u.toolCallId ?? "";
1053
+ const name = pickName(u);
1054
+ this.toolMeta.set(toolCallId, { name, kind: u.kind, rawInput: u.rawInput });
1055
+ const text = this.pendingText;
1056
+ this.pendingText = "";
1057
+ return {
1058
+ kind: "agent_step",
1059
+ ...this.base(),
1060
+ text,
1061
+ toolCalls: [{ toolCallId, name, args: toArgs(u.rawInput) }]
1062
+ };
1063
+ }
1064
+ toolResult(u) {
1065
+ const status = u.status ?? "completed";
1066
+ if (status !== "completed" && status !== "failed")
1067
+ return null;
1068
+ const toolCallId = u.toolCallId ?? "";
1069
+ const meta = this.toolMeta.get(toolCallId);
1070
+ const name = meta?.name ?? pickName(u);
1071
+ const ok = status !== "failed";
1072
+ const preview = truncate(flattenAcpContent(u.content), this.previewLimit);
1073
+ return {
1074
+ kind: "tool_result",
1075
+ ...this.base(),
1076
+ result: {
1077
+ name,
1078
+ toolCategory: mapToolCategory(meta?.kind ?? u.kind),
1079
+ toolCallId,
1080
+ source: deriveSource(name, meta?.rawInput),
1081
+ ok,
1082
+ error: ok ? null : preview || "tool failed",
1083
+ preview
1084
+ }
1085
+ };
1086
+ }
1087
+ /** Common per-event fields shared by every branch-scoped event. */
1088
+ base() {
1089
+ return {
1090
+ runId: this.ctx.runId,
1091
+ branchId: this.ctx.branchId,
1092
+ // ACP/deepagents is flat (verified 2026-06-29) — no nesting path, no label.
1093
+ path: [],
1094
+ seq: this.nextSeq(),
1095
+ label: null,
1096
+ ts: this.now().toISOString()
1097
+ };
1098
+ }
1099
+ nextSeq() {
1100
+ return this.seqCounter++;
1101
+ }
1102
+ };
1103
+ function pickName(u) {
1104
+ const title = typeof u.title === "string" ? u.title.trim() : "";
1105
+ if (title)
1106
+ return title;
1107
+ const kind = typeof u.kind === "string" ? u.kind.trim() : "";
1108
+ return kind || "tool";
1109
+ }
1110
+ function toArgs(rawInput) {
1111
+ if (rawInput === void 0 || rawInput === null)
1112
+ return {};
1113
+ if (typeof rawInput === "object" && !Array.isArray(rawInput)) {
1114
+ return unwrapInput(rawInput);
1115
+ }
1116
+ return { value: rawInput };
1117
+ }
1118
+ function unwrapInput(args) {
1119
+ const keys = Object.keys(args);
1120
+ if (keys.length === 1 && keys[0] === "input" && typeof args.input === "string") {
1121
+ try {
1122
+ const parsed = JSON.parse(args.input);
1123
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1124
+ return parsed;
1125
+ }
1126
+ } catch {
1127
+ }
1128
+ }
1129
+ return args;
1130
+ }
1131
+ function flattenAcpContent(content) {
1132
+ if (content === void 0 || content === null)
1133
+ return "";
1134
+ if (typeof content === "string")
1135
+ return content;
1136
+ if (Array.isArray(content))
1137
+ return content.map(flattenAcpBlock).join("");
1138
+ return flattenAcpBlock(content);
1139
+ }
1140
+ function flattenAcpBlock(block) {
1141
+ if (typeof block === "string")
1142
+ return block;
1143
+ if (block && typeof block === "object") {
1144
+ const b = block;
1145
+ if (typeof b.text === "string")
1146
+ return b.text;
1147
+ if (b.content && typeof b.content === "object") {
1148
+ const inner = b.content;
1149
+ if (typeof inner.text === "string")
1150
+ return inner.text;
1151
+ }
1152
+ }
1153
+ return "";
1154
+ }
1155
+ function deriveSource(name, input) {
1156
+ if (input === void 0 || input === null)
1157
+ return name;
1158
+ const args = typeof input === "object" && !Array.isArray(input) ? unwrapInput(input) : input;
1159
+ let rendered;
1160
+ try {
1161
+ rendered = JSON.stringify(args);
1162
+ } catch {
1163
+ rendered = String(args);
1164
+ }
1165
+ return `${name}(${rendered})`;
1166
+ }
1167
+ function mapToolCategory(kind) {
1168
+ switch (kind) {
1169
+ case "search":
1170
+ return "search";
1171
+ case "read":
1172
+ case "edit":
1173
+ case "move":
1174
+ case "delete":
1175
+ return "file";
1176
+ default:
1177
+ return null;
1178
+ }
1179
+ }
1180
+ function mapStopReason(stopReason) {
1181
+ switch (stopReason) {
1182
+ case "end_turn":
1183
+ return "submitted";
1184
+ case "max_tokens":
1185
+ case "max_turn_requests":
1186
+ return "budget";
1187
+ default:
1188
+ return "no_progress";
1189
+ }
1190
+ }
1191
+ function truncate(s, limit) {
1192
+ return s.length > limit ? `${s.slice(0, limit)}\u2026` : s;
1193
+ }
1194
+
1195
+ // ../@prismalens/engine/dist/runner/acp-run-branch.js
1196
+ async function* runBranch(items, ctx) {
1197
+ const adapter = new AcpAdapter(ctx);
1198
+ try {
1199
+ for await (const item of items) {
1200
+ if (item.kind === "update") {
1201
+ const canonical = adapter.normalize(item.update);
1202
+ if (canonical)
1203
+ yield canonical;
1204
+ } else if (item.kind === "done") {
1205
+ const flushed2 = adapter.flushText();
1206
+ if (flushed2)
1207
+ yield flushed2;
1208
+ yield adapter.branchDone(mapStopReason(item.stopReason));
1209
+ return;
1210
+ } else {
1211
+ const flushed2 = adapter.flushText();
1212
+ if (flushed2)
1213
+ yield flushed2;
1214
+ yield adapter.error(item.message);
1215
+ return;
1216
+ }
1217
+ }
1218
+ const flushed = adapter.flushText();
1219
+ if (flushed)
1220
+ yield flushed;
1221
+ yield adapter.branchDone("submitted");
1222
+ } catch (err) {
1223
+ yield adapter.error(err instanceof Error ? err.message : String(err));
1224
+ }
1225
+ }
1226
+ async function* runDeepAgentsBranch(config, ctx) {
1227
+ yield* runBranch(runAcpBranch(config), ctx);
1228
+ }
1229
+
1230
+ // ../@prismalens/engine/dist/runner/claude-code-runner.js
1231
+ import { mkdtemp, rm } from "node:fs/promises";
1232
+ import { tmpdir as tmpdir2 } from "node:os";
1233
+ import { join as join2 } from "node:path";
1234
+ import { query } from "@anthropic-ai/claude-agent-sdk";
1235
+
1236
+ // ../@prismalens/engine/dist/adapter/claude-code-adapter.js
1237
+ var DEFAULT_PREVIEW_LIMIT2 = 4e3;
1238
+ var ClaudeCodeAdapter = class {
1239
+ ctx;
1240
+ seqCounter = 0;
1241
+ now;
1242
+ previewLimit;
1243
+ /** Task tool_use_id → human subagent label (for depth resolution). */
1244
+ taskLabels = /* @__PURE__ */ new Map();
1245
+ /** tool_use_id → {name,input} so a later tool_result can be named + sourced. */
1246
+ toolMeta = /* @__PURE__ */ new Map();
1247
+ constructor(ctx) {
1248
+ this.ctx = ctx;
1249
+ this.now = ctx.now ?? (() => /* @__PURE__ */ new Date());
1250
+ this.previewLimit = ctx.previewLimit ?? DEFAULT_PREVIEW_LIMIT2;
1251
+ }
1252
+ /** Map one SDK message to zero-or-more canonical events. */
1253
+ normalize(m) {
1254
+ switch (m.type) {
1255
+ case "assistant":
1256
+ return this.assistant(m);
1257
+ case "user":
1258
+ return this.toolResults(m);
1259
+ default:
1260
+ return [];
1261
+ }
1262
+ }
1263
+ /** Map a terminal `result` SDK message to the branch's terminal event. */
1264
+ terminalFromResult(m) {
1265
+ if (m.subtype === "success")
1266
+ return this.branchDone("submitted", m);
1267
+ if (m.subtype === "error_max_turns")
1268
+ return this.branchDone("budget", m);
1269
+ return this.error(m.result ?? `claude code ended: ${m.subtype ?? "unknown"}`);
1270
+ }
1271
+ branchDone(reason, m) {
1272
+ return {
1273
+ kind: "branch_done",
1274
+ ...this.base(null),
1275
+ reason,
1276
+ ...m?.total_cost_usd !== void 0 ? { total_cost_usd: m.total_cost_usd } : {},
1277
+ ...m?.usage !== void 0 ? { usage: m.usage } : {},
1278
+ ...m?.modelUsage !== void 0 ? { modelUsage: m.modelUsage } : {},
1279
+ ...m?.num_turns !== void 0 ? { num_turns: m.num_turns } : {},
1280
+ ...m?.duration_ms !== void 0 ? { duration_ms: m.duration_ms } : {}
1281
+ };
1282
+ }
1283
+ error(message) {
1284
+ return { kind: "error", ...this.base(null), message };
1285
+ }
1286
+ report(report) {
1287
+ return {
1288
+ kind: "report",
1289
+ runId: this.ctx.runId,
1290
+ seq: this.nextSeq(),
1291
+ ts: this.now().toISOString(),
1292
+ report
1293
+ };
1294
+ }
1295
+ // --- internals ---
1296
+ assistant(m) {
1297
+ const content = m.message?.content;
1298
+ const blocks = Array.isArray(content) ? content : [];
1299
+ const text = typeof content === "string" ? content : blocks.filter((b) => b.type === "text").map((b) => b.text ?? "").join("");
1300
+ const toolUses = blocks.filter((b) => b.type === "tool_use");
1301
+ for (const tu of toolUses) {
1302
+ const id = tu.id ?? "";
1303
+ const name = tu.name ?? "tool";
1304
+ if (id)
1305
+ this.toolMeta.set(id, { name, input: tu.input });
1306
+ if (id && name === "Task")
1307
+ this.taskLabels.set(id, pickTaskLabel(tu.input));
1308
+ }
1309
+ if (!text && toolUses.length === 0)
1310
+ return [];
1311
+ return [
1312
+ {
1313
+ kind: "agent_step",
1314
+ ...this.base(m.parent_tool_use_id ?? null),
1315
+ text,
1316
+ toolCalls: toolUses.map((tu) => ({
1317
+ toolCallId: tu.id ?? "",
1318
+ name: tu.name ?? "tool",
1319
+ args: asRecord(tu.input)
1320
+ }))
1321
+ }
1322
+ ];
1323
+ }
1324
+ toolResults(m) {
1325
+ const content = m.message?.content;
1326
+ if (!Array.isArray(content))
1327
+ return [];
1328
+ const out = [];
1329
+ for (const b of content) {
1330
+ if (b.type !== "tool_result")
1331
+ continue;
1332
+ const id = b.tool_use_id ?? "";
1333
+ const meta = this.toolMeta.get(id);
1334
+ const name = meta?.name ?? "tool";
1335
+ const ok = b.is_error !== true;
1336
+ const preview = truncate2(flattenContent(b.content), this.previewLimit);
1337
+ out.push({
1338
+ kind: "tool_result",
1339
+ ...this.base(m.parent_tool_use_id ?? null),
1340
+ result: {
1341
+ name,
1342
+ toolCategory: mapToolCategory2(name),
1343
+ toolCallId: id,
1344
+ source: deriveSource(name, meta?.input),
1345
+ ok,
1346
+ error: ok ? null : preview || "tool failed",
1347
+ preview
1348
+ }
1349
+ });
1350
+ }
1351
+ return out;
1352
+ }
1353
+ /** Resolve depth from the spawning Task tool-call (deep, unlike flat ACP). */
1354
+ base(parentToolUseId) {
1355
+ const label = parentToolUseId ? this.taskLabels.get(parentToolUseId) ?? parentToolUseId : null;
1356
+ return {
1357
+ runId: this.ctx.runId,
1358
+ branchId: this.ctx.branchId,
1359
+ path: label ? [label] : [],
1360
+ seq: this.nextSeq(),
1361
+ label,
1362
+ ts: this.now().toISOString()
1363
+ };
1364
+ }
1365
+ nextSeq() {
1366
+ return this.seqCounter++;
1367
+ }
1368
+ };
1369
+ function pickTaskLabel(input) {
1370
+ if (input && typeof input === "object") {
1371
+ const o = input;
1372
+ if (typeof o.subagent_type === "string" && o.subagent_type)
1373
+ return o.subagent_type;
1374
+ if (typeof o.description === "string" && o.description)
1375
+ return o.description.slice(0, 40);
1376
+ }
1377
+ return "task";
1378
+ }
1379
+ function asRecord(input) {
1380
+ if (input && typeof input === "object" && !Array.isArray(input)) {
1381
+ return input;
1382
+ }
1383
+ return input === void 0 || input === null ? {} : { value: input };
1384
+ }
1385
+ function flattenContent(content) {
1386
+ if (content === void 0 || content === null)
1387
+ return "";
1388
+ if (typeof content === "string")
1389
+ return content;
1390
+ if (Array.isArray(content))
1391
+ return content.map(flattenBlock).join("");
1392
+ return flattenBlock(content);
1393
+ }
1394
+ function flattenBlock(block) {
1395
+ if (typeof block === "string")
1396
+ return block;
1397
+ if (block && typeof block === "object") {
1398
+ const t = block.text;
1399
+ if (typeof t === "string")
1400
+ return t;
1401
+ }
1402
+ return "";
1403
+ }
1404
+ function mapToolCategory2(name) {
1405
+ const n = name.toLowerCase();
1406
+ if (n === "read" || n === "write" || n === "edit" || n === "multiedit")
1407
+ return "file";
1408
+ if (n === "grep" || n === "glob")
1409
+ return "search";
1410
+ return null;
1411
+ }
1412
+ function truncate2(s, cap) {
1413
+ return s.length > cap ? `${s.slice(0, cap)}\u2026` : s;
1414
+ }
1415
+
1416
+ // ../@prismalens/engine/dist/runner/claude-code-sandbox-spawn.js
1417
+ import { EventEmitter as EventEmitter2 } from "node:events";
1418
+ function sandboxSpawnClaudeCodeProcess(sandbox, opts = {}) {
1419
+ return (options) => {
1420
+ const child = sandbox.spawn(options.command, options.args, {
1421
+ cwd: options.cwd ?? opts.cwd ?? process.cwd(),
1422
+ env: opts.env ? { ...options.env, ...opts.env } : options.env,
1423
+ ...opts.limits ? { limits: opts.limits } : {}
1424
+ });
1425
+ const emitter = new EventEmitter2();
1426
+ let exitCode = null;
1427
+ let exited = false;
1428
+ child.on("close", (code, signal) => {
1429
+ exitCode = code;
1430
+ exited = true;
1431
+ emitter.emit("exit", code, signal);
1432
+ });
1433
+ child.on("error", (err) => emitter.emit("error", err));
1434
+ const onAbort = () => {
1435
+ if (!exited && !child.killed)
1436
+ child.kill("SIGKILL");
1437
+ };
1438
+ if (options.signal.aborted)
1439
+ onAbort();
1440
+ else
1441
+ options.signal.addEventListener("abort", onAbort, { once: true });
1442
+ return {
1443
+ stdin: child.stdin,
1444
+ stdout: child.stdout,
1445
+ get killed() {
1446
+ return child.killed;
1447
+ },
1448
+ get exitCode() {
1449
+ return exitCode;
1450
+ },
1451
+ kill(signal) {
1452
+ return child.kill(signal);
1453
+ },
1454
+ on(event, listener) {
1455
+ emitter.on(event, listener);
1456
+ },
1457
+ once(event, listener) {
1458
+ emitter.once(event, listener);
1459
+ },
1460
+ off(event, listener) {
1461
+ emitter.off(event, listener);
1462
+ }
1463
+ };
1464
+ };
1465
+ }
1466
+
1467
+ // ../@prismalens/engine/dist/runner/claude-code-runner.js
1468
+ var READ_ONLY_DENY = [
1469
+ ...HARNESS_REGISTRY["claude-code"].readOnlyDeny ?? []
1470
+ ];
1471
+ async function* runClaudeCodeBranch(config, ctx) {
1472
+ const adapter = new ClaudeCodeAdapter(ctx);
1473
+ let sawTerminal = false;
1474
+ const mode = config.permissionMode ?? "read-only";
1475
+ const readOnlyFloor = mode === "read-only" || mode === "supervised";
1476
+ const permissionMode = mode === "auto" ? "acceptEdits" : "bypassPermissions";
1477
+ const disallowedTools = readOnlyFloor ? config.disallowedTools ?? READ_ONLY_DENY : config.disallowedTools;
1478
+ const sandbox = config.sandbox ?? createProcessFloorSandbox();
1479
+ const ownsSandbox = config.sandbox === void 0;
1480
+ let configDir;
1481
+ try {
1482
+ if (config.isolateSettings) {
1483
+ configDir = await mkdtemp(join2(tmpdir2(), "claude-config-"));
1484
+ }
1485
+ const response = query({
1486
+ prompt: config.prompt,
1487
+ options: {
1488
+ // NATIVE PASSTHROUGH first, so our posture keys below win on overlap.
1489
+ ...config.native ?? {},
1490
+ cwd: config.cwd,
1491
+ ...config.model ? { model: config.model } : {},
1492
+ // Behave as the real Claude Code harness (its tools + subagents).
1493
+ systemPrompt: { type: "preset", preset: "claude_code" },
1494
+ ...config.maxTurns ? { maxTurns: config.maxTurns } : {},
1495
+ ...config.abortController ? { abortController: config.abortController } : {},
1496
+ // prismalens posture-derived keys LAST — the read-only floor wins.
1497
+ settingSources: config.isolateSettings ? [] : ["user", "project", "local"],
1498
+ permissionMode,
1499
+ ...disallowedTools ? { disallowedTools } : {},
1500
+ spawnClaudeCodeProcess: sandboxSpawnClaudeCodeProcess(sandbox, {
1501
+ cwd: config.cwd,
1502
+ ...config.limits ? { limits: config.limits } : {},
1503
+ ...configDir ? { env: { CLAUDE_CONFIG_DIR: configDir } } : {}
1504
+ })
1505
+ }
1506
+ });
1507
+ for await (const message of response) {
1508
+ const m = message;
1509
+ for (const ev of adapter.normalize(m))
1510
+ yield ev;
1511
+ if (m.type === "result") {
1512
+ sawTerminal = true;
1513
+ yield adapter.terminalFromResult(m);
1514
+ }
1515
+ }
1516
+ if (!sawTerminal)
1517
+ yield adapter.branchDone("submitted");
1518
+ } catch (err) {
1519
+ yield adapter.error(err instanceof Error ? err.message : String(err));
1520
+ } finally {
1521
+ if (ownsSandbox)
1522
+ await sandbox.destroy();
1523
+ if (configDir) {
1524
+ await rm(configDir, { recursive: true, force: true });
1525
+ }
1526
+ }
1527
+ }
1528
+
1529
+ // ../@prismalens/engine/dist/supervisor/decompose.js
1530
+ var DEFAULT_MAX_BRANCHES = 3;
1531
+ function decompose(context, opts = {}) {
1532
+ if (context.alerts.length <= 1) {
1533
+ return [{ branchId: "root", prompt: buildInvestigationPrompt(context) }];
1534
+ }
1535
+ const cap = Math.max(1, opts.maxBranches ?? DEFAULT_MAX_BRANCHES);
1536
+ return context.alerts.slice(0, cap).map((focus, i) => ({
1537
+ branchId: `b${i}`,
1538
+ prompt: buildInvestigationPrompt(context, focus)
1539
+ }));
1540
+ }
1541
+ function buildInvestigationPrompt(context, focus) {
1542
+ const primary = focus ?? context.alerts[0];
1543
+ const rest = focus ? context.alerts.filter((a) => a !== focus) : context.alerts.slice(1);
1544
+ const t = context.telemetry;
1545
+ const labels = JSON.stringify(primary.labels);
1546
+ const annotations = JSON.stringify(primary.annotations);
1547
+ const s = context.service;
1548
+ const serviceBlock = s ? `
1549
+
1550
+ AFFECTED SERVICE
1551
+ name: ${s.name}${s.tier ? ` \xB7 tier: ${s.tier}` : ""}${s.repo ? ` \xB7 repo: ${s.repo}` : ""}${s.dependsOn?.length ? `
1552
+ depends on: ${s.dependsOn.join(", ")}` : ""}` : "";
1553
+ const relatedBlock = rest.length ? `
1554
+
1555
+ RELATED FIRING ALERTS (same incident \u2014 correlate, don't investigate in isolation)
1556
+ ${rest.map((a) => ` - ${a.alertname} (severity=${a.severity ?? "unknown"})`).join("\n")}` : "";
1557
+ const logsSurface = context.logs?.url ? `
1558
+ - Logs (${context.logs.kind ?? "log system"}) ${context.logs.url} query recent logs for the affected service` : "";
1559
+ return `You are an on-call Site Reliability Engineer running a LIVE investigation of a firing production alert. Your job is to find the ROOT CAUSE \u2014 the specific code path, configuration, dependency, or resource that produced this alert \u2014 not merely the symptom.
1560
+
1561
+ FIRING ALERT
1562
+ name: ${primary.alertname}
1563
+ severity: ${primary.severity ?? "unknown"}
1564
+ labels: ${labels}
1565
+ annotations: ${annotations}${serviceBlock}${relatedBlock}
1566
+
1567
+ READ-ONLY SURFACES (never modify, deploy, restart, or write anything)
1568
+ - Prometheus ${t.prometheusUrl}
1569
+ curl -s '${t.prometheusUrl}/api/v1/query' --data-urlencode 'query=<promql>' \xB7 /api/v1/rules \xB7 /api/v1/label/__name__/values
1570
+ - Alertmanager ${t.alertmanagerUrl} curl -s '${t.alertmanagerUrl}/api/v2/alerts'
1571
+ - Application API ${t.apiUrl}${logsSurface}
1572
+ - Application SOURCE CODE is in your current working directory \u2014 ls / cat / grep / head.
1573
+
1574
+ METHOD (work iteratively \u2014 think \u2192 run a command \u2192 observe \u2192 decide)
1575
+ 0. Shell tool calls take the full command as ONE string in the tool's \`command\` field \u2014 never an argv array
1576
+ (a malformed tool call can abort the whole investigation).
1577
+ 1. File reads, greps, and globs stay INSIDE your current working directory \u2014 use relative paths only. Never search
1578
+ from the filesystem root or pass absolute paths outside the repo (a permission error aborts the whole investigation).
1579
+ 2. Confirm the alert's signal in Prometheus: which metric/expression fired and how far past threshold.
1580
+ 3. After EACH command, say in one line what you learned and what you will check next; let the evidence pick the next probe.
1581
+ 4. Localize, then go to the code. Identify WHICH operation/endpoint/component the signal is about \u2014 e.g. for a latency
1582
+ alert, find the SLOWEST endpoint or operation \u2014 then READ that code path's handler and the configuration it depends on.
1583
+ 5. Never run the same command with the same arguments twice. If your last couple of probes produced nothing new, stop and write the diagnosis.
1584
+
1585
+ WHAT COUNTS AS A ROOT CAUSE (important)
1586
+ Restating the symptom is NOT a root cause. "The service is slow / unresponsive / latency is high" is the alert restated,
1587
+ not its cause. A surface symptom (e.g. requests timing out) is almost always a downstream EFFECT \u2014 keep digging until you
1588
+ can name the concrete code, configuration, dependency, or resource responsible and explain the mechanism that links it to
1589
+ the alert.
1590
+
1591
+ OUTPUT
1592
+ State the single most likely root cause and the mechanism. List the evidence as VALIDATED (a command/metric/file directly
1593
+ showed it \u2014 quote the exact command) versus INFERRED (reasoned, not directly observed). Recommend a fix. Be specific and
1594
+ concise; never assert without evidence.`;
1595
+ }
1596
+
1597
+ // ../@prismalens/engine/dist/supervisor/fan-out.js
1598
+ var MAX_BRANCH_RESPAWNS = 1;
1599
+ function branchErrorEvent(runId, branchId, seq, message) {
1600
+ return {
1601
+ kind: "error",
1602
+ runId,
1603
+ branchId,
1604
+ path: [],
1605
+ seq,
1606
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
1607
+ message
1608
+ };
1609
+ }
1610
+ async function* runBranch2(branch, harness, runId) {
1611
+ let seq = 0;
1612
+ let sawEvent = false;
1613
+ for (let attempt = 0; ; attempt++) {
1614
+ const base = seq;
1615
+ try {
1616
+ for await (const ev of harness(branch.prompt, {
1617
+ runId,
1618
+ branchId: branch.branchId
1619
+ })) {
1620
+ sawEvent = true;
1621
+ const stamped = base > 0 ? { ...ev, seq: ev.seq + base } : ev;
1622
+ seq = stamped.seq + 1;
1623
+ yield stamped;
1624
+ }
1625
+ return;
1626
+ } catch (err) {
1627
+ if (!sawEvent)
1628
+ throw err;
1629
+ const message = String(err?.message ?? err);
1630
+ if (attempt < MAX_BRANCH_RESPAWNS) {
1631
+ yield branchErrorEvent(runId, branch.branchId, seq++, `harness aborted mid-run \u2014 respawning branch once (attempt ${attempt + 2}/${MAX_BRANCH_RESPAWNS + 1}): ${message}`);
1632
+ continue;
1633
+ }
1634
+ yield branchErrorEvent(runId, branch.branchId, seq, message);
1635
+ return;
1636
+ }
1637
+ }
1638
+ }
1639
+ async function* fanOut(branches, harness, runId, opts = {}) {
1640
+ if (branches.length === 0)
1641
+ return;
1642
+ if (branches.length === 1) {
1643
+ yield* runBranch2(branches[0], harness, runId);
1644
+ return;
1645
+ }
1646
+ yield* interleave(branches, harness, runId, opts.concurrency ?? branches.length);
1647
+ }
1648
+ async function* interleave(branches, harness, runId, concurrency) {
1649
+ const buffer = [];
1650
+ let wake = null;
1651
+ let finished = false;
1652
+ let cancelled = false;
1653
+ const notify = () => {
1654
+ if (wake) {
1655
+ wake();
1656
+ wake = null;
1657
+ }
1658
+ };
1659
+ const pump = async (branch) => {
1660
+ let seq = 0;
1661
+ const it = runBranch2(branch, harness, runId)[Symbol.asyncIterator]();
1662
+ try {
1663
+ while (true) {
1664
+ if (cancelled) {
1665
+ await it.return?.(void 0);
1666
+ break;
1667
+ }
1668
+ const { value: ev, done } = await it.next();
1669
+ if (done)
1670
+ break;
1671
+ seq = ev.seq + 1;
1672
+ buffer.push(ev);
1673
+ notify();
1674
+ }
1675
+ } catch (err) {
1676
+ buffer.push(branchErrorEvent(runId, branch.branchId, seq, String(err?.message ?? err)));
1677
+ notify();
1678
+ }
1679
+ };
1680
+ let cursor = 0;
1681
+ const lane = async () => {
1682
+ while (cursor < branches.length) {
1683
+ await pump(branches[cursor++]);
1684
+ }
1685
+ };
1686
+ const cap = Math.max(1, Math.min(concurrency, branches.length));
1687
+ const lanes = Promise.all(Array.from({ length: cap }, lane)).then(() => {
1688
+ finished = true;
1689
+ notify();
1690
+ });
1691
+ try {
1692
+ while (true) {
1693
+ while (buffer.length > 0) {
1694
+ yield buffer.shift();
1695
+ }
1696
+ if (finished)
1697
+ break;
1698
+ await new Promise((resolve) => {
1699
+ wake = resolve;
1700
+ });
1701
+ }
1702
+ } finally {
1703
+ cancelled = true;
1704
+ cursor = branches.length;
1705
+ await lanes;
1706
+ }
1707
+ }
1708
+
1709
+ // ../@prismalens/config/dist/providers/agents.js
1710
+ import { z } from "zod";
1711
+ var INVESTIGATION_AGENTS = {
1712
+ scout: {
1713
+ id: "scout",
1714
+ name: "Scout",
1715
+ description: "Initial alert validation and triage",
1716
+ role: "entry"
1717
+ },
1718
+ gatherer: {
1719
+ id: "gatherer",
1720
+ name: "Gatherer",
1721
+ description: "Deep data collection from integrations",
1722
+ role: "worker"
1723
+ },
1724
+ analyst: {
1725
+ id: "analyst",
1726
+ name: "Analyst",
1727
+ description: "Root cause analysis and hypothesis generation",
1728
+ role: "worker"
1729
+ },
1730
+ resolver: {
1731
+ id: "resolver",
1732
+ name: "Resolver",
1733
+ description: "Remediation recommendations and fix suggestions",
1734
+ role: "worker"
1735
+ },
1736
+ supervisor: {
1737
+ id: "supervisor",
1738
+ name: "Supervisor",
1739
+ description: "Orchestrates agent workflow and routing",
1740
+ role: "orchestrator"
1741
+ }
1742
+ };
1743
+ var AGENT_IDS = Object.keys(INVESTIGATION_AGENTS);
1744
+ var agentIdSchema = z.enum(AGENT_IDS);
1745
+ var ROUTABLE_AGENT_IDS = Object.entries(INVESTIGATION_AGENTS).filter(([, a]) => a.role === "worker").map(([id]) => id);
1746
+
1747
+ // ../@prismalens/contracts/dist/schemas/common.js
1748
+ import { z as z2 } from "zod";
1749
+ var GlobalRoleSchema = z2.enum(["owner", "admin", "member"]);
1750
+ var ServiceTypeSchema = z2.enum([
1751
+ "service",
1752
+ "database",
1753
+ "queue",
1754
+ "cache",
1755
+ "gateway",
1756
+ "external",
1757
+ "infrastructure"
1758
+ ]);
1759
+ var ServiceTierSchema = z2.enum([
1760
+ "tier_1",
1761
+ "tier_2",
1762
+ "tier_3",
1763
+ "tier_4"
1764
+ ]);
1765
+ var DependencyTypeSchema = z2.enum(["runtime", "build", "data"]);
1766
+ var DependencyCriticalitySchema = z2.enum([
1767
+ "required",
1768
+ "optional",
1769
+ "degraded"
1770
+ ]);
1771
+ var SeveritySchema = z2.enum([
1772
+ "critical",
1773
+ "high",
1774
+ "medium",
1775
+ "low",
1776
+ "info"
1777
+ ]);
1778
+ var AlertStatusSchema = z2.enum([
1779
+ "triggered",
1780
+ "acknowledged",
1781
+ "correlated",
1782
+ "resolved",
1783
+ "suppressed"
1784
+ ]);
1785
+ var IncidentStatusSchema = z2.enum([
1786
+ "triggered",
1787
+ "investigating",
1788
+ "identified",
1789
+ "monitoring",
1790
+ "resolved",
1791
+ "closed"
1792
+ ]);
1793
+ var PrioritySchema = z2.enum(["p1", "p2", "p3", "p4", "p5"]);
1794
+ var WorkflowStatusSchema = z2.enum([
1795
+ "pending",
1796
+ "running",
1797
+ "completed",
1798
+ "failed",
1799
+ "cancelled"
1800
+ ]);
1801
+ var RootCauseCategorySchema = z2.enum([
1802
+ "code",
1803
+ "config",
1804
+ "infrastructure",
1805
+ "external",
1806
+ "unknown"
1807
+ ]);
1808
+ var AgentNameSchema = z2.enum(AGENT_IDS);
1809
+ var AgentTypeSchema = z2.enum(["llm", "sequential", "loop"]);
1810
+ var ExecutionStatusSchema = z2.enum([
1811
+ "pending",
1812
+ "running",
1813
+ "completed",
1814
+ "failed"
1815
+ ]);
1816
+ var ToolExecutionStatusSchema = z2.enum([
1817
+ "pending",
1818
+ "running",
1819
+ "success",
1820
+ "error"
1821
+ ]);
1822
+ var ToolCategorySchema = z2.enum([
1823
+ "file",
1824
+ "search",
1825
+ "github",
1826
+ "logs",
1827
+ "analysis"
1828
+ ]);
1829
+ var HypothesisStatusSchema = z2.enum([
1830
+ "confirmed",
1831
+ // direct evidence
1832
+ "supported",
1833
+ // consistent with evidence
1834
+ "speculative",
1835
+ // no evidence yet
1836
+ "refuted"
1837
+ ]);
1838
+ var EvidenceStatusSchema = z2.enum([
1839
+ "verified",
1840
+ // a tool directly showed it
1841
+ "inferred"
1842
+ // reasoned, not directly observed
1843
+ ]);
1844
+ var EvidenceDirectionSchema = z2.enum(["supports", "contradicts"]);
1845
+ var RecommendationPrioritySchema = z2.enum([
1846
+ "critical",
1847
+ "high",
1848
+ "medium",
1849
+ "low"
1850
+ ]);
1851
+ var RecommendationCategorySchema = z2.enum([
1852
+ "code_fix",
1853
+ "config_change",
1854
+ "rollback",
1855
+ "monitoring",
1856
+ "investigation"
1857
+ ]);
1858
+ var UrgencySchema = z2.enum(["immediate", "short_term", "long_term"]);
1859
+ var EffortEstimateSchema = z2.enum(["minutes", "hours", "days"]);
1860
+ var RecommendationStatusSchema = z2.enum([
1861
+ "pending",
1862
+ "in_progress",
1863
+ "completed",
1864
+ "rejected",
1865
+ "deferred"
1866
+ ]);
1867
+ var TimelineEntryTypeSchema = z2.enum([
1868
+ "incident_created",
1869
+ "alert_added",
1870
+ "alert_removed",
1871
+ "status_changed",
1872
+ "severity_changed",
1873
+ "assigned",
1874
+ "investigation_started",
1875
+ "investigation_completed",
1876
+ "recommendation_added",
1877
+ "recommendation_completed",
1878
+ "comment",
1879
+ "postmortem_created",
1880
+ "custom"
1881
+ ]);
1882
+ var TimelineSourceSchema = z2.enum(["system", "user", "ai_worker"]);
1883
+ var PostmortemStatusSchema = z2.enum([
1884
+ "draft",
1885
+ "in_review",
1886
+ "published",
1887
+ "archived"
1888
+ ]);
1889
+ var CorrelationActionSchema = z2.enum([
1890
+ "correlate",
1891
+ "suppress",
1892
+ "create_incident"
1893
+ ]);
1894
+ var SettingTypeSchema = z2.enum([
1895
+ "string",
1896
+ "number",
1897
+ "boolean",
1898
+ "json",
1899
+ "encrypted"
1900
+ ]);
1901
+ var SettingCategorySchema = z2.enum([
1902
+ "general",
1903
+ "correlation",
1904
+ "ai",
1905
+ "notifications",
1906
+ "setup"
1907
+ ]);
1908
+ var ConnectionStatusSchema = z2.enum([
1909
+ "ACTIVE",
1910
+ "TOKEN_EXPIRED",
1911
+ "REFRESH_FAILED",
1912
+ "CREDENTIALS_INVALID",
1913
+ "REVOKED",
1914
+ "ERROR"
1915
+ ]);
1916
+ var SuggestionStatusSchema = z2.enum([
1917
+ "pending",
1918
+ "accepted",
1919
+ "rejected",
1920
+ "ignored"
1921
+ ]);
1922
+ var ChangeEventTypeSchema = z2.enum([
1923
+ "deployment",
1924
+ "config",
1925
+ "migration",
1926
+ "commit",
1927
+ "rollback"
1928
+ ]);
1929
+ var LicenseTypeSchema = z2.enum(["none", "subscription"]);
1930
+ var LicenseTierSchema = z2.enum(["community", "enterprise"]);
1931
+ var PaginationSchema = z2.object({
1932
+ limit: z2.coerce.number().int().min(1).max(100).default(50),
1933
+ offset: z2.coerce.number().int().min(0).default(0)
1934
+ });
1935
+ var IdParamSchema = z2.object({
1936
+ id: z2.string().uuid()
1937
+ });
1938
+ var DateStringSchema = z2.string().datetime();
1939
+ var CoerceDateSchema = z2.coerce.date();
1940
+ var SuccessResponseSchema = z2.object({
1941
+ success: z2.boolean()
1942
+ });
1943
+ var MessageResponseSchema = z2.object({
1944
+ message: z2.string()
1945
+ });
1946
+
1947
+ // ../@prismalens/contracts/dist/schemas/investigation.js
1948
+ import { z as z4 } from "zod";
1949
+
1950
+ // ../@prismalens/contracts/dist/schemas/overlay.js
1951
+ import { z as z3 } from "zod";
1952
+ var MatchedChangeSchema = z3.object({
1953
+ /** Which timeline table this row came from. */
1954
+ kind: z3.enum(["deployment", "change_event"]),
1955
+ /** Row id (Deployment.id or ChangeEvent.id). */
1956
+ id: z3.string(),
1957
+ /** Human label — deployment name or change description. */
1958
+ title: z3.string(),
1959
+ /** Origin — the change source (e.g. "render", "github") or "deployment". */
1960
+ source: z3.string(),
1961
+ /** Affected service name for this row, when known. */
1962
+ serviceName: z3.string().nullable(),
1963
+ /** When the change/deploy happened (ISO). */
1964
+ timestamp: z3.string(),
1965
+ /** Index into the report's ordered `hypotheses` this row matched. */
1966
+ hypothesisIndex: z3.number().int().min(0),
1967
+ /** The literal token (service name or identifier) that produced the match. */
1968
+ matchedOn: z3.string()
1969
+ });
1970
+ var ServiceProximitySchema = z3.object({
1971
+ serviceName: z3.string(),
1972
+ proximity: z3.union([z3.literal(0), z3.literal(1), z3.literal(2)]),
1973
+ relation: z3.enum(["self", "dependency", "dependent", "beyond"]),
1974
+ /** Indices into the report's ordered `hypotheses` that name this service. */
1975
+ hypothesisIndexes: z3.array(z3.number().int().min(0))
1976
+ });
1977
+ var SimilarIncidentSchema = z3.object({
1978
+ incidentId: z3.string(),
1979
+ incidentNumber: z3.number().int(),
1980
+ title: z3.string(),
1981
+ /** Normalised 0..1 similarity. */
1982
+ score: z3.number().min(0).max(1),
1983
+ factors: z3.object({
1984
+ jaccard: z3.number().min(0).max(1),
1985
+ sameService: z3.boolean(),
1986
+ sharedCategory: z3.boolean()
1987
+ })
1988
+ });
1989
+ var OverlaySchema = z3.object({
1990
+ matchedChanges: z3.array(MatchedChangeSchema),
1991
+ serviceProximity: z3.array(ServiceProximitySchema),
1992
+ similarIncidents: z3.array(SimilarIncidentSchema),
1993
+ /** When the overlay was computed (ISO). */
1994
+ computedAt: z3.string()
1995
+ });
1996
+
1997
+ // ../@prismalens/contracts/dist/schemas/investigation.js
1998
+ var EvidenceSchema = z4.object({
1999
+ /** What was observed. */
2000
+ observation: z4.string().min(1),
2001
+ /** Where it came from — the exact command or origin that produced it. */
2002
+ source: z4.string().min(1),
2003
+ direction: EvidenceDirectionSchema,
2004
+ status: EvidenceStatusSchema,
2005
+ /**
2006
+ * Links a finding to the live tool call that produced it
2007
+ * (StreamToolResult.toolCallId), so the report view can drill into the
2008
+ * originating output (ADR-0007). Null for `inferred` evidence with no single
2009
+ * originating call.
2010
+ */
2011
+ toolCallId: z4.string().nullable().optional()
2012
+ });
2013
+ var HypothesisSchema = z4.object({
2014
+ // Ordering is by ARRAY POSITION (most → least plausible) — the single source of
2015
+ // truth, per ADR-0002's "ordered list". No numeric rank/confidence.
2016
+ statement: z4.string().min(1),
2017
+ status: HypothesisStatusSchema,
2018
+ evidence: z4.array(EvidenceSchema)
2019
+ });
2020
+ var RuledOutSchema = z4.object({
2021
+ // A candidate cause never promoted to a ranked hypothesis. (A hypothesis that WAS
2022
+ // considered then disproved stays in `hypotheses` with status "refuted".)
2023
+ statement: z4.string().min(1),
2024
+ why: z4.string().min(1),
2025
+ /** The contradicting evidence that ruled it out (direction "contradicts"). */
2026
+ evidence: z4.array(EvidenceSchema)
2027
+ });
2028
+ var CoverageSchema = z4.object({
2029
+ queried: z4.array(z4.string()),
2030
+ notQueried: z4.array(z4.string())
2031
+ });
2032
+ var NextStepSchema = z4.object({
2033
+ title: z4.string().min(1),
2034
+ detail: z4.string().min(1),
2035
+ priority: RecommendationPrioritySchema.nullable().optional()
2036
+ });
2037
+ var RunFidelitySandboxSchema = z4.object({
2038
+ requested: z4.string(),
2039
+ actual: z4.string(),
2040
+ fidelity: z4.enum(["enforced", "cooperative"])
2041
+ });
2042
+ var RunFidelitySchema = z4.object({
2043
+ harness: z4.string(),
2044
+ mode: z4.string(),
2045
+ fidelity: z4.enum(["enforced", "cooperative", "advisory"]),
2046
+ mechanism: z4.string(),
2047
+ /**
2048
+ * The Sandbox boundary (ADR-0020) the harness was spawned into, when one was
2049
+ * wired. Additive/optional — omitted when no sandbox applies (e.g. the
2050
+ * in-process Agent SDK harness, or no boundary requested at all).
2051
+ */
2052
+ sandbox: RunFidelitySandboxSchema.optional()
2053
+ });
2054
+ var InvestigationReportSchema = z4.object({
2055
+ summary: z4.string().min(1),
2056
+ rootCause: z4.string().nullable(),
2057
+ rootCauseCategory: RootCauseCategorySchema.nullable(),
2058
+ /** Ordered most → least plausible (array order is the ordering). */
2059
+ hypotheses: z4.array(HypothesisSchema),
2060
+ ruledOut: z4.array(RuledOutSchema),
2061
+ coverage: CoverageSchema,
2062
+ nextSteps: z4.array(NextStepSchema),
2063
+ /**
2064
+ * Run-metadata, ADR-0017 honest fidelity — the enforcement the harness
2065
+ * actually applied. Attached deterministically after synthesis; never
2066
+ * LLM-generated.
2067
+ */
2068
+ fidelity: RunFidelitySchema.nullable().optional()
2069
+ });
2070
+ var ToolExecutionSchema = z4.object({
2071
+ id: z4.string().uuid(),
2072
+ agentExecutionId: z4.string().uuid(),
2073
+ toolName: z4.string(),
2074
+ toolCategory: ToolCategorySchema.nullable(),
2075
+ arguments: z4.record(z4.unknown()).nullable(),
2076
+ result: z4.record(z4.unknown()).nullable(),
2077
+ status: ToolExecutionStatusSchema,
2078
+ executionTimeMs: z4.number().int().nullable(),
2079
+ dataQuality: z4.string().nullable(),
2080
+ error: z4.string().nullable(),
2081
+ executedAt: DateStringSchema
2082
+ });
2083
+ var AgentExecutionSchema = z4.object({
2084
+ id: z4.string().uuid(),
2085
+ investigationId: z4.string().uuid(),
2086
+ agentName: AgentNameSchema,
2087
+ agentType: AgentTypeSchema,
2088
+ status: ExecutionStatusSchema,
2089
+ startedAt: DateStringSchema.nullable(),
2090
+ completedAt: DateStringSchema.nullable(),
2091
+ executionTimeMs: z4.number().int().nullable(),
2092
+ output: z4.record(z4.unknown()).nullable(),
2093
+ inputTokens: z4.number().int().nullable(),
2094
+ outputTokens: z4.number().int().nullable(),
2095
+ error: z4.string().nullable(),
2096
+ createdAt: DateStringSchema
2097
+ });
2098
+ var AgentExecutionWithToolsSchema = AgentExecutionSchema.extend({
2099
+ toolExecutions: z4.array(ToolExecutionSchema).optional()
2100
+ });
2101
+ var InvestigationSchema = z4.object({
2102
+ id: z4.string().uuid(),
2103
+ incidentId: z4.string().uuid(),
2104
+ status: WorkflowStatusSchema,
2105
+ startedAt: DateStringSchema.nullable(),
2106
+ completedAt: DateStringSchema.nullable(),
2107
+ summary: z4.string().nullable(),
2108
+ rootCause: z4.string().nullable(),
2109
+ rootCauseCategory: RootCauseCategorySchema.nullable(),
2110
+ /** The full ordered-evidence report (ADR-0002); supersedes the old confidence/dataQuality/rawOutput columns. */
2111
+ report: InvestigationReportSchema.nullable().optional(),
2112
+ /**
2113
+ * App-side reduce overlay (ADR-0016 §5c) — post-report enrichment computed
2114
+ * BESIDE the canonical report (related changes, service-graph proximity, similar
2115
+ * incidents). Absent until computed; the engine never sees it (ADR-0011).
2116
+ */
2117
+ overlay: OverlaySchema.nullable().optional(),
2118
+ error: z4.string().nullable(),
2119
+ createdAt: DateStringSchema,
2120
+ updatedAt: DateStringSchema
2121
+ });
2122
+ var CreateInvestigationSchema = z4.object({
2123
+ incidentId: z4.string().uuid()
2124
+ });
2125
+ var RecommendationRefSchema = z4.object({
2126
+ id: z4.string().uuid(),
2127
+ title: z4.string(),
2128
+ priority: z4.string(),
2129
+ status: z4.string()
2130
+ });
2131
+ var InvestigationWithRelationsSchema = InvestigationSchema.extend({
2132
+ agentExecutions: z4.array(AgentExecutionWithToolsSchema).optional(),
2133
+ recommendations: z4.array(RecommendationRefSchema).optional()
2134
+ });
2135
+ var InvestigationStatusSchema = z4.object({
2136
+ investigation: InvestigationSchema,
2137
+ job: z4.object({
2138
+ id: z4.string(),
2139
+ state: z4.string(),
2140
+ progress: z4.number().min(0).max(100).nullable(),
2141
+ attemptsMade: z4.number().int(),
2142
+ failedReason: z4.string().nullable()
2143
+ }).nullable()
2144
+ });
2145
+ var InvestigationQuerySchema = z4.object({
2146
+ incidentId: z4.string().uuid().optional(),
2147
+ status: WorkflowStatusSchema.optional(),
2148
+ limit: z4.coerce.number().int().min(1).max(100).default(50),
2149
+ offset: z4.coerce.number().int().min(0).default(0)
2150
+ });
2151
+ var UpdateInvestigationStatusSchema = z4.object({
2152
+ id: z4.string().uuid(),
2153
+ status: WorkflowStatusSchema,
2154
+ error: z4.string().optional(),
2155
+ harnessThreadId: z4.string().uuid().optional()
2156
+ });
2157
+ var CreateToolExecutionInputSchema = z4.object({
2158
+ toolName: z4.string(),
2159
+ toolCategory: z4.string().optional(),
2160
+ // Using string directly to be permissive for inputs
2161
+ arguments: z4.record(z4.unknown()).nullable().optional(),
2162
+ result: z4.record(z4.unknown()).nullable().optional(),
2163
+ status: ToolExecutionStatusSchema.optional(),
2164
+ executionTimeMs: z4.number().int().optional(),
2165
+ dataQuality: z4.string().optional(),
2166
+ error: z4.string().optional()
2167
+ });
2168
+ var CreateAgentExecutionInputSchema = z4.object({
2169
+ agentName: z4.string(),
2170
+ agentType: z4.string().optional(),
2171
+ status: ExecutionStatusSchema.optional(),
2172
+ startedAt: z4.string().datetime().optional(),
2173
+ completedAt: z4.string().datetime().optional(),
2174
+ executionTimeMs: z4.number().int().optional(),
2175
+ output: z4.record(z4.unknown()).optional(),
2176
+ inputTokens: z4.number().int().optional(),
2177
+ outputTokens: z4.number().int().optional(),
2178
+ error: z4.string().optional(),
2179
+ toolExecutions: z4.array(CreateToolExecutionInputSchema).optional()
2180
+ });
2181
+ var CreateRecommendationInputSchema = z4.object({
2182
+ title: z4.string(),
2183
+ description: z4.string().optional(),
2184
+ priority: z4.string().optional(),
2185
+ // 'low' | 'medium' | 'high' | 'critical'
2186
+ category: z4.string().optional(),
2187
+ urgency: z4.string().optional(),
2188
+ actionable: z4.boolean().optional(),
2189
+ estimatedEffort: z4.string().optional()
2190
+ });
2191
+ var WriteInvestigationResultSchema = z4.object({
2192
+ id: z4.string().uuid(),
2193
+ status: WorkflowStatusSchema,
2194
+ summary: z4.string().optional(),
2195
+ rootCause: z4.string().optional(),
2196
+ rootCauseCategory: z4.string().optional(),
2197
+ /** The full ordered-evidence report (ADR-0002), persisted as Investigation.report. */
2198
+ report: InvestigationReportSchema.optional(),
2199
+ error: z4.string().optional(),
2200
+ agentExecutions: z4.array(CreateAgentExecutionInputSchema).optional(),
2201
+ recommendations: z4.array(CreateRecommendationInputSchema).optional()
2202
+ });
2203
+ var StreamToolResultSchema = z4.object({
2204
+ /** Tool name — same key as the originating agent_step `toolCalls[].name`. */
2205
+ name: z4.string().min(1),
2206
+ toolCategory: ToolCategorySchema.nullable().optional(),
2207
+ /** Links this result to its call. Derive from ToolMessage.tool_call_id. */
2208
+ toolCallId: z4.string(),
2209
+ /** The command/args that produced it (human-readable provenance). */
2210
+ source: z4.string().min(1),
2211
+ /**
2212
+ * Derive from ToolMessage.status === "error" (NOT from "on_tool_end fired" —
2213
+ * LangGraph ToolNode has handleToolErrors=true and emits a failed tool as a
2214
+ * normal end event with status "error"; MCP tools may return error-as-content).
2215
+ */
2216
+ ok: z4.boolean(),
2217
+ /** Failure message when !ok, for the drill-down. */
2218
+ error: z4.string().nullable().optional(),
2219
+ /** Truncated/sanitised result. */
2220
+ preview: z4.string()
2221
+ });
2222
+ var StreamBaseShape = {
2223
+ runId: z4.string().uuid(),
2224
+ /**
2225
+ * Slice 0: a single constant branch. Fan-out (Slice 1) varies it. The UI's
2226
+ * ordering + idempotent-upsert key is (branchId, seq) — NOT seq alone, since each
2227
+ * branch is a separate harness run with its own counter.
2228
+ */
2229
+ branchId: z4.string().min(1),
2230
+ /**
2231
+ * Structural nesting depth within a branch, from the harness checkpoint ns
2232
+ * (LangGraph node names + task uuids; the `tools:` wrapper collapsed). These are
2233
+ * NOT subagent names — see `label` for the human name. [] = branch top.
2234
+ */
2235
+ path: z4.array(z4.string()),
2236
+ /** Per-branch monotonic sequence (adapter-assigned in arrival order). */
2237
+ seq: z4.number().int(),
2238
+ /**
2239
+ * Human-readable node/subagent label when resolvable (from the spawning `task`
2240
+ * tool-call's subagent_type via run_id parentage); null at the branch top.
2241
+ */
2242
+ label: z4.string().nullable().optional(),
2243
+ /** Wall-clock emit time (adapter-stamped) for step/tool durations in the drill-down. */
2244
+ ts: z4.string().datetime()
2245
+ };
2246
+ var CanonicalEventSchema = z4.discriminatedUnion("kind", [
2247
+ z4.object({
2248
+ kind: z4.literal("agent_step"),
2249
+ ...StreamBaseShape,
2250
+ text: z4.string(),
2251
+ toolCalls: z4.array(z4.object({
2252
+ /** Stable id from AIMessage tool_calls[].id; pairs with a tool_result. */
2253
+ toolCallId: z4.string(),
2254
+ name: z4.string().min(1),
2255
+ /** Post-unwrap args (the deepagents {input:"<json>"} wrapper removed). */
2256
+ args: z4.record(z4.unknown())
2257
+ }))
2258
+ }),
2259
+ z4.object({
2260
+ kind: z4.literal("tool_result"),
2261
+ ...StreamBaseShape,
2262
+ result: StreamToolResultSchema
2263
+ }),
2264
+ z4.object({
2265
+ kind: z4.literal("branch_done"),
2266
+ ...StreamBaseShape,
2267
+ /**
2268
+ * Supervisor classification (not a harness field). The adapter maps a thrown
2269
+ * GraphRecursionError to "budget"; genuine failures emit an `error` event.
2270
+ */
2271
+ reason: z4.enum(["submitted", "budget", "no_progress"]),
2272
+ usage: z4.object({
2273
+ input_tokens: z4.number().int().min(0).optional(),
2274
+ output_tokens: z4.number().int().min(0).optional()
2275
+ }).nullable().optional(),
2276
+ total_cost_usd: z4.number().min(0).optional(),
2277
+ modelUsage: z4.record(z4.unknown()).nullable().optional(),
2278
+ num_turns: z4.number().int().min(0).optional(),
2279
+ duration_ms: z4.number().int().min(0).optional()
2280
+ }),
2281
+ z4.object({
2282
+ kind: z4.literal("error"),
2283
+ ...StreamBaseShape,
2284
+ message: z4.string()
2285
+ }),
2286
+ z4.object({
2287
+ kind: z4.literal("report"),
2288
+ runId: z4.string().uuid(),
2289
+ seq: z4.number().int(),
2290
+ ts: z4.string().datetime(),
2291
+ report: InvestigationReportSchema
2292
+ }),
2293
+ z4.object({
2294
+ kind: z4.literal("llm_call"),
2295
+ runId: z4.string().uuid(),
2296
+ seq: z4.number().int(),
2297
+ ts: z4.string().datetime(),
2298
+ phase: z4.enum(["decompose", "map", "reduce"]),
2299
+ provider: z4.string(),
2300
+ model: z4.string(),
2301
+ usage: z4.object({
2302
+ inputTokens: z4.number().int().min(0).nullable(),
2303
+ outputTokens: z4.number().int().min(0).nullable()
2304
+ }).nullable(),
2305
+ latencyMs: z4.number().int().min(0),
2306
+ outcome: z4.enum(["ok", "error"]),
2307
+ failureCause: z4.string().nullable()
2308
+ })
2309
+ ]);
2310
+ var AppendInvestigationEventsSchema = z4.object({
2311
+ events: z4.array(z4.unknown())
2312
+ });
2313
+ var AppendInvestigationEventsResultSchema = z4.object({
2314
+ accepted: z4.number().int(),
2315
+ dropped: z4.number().int()
2316
+ });
2317
+ var GetInvestigationEventsSchema = z4.object({
2318
+ id: z4.string().uuid(),
2319
+ /** Exclusive `seq` cursor; omit for the first page. */
2320
+ cursor: z4.coerce.number().int().min(0).optional(),
2321
+ limit: z4.coerce.number().int().min(1).max(200).default(100)
2322
+ });
2323
+ var InvestigationEventsPageSchema = z4.object({
2324
+ events: z4.array(CanonicalEventSchema),
2325
+ nextCursor: z4.number().int().nullable()
2326
+ });
2327
+ var FiringAlertSchema = z4.object({
2328
+ alertname: z4.string(),
2329
+ severity: z4.string().nullable(),
2330
+ labels: z4.record(z4.string()),
2331
+ annotations: z4.record(z4.string()),
2332
+ startsAt: z4.string().nullable()
2333
+ });
2334
+ var TelemetryEndpointsSchema = z4.object({
2335
+ prometheusUrl: z4.string(),
2336
+ alertmanagerUrl: z4.string(),
2337
+ apiUrl: z4.string()
2338
+ });
2339
+ var IncidentContextSchema = z4.object({
2340
+ title: z4.string().optional(),
2341
+ description: z4.string().optional(),
2342
+ severity: z4.string().optional(),
2343
+ startedAt: z4.string().optional()
2344
+ });
2345
+ var ServiceContextSchema = z4.object({
2346
+ name: z4.string().min(1),
2347
+ tier: z4.string().optional(),
2348
+ /** owner/name slug or a local path — where the harness reads the code. */
2349
+ repo: z4.string().optional(),
2350
+ /** Direct dependency names (blast-radius seed for a future reduce overlay). */
2351
+ dependsOn: z4.array(z4.string()).optional()
2352
+ });
2353
+ var LogSystemContextSchema = z4.object({
2354
+ kind: z4.string().optional(),
2355
+ url: z4.string().optional()
2356
+ });
2357
+ var PriorInvestigationSchema = z4.object({
2358
+ incidentTitle: z4.string().optional(),
2359
+ summary: z4.string().optional(),
2360
+ rootCause: z4.string().optional()
2361
+ });
2362
+ var InvestigationContextSchema = z4.object({
2363
+ /** ≥1 firing alert. A single-alert run is the degenerate case, not empty. */
2364
+ alerts: z4.array(FiringAlertSchema).min(1),
2365
+ /** Read-only telemetry surfaces (resolved by the host — ADR-0011). */
2366
+ telemetry: TelemetryEndpointsSchema,
2367
+ incident: IncidentContextSchema.optional(),
2368
+ service: ServiceContextSchema.optional(),
2369
+ /** Repo slugs in play (owner/name); the harness cwd is the primary one. */
2370
+ repos: z4.array(z4.string()).optional(),
2371
+ logs: LogSystemContextSchema.optional(),
2372
+ priorInvestigations: z4.array(PriorInvestigationSchema).optional()
2373
+ });
2374
+ function singleAlertContext(alert, telemetry, extras = {}) {
2375
+ return {
2376
+ alerts: [alert],
2377
+ telemetry,
2378
+ ...extras.incident ? { incident: extras.incident } : {},
2379
+ ...extras.service ? { service: extras.service } : {},
2380
+ ...extras.repos ? { repos: extras.repos } : {},
2381
+ ...extras.logs ? { logs: extras.logs } : {},
2382
+ ...extras.priorInvestigations ? { priorInvestigations: extras.priorInvestigations } : {}
2383
+ };
2384
+ }
2385
+
2386
+ // ../@prismalens/engine/dist/supervisor/synthesize.js
2387
+ import { generateObject, generateText as generateText2 } from "ai";
2388
+ var SYSTEM = `You are a senior Site Reliability Engineer writing the FINAL structured root-cause report for an incident investigation.
2389
+
2390
+ Epistemics (strict): order hypotheses MOST \u2192 LEAST plausible by array position. Do NOT use numeric confidence/probability. Each hypothesis carries a discrete status and a list of evidence; each evidence item records what was observed, the exact source (the command/metric/file that produced it), whether it supports or contradicts, and whether it was directly verified or inferred. Ground every claim in the transcript \u2014 do not invent evidence.`;
2391
+ var MERGE_SYSTEM = `You are a senior Site Reliability Engineer consolidating SEVERAL per-branch root-cause reports into ONE report for the SAME incident. Each input report investigated a different firing alert of that incident.
2392
+
2393
+ Merge rules (strict):
2394
+ - DEDUPE across branches: the SAME hypothesis raised by multiple branches becomes ONE hypothesis; UNITE its evidence (keep every distinct item, drop exact duplicates).
2395
+ - RANK by array position (most \u2192 least plausible). Position IS the rank \u2014 do NOT use numeric confidence/probability (ADR-0002 ordered-evidence).
2396
+ - ruledOut is the UNION across branches (dedupe identical entries).
2397
+ - coverage.queried / coverage.notQueried are the UNION across branches.
2398
+ - Ground every claim in the provided per-branch reports \u2014 do NOT invent evidence.`;
2399
+ var PREVIEW_CAP = 1200;
2400
+ var TRANSCRIPT_CAP = 24e3;
2401
+ var RAW_REPORT_NOTICE = "[RAW \u2014 un-synthesized harness output; no Tier-1 provider configured]";
2402
+ var defaultReportModel = (prompt, cfg, phase = "reduce") => runReportModel(cfg, prompt, phase);
2403
+ async function reduce(context, events, cfg, model = defaultReportModel) {
2404
+ const groups = groupEventsByBranch(events);
2405
+ if (groups.length <= 1) {
2406
+ return model(synthesisPrompt(buildTranscript(context, events)), cfg, "reduce");
2407
+ }
2408
+ const nonEmpty = groups.filter((g) => hasToolEvidence(g.events));
2409
+ if (nonEmpty.length === 1) {
2410
+ const only = nonEmpty[0];
2411
+ return model(synthesisPrompt(buildTranscript(context, only.events, branchFocus(context, only.branchId))), cfg, "reduce");
2412
+ }
2413
+ const perBranch = await Promise.all(nonEmpty.map((g) => model(synthesisPrompt(buildTranscript(context, g.events, branchFocus(context, g.branchId))), cfg, "map")));
2414
+ return model(mergePrompt(context, perBranch), cfg, "reduce");
2415
+ }
2416
+ function rawReport(_context, events, synthError) {
2417
+ const groups = groupEventsByBranch(events);
2418
+ const surviving = groups.filter((g) => hasToolEvidence(g.events));
2419
+ let summary = RAW_REPORT_NOTICE;
2420
+ if (synthError !== void 0) {
2421
+ summary += ` Synthesis failed: ${synthError}`;
2422
+ }
2423
+ summary += "\n\n";
2424
+ const conclusions = surviving.map((g) => branchConclusion(g.events)).filter((c) => c !== "");
2425
+ if (conclusions.length > 0) {
2426
+ summary += conclusions.join("\n\n");
2427
+ } else {
2428
+ summary += "No branch conclusions gathered.";
2429
+ }
2430
+ return {
2431
+ summary,
2432
+ rootCause: null,
2433
+ rootCauseCategory: null,
2434
+ hypotheses: [],
2435
+ ruledOut: [],
2436
+ coverage: { queried: uniqueSources(events), notQueried: [] },
2437
+ nextSteps: []
2438
+ };
2439
+ }
2440
+ function branchConclusion(events) {
2441
+ let last = "";
2442
+ for (const e of events) {
2443
+ if (e.kind === "agent_step" && e.text.trim() !== "") {
2444
+ last = e.text.trim();
2445
+ }
2446
+ }
2447
+ return last;
2448
+ }
2449
+ function uniqueSources(events) {
2450
+ const sources = /* @__PURE__ */ new Set();
2451
+ for (const e of events) {
2452
+ if (e.kind === "tool_result") {
2453
+ sources.add(e.result.source);
2454
+ }
2455
+ }
2456
+ return Array.from(sources);
2457
+ }
2458
+ function groupEventsByBranch(events) {
2459
+ const byId = /* @__PURE__ */ new Map();
2460
+ for (const ev of events) {
2461
+ if (!("branchId" in ev))
2462
+ continue;
2463
+ const group = byId.get(ev.branchId);
2464
+ if (group)
2465
+ group.push(ev);
2466
+ else
2467
+ byId.set(ev.branchId, [ev]);
2468
+ }
2469
+ return [...byId.entries()].map(([branchId, evs]) => ({
2470
+ branchId,
2471
+ events: evs
2472
+ }));
2473
+ }
2474
+ function branchFocus(context, branchId) {
2475
+ const m = /^b(\d+)$/.exec(branchId);
2476
+ return m ? context.alerts[Number(m[1])] : void 0;
2477
+ }
2478
+ function hasToolEvidence(events) {
2479
+ return events.some((e) => e.kind === "tool_result");
2480
+ }
2481
+ function synthesisPrompt(transcript) {
2482
+ return `${SYSTEM}
2483
+
2484
+ === INVESTIGATION TRANSCRIPT ===
2485
+ ${transcript}
2486
+ === END TRANSCRIPT ===
2487
+
2488
+ Write the report now.`;
2489
+ }
2490
+ function mergePrompt(context, reports) {
2491
+ const header = context.alerts.map((a) => a.alertname).join(", ");
2492
+ const body = reports.map((r, i) => `--- BRANCH ${i} REPORT ---
2493
+ ${JSON.stringify(r, null, 2)}`).join("\n\n");
2494
+ return `${MERGE_SYSTEM}
2495
+
2496
+ INCIDENT ALERTS: ${header}
2497
+
2498
+ === PER-BRANCH REPORTS ===
2499
+ ${body}
2500
+ === END REPORTS ===
2501
+
2502
+ Write the consolidated report now.`;
2503
+ }
2504
+ var SHAPE_HINT = `{
2505
+ "summary": string,
2506
+ "rootCause": string | null,
2507
+ "rootCauseCategory": "code" | "config" | "infrastructure" | "external" | "unknown" | null,
2508
+ "hypotheses": [ { "statement": string, "status": "confirmed" | "supported" | "speculative" | "refuted", "evidence": [ { "observation": string, "source": string, "direction": "supports" | "contradicts", "status": "verified" | "inferred" } ] } ],
2509
+ "ruledOut": [ { "statement": string, "why": string, "evidence": [ { "observation": string, "source": string, "direction": "supports" | "contradicts", "status": "verified" | "inferred" } ] } ],
2510
+ "coverage": { "queried": string[], "notQueried": string[] },
2511
+ "nextSteps": [ { "title": string, "detail": string, "priority": "critical" | "high" | "medium" | "low" | null } ]
2512
+ }`;
2513
+ async function runReportModel(cfg, prompt, phase = "reduce") {
2514
+ const model = resolveModel(cfg.providerId, cfg.model, {
2515
+ apiKey: cfg.apiKey,
2516
+ baseURL: cfg.baseURL
2517
+ });
2518
+ const start = Date.now();
2519
+ try {
2520
+ const { object, usage } = await generateObject({
2521
+ model,
2522
+ // fidelity is run-metadata, attached deterministically AFTER synthesis
2523
+ // (ADR-0017) — the LLM must NOT generate it, so omit it from the schema.
2524
+ schema: InvestigationReportSchema.omit({ fidelity: true }),
2525
+ prompt
2526
+ });
2527
+ cfg.onLlmCall?.({
2528
+ phase,
2529
+ provider: cfg.providerId,
2530
+ model: cfg.model,
2531
+ usage: toCallUsage(usage),
2532
+ latencyMs: Date.now() - start,
2533
+ outcome: "ok",
2534
+ failureCause: null
2535
+ });
2536
+ return object;
2537
+ } catch (err1) {
2538
+ cfg.onLlmCall?.({
2539
+ phase,
2540
+ provider: cfg.providerId,
2541
+ model: cfg.model,
2542
+ usage: null,
2543
+ latencyMs: Date.now() - start,
2544
+ outcome: "error",
2545
+ failureCause: err1 instanceof Error ? err1.message : String(err1)
2546
+ });
2547
+ const start2 = Date.now();
2548
+ let fallbackUsage;
2549
+ try {
2550
+ const { text, usage } = await generateText2({
2551
+ model,
2552
+ prompt: `${prompt}
2553
+
2554
+ Respond with ONLY a single JSON object (no prose, no code fences) matching exactly this shape:
2555
+ ${SHAPE_HINT}`
2556
+ });
2557
+ fallbackUsage = usage;
2558
+ const report = InvestigationReportSchema.parse(extractJsonObject(text));
2559
+ cfg.onLlmCall?.({
2560
+ phase,
2561
+ provider: cfg.providerId,
2562
+ model: cfg.model,
2563
+ usage: toCallUsage(usage),
2564
+ latencyMs: Date.now() - start2,
2565
+ outcome: "ok",
2566
+ failureCause: null
2567
+ });
2568
+ return report;
2569
+ } catch (err2) {
2570
+ cfg.onLlmCall?.({
2571
+ phase,
2572
+ provider: cfg.providerId,
2573
+ model: cfg.model,
2574
+ // Real usage when generateText succeeded but parsing failed.
2575
+ usage: toCallUsage(fallbackUsage),
2576
+ latencyMs: Date.now() - start2,
2577
+ outcome: "error",
2578
+ failureCause: err2 instanceof Error ? err2.message : String(err2)
2579
+ });
2580
+ throw err2;
2581
+ }
2582
+ }
2583
+ }
2584
+ function toCallUsage(usage) {
2585
+ return usage ? {
2586
+ inputTokens: usage.inputTokens ?? null,
2587
+ outputTokens: usage.outputTokens ?? null
2588
+ } : null;
2589
+ }
2590
+ function extractJsonObject(text) {
2591
+ const cleaned = text.replace(/```(?:json)?/gi, "");
2592
+ const start = cleaned.indexOf("{");
2593
+ if (start === -1)
2594
+ throw new Error("synthesize: no JSON object found in completion");
2595
+ let depth = 0;
2596
+ let inString = false;
2597
+ let escaped = false;
2598
+ for (let i = start; i < cleaned.length; i++) {
2599
+ const ch = cleaned[i];
2600
+ if (inString) {
2601
+ if (escaped)
2602
+ escaped = false;
2603
+ else if (ch === "\\")
2604
+ escaped = true;
2605
+ else if (ch === '"')
2606
+ inString = false;
2607
+ continue;
2608
+ }
2609
+ if (ch === '"')
2610
+ inString = true;
2611
+ else if (ch === "{")
2612
+ depth++;
2613
+ else if (ch === "}" && --depth === 0) {
2614
+ return JSON.parse(cleaned.slice(start, i + 1));
2615
+ }
2616
+ }
2617
+ throw new Error("synthesize: unterminated JSON object in completion");
2618
+ }
2619
+ function buildTranscript(context, events, focus) {
2620
+ const primary = focus ?? context.alerts[0];
2621
+ const rest = context.alerts.filter((a) => a !== primary);
2622
+ const lines = [
2623
+ `FIRING ALERT: ${primary.alertname} (severity=${primary.severity ?? "unknown"})`,
2624
+ `annotations: ${JSON.stringify(primary.annotations)}`,
2625
+ ...rest.length ? [`related alerts: ${rest.map((a) => a.alertname).join(", ")}`] : [],
2626
+ "",
2627
+ "AGENT INVESTIGATION (steps, tool calls, and observed results):"
2628
+ ];
2629
+ for (const ev of events) {
2630
+ if (ev.kind === "agent_step") {
2631
+ if (ev.text.trim())
2632
+ lines.push(`
2633
+ [think] ${ev.text.trim()}`);
2634
+ for (const tc of ev.toolCalls) {
2635
+ lines.push(`[call] ${tc.name} ${JSON.stringify(tc.args).slice(0, 300)}`);
2636
+ }
2637
+ } else if (ev.kind === "tool_result") {
2638
+ const r = ev.result;
2639
+ lines.push(`[result ${r.ok ? "ok" : "ERROR"}] ${r.source}
2640
+ ${truncate3(r.preview, PREVIEW_CAP)}`);
2641
+ } else if (ev.kind === "branch_done") {
2642
+ lines.push(`
2643
+ [branch ended: ${ev.reason}]`);
2644
+ } else if (ev.kind === "error") {
2645
+ lines.push(`
2646
+ [branch error: ${ev.message}]`);
2647
+ }
2648
+ }
2649
+ return truncate3(lines.join("\n"), TRANSCRIPT_CAP);
2650
+ }
2651
+ function truncate3(s, cap) {
2652
+ return s.length > cap ? `${s.slice(0, cap)}
2653
+ \u2026[truncated]` : s;
2654
+ }
2655
+
2656
+ // ../@prismalens/engine/dist/supervisor/investigate.js
2657
+ function deepAgentsHarness(cfg) {
2658
+ return (prompt, ctx) => runDeepAgentsBranch({ ...cfg, prompt, permission: cfg.permission ?? autoAllowReadOnly }, ctx);
2659
+ }
2660
+ function claudeCodeHarness(cfg) {
2661
+ return (prompt, ctx) => runClaudeCodeBranch({ ...cfg, prompt }, ctx);
2662
+ }
2663
+ var CANCELLED_MESSAGE = "investigation cancelled by request";
2664
+ var CANCELLED_BRANCH_ID = "supervisor";
2665
+ function isCancelledError(message) {
2666
+ return message === CANCELLED_MESSAGE;
2667
+ }
2668
+ function cancelledErrorEvent(runId, seq) {
2669
+ return {
2670
+ kind: "error",
2671
+ runId,
2672
+ branchId: CANCELLED_BRANCH_ID,
2673
+ path: [],
2674
+ seq,
2675
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2676
+ message: CANCELLED_MESSAGE
2677
+ };
2678
+ }
2679
+ function stepWithSignal(iter, signal) {
2680
+ if (signal?.aborted)
2681
+ return Promise.resolve({ kind: "aborted" });
2682
+ const step = iter.next().then((r) => r.done ? { kind: "done" } : { kind: "value", value: r.value });
2683
+ if (!signal)
2684
+ return step;
2685
+ return new Promise((resolve, reject) => {
2686
+ let settled = false;
2687
+ const onAbort = () => {
2688
+ if (settled)
2689
+ return;
2690
+ settled = true;
2691
+ resolve({ kind: "aborted" });
2692
+ };
2693
+ signal.addEventListener("abort", onAbort, { once: true });
2694
+ step.then((s) => {
2695
+ if (settled)
2696
+ return;
2697
+ settled = true;
2698
+ signal.removeEventListener("abort", onAbort);
2699
+ resolve(s);
2700
+ }, (err) => {
2701
+ if (settled)
2702
+ return;
2703
+ settled = true;
2704
+ signal.removeEventListener("abort", onAbort);
2705
+ reject(err);
2706
+ });
2707
+ });
2708
+ }
2709
+ async function* investigateIncidentStream(opts) {
2710
+ const runId = opts.runId ?? randomUUID();
2711
+ const maxBranches = opts.maxBranches;
2712
+ const branchConcurrency = maxBranches ?? DEFAULT_MAX_BRANCHES;
2713
+ const branches = decompose(opts.context, maxBranches !== void 0 ? { maxBranches } : {});
2714
+ const collected = [];
2715
+ const iter = fanOut(branches, opts.harness, runId, {
2716
+ concurrency: branchConcurrency
2717
+ })[Symbol.asyncIterator]();
2718
+ let cancelled = false;
2719
+ let drained = false;
2720
+ try {
2721
+ while (true) {
2722
+ const step = await stepWithSignal(iter, opts.signal);
2723
+ if (step.kind === "aborted") {
2724
+ cancelled = true;
2725
+ break;
2726
+ }
2727
+ if (step.kind === "done") {
2728
+ drained = true;
2729
+ break;
2730
+ }
2731
+ collected.push(step.value);
2732
+ yield step.value;
2733
+ }
2734
+ } finally {
2735
+ if (!drained)
2736
+ void Promise.resolve(iter.return?.(void 0)).catch(() => {
2737
+ });
2738
+ }
2739
+ if (cancelled) {
2740
+ yield cancelledErrorEvent(runId, collected.length);
2741
+ return;
2742
+ }
2743
+ const toolResults = collected.filter((e) => e.kind === "tool_result").length;
2744
+ if (toolResults === 0)
2745
+ return;
2746
+ if (opts.signal?.aborted) {
2747
+ yield cancelledErrorEvent(runId, collected.length);
2748
+ return;
2749
+ }
2750
+ let report;
2751
+ if (!opts.synth.configured) {
2752
+ report = rawReport(opts.context, collected);
2753
+ } else {
2754
+ const llmEvents = [];
2755
+ const callerOnLlmCall = opts.synth.onLlmCall;
2756
+ const synthCfg = {
2757
+ ...opts.synth,
2758
+ onLlmCall: (call) => {
2759
+ callerOnLlmCall?.(call);
2760
+ llmEvents.push({
2761
+ kind: "llm_call",
2762
+ runId,
2763
+ seq: 0,
2764
+ // Assigned properly when yielded
2765
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2766
+ ...call
2767
+ });
2768
+ }
2769
+ };
2770
+ try {
2771
+ report = await reduce(opts.context, collected, synthCfg, opts.model);
2772
+ for (const ev of llmEvents) {
2773
+ ev.seq = collected.length;
2774
+ yield ev;
2775
+ collected.push(ev);
2776
+ }
2777
+ } catch (err) {
2778
+ for (const ev of llmEvents) {
2779
+ ev.seq = collected.length;
2780
+ yield ev;
2781
+ collected.push(ev);
2782
+ }
2783
+ report = rawReport(opts.context, collected, err instanceof Error ? err.message : String(err));
2784
+ }
2785
+ }
2786
+ if (opts.signal?.aborted) {
2787
+ yield cancelledErrorEvent(runId, collected.length);
2788
+ return;
2789
+ }
2790
+ yield {
2791
+ kind: "report",
2792
+ runId,
2793
+ seq: collected.length,
2794
+ ts: (/* @__PURE__ */ new Date()).toISOString(),
2795
+ // Attach the deterministic fidelity AFTER synthesis (ADR-0017): the LLM never
2796
+ // generates it — reduce() omits it, we spread it on here.
2797
+ report: opts.fidelity ? { ...report, fidelity: opts.fidelity } : report
2798
+ };
2799
+ }
2800
+
2801
+ // ../@prismalens/engine/dist/supervisor/conductor.js
2802
+ async function conductRun(opts, io) {
2803
+ const runId = opts.runId ?? randomUUID2();
2804
+ await io.store.create();
2805
+ let report = null;
2806
+ let lastError = null;
2807
+ let cancelled = false;
2808
+ try {
2809
+ for await (const event of investigateIncidentStream({ ...opts, runId })) {
2810
+ await io.sink(event);
2811
+ await io.store.append(event);
2812
+ if (event.kind === "report")
2813
+ report = event.report;
2814
+ else if (event.kind === "error") {
2815
+ lastError = event.message;
2816
+ if (isCancelledError(event.message))
2817
+ cancelled = true;
2818
+ }
2819
+ }
2820
+ } catch (err2) {
2821
+ const msg = String(err2?.message ?? err2);
2822
+ await io.store.fail(msg);
2823
+ return { runId, report: null, error: msg, failureKind: "error" };
2824
+ }
2825
+ if (cancelled) {
2826
+ await io.store.flush?.();
2827
+ return { runId, report: null, error: lastError, failureKind: "cancelled" };
2828
+ }
2829
+ if (report) {
2830
+ await io.store.finish(report);
2831
+ return { runId, report, error: null, failureKind: "none" };
2832
+ }
2833
+ const err = lastError ?? "investigation produced no evidence";
2834
+ await io.store.fail(err);
2835
+ return {
2836
+ runId,
2837
+ report: null,
2838
+ error: err,
2839
+ failureKind: lastError ? "error" : "no-evidence"
2840
+ };
2841
+ }
2842
+
2843
+ // ../@prismalens/engine/dist/config/resolve.js
2844
+ function resolveInvestigation(req) {
2845
+ const context = req.context ? InvestigationContextSchema.parse(req.context) : singleAlertContext(resolveSeedAlert(req), requireTelemetry(req), {
2846
+ ...req.incident ? { incident: req.incident } : {},
2847
+ ...req.service ? { service: req.service } : {},
2848
+ ...req.repos ? { repos: req.repos } : {},
2849
+ ...req.logs ? { logs: req.logs } : {}
2850
+ });
2851
+ const mode = req.permissionMode ?? "read-only";
2852
+ if (!HARNESS_REGISTRY[req.harness]) {
2853
+ throw new Error(`Unknown harness: ${req.harness}`);
2854
+ }
2855
+ const outcome = resolvePermissionOutcome(req.harness, mode);
2856
+ const native = req.harnessNative;
2857
+ if (native && HARNESS_REGISTRY[req.harness]?.transport === "acp") {
2858
+ const inert = ["shellAllowList", "sandbox"].filter((k) => k in native);
2859
+ if (inert.length > 0) {
2860
+ throw new Error(`deepagents native config ${inert.map((k) => `"${k}"`).join(", ")} no longer maps to anything \u2014 the published deepagents-acp binary has no shell-allowlist/sandbox flags (removed in the B.1 Sandbox-port spike). Remove ${inert.length > 1 ? "them" : "it"} and use --sandbox <process|srt|e2b> for real isolation (ADR-0020).`);
2861
+ }
2862
+ }
2863
+ const mechanism = req.sandbox ? `${outcome.mechanism} \xB7 sandbox=${req.sandbox.id} (${req.sandbox.fidelity})` : outcome.mechanism;
2864
+ const fidelity = {
2865
+ harness: req.harness,
2866
+ mode,
2867
+ fidelity: outcome.fidelity,
2868
+ mechanism,
2869
+ // The structured sibling of the mechanism string above (ADR-0020 B.1.1
2870
+ // follow-up) — same requested/actual/fidelity facts, machine-readable.
2871
+ // `requested` defaults to `sandbox.id` when the caller didn't separately
2872
+ // know the request, so the field is never a lie by omission.
2873
+ ...req.sandbox ? {
2874
+ sandbox: {
2875
+ requested: req.requestedSandbox ?? req.sandbox.id,
2876
+ actual: req.sandbox.id,
2877
+ fidelity: req.sandbox.fidelity
2878
+ }
2879
+ } : {}
2880
+ };
2881
+ const harness = buildHarness(req.harness, req.cwd, {
2882
+ model: req.model,
2883
+ harnessEnv: req.harnessEnv,
2884
+ initTimeoutMs: req.initTimeoutMs,
2885
+ permissionMode: mode,
2886
+ native: req.harnessNative,
2887
+ ...req.sandbox ? { sandbox: req.sandbox } : {},
2888
+ ...req.limits ? { limits: req.limits } : {},
2889
+ ...req.maxTurns !== void 0 ? { maxTurns: req.maxTurns } : {},
2890
+ ...req.isolateSettings ? { isolateSettings: req.isolateSettings } : {}
2891
+ });
2892
+ return {
2893
+ context,
2894
+ harness,
2895
+ synth: req.synth,
2896
+ cwd: req.cwd,
2897
+ harnessName: req.harness,
2898
+ fidelity,
2899
+ ...req.maxBranches !== void 0 ? { maxBranches: req.maxBranches } : {}
2900
+ };
2901
+ }
2902
+ function resolveSeedAlert(req) {
2903
+ if (req.alert)
2904
+ return coerceFiringAlert(req.alert);
2905
+ if (req.query)
2906
+ return synthesizeAlert(req.query);
2907
+ throw new Error("No alert to investigate \u2014 supply a context, a FiringAlert payload, or a query.");
2908
+ }
2909
+ function requireTelemetry(req) {
2910
+ if (!req.telemetry) {
2911
+ throw new Error("Missing telemetry endpoints \u2014 required to build a single-alert context.");
2912
+ }
2913
+ return req.telemetry;
2914
+ }
2915
+ var HARNESS_RUNNERS = {
2916
+ deepagents: (cwd, opts, model) => deepAgentsHarness({
2917
+ cwd,
2918
+ ...opts.initTimeoutMs ? { initTimeoutMs: opts.initTimeoutMs } : {},
2919
+ ...model ? { model } : {},
2920
+ ...opts.harnessEnv ? { env: opts.harnessEnv } : {},
2921
+ ...opts.native ? { native: opts.native } : {},
2922
+ ...opts.sandbox ? { sandbox: opts.sandbox } : {},
2923
+ ...opts.limits ? { limits: opts.limits } : {}
2924
+ }),
2925
+ "claude-code": (cwd, opts, model) => claudeCodeHarness({
2926
+ cwd,
2927
+ ...model ? { model } : {},
2928
+ ...opts.permissionMode ? { permissionMode: opts.permissionMode } : {},
2929
+ ...opts.native ? { native: opts.native } : {},
2930
+ ...opts.sandbox ? { sandbox: opts.sandbox } : {},
2931
+ ...opts.limits ? { limits: opts.limits } : {},
2932
+ ...opts.maxTurns ? { maxTurns: opts.maxTurns } : {},
2933
+ ...opts.isolateSettings ? { isolateSettings: opts.isolateSettings } : {}
2934
+ })
2935
+ };
2936
+ function buildHarness(harnessName, cwd, opts) {
2937
+ const descriptor = HARNESS_REGISTRY[harnessName];
2938
+ if (!descriptor)
2939
+ throw new Error(`Unknown harness: ${harnessName}`);
2940
+ if (!descriptor.implemented) {
2941
+ throw new Error(`The '${harnessName}' harness is not implemented yet.`);
2942
+ }
2943
+ const model = opts.model && descriptor.modelPrefix ? `${descriptor.modelPrefix}${opts.model}` : opts.model;
2944
+ const builder = HARNESS_RUNNERS[harnessName];
2945
+ if (!builder) {
2946
+ throw new Error(`No runner wired for harness: ${harnessName}`);
2947
+ }
2948
+ return builder(cwd, opts, model);
2949
+ }
2950
+ function synthesizeAlert(query2) {
2951
+ return {
2952
+ alertname: query2,
2953
+ severity: "unknown",
2954
+ labels: {},
2955
+ annotations: {},
2956
+ startsAt: null
2957
+ };
2958
+ }
2959
+ function coerceFiringAlert(raw) {
2960
+ const labels = asStringMap(raw.labels);
2961
+ const annotations = asStringMap(raw.annotations);
2962
+ const alertname = typeof raw.alertname === "string" && raw.alertname || labels.alertname || "unknown";
2963
+ const severity = typeof raw.severity === "string" ? raw.severity : typeof labels.severity === "string" ? labels.severity : null;
2964
+ const startsAt = typeof raw.startsAt === "string" ? raw.startsAt : null;
2965
+ return { alertname, severity, labels, annotations, startsAt };
2966
+ }
2967
+ function asStringMap(x) {
2968
+ if (x === null || typeof x !== "object")
2969
+ return {};
2970
+ const out = {};
2971
+ for (const [k, v] of Object.entries(x)) {
2972
+ if (typeof v === "string")
2973
+ out[k] = v;
2974
+ }
2975
+ return out;
2976
+ }
2977
+
2978
+ export {
2979
+ HARNESS_IDS,
2980
+ HARNESS_REGISTRY,
2981
+ HARNESS_BINARY,
2982
+ PERMISSION_MODES,
2983
+ pingModel,
2984
+ SeveritySchema,
2985
+ resolveInvestigation,
2986
+ coerceFiringAlert,
2987
+ SANDBOX_MODES,
2988
+ resolveSandbox,
2989
+ conductRun
2990
+ };