@lesscap/baton-cli 0.2.2 → 0.2.4
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/baton.mjs +184 -28
- package/package.json +1 -1
package/dist/baton.mjs
CHANGED
|
@@ -550,6 +550,7 @@ var requirementClient = (baseUrl) => {
|
|
|
550
550
|
listByProject: (projectId) => request(u(`/projects/${projectId}/requirements`), { method: "GET" }),
|
|
551
551
|
get: (id) => request(u(`/requirements/${id}`), { method: "GET" }),
|
|
552
552
|
getByCode: (projectId, code) => fetchItemByCode(baseUrl, projectId, code, "requirement"),
|
|
553
|
+
update: (id, patch2) => request(u(`/requirements/${id}`), { method: "PATCH", body: patch2 }),
|
|
553
554
|
setStatus: (id, status) => request(u(`/requirements/${id}`), { method: "PATCH", body: { status } }),
|
|
554
555
|
remove: (id) => request(u(`/requirements/${id}`), { method: "DELETE" })
|
|
555
556
|
};
|
|
@@ -587,9 +588,13 @@ var sessionsClient = (baseUrl) => {
|
|
|
587
588
|
const matches = all.filter((s) => s.name === name);
|
|
588
589
|
return matches.length === 0 ? null : matches[matches.length - 1] ?? null;
|
|
589
590
|
},
|
|
590
|
-
sendMessage: (id, text, attachments) => request(u(`/sessions/${id}/messages`), {
|
|
591
|
+
sendMessage: (id, text, attachments, planMode) => request(u(`/sessions/${id}/messages`), {
|
|
591
592
|
method: "POST",
|
|
592
|
-
body:
|
|
593
|
+
body: {
|
|
594
|
+
text,
|
|
595
|
+
...attachments && attachments.length > 0 ? { attachments } : {},
|
|
596
|
+
...planMode ? { planMode: true } : {}
|
|
597
|
+
}
|
|
593
598
|
}),
|
|
594
599
|
// Raw-body upload: the file streams as the request body (no multipart), so
|
|
595
600
|
// a Blob backed by a file on disk uploads without buffering. filename rides
|
|
@@ -618,6 +623,7 @@ var taskClient = (baseUrl) => {
|
|
|
618
623
|
listByRequirement: (requirementId) => request(u(`/requirements/${requirementId}/tasks`), { method: "GET" }),
|
|
619
624
|
get: (id) => request(u(`/tasks/${id}`), { method: "GET" }),
|
|
620
625
|
getByCode: (projectId, code) => fetchItemByCode(baseUrl, projectId, code, "task"),
|
|
626
|
+
update: (id, patch2) => request(u(`/tasks/${id}`), { method: "PATCH", body: patch2 }),
|
|
621
627
|
setStatus: (id, status) => request(u(`/tasks/${id}`), { method: "PATCH", body: { status } }),
|
|
622
628
|
remove: (id) => request(u(`/tasks/${id}`), { method: "DELETE" }),
|
|
623
629
|
listComments: (id) => request(u(`/tasks/${id}/comments`), { method: "GET" }),
|
|
@@ -734,6 +740,11 @@ var viewWorker = (cfg) => {
|
|
|
734
740
|
apiToken: worker2.apiToken
|
|
735
741
|
};
|
|
736
742
|
};
|
|
743
|
+
var worktreeConfig = (cfg) => ({
|
|
744
|
+
server: cfg.server,
|
|
745
|
+
project: cfg.projectId,
|
|
746
|
+
worker: { id: cfg.workerId, name: cfg.name, machineId: cfg.machineId, apiToken: cfg.apiToken }
|
|
747
|
+
});
|
|
737
748
|
|
|
738
749
|
// src/config.ts
|
|
739
750
|
var resolveBaseUrl = (urlArg, env = process.env) => {
|
|
@@ -772,6 +783,12 @@ var resolveWorkspaceId = (args) => {
|
|
|
772
783
|
"no workspace in scope. pass --workspace <id> or run `baton init` in this directory."
|
|
773
784
|
);
|
|
774
785
|
};
|
|
786
|
+
var parseIssueUrl = (url) => {
|
|
787
|
+
const m = url.match(/^https:\/\/github\.com\/[^/]+\/[^/]+\/issues\/(\d+)/);
|
|
788
|
+
if (!m)
|
|
789
|
+
throw new Error(`expected a GitHub issue url (https://github.com/o/r/issues/N), got "${url}"`);
|
|
790
|
+
return { source: "github", number: Number(m[1]), url: url.split(/[?#]/)[0] };
|
|
791
|
+
};
|
|
775
792
|
var splitCsv = (s) => s ? s.split(",").map((x) => x.trim()).filter(Boolean) : void 0;
|
|
776
793
|
|
|
777
794
|
// src/commands/init.ts
|
|
@@ -931,6 +948,7 @@ var project = defineCommand({
|
|
|
931
948
|
|
|
932
949
|
// src/commands/requirement.ts
|
|
933
950
|
var createRequirement = (c, input, json) => c.requirements.create(input).then((r) => renderOne(r, fmtRequirement, json));
|
|
951
|
+
var updateRequirement = (c, id, patch2, json) => c.requirements.update(id, patch2).then((r) => renderOne(r, fmtRequirement, json));
|
|
934
952
|
var listRequirements = (c, projectId, json) => c.requirements.listByProject(projectId).then((rs) => renderList(rs, fmtRequirement, json));
|
|
935
953
|
var getRequirement = (c, id, json) => c.requirements.get(id).then((r) => renderOne(r, fmtRequirement, json));
|
|
936
954
|
var setRequirementStatus = (c, id, status, json) => c.requirements.setStatus(id, status).then((r) => renderOne(r, fmtRequirement, json));
|
|
@@ -946,6 +964,7 @@ var requirement = defineCommand({
|
|
|
946
964
|
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
947
965
|
desc: { type: "string", description: "description" },
|
|
948
966
|
body: { type: "string", description: "requirement body (markdown)" },
|
|
967
|
+
github: { type: "string", description: "link a GitHub issue url (light association)" },
|
|
949
968
|
...common
|
|
950
969
|
},
|
|
951
970
|
run: async ({ args }) => {
|
|
@@ -956,13 +975,69 @@ var requirement = defineCommand({
|
|
|
956
975
|
projectId: resolveProjectId(args),
|
|
957
976
|
title: args.title,
|
|
958
977
|
description: args.desc,
|
|
959
|
-
body: args.body
|
|
978
|
+
body: args.body,
|
|
979
|
+
external: args.github ? parseIssueUrl(args.github) : void 0
|
|
960
980
|
},
|
|
961
981
|
Boolean(args.json)
|
|
962
982
|
)
|
|
963
983
|
);
|
|
964
984
|
}
|
|
965
985
|
}),
|
|
986
|
+
update: defineCommand({
|
|
987
|
+
meta: { name: "update", description: "update a requirement title / body" },
|
|
988
|
+
args: {
|
|
989
|
+
code: { type: "positional", required: true, description: "requirement code (R-N)" },
|
|
990
|
+
title: { type: "string", description: "new title" },
|
|
991
|
+
body: { type: "string", description: "new body (markdown)" },
|
|
992
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
993
|
+
...common
|
|
994
|
+
},
|
|
995
|
+
run: async ({ args }) => {
|
|
996
|
+
const patch2 = {
|
|
997
|
+
...args.title !== void 0 ? { title: args.title } : {},
|
|
998
|
+
...args.body !== void 0 ? { body: args.body } : {}
|
|
999
|
+
};
|
|
1000
|
+
if (Object.keys(patch2).length === 0) throw new Error("pass --title and/or --body");
|
|
1001
|
+
const c = clientFor(args);
|
|
1002
|
+
const id = await resolveByCode(c, resolveProjectId(args), args.code);
|
|
1003
|
+
console.log(await updateRequirement(c, id, patch2, Boolean(args.json)));
|
|
1004
|
+
}
|
|
1005
|
+
}),
|
|
1006
|
+
link: defineCommand({
|
|
1007
|
+
meta: { name: "link", description: "link a requirement to a GitHub issue url" },
|
|
1008
|
+
args: {
|
|
1009
|
+
code: { type: "positional", required: true, description: "requirement code (R-N)" },
|
|
1010
|
+
// Named `issue` (not `url`) — `url` would collide with the common --url flag.
|
|
1011
|
+
issue: { type: "positional", required: true, description: "GitHub issue url" },
|
|
1012
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
1013
|
+
...common
|
|
1014
|
+
},
|
|
1015
|
+
run: async ({ args }) => {
|
|
1016
|
+
const c = clientFor(args);
|
|
1017
|
+
const id = await resolveByCode(c, resolveProjectId(args), args.code);
|
|
1018
|
+
console.log(
|
|
1019
|
+
await updateRequirement(
|
|
1020
|
+
c,
|
|
1021
|
+
id,
|
|
1022
|
+
{ external: parseIssueUrl(args.issue) },
|
|
1023
|
+
Boolean(args.json)
|
|
1024
|
+
)
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
1027
|
+
}),
|
|
1028
|
+
unlink: defineCommand({
|
|
1029
|
+
meta: { name: "unlink", description: "clear a requirement\u2019s GitHub issue association" },
|
|
1030
|
+
args: {
|
|
1031
|
+
code: { type: "positional", required: true, description: "requirement code (R-N)" },
|
|
1032
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
1033
|
+
...common
|
|
1034
|
+
},
|
|
1035
|
+
run: async ({ args }) => {
|
|
1036
|
+
const c = clientFor(args);
|
|
1037
|
+
const id = await resolveByCode(c, resolveProjectId(args), args.code);
|
|
1038
|
+
console.log(await updateRequirement(c, id, { external: null }, Boolean(args.json)));
|
|
1039
|
+
}
|
|
1040
|
+
}),
|
|
966
1041
|
ls: defineCommand({
|
|
967
1042
|
meta: { name: "ls", description: "list requirements in a project" },
|
|
968
1043
|
args: {
|
|
@@ -1795,14 +1870,15 @@ ${text}` : header;
|
|
|
1795
1870
|
};
|
|
1796
1871
|
|
|
1797
1872
|
// src/session/runner/query.ts
|
|
1798
|
-
var startQuery = (config, text, resuming, queryFn, abortController, log, envOverlay) => {
|
|
1873
|
+
var startQuery = (config, text, resuming, queryFn, abortController, log, envOverlay, planMode = false) => {
|
|
1799
1874
|
const env = buildSdkEnv(envOverlay);
|
|
1800
1875
|
const exe = claudeExecutable();
|
|
1801
1876
|
const addDirs = additionalDirs();
|
|
1802
1877
|
if (addDirs) log(`[add-dir] ${addDirs.join(", ")}`);
|
|
1878
|
+
if (planMode) log("[plan] read-only planning turn");
|
|
1803
1879
|
const options = {
|
|
1804
1880
|
cwd: config.worktreePath,
|
|
1805
|
-
permissionMode: "bypassPermissions",
|
|
1881
|
+
permissionMode: planMode ? "plan" : "bypassPermissions",
|
|
1806
1882
|
includePartialMessages: false,
|
|
1807
1883
|
abortController,
|
|
1808
1884
|
stderr: (line) => log(`[claude] ${line.trimEnd()}`),
|
|
@@ -1868,6 +1944,7 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
1868
1944
|
const payload = msg.payload;
|
|
1869
1945
|
const rawText = typeof payload?.text === "string" ? payload.text : "";
|
|
1870
1946
|
const attachments = Array.isArray(payload?.attachments) ? payload.attachments : [];
|
|
1947
|
+
const planMode = payload?.planMode === true;
|
|
1871
1948
|
if (rawText.length === 0 && attachments.length === 0) {
|
|
1872
1949
|
await worker2.emitEvent("turn_error", { message: "user_message missing text and attachments" });
|
|
1873
1950
|
return -1;
|
|
@@ -1883,15 +1960,15 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
1883
1960
|
const abort = new AbortController();
|
|
1884
1961
|
const ceiling = turnTimeoutMs();
|
|
1885
1962
|
let timer;
|
|
1886
|
-
const timeout = new Promise((
|
|
1887
|
-
timer = setTimeout(() =>
|
|
1963
|
+
const timeout = new Promise((resolve2) => {
|
|
1964
|
+
timer = setTimeout(() => resolve2(TIMEOUT), ceiling);
|
|
1888
1965
|
});
|
|
1889
|
-
const interrupted = new Promise((
|
|
1890
|
-
if (externalSignal?.aborted)
|
|
1891
|
-
else externalSignal?.addEventListener("abort", () =>
|
|
1966
|
+
const interrupted = new Promise((resolve2) => {
|
|
1967
|
+
if (externalSignal?.aborted) resolve2(ABORTED);
|
|
1968
|
+
else externalSignal?.addEventListener("abort", () => resolve2(ABORTED), { once: true });
|
|
1892
1969
|
});
|
|
1893
1970
|
try {
|
|
1894
|
-
const messages = startQuery(config, text, resuming, queryFn, abort, log, envOverlay);
|
|
1971
|
+
const messages = startQuery(config, text, resuming, queryFn, abort, log, envOverlay, planMode);
|
|
1895
1972
|
const consume = streamSdkEvents(messages, worker2);
|
|
1896
1973
|
void consume.catch(() => {
|
|
1897
1974
|
});
|
|
@@ -1906,7 +1983,9 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
1906
1983
|
if (outcome === TIMEOUT) {
|
|
1907
1984
|
log(`[watchdog] turn exceeded ${ceiling}ms \u2014 aborting claude`);
|
|
1908
1985
|
abort.abort();
|
|
1909
|
-
await worker2.emitEvent("turn_error", {
|
|
1986
|
+
await worker2.emitEvent("turn_error", {
|
|
1987
|
+
message: `turn exceeded ${ceiling}ms \u2014 claude aborted`
|
|
1988
|
+
});
|
|
1910
1989
|
await worker2.emitEvent("turn_complete", {});
|
|
1911
1990
|
return -1;
|
|
1912
1991
|
}
|
|
@@ -1940,9 +2019,9 @@ var subscribeStream = (url, ESCtor, seen, log, onUserMessage, onInterrupt, onRea
|
|
|
1940
2019
|
es.onerror = () => log("sse error (eventsource will retry)");
|
|
1941
2020
|
return es;
|
|
1942
2021
|
};
|
|
1943
|
-
var waitForAbort = (signal) => new Promise((
|
|
1944
|
-
if (signal.aborted) return
|
|
1945
|
-
signal.addEventListener("abort", () =>
|
|
2022
|
+
var waitForAbort = (signal) => new Promise((resolve2) => {
|
|
2023
|
+
if (signal.aborted) return resolve2();
|
|
2024
|
+
signal.addEventListener("abort", () => resolve2(), { once: true });
|
|
1946
2025
|
});
|
|
1947
2026
|
var shouldReap = (lastActivity, now, busy, queueLen, idleMs) => !busy && queueLen === 0 && now - lastActivity >= idleMs;
|
|
1948
2027
|
var idleMsFromEnv = () => Number(process.env.BATON_SESSION_IDLE_MS) || 30 * 6e4;
|
|
@@ -2025,12 +2104,12 @@ var runDaemon = async (config, deps, signal) => {
|
|
|
2025
2104
|
);
|
|
2026
2105
|
const idleMs = idleMsFromEnv();
|
|
2027
2106
|
let idleTimer;
|
|
2028
|
-
const reaped = new Promise((
|
|
2107
|
+
const reaped = new Promise((resolve2) => {
|
|
2029
2108
|
idleTimer = setInterval(
|
|
2030
2109
|
() => {
|
|
2031
2110
|
if (shouldReap(lastActivity, Date.now(), busy, pendingQueue.length, idleMs)) {
|
|
2032
2111
|
log("idle \u2014 shutting down (resumes on next message)");
|
|
2033
|
-
|
|
2112
|
+
resolve2();
|
|
2034
2113
|
}
|
|
2035
2114
|
},
|
|
2036
2115
|
Math.min(idleMs, 3e4)
|
|
@@ -2209,6 +2288,7 @@ var session = defineCommand({
|
|
|
2209
2288
|
|
|
2210
2289
|
// src/commands/task.ts
|
|
2211
2290
|
var createTask = (c, input, json) => c.tasks.create(input).then((t) => renderOne(t, fmtTask, json));
|
|
2291
|
+
var updateTask = (c, id, patch2, json) => c.tasks.update(id, patch2).then((t) => renderOne(t, fmtTask, json));
|
|
2212
2292
|
var listTasks = (c, requirementId, json) => c.tasks.listByRequirement(requirementId).then((ts) => renderList(ts, fmtTask, json));
|
|
2213
2293
|
var getTask = (c, id, json) => c.tasks.get(id).then((t) => renderOne(t, fmtTask, json));
|
|
2214
2294
|
var setTaskStatus = (c, id, status, json) => c.tasks.setStatus(id, status).then((t) => renderOne(t, fmtTask, json));
|
|
@@ -2228,6 +2308,7 @@ var task = defineCommand({
|
|
|
2228
2308
|
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2229
2309
|
body: { type: "string", description: "task body (markdown)" },
|
|
2230
2310
|
deps: { type: "string", description: "comma-separated dependency task codes (T-N,T-N)" },
|
|
2311
|
+
github: { type: "string", description: "link a GitHub issue url (light association)" },
|
|
2231
2312
|
...common
|
|
2232
2313
|
},
|
|
2233
2314
|
run: async ({ args }) => {
|
|
@@ -2245,13 +2326,64 @@ var task = defineCommand({
|
|
|
2245
2326
|
requirementId,
|
|
2246
2327
|
title: args.title,
|
|
2247
2328
|
body: args.body,
|
|
2248
|
-
dependsOn: dependsOn.length ? dependsOn : void 0
|
|
2329
|
+
dependsOn: dependsOn.length ? dependsOn : void 0,
|
|
2330
|
+
external: args.github ? parseIssueUrl(args.github) : void 0
|
|
2249
2331
|
},
|
|
2250
2332
|
Boolean(args.json)
|
|
2251
2333
|
)
|
|
2252
2334
|
);
|
|
2253
2335
|
}
|
|
2254
2336
|
}),
|
|
2337
|
+
update: defineCommand({
|
|
2338
|
+
meta: { name: "update", description: "update a task title / body" },
|
|
2339
|
+
args: {
|
|
2340
|
+
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
2341
|
+
title: { type: "string", description: "new title" },
|
|
2342
|
+
body: { type: "string", description: "new body (markdown)" },
|
|
2343
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2344
|
+
...common
|
|
2345
|
+
},
|
|
2346
|
+
run: async ({ args }) => {
|
|
2347
|
+
const patch2 = {
|
|
2348
|
+
...args.title !== void 0 ? { title: args.title } : {},
|
|
2349
|
+
...args.body !== void 0 ? { body: args.body } : {}
|
|
2350
|
+
};
|
|
2351
|
+
if (Object.keys(patch2).length === 0) throw new Error("pass --title and/or --body");
|
|
2352
|
+
const c = clientFor(args);
|
|
2353
|
+
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
2354
|
+
console.log(await updateTask(c, id, patch2, Boolean(args.json)));
|
|
2355
|
+
}
|
|
2356
|
+
}),
|
|
2357
|
+
link: defineCommand({
|
|
2358
|
+
meta: { name: "link", description: "link a task to a GitHub issue url" },
|
|
2359
|
+
args: {
|
|
2360
|
+
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
2361
|
+
// Named `issue` (not `url`) — `url` would collide with the common --url flag.
|
|
2362
|
+
issue: { type: "positional", required: true, description: "GitHub issue url" },
|
|
2363
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2364
|
+
...common
|
|
2365
|
+
},
|
|
2366
|
+
run: async ({ args }) => {
|
|
2367
|
+
const c = clientFor(args);
|
|
2368
|
+
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
2369
|
+
console.log(
|
|
2370
|
+
await updateTask(c, id, { external: parseIssueUrl(args.issue) }, Boolean(args.json))
|
|
2371
|
+
);
|
|
2372
|
+
}
|
|
2373
|
+
}),
|
|
2374
|
+
unlink: defineCommand({
|
|
2375
|
+
meta: { name: "unlink", description: "clear a task\u2019s GitHub issue association" },
|
|
2376
|
+
args: {
|
|
2377
|
+
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
2378
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2379
|
+
...common
|
|
2380
|
+
},
|
|
2381
|
+
run: async ({ args }) => {
|
|
2382
|
+
const c = clientFor(args);
|
|
2383
|
+
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
2384
|
+
console.log(await updateTask(c, id, { external: null }, Boolean(args.json)));
|
|
2385
|
+
}
|
|
2386
|
+
}),
|
|
2255
2387
|
ls: defineCommand({
|
|
2256
2388
|
meta: { name: "ls", description: "list tasks in a requirement" },
|
|
2257
2389
|
args: {
|
|
@@ -2281,7 +2413,7 @@ var task = defineCommand({
|
|
|
2281
2413
|
"set-status": defineCommand({
|
|
2282
2414
|
meta: {
|
|
2283
2415
|
name: "set-status",
|
|
2284
|
-
description: "set task status (todo|in_progress|done|failed|cancelled)"
|
|
2416
|
+
description: "set task status (todo|in_progress|blocked|done|failed|cancelled)"
|
|
2285
2417
|
},
|
|
2286
2418
|
args: {
|
|
2287
2419
|
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
@@ -2359,7 +2491,7 @@ import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
|
|
|
2359
2491
|
// src/session/runner/title.ts
|
|
2360
2492
|
var clip = (s, max) => s.length > max ? s.slice(0, max) : s;
|
|
2361
2493
|
var isDeclined = (title) => title.replace(/[^a-z]/gi, "").toUpperCase() === "NONE";
|
|
2362
|
-
var sanitizeTitle = (raw) => raw.replace(/[\r\n]+/g, " ").replace(/["'
|
|
2494
|
+
var sanitizeTitle = (raw) => raw.replace(/[\r\n]+/g, " ").replace(/[*_`~#>]/g, "").replace(/["']/g, "").replace(/^\s*(?:title|session|标题)\s*[::-]\s*/i, "").replace(/^\s*(?:[-*•]|\d+[.)、])\s+/, "").replace(/\s+/g, " ").trim().slice(0, 30).replace(/[\s。.,,、;;::!!??.]+$/, "").trim();
|
|
2363
2495
|
var TITLE_TIMEOUT_MS = 3e4;
|
|
2364
2496
|
var generateTitle = async (input) => {
|
|
2365
2497
|
const { worktreePath, userText, assistantText, queryFn } = input;
|
|
@@ -2368,7 +2500,8 @@ var generateTitle = async (input) => {
|
|
|
2368
2500
|
`User: ${clip(userText, 800)}`,
|
|
2369
2501
|
assistantText ? `Assistant: ${clip(assistantText, 800)}` : ""
|
|
2370
2502
|
].filter(Boolean).join("\n");
|
|
2371
|
-
const prompt = `Reply with ONLY a
|
|
2503
|
+
const prompt = `Reply with ONLY a short title for this session: a noun phrase like a filename \u2014 at most 6 words or ~12 Chinese characters. It must NOT be a sentence, no punctuation, no markdown, no quotes, and never an opener like "\u597D\u7684"/"\u6536\u5230"/"I'll". If it is too thin or generic to title meaningfully, reply with exactly NONE.
|
|
2504
|
+
|
|
2372
2505
|
${exchange}`;
|
|
2373
2506
|
const exe = claudeExecutable();
|
|
2374
2507
|
const abort = new AbortController();
|
|
@@ -2379,6 +2512,9 @@ ${exchange}`;
|
|
|
2379
2512
|
prompt,
|
|
2380
2513
|
options: {
|
|
2381
2514
|
cwd: worktreePath,
|
|
2515
|
+
// Don't load the worktree's CLAUDE.md / project settings — they steer the
|
|
2516
|
+
// model into verbose summaries instead of a terse title.
|
|
2517
|
+
settingSources: [],
|
|
2382
2518
|
permissionMode: "bypassPermissions",
|
|
2383
2519
|
allowedTools: [],
|
|
2384
2520
|
includePartialMessages: false,
|
|
@@ -2401,8 +2537,8 @@ ${exchange}`;
|
|
|
2401
2537
|
|
|
2402
2538
|
// src/session/worktree.ts
|
|
2403
2539
|
import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
2404
|
-
import { existsSync as existsSync4, mkdirSync } from "node:fs";
|
|
2405
|
-
import { dirname } from "node:path";
|
|
2540
|
+
import { appendFileSync, existsSync as existsSync4, mkdirSync, readFileSync as readFileSync3 } from "node:fs";
|
|
2541
|
+
import { dirname, isAbsolute as isAbsolute2, resolve } from "node:path";
|
|
2406
2542
|
var createWorktree = (input) => {
|
|
2407
2543
|
if (existsSync4(input.worktreePath))
|
|
2408
2544
|
throw new Error(`worktree path already exists: ${input.worktreePath}`);
|
|
@@ -2425,6 +2561,24 @@ var repoHeadBranch = (repo) => {
|
|
|
2425
2561
|
const branch = r.status === 0 ? r.stdout.trim() : "";
|
|
2426
2562
|
return branch || "main";
|
|
2427
2563
|
};
|
|
2564
|
+
var ensureExcluded = (repo, pattern) => {
|
|
2565
|
+
try {
|
|
2566
|
+
const r = spawnSync2("git", ["-C", repo, "rev-parse", "--git-path", "info/exclude"], {
|
|
2567
|
+
stdio: "pipe",
|
|
2568
|
+
encoding: "utf8"
|
|
2569
|
+
});
|
|
2570
|
+
if (r.status !== 0) return;
|
|
2571
|
+
const rel = r.stdout.trim();
|
|
2572
|
+
const path = isAbsolute2(rel) ? rel : resolve(repo, rel);
|
|
2573
|
+
const current = existsSync4(path) ? readFileSync3(path, "utf8") : "";
|
|
2574
|
+
if (current.split("\n").includes(pattern)) return;
|
|
2575
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
2576
|
+
const sep = current === "" || current.endsWith("\n") ? "" : "\n";
|
|
2577
|
+
appendFileSync(path, `${sep}${pattern}
|
|
2578
|
+
`, "utf8");
|
|
2579
|
+
} catch {
|
|
2580
|
+
}
|
|
2581
|
+
};
|
|
2428
2582
|
var removeWorktree = (repo, worktreePath) => {
|
|
2429
2583
|
if (!existsSync4(worktreePath)) return;
|
|
2430
2584
|
try {
|
|
@@ -2494,6 +2648,8 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
2494
2648
|
await client.sessions.materialize(sessionId, { agentSessionId, worktreePath }, cfg.apiToken);
|
|
2495
2649
|
log(`materialized session #${sessionId} \u2192 ${worktreePath}`);
|
|
2496
2650
|
}
|
|
2651
|
+
ensureExcluded(repo, PROJECT_CONFIG_NAME);
|
|
2652
|
+
saveProjectConfig(join5(worktreePath, PROJECT_CONFIG_NAME), worktreeConfig(cfg));
|
|
2497
2653
|
spawnChild(sessionId, worktreePath);
|
|
2498
2654
|
};
|
|
2499
2655
|
const onStop = (sessionId) => {
|
|
@@ -2565,9 +2721,9 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
2565
2721
|
};
|
|
2566
2722
|
es.onerror = () => log("command stream error (eventsource will retry)");
|
|
2567
2723
|
log(`listening for commands (server ${cfg.server}, repo ${repo})`);
|
|
2568
|
-
await new Promise((
|
|
2569
|
-
if (signal.aborted) return
|
|
2570
|
-
signal.addEventListener("abort", () =>
|
|
2724
|
+
await new Promise((resolve2) => {
|
|
2725
|
+
if (signal.aborted) return resolve2();
|
|
2726
|
+
signal.addEventListener("abort", () => resolve2(), { once: true });
|
|
2571
2727
|
});
|
|
2572
2728
|
es.close();
|
|
2573
2729
|
clearInterval(hb);
|
|
@@ -2576,13 +2732,13 @@ var runWorkerDaemon = async (cfg, client, signal) => {
|
|
|
2576
2732
|
|
|
2577
2733
|
// src/worker/machine-id.ts
|
|
2578
2734
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
2579
|
-
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as
|
|
2735
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync2, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
|
|
2580
2736
|
import { homedir as homedir3 } from "node:os";
|
|
2581
2737
|
import { dirname as dirname3, join as join6 } from "node:path";
|
|
2582
2738
|
var machineIdPath = (env = process.env) => join6(env.XDG_DATA_HOME ?? join6(env.HOME ?? homedir3(), ".local/share"), "baton", "machine-id");
|
|
2583
2739
|
var readOrCreateMachineId = (path = machineIdPath()) => {
|
|
2584
2740
|
if (existsSync6(path)) {
|
|
2585
|
-
const s =
|
|
2741
|
+
const s = readFileSync4(path, "utf8").trim();
|
|
2586
2742
|
if (s) return s;
|
|
2587
2743
|
}
|
|
2588
2744
|
const id = randomUUID2();
|