@tangle-network/agent-runtime 0.71.1 → 0.73.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/agent.d.ts +27 -17
- package/dist/agent.js +21 -9
- package/dist/agent.js.map +1 -1
- package/dist/analyst-loop.d.ts +1 -1
- package/dist/analyst-loop.js +3 -2
- package/dist/{chunk-4KGQHS7U.js → chunk-7ODB76J5.js} +2 -18
- package/dist/chunk-7ODB76J5.js.map +1 -0
- package/dist/chunk-HPYWEFVY.js +4039 -0
- package/dist/chunk-HPYWEFVY.js.map +1 -0
- package/dist/{chunk-P5OKDSLB.js → chunk-IODKUOBA.js} +5 -3
- package/dist/{chunk-P5OKDSLB.js.map → chunk-IODKUOBA.js.map} +1 -1
- package/dist/chunk-NBV35BR6.js +68 -0
- package/dist/chunk-NBV35BR6.js.map +1 -0
- package/dist/{chunk-5ISW5JUF.js → chunk-NCH4XUZ7.js} +2004 -6551
- package/dist/chunk-NCH4XUZ7.js.map +1 -0
- package/dist/chunk-PBE35ULD.js +52 -0
- package/dist/chunk-PBE35ULD.js.map +1 -0
- package/dist/{chunk-VLF5RHEQ.js → chunk-T2HVQVB4.js} +1 -66
- package/dist/chunk-T2HVQVB4.js.map +1 -0
- package/dist/{chunk-K3RM4MPM.js → chunk-U56XGKVY.js} +9 -24
- package/dist/chunk-U56XGKVY.js.map +1 -0
- package/dist/chunk-UZ5SODU7.js +29 -0
- package/dist/chunk-UZ5SODU7.js.map +1 -0
- package/dist/{delegates-CsXJPZDH.d.ts → coordination-DU0saWeg.d.ts} +875 -1099
- package/dist/index.d.ts +7 -8
- package/dist/index.js +10 -12
- package/dist/index.js.map +1 -1
- package/dist/intelligence.d.ts +1 -1
- package/dist/lifecycle.d.ts +281 -0
- package/dist/lifecycle.js +174 -0
- package/dist/lifecycle.js.map +1 -0
- package/dist/{loop-runner-bin-DLM_bVQO.d.ts → loop-runner-bin-eD3m0rHW.d.ts} +10 -27
- package/dist/loop-runner-bin.d.ts +5 -6
- package/dist/loop-runner-bin.js +6 -6
- package/dist/loops.d.ts +47 -10
- package/dist/loops.js +47 -42
- package/dist/mcp/bin.js +17 -329
- package/dist/mcp/bin.js.map +1 -1
- package/dist/mcp/index.d.ts +10 -190
- package/dist/mcp/index.js +949 -47
- package/dist/mcp/index.js.map +1 -1
- package/dist/{openai-tools-kdCS-T12.d.ts → openai-tools-CBurv8Cu.d.ts} +11 -13
- package/dist/otel-export-BKmNwiCb.d.ts +180 -0
- package/dist/profiles.d.ts +3 -3
- package/dist/profiles.js +1 -5
- package/dist/profiles.js.map +1 -1
- package/dist/{substrate-BoRXgvka.d.ts → substrate-rNj6TDc3.d.ts} +7 -23
- package/dist/{types-CdnEAE3U.d.ts → types-JufmXF2a.d.ts} +80 -1
- package/dist/worktree-DaxOvw-C.d.ts +702 -0
- package/dist/{worktree-fanout-CK2ypmEm.d.ts → worktree-fanout-DIffZohV.d.ts} +15 -5
- package/package.json +6 -1
- package/dist/chunk-4KGQHS7U.js.map +0 -1
- package/dist/chunk-5ISW5JUF.js.map +0 -1
- package/dist/chunk-74UAWZXE.js +0 -278
- package/dist/chunk-74UAWZXE.js.map +0 -1
- package/dist/chunk-DVQGYDN5.js +0 -59
- package/dist/chunk-DVQGYDN5.js.map +0 -1
- package/dist/chunk-INXDNX2W.js +0 -475
- package/dist/chunk-INXDNX2W.js.map +0 -1
- package/dist/chunk-K3RM4MPM.js.map +0 -1
- package/dist/chunk-VLF5RHEQ.js.map +0 -1
- package/dist/chunk-XRYEZPR6.js +0 -88
- package/dist/chunk-XRYEZPR6.js.map +0 -1
- package/dist/coordination-BPQmuwv8.d.ts +0 -666
- package/dist/delegation-profile-Bvfro2m1.d.ts +0 -99
package/dist/chunk-74UAWZXE.js
DELETED
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createFleetWorkspaceExecutor,
|
|
3
|
-
createSiblingSandboxExecutor
|
|
4
|
-
} from "./chunk-INXDNX2W.js";
|
|
5
|
-
import {
|
|
6
|
-
runWorktreeHarness
|
|
7
|
-
} from "./chunk-5ISW5JUF.js";
|
|
8
|
-
import {
|
|
9
|
-
buildLoopOtelSpans,
|
|
10
|
-
createOtelExporter
|
|
11
|
-
} from "./chunk-VMNEQHJR.js";
|
|
12
|
-
|
|
13
|
-
// src/mcp/in-process-executor.ts
|
|
14
|
-
import { randomUUID } from "crypto";
|
|
15
|
-
var DEFAULT_HARNESS_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
16
|
-
var DEFAULT_POSTCHECK_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
17
|
-
function createInProcessExecutor(options) {
|
|
18
|
-
const harnesses = options.harnesses && options.harnesses.length > 0 ? [...options.harnesses] : ["claude"];
|
|
19
|
-
const runPostCheck = options.runPostCheck ?? defaultRunPostCheck;
|
|
20
|
-
const runCommand = async ({
|
|
21
|
-
command,
|
|
22
|
-
cwd,
|
|
23
|
-
signal
|
|
24
|
-
}) => {
|
|
25
|
-
try {
|
|
26
|
-
const r = await runPostCheck(command, cwd, signal);
|
|
27
|
-
return { exitCode: r.exitCode, output: r.stderr || r.stdout };
|
|
28
|
-
} catch (err) {
|
|
29
|
-
return { exitCode: -1, output: err instanceof Error ? err.message : String(err) };
|
|
30
|
-
}
|
|
31
|
-
};
|
|
32
|
-
let callIndex = 0;
|
|
33
|
-
const client = {
|
|
34
|
-
async create(opts) {
|
|
35
|
-
const runId = randomUUID();
|
|
36
|
-
const harness = harnesses[callIndex % harnesses.length];
|
|
37
|
-
callIndex += 1;
|
|
38
|
-
const profile = opts?.backend?.profile ?? { name: `in-process-${harness}` };
|
|
39
|
-
const virtual = {
|
|
40
|
-
id: `in-process-${runId}`,
|
|
41
|
-
__inProcess: { runId, harness },
|
|
42
|
-
async *streamPrompt(message, promptOpts) {
|
|
43
|
-
const taskPrompt = typeof message === "string" ? message : message.map(
|
|
44
|
-
(p) => typeof p === "object" && p && "text" in p ? String(p.text) : ""
|
|
45
|
-
).join("\n");
|
|
46
|
-
const run = await runWorktreeHarness({
|
|
47
|
-
repoRoot: options.repoRoot,
|
|
48
|
-
profile,
|
|
49
|
-
harness,
|
|
50
|
-
taskPrompt,
|
|
51
|
-
runId,
|
|
52
|
-
harnessTimeoutMs: options.harnessTimeoutMs ?? DEFAULT_HARNESS_TIMEOUT_MS,
|
|
53
|
-
checkTimeoutMs: options.postCheckTimeoutMs ?? DEFAULT_POSTCHECK_TIMEOUT_MS,
|
|
54
|
-
...options.testCmd !== void 0 ? { testCmd: options.testCmd } : {},
|
|
55
|
-
...options.typecheckCmd !== void 0 ? { typecheckCmd: options.typecheckCmd } : {},
|
|
56
|
-
...options.runGit ? { runGit: options.runGit } : {},
|
|
57
|
-
...options.runHarness ? { runHarness: options.runHarness } : {},
|
|
58
|
-
runCommand,
|
|
59
|
-
...promptOpts?.signal ? { signal: promptOpts.signal } : {}
|
|
60
|
-
});
|
|
61
|
-
this.__inProcess.worktree = run.worktree;
|
|
62
|
-
try {
|
|
63
|
-
yield {
|
|
64
|
-
type: "in_process.harness.started",
|
|
65
|
-
data: { runId, harness, worktreePath: run.worktree.path, command: harness }
|
|
66
|
-
};
|
|
67
|
-
const h = run.result.harness;
|
|
68
|
-
yield {
|
|
69
|
-
type: "in_process.harness.ended",
|
|
70
|
-
data: {
|
|
71
|
-
runId,
|
|
72
|
-
exitCode: h.exitCode,
|
|
73
|
-
durationMs: h.durationMs,
|
|
74
|
-
killedBySignal: h.killedBySignal,
|
|
75
|
-
timedOut: h.timedOut,
|
|
76
|
-
stdoutBytes: h.stdout.length,
|
|
77
|
-
stderrBytes: h.stderr.length
|
|
78
|
-
}
|
|
79
|
-
};
|
|
80
|
-
yield {
|
|
81
|
-
type: "result",
|
|
82
|
-
data: {
|
|
83
|
-
result: run.result,
|
|
84
|
-
source: "in-process-executor",
|
|
85
|
-
harness,
|
|
86
|
-
runId
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
} finally {
|
|
90
|
-
await run.cleanup();
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
};
|
|
94
|
-
return virtual;
|
|
95
|
-
},
|
|
96
|
-
describePlacement(box) {
|
|
97
|
-
const sandboxId = box.id;
|
|
98
|
-
const meta = box.__inProcess;
|
|
99
|
-
return {
|
|
100
|
-
kind: "sibling",
|
|
101
|
-
sandboxId,
|
|
102
|
-
worktreePath: meta?.worktree?.path,
|
|
103
|
-
harness: meta?.harness
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
return {
|
|
108
|
-
client,
|
|
109
|
-
placement: "in-process",
|
|
110
|
-
describe() {
|
|
111
|
-
return `in-process (repoRoot=${options.repoRoot}, harnesses=[${harnesses.join(",")}]${options.testCmd ? `, testCmd="${options.testCmd}"` : ""}${options.typecheckCmd ? `, typecheckCmd="${options.typecheckCmd}"` : ""})`;
|
|
112
|
-
}
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
async function defaultRunPostCheck(cmd, cwd, signal) {
|
|
116
|
-
const { spawn } = await import("child_process");
|
|
117
|
-
return new Promise((resolve, reject) => {
|
|
118
|
-
const child = spawn("sh", ["-c", cmd], { cwd, stdio: "pipe" });
|
|
119
|
-
let stdout = "";
|
|
120
|
-
let stderr = "";
|
|
121
|
-
child.stdout?.on("data", (c) => {
|
|
122
|
-
stdout += String(c);
|
|
123
|
-
});
|
|
124
|
-
child.stderr?.on("data", (c) => {
|
|
125
|
-
stderr += String(c);
|
|
126
|
-
});
|
|
127
|
-
if (signal) {
|
|
128
|
-
const onAbort = () => {
|
|
129
|
-
if (!child.killed) child.kill("SIGTERM");
|
|
130
|
-
};
|
|
131
|
-
if (signal.aborted) onAbort();
|
|
132
|
-
else signal.addEventListener("abort", onAbort, { once: true });
|
|
133
|
-
}
|
|
134
|
-
const killTimer = setTimeout(() => {
|
|
135
|
-
if (!child.killed) child.kill("SIGTERM");
|
|
136
|
-
}, DEFAULT_POSTCHECK_TIMEOUT_MS);
|
|
137
|
-
if (typeof killTimer.unref === "function") {
|
|
138
|
-
;
|
|
139
|
-
killTimer.unref();
|
|
140
|
-
}
|
|
141
|
-
child.on("error", (err) => {
|
|
142
|
-
clearTimeout(killTimer);
|
|
143
|
-
reject(err);
|
|
144
|
-
});
|
|
145
|
-
child.on("close", (code) => {
|
|
146
|
-
clearTimeout(killTimer);
|
|
147
|
-
resolve({ exitCode: code ?? -1, stdout, stderr });
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// src/mcp/bin-helpers.ts
|
|
153
|
-
async function detectExecutor(args) {
|
|
154
|
-
const env = args.env ?? process.env;
|
|
155
|
-
if (env.AGENT_RUNTIME_IN_SANDBOX === "1") {
|
|
156
|
-
const repoRoot = env.AGENT_RUNTIME_REPO_ROOT?.trim();
|
|
157
|
-
if (!repoRoot) {
|
|
158
|
-
throw new Error(
|
|
159
|
-
"agent-runtime-mcp: AGENT_RUNTIME_IN_SANDBOX=1 requires AGENT_RUNTIME_REPO_ROOT to point at the workspace root"
|
|
160
|
-
);
|
|
161
|
-
}
|
|
162
|
-
return createInProcessExecutor({
|
|
163
|
-
repoRoot,
|
|
164
|
-
harnesses: parseHarnesses(env.AGENT_RUNTIME_LOCAL_HARNESSES),
|
|
165
|
-
testCmd: env.AGENT_RUNTIME_TEST_CMD?.trim() || void 0,
|
|
166
|
-
typecheckCmd: env.AGENT_RUNTIME_TYPECHECK_CMD?.trim() || void 0
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
const fleetId = parseFleetId(env.TANGLE_FLEET_ID);
|
|
170
|
-
if (!fleetId) {
|
|
171
|
-
return createSiblingSandboxExecutor({ client: args.sandboxClient });
|
|
172
|
-
}
|
|
173
|
-
const resolveFleet = args.resolveFleet ?? defaultResolveFleet;
|
|
174
|
-
const fleet = await resolveFleet(args.sandboxClient, fleetId);
|
|
175
|
-
const excludeMachineIds = parseList(env.TANGLE_FLEET_EXCLUDE_MACHINES);
|
|
176
|
-
return createFleetWorkspaceExecutor({
|
|
177
|
-
fleet,
|
|
178
|
-
excludeMachineIds
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
var KNOWN_HARNESSES = ["claude", "codex", "opencode"];
|
|
182
|
-
function parseHarnesses(raw) {
|
|
183
|
-
if (!raw) return void 0;
|
|
184
|
-
const parts = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
185
|
-
if (parts.length === 0) return void 0;
|
|
186
|
-
for (const part of parts) {
|
|
187
|
-
if (!KNOWN_HARNESSES.includes(part)) {
|
|
188
|
-
throw new Error(
|
|
189
|
-
`agent-runtime-mcp: AGENT_RUNTIME_LOCAL_HARNESSES contains unknown harness "${part}". Expected: ${KNOWN_HARNESSES.join(", ")}.`
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return parts;
|
|
194
|
-
}
|
|
195
|
-
async function defaultResolveFleet(sandboxClient, fleetId) {
|
|
196
|
-
const fleets = sandboxClient.fleets;
|
|
197
|
-
if (!fleets || typeof fleets.get !== "function") {
|
|
198
|
-
throw new Error(
|
|
199
|
-
"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."
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
const raw = await fleets.get(fleetId);
|
|
203
|
-
if (!raw || typeof raw !== "object") {
|
|
204
|
-
throw new Error(`agent-runtime-mcp: fleets.get(${fleetId}) returned no handle`);
|
|
205
|
-
}
|
|
206
|
-
const handle = raw;
|
|
207
|
-
if (typeof handle.fleetId !== "string" || !Array.isArray(handle.ids)) {
|
|
208
|
-
throw new Error(
|
|
209
|
-
`agent-runtime-mcp: fleet handle for ${fleetId} is missing fleetId/ids \u2014 incompatible sandbox SDK shape`
|
|
210
|
-
);
|
|
211
|
-
}
|
|
212
|
-
if (typeof handle.sandbox !== "function") {
|
|
213
|
-
throw new Error(
|
|
214
|
-
`agent-runtime-mcp: fleet handle for ${fleetId} is missing sandbox(machineId) \u2014 incompatible sandbox SDK shape`
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
return handle;
|
|
218
|
-
}
|
|
219
|
-
function parseFleetId(raw) {
|
|
220
|
-
if (typeof raw !== "string") return void 0;
|
|
221
|
-
const trimmed = raw.trim();
|
|
222
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
223
|
-
}
|
|
224
|
-
function parseList(raw) {
|
|
225
|
-
if (!raw) return void 0;
|
|
226
|
-
const list = raw.split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
227
|
-
return list.length > 0 ? list : void 0;
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
// src/mcp/trace-propagation.ts
|
|
231
|
-
function readTraceContextFromEnv() {
|
|
232
|
-
const traceId = process.env.TRACE_ID || generateTraceId();
|
|
233
|
-
const parentSpanId = process.env.PARENT_SPAN_ID || void 0;
|
|
234
|
-
return { traceId, parentSpanId };
|
|
235
|
-
}
|
|
236
|
-
function createPropagatingTraceEmitter(ctx) {
|
|
237
|
-
const exporter = createOtelExporter();
|
|
238
|
-
const buffers = /* @__PURE__ */ new Map();
|
|
239
|
-
const emitter = {
|
|
240
|
-
emit(event) {
|
|
241
|
-
if (!exporter) return;
|
|
242
|
-
const buf = buffers.get(event.runId);
|
|
243
|
-
if (buf) buf.push(event);
|
|
244
|
-
else buffers.set(event.runId, [event]);
|
|
245
|
-
if (event.kind === "loop.ended") {
|
|
246
|
-
const events = buffers.get(event.runId) ?? [event];
|
|
247
|
-
buffers.delete(event.runId);
|
|
248
|
-
for (const span of buildLoopOtelSpans(events, ctx.traceId, ctx.parentSpanId)) {
|
|
249
|
-
exporter.exportSpan(span);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
};
|
|
254
|
-
return { emitter, exporter, context: ctx };
|
|
255
|
-
}
|
|
256
|
-
function traceContextToEnv(ctx) {
|
|
257
|
-
const env = { TRACE_ID: ctx.traceId };
|
|
258
|
-
if (ctx.parentSpanId) env.PARENT_SPAN_ID = ctx.parentSpanId;
|
|
259
|
-
return env;
|
|
260
|
-
}
|
|
261
|
-
function generateTraceId() {
|
|
262
|
-
const bytes = new Uint8Array(16);
|
|
263
|
-
if (typeof globalThis.crypto?.getRandomValues === "function") {
|
|
264
|
-
globalThis.crypto.getRandomValues(bytes);
|
|
265
|
-
} else {
|
|
266
|
-
for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);
|
|
267
|
-
}
|
|
268
|
-
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export {
|
|
272
|
-
createInProcessExecutor,
|
|
273
|
-
detectExecutor,
|
|
274
|
-
readTraceContextFromEnv,
|
|
275
|
-
createPropagatingTraceEmitter,
|
|
276
|
-
traceContextToEnv
|
|
277
|
-
};
|
|
278
|
-
//# sourceMappingURL=chunk-74UAWZXE.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp/in-process-executor.ts","../src/mcp/bin-helpers.ts","../src/mcp/trace-propagation.ts"],"sourcesContent":["/**\n * @experimental\n *\n * In-process delegation executor — when `agent-runtime-mcp` runs inside a sandbox whose image\n * carries the local coding-harness CLIs (claude / codex / opencode), delegations spawn the harness\n * AS A SUBPROCESS against a git worktree on the SAME filesystem instead of provisioning a sibling\n * sandbox. Zero provisioning latency; worker diffs land in-place; multi-harness fanout = N parallel\n * subprocesses in N parallel worktrees (round-robin `harnesses`).\n *\n * This is a THIN adapter over `runWorktreeHarness` (`./worktree-harness`) — the SAME core the\n * `Scope` leaf `createWorktreeCliExecutor` uses. It only adapts the core to the `SandboxClient`\n * port: `create()` reads the authored profile from `CreateSandboxOptions.backend.profile`, and\n * `streamPrompt` runs the core then emits its raw `WorktreeHarnessResult` (the content-addressed\n * patch artifact) on the `result` event. The sandbox-session decode layer\n * (`./detached-coder`) projects that artifact onto `CoderOutput`; the generic `Scope` path settles\n * the artifact directly. The §1.5 payload (systemPrompt + model) reaches the harness inside the core.\n */\n\nimport { randomUUID } from 'node:crypto'\nimport type {\n AgentProfile,\n CreateSandboxOptions,\n SandboxEvent,\n SandboxInstance,\n} from '@tangle-network/sandbox'\nimport type { LoopSandboxPlacement, SandboxClient } from '../runtime'\nimport type { DelegationExecutor } from './executor'\nimport type { LocalHarness } from './local-harness'\nimport type { GitRunner, WorktreeHandle } from './worktree'\nimport { runWorktreeHarness } from './worktree-harness'\n\n/** @experimental */\nexport interface InProcessExecutorOptions {\n /** Absolute path to the git repo (the workspace). Worktrees go under `<repoRoot>/.agent-worktrees/`. */\n repoRoot: string\n /** Harnesses to round-robin across `create()` calls. One entry = no fanout. Default `['claude']`. */\n harnesses?: ReadonlyArray<LocalHarness>\n /** Optional per-delegation test command run in the worktree after the harness exits. */\n testCmd?: string\n /** Optional per-delegation typecheck command. Same shape as `testCmd`. */\n typecheckCmd?: string\n /** Wall-clock cap per harness subprocess (ms). Default 5min. */\n harnessTimeoutMs?: number\n /** Wall-clock cap per test/typecheck subprocess (ms). Default 2min. */\n postCheckTimeoutMs?: number\n /** Test seam — override the git runner used by the worktree helpers. */\n runGit?: GitRunner\n /** Test seam — override the harness runner (defaults to the real CLI via `runLocalHarness`). */\n runHarness?: typeof import('./local-harness').runLocalHarness\n /** Test seam — override the post-check runner (defaults to a `sh -c` spawn). A throw is folded\n * into a non-fatal `{exitCode:-1}` so a broken check command fails the signal, not the run. */\n runPostCheck?: (\n cmd: string,\n cwd: string,\n signal?: AbortSignal,\n ) => Promise<{ exitCode: number; stdout: string; stderr: string }>\n}\n\n/** @experimental */\nexport interface InProcessExecutorDescribePlacement extends LoopSandboxPlacement {\n /** Worktree path in the parent sandbox's filesystem (set so traces correlate to on-disk artifacts). */\n worktreePath?: string\n /** Which harness handled this delegation. */\n harness?: LocalHarness\n}\n\ninterface VirtualSandbox extends SandboxInstance {\n __inProcess: {\n runId: string\n harness: LocalHarness\n worktree?: WorktreeHandle\n }\n}\n\nconst DEFAULT_HARNESS_TIMEOUT_MS = 5 * 60 * 1000\nconst DEFAULT_POSTCHECK_TIMEOUT_MS = 2 * 60 * 1000\n\n/**\n * Build an in-process executor. Returns a {@link DelegationExecutor} whose `client.create()`\n * returns a minimal virtual `SandboxInstance`; the kernel calls `streamPrompt(msg)` on it, which\n * runs the shared worktree-harness core and emits one `result` event whose `data.result` is the\n * raw `WorktreeHarnessResult` (the content-addressed patch artifact). The authored profile\n * (`backend.profile`) threads its systemPrompt + model into the harness via the core.\n *\n * @experimental\n */\nexport function createInProcessExecutor(options: InProcessExecutorOptions): DelegationExecutor {\n const harnesses =\n options.harnesses && options.harnesses.length > 0\n ? [...options.harnesses]\n : (['claude'] as const)\n const runPostCheck = options.runPostCheck ?? defaultRunPostCheck\n // The core speaks one `runCommand` seam ({exitCode, output}); adapt the post-check seam\n // ({exitCode, stdout, stderr}) onto it, folding a throw into a non-fatal failure signal so a\n // broken check command fails the signal rather than aborting the whole delegation.\n const runCommand = async ({\n command,\n cwd,\n signal,\n }: {\n command: string\n cwd: string\n timeoutMs: number\n signal?: AbortSignal\n }): Promise<{ exitCode: number | null; output: string }> => {\n try {\n const r = await runPostCheck(command, cwd, signal)\n return { exitCode: r.exitCode, output: r.stderr || r.stdout }\n } catch (err) {\n return { exitCode: -1, output: err instanceof Error ? err.message : String(err) }\n }\n }\n\n let callIndex = 0\n\n const client: SandboxClient = {\n async create(opts?: CreateSandboxOptions): Promise<SandboxInstance> {\n const runId = randomUUID()\n const harness = harnesses[callIndex % harnesses.length] as LocalHarness\n callIndex += 1\n // §1.5: the authored profile rides in `backend.profile` (set by `buildBackendOptions`).\n // Without one (a direct test `create()`), fall back to a name-only profile → the harness\n // sees the task prompt with no system prepend, the pre-fix behavior.\n const profile =\n ((opts?.backend as { profile?: AgentProfile } | undefined)?.profile as\n | AgentProfile\n | undefined) ?? ({ name: `in-process-${harness}` } as AgentProfile)\n\n const virtual: VirtualSandbox = {\n id: `in-process-${runId}`,\n __inProcess: { runId, harness },\n async *streamPrompt(\n this: VirtualSandbox,\n message: string | unknown[],\n promptOpts?: { signal?: AbortSignal },\n ): AsyncGenerator<SandboxEvent> {\n const taskPrompt =\n typeof message === 'string'\n ? message\n : message\n .map((p) =>\n typeof p === 'object' && p && 'text' in p\n ? String((p as { text: unknown }).text)\n : '',\n )\n .join('\\n')\n\n // The shared worktree-harness core: worktree → profile-aware harness → diff → checks.\n // A throw cleans up inside the core; on success we own the teardown (the finally).\n const run = await runWorktreeHarness({\n repoRoot: options.repoRoot,\n profile,\n harness,\n taskPrompt,\n runId,\n harnessTimeoutMs: options.harnessTimeoutMs ?? DEFAULT_HARNESS_TIMEOUT_MS,\n checkTimeoutMs: options.postCheckTimeoutMs ?? DEFAULT_POSTCHECK_TIMEOUT_MS,\n ...(options.testCmd !== undefined ? { testCmd: options.testCmd } : {}),\n ...(options.typecheckCmd !== undefined ? { typecheckCmd: options.typecheckCmd } : {}),\n ...(options.runGit ? { runGit: options.runGit } : {}),\n ...(options.runHarness ? { runHarness: options.runHarness } : {}),\n runCommand,\n ...(promptOpts?.signal ? { signal: promptOpts.signal } : {}),\n })\n this.__inProcess.worktree = run.worktree\n\n try {\n yield {\n type: 'in_process.harness.started',\n data: { runId, harness, worktreePath: run.worktree.path, command: harness },\n }\n const h = run.result.harness\n yield {\n type: 'in_process.harness.ended',\n data: {\n runId,\n exitCode: h.exitCode,\n durationMs: h.durationMs,\n killedBySignal: h.killedBySignal,\n timedOut: h.timedOut,\n stdoutBytes: h.stdout.length,\n stderrBytes: h.stderr.length,\n },\n }\n yield {\n type: 'result',\n data: {\n result: run.result,\n source: 'in-process-executor',\n harness,\n runId,\n },\n }\n } finally {\n await run.cleanup()\n }\n },\n } as unknown as VirtualSandbox\n\n return virtual\n },\n describePlacement(box: SandboxInstance): InProcessExecutorDescribePlacement {\n const sandboxId = (box as unknown as { id?: string }).id\n const meta = (box as VirtualSandbox).__inProcess\n return {\n kind: 'sibling',\n sandboxId,\n worktreePath: meta?.worktree?.path,\n harness: meta?.harness,\n }\n },\n }\n\n return {\n client,\n placement: 'in-process',\n describe(): string {\n return `in-process (repoRoot=${options.repoRoot}, harnesses=[${harnesses.join(',')}]${\n options.testCmd ? `, testCmd=\"${options.testCmd}\"` : ''\n }${options.typecheckCmd ? `, typecheckCmd=\"${options.typecheckCmd}\"` : ''})`\n },\n }\n}\n\nasync function defaultRunPostCheck(\n cmd: string,\n cwd: string,\n signal?: AbortSignal,\n): Promise<{ exitCode: number; stdout: string; stderr: string }> {\n const { spawn } = await import('node:child_process')\n return new Promise((resolve, reject) => {\n const child = spawn('sh', ['-c', cmd], { cwd, stdio: 'pipe' })\n let stdout = ''\n let stderr = ''\n child.stdout?.on('data', (c) => {\n stdout += String(c)\n })\n child.stderr?.on('data', (c) => {\n stderr += String(c)\n })\n if (signal) {\n const onAbort = () => {\n if (!child.killed) child.kill('SIGTERM')\n }\n if (signal.aborted) onAbort()\n else signal.addEventListener('abort', onAbort, { once: true })\n }\n const killTimer = setTimeout(() => {\n if (!child.killed) child.kill('SIGTERM')\n }, DEFAULT_POSTCHECK_TIMEOUT_MS)\n if (typeof (killTimer as { unref?: () => void }).unref === 'function') {\n ;(killTimer as { unref: () => void }).unref()\n }\n child.on('error', (err) => {\n clearTimeout(killTimer)\n reject(err)\n })\n child.on('close', (code) => {\n clearTimeout(killTimer)\n resolve({ exitCode: code ?? -1, stdout, stderr })\n })\n })\n}\n","/**\n * @experimental\n *\n * Helpers extracted from `bin.ts` so the env-detection + executor-selection\n * logic is unit-testable without spawning a subprocess. The bin imports from\n * here; tests import from here directly.\n */\n\nimport type { SandboxClient } from '../runtime'\nimport {\n createFleetWorkspaceExecutor,\n createSiblingSandboxExecutor,\n type DelegationExecutor,\n type FleetHandle,\n} from './executor'\nimport { createInProcessExecutor } from './in-process-executor'\nimport type { LocalHarness } from './local-harness'\n\n/** @experimental */\nexport interface DetectExecutorArgs {\n sandboxClient: SandboxClient\n /** Raw env (defaults to `process.env`). Pass an explicit map for tests. */\n env?: Record<string, string | undefined>\n /**\n * Override how a fleet handle is resolved from the client + fleet id. The\n * default reads `client.fleets.get(fleetId)` and validates the returned\n * shape against the structural `FleetHandle` contract.\n */\n resolveFleet?: (client: SandboxClient, fleetId: string) => Promise<FleetHandle>\n}\n\n/**\n * Pick the right executor for an MCP server invocation based on env vars.\n *\n * - `TANGLE_FLEET_ID` set → fleet-workspace placement; resolves the handle\n * via `sandboxClient.fleets.get(...)`.\n * - Otherwise → sibling-sandbox placement; each delegation creates a fresh\n * sandbox via `sandboxClient.create(...)`.\n *\n * Fails loud (throws) when fleet mode is requested but the SDK shape is\n * incompatible — the operator chose fleet semantics, silently degrading to\n * sibling mode would lie about workspace topology.\n *\n * @experimental\n */\nexport async function detectExecutor(args: DetectExecutorArgs): Promise<DelegationExecutor> {\n const env = args.env ?? process.env\n\n // In-process (Phase 2.8): parent harness sets AGENT_RUNTIME_IN_SANDBOX=1\n // and points us at the workspace root. Highest-priority — when this is\n // set, delegations spawn local harness CLIs on git worktrees in the\n // SAME filesystem instead of provisioning sibling sandboxes.\n if (env.AGENT_RUNTIME_IN_SANDBOX === '1') {\n const repoRoot = env.AGENT_RUNTIME_REPO_ROOT?.trim()\n if (!repoRoot) {\n throw new Error(\n 'agent-runtime-mcp: AGENT_RUNTIME_IN_SANDBOX=1 requires AGENT_RUNTIME_REPO_ROOT to point at the workspace root',\n )\n }\n return createInProcessExecutor({\n repoRoot,\n harnesses: parseHarnesses(env.AGENT_RUNTIME_LOCAL_HARNESSES),\n testCmd: env.AGENT_RUNTIME_TEST_CMD?.trim() || undefined,\n typecheckCmd: env.AGENT_RUNTIME_TYPECHECK_CMD?.trim() || undefined,\n })\n }\n\n const fleetId = parseFleetId(env.TANGLE_FLEET_ID)\n if (!fleetId) {\n return createSiblingSandboxExecutor({ client: args.sandboxClient })\n }\n const resolveFleet = args.resolveFleet ?? defaultResolveFleet\n const fleet = await resolveFleet(args.sandboxClient, fleetId)\n const excludeMachineIds = parseList(env.TANGLE_FLEET_EXCLUDE_MACHINES)\n return createFleetWorkspaceExecutor({\n fleet,\n excludeMachineIds,\n })\n}\n\nconst KNOWN_HARNESSES: ReadonlyArray<LocalHarness> = ['claude', 'codex', 'opencode']\n\nfunction parseHarnesses(raw: string | undefined): ReadonlyArray<LocalHarness> | undefined {\n if (!raw) return undefined\n const parts = raw\n .split(',')\n .map((s) => s.trim())\n .filter(Boolean)\n if (parts.length === 0) return undefined\n for (const part of parts) {\n if (!KNOWN_HARNESSES.includes(part as LocalHarness)) {\n throw new Error(\n `agent-runtime-mcp: AGENT_RUNTIME_LOCAL_HARNESSES contains unknown harness \"${part}\". Expected: ${KNOWN_HARNESSES.join(', ')}.`,\n )\n }\n }\n return parts as LocalHarness[]\n}\n\ninterface FleetsApi {\n get(fleetId: string): Promise<unknown>\n}\n\nasync function defaultResolveFleet(\n sandboxClient: SandboxClient,\n fleetId: string,\n): Promise<FleetHandle> {\n const fleets = (sandboxClient as unknown as { fleets?: FleetsApi }).fleets\n if (!fleets || typeof fleets.get !== 'function') {\n throw new Error(\n '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.',\n )\n }\n const raw = await fleets.get(fleetId)\n if (!raw || typeof raw !== 'object') {\n throw new Error(`agent-runtime-mcp: fleets.get(${fleetId}) returned no handle`)\n }\n const handle = raw as Partial<FleetHandle>\n if (typeof handle.fleetId !== 'string' || !Array.isArray(handle.ids)) {\n throw new Error(\n `agent-runtime-mcp: fleet handle for ${fleetId} is missing fleetId/ids — incompatible sandbox SDK shape`,\n )\n }\n if (typeof handle.sandbox !== 'function') {\n throw new Error(\n `agent-runtime-mcp: fleet handle for ${fleetId} is missing sandbox(machineId) — incompatible sandbox SDK shape`,\n )\n }\n return handle as FleetHandle\n}\n\nfunction parseFleetId(raw: string | undefined): string | undefined {\n if (typeof raw !== 'string') return undefined\n const trimmed = raw.trim()\n return trimmed.length > 0 ? trimmed : undefined\n}\n\nfunction parseList(raw: string | undefined): string[] | undefined {\n if (!raw) return undefined\n const list = raw\n .split(',')\n .map((entry) => entry.trim())\n .filter(Boolean)\n return list.length > 0 ? list : undefined\n}\n","/**\n * @experimental\n *\n * Trace context propagation for MCP subprocess.\n *\n * When the MCP server is launched as a child process by a sandbox harness,\n * the parent passes trace context via environment variables:\n *\n * TRACE_ID=<current-run-trace-id>\n * PARENT_SPAN_ID=<span-that-dispatched-the-delegation>\n *\n * The MCP server reads these at startup and uses them as the root of its\n * internal trace tree. All spans emitted by `runLoop` invocations inside\n * the MCP are children of the parent's delegation span.\n *\n * When these env vars are absent, the MCP generates a fresh trace root —\n * the server operates standalone without trace joining.\n */\n\nimport type { OtelExporter } from '../otel-export'\nimport { buildLoopOtelSpans, createOtelExporter } from '../otel-export'\nimport type { LoopTraceEmitter, LoopTraceEvent } from '../runtime/types'\n\nexport interface TraceContext {\n /** Trace id inherited from the parent process, or a fresh one. */\n traceId: string\n /** Parent span id from the delegation that launched this MCP server. */\n parentSpanId?: string\n}\n\n/**\n * Read trace context from the process environment.\n * Returns a context with inherited ids or a freshly generated root.\n */\nexport function readTraceContextFromEnv(): TraceContext {\n const traceId = process.env.TRACE_ID || generateTraceId()\n const parentSpanId = process.env.PARENT_SPAN_ID || undefined\n return { traceId, parentSpanId }\n}\n\n/**\n * Create a LoopTraceEmitter that:\n * 1. Parents all spans under the inherited PARENT_SPAN_ID.\n * 2. Exports spans to OTEL when OTEL_EXPORTER_OTLP_ENDPOINT is set.\n *\n * Returns both the emitter and the optional exporter handle for shutdown.\n */\nexport function createPropagatingTraceEmitter(ctx: TraceContext): {\n emitter: LoopTraceEmitter\n exporter: OtelExporter | undefined\n context: TraceContext\n} {\n const exporter = createOtelExporter()\n\n // Buffer events per loop run, then emit the full nested span tree on\n // `loop.ended` so the topology hierarchy (loop → round → branch) reaches the\n // OTLP collector — not a flat list of zero-duration point spans. A run that\n // never reaches `loop.ended` (hard abort) drops its buffer; acceptable for\n // the short-lived MCP subprocess.\n const buffers = new Map<string, LoopTraceEvent[]>()\n\n const emitter: LoopTraceEmitter = {\n emit(event: LoopTraceEvent) {\n if (!exporter) return\n const buf = buffers.get(event.runId)\n if (buf) buf.push(event)\n else buffers.set(event.runId, [event])\n if (event.kind === 'loop.ended') {\n const events = buffers.get(event.runId) ?? [event]\n buffers.delete(event.runId)\n for (const span of buildLoopOtelSpans(events, ctx.traceId, ctx.parentSpanId)) {\n exporter.exportSpan(span)\n }\n }\n },\n }\n\n return { emitter, exporter, context: ctx }\n}\n\n/**\n * Build env vars to pass to a child MCP subprocess so it inherits the\n * current trace context.\n */\nexport function traceContextToEnv(ctx: TraceContext): Record<string, string> {\n const env: Record<string, string> = { TRACE_ID: ctx.traceId }\n if (ctx.parentSpanId) env.PARENT_SPAN_ID = ctx.parentSpanId\n return env\n}\n\nfunction generateTraceId(): string {\n const bytes = new Uint8Array(16)\n if (typeof globalThis.crypto?.getRandomValues === 'function') {\n globalThis.crypto.getRandomValues(bytes)\n } else {\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256)\n }\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-DVQGYDN5.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// src/profiles/coder.ts
|
|
2
|
-
var DEFAULT_MAX_DIFF_LINES = 400;
|
|
3
|
-
var DEFAULT_CODER_SYSTEM_PROMPT = [
|
|
4
|
-
"You are a coder agent operating inside an isolated sandbox workspace.",
|
|
5
|
-
"Your job is to deliver a minimal, correct patch for the user-supplied goal.",
|
|
6
|
-
"",
|
|
7
|
-
"Hard rules:",
|
|
8
|
-
" 1. Work on a fresh branch off the supplied base. Do not mutate the base branch.",
|
|
9
|
-
" 2. Never touch a forbidden path. The user will list them explicitly.",
|
|
10
|
-
" 3. Keep the diff under the max-diff cap. Prefer the smallest change that ships.",
|
|
11
|
-
" 4. Run the supplied test and typecheck commands before declaring done.",
|
|
12
|
-
" 5. If either command fails, fix the cause \u2014 do not weaken the test or hide the error.",
|
|
13
|
-
"",
|
|
14
|
-
"When you finish, emit a single final structured message of the shape:",
|
|
15
|
-
" ```json",
|
|
16
|
-
' { "branch": "<branch-name>",',
|
|
17
|
-
' "patch": "<unified-diff>",',
|
|
18
|
-
' "testResult": { "passed": <bool>, "output": "<stdout/stderr>" },',
|
|
19
|
-
' "typecheckResult": { "passed": <bool>, "output": "<stdout/stderr>" },',
|
|
20
|
-
' "diffStats": { "filesChanged": <int>, "insertions": <int>, "deletions": <int> },',
|
|
21
|
-
' "reviewerNotes": "<optional commentary>" }',
|
|
22
|
-
" ```"
|
|
23
|
-
].join("\n");
|
|
24
|
-
var coderProfile = {
|
|
25
|
-
name: "coder",
|
|
26
|
-
description: "Code-modification agent. Minimal-diff worktree-based coder.",
|
|
27
|
-
prompt: { systemPrompt: DEFAULT_CODER_SYSTEM_PROMPT },
|
|
28
|
-
tools: { git: true, fs: true, shell: true, test_runner: true },
|
|
29
|
-
metadata: { role: "coder" }
|
|
30
|
-
};
|
|
31
|
-
function coderTaskToPrompt(task) {
|
|
32
|
-
const base = task.baseBranch ?? "main";
|
|
33
|
-
const testCmd = task.testCmd ?? "pnpm test --run";
|
|
34
|
-
const typecheckCmd = task.typecheckCmd ?? "pnpm typecheck";
|
|
35
|
-
const maxDiff = task.maxDiffLines ?? DEFAULT_MAX_DIFF_LINES;
|
|
36
|
-
const forbidden = task.forbiddenPaths?.length ? task.forbiddenPaths.join(", ") : "(none)";
|
|
37
|
-
const context = task.contextFiles?.length ? task.contextFiles.map((f) => ` - ${f}`).join("\n") : " (none)";
|
|
38
|
-
return [
|
|
39
|
-
`Goal: ${task.goal}`,
|
|
40
|
-
`Repo: ${task.repoRoot}`,
|
|
41
|
-
`Base branch: ${base}`,
|
|
42
|
-
`Run tests with: ${testCmd}`,
|
|
43
|
-
`Run typecheck with: ${typecheckCmd}`,
|
|
44
|
-
`Forbidden paths: ${forbidden}`,
|
|
45
|
-
`Max diff lines: ${maxDiff}`,
|
|
46
|
-
"Context files:",
|
|
47
|
-
context,
|
|
48
|
-
"",
|
|
49
|
-
"Produce a minimal patch on a fresh branch. Run tests and typecheck before",
|
|
50
|
-
"returning. Emit the final JSON result block exactly as instructed."
|
|
51
|
-
].join("\n");
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export {
|
|
55
|
-
DEFAULT_CODER_SYSTEM_PROMPT,
|
|
56
|
-
coderProfile,
|
|
57
|
-
coderTaskToPrompt
|
|
58
|
-
};
|
|
59
|
-
//# sourceMappingURL=chunk-DVQGYDN5.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/profiles/coder.ts"],"sourcesContent":["/**\n * @experimental\n *\n * `coderProfile` — the §1.5 author-the-profile DATA for code-modification tasks: an `AgentProfile`\n * constant (the agent IS its profile) plus a pure `coderTaskToPrompt` formatter that renders a\n * `CoderTask` into the per-task instruction. There is no factory, output adapter, or validator\n * here — a domain customizes the worker by authoring a profile + handing it to a leaf executor\n * (`createWorktreeCliExecutor`) or a fanout (`worktreeFanout`), and \"is it delivered\" is a\n * `DeliverableSpec` (`patchDelivered`), not a bundled validator.\n *\n * The standing instruction tells the agent to work on a fresh branch, keep the patch minimal,\n * avoid forbidden paths, and run the test + typecheck commands before declaring done.\n */\n\nimport type { AgentProfile } from '@tangle-network/agent-interface'\n\nconst DEFAULT_MAX_DIFF_LINES = 400\n\n/** @experimental The per-task inputs `coderTaskToPrompt` renders + the worktree gate enforces. */\nexport interface CoderTask {\n /** What the agent must accomplish. Free-form prose. */\n goal: string\n /** Absolute path inside the sandbox where the repo lives. */\n repoRoot: string\n /** Default `main`. The branch the agent diffs against. */\n baseBranch?: string\n /** Default `pnpm test --run`. */\n testCmd?: string\n /** Default `pnpm typecheck`. */\n typecheckCmd?: string\n /** Files the agent may inspect for context. Surfaced verbatim in the prompt. */\n contextFiles?: string[]\n /**\n * Paths the agent must not touch. The mechanical gate hard-fails on any match.\n * Use glob-free literal path prefixes for unambiguous enforcement.\n */\n forbiddenPaths?: string[]\n /** Default 400. Hard cap; the gate hard-fails when exceeded. */\n maxDiffLines?: number\n}\n\n/** @experimental The coder agent's standing instruction (its body lives in `coderProfile.prompt`). */\nexport const DEFAULT_CODER_SYSTEM_PROMPT = [\n 'You are a coder agent operating inside an isolated sandbox workspace.',\n 'Your job is to deliver a minimal, correct patch for the user-supplied goal.',\n '',\n 'Hard rules:',\n ' 1. Work on a fresh branch off the supplied base. Do not mutate the base branch.',\n ' 2. Never touch a forbidden path. The user will list them explicitly.',\n ' 3. Keep the diff under the max-diff cap. Prefer the smallest change that ships.',\n ' 4. Run the supplied test and typecheck commands before declaring done.',\n ' 5. If either command fails, fix the cause — do not weaken the test or hide the error.',\n '',\n 'When you finish, emit a single final structured message of the shape:',\n ' ```json',\n ' { \"branch\": \"<branch-name>\",',\n ' \"patch\": \"<unified-diff>\",',\n ' \"testResult\": { \"passed\": <bool>, \"output\": \"<stdout/stderr>\" },',\n ' \"typecheckResult\": { \"passed\": <bool>, \"output\": \"<stdout/stderr>\" },',\n ' \"diffStats\": { \"filesChanged\": <int>, \"insertions\": <int>, \"deletions\": <int> },',\n ' \"reviewerNotes\": \"<optional commentary>\" }',\n ' ```',\n].join('\\n')\n\n/**\n * @experimental\n *\n * The coder `AgentProfile` — the §1.5 DATA the substrate materializes into a harness invocation.\n * Stateless and harness-agnostic: a consumer overrides `model`/`metadata.backendType` by spreading\n * a copy, never by a factory. `worktreeFanout` authors one such profile per harness leaf.\n */\nexport const coderProfile: AgentProfile = {\n name: 'coder',\n description: 'Code-modification agent. Minimal-diff worktree-based coder.',\n prompt: { systemPrompt: DEFAULT_CODER_SYSTEM_PROMPT },\n tools: { git: true, fs: true, shell: true, test_runner: true },\n metadata: { role: 'coder' },\n}\n\n/** @experimental Render a `CoderTask` into the per-task instruction handed to the coder profile. */\nexport function coderTaskToPrompt(task: CoderTask): string {\n const base = task.baseBranch ?? 'main'\n const testCmd = task.testCmd ?? 'pnpm test --run'\n const typecheckCmd = task.typecheckCmd ?? 'pnpm typecheck'\n const maxDiff = task.maxDiffLines ?? DEFAULT_MAX_DIFF_LINES\n const forbidden = task.forbiddenPaths?.length ? task.forbiddenPaths.join(', ') : '(none)'\n const context = task.contextFiles?.length\n ? task.contextFiles.map((f) => ` - ${f}`).join('\\n')\n : ' (none)'\n return [\n `Goal: ${task.goal}`,\n `Repo: ${task.repoRoot}`,\n `Base branch: ${base}`,\n `Run tests with: ${testCmd}`,\n `Run typecheck with: ${typecheckCmd}`,\n `Forbidden paths: ${forbidden}`,\n `Max diff lines: ${maxDiff}`,\n 'Context files:',\n context,\n '',\n 'Produce a minimal patch on a fresh branch. Run tests and typecheck before',\n 'returning. Emit the final JSON result block exactly as instructed.',\n ].join('\\n')\n}\n"],"mappings":";AAgBA,IAAM,yBAAyB;AA0BxB,IAAM,8BAA8B;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AASJ,IAAM,eAA6B;AAAA,EACxC,MAAM;AAAA,EACN,aAAa;AAAA,EACb,QAAQ,EAAE,cAAc,4BAA4B;AAAA,EACpD,OAAO,EAAE,KAAK,MAAM,IAAI,MAAM,OAAO,MAAM,aAAa,KAAK;AAAA,EAC7D,UAAU,EAAE,MAAM,QAAQ;AAC5B;AAGO,SAAS,kBAAkB,MAAyB;AACzD,QAAM,OAAO,KAAK,cAAc;AAChC,QAAM,UAAU,KAAK,WAAW;AAChC,QAAM,eAAe,KAAK,gBAAgB;AAC1C,QAAM,UAAU,KAAK,gBAAgB;AACrC,QAAM,YAAY,KAAK,gBAAgB,SAAS,KAAK,eAAe,KAAK,IAAI,IAAI;AACjF,QAAM,UAAU,KAAK,cAAc,SAC/B,KAAK,aAAa,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI,IAClD;AACJ,SAAO;AAAA,IACL,SAAS,KAAK,IAAI;AAAA,IAClB,SAAS,KAAK,QAAQ;AAAA,IACtB,gBAAgB,IAAI;AAAA,IACpB,mBAAmB,OAAO;AAAA,IAC1B,uBAAuB,YAAY;AAAA,IACnC,oBAAoB,SAAS;AAAA,IAC7B,mBAAmB,OAAO;AAAA,IAC1B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;","names":[]}
|