opencara 0.108.0 → 0.108.2

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 CHANGED
@@ -1153,6 +1153,7 @@ function runAcpJob(opts) {
1153
1153
  const mcpServers = [host.acpServerEntry()];
1154
1154
  const shimSupportsLoad = initResult.agentCapabilities?.loadSession === true;
1155
1155
  let sessionId;
1156
+ let resumed = false;
1156
1157
  if (acpSpec.priorSessionId && shimSupportsLoad) {
1157
1158
  await client.loadSession({
1158
1159
  sessionId: acpSpec.priorSessionId,
@@ -1160,6 +1161,7 @@ function runAcpJob(opts) {
1160
1161
  mcpServers
1161
1162
  });
1162
1163
  sessionId = acpSpec.priorSessionId;
1164
+ resumed = true;
1163
1165
  } else {
1164
1166
  const session = await client.newSession({ cwd, mcpServers });
1165
1167
  sessionId = session.sessionId;
@@ -1173,7 +1175,10 @@ function runAcpJob(opts) {
1173
1175
  result = { exitCode: 1, stopReason: "cancelled", sessionId };
1174
1176
  return result;
1175
1177
  }
1176
- const prompt = buildPromptContent(acpSpec);
1178
+ const prompt = buildPromptContent({
1179
+ ...acpSpec,
1180
+ history: resumed ? [] : acpSpec.history
1181
+ });
1177
1182
  const promptResult = await client.prompt({
1178
1183
  sessionId,
1179
1184
  prompt,
@@ -1307,7 +1312,7 @@ function resolveLocalAcpAdapter(command, args) {
1307
1312
  }
1308
1313
 
1309
1314
  // src/commands/run.ts
1310
- var PKG_VERSION = "0.108.0";
1315
+ var PKG_VERSION = "0.108.2";
1311
1316
  var LOG_FLUSH_MS = 800;
1312
1317
  var MAX_CHUNK_SIZE = 4 * 1024;
1313
1318
  async function run(opts = {}) {
@@ -1683,20 +1688,34 @@ function worktreeCreate(args) {
1683
1688
  mkdirSync2(join2(cacheDir, ".git", "lfs", "objects"), { recursive: true });
1684
1689
  }
1685
1690
  }
1691
+ let reused = false;
1686
1692
  if (existsSync4(join2(checkoutDir, ".git"))) {
1687
- git(checkoutDir, ["fetch", "origin"], gitEnv);
1688
- if (refExists(checkoutDir, `refs/remotes/origin/${branch}`)) {
1689
- git(checkoutDir, ["checkout", "-B", branch, `origin/${branch}`], gitEnv);
1690
- } else if (refExists(checkoutDir, `refs/heads/${branch}`)) {
1691
- git(checkoutDir, ["checkout", branch], gitEnv);
1692
- } else if (fromBranch) {
1693
- git(checkoutDir, ["checkout", "-B", branch, `origin/${fromBranch}`], gitEnv);
1694
- } else {
1695
- fail(
1696
- `worktree create: '${branch}' missing locally and on origin/, no --from-branch to fall back to`
1693
+ try {
1694
+ git(checkoutDir, ["reset", "--hard", "HEAD"], gitEnv);
1695
+ git(checkoutDir, ["clean", "-fdx"], gitEnv);
1696
+ git(checkoutDir, ["fetch", "origin"], gitEnv);
1697
+ if (refExists(checkoutDir, `refs/remotes/origin/${branch}`)) {
1698
+ git(checkoutDir, ["checkout", "-B", branch, `origin/${branch}`], gitEnv);
1699
+ } else if (refExists(checkoutDir, `refs/heads/${branch}`)) {
1700
+ git(checkoutDir, ["checkout", branch], gitEnv);
1701
+ } else if (fromBranch) {
1702
+ git(checkoutDir, ["checkout", "-B", branch, `origin/${fromBranch}`], gitEnv);
1703
+ } else {
1704
+ fail(
1705
+ `worktree create: '${branch}' missing locally and on origin/, no --from-branch to fall back to`
1706
+ );
1707
+ }
1708
+ reused = true;
1709
+ } catch (err) {
1710
+ console.warn(
1711
+ `[worktree] reuse of ${checkoutDir} failed (${err.message}); re-cloning`
1697
1712
  );
1713
+ rmSync(checkoutDir, { recursive: true, force: true });
1698
1714
  }
1699
- } else {
1715
+ } else if (existsSync4(checkoutDir)) {
1716
+ rmSync(checkoutDir, { recursive: true, force: true });
1717
+ }
1718
+ if (!reused) {
1700
1719
  mkdirSync2(checkoutDir, { recursive: true });
1701
1720
  const cloneArgs = ["-c", `credential.helper=${HELPER_SNIPPET}`, "clone"];
1702
1721
  if (cacheDir) {
@@ -61,6 +61,43 @@ function replyError(id, code, message) {
61
61
  function notify(method, params) {
62
62
  send({ jsonrpc: "2.0", method, params });
63
63
  }
64
+ function normalizeMcpServers(raw) {
65
+ if (!Array.isArray(raw)) return [];
66
+ const out = [];
67
+ for (const entry of raw) {
68
+ if (!entry || typeof entry !== "object") continue;
69
+ const e = entry;
70
+ if (e["type"] !== "stdio") continue;
71
+ if (typeof e["name"] !== "string" || typeof e["command"] !== "string") continue;
72
+ const args = Array.isArray(e["args"]) ? e["args"].map(String) : [];
73
+ const env = [];
74
+ if (Array.isArray(e["env"])) {
75
+ for (const kv of e["env"]) {
76
+ if (!kv || typeof kv !== "object") continue;
77
+ const r = kv;
78
+ if (typeof r["name"] !== "string" || typeof r["value"] !== "string") continue;
79
+ env.push({ name: r["name"], value: r["value"] });
80
+ }
81
+ }
82
+ out.push({
83
+ type: "stdio",
84
+ name: e["name"],
85
+ command: e["command"],
86
+ args,
87
+ env
88
+ });
89
+ }
90
+ return out;
91
+ }
92
+ function buildClaudeMcpConfig(servers) {
93
+ const mcpServers = {};
94
+ for (const s of servers) {
95
+ const env = {};
96
+ for (const kv of s.env) env[kv.name] = kv.value;
97
+ mcpServers[s.name] = { command: s.command, args: s.args, env };
98
+ }
99
+ return JSON.stringify({ mcpServers });
100
+ }
64
101
  var sessions = /* @__PURE__ */ new Map();
65
102
  async function runClaudeTurn(sessionId, state, promptText, permissionMode) {
66
103
  return new Promise((resolve, reject) => {
@@ -82,6 +119,13 @@ async function runClaudeTurn(sessionId, state, promptText, permissionMode) {
82
119
  } else {
83
120
  args.push("--dangerously-skip-permissions");
84
121
  }
122
+ if (state.mcpServers && state.mcpServers.length > 0) {
123
+ args.push(
124
+ "--mcp-config",
125
+ buildClaudeMcpConfig(state.mcpServers),
126
+ "--strict-mcp-config"
127
+ );
128
+ }
85
129
  const child = spawn("claude", args, {
86
130
  cwd: state.cwd,
87
131
  env: process.env,
@@ -202,9 +246,9 @@ function handleInitialize(_params) {
202
246
  agentCapabilities: {
203
247
  // Session resume works by passing the ACP sessionId back as
204
248
  // `claude --session-id <uuid>` on the next prompt — Claude CLI
205
- // replays its own JSONL internally. MCP via stdio is not yet
206
- // propagated from ACP's mcpServers config (the `claude` CLI uses
207
- // settings.json for that today; bridging is a separate change).
249
+ // replays its own JSONL internally. ACP's mcpServers are bridged
250
+ // to Claude via `--mcp-config <inline-json> --strict-mcp-config`
251
+ // on each turn (see SessionState.mcpServers / runClaudeTurn).
208
252
  loadSession: true,
209
253
  mcpCapabilities: {},
210
254
  promptCapabilities: { embeddedContext: false, image: false, audio: false }
@@ -214,14 +258,24 @@ function handleInitialize(_params) {
214
258
  }
215
259
  function handleNewSession(params) {
216
260
  const sessionId = randomUUID();
217
- sessions.set(sessionId, { cwd: params.cwd ?? process.cwd(), resume: false });
261
+ const mcpServers = normalizeMcpServers(params.mcpServers);
262
+ sessions.set(sessionId, {
263
+ cwd: params.cwd ?? process.cwd(),
264
+ resume: false,
265
+ ...mcpServers.length > 0 ? { mcpServers } : {}
266
+ });
218
267
  return { sessionId };
219
268
  }
220
269
  function handleLoadSession(params) {
221
270
  if (typeof params.sessionId !== "string" || params.sessionId.length === 0) {
222
271
  throw new Error("session/load: sessionId required");
223
272
  }
224
- sessions.set(params.sessionId, { cwd: params.cwd ?? process.cwd(), resume: true });
273
+ const mcpServers = normalizeMcpServers(params.mcpServers);
274
+ sessions.set(params.sessionId, {
275
+ cwd: params.cwd ?? process.cwd(),
276
+ resume: true,
277
+ ...mcpServers.length > 0 ? { mcpServers } : {}
278
+ });
225
279
  return {};
226
280
  }
227
281
  async function handlePrompt(params) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencara",
3
- "version": "0.108.0",
3
+ "version": "0.108.2",
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": {