opencara 0.105.3 → 0.106.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/dist/bin.js +117 -37
- package/dist/claude-acp.js +5 -3
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -1070,7 +1070,8 @@ function runAcpJob(opts) {
|
|
|
1070
1070
|
env: spec.env,
|
|
1071
1071
|
cwd: spec.cwd
|
|
1072
1072
|
});
|
|
1073
|
-
|
|
1073
|
+
const translator = createUpdateTranslator(handlers.onLog);
|
|
1074
|
+
client.onSessionUpdate((p) => translator.handle(p.update));
|
|
1074
1075
|
client.onStderr((chunk) => handlers.onLog("stderr", chunk));
|
|
1075
1076
|
const controller = {
|
|
1076
1077
|
onAgentCallResult(msg) {
|
|
@@ -1110,6 +1111,7 @@ function runAcpJob(opts) {
|
|
|
1110
1111
|
};
|
|
1111
1112
|
return result;
|
|
1112
1113
|
} finally {
|
|
1114
|
+
translator.flush();
|
|
1113
1115
|
bridge.shutdown("acp run ended");
|
|
1114
1116
|
await Promise.race([
|
|
1115
1117
|
host.stop().catch(() => void 0),
|
|
@@ -1152,37 +1154,61 @@ ${turns}`);
|
|
|
1152
1154
|
${acp.userPromptMd}`);
|
|
1153
1155
|
return [{ type: "text", text: parts.join("\n\n---\n\n") }];
|
|
1154
1156
|
}
|
|
1155
|
-
function
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1157
|
+
function createUpdateTranslator(onLog) {
|
|
1158
|
+
let inThought = false;
|
|
1159
|
+
const enterThought = () => {
|
|
1160
|
+
if (!inThought) {
|
|
1161
|
+
onLog("stdout", "\n[think]\n");
|
|
1162
|
+
inThought = true;
|
|
1159
1163
|
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
if (
|
|
1163
|
-
onLog("stdout",
|
|
1164
|
-
|
|
1164
|
+
};
|
|
1165
|
+
const leaveThought = () => {
|
|
1166
|
+
if (inThought) {
|
|
1167
|
+
onLog("stdout", "\n[/think]\n");
|
|
1168
|
+
inThought = false;
|
|
1165
1169
|
}
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1170
|
+
};
|
|
1171
|
+
return {
|
|
1172
|
+
handle(update) {
|
|
1173
|
+
if (isMessageChunk(update)) {
|
|
1174
|
+
if (update.sessionUpdate === "user_message_chunk") {
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
const text = textOfContent(update.content);
|
|
1178
|
+
if (!text) return;
|
|
1179
|
+
if (update.sessionUpdate === "agent_thought_chunk") {
|
|
1180
|
+
enterThought();
|
|
1181
|
+
onLog("stdout", text);
|
|
1182
|
+
return;
|
|
1183
|
+
}
|
|
1184
|
+
leaveThought();
|
|
1185
|
+
onLog("stdout", text);
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
if (isToolCallStart(update)) {
|
|
1189
|
+
leaveThought();
|
|
1190
|
+
const status2 = update.status ?? "?";
|
|
1191
|
+
onLog("stdout", `
|
|
1172
1192
|
[tool] ${update.title} (${status2})
|
|
1173
1193
|
`);
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
if (isToolCallProgress(update)) {
|
|
1197
|
+
leaveThought();
|
|
1198
|
+
const status2 = update.status ?? "?";
|
|
1199
|
+
const title = update.title ?? "(tool)";
|
|
1200
|
+
onLog("stdout", `
|
|
1180
1201
|
[tool] ${title} \u2192 ${status2}
|
|
1181
1202
|
`);
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
onLog("stderr", `[acp] unmodeled update: ${update.sessionUpdate}
|
|
1185
1206
|
`);
|
|
1207
|
+
},
|
|
1208
|
+
flush() {
|
|
1209
|
+
leaveThought();
|
|
1210
|
+
}
|
|
1211
|
+
};
|
|
1186
1212
|
}
|
|
1187
1213
|
function textOfContent(content) {
|
|
1188
1214
|
if (content.type !== "text") return "";
|
|
@@ -1206,7 +1232,7 @@ function resolveLocalAcpAdapter(command, args) {
|
|
|
1206
1232
|
}
|
|
1207
1233
|
|
|
1208
1234
|
// src/commands/run.ts
|
|
1209
|
-
var PKG_VERSION = "0.
|
|
1235
|
+
var PKG_VERSION = "0.106.0";
|
|
1210
1236
|
var LOG_FLUSH_MS = 800;
|
|
1211
1237
|
var MAX_CHUNK_SIZE = 4 * 1024;
|
|
1212
1238
|
async function run(opts = {}) {
|
|
@@ -1479,13 +1505,15 @@ import {
|
|
|
1479
1505
|
existsSync as existsSync4,
|
|
1480
1506
|
realpathSync,
|
|
1481
1507
|
writeFileSync as writeFileSync2,
|
|
1482
|
-
renameSync
|
|
1508
|
+
renameSync,
|
|
1509
|
+
symlinkSync
|
|
1483
1510
|
} from "node:fs";
|
|
1484
1511
|
import { homedir as homedir2 } from "node:os";
|
|
1485
1512
|
import { join as join2, sep } from "node:path";
|
|
1486
1513
|
var OPENCARA_ROOT = join2(homedir2(), ".opencara");
|
|
1487
1514
|
var WORK_ROOT = join2(OPENCARA_ROOT, "work");
|
|
1488
1515
|
var SESSION_ROOT = join2(OPENCARA_ROOT, "sessions");
|
|
1516
|
+
var CACHE_ROOT = join2(OPENCARA_ROOT, "cache");
|
|
1489
1517
|
async function internal(argv) {
|
|
1490
1518
|
const sub = argv[0];
|
|
1491
1519
|
const rest = argv.slice(1);
|
|
@@ -1528,17 +1556,51 @@ function worktreeCreate(args) {
|
|
|
1528
1556
|
if (!key) fail(`invalid --key '${rawKey}'`);
|
|
1529
1557
|
const sessionDir = join2(SESSION_ROOT, key);
|
|
1530
1558
|
const checkoutDir = join2(WORK_ROOT, key, "checkout");
|
|
1559
|
+
const useCache = hasFlag(args, "--cache-repo");
|
|
1560
|
+
const useLfs = hasFlag(args, "--lfs");
|
|
1561
|
+
if (useLfs && !useCache) {
|
|
1562
|
+
fail("--lfs requires --cache-repo");
|
|
1563
|
+
}
|
|
1564
|
+
const cacheDir = useCache ? join2(CACHE_ROOT, safeKey(repo)) : null;
|
|
1565
|
+
const gitEnv = useCache && !useLfs ? { ...process.env, GIT_LFS_SKIP_SMUDGE: "1" } : void 0;
|
|
1531
1566
|
const HELPER_SNIPPET = '!f() { echo username=x-access-token; echo "password=$GH_TOKEN"; }; f';
|
|
1532
1567
|
const cleanUrl = `https://github.com/${repo}.git`;
|
|
1533
1568
|
mkdirSync2(sessionDir, { recursive: true });
|
|
1569
|
+
if (cacheDir) {
|
|
1570
|
+
if (existsSync4(join2(cacheDir, ".git"))) {
|
|
1571
|
+
git(cacheDir, ["fetch", "--all", "--prune"], gitEnv);
|
|
1572
|
+
} else {
|
|
1573
|
+
mkdirSync2(cacheDir, { recursive: true });
|
|
1574
|
+
try {
|
|
1575
|
+
git(
|
|
1576
|
+
cacheDir,
|
|
1577
|
+
["-c", `credential.helper=${HELPER_SNIPPET}`, "clone", cleanUrl, "."],
|
|
1578
|
+
gitEnv
|
|
1579
|
+
);
|
|
1580
|
+
git(cacheDir, ["config", "credential.helper", HELPER_SNIPPET]);
|
|
1581
|
+
} catch (err) {
|
|
1582
|
+
try {
|
|
1583
|
+
if (!existsSync4(join2(cacheDir, ".git", "HEAD"))) {
|
|
1584
|
+
rmSync(cacheDir, { recursive: true, force: true });
|
|
1585
|
+
}
|
|
1586
|
+
} catch {
|
|
1587
|
+
}
|
|
1588
|
+
throw err;
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
if (useLfs) {
|
|
1592
|
+
git(cacheDir, ["lfs", "fetch", "--all"], gitEnv);
|
|
1593
|
+
mkdirSync2(join2(cacheDir, ".git", "lfs", "objects"), { recursive: true });
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1534
1596
|
if (existsSync4(join2(checkoutDir, ".git"))) {
|
|
1535
|
-
git(checkoutDir, ["fetch", "origin"]);
|
|
1597
|
+
git(checkoutDir, ["fetch", "origin"], gitEnv);
|
|
1536
1598
|
if (refExists(checkoutDir, `refs/remotes/origin/${branch}`)) {
|
|
1537
|
-
git(checkoutDir, ["checkout", "-B", branch, `origin/${branch}`]);
|
|
1599
|
+
git(checkoutDir, ["checkout", "-B", branch, `origin/${branch}`], gitEnv);
|
|
1538
1600
|
} else if (refExists(checkoutDir, `refs/heads/${branch}`)) {
|
|
1539
|
-
git(checkoutDir, ["checkout", branch]);
|
|
1601
|
+
git(checkoutDir, ["checkout", branch], gitEnv);
|
|
1540
1602
|
} else if (fromBranch) {
|
|
1541
|
-
git(checkoutDir, ["checkout", "-B", branch, `origin/${fromBranch}`]);
|
|
1603
|
+
git(checkoutDir, ["checkout", "-B", branch, `origin/${fromBranch}`], gitEnv);
|
|
1542
1604
|
} else {
|
|
1543
1605
|
fail(
|
|
1544
1606
|
`worktree create: '${branch}' missing locally and on origin/, no --from-branch to fall back to`
|
|
@@ -1547,18 +1609,29 @@ function worktreeCreate(args) {
|
|
|
1547
1609
|
} else {
|
|
1548
1610
|
mkdirSync2(checkoutDir, { recursive: true });
|
|
1549
1611
|
const cloneArgs = ["-c", `credential.helper=${HELPER_SNIPPET}`, "clone"];
|
|
1612
|
+
if (cacheDir) {
|
|
1613
|
+
cloneArgs.push("--no-checkout", "--reference", cacheDir);
|
|
1614
|
+
}
|
|
1550
1615
|
if (fromBranch) {
|
|
1551
1616
|
cloneArgs.push("--branch", fromBranch);
|
|
1552
1617
|
}
|
|
1553
1618
|
cloneArgs.push(cleanUrl, ".");
|
|
1554
1619
|
try {
|
|
1555
|
-
git(checkoutDir, cloneArgs);
|
|
1620
|
+
git(checkoutDir, cloneArgs, gitEnv);
|
|
1621
|
+
if (cacheDir && useLfs) {
|
|
1622
|
+
const checkoutLfsDir = join2(checkoutDir, ".git", "lfs");
|
|
1623
|
+
mkdirSync2(checkoutLfsDir, { recursive: true });
|
|
1624
|
+
symlinkSync(
|
|
1625
|
+
join2(cacheDir, ".git", "lfs", "objects"),
|
|
1626
|
+
join2(checkoutLfsDir, "objects")
|
|
1627
|
+
);
|
|
1628
|
+
}
|
|
1556
1629
|
if (fromBranch && branch === fromBranch) {
|
|
1557
|
-
git(checkoutDir, ["checkout", branch]);
|
|
1630
|
+
git(checkoutDir, ["checkout", branch], gitEnv);
|
|
1558
1631
|
} else {
|
|
1559
|
-
git(checkoutDir, ["checkout", "-b", branch]);
|
|
1632
|
+
git(checkoutDir, ["checkout", "-b", branch], gitEnv);
|
|
1560
1633
|
}
|
|
1561
|
-
git(checkoutDir, ["config", "credential.helper", HELPER_SNIPPET]);
|
|
1634
|
+
git(checkoutDir, ["config", "credential.helper", HELPER_SNIPPET], gitEnv);
|
|
1562
1635
|
} catch (err) {
|
|
1563
1636
|
try {
|
|
1564
1637
|
rmSync(checkoutDir, { recursive: true, force: true });
|
|
@@ -1642,8 +1715,12 @@ function worktreeRemove(args) {
|
|
|
1642
1715
|
rmSync(resolved, { recursive: true, force: true });
|
|
1643
1716
|
}
|
|
1644
1717
|
}
|
|
1645
|
-
function git(cwd, args) {
|
|
1646
|
-
execFileSync("git", args, {
|
|
1718
|
+
function git(cwd, args, env) {
|
|
1719
|
+
execFileSync("git", args, {
|
|
1720
|
+
cwd,
|
|
1721
|
+
stdio: ["ignore", "ignore", "inherit"],
|
|
1722
|
+
env: env ?? process.env
|
|
1723
|
+
});
|
|
1647
1724
|
}
|
|
1648
1725
|
function refExists(cwd, ref) {
|
|
1649
1726
|
try {
|
|
@@ -1661,6 +1738,9 @@ function pickFlag(argv, name) {
|
|
|
1661
1738
|
if (i === -1) return void 0;
|
|
1662
1739
|
return argv[i + 1];
|
|
1663
1740
|
}
|
|
1741
|
+
function hasFlag(argv, name) {
|
|
1742
|
+
return argv.indexOf(name) !== -1;
|
|
1743
|
+
}
|
|
1664
1744
|
function fail(msg) {
|
|
1665
1745
|
console.error(msg);
|
|
1666
1746
|
process.exit(1);
|
package/dist/claude-acp.js
CHANGED
|
@@ -64,6 +64,7 @@ function notify(method, params) {
|
|
|
64
64
|
var sessions = /* @__PURE__ */ new Map();
|
|
65
65
|
async function runClaudeTurn(sessionId, state, promptText) {
|
|
66
66
|
return new Promise((resolve, reject) => {
|
|
67
|
+
const idFlag = state.resume ? "--resume" : "--session-id";
|
|
67
68
|
const args = [
|
|
68
69
|
"-p",
|
|
69
70
|
"--output-format",
|
|
@@ -73,7 +74,7 @@ async function runClaudeTurn(sessionId, state, promptText) {
|
|
|
73
74
|
// sense only when stdin can be partial too.
|
|
74
75
|
"--include-partial-messages",
|
|
75
76
|
"--verbose",
|
|
76
|
-
|
|
77
|
+
idFlag,
|
|
77
78
|
sessionId,
|
|
78
79
|
// Headless: no human in the loop to approve tool use. Matches the
|
|
79
80
|
// legacy `claudeAdapter` posture in agents/kinds.ts.
|
|
@@ -205,14 +206,14 @@ function handleInitialize(_params) {
|
|
|
205
206
|
}
|
|
206
207
|
function handleNewSession(params) {
|
|
207
208
|
const sessionId = randomUUID();
|
|
208
|
-
sessions.set(sessionId, { cwd: params.cwd ?? process.cwd() });
|
|
209
|
+
sessions.set(sessionId, { cwd: params.cwd ?? process.cwd(), resume: false });
|
|
209
210
|
return { sessionId };
|
|
210
211
|
}
|
|
211
212
|
function handleLoadSession(params) {
|
|
212
213
|
if (typeof params.sessionId !== "string" || params.sessionId.length === 0) {
|
|
213
214
|
throw new Error("session/load: sessionId required");
|
|
214
215
|
}
|
|
215
|
-
sessions.set(params.sessionId, { cwd: params.cwd ?? process.cwd() });
|
|
216
|
+
sessions.set(params.sessionId, { cwd: params.cwd ?? process.cwd(), resume: true });
|
|
216
217
|
return {};
|
|
217
218
|
}
|
|
218
219
|
async function handlePrompt(params) {
|
|
@@ -225,6 +226,7 @@ async function handlePrompt(params) {
|
|
|
225
226
|
throw new Error("session/prompt: no text content blocks");
|
|
226
227
|
}
|
|
227
228
|
const result = await runClaudeTurn(params.sessionId, state, promptText);
|
|
229
|
+
state.resume = true;
|
|
228
230
|
return { stopReason: result.stopReason };
|
|
229
231
|
}
|
|
230
232
|
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;
|