opencara 0.104.1 → 0.105.1
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/dist/bin.js +64 -174
- package/dist/claude-acp.js +48 -27
- package/dist/opencara-mcp.js +8 -3
- package/package.json +2 -2
package/dist/bin.js
CHANGED
|
@@ -85,7 +85,8 @@ var AcpSpecSchema = z3.object({
|
|
|
85
85
|
systemPromptMd: z3.string(),
|
|
86
86
|
userPromptMd: z3.string(),
|
|
87
87
|
history: z3.array(AcpHistoryTurnSchema).default([]),
|
|
88
|
-
pageContextJson: z3.string().optional()
|
|
88
|
+
pageContextJson: z3.string().optional(),
|
|
89
|
+
priorSessionId: z3.string().optional()
|
|
89
90
|
});
|
|
90
91
|
var AgentSpecSchema = z3.object({
|
|
91
92
|
kind: z3.string(),
|
|
@@ -184,7 +185,12 @@ var RunDoneSchema = z4.object({
|
|
|
184
185
|
runId: z4.string(),
|
|
185
186
|
status: z4.enum(["succeeded", "failed", "cancelled"]),
|
|
186
187
|
exitCode: z4.number().int().nullable().optional(),
|
|
187
|
-
errorMessage: z4.string().optional()
|
|
188
|
+
errorMessage: z4.string().optional(),
|
|
189
|
+
/** ACP session id the agent ran under (fresh from session/new, or
|
|
190
|
+
* echoed from session/load). The orchestrator persists this per
|
|
191
|
+
* (repo, branch) so the next iteration can resume via session/load.
|
|
192
|
+
* Null/absent for non-ACP runs (worktree-allocate, write-session). */
|
|
193
|
+
acpSessionId: z4.string().nullable().optional()
|
|
188
194
|
});
|
|
189
195
|
var HelloAckSchema = z4.object({
|
|
190
196
|
type: z4.literal("hello-ack"),
|
|
@@ -273,7 +279,6 @@ var DeviceToServerMessageSchema = z4.union([
|
|
|
273
279
|
LogFrameSchema,
|
|
274
280
|
RunDoneSchema,
|
|
275
281
|
PongSchema,
|
|
276
|
-
AgentCallSchema,
|
|
277
282
|
AgentCallRequestSchema
|
|
278
283
|
]);
|
|
279
284
|
var HostRegisterRequestSchema = z4.object({
|
|
@@ -455,9 +460,6 @@ var WsClient = class {
|
|
|
455
460
|
}
|
|
456
461
|
};
|
|
457
462
|
|
|
458
|
-
// src/runner/spawn.ts
|
|
459
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
460
|
-
|
|
461
463
|
// src/runner/acpRunner.ts
|
|
462
464
|
import { existsSync as existsSync3 } from "node:fs";
|
|
463
465
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
@@ -565,6 +567,9 @@ var AcpConnection = class {
|
|
|
565
567
|
newSession(req) {
|
|
566
568
|
return this.request(ACP_METHODS.session_new, req);
|
|
567
569
|
}
|
|
570
|
+
loadSession(req) {
|
|
571
|
+
return this.request(ACP_METHODS.session_load, req);
|
|
572
|
+
}
|
|
568
573
|
prompt(req) {
|
|
569
574
|
return this.request(ACP_METHODS.session_prompt, req);
|
|
570
575
|
}
|
|
@@ -726,6 +731,9 @@ var AcpClient = class {
|
|
|
726
731
|
newSession(req) {
|
|
727
732
|
return this.must().newSession(req);
|
|
728
733
|
}
|
|
734
|
+
loadSession(req) {
|
|
735
|
+
return this.must().loadSession(req);
|
|
736
|
+
}
|
|
729
737
|
prompt(req) {
|
|
730
738
|
return this.must().prompt(req);
|
|
731
739
|
}
|
|
@@ -1069,26 +1077,35 @@ function runAcpJob(opts) {
|
|
|
1069
1077
|
}
|
|
1070
1078
|
};
|
|
1071
1079
|
const promise = (async () => {
|
|
1072
|
-
let result = { exitCode: 1, stopReason: "uninitialized" };
|
|
1080
|
+
let result = { exitCode: 1, stopReason: "uninitialized", sessionId: "" };
|
|
1073
1081
|
try {
|
|
1074
1082
|
await host.start();
|
|
1075
1083
|
client.start();
|
|
1076
|
-
await client.initialize({
|
|
1084
|
+
const initResult = await client.initialize({
|
|
1077
1085
|
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
1078
1086
|
clientCapabilities: {}
|
|
1079
1087
|
});
|
|
1080
|
-
const
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1088
|
+
const cwd = spec.cwd ?? process.cwd();
|
|
1089
|
+
const mcpServers = [host.acpServerEntry()];
|
|
1090
|
+
const shimSupportsLoad = initResult.agentCapabilities?.loadSession === true;
|
|
1091
|
+
let sessionId;
|
|
1092
|
+
if (acpSpec.priorSessionId && shimSupportsLoad) {
|
|
1093
|
+
await client.loadSession({
|
|
1094
|
+
sessionId: acpSpec.priorSessionId,
|
|
1095
|
+
cwd,
|
|
1096
|
+
mcpServers
|
|
1097
|
+
});
|
|
1098
|
+
sessionId = acpSpec.priorSessionId;
|
|
1099
|
+
} else {
|
|
1100
|
+
const session = await client.newSession({ cwd, mcpServers });
|
|
1101
|
+
sessionId = session.sessionId;
|
|
1102
|
+
}
|
|
1084
1103
|
const prompt = buildPromptContent(acpSpec);
|
|
1085
|
-
const promptResult = await client.prompt({
|
|
1086
|
-
sessionId: session.sessionId,
|
|
1087
|
-
prompt
|
|
1088
|
-
});
|
|
1104
|
+
const promptResult = await client.prompt({ sessionId, prompt });
|
|
1089
1105
|
result = {
|
|
1090
1106
|
exitCode: promptResult.stopReason === "end_turn" ? 0 : 1,
|
|
1091
|
-
stopReason: promptResult.stopReason
|
|
1107
|
+
stopReason: promptResult.stopReason,
|
|
1108
|
+
sessionId
|
|
1092
1109
|
};
|
|
1093
1110
|
return result;
|
|
1094
1111
|
} finally {
|
|
@@ -1187,100 +1204,8 @@ function resolveLocalAcpAdapter(command, args) {
|
|
|
1187
1204
|
return { command, args: [...args] };
|
|
1188
1205
|
}
|
|
1189
1206
|
|
|
1190
|
-
// src/runner/spawn.ts
|
|
1191
|
-
function runJob(spec, stdinJson, handlers) {
|
|
1192
|
-
return new Promise((resolve, reject) => {
|
|
1193
|
-
const child = spawn3(spec.command, spec.args ?? [], {
|
|
1194
|
-
env: { ...process.env, ...spec.env ?? {} },
|
|
1195
|
-
cwd: spec.cwd,
|
|
1196
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1197
|
-
});
|
|
1198
|
-
child.stdout.setEncoding("utf8");
|
|
1199
|
-
child.stderr.setEncoding("utf8");
|
|
1200
|
-
child.stdout.on("data", (c) => handlers.onLog("stdout", c));
|
|
1201
|
-
child.stderr.on("data", (c) => handlers.onLog("stderr", c));
|
|
1202
|
-
child.on("error", reject);
|
|
1203
|
-
child.on("close", (code) => resolve({ exitCode: code ?? -1 }));
|
|
1204
|
-
if (stdinJson !== void 0) {
|
|
1205
|
-
try {
|
|
1206
|
-
child.stdin.end(JSON.stringify(stdinJson));
|
|
1207
|
-
} catch (err) {
|
|
1208
|
-
child.kill();
|
|
1209
|
-
reject(err);
|
|
1210
|
-
return;
|
|
1211
|
-
}
|
|
1212
|
-
} else {
|
|
1213
|
-
child.stdin.end();
|
|
1214
|
-
}
|
|
1215
|
-
});
|
|
1216
|
-
}
|
|
1217
|
-
|
|
1218
|
-
// src/runner/agentCallParser.ts
|
|
1219
|
-
import { z as z6 } from "zod";
|
|
1220
|
-
var MAX_BUFFER_BYTES = 64 * 1024;
|
|
1221
|
-
var FENCE_RE = /```opencara-call\r?\n([\s\S]*?)\r?\n```/;
|
|
1222
|
-
var VARIANT_SCHEMAS = {
|
|
1223
|
-
"issue.body.set": IssueBodySetCallSchema.omit({ type: true, runId: true }),
|
|
1224
|
-
"flow.node.config.set": FlowNodeConfigSetCallSchema.omit({
|
|
1225
|
-
type: true,
|
|
1226
|
-
runId: true
|
|
1227
|
-
}),
|
|
1228
|
-
"template.node.config.set": TemplateNodeConfigSetCallSchema.omit({
|
|
1229
|
-
type: true,
|
|
1230
|
-
runId: true
|
|
1231
|
-
})
|
|
1232
|
-
};
|
|
1233
|
-
var KindSchema = z6.enum([
|
|
1234
|
-
"issue.body.set",
|
|
1235
|
-
"flow.node.config.set",
|
|
1236
|
-
"template.node.config.set"
|
|
1237
|
-
]);
|
|
1238
|
-
var AgentCallParser = class {
|
|
1239
|
-
constructor(emit) {
|
|
1240
|
-
this.emit = emit;
|
|
1241
|
-
}
|
|
1242
|
-
emit;
|
|
1243
|
-
buffer = "";
|
|
1244
|
-
feed(chunk) {
|
|
1245
|
-
this.buffer += chunk;
|
|
1246
|
-
if (this.buffer.length > MAX_BUFFER_BYTES) {
|
|
1247
|
-
const cutoff = Math.floor(MAX_BUFFER_BYTES / 2);
|
|
1248
|
-
const nl = this.buffer.indexOf("\n", this.buffer.length - cutoff);
|
|
1249
|
-
this.buffer = nl >= 0 ? this.buffer.slice(nl + 1) : this.buffer.slice(-cutoff);
|
|
1250
|
-
}
|
|
1251
|
-
while (true) {
|
|
1252
|
-
const m = FENCE_RE.exec(this.buffer);
|
|
1253
|
-
if (!m) break;
|
|
1254
|
-
const inner = m[1] ?? "";
|
|
1255
|
-
const consumedTo = m.index + m[0].length;
|
|
1256
|
-
this.buffer = this.buffer.slice(consumedTo);
|
|
1257
|
-
this.tryEmit(inner);
|
|
1258
|
-
}
|
|
1259
|
-
}
|
|
1260
|
-
tryEmit(inner) {
|
|
1261
|
-
let parsed;
|
|
1262
|
-
try {
|
|
1263
|
-
parsed = JSON.parse(inner);
|
|
1264
|
-
} catch {
|
|
1265
|
-
return;
|
|
1266
|
-
}
|
|
1267
|
-
if (!parsed || typeof parsed !== "object") return;
|
|
1268
|
-
const raw = parsed;
|
|
1269
|
-
const kindResult = KindSchema.safeParse(raw.kind);
|
|
1270
|
-
if (!kindResult.success) return;
|
|
1271
|
-
const withCallId = {
|
|
1272
|
-
...raw,
|
|
1273
|
-
callId: typeof raw.callId === "string" && raw.callId.length > 0 ? raw.callId : `call_${Date.now().toString(36)}`
|
|
1274
|
-
};
|
|
1275
|
-
const schema = VARIANT_SCHEMAS[kindResult.data];
|
|
1276
|
-
const result = schema.safeParse(withCallId);
|
|
1277
|
-
if (!result.success) return;
|
|
1278
|
-
this.emit(result.data);
|
|
1279
|
-
}
|
|
1280
|
-
};
|
|
1281
|
-
|
|
1282
1207
|
// src/commands/run.ts
|
|
1283
|
-
var PKG_VERSION = "0.
|
|
1208
|
+
var PKG_VERSION = "0.105.1";
|
|
1284
1209
|
var LOG_FLUSH_MS = 800;
|
|
1285
1210
|
var MAX_CHUNK_SIZE = 4 * 1024;
|
|
1286
1211
|
async function run(opts = {}) {
|
|
@@ -1300,12 +1225,11 @@ async function run(opts = {}) {
|
|
|
1300
1225
|
type: "hello",
|
|
1301
1226
|
platform: platform(),
|
|
1302
1227
|
version: PKG_VERSION,
|
|
1303
|
-
// Advertise
|
|
1304
|
-
//
|
|
1305
|
-
//
|
|
1306
|
-
//
|
|
1307
|
-
|
|
1308
|
-
capabilities: ["agent-call"],
|
|
1228
|
+
// Advertise ACP transport support. Pre-v0.30 devices reported
|
|
1229
|
+
// "agent-call" (the fenced-stdout-block protocol); since the
|
|
1230
|
+
// legacy path was removed, this version reports "acp" so the
|
|
1231
|
+
// orchestrator knows the device can handle `spec.acp` jobs.
|
|
1232
|
+
capabilities: ["acp"],
|
|
1309
1233
|
systemInfo: collectSystemInfo()
|
|
1310
1234
|
});
|
|
1311
1235
|
},
|
|
@@ -1357,79 +1281,45 @@ async function executeJob(job, client) {
|
|
|
1357
1281
|
if (flushTimer) return;
|
|
1358
1282
|
flushTimer = setTimeout(flush, LOG_FLUSH_MS);
|
|
1359
1283
|
};
|
|
1360
|
-
if (job.spec.acp) {
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
onLog: (stream, chunk) => {
|
|
1366
|
-
pending[stream] += chunk;
|
|
1367
|
-
scheduleFlush();
|
|
1368
|
-
},
|
|
1369
|
-
sendAgentCall: (req) => client.send(req)
|
|
1370
|
-
}
|
|
1371
|
-
});
|
|
1372
|
-
acpControllers.set(runId, handle.controller);
|
|
1373
|
-
try {
|
|
1374
|
-
const result = await handle.promise;
|
|
1375
|
-
flush();
|
|
1376
|
-
client.send({
|
|
1377
|
-
type: "done",
|
|
1378
|
-
runId,
|
|
1379
|
-
status: result.exitCode === 0 ? "succeeded" : "failed",
|
|
1380
|
-
exitCode: result.exitCode
|
|
1381
|
-
});
|
|
1382
|
-
console.log(
|
|
1383
|
-
`[opencara] job ${runId.slice(-8)} (acp) \u2192 ${result.stopReason} exit=${result.exitCode}`
|
|
1384
|
-
);
|
|
1385
|
-
} catch (err) {
|
|
1386
|
-
flush();
|
|
1387
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1388
|
-
client.send({ type: "done", runId, status: "failed", errorMessage: message });
|
|
1389
|
-
console.error(`[opencara] job ${runId.slice(-8)} (acp) failed`, message);
|
|
1390
|
-
} finally {
|
|
1391
|
-
acpControllers.delete(runId);
|
|
1392
|
-
}
|
|
1284
|
+
if (!job.spec.acp) {
|
|
1285
|
+
flush();
|
|
1286
|
+
const message = `legacy stdin-JSON dispatch removed in v0.30 \u2014 orchestrator must send spec.acp. Got command: ${job.spec.command}.`;
|
|
1287
|
+
client.send({ type: "done", runId, status: "failed", errorMessage: message });
|
|
1288
|
+
console.error(`[opencara] job ${runId.slice(-8)} rejected: ${message}`);
|
|
1393
1289
|
return;
|
|
1394
1290
|
}
|
|
1395
|
-
const
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
return;
|
|
1400
|
-
case "flow.node.config.set":
|
|
1401
|
-
client.send({ type: "agent-call", runId, ...call });
|
|
1402
|
-
return;
|
|
1403
|
-
case "template.node.config.set":
|
|
1404
|
-
client.send({ type: "agent-call", runId, ...call });
|
|
1405
|
-
return;
|
|
1406
|
-
default: {
|
|
1407
|
-
const exhaustive = call;
|
|
1408
|
-
void exhaustive;
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
});
|
|
1412
|
-
try {
|
|
1413
|
-
const result = await runJob(job.spec, job.stdinJson, {
|
|
1291
|
+
const handle = runAcpJob({
|
|
1292
|
+
runId,
|
|
1293
|
+
spec: job.spec,
|
|
1294
|
+
handlers: {
|
|
1414
1295
|
onLog: (stream, chunk) => {
|
|
1415
1296
|
pending[stream] += chunk;
|
|
1416
1297
|
scheduleFlush();
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
}
|
|
1298
|
+
},
|
|
1299
|
+
sendAgentCall: (req) => client.send(req)
|
|
1300
|
+
}
|
|
1301
|
+
});
|
|
1302
|
+
acpControllers.set(runId, handle.controller);
|
|
1303
|
+
try {
|
|
1304
|
+
const result = await handle.promise;
|
|
1420
1305
|
flush();
|
|
1421
1306
|
client.send({
|
|
1422
1307
|
type: "done",
|
|
1423
1308
|
runId,
|
|
1424
1309
|
status: result.exitCode === 0 ? "succeeded" : "failed",
|
|
1425
|
-
exitCode: result.exitCode
|
|
1310
|
+
exitCode: result.exitCode,
|
|
1311
|
+
acpSessionId: result.sessionId || null
|
|
1426
1312
|
});
|
|
1427
|
-
console.log(
|
|
1313
|
+
console.log(
|
|
1314
|
+
`[opencara] job ${runId.slice(-8)} (acp) \u2192 ${result.stopReason} exit=${result.exitCode}`
|
|
1315
|
+
);
|
|
1428
1316
|
} catch (err) {
|
|
1429
1317
|
flush();
|
|
1430
1318
|
const message = err instanceof Error ? err.message : String(err);
|
|
1431
1319
|
client.send({ type: "done", runId, status: "failed", errorMessage: message });
|
|
1432
|
-
console.error(`[opencara] job ${runId.slice(-8)} failed`, message);
|
|
1320
|
+
console.error(`[opencara] job ${runId.slice(-8)} (acp) failed`, message);
|
|
1321
|
+
} finally {
|
|
1322
|
+
acpControllers.delete(runId);
|
|
1433
1323
|
}
|
|
1434
1324
|
}
|
|
1435
1325
|
function collectSystemInfo() {
|
package/dist/claude-acp.js
CHANGED
|
@@ -74,23 +74,25 @@ async function runClaudeTurn(sessionId, state, promptText) {
|
|
|
74
74
|
"--include-partial-messages",
|
|
75
75
|
"--verbose",
|
|
76
76
|
"--session-id",
|
|
77
|
-
|
|
77
|
+
sessionId,
|
|
78
78
|
// Headless: no human in the loop to approve tool use. Matches the
|
|
79
79
|
// legacy `claudeAdapter` posture in agents/kinds.ts.
|
|
80
|
-
"--dangerously-skip-permissions"
|
|
81
|
-
promptText
|
|
80
|
+
"--dangerously-skip-permissions"
|
|
82
81
|
];
|
|
83
82
|
const child = spawn("claude", args, {
|
|
84
83
|
cwd: state.cwd,
|
|
85
84
|
env: process.env,
|
|
86
|
-
stdio: ["
|
|
85
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
86
|
+
});
|
|
87
|
+
child.stdin.on("error", () => {
|
|
87
88
|
});
|
|
88
|
-
|
|
89
|
+
child.stdin.end(promptText);
|
|
90
|
+
const decoder = new FrameDecoder();
|
|
89
91
|
let resolved = false;
|
|
90
92
|
let stopReason = "end_turn";
|
|
91
93
|
child.stdout.setEncoding("utf8");
|
|
92
94
|
child.stdout.on("data", (chunk) => {
|
|
93
|
-
const { messages, malformed } =
|
|
95
|
+
const { messages, malformed } = decoder.feed(chunk);
|
|
94
96
|
for (const line of malformed) {
|
|
95
97
|
stderr.write(`[claude-acp] malformed: ${line}
|
|
96
98
|
`);
|
|
@@ -189,10 +191,12 @@ function handleInitialize(_params) {
|
|
|
189
191
|
version: "0.0.1"
|
|
190
192
|
},
|
|
191
193
|
agentCapabilities: {
|
|
192
|
-
//
|
|
193
|
-
//
|
|
194
|
-
//
|
|
195
|
-
|
|
194
|
+
// Session resume works by passing the ACP sessionId back as
|
|
195
|
+
// `claude --session-id <uuid>` on the next prompt — Claude CLI
|
|
196
|
+
// replays its own JSONL internally. MCP via stdio is not yet
|
|
197
|
+
// propagated from ACP's mcpServers config (the `claude` CLI uses
|
|
198
|
+
// settings.json for that today; bridging is a separate change).
|
|
199
|
+
loadSession: true,
|
|
196
200
|
mcpCapabilities: {},
|
|
197
201
|
promptCapabilities: { embeddedContext: false, image: false, audio: false }
|
|
198
202
|
},
|
|
@@ -201,12 +205,16 @@ function handleInitialize(_params) {
|
|
|
201
205
|
}
|
|
202
206
|
function handleNewSession(params) {
|
|
203
207
|
const sessionId = randomUUID();
|
|
204
|
-
sessions.set(sessionId, {
|
|
205
|
-
claudeSessionId: randomUUID(),
|
|
206
|
-
cwd: params.cwd ?? process.cwd()
|
|
207
|
-
});
|
|
208
|
+
sessions.set(sessionId, { cwd: params.cwd ?? process.cwd() });
|
|
208
209
|
return { sessionId };
|
|
209
210
|
}
|
|
211
|
+
function handleLoadSession(params) {
|
|
212
|
+
if (typeof params.sessionId !== "string" || params.sessionId.length === 0) {
|
|
213
|
+
throw new Error("session/load: sessionId required");
|
|
214
|
+
}
|
|
215
|
+
sessions.set(params.sessionId, { cwd: params.cwd ?? process.cwd() });
|
|
216
|
+
return {};
|
|
217
|
+
}
|
|
210
218
|
async function handlePrompt(params) {
|
|
211
219
|
const state = sessions.get(params.sessionId);
|
|
212
220
|
if (!state) {
|
|
@@ -219,19 +227,22 @@ async function handlePrompt(params) {
|
|
|
219
227
|
const result = await runClaudeTurn(params.sessionId, state, promptText);
|
|
220
228
|
return { stopReason: result.stopReason };
|
|
221
229
|
}
|
|
222
|
-
var
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
230
|
+
var isMainModule = import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("claude-acp.ts") === true || process.argv[1]?.endsWith("claude-acp.js") === true;
|
|
231
|
+
if (isMainModule) {
|
|
232
|
+
const decoder = new FrameDecoder();
|
|
233
|
+
stdin.setEncoding("utf8");
|
|
234
|
+
stdin.on("data", (chunk) => {
|
|
235
|
+
const { messages, malformed } = decoder.feed(chunk);
|
|
236
|
+
for (const line of malformed) {
|
|
237
|
+
stderr.write(`[claude-acp] malformed inbound: ${line}
|
|
228
238
|
`);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
});
|
|
232
|
-
stdin.on("end", () => {
|
|
233
|
-
|
|
234
|
-
});
|
|
239
|
+
}
|
|
240
|
+
for (const msg of messages) void dispatch(msg);
|
|
241
|
+
});
|
|
242
|
+
stdin.on("end", () => {
|
|
243
|
+
exit(0);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
235
246
|
async function dispatch(msg) {
|
|
236
247
|
if (!("id" in msg) || msg.id == null) return;
|
|
237
248
|
if ("result" in msg || "error" in msg) return;
|
|
@@ -244,6 +255,9 @@ async function dispatch(msg) {
|
|
|
244
255
|
case "session/new":
|
|
245
256
|
reply(req.id, handleNewSession(req.params));
|
|
246
257
|
return;
|
|
258
|
+
case "session/load":
|
|
259
|
+
reply(req.id, handleLoadSession(req.params));
|
|
260
|
+
return;
|
|
247
261
|
case "session/prompt": {
|
|
248
262
|
const result = await handlePrompt(req.params);
|
|
249
263
|
reply(req.id, result);
|
|
@@ -258,10 +272,17 @@ async function dispatch(msg) {
|
|
|
258
272
|
}
|
|
259
273
|
} catch (err) {
|
|
260
274
|
const message = err instanceof Error ? err.message : String(err);
|
|
275
|
+
const isParamsError = err instanceof Error && (message.startsWith("session/prompt:") || message.startsWith("session/load:"));
|
|
261
276
|
replyError(
|
|
262
277
|
req.id,
|
|
263
|
-
|
|
278
|
+
isParamsError ? JSON_RPC_ERROR_INVALID_PARAMS : JSON_RPC_ERROR_INTERNAL,
|
|
264
279
|
message
|
|
265
280
|
);
|
|
266
281
|
}
|
|
267
282
|
}
|
|
283
|
+
export {
|
|
284
|
+
handleInitialize,
|
|
285
|
+
handleLoadSession,
|
|
286
|
+
handleNewSession,
|
|
287
|
+
sessions
|
|
288
|
+
};
|
package/dist/opencara-mcp.js
CHANGED
|
@@ -127,7 +127,8 @@ var AcpSpecSchema = z2.object({
|
|
|
127
127
|
systemPromptMd: z2.string(),
|
|
128
128
|
userPromptMd: z2.string(),
|
|
129
129
|
history: z2.array(AcpHistoryTurnSchema).default([]),
|
|
130
|
-
pageContextJson: z2.string().optional()
|
|
130
|
+
pageContextJson: z2.string().optional(),
|
|
131
|
+
priorSessionId: z2.string().optional()
|
|
131
132
|
});
|
|
132
133
|
var AgentSpecSchema = z2.object({
|
|
133
134
|
kind: z2.string(),
|
|
@@ -226,7 +227,12 @@ var RunDoneSchema = z3.object({
|
|
|
226
227
|
runId: z3.string(),
|
|
227
228
|
status: z3.enum(["succeeded", "failed", "cancelled"]),
|
|
228
229
|
exitCode: z3.number().int().nullable().optional(),
|
|
229
|
-
errorMessage: z3.string().optional()
|
|
230
|
+
errorMessage: z3.string().optional(),
|
|
231
|
+
/** ACP session id the agent ran under (fresh from session/new, or
|
|
232
|
+
* echoed from session/load). The orchestrator persists this per
|
|
233
|
+
* (repo, branch) so the next iteration can resume via session/load.
|
|
234
|
+
* Null/absent for non-ACP runs (worktree-allocate, write-session). */
|
|
235
|
+
acpSessionId: z3.string().nullable().optional()
|
|
230
236
|
});
|
|
231
237
|
var HelloAckSchema = z3.object({
|
|
232
238
|
type: z3.literal("hello-ack"),
|
|
@@ -315,7 +321,6 @@ var DeviceToServerMessageSchema = z3.union([
|
|
|
315
321
|
LogFrameSchema,
|
|
316
322
|
RunDoneSchema,
|
|
317
323
|
PongSchema,
|
|
318
|
-
AgentCallSchema,
|
|
319
324
|
AgentCallRequestSchema
|
|
320
325
|
]);
|
|
321
326
|
var HostRegisterRequestSchema = z3.object({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencara",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.105.1",
|
|
4
4
|
"description": "OpenCara agent-host CLI: register a machine as an agent host and run dispatched agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"dev": "tsx watch src/bin.ts",
|
|
39
39
|
"start": "node dist/bin.js",
|
|
40
40
|
"typecheck": "tsc -b",
|
|
41
|
-
"test": "node --import tsx --test --test-reporter=spec src/acp/__tests__/*.test.ts src/mcp/__tests__/*.test.ts src/runner/__tests__/*.test.ts",
|
|
41
|
+
"test": "node --import tsx --test --test-reporter=spec src/acp/__tests__/*.test.ts src/mcp/__tests__/*.test.ts src/runner/__tests__/*.test.ts src/bin/__tests__/*.test.ts",
|
|
42
42
|
"acp:spike": "tsx src/acp/spike.ts",
|
|
43
43
|
"mcp:smoke": "tsx src/mcp/smoke.ts",
|
|
44
44
|
"clean": "rm -rf dist *.tsbuildinfo"
|