@tangle-network/agent-runtime 0.52.0 → 0.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +27 -16
  2. package/dist/agent.d.ts +2 -2
  3. package/dist/agent.js +5 -3
  4. package/dist/agent.js.map +1 -1
  5. package/dist/analyst-loop.d.ts +1 -1
  6. package/dist/analyst-loop.js +2 -2
  7. package/dist/{chunk-COAVO6QB.js → chunk-2BDXWZUC.js} +5 -34
  8. package/dist/chunk-2BDXWZUC.js.map +1 -0
  9. package/dist/chunk-A73RADPB.js +281 -0
  10. package/dist/chunk-A73RADPB.js.map +1 -0
  11. package/dist/chunk-FRBWCJLP.js +396 -0
  12. package/dist/chunk-FRBWCJLP.js.map +1 -0
  13. package/dist/chunk-GRAGM4MC.js +72 -0
  14. package/dist/chunk-GRAGM4MC.js.map +1 -0
  15. package/dist/{chunk-2OU7ZQPD.js → chunk-JTH2FPCK.js} +3248 -456
  16. package/dist/chunk-JTH2FPCK.js.map +1 -0
  17. package/dist/{chunk-V2K35HF2.js → chunk-KJH62YEK.js} +2 -2
  18. package/dist/{chunk-HNUXAZIJ.js → chunk-P5OKDSLB.js} +2 -2
  19. package/dist/{chunk-GSUO5QS6.js → chunk-VLF5RHEQ.js} +2 -5
  20. package/dist/{chunk-GSUO5QS6.js.map → chunk-VLF5RHEQ.js.map} +1 -1
  21. package/dist/{chunk-7JITYN6T.js → chunk-XRYEZPR6.js} +18 -2
  22. package/dist/chunk-XRYEZPR6.js.map +1 -0
  23. package/dist/{coder-_YCf3BAK.d.ts → coder-CEkUFv8h.d.ts} +1 -1
  24. package/dist/{types-5MGt5KTY.d.ts → coordination-BMzskrUR.d.ts} +268 -2
  25. package/dist/{kb-gate-CHAyt4aI.d.ts → delegates-BPLIl8EC.d.ts} +491 -566
  26. package/dist/{delegation-profile-1GbW5yA3.d.ts → delegation-profile-Bvfro2m1.d.ts} +28 -2
  27. package/dist/index.d.ts +7 -7
  28. package/dist/index.js +25 -80
  29. package/dist/index.js.map +1 -1
  30. package/dist/intelligence.d.ts +475 -5
  31. package/dist/intelligence.js +547 -3
  32. package/dist/intelligence.js.map +1 -1
  33. package/dist/kb-gate-CuzMYGYM.d.ts +76 -0
  34. package/dist/{loop-runner-bin-DFUNgpeK.d.ts → loop-runner-bin-BGpVVyXp.d.ts} +6 -27
  35. package/dist/loop-runner-bin.d.ts +5 -5
  36. package/dist/loop-runner-bin.js +6 -5
  37. package/dist/loops.d.ts +8 -5
  38. package/dist/loops.js +32 -8
  39. package/dist/mcp/bin.js +94 -30
  40. package/dist/mcp/bin.js.map +1 -1
  41. package/dist/mcp/index.d.ts +10 -273
  42. package/dist/mcp/index.js +45 -365
  43. package/dist/mcp/index.js.map +1 -1
  44. package/dist/{openai-tools-D4HLDWgw.d.ts → openai-tools-CoeLQ7Uo.d.ts} +1 -1
  45. package/dist/profiles.d.ts +2 -2
  46. package/dist/profiles.js +4 -4
  47. package/dist/router-client-30Y_pca8.d.ts +120 -0
  48. package/dist/{run-loop-BIineL1T.d.ts → run-loop-DluzfJ2h.d.ts} +1 -1
  49. package/dist/runtime.d.ts +429 -131
  50. package/dist/runtime.js +32 -8
  51. package/dist/topology.d.ts +54 -1
  52. package/dist/topology.js +222 -0
  53. package/dist/topology.js.map +1 -1
  54. package/dist/{types-BEQsBhOE.d.ts → types-C8rNlxfV.d.ts} +6 -5
  55. package/dist/workflow.d.ts +2 -2
  56. package/dist/workflow.js +4 -2
  57. package/dist/workflow.js.map +1 -1
  58. package/package.json +5 -5
  59. package/skills/agent-runtime-adoption/SKILL.md +54 -46
  60. package/skills/build-with-agent-runtime/SKILL.md +12 -8
  61. package/skills/loop-writer/SKILL.md +9 -1
  62. package/skills/supervise/SKILL.md +24 -0
  63. package/dist/chunk-2OU7ZQPD.js.map +0 -1
  64. package/dist/chunk-4JI4BCBI.js +0 -623
  65. package/dist/chunk-4JI4BCBI.js.map +0 -1
  66. package/dist/chunk-7JITYN6T.js.map +0 -1
  67. package/dist/chunk-7SP2OVYZ.js +0 -908
  68. package/dist/chunk-7SP2OVYZ.js.map +0 -1
  69. package/dist/chunk-BERLUBAP.js +0 -1356
  70. package/dist/chunk-BERLUBAP.js.map +0 -1
  71. package/dist/chunk-COAVO6QB.js.map +0 -1
  72. package/dist/driver-DLI1io57.d.ts +0 -221
  73. /package/dist/{chunk-V2K35HF2.js.map → chunk-KJH62YEK.js.map} +0 -0
  74. /package/dist/{chunk-HNUXAZIJ.js.map → chunk-P5OKDSLB.js.map} +0 -0
