@lesscap/baton-cli 0.2.3 → 0.2.5
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 +163 -18
- 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
|
};
|
|
@@ -622,6 +623,7 @@ var taskClient = (baseUrl) => {
|
|
|
622
623
|
listByRequirement: (requirementId) => request(u(`/requirements/${requirementId}/tasks`), { method: "GET" }),
|
|
623
624
|
get: (id) => request(u(`/tasks/${id}`), { method: "GET" }),
|
|
624
625
|
getByCode: (projectId, code) => fetchItemByCode(baseUrl, projectId, code, "task"),
|
|
626
|
+
update: (id, patch2) => request(u(`/tasks/${id}`), { method: "PATCH", body: patch2 }),
|
|
625
627
|
setStatus: (id, status) => request(u(`/tasks/${id}`), { method: "PATCH", body: { status } }),
|
|
626
628
|
remove: (id) => request(u(`/tasks/${id}`), { method: "DELETE" }),
|
|
627
629
|
listComments: (id) => request(u(`/tasks/${id}/comments`), { method: "GET" }),
|
|
@@ -766,7 +768,11 @@ var common = {
|
|
|
766
768
|
},
|
|
767
769
|
json: { type: "boolean", description: "output JSON" }
|
|
768
770
|
};
|
|
769
|
-
var clientFor = (args) =>
|
|
771
|
+
var clientFor = (args) => {
|
|
772
|
+
const envAuth = process.env.BATON_TOKEN ?? (process.env.BATON_USER && process.env.BATON_PASS);
|
|
773
|
+
const cfgToken = envAuth ? void 0 : loadProjectConfigOrNull(projectConfigPath())?.worker?.apiToken;
|
|
774
|
+
return createClient(resolveBaseUrl(args.url), cfgToken ? { bearer: cfgToken } : void 0);
|
|
775
|
+
};
|
|
770
776
|
var resolveProjectId = (args) => {
|
|
771
777
|
if (args.project !== void 0 && args.project !== "") return Number(args.project);
|
|
772
778
|
const cfg = loadProjectConfigOrNull(projectConfigPath());
|
|
@@ -781,6 +787,16 @@ var resolveWorkspaceId = (args) => {
|
|
|
781
787
|
"no workspace in scope. pass --workspace <id> or run `baton init` in this directory."
|
|
782
788
|
);
|
|
783
789
|
};
|
|
790
|
+
var parseWorkerHandle = (handle) => {
|
|
791
|
+
const m = handle.trim().match(/^(?:[wW]-)?(\d+)$/);
|
|
792
|
+
return m ? Number(m[1]) : null;
|
|
793
|
+
};
|
|
794
|
+
var parseIssueUrl = (url) => {
|
|
795
|
+
const m = url.match(/^https:\/\/github\.com\/[^/]+\/[^/]+\/issues\/(\d+)/);
|
|
796
|
+
if (!m)
|
|
797
|
+
throw new Error(`expected a GitHub issue url (https://github.com/o/r/issues/N), got "${url}"`);
|
|
798
|
+
return { source: "github", number: Number(m[1]), url: url.split(/[?#]/)[0] };
|
|
799
|
+
};
|
|
784
800
|
var splitCsv = (s) => s ? s.split(",").map((x) => x.trim()).filter(Boolean) : void 0;
|
|
785
801
|
|
|
786
802
|
// src/commands/init.ts
|
|
@@ -855,7 +871,7 @@ var fmtComment = (c) => `${c.workerId !== void 0 ? `worker#${c.workerId}` : "you
|
|
|
855
871
|
var fmtSession = (s) => `${s.id} ${s.name} ${s.attached ? "[active]" : "[inactive]"} ${s.worktreePath ?? "(pending)"}`;
|
|
856
872
|
var fmtWorker = (w) => {
|
|
857
873
|
const offline = w.alive === false ? " [offline]" : "";
|
|
858
|
-
return
|
|
874
|
+
return `W-${w.id} ${w.name} ${w.hostname}${offline}`;
|
|
859
875
|
};
|
|
860
876
|
var renderOne = (item, fmt, json) => json ? toJson(item) : fmt(item);
|
|
861
877
|
var renderList = (items, fmt, json) => {
|
|
@@ -940,6 +956,7 @@ var project = defineCommand({
|
|
|
940
956
|
|
|
941
957
|
// src/commands/requirement.ts
|
|
942
958
|
var createRequirement = (c, input, json) => c.requirements.create(input).then((r) => renderOne(r, fmtRequirement, json));
|
|
959
|
+
var updateRequirement = (c, id, patch2, json) => c.requirements.update(id, patch2).then((r) => renderOne(r, fmtRequirement, json));
|
|
943
960
|
var listRequirements = (c, projectId, json) => c.requirements.listByProject(projectId).then((rs) => renderList(rs, fmtRequirement, json));
|
|
944
961
|
var getRequirement = (c, id, json) => c.requirements.get(id).then((r) => renderOne(r, fmtRequirement, json));
|
|
945
962
|
var setRequirementStatus = (c, id, status, json) => c.requirements.setStatus(id, status).then((r) => renderOne(r, fmtRequirement, json));
|
|
@@ -955,6 +972,7 @@ var requirement = defineCommand({
|
|
|
955
972
|
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
956
973
|
desc: { type: "string", description: "description" },
|
|
957
974
|
body: { type: "string", description: "requirement body (markdown)" },
|
|
975
|
+
github: { type: "string", description: "link a GitHub issue url (light association)" },
|
|
958
976
|
...common
|
|
959
977
|
},
|
|
960
978
|
run: async ({ args }) => {
|
|
@@ -965,13 +983,69 @@ var requirement = defineCommand({
|
|
|
965
983
|
projectId: resolveProjectId(args),
|
|
966
984
|
title: args.title,
|
|
967
985
|
description: args.desc,
|
|
968
|
-
body: args.body
|
|
986
|
+
body: args.body,
|
|
987
|
+
external: args.github ? parseIssueUrl(args.github) : void 0
|
|
969
988
|
},
|
|
970
989
|
Boolean(args.json)
|
|
971
990
|
)
|
|
972
991
|
);
|
|
973
992
|
}
|
|
974
993
|
}),
|
|
994
|
+
update: defineCommand({
|
|
995
|
+
meta: { name: "update", description: "update a requirement title / body" },
|
|
996
|
+
args: {
|
|
997
|
+
code: { type: "positional", required: true, description: "requirement code (R-N)" },
|
|
998
|
+
title: { type: "string", description: "new title" },
|
|
999
|
+
body: { type: "string", description: "new body (markdown)" },
|
|
1000
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
1001
|
+
...common
|
|
1002
|
+
},
|
|
1003
|
+
run: async ({ args }) => {
|
|
1004
|
+
const patch2 = {
|
|
1005
|
+
...args.title !== void 0 ? { title: args.title } : {},
|
|
1006
|
+
...args.body !== void 0 ? { body: args.body } : {}
|
|
1007
|
+
};
|
|
1008
|
+
if (Object.keys(patch2).length === 0) throw new Error("pass --title and/or --body");
|
|
1009
|
+
const c = clientFor(args);
|
|
1010
|
+
const id = await resolveByCode(c, resolveProjectId(args), args.code);
|
|
1011
|
+
console.log(await updateRequirement(c, id, patch2, Boolean(args.json)));
|
|
1012
|
+
}
|
|
1013
|
+
}),
|
|
1014
|
+
link: defineCommand({
|
|
1015
|
+
meta: { name: "link", description: "link a requirement to a GitHub issue url" },
|
|
1016
|
+
args: {
|
|
1017
|
+
code: { type: "positional", required: true, description: "requirement code (R-N)" },
|
|
1018
|
+
// Named `issue` (not `url`) — `url` would collide with the common --url flag.
|
|
1019
|
+
issue: { type: "positional", required: true, description: "GitHub issue url" },
|
|
1020
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
1021
|
+
...common
|
|
1022
|
+
},
|
|
1023
|
+
run: async ({ args }) => {
|
|
1024
|
+
const c = clientFor(args);
|
|
1025
|
+
const id = await resolveByCode(c, resolveProjectId(args), args.code);
|
|
1026
|
+
console.log(
|
|
1027
|
+
await updateRequirement(
|
|
1028
|
+
c,
|
|
1029
|
+
id,
|
|
1030
|
+
{ external: parseIssueUrl(args.issue) },
|
|
1031
|
+
Boolean(args.json)
|
|
1032
|
+
)
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
}),
|
|
1036
|
+
unlink: defineCommand({
|
|
1037
|
+
meta: { name: "unlink", description: "clear a requirement\u2019s GitHub issue association" },
|
|
1038
|
+
args: {
|
|
1039
|
+
code: { type: "positional", required: true, description: "requirement code (R-N)" },
|
|
1040
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
1041
|
+
...common
|
|
1042
|
+
},
|
|
1043
|
+
run: async ({ args }) => {
|
|
1044
|
+
const c = clientFor(args);
|
|
1045
|
+
const id = await resolveByCode(c, resolveProjectId(args), args.code);
|
|
1046
|
+
console.log(await updateRequirement(c, id, { external: null }, Boolean(args.json)));
|
|
1047
|
+
}
|
|
1048
|
+
}),
|
|
975
1049
|
ls: defineCommand({
|
|
976
1050
|
meta: { name: "ls", description: "list requirements in a project" },
|
|
977
1051
|
args: {
|
|
@@ -1047,7 +1121,10 @@ var resolveSession = async (client, projectId, handle) => {
|
|
|
1047
1121
|
|
|
1048
1122
|
// src/commands/session/abort.ts
|
|
1049
1123
|
var sessionAbortCommand = defineCommand({
|
|
1050
|
-
meta: {
|
|
1124
|
+
meta: {
|
|
1125
|
+
name: "abort",
|
|
1126
|
+
description: "interrupt the in-flight turn (like Esc); keeps the session"
|
|
1127
|
+
},
|
|
1051
1128
|
args: {
|
|
1052
1129
|
session: { type: "positional", required: true, description: "session int id or name" },
|
|
1053
1130
|
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
@@ -1063,7 +1140,10 @@ var sessionAbortCommand = defineCommand({
|
|
|
1063
1140
|
|
|
1064
1141
|
// src/commands/session/clear.ts
|
|
1065
1142
|
var sessionClearCommand = defineCommand({
|
|
1066
|
-
meta: {
|
|
1143
|
+
meta: {
|
|
1144
|
+
name: "clear",
|
|
1145
|
+
description: "reset the conversation context (keeps the session + worktree)"
|
|
1146
|
+
},
|
|
1067
1147
|
args: {
|
|
1068
1148
|
session: { type: "positional", required: true, description: "session int id or name" },
|
|
1069
1149
|
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
@@ -1082,16 +1162,24 @@ var sessionCreateCommand = defineCommand({
|
|
|
1082
1162
|
meta: { name: "create", description: "create + start a session on a worker" },
|
|
1083
1163
|
args: {
|
|
1084
1164
|
name: { type: "positional", required: true, description: "session name" },
|
|
1085
|
-
worker: {
|
|
1086
|
-
|
|
1165
|
+
worker: {
|
|
1166
|
+
type: "string",
|
|
1167
|
+
description: "worker handle: W-N or int id (default: this machine's worker)"
|
|
1168
|
+
},
|
|
1169
|
+
project: {
|
|
1170
|
+
type: "string",
|
|
1171
|
+
description: "project id (default: the worker's own project, else .baton.json)"
|
|
1172
|
+
},
|
|
1087
1173
|
...common
|
|
1088
1174
|
},
|
|
1089
1175
|
run: async ({ args }) => {
|
|
1090
1176
|
const c = clientFor(args);
|
|
1091
|
-
const
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1177
|
+
const workerId = args.worker ? parseWorkerHandle(args.worker) : loadProjectConfigOrNull(projectConfigPath())?.worker?.id ?? null;
|
|
1178
|
+
if (workerId === null)
|
|
1179
|
+
throw new Error(
|
|
1180
|
+
"no worker \u2014 pass --worker <W-N|id> or run `baton worker register` first (names need --project)"
|
|
1181
|
+
);
|
|
1182
|
+
const projectId = args.project !== void 0 && args.project !== "" ? Number(args.project) : args.worker ? (await c.workers.get(workerId)).projectId : resolveProjectId(args);
|
|
1095
1183
|
const s = await c.sessions.create({ projectId, workerId, name: args.name });
|
|
1096
1184
|
console.log(renderOne(s, fmtSession, Boolean(args.json)));
|
|
1097
1185
|
}
|
|
@@ -2222,6 +2310,7 @@ var session = defineCommand({
|
|
|
2222
2310
|
|
|
2223
2311
|
// src/commands/task.ts
|
|
2224
2312
|
var createTask = (c, input, json) => c.tasks.create(input).then((t) => renderOne(t, fmtTask, json));
|
|
2313
|
+
var updateTask = (c, id, patch2, json) => c.tasks.update(id, patch2).then((t) => renderOne(t, fmtTask, json));
|
|
2225
2314
|
var listTasks = (c, requirementId, json) => c.tasks.listByRequirement(requirementId).then((ts) => renderList(ts, fmtTask, json));
|
|
2226
2315
|
var getTask = (c, id, json) => c.tasks.get(id).then((t) => renderOne(t, fmtTask, json));
|
|
2227
2316
|
var setTaskStatus = (c, id, status, json) => c.tasks.setStatus(id, status).then((t) => renderOne(t, fmtTask, json));
|
|
@@ -2241,6 +2330,7 @@ var task = defineCommand({
|
|
|
2241
2330
|
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2242
2331
|
body: { type: "string", description: "task body (markdown)" },
|
|
2243
2332
|
deps: { type: "string", description: "comma-separated dependency task codes (T-N,T-N)" },
|
|
2333
|
+
github: { type: "string", description: "link a GitHub issue url (light association)" },
|
|
2244
2334
|
...common
|
|
2245
2335
|
},
|
|
2246
2336
|
run: async ({ args }) => {
|
|
@@ -2258,13 +2348,64 @@ var task = defineCommand({
|
|
|
2258
2348
|
requirementId,
|
|
2259
2349
|
title: args.title,
|
|
2260
2350
|
body: args.body,
|
|
2261
|
-
dependsOn: dependsOn.length ? dependsOn : void 0
|
|
2351
|
+
dependsOn: dependsOn.length ? dependsOn : void 0,
|
|
2352
|
+
external: args.github ? parseIssueUrl(args.github) : void 0
|
|
2262
2353
|
},
|
|
2263
2354
|
Boolean(args.json)
|
|
2264
2355
|
)
|
|
2265
2356
|
);
|
|
2266
2357
|
}
|
|
2267
2358
|
}),
|
|
2359
|
+
update: defineCommand({
|
|
2360
|
+
meta: { name: "update", description: "update a task title / body" },
|
|
2361
|
+
args: {
|
|
2362
|
+
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
2363
|
+
title: { type: "string", description: "new title" },
|
|
2364
|
+
body: { type: "string", description: "new body (markdown)" },
|
|
2365
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2366
|
+
...common
|
|
2367
|
+
},
|
|
2368
|
+
run: async ({ args }) => {
|
|
2369
|
+
const patch2 = {
|
|
2370
|
+
...args.title !== void 0 ? { title: args.title } : {},
|
|
2371
|
+
...args.body !== void 0 ? { body: args.body } : {}
|
|
2372
|
+
};
|
|
2373
|
+
if (Object.keys(patch2).length === 0) throw new Error("pass --title and/or --body");
|
|
2374
|
+
const c = clientFor(args);
|
|
2375
|
+
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
2376
|
+
console.log(await updateTask(c, id, patch2, Boolean(args.json)));
|
|
2377
|
+
}
|
|
2378
|
+
}),
|
|
2379
|
+
link: defineCommand({
|
|
2380
|
+
meta: { name: "link", description: "link a task to a GitHub issue url" },
|
|
2381
|
+
args: {
|
|
2382
|
+
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
2383
|
+
// Named `issue` (not `url`) — `url` would collide with the common --url flag.
|
|
2384
|
+
issue: { type: "positional", required: true, description: "GitHub issue url" },
|
|
2385
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2386
|
+
...common
|
|
2387
|
+
},
|
|
2388
|
+
run: async ({ args }) => {
|
|
2389
|
+
const c = clientFor(args);
|
|
2390
|
+
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
2391
|
+
console.log(
|
|
2392
|
+
await updateTask(c, id, { external: parseIssueUrl(args.issue) }, Boolean(args.json))
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
}),
|
|
2396
|
+
unlink: defineCommand({
|
|
2397
|
+
meta: { name: "unlink", description: "clear a task\u2019s GitHub issue association" },
|
|
2398
|
+
args: {
|
|
2399
|
+
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
2400
|
+
project: { type: "string", description: "project id (overrides .baton.json)" },
|
|
2401
|
+
...common
|
|
2402
|
+
},
|
|
2403
|
+
run: async ({ args }) => {
|
|
2404
|
+
const c = clientFor(args);
|
|
2405
|
+
const id = await resolveTaskByCode(c, resolveProjectId(args), args.code);
|
|
2406
|
+
console.log(await updateTask(c, id, { external: null }, Boolean(args.json)));
|
|
2407
|
+
}
|
|
2408
|
+
}),
|
|
2268
2409
|
ls: defineCommand({
|
|
2269
2410
|
meta: { name: "ls", description: "list tasks in a requirement" },
|
|
2270
2411
|
args: {
|
|
@@ -2294,7 +2435,7 @@ var task = defineCommand({
|
|
|
2294
2435
|
"set-status": defineCommand({
|
|
2295
2436
|
meta: {
|
|
2296
2437
|
name: "set-status",
|
|
2297
|
-
description: "set task status (todo|in_progress|done|failed|cancelled)"
|
|
2438
|
+
description: "set task status (todo|in_progress|blocked|done|failed|cancelled)"
|
|
2298
2439
|
},
|
|
2299
2440
|
args: {
|
|
2300
2441
|
code: { type: "positional", required: true, description: "task code (T-N)" },
|
|
@@ -2372,7 +2513,7 @@ import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
|
|
|
2372
2513
|
// src/session/runner/title.ts
|
|
2373
2514
|
var clip = (s, max) => s.length > max ? s.slice(0, max) : s;
|
|
2374
2515
|
var isDeclined = (title) => title.replace(/[^a-z]/gi, "").toUpperCase() === "NONE";
|
|
2375
|
-
var sanitizeTitle = (raw) => raw.replace(/[\r\n]+/g, " ").replace(/["'
|
|
2516
|
+
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();
|
|
2376
2517
|
var TITLE_TIMEOUT_MS = 3e4;
|
|
2377
2518
|
var generateTitle = async (input) => {
|
|
2378
2519
|
const { worktreePath, userText, assistantText, queryFn } = input;
|
|
@@ -2381,7 +2522,8 @@ var generateTitle = async (input) => {
|
|
|
2381
2522
|
`User: ${clip(userText, 800)}`,
|
|
2382
2523
|
assistantText ? `Assistant: ${clip(assistantText, 800)}` : ""
|
|
2383
2524
|
].filter(Boolean).join("\n");
|
|
2384
|
-
const prompt = `Reply with ONLY a
|
|
2525
|
+
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.
|
|
2526
|
+
|
|
2385
2527
|
${exchange}`;
|
|
2386
2528
|
const exe = claudeExecutable();
|
|
2387
2529
|
const abort = new AbortController();
|
|
@@ -2392,6 +2534,9 @@ ${exchange}`;
|
|
|
2392
2534
|
prompt,
|
|
2393
2535
|
options: {
|
|
2394
2536
|
cwd: worktreePath,
|
|
2537
|
+
// Don't load the worktree's CLAUDE.md / project settings — they steer the
|
|
2538
|
+
// model into verbose summaries instead of a terse title.
|
|
2539
|
+
settingSources: [],
|
|
2395
2540
|
permissionMode: "bypassPermissions",
|
|
2396
2541
|
allowedTools: [],
|
|
2397
2542
|
includePartialMessages: false,
|
|
@@ -2627,9 +2772,9 @@ var readOrCreateMachineId = (path = machineIdPath()) => {
|
|
|
2627
2772
|
|
|
2628
2773
|
// src/commands/worker.ts
|
|
2629
2774
|
var resolveWorker = async (client, projectId, handle) => {
|
|
2630
|
-
const
|
|
2631
|
-
if (
|
|
2632
|
-
const byId = await client.workers.get(
|
|
2775
|
+
const asId = parseWorkerHandle(handle);
|
|
2776
|
+
if (asId !== null) {
|
|
2777
|
+
const byId = await client.workers.get(asId).catch(() => null);
|
|
2633
2778
|
if (byId) return { id: byId.id, name: byId.name };
|
|
2634
2779
|
}
|
|
2635
2780
|
const byName = await client.workers.findByName(projectId, handle);
|