@@ -1,908 +0,0 @@
1
- import {
2
- UI_LENSES
3
- } from "./chunk-WIR4HOOJ.js";
4
- import {
5
- DELEGATE_CODE_DESCRIPTION,
6
- DELEGATE_CODE_INPUT_SCHEMA,
7
- DELEGATE_CODE_TOOL_NAME,
8
- DELEGATE_FEEDBACK_DESCRIPTION,
9
- DELEGATE_FEEDBACK_INPUT_SCHEMA,
10
- DELEGATE_FEEDBACK_TOOL_NAME,
11
- DELEGATE_RESEARCH_DESCRIPTION,
12
- DELEGATE_RESEARCH_INPUT_SCHEMA,
13
- DELEGATE_RESEARCH_TOOL_NAME,
14
- DELEGATION_HISTORY_DESCRIPTION,
15
- DELEGATION_HISTORY_INPUT_SCHEMA,
16
- DELEGATION_HISTORY_TOOL_NAME,
17
- DELEGATION_STATUS_DESCRIPTION,
18
- DELEGATION_STATUS_INPUT_SCHEMA,
19
- DELEGATION_STATUS_TOOL_NAME,
20
- DelegationTaskQueue,
21
- InMemoryFeedbackStore,
22
- createDelegateCodeHandler,
23
- createDelegateFeedbackHandler,
24
- createDelegateResearchHandler,
25
- createDelegationHistoryHandler,
26
- createDelegationStatusHandler,
27
- hashIdempotencyInput
28
- } from "./chunk-BERLUBAP.js";
29
- import {
30
- createFleetWorkspaceExecutor,
31
- createSiblingSandboxExecutor
32
- } from "./chunk-4JI4BCBI.js";
33
- import {
34
- runLocalHarness
35
- } from "./chunk-GLR25NG7.js";
36
- import {
37
- buildLoopOtelSpans,
38
- createOtelExporter
39
- } from "./chunk-G3RGMA7C.js";
40
- import {
41
- ValidationError
42
- } from "./chunk-GSUO5QS6.js";
43
-
44
- // src/mcp/worktree.ts
45
- import { spawn } from "child_process";
46
- async function runGitAsync(args, cwd, runner) {
47
- if (runner) return runner(args, { cwd });
48
- return new Promise((resolve, reject) => {
49
- const proc = spawn("git", args, { cwd, stdio: "pipe" });
50
- let stdout = "";
51
- let stderr = "";
52
- proc.stdout?.on("data", (c) => {
53
- stdout += String(c);
54
- });
55
- proc.stderr?.on("data", (c) => {
56
- stderr += String(c);
57
- });
58
- proc.on("error", reject);
59
- proc.on("close", (code) => resolve({ stdout, stderr, exitCode: code ?? -1 }));
60
- });
61
- }
62
- function ensureGitOk(step, result) {
63
- if (result.exitCode !== 0) {
64
- throw new Error(
65
- `worktree: git ${step} failed (exit ${result.exitCode}): ${result.stderr.slice(0, 400)}`
66
- );
67
- }
68
- }
69
- async function createWorktree(options) {
70
- const variants = options.variantsDir ?? ".coder-variants";
71
- const baseRef = options.baseRef ?? "HEAD";
72
- const branch = `delegate/${options.runId}`;
73
- const path2 = `${options.repoRoot.replace(/\/+$/, "")}/${variants}/${options.runId}`;
74
- const headSha = await runGitAsync(["rev-parse", baseRef], options.repoRoot, options.runGit);
75
- ensureGitOk(`rev-parse ${baseRef}`, headSha);
76
- const add = await runGitAsync(
77
- ["worktree", "add", "-b", branch, path2, baseRef],
78
- options.repoRoot,
79
- options.runGit
80
- );
81
- ensureGitOk(`worktree add ${path2}`, add);
82
- return { path: path2, baseSha: headSha.stdout.trim(), branch };
83
- }
84
- async function captureWorktreeDiff(options) {
85
- const baseRef = options.baseRef ?? options.worktree.baseSha;
86
- const patch = await runGitAsync(["diff", baseRef], options.worktree.path, options.runGit);
87
- const shortstat = await runGitAsync(
88
- ["diff", "--shortstat", baseRef],
89
- options.worktree.path,
90
- options.runGit
91
- );
92
- const stats = parseShortstat(shortstat.stdout);
93
- return { patch: patch.stdout, stats };
94
- }
95
- function parseShortstat(text) {
96
- const out = { filesChanged: 0, insertions: 0, deletions: 0 };
97
- const filesMatch = text.match(/(\d+)\s+files?\s+changed/);
98
- if (filesMatch?.[1]) out.filesChanged = Number(filesMatch[1]);
99
- const insertMatch = text.match(/(\d+)\s+insertions?/);
100
- if (insertMatch?.[1]) out.insertions = Number(insertMatch[1]);
101
- const deleteMatch = text.match(/(\d+)\s+deletions?/);
102
- if (deleteMatch?.[1]) out.deletions = Number(deleteMatch[1]);
103
- return out;
104
- }
105
- async function removeWorktree(options) {
106
- const force = options.force ?? true;
107
- const args = ["worktree", "remove"];
108
- if (force) args.push("--force");
109
- args.push(options.worktree.path);
110
- const result = await runGitAsync(args, options.repoRoot, options.runGit);
111
- if (result.exitCode !== 0 && !/not a working tree/.test(result.stderr)) {
112
- await runGitAsync(
113
- ["branch", "-D", options.worktree.branch],
114
- options.repoRoot,
115
- options.runGit
116
- ).catch(() => void 0);
117
- }
118
- await runGitAsync(
119
- ["branch", "-D", options.worktree.branch],
120
- options.repoRoot,
121
- options.runGit
122
- ).catch(() => void 0);
123
- }
124
-
125
- // src/mcp/in-process-executor.ts
126
- import { randomUUID } from "crypto";
127
- var DEFAULT_HARNESS_TIMEOUT_MS = 5 * 60 * 1e3;
128
- var DEFAULT_POSTCHECK_TIMEOUT_MS = 2 * 60 * 1e3;
129
- function createInProcessExecutor(options) {
130
- const harnesses = options.harnesses && options.harnesses.length > 0 ? [...options.harnesses] : ["claude"];
131
- const runHarness = options.runHarness ?? runLocalHarness;
132
- const runPostCheck = options.runPostCheck ?? defaultRunPostCheck;
133
- let callIndex = 0;
134
- const client = {
135
- async create(_opts) {
136
- const runId = randomUUID();
137
- const harness = harnesses[callIndex % harnesses.length];
138
- callIndex += 1;
139
- const virtual = {
140
- // Synthesize the minimum SandboxInstance surface the kernel touches.
141
- // We CAST through unknown because SandboxInstance is a `declare class`
142
- // with private fields; we're producing a structural subtype that
143
- // satisfies the kernel's narrow usage (`box.id`, `box.streamPrompt`).
144
- id: `in-process-${runId}`,
145
- __inProcess: { runId, harness },
146
- // eslint-disable-next-line require-yield
147
- async *streamPrompt(message, promptOpts) {
148
- const taskPrompt = typeof message === "string" ? message : message.map(
149
- (p) => typeof p === "object" && p && "text" in p ? String(p.text) : ""
150
- ).join("\n");
151
- let worktree;
152
- try {
153
- worktree = await createWorktree({
154
- repoRoot: options.repoRoot,
155
- runId,
156
- runGit: options.runGit
157
- });
158
- this.__inProcess.worktree = worktree;
159
- yield {
160
- type: "in_process.harness.started",
161
- data: {
162
- runId,
163
- harness,
164
- worktreePath: worktree.path,
165
- command: harness
166
- }
167
- };
168
- const harnessResult = await runHarness({
169
- harness,
170
- cwd: worktree.path,
171
- taskPrompt,
172
- timeoutMs: options.harnessTimeoutMs ?? DEFAULT_HARNESS_TIMEOUT_MS,
173
- signal: promptOpts?.signal
174
- });
175
- yield {
176
- type: "in_process.harness.ended",
177
- data: {
178
- runId,
179
- exitCode: harnessResult.exitCode,
180
- durationMs: harnessResult.durationMs,
181
- killedBySignal: harnessResult.killedBySignal,
182
- timedOut: harnessResult.timedOut,
183
- stdoutBytes: harnessResult.stdout.length,
184
- stderrBytes: harnessResult.stderr.length
185
- }
186
- };
187
- const diff = await captureWorktreeDiff({ worktree, runGit: options.runGit });
188
- const testCheck = options.testCmd ? await runPostCheck(options.testCmd, worktree.path, promptOpts?.signal).catch(
189
- (err) => ({
190
- exitCode: -1,
191
- stdout: "",
192
- stderr: err instanceof Error ? err.message : String(err)
193
- })
194
- ) : { exitCode: 0, stdout: "", stderr: "" };
195
- const typecheckCheck = options.typecheckCmd ? await runPostCheck(options.typecheckCmd, worktree.path, promptOpts?.signal).catch(
196
- (err) => ({
197
- exitCode: -1,
198
- stdout: "",
199
- stderr: err instanceof Error ? err.message : String(err)
200
- })
201
- ) : { exitCode: 0, stdout: "", stderr: "" };
202
- const coderOutput = {
203
- branch: worktree.branch,
204
- patch: diff.patch,
205
- testResult: {
206
- passed: !options.testCmd || testCheck.exitCode === 0,
207
- output: tail(testCheck.stderr || testCheck.stdout, 4e3)
208
- },
209
- typecheckResult: {
210
- passed: !options.typecheckCmd || typecheckCheck.exitCode === 0,
211
- output: tail(typecheckCheck.stderr || typecheckCheck.stdout, 4e3)
212
- },
213
- diffStats: diff.stats,
214
- reviewerNotes: harnessResult.exitCode === 0 ? void 0 : `harness ${harness} exited ${harnessResult.exitCode}${harnessResult.timedOut ? " (timed out)" : ""}`
215
- };
216
- yield {
217
- type: "result",
218
- data: {
219
- result: coderOutput,
220
- source: "in-process-executor",
221
- harness,
222
- runId
223
- }
224
- };
225
- } finally {
226
- if (worktree) {
227
- await removeWorktree({
228
- worktree,
229
- repoRoot: options.repoRoot,
230
- runGit: options.runGit
231
- }).catch(() => void 0);
232
- }
233
- }
234
- }
235
- };
236
- return virtual;
237
- },
238
- describePlacement(box) {
239
- const sandboxId = box.id;
240
- const meta = box.__inProcess;
241
- return {
242
- kind: "sibling",
243
- sandboxId,
244
- worktreePath: meta?.worktree?.path,
245
- harness: meta?.harness
246
- };
247
- }
248
- };
249
- return {
250
- client,
251
- placement: "in-process",
252
- describe() {
253
- return `in-process (repoRoot=${options.repoRoot}, harnesses=[${harnesses.join(",")}]${options.testCmd ? `, testCmd="${options.testCmd}"` : ""}${options.typecheckCmd ? `, typecheckCmd="${options.typecheckCmd}"` : ""})`;
254
- }
255
- };
256
- }
257
- async function defaultRunPostCheck(cmd, cwd, signal) {
258
- const { spawn: spawn2 } = await import("child_process");
259
- return new Promise((resolve, reject) => {
260
- const child = spawn2("sh", ["-c", cmd], { cwd, stdio: "pipe" });
261
- let stdout = "";
262
- let stderr = "";
263
- child.stdout?.on("data", (c) => {
264
- stdout += String(c);
265
- });
266
- child.stderr?.on("data", (c) => {
267
- stderr += String(c);
268
- });
269
- if (signal) {
270
- const onAbort = () => {
271
- if (!child.killed) child.kill("SIGTERM");
272
- };
273
- if (signal.aborted) onAbort();
274
- else signal.addEventListener("abort", onAbort, { once: true });
275
- }
276
- const killTimer = setTimeout(() => {
277
- if (!child.killed) child.kill("SIGTERM");
278
- }, DEFAULT_POSTCHECK_TIMEOUT_MS);
279
- if (typeof killTimer.unref === "function") {
280
- ;
281
- killTimer.unref();
282
- }
283
- child.on("error", (err) => {
284
- clearTimeout(killTimer);
285
- reject(err);
286
- });
287
- child.on("close", (code) => {
288
- clearTimeout(killTimer);
289
- resolve({ exitCode: code ?? -1, stdout, stderr });
290
- });
291
- });
292
- }
293
- function tail(text, max) {
294
- if (text.length <= max) return text;
295
- return text.slice(text.length - max);
296
- }
297
-
298
- // src/mcp/bin-helpers.ts
299
- async function detectExecutor(args) {
300
- const env = args.env ?? process.env;
301
- if (env.AGENT_RUNTIME_IN_SANDBOX === "1") {
302
- const repoRoot = env.AGENT_RUNTIME_REPO_ROOT?.trim();
303
- if (!repoRoot) {
304
- throw new Error(
305
- "agent-runtime-mcp: AGENT_RUNTIME_IN_SANDBOX=1 requires AGENT_RUNTIME_REPO_ROOT to point at the workspace root"
306
- );
307
- }
308
- return createInProcessExecutor({
309
- repoRoot,
310
- harnesses: parseHarnesses(env.AGENT_RUNTIME_LOCAL_HARNESSES),
311
- testCmd: env.AGENT_RUNTIME_TEST_CMD?.trim() || void 0,
312
- typecheckCmd: env.AGENT_RUNTIME_TYPECHECK_CMD?.trim() || void 0
313
- });
314
- }
315
- const fleetId = parseFleetId(env.TANGLE_FLEET_ID);
316
- if (!fleetId) {
317
- return createSiblingSandboxExecutor({ client: args.sandboxClient });
318
- }
319
- const resolveFleet = args.resolveFleet ?? defaultResolveFleet;
320
- const fleet = await resolveFleet(args.sandboxClient, fleetId);
321
- const excludeMachineIds = parseList(env.TANGLE_FLEET_EXCLUDE_MACHINES);
322
- return createFleetWorkspaceExecutor({
323
- fleet,
324
- excludeMachineIds
325
- });
326
- }
327
- var KNOWN_HARNESSES = ["claude", "codex", "opencode"];
328
- function parseHarnesses(raw) {
329
- if (!raw) return void 0;
330
- const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
331
- if (parts.length === 0) return void 0;
332
- for (const part of parts) {
333
- if (!KNOWN_HARNESSES.includes(part)) {
334
- throw new Error(
335
- `agent-runtime-mcp: AGENT_RUNTIME_LOCAL_HARNESSES contains unknown harness "${part}". Expected: ${KNOWN_HARNESSES.join(", ")}.`
336
- );
337
- }
338
- }
339
- return parts;
340
- }
341
- async function defaultResolveFleet(sandboxClient, fleetId) {
342
- const fleets = sandboxClient.fleets;
343
- if (!fleets || typeof fleets.get !== "function") {
344
- throw new Error(
345
- "agent-runtime-mcp: the configured sandbox client does not expose `.fleets.get`; upgrade @tangle-network/sandbox to >= 0.2.1 or unset TANGLE_FLEET_ID."
346
- );
347
- }
348
- const raw = await fleets.get(fleetId);
349
- if (!raw || typeof raw !== "object") {
350
- throw new Error(`agent-runtime-mcp: fleets.get(${fleetId}) returned no handle`);
351
- }
352
- const handle = raw;
353
- if (typeof handle.fleetId !== "string" || !Array.isArray(handle.ids)) {
354
- throw new Error(
355
- `agent-runtime-mcp: fleet handle for ${fleetId} is missing fleetId/ids \u2014 incompatible sandbox SDK shape`
356
- );
357
- }
358
- if (typeof handle.sandbox !== "function") {
359
- throw new Error(
360
- `agent-runtime-mcp: fleet handle for ${fleetId} is missing sandbox(machineId) \u2014 incompatible sandbox SDK shape`
361
- );
362
- }
363
- return handle;
364
- }
365
- function parseFleetId(raw) {
366
- if (typeof raw !== "string") return void 0;
367
- const trimmed = raw.trim();
368
- return trimmed.length > 0 ? trimmed : void 0;
369
- }
370
- function parseList(raw) {
371
- if (!raw) return void 0;
372
- const list = raw.split(",").map((entry) => entry.trim()).filter(Boolean);
373
- return list.length > 0 ? list : void 0;
374
- }
375
-
376
- // src/mcp/tools/delegate-ui-audit.ts
377
- import path from "path";
378
- var DELEGATE_UI_AUDIT_TOOL_NAME = "delegate_ui_audit";
379
- var DELEGATE_UI_AUDIT_DESCRIPTION = [
380
- "Delegate a UI/UX audit to a vision-driven auditor that produces self-contained",
381
- "GitHub-issue-ready Markdown findings \u2014 one file per finding, with embedded",
382
- "screenshot evidence and a suggested fix.",
383
- "",
384
- "Use when: you want a thorough pass over a running web app for consistency,",
385
- "hierarchy, layout, ux-flow, duplication, accessibility, responsive, states,",
386
- "content, interaction, or perceived-performance issues. The auditor iterates",
387
- "lens-by-lens so each pass finds new classes of issues; the workspace registry",
388
- "deduplicates across iterations.",
389
- "",
390
- "Returns immediately with a taskId. Poll delegation_status to retrieve the",
391
- "workspace path + indexed findings (typically minutes per audited route).",
392
- "Identical inputs return the same taskId \u2014 safe to retry.",
393
- "",
394
- "Output layout under workspaceDir:",
395
- " registry.json \u2014 finding index + capture sidecar",
396
- " index.md \u2014 human-readable rollup",
397
- " issues/NNN--<lens>--<slug>.md \u2014 one self-contained GitHub-issue",
398
- " screenshots/<route>--<viewport>.png \u2014 capture archive",
399
- "",
400
- "Multi-tenant isolation: every finding is scoped to `namespace` when set.",
401
- "Never pass another tenant's namespace."
402
- ].join("\n");
403
- var VIEWPORT_SCHEMA = {
404
- type: "object",
405
- properties: {
406
- width: { type: "integer", minimum: 1 },
407
- height: { type: "integer", minimum: 1 }
408
- },
409
- required: ["width", "height"],
410
- additionalProperties: false
411
- };
412
- var ROUTE_SCHEMA = {
413
- type: "object",
414
- properties: {
415
- name: { type: "string", description: "Stable route name (used in screenshot filenames)." },
416
- url: { type: "string", description: "Fully-qualified URL." },
417
- viewports: {
418
- type: "array",
419
- items: VIEWPORT_SCHEMA,
420
- description: "Viewports to capture at. Default [{1280, 800}]."
421
- },
422
- fullPage: { type: "boolean" },
423
- waitFor: { type: "string", description: "CSS selector to wait for before capturing." }
424
- },
425
- required: ["name", "url"],
426
- additionalProperties: false
427
- };
428
- var DELEGATE_UI_AUDIT_INPUT_SCHEMA = {
429
- type: "object",
430
- properties: {
431
- workspaceDir: { type: "string", description: "Absolute path for the audit workspace." },
432
- routes: { type: "array", items: ROUTE_SCHEMA, minItems: 1 },
433
- namespace: { type: "string", description: "Multi-tenant scope." },
434
- config: {
435
- type: "object",
436
- properties: {
437
- lenses: {
438
- type: "array",
439
- items: { type: "string", enum: [...UI_LENSES] },
440
- description: 'Lenses to iterate. Default: every lens except "other".'
441
- },
442
- maxIterations: { type: "integer", minimum: 1 },
443
- maxConcurrency: { type: "integer", minimum: 1 },
444
- productContext: { type: "string" }
445
- },
446
- additionalProperties: false
447
- }
448
- },
449
- required: ["workspaceDir", "routes"],
450
- additionalProperties: false
451
- };
452
- var PER_LENS_PER_ROUTE_ESTIMATE_MS = 45e3;
453
- function validateDelegateUiAuditArgs(raw) {
454
- if (raw === null || typeof raw !== "object") {
455
- throw new TypeError("delegate_ui_audit: arguments must be an object");
456
- }
457
- const value = raw;
458
- const workspaceDir = value.workspaceDir;
459
- if (typeof workspaceDir !== "string" || workspaceDir.trim().length === 0) {
460
- throw new TypeError("delegate_ui_audit: `workspaceDir` must be a non-empty string");
461
- }
462
- const trimmedWs = workspaceDir.trim();
463
- if (!path.isAbsolute(trimmedWs)) {
464
- throw new TypeError(
465
- `delegate_ui_audit: \`workspaceDir\` must be an absolute path (got ${JSON.stringify(workspaceDir)})`
466
- );
467
- }
468
- if (trimmedWs.split(path.sep).includes("..")) {
469
- throw new TypeError(
470
- `delegate_ui_audit: \`workspaceDir\` must not contain '..' segments (got ${JSON.stringify(workspaceDir)})`
471
- );
472
- }
473
- const routesRaw = value.routes;
474
- if (!Array.isArray(routesRaw) || routesRaw.length === 0) {
475
- throw new TypeError("delegate_ui_audit: `routes` must be a non-empty array");
476
- }
477
- const routes = routesRaw.map((r, i) => validateRoute(r, i));
478
- const args = { workspaceDir: workspaceDir.trim(), routes };
479
- if (value.namespace !== void 0) {
480
- if (typeof value.namespace !== "string" || value.namespace.trim().length === 0) {
481
- throw new TypeError("delegate_ui_audit: `namespace` must be a non-empty string when set");
482
- }
483
- args.namespace = value.namespace.trim();
484
- }
485
- if (value.config !== void 0) {
486
- args.config = validateConfig(value.config);
487
- }
488
- return args;
489
- }
490
- function validateRoute(raw, index) {
491
- if (raw === null || typeof raw !== "object") {
492
- throw new TypeError(`delegate_ui_audit: routes[${index}] must be an object`);
493
- }
494
- const v = raw;
495
- if (typeof v.name !== "string" || v.name.trim().length === 0) {
496
- throw new TypeError(`delegate_ui_audit: routes[${index}].name must be a non-empty string`);
497
- }
498
- const trimmedName = v.name.trim();
499
- if (/[./\\]/.test(trimmedName) || trimmedName.includes("\0")) {
500
- throw new TypeError(
501
- `delegate_ui_audit: routes[${index}].name must not contain path separators, dots, or NUL (got ${JSON.stringify(v.name)})`
502
- );
503
- }
504
- if (typeof v.url !== "string" || v.url.trim().length === 0) {
505
- throw new TypeError(`delegate_ui_audit: routes[${index}].url must be a non-empty string`);
506
- }
507
- let parsedUrl;
508
- try {
509
- parsedUrl = new URL(v.url);
510
- } catch {
511
- throw new TypeError(
512
- `delegate_ui_audit: routes[${index}].url is not a parseable URL (got ${JSON.stringify(v.url)})`
513
- );
514
- }
515
- if (parsedUrl.protocol !== "http:" && parsedUrl.protocol !== "https:") {
516
- throw new TypeError(
517
- `delegate_ui_audit: routes[${index}].url must use http or https (got ${parsedUrl.protocol})`
518
- );
519
- }
520
- const out = { name: v.name.trim(), url: v.url.trim() };
521
- if (v.viewports !== void 0) {
522
- if (!Array.isArray(v.viewports) || v.viewports.length === 0) {
523
- throw new TypeError(
524
- `delegate_ui_audit: routes[${index}].viewports must be a non-empty array when set`
525
- );
526
- }
527
- out.viewports = v.viewports.map((vp, j) => validateViewport(vp, index, j));
528
- }
529
- if (v.fullPage !== void 0) {
530
- if (typeof v.fullPage !== "boolean") {
531
- throw new TypeError(`delegate_ui_audit: routes[${index}].fullPage must be a boolean`);
532
- }
533
- out.fullPage = v.fullPage;
534
- }
535
- if (v.waitFor !== void 0) {
536
- if (typeof v.waitFor !== "string" || v.waitFor.trim().length === 0) {
537
- throw new TypeError(
538
- `delegate_ui_audit: routes[${index}].waitFor must be a non-empty string when set`
539
- );
540
- }
541
- out.waitFor = v.waitFor.trim();
542
- }
543
- return out;
544
- }
545
- function validateViewport(raw, routeIndex, viewportIndex) {
546
- if (raw === null || typeof raw !== "object") {
547
- throw new TypeError(
548
- `delegate_ui_audit: routes[${routeIndex}].viewports[${viewportIndex}] must be an object`
549
- );
550
- }
551
- const v = raw;
552
- const w = Number(v.width);
553
- const h = Number(v.height);
554
- if (!Number.isInteger(w) || w <= 0 || !Number.isInteger(h) || h <= 0) {
555
- throw new RangeError(
556
- `delegate_ui_audit: routes[${routeIndex}].viewports[${viewportIndex}] must have positive integer width/height`
557
- );
558
- }
559
- return { width: w, height: h };
560
- }
561
- function validateConfig(raw) {
562
- if (raw === null || typeof raw !== "object") {
563
- throw new TypeError("delegate_ui_audit: `config` must be an object");
564
- }
565
- const v = raw;
566
- const out = {};
567
- if (v.lenses !== void 0) {
568
- if (!Array.isArray(v.lenses) || v.lenses.length === 0) {
569
- throw new TypeError("delegate_ui_audit: `config.lenses` must be a non-empty array when set");
570
- }
571
- const knownSet = new Set(UI_LENSES);
572
- const lenses = [];
573
- for (let i = 0; i < v.lenses.length; i += 1) {
574
- const lens = v.lenses[i];
575
- if (typeof lens !== "string" || !knownSet.has(lens)) {
576
- throw new TypeError(
577
- `delegate_ui_audit: config.lenses[${i}] must be one of ${UI_LENSES.join("|")}`
578
- );
579
- }
580
- lenses.push(lens);
581
- }
582
- out.lenses = lenses;
583
- }
584
- if (v.maxIterations !== void 0) {
585
- const n = Number(v.maxIterations);
586
- if (!Number.isInteger(n) || n < 1) {
587
- throw new RangeError("delegate_ui_audit: `config.maxIterations` must be a positive integer");
588
- }
589
- out.maxIterations = n;
590
- }
591
- if (v.maxConcurrency !== void 0) {
592
- const n = Number(v.maxConcurrency);
593
- if (!Number.isInteger(n) || n < 1) {
594
- throw new RangeError("delegate_ui_audit: `config.maxConcurrency` must be a positive integer");
595
- }
596
- out.maxConcurrency = n;
597
- }
598
- if (v.productContext !== void 0) {
599
- if (typeof v.productContext !== "string") {
600
- throw new TypeError("delegate_ui_audit: `config.productContext` must be a string");
601
- }
602
- out.productContext = v.productContext;
603
- }
604
- return out;
605
- }
606
- function createDelegateUiAuditHandler(options) {
607
- const estimateDurationMs = options.estimateDurationMs ?? defaultEstimate;
608
- return async (raw) => {
609
- const args = validateDelegateUiAuditArgs(raw);
610
- const idempotencyKey = hashIdempotencyInput({
611
- profile: "ui-auditor",
612
- workspaceDir: args.workspaceDir,
613
- routes: args.routes,
614
- namespace: args.namespace,
615
- config: args.config
616
- });
617
- const submitted = options.queue.submit({
618
- profile: "ui-auditor",
619
- args,
620
- namespace: args.namespace,
621
- idempotencyKey,
622
- run: async (ctx) => options.delegate(args, ctx)
623
- });
624
- return {
625
- taskId: submitted.taskId,
626
- estimatedDurationMs: estimateDurationMs(args)
627
- };
628
- };
629
- }
630
- function defaultEstimate(args) {
631
- const lenses = args.config?.lenses?.length ?? UI_LENSES.length - 1;
632
- const routes = args.routes.length;
633
- return PER_LENS_PER_ROUTE_ESTIMATE_MS * lenses * routes;
634
- }
635
-
636
- // src/mcp/server.ts
637
- import { createInterface } from "readline";
638
- import { Readable, Writable } from "stream";
639
- var PROTOCOL_VERSION = "2024-11-05";
640
- var DEFAULT_SERVER_NAME = "agent-runtime-mcp";
641
- var DEFAULT_SERVER_VERSION = "0.22.0";
642
- function createMcpServer(options = {}) {
643
- const queue = options.queue ?? new DelegationTaskQueue(
644
- options.traceContext !== void 0 ? { traceContext: options.traceContext } : {}
645
- );
646
- const feedbackStore = options.feedbackStore ?? new InMemoryFeedbackStore();
647
- const serverName = options.serverName ?? DEFAULT_SERVER_NAME;
648
- const serverVersion = options.serverVersion ?? DEFAULT_SERVER_VERSION;
649
- const tools = /* @__PURE__ */ new Map();
650
- if (options.coderDelegate) {
651
- tools.set(DELEGATE_CODE_TOOL_NAME, {
652
- name: DELEGATE_CODE_TOOL_NAME,
653
- description: DELEGATE_CODE_DESCRIPTION,
654
- inputSchema: DELEGATE_CODE_INPUT_SCHEMA,
655
- handler: createDelegateCodeHandler({
656
- queue,
657
- delegate: options.coderDelegate,
658
- ...options.detachedDispatch !== void 0 ? { detachedDispatch: options.detachedDispatch } : {}
659
- })
660
- });
661
- }
662
- if (options.researcherDelegate) {
663
- tools.set(DELEGATE_RESEARCH_TOOL_NAME, {
664
- name: DELEGATE_RESEARCH_TOOL_NAME,
665
- description: DELEGATE_RESEARCH_DESCRIPTION,
666
- inputSchema: DELEGATE_RESEARCH_INPUT_SCHEMA,
667
- handler: createDelegateResearchHandler({
668
- queue,
669
- delegate: options.researcherDelegate,
670
- ...options.detachedDispatch !== void 0 ? { detachedDispatch: options.detachedDispatch } : {}
671
- })
672
- });
673
- }
674
- if (options.uiAuditorDelegate) {
675
- tools.set(DELEGATE_UI_AUDIT_TOOL_NAME, {
676
- name: DELEGATE_UI_AUDIT_TOOL_NAME,
677
- description: DELEGATE_UI_AUDIT_DESCRIPTION,
678
- inputSchema: DELEGATE_UI_AUDIT_INPUT_SCHEMA,
679
- handler: createDelegateUiAuditHandler({ queue, delegate: options.uiAuditorDelegate })
680
- });
681
- }
682
- tools.set(DELEGATE_FEEDBACK_TOOL_NAME, {
683
- name: DELEGATE_FEEDBACK_TOOL_NAME,
684
- description: DELEGATE_FEEDBACK_DESCRIPTION,
685
- inputSchema: DELEGATE_FEEDBACK_INPUT_SCHEMA,
686
- handler: createDelegateFeedbackHandler({ queue, store: feedbackStore })
687
- });
688
- tools.set(DELEGATION_STATUS_TOOL_NAME, {
689
- name: DELEGATION_STATUS_TOOL_NAME,
690
- description: DELEGATION_STATUS_DESCRIPTION,
691
- inputSchema: DELEGATION_STATUS_INPUT_SCHEMA,
692
- handler: createDelegationStatusHandler({ queue })
693
- });
694
- tools.set(DELEGATION_HISTORY_TOOL_NAME, {
695
- name: DELEGATION_HISTORY_TOOL_NAME,
696
- description: DELEGATION_HISTORY_DESCRIPTION,
697
- inputSchema: DELEGATION_HISTORY_INPUT_SCHEMA,
698
- handler: createDelegationHistoryHandler({ queue })
699
- });
700
- for (const tool of options.extraTools ?? []) {
701
- if (tools.has(tool.name)) {
702
- throw new ValidationError(
703
- `createMcpServer: extra tool "${tool.name}" shadows a built-in tool`
704
- );
705
- }
706
- tools.set(tool.name, tool);
707
- }
708
- let stopped = false;
709
- let activeReadline;
710
- async function handle(message) {
711
- if (stopped) {
712
- return rpcError(message.id ?? null, -32099, "server stopped");
713
- }
714
- if (message.method === "initialize") {
715
- return rpcResult(message.id ?? null, {
716
- protocolVersion: PROTOCOL_VERSION,
717
- capabilities: { tools: {} },
718
- serverInfo: { name: serverName, version: serverVersion }
719
- });
720
- }
721
- if (message.method === "notifications/initialized") {
722
- return null;
723
- }
724
- if (message.method === "tools/list") {
725
- return rpcResult(message.id ?? null, {
726
- tools: [...tools.values()].map((tool) => ({
727
- name: tool.name,
728
- description: tool.description,
729
- inputSchema: tool.inputSchema
730
- }))
731
- });
732
- }
733
- if (message.method === "tools/call") {
734
- const params = message.params ?? {};
735
- const name = typeof params.name === "string" ? params.name : "";
736
- const tool = tools.get(name);
737
- if (!tool) {
738
- return rpcError(message.id ?? null, -32601, `unknown tool: ${name}`);
739
- }
740
- try {
741
- const output = await tool.handler(params.arguments ?? {});
742
- return rpcResult(message.id ?? null, {
743
- content: [{ type: "text", text: JSON.stringify(output) }],
744
- structuredContent: output,
745
- isError: false
746
- });
747
- } catch (err) {
748
- const reason = err instanceof Error ? err.message : String(err);
749
- const code = err instanceof TypeError || err instanceof RangeError ? -32602 : -32e3;
750
- return rpcError(message.id ?? null, code, reason);
751
- }
752
- }
753
- if (message.id === void 0 || message.id === null) return null;
754
- return rpcError(message.id, -32601, `unknown method: ${message.method}`);
755
- }
756
- async function serve(transport) {
757
- const input = transport?.input ?? process.stdin;
758
- const output = transport?.output ?? process.stdout;
759
- const rl = createInterface({ input, crlfDelay: Number.POSITIVE_INFINITY });
760
- activeReadline = rl;
761
- return new Promise((resolve, reject) => {
762
- rl.on("line", (line) => {
763
- const trimmed = line.trim();
764
- if (!trimmed) return;
765
- let parsed;
766
- try {
767
- parsed = JSON.parse(trimmed);
768
- } catch (err) {
769
- writeResponse(output, rpcError(null, -32700, `parse error: ${err.message}`));
770
- return;
771
- }
772
- if (!parsed || parsed.jsonrpc !== "2.0" || typeof parsed.method !== "string") {
773
- writeResponse(output, rpcError(parsed?.id ?? null, -32600, "invalid request"));
774
- return;
775
- }
776
- void handle(parsed).then((response) => {
777
- if (response) writeResponse(output, response);
778
- });
779
- });
780
- rl.on("close", () => resolve());
781
- rl.on("error", (err) => reject(err));
782
- if (stopped) {
783
- rl.close();
784
- resolve();
785
- }
786
- });
787
- }
788
- function stop() {
789
- stopped = true;
790
- activeReadline?.close();
791
- activeReadline = void 0;
792
- }
793
- return {
794
- tools,
795
- queue,
796
- feedbackStore,
797
- handle,
798
- serve,
799
- stop
800
- };
801
- }
802
- function rpcResult(id, result) {
803
- return { jsonrpc: "2.0", id, result };
804
- }
805
- function rpcError(id, code, message, data) {
806
- return {
807
- jsonrpc: "2.0",
808
- id,
809
- error: data === void 0 ? { code, message } : { code, message, data }
810
- };
811
- }
812
- function writeResponse(output, response) {
813
- output.write(`${JSON.stringify(response)}
814
- `);
815
- }
816
- function createInProcessTransport() {
817
- const responses = [];
818
- const input = new Readable({ read() {
819
- } });
820
- const output = new Writable({
821
- write(chunk, _enc, cb) {
822
- const text = chunk.toString("utf8");
823
- for (const line of text.split("\n")) {
824
- const trimmed = line.trim();
825
- if (!trimmed) continue;
826
- try {
827
- responses.push(JSON.parse(trimmed));
828
- } catch {
829
- }
830
- }
831
- cb();
832
- }
833
- });
834
- return {
835
- transport: { input, output },
836
- clientWrite(line) {
837
- input.push(`${line}
838
- `);
839
- },
840
- clientClose() {
841
- input.push(null);
842
- },
843
- async readServer() {
844
- for (let i = 0; i < 5; i += 1) await new Promise((r) => setImmediate(r));
845
- return [...responses];
846
- }
847
- };
848
- }
849
-
850
- // src/mcp/trace-propagation.ts
851
- function readTraceContextFromEnv() {
852
- const traceId = process.env.TRACE_ID || generateTraceId();
853
- const parentSpanId = process.env.PARENT_SPAN_ID || void 0;
854
- return { traceId, parentSpanId };
855
- }
856
- function createPropagatingTraceEmitter(ctx) {
857
- const exporter = createOtelExporter();
858
- const buffers = /* @__PURE__ */ new Map();
859
- const emitter = {
860
- emit(event) {
861
- if (!exporter) return;
862
- const buf = buffers.get(event.runId);
863
- if (buf) buf.push(event);
864
- else buffers.set(event.runId, [event]);
865
- if (event.kind === "loop.ended") {
866
- const events = buffers.get(event.runId) ?? [event];
867
- buffers.delete(event.runId);
868
- for (const span of buildLoopOtelSpans(events, ctx.traceId, ctx.parentSpanId)) {
869
- exporter.exportSpan(span);
870
- }
871
- }
872
- }
873
- };
874
- return { emitter, exporter, context: ctx };
875
- }
876
- function traceContextToEnv(ctx) {
877
- const env = { TRACE_ID: ctx.traceId };
878
- if (ctx.parentSpanId) env.PARENT_SPAN_ID = ctx.parentSpanId;
879
- return env;
880
- }
881
- function generateTraceId() {
882
- const bytes = new Uint8Array(16);
883
- if (typeof globalThis.crypto?.getRandomValues === "function") {
884
- globalThis.crypto.getRandomValues(bytes);
885
- } else {
886
- for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);
887
- }
888
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
889
- }
890
-
891
- export {
892
- createWorktree,
893
- captureWorktreeDiff,
894
- removeWorktree,
895
- createInProcessExecutor,
896
- detectExecutor,
897
- DELEGATE_UI_AUDIT_TOOL_NAME,
898
- DELEGATE_UI_AUDIT_DESCRIPTION,
899
- DELEGATE_UI_AUDIT_INPUT_SCHEMA,
900
- validateDelegateUiAuditArgs,
901
- createDelegateUiAuditHandler,
902
- createMcpServer,
903
- createInProcessTransport,
904
- readTraceContextFromEnv,
905
- createPropagatingTraceEmitter,
906
- traceContextToEnv
907
- };
908
- //# sourceMappingURL=chunk-7SP2OVYZ.js.map