@lesscap/baton-cli 0.4.2 → 0.5.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/baton.mjs +452 -47
- package/package.json +5 -1
package/dist/baton.mjs
CHANGED
|
@@ -3724,14 +3724,14 @@ function isUppercase(char = "") {
|
|
|
3724
3724
|
if (NUMBER_CHAR_RE.test(char)) return;
|
|
3725
3725
|
return char !== char.toLowerCase();
|
|
3726
3726
|
}
|
|
3727
|
-
function splitByCase(
|
|
3727
|
+
function splitByCase(str3, separators) {
|
|
3728
3728
|
const splitters = separators ?? STR_SPLITTERS;
|
|
3729
3729
|
const parts = [];
|
|
3730
|
-
if (!
|
|
3730
|
+
if (!str3 || typeof str3 !== "string") return parts;
|
|
3731
3731
|
let buff = "";
|
|
3732
3732
|
let previousUpper;
|
|
3733
3733
|
let previousSplitter;
|
|
3734
|
-
for (const char of
|
|
3734
|
+
for (const char of str3) {
|
|
3735
3735
|
const isSplitter = splitters.includes(char);
|
|
3736
3736
|
if (isSplitter === true) {
|
|
3737
3737
|
parts.push(buff);
|
|
@@ -3762,23 +3762,23 @@ function splitByCase(str, separators) {
|
|
|
3762
3762
|
parts.push(buff);
|
|
3763
3763
|
return parts;
|
|
3764
3764
|
}
|
|
3765
|
-
function upperFirst(
|
|
3766
|
-
return
|
|
3765
|
+
function upperFirst(str3) {
|
|
3766
|
+
return str3 ? str3[0].toUpperCase() + str3.slice(1) : "";
|
|
3767
3767
|
}
|
|
3768
|
-
function lowerFirst(
|
|
3769
|
-
return
|
|
3768
|
+
function lowerFirst(str3) {
|
|
3769
|
+
return str3 ? str3[0].toLowerCase() + str3.slice(1) : "";
|
|
3770
3770
|
}
|
|
3771
|
-
function pascalCase(
|
|
3772
|
-
return
|
|
3771
|
+
function pascalCase(str3, opts) {
|
|
3772
|
+
return str3 ? (Array.isArray(str3) ? str3 : splitByCase(str3)).map((p) => upperFirst(opts?.normalize ? p.toLowerCase() : p)).join("") : "";
|
|
3773
3773
|
}
|
|
3774
|
-
function camelCase(
|
|
3775
|
-
return lowerFirst(pascalCase(
|
|
3774
|
+
function camelCase(str3, opts) {
|
|
3775
|
+
return lowerFirst(pascalCase(str3 || "", opts));
|
|
3776
3776
|
}
|
|
3777
|
-
function kebabCase(
|
|
3778
|
-
return
|
|
3777
|
+
function kebabCase(str3, joiner) {
|
|
3778
|
+
return str3 ? (Array.isArray(str3) ? str3 : splitByCase(str3)).map((p) => p.toLowerCase()).join(joiner ?? "-") : "";
|
|
3779
3779
|
}
|
|
3780
|
-
function snakeCase(
|
|
3781
|
-
return kebabCase(
|
|
3780
|
+
function snakeCase(str3) {
|
|
3781
|
+
return kebabCase(str3 || "", "_");
|
|
3782
3782
|
}
|
|
3783
3783
|
|
|
3784
3784
|
// ../../node_modules/.pnpm/citty@0.2.2/node_modules/citty/dist/index.mjs
|
|
@@ -4812,6 +4812,7 @@ var viewWorker = (cfg) => {
|
|
|
4812
4812
|
server,
|
|
4813
4813
|
projectId: project2,
|
|
4814
4814
|
workerId: worker2.id,
|
|
4815
|
+
agentKind: worker2.agentKind ?? "claude-code",
|
|
4815
4816
|
name: worker2.name,
|
|
4816
4817
|
machineId: worker2.machineId,
|
|
4817
4818
|
apiToken: worker2.apiToken
|
|
@@ -4820,7 +4821,13 @@ var viewWorker = (cfg) => {
|
|
|
4820
4821
|
var worktreeConfig = (cfg) => ({
|
|
4821
4822
|
server: cfg.server,
|
|
4822
4823
|
project: cfg.projectId,
|
|
4823
|
-
worker: {
|
|
4824
|
+
worker: {
|
|
4825
|
+
id: cfg.workerId,
|
|
4826
|
+
name: cfg.name,
|
|
4827
|
+
agentKind: cfg.agentKind,
|
|
4828
|
+
machineId: cfg.machineId,
|
|
4829
|
+
apiToken: cfg.apiToken
|
|
4830
|
+
}
|
|
4824
4831
|
});
|
|
4825
4832
|
|
|
4826
4833
|
// src/config.ts
|
|
@@ -4847,7 +4854,7 @@ var fmtComment = (c) => `${c.workerId !== void 0 ? `worker#${c.workerId}` : "you
|
|
|
4847
4854
|
var fmtSession = (s) => `${s.id} ${s.name} ${s.attached ? "[active]" : "[inactive]"} ${s.worktreePath ?? "(pending)"}`;
|
|
4848
4855
|
var fmtWorker = (w) => {
|
|
4849
4856
|
const offline = w.connected === false ? " [offline]" : "";
|
|
4850
|
-
return `W-${w.id} ${w.name} ${w.hostname}${offline}`;
|
|
4857
|
+
return `W-${w.id} ${w.name} ${w.hostname} ${w.agentKind}${offline}`;
|
|
4851
4858
|
};
|
|
4852
4859
|
var fmtInterval = (sec) => {
|
|
4853
4860
|
if (sec % 86400 === 0) return `${sec / 86400}d`;
|
|
@@ -5133,7 +5140,12 @@ var createWorkerClient = (baseUrl, workerToken, sessionId) => {
|
|
|
5133
5140
|
body: { active },
|
|
5134
5141
|
headers: auth
|
|
5135
5142
|
}),
|
|
5136
|
-
listEvents: () => request(u(`/sessions/${sessionId}/events`), { method: "GET", headers: auth })
|
|
5143
|
+
listEvents: () => request(u(`/sessions/${sessionId}/events`), { method: "GET", headers: auth }),
|
|
5144
|
+
materialize: (input) => request(u(`/sessions/${sessionId}`), {
|
|
5145
|
+
method: "PATCH",
|
|
5146
|
+
body: input,
|
|
5147
|
+
headers: auth
|
|
5148
|
+
})
|
|
5137
5149
|
};
|
|
5138
5150
|
};
|
|
5139
5151
|
|
|
@@ -6511,6 +6523,161 @@ var augmentPrompt = (text, relPaths, labels) => {
|
|
|
6511
6523
|
${text}` : header;
|
|
6512
6524
|
};
|
|
6513
6525
|
|
|
6526
|
+
// src/session/runner/codex.ts
|
|
6527
|
+
import { Codex } from "@openai/codex-sdk";
|
|
6528
|
+
var isRecord2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
6529
|
+
var str = (v) => typeof v === "string" ? v : void 0;
|
|
6530
|
+
var compactEnv = (env) => {
|
|
6531
|
+
if (!env) return void 0;
|
|
6532
|
+
const out = {};
|
|
6533
|
+
for (const [key, value] of Object.entries(env)) {
|
|
6534
|
+
if (value !== void 0) out[key] = value;
|
|
6535
|
+
}
|
|
6536
|
+
return out;
|
|
6537
|
+
};
|
|
6538
|
+
var statusOf = (v) => v === "in_progress" || v === "failed" || v === "completed" ? v : "completed";
|
|
6539
|
+
var itemId = (item) => str(item.id) ?? `${str(item.type) ?? "item"}-${Math.random().toString(36).slice(2)}`;
|
|
6540
|
+
var todoItems = (raw) => Array.isArray(raw) ? raw.filter(isRecord2).map((todo) => ({
|
|
6541
|
+
text: str(todo.text) ?? str(todo.content) ?? "",
|
|
6542
|
+
completed: todo.completed === true || todo.status === "completed"
|
|
6543
|
+
})) : [];
|
|
6544
|
+
var fileKind = (v) => v === "add" || v === "delete" || v === "update" ? v : "update";
|
|
6545
|
+
var toAgentItem = (raw) => {
|
|
6546
|
+
if (!isRecord2(raw)) {
|
|
6547
|
+
return {
|
|
6548
|
+
type: "error",
|
|
6549
|
+
id: "bad-item",
|
|
6550
|
+
status: "failed",
|
|
6551
|
+
message: "codex item was not an object"
|
|
6552
|
+
};
|
|
6553
|
+
}
|
|
6554
|
+
const type = str(raw.type);
|
|
6555
|
+
const id = itemId(raw);
|
|
6556
|
+
const status = statusOf(raw.status);
|
|
6557
|
+
if (type === "agent_message") {
|
|
6558
|
+
return { type, id, status, text: str(raw.text) ?? str(raw.message) ?? "" };
|
|
6559
|
+
}
|
|
6560
|
+
if (type === "reasoning") {
|
|
6561
|
+
return { type, id, status, text: str(raw.text) ?? str(raw.summary) ?? "" };
|
|
6562
|
+
}
|
|
6563
|
+
if (type === "command_execution") {
|
|
6564
|
+
return {
|
|
6565
|
+
type,
|
|
6566
|
+
id,
|
|
6567
|
+
status,
|
|
6568
|
+
command: str(raw.command) ?? "",
|
|
6569
|
+
output: str(raw.aggregated_output) ?? str(raw.output) ?? "",
|
|
6570
|
+
exitCode: typeof raw.exit_code === "number" ? raw.exit_code : void 0
|
|
6571
|
+
};
|
|
6572
|
+
}
|
|
6573
|
+
if (type === "file_change") {
|
|
6574
|
+
const changes = Array.isArray(raw.changes) ? raw.changes.filter(isRecord2).map((change) => ({
|
|
6575
|
+
path: str(change.path) ?? "",
|
|
6576
|
+
kind: fileKind(change.kind)
|
|
6577
|
+
})) : [];
|
|
6578
|
+
return { type, id, status, changes };
|
|
6579
|
+
}
|
|
6580
|
+
if (type === "mcp_tool_call") {
|
|
6581
|
+
return {
|
|
6582
|
+
type,
|
|
6583
|
+
id,
|
|
6584
|
+
status,
|
|
6585
|
+
server: str(raw.server) ?? "",
|
|
6586
|
+
tool: str(raw.tool) ?? str(raw.name) ?? "",
|
|
6587
|
+
arguments: raw.arguments ?? raw.input ?? null,
|
|
6588
|
+
output: raw.result ?? raw.output ?? raw.error,
|
|
6589
|
+
isError: raw.is_error === true || raw.error !== void 0
|
|
6590
|
+
};
|
|
6591
|
+
}
|
|
6592
|
+
if (type === "web_search") {
|
|
6593
|
+
return { type, id, status, query: str(raw.query) ?? "" };
|
|
6594
|
+
}
|
|
6595
|
+
if (type === "todo_list") {
|
|
6596
|
+
return { type, id, status, items: todoItems(raw.items) };
|
|
6597
|
+
}
|
|
6598
|
+
if (type === "error") {
|
|
6599
|
+
return { type, id, status: "failed", message: str(raw.message) ?? "codex error" };
|
|
6600
|
+
}
|
|
6601
|
+
return {
|
|
6602
|
+
type: "tool_call",
|
|
6603
|
+
id,
|
|
6604
|
+
status,
|
|
6605
|
+
name: str(raw.name) ?? type ?? "codex_item",
|
|
6606
|
+
input: raw,
|
|
6607
|
+
output: raw.output
|
|
6608
|
+
};
|
|
6609
|
+
};
|
|
6610
|
+
var usageOf = (raw) => {
|
|
6611
|
+
if (!isRecord2(raw)) return void 0;
|
|
6612
|
+
return {
|
|
6613
|
+
inputTokens: typeof raw.input_tokens === "number" ? raw.input_tokens : void 0,
|
|
6614
|
+
cachedInputTokens: typeof raw.cached_input_tokens === "number" ? raw.cached_input_tokens : void 0,
|
|
6615
|
+
outputTokens: typeof raw.output_tokens === "number" ? raw.output_tokens : void 0,
|
|
6616
|
+
reasoningOutputTokens: typeof raw.reasoning_output_tokens === "number" ? raw.reasoning_output_tokens : void 0
|
|
6617
|
+
};
|
|
6618
|
+
};
|
|
6619
|
+
var toAgentEvent = (raw) => {
|
|
6620
|
+
if (!isRecord2(raw)) return { type: "raw", raw };
|
|
6621
|
+
const type = str(raw.type);
|
|
6622
|
+
if (type === "thread.started") {
|
|
6623
|
+
return {
|
|
6624
|
+
type,
|
|
6625
|
+
sessionId: str(raw.thread_id) ?? str(raw.sessionId) ?? "",
|
|
6626
|
+
model: str(raw.model),
|
|
6627
|
+
raw
|
|
6628
|
+
};
|
|
6629
|
+
}
|
|
6630
|
+
if (type === "turn.started") return { type, raw };
|
|
6631
|
+
if ((type === "item.started" || type === "item.updated" || type === "item.completed") && raw.item !== void 0) {
|
|
6632
|
+
return { type, item: toAgentItem(raw.item), raw };
|
|
6633
|
+
}
|
|
6634
|
+
if (type === "turn.completed") return { type, usage: usageOf(raw.usage), raw };
|
|
6635
|
+
if (type === "turn.failed") {
|
|
6636
|
+
const error = isRecord2(raw.error) ? raw.error : raw;
|
|
6637
|
+
return { type, error: { message: str(error.message) ?? "codex turn failed" }, raw };
|
|
6638
|
+
}
|
|
6639
|
+
if (type === "error") return { type, message: str(raw.message) ?? "codex error", raw };
|
|
6640
|
+
return { type: "raw", raw };
|
|
6641
|
+
};
|
|
6642
|
+
var withPlanPrefix = (input) => {
|
|
6643
|
+
const prefix = "Plan mode: inspect and propose a plan only. Do not edit files or run mutating commands.\n\n";
|
|
6644
|
+
if (typeof input === "string") return `${prefix}${input}`;
|
|
6645
|
+
return input.map(
|
|
6646
|
+
(entry, i) => i === 0 && entry.type === "text" ? { ...entry, text: `${prefix}${entry.text}` } : entry
|
|
6647
|
+
);
|
|
6648
|
+
};
|
|
6649
|
+
async function* startCodexEvents(config, input, worker2, opts) {
|
|
6650
|
+
const env = compactEnv(buildSdkEnv(opts.envOverlay));
|
|
6651
|
+
const codex = new Codex(env ? { env } : void 0);
|
|
6652
|
+
const resuming = !config.agentSessionId.startsWith("pending:");
|
|
6653
|
+
const addDirs = additionalDirs();
|
|
6654
|
+
const threadOptions = {
|
|
6655
|
+
workingDirectory: config.worktreePath,
|
|
6656
|
+
skipGitRepoCheck: true,
|
|
6657
|
+
sandboxMode: opts.planMode ? "read-only" : "workspace-write",
|
|
6658
|
+
approvalPolicy: "never",
|
|
6659
|
+
...opts.model ? { model: opts.model } : {},
|
|
6660
|
+
...addDirs ? { additionalDirectories: addDirs } : {}
|
|
6661
|
+
};
|
|
6662
|
+
const thread = resuming ? codex.resumeThread(config.agentSessionId, threadOptions) : codex.startThread(threadOptions);
|
|
6663
|
+
const runInput = opts.planMode ? withPlanPrefix(input) : input;
|
|
6664
|
+
const { events } = await thread.runStreamed(runInput, {
|
|
6665
|
+
...opts.signal ? { signal: opts.signal } : {}
|
|
6666
|
+
});
|
|
6667
|
+
for await (const raw of events) {
|
|
6668
|
+
const event = toAgentEvent(raw);
|
|
6669
|
+
if (event.type === "thread.started" && !resuming && event.sessionId) {
|
|
6670
|
+
config.agentSessionId = event.sessionId;
|
|
6671
|
+
await worker2.materialize({
|
|
6672
|
+
agentSessionId: event.sessionId,
|
|
6673
|
+
worktreePath: config.worktreePath
|
|
6674
|
+
});
|
|
6675
|
+
opts.log(`[codex] thread ${event.sessionId}`);
|
|
6676
|
+
}
|
|
6677
|
+
yield event;
|
|
6678
|
+
}
|
|
6679
|
+
}
|
|
6680
|
+
|
|
6514
6681
|
// src/session/runner/query.ts
|
|
6515
6682
|
var startQuery = (config, text, resuming, queryFn, abortController, log, { envOverlay, planMode = false, model } = {}) => {
|
|
6516
6683
|
const env = buildSdkEnv(envOverlay);
|
|
@@ -6539,21 +6706,223 @@ var startQuery = (config, text, resuming, queryFn, abortController, log, { envOv
|
|
|
6539
6706
|
};
|
|
6540
6707
|
|
|
6541
6708
|
// src/session/runner/stream.ts
|
|
6542
|
-
var
|
|
6709
|
+
var streamAgentEvents = async (events, worker2) => {
|
|
6543
6710
|
let result = null;
|
|
6544
|
-
for await (const
|
|
6545
|
-
await worker2.emitEvent("
|
|
6546
|
-
if (
|
|
6711
|
+
for await (const event of events) {
|
|
6712
|
+
await worker2.emitEvent("agent_event", event);
|
|
6713
|
+
if (event.type === "turn.completed") {
|
|
6714
|
+
result = {
|
|
6715
|
+
subtype: event.subtype ?? "success",
|
|
6716
|
+
isError: false,
|
|
6717
|
+
resultText: ""
|
|
6718
|
+
};
|
|
6719
|
+
} else if (event.type === "turn.failed") {
|
|
6720
|
+
result = {
|
|
6721
|
+
subtype: event.error.subtype ?? "error",
|
|
6722
|
+
isError: true,
|
|
6723
|
+
resultText: event.error.message
|
|
6724
|
+
};
|
|
6725
|
+
}
|
|
6547
6726
|
}
|
|
6548
6727
|
return result;
|
|
6549
6728
|
};
|
|
6550
|
-
var
|
|
6729
|
+
var streamClaudeSdkEvents = (messages, worker2) => streamAgentEvents(claudeToAgentEvents(messages), worker2);
|
|
6730
|
+
var isRecord3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
6731
|
+
var str2 = (v) => typeof v === "string" ? v : void 0;
|
|
6732
|
+
var messageContent = (payload) => {
|
|
6733
|
+
const msg = payload.message;
|
|
6734
|
+
if (!isRecord3(msg) || !Array.isArray(msg.content)) return [];
|
|
6735
|
+
return msg.content.filter(isRecord3);
|
|
6736
|
+
};
|
|
6737
|
+
var textFromToolResult = (raw) => {
|
|
6738
|
+
const c = raw.content;
|
|
6739
|
+
if (typeof c === "string") return c;
|
|
6740
|
+
if (Array.isArray(c)) {
|
|
6741
|
+
return c.map((b) => isRecord3(b) && typeof b.text === "string" ? b.text : JSON.stringify(b)).join("\n");
|
|
6742
|
+
}
|
|
6743
|
+
return JSON.stringify(c ?? "");
|
|
6744
|
+
};
|
|
6745
|
+
var commandOf = (input) => {
|
|
6746
|
+
if (!isRecord3(input)) return "";
|
|
6747
|
+
return str2(input.command) ?? str2(input.cmd) ?? "";
|
|
6748
|
+
};
|
|
6749
|
+
var pathOf = (input) => {
|
|
6750
|
+
if (!isRecord3(input)) return void 0;
|
|
6751
|
+
return str2(input.file_path) ?? str2(input.path);
|
|
6752
|
+
};
|
|
6753
|
+
var fileKindOf = (name) => name === "Delete" ? "delete" : "update";
|
|
6754
|
+
var todoItems2 = (input) => {
|
|
6755
|
+
if (!isRecord3(input) || !Array.isArray(input.todos)) return [];
|
|
6756
|
+
return input.todos.filter(isRecord3).map((todo) => ({
|
|
6757
|
+
text: str2(todo.content) ?? str2(todo.text) ?? "",
|
|
6758
|
+
completed: todo.status === "completed" || todo.completed === true
|
|
6759
|
+
}));
|
|
6760
|
+
};
|
|
6761
|
+
var mcpParts = (name) => {
|
|
6762
|
+
const match = /^mcp__(.+?)__(.+)$/.exec(name);
|
|
6763
|
+
return match ? { server: match[1] ?? "", tool: match[2] ?? "" } : null;
|
|
6764
|
+
};
|
|
6765
|
+
var startedItemFromToolUse = (block) => {
|
|
6766
|
+
const id = str2(block.id) ?? `tool-${Math.random().toString(36).slice(2)}`;
|
|
6767
|
+
const name = str2(block.name) ?? "tool";
|
|
6768
|
+
const input = block.input ?? null;
|
|
6769
|
+
if (name === "Bash") {
|
|
6770
|
+
return {
|
|
6771
|
+
type: "command_execution",
|
|
6772
|
+
id,
|
|
6773
|
+
status: "in_progress",
|
|
6774
|
+
command: commandOf(input),
|
|
6775
|
+
output: ""
|
|
6776
|
+
};
|
|
6777
|
+
}
|
|
6778
|
+
if (name === "Edit" || name === "Write" || name === "MultiEdit" || name === "Delete") {
|
|
6779
|
+
const path = pathOf(input);
|
|
6780
|
+
return {
|
|
6781
|
+
type: "file_change",
|
|
6782
|
+
id,
|
|
6783
|
+
status: "in_progress",
|
|
6784
|
+
changes: path ? [{ path, kind: fileKindOf(name) }] : []
|
|
6785
|
+
};
|
|
6786
|
+
}
|
|
6787
|
+
const mcp = mcpParts(name);
|
|
6788
|
+
if (mcp) {
|
|
6789
|
+
return {
|
|
6790
|
+
type: "mcp_tool_call",
|
|
6791
|
+
id,
|
|
6792
|
+
status: "in_progress",
|
|
6793
|
+
server: mcp.server,
|
|
6794
|
+
tool: mcp.tool,
|
|
6795
|
+
arguments: input
|
|
6796
|
+
};
|
|
6797
|
+
}
|
|
6798
|
+
if (name === "WebSearch" || name === "web_search") {
|
|
6799
|
+
return {
|
|
6800
|
+
type: "web_search",
|
|
6801
|
+
id,
|
|
6802
|
+
status: "in_progress",
|
|
6803
|
+
query: isRecord3(input) ? str2(input.query) ?? "" : ""
|
|
6804
|
+
};
|
|
6805
|
+
}
|
|
6806
|
+
if (name === "TodoWrite") {
|
|
6807
|
+
return { type: "todo_list", id, status: "in_progress", items: todoItems2(input) };
|
|
6808
|
+
}
|
|
6809
|
+
return { type: "tool_call", id, status: "in_progress", name, input };
|
|
6810
|
+
};
|
|
6811
|
+
var completeItem = (item, output, isError) => {
|
|
6812
|
+
if (item.type === "command_execution")
|
|
6813
|
+
return { ...item, status: isError ? "failed" : "completed", output };
|
|
6814
|
+
if (item.type === "mcp_tool_call")
|
|
6815
|
+
return { ...item, status: isError ? "failed" : "completed", output, isError };
|
|
6816
|
+
if (item.type === "tool_call")
|
|
6817
|
+
return { ...item, status: isError ? "failed" : "completed", output, isError };
|
|
6818
|
+
return { ...item, status: isError ? "failed" : "completed" };
|
|
6819
|
+
};
|
|
6820
|
+
var resultEvent = (message) => {
|
|
6551
6821
|
const rec = message;
|
|
6552
|
-
const subtype =
|
|
6822
|
+
const subtype = str2(rec.subtype) ?? "unknown";
|
|
6553
6823
|
const isError = rec.is_error === true || subtype !== "success";
|
|
6554
|
-
const resultText =
|
|
6555
|
-
|
|
6824
|
+
const resultText = str2(rec.result) ?? "";
|
|
6825
|
+
const usage = {
|
|
6826
|
+
numTurns: typeof rec.num_turns === "number" ? rec.num_turns : void 0,
|
|
6827
|
+
totalCostUsd: typeof rec.total_cost_usd === "number" ? rec.total_cost_usd : void 0,
|
|
6828
|
+
durationMs: typeof rec.duration_ms === "number" ? rec.duration_ms : void 0
|
|
6829
|
+
};
|
|
6830
|
+
return isError ? {
|
|
6831
|
+
type: "turn.failed",
|
|
6832
|
+
error: { message: resultText || `claude result: ${subtype}`, subtype },
|
|
6833
|
+
usage,
|
|
6834
|
+
raw: message
|
|
6835
|
+
} : { type: "turn.completed", subtype, usage, raw: message };
|
|
6556
6836
|
};
|
|
6837
|
+
async function* claudeToAgentEvents(messages) {
|
|
6838
|
+
const pendingTools = /* @__PURE__ */ new Map();
|
|
6839
|
+
let systemEmitted = false;
|
|
6840
|
+
let textSeq = 0;
|
|
6841
|
+
let reasoningSeq = 0;
|
|
6842
|
+
for await (const message of messages) {
|
|
6843
|
+
const p = message;
|
|
6844
|
+
if (message.type === "system") {
|
|
6845
|
+
if (!systemEmitted) {
|
|
6846
|
+
systemEmitted = true;
|
|
6847
|
+
yield {
|
|
6848
|
+
type: "thread.started",
|
|
6849
|
+
sessionId: str2(p.session_id) ?? "",
|
|
6850
|
+
model: str2(p.model) ?? (isRecord3(p.model_info) ? str2(p.model_info.id) : void 0),
|
|
6851
|
+
raw: message
|
|
6852
|
+
};
|
|
6853
|
+
yield { type: "turn.started", raw: message };
|
|
6854
|
+
}
|
|
6855
|
+
continue;
|
|
6856
|
+
}
|
|
6857
|
+
if (message.type === "assistant") {
|
|
6858
|
+
for (const block of messageContent(p)) {
|
|
6859
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
6860
|
+
yield {
|
|
6861
|
+
type: "item.completed",
|
|
6862
|
+
item: {
|
|
6863
|
+
type: "agent_message",
|
|
6864
|
+
id: `assistant-${++textSeq}`,
|
|
6865
|
+
status: "completed",
|
|
6866
|
+
text: block.text
|
|
6867
|
+
},
|
|
6868
|
+
raw: block
|
|
6869
|
+
};
|
|
6870
|
+
} else if (block.type === "thinking" && typeof block.thinking === "string") {
|
|
6871
|
+
const text = block.thinking.trim();
|
|
6872
|
+
if (text) {
|
|
6873
|
+
yield {
|
|
6874
|
+
type: "item.completed",
|
|
6875
|
+
item: {
|
|
6876
|
+
type: "reasoning",
|
|
6877
|
+
id: `reasoning-${++reasoningSeq}`,
|
|
6878
|
+
status: "completed",
|
|
6879
|
+
text
|
|
6880
|
+
},
|
|
6881
|
+
raw: block
|
|
6882
|
+
};
|
|
6883
|
+
}
|
|
6884
|
+
} else if (block.type === "tool_use" || block.type === "server_tool_use") {
|
|
6885
|
+
const item = startedItemFromToolUse(block);
|
|
6886
|
+
pendingTools.set(item.id, item);
|
|
6887
|
+
yield { type: "item.started", item, raw: block };
|
|
6888
|
+
} else if (block.type === "tool_result") {
|
|
6889
|
+
const id = str2(block.tool_use_id) ?? "";
|
|
6890
|
+
const item = pendingTools.get(id);
|
|
6891
|
+
if (item) {
|
|
6892
|
+
const completed = completeItem(item, textFromToolResult(block), block.is_error === true);
|
|
6893
|
+
pendingTools.set(id, completed);
|
|
6894
|
+
yield { type: "item.completed", item: completed, raw: block };
|
|
6895
|
+
} else {
|
|
6896
|
+
yield { type: "raw", raw: block };
|
|
6897
|
+
}
|
|
6898
|
+
} else {
|
|
6899
|
+
yield { type: "raw", raw: block };
|
|
6900
|
+
}
|
|
6901
|
+
}
|
|
6902
|
+
continue;
|
|
6903
|
+
}
|
|
6904
|
+
if (message.type === "user") {
|
|
6905
|
+
for (const block of messageContent(p)) {
|
|
6906
|
+
if (block.type !== "tool_result") continue;
|
|
6907
|
+
const id = str2(block.tool_use_id) ?? "";
|
|
6908
|
+
const item = pendingTools.get(id);
|
|
6909
|
+
if (!item) {
|
|
6910
|
+
yield { type: "raw", raw: block };
|
|
6911
|
+
continue;
|
|
6912
|
+
}
|
|
6913
|
+
const completed = completeItem(item, textFromToolResult(block), block.is_error === true);
|
|
6914
|
+
pendingTools.set(id, completed);
|
|
6915
|
+
yield { type: "item.completed", item: completed, raw: block };
|
|
6916
|
+
}
|
|
6917
|
+
continue;
|
|
6918
|
+
}
|
|
6919
|
+
if (message.type === "result") {
|
|
6920
|
+
yield resultEvent(message);
|
|
6921
|
+
continue;
|
|
6922
|
+
}
|
|
6923
|
+
yield { type: "raw", raw: message };
|
|
6924
|
+
}
|
|
6925
|
+
}
|
|
6557
6926
|
|
|
6558
6927
|
// src/session/runner/turn.ts
|
|
6559
6928
|
var turnTimeoutMs = () => Number(process.env.BATON_TURN_TIMEOUT_MS) || 30 * 6e4;
|
|
@@ -6563,14 +6932,14 @@ var ABORTED = /* @__PURE__ */ Symbol("turn-aborted");
|
|
|
6563
6932
|
var finalizeTurn = async (result, worker2, log) => {
|
|
6564
6933
|
if (!result) {
|
|
6565
6934
|
log("[exit] stream ended with no result");
|
|
6566
|
-
await worker2.emitEvent("turn_error", { message: "
|
|
6935
|
+
await worker2.emitEvent("turn_error", { message: "agent produced no result" });
|
|
6567
6936
|
await worker2.emitEvent("turn_complete", {});
|
|
6568
6937
|
return -1;
|
|
6569
6938
|
}
|
|
6570
6939
|
log(`[exit] subtype=${result.subtype} isError=${result.isError}`);
|
|
6571
6940
|
if (result.isError) {
|
|
6572
6941
|
await worker2.emitEvent("turn_error", {
|
|
6573
|
-
message: result.resultText || `
|
|
6942
|
+
message: result.resultText || `agent result: ${result.subtype}`,
|
|
6574
6943
|
subtype: result.subtype
|
|
6575
6944
|
});
|
|
6576
6945
|
}
|
|
@@ -6578,7 +6947,7 @@ var finalizeTurn = async (result, worker2, log) => {
|
|
|
6578
6947
|
return result.isError ? 1 : 0;
|
|
6579
6948
|
};
|
|
6580
6949
|
var buildPrompt = async (config, rawText, attachments, log, fetchImpl) => {
|
|
6581
|
-
if (attachments.length === 0) return rawText;
|
|
6950
|
+
if (attachments.length === 0) return { text: rawText, input: rawText };
|
|
6582
6951
|
const relPaths = await materializeAttachments({
|
|
6583
6952
|
worktreePath: config.worktreePath,
|
|
6584
6953
|
serverBase: config.server,
|
|
@@ -6586,7 +6955,13 @@ var buildPrompt = async (config, rawText, attachments, log, fetchImpl) => {
|
|
|
6586
6955
|
fetchImpl
|
|
6587
6956
|
});
|
|
6588
6957
|
log(`[attach] downloaded ${relPaths.length} file(s) \u2192 ${config.worktreePath}/attachments`);
|
|
6589
|
-
|
|
6958
|
+
const labels = labelAttachments(attachments);
|
|
6959
|
+
const text = augmentPrompt(rawText, relPaths, labels);
|
|
6960
|
+
const images = relPaths.flatMap((relPath, i) => {
|
|
6961
|
+
const att = attachments[i];
|
|
6962
|
+
return att?.contentType.startsWith("image/") ? [{ type: "local_image", path: `${config.worktreePath}/${relPath}` }] : [];
|
|
6963
|
+
});
|
|
6964
|
+
return images.length > 0 ? { text, input: [{ type: "text", text }, ...images] } : { text, input: text };
|
|
6590
6965
|
};
|
|
6591
6966
|
var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => console.log(m), envOverlay, fetchImpl, externalSignal) => {
|
|
6592
6967
|
await worker2.emitEvent("turn_start", { messageId: msg.id });
|
|
@@ -6599,9 +6974,9 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
6599
6974
|
await worker2.emitEvent("turn_error", { message: "user_message missing text and attachments" });
|
|
6600
6975
|
return -1;
|
|
6601
6976
|
}
|
|
6602
|
-
let
|
|
6977
|
+
let built;
|
|
6603
6978
|
try {
|
|
6604
|
-
|
|
6979
|
+
built = await buildPrompt(config, rawText, attachments, log, fetchImpl);
|
|
6605
6980
|
} catch (err) {
|
|
6606
6981
|
const message = err instanceof Error ? err.message : String(err);
|
|
6607
6982
|
await worker2.emitEvent("turn_error", { message: `attachment download failed: ${message}` });
|
|
@@ -6622,12 +6997,23 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
6622
6997
|
heartbeat = setInterval(() => {
|
|
6623
6998
|
void worker2.emitEvent("turn_heartbeat", {}).catch((e) => log(`[heartbeat] ${String(e)}`));
|
|
6624
6999
|
}, heartbeatMs());
|
|
6625
|
-
const
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
7000
|
+
const consume = config.agentKind === "codex" ? streamAgentEvents(
|
|
7001
|
+
startCodexEvents(config, built.input, worker2, {
|
|
7002
|
+
envOverlay,
|
|
7003
|
+
planMode,
|
|
7004
|
+
model,
|
|
7005
|
+
signal: abort.signal,
|
|
7006
|
+
log
|
|
7007
|
+
}),
|
|
7008
|
+
worker2
|
|
7009
|
+
) : streamClaudeSdkEvents(
|
|
7010
|
+
startQuery(config, built.text, resuming, queryFn, abort, log, {
|
|
7011
|
+
envOverlay,
|
|
7012
|
+
planMode,
|
|
7013
|
+
model
|
|
7014
|
+
}),
|
|
7015
|
+
worker2
|
|
7016
|
+
);
|
|
6631
7017
|
void consume.catch(() => {
|
|
6632
7018
|
});
|
|
6633
7019
|
const outcome = await Promise.race([consume, timeout, interrupted]);
|
|
@@ -6639,10 +7025,10 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
6639
7025
|
return -1;
|
|
6640
7026
|
}
|
|
6641
7027
|
if (outcome === TIMEOUT) {
|
|
6642
|
-
log(`[watchdog] turn exceeded ${ceiling}ms \u2014 aborting
|
|
7028
|
+
log(`[watchdog] turn exceeded ${ceiling}ms \u2014 aborting agent`);
|
|
6643
7029
|
abort.abort();
|
|
6644
7030
|
await worker2.emitEvent("turn_error", {
|
|
6645
|
-
message: `turn exceeded ${ceiling}ms \u2014
|
|
7031
|
+
message: `turn exceeded ${ceiling}ms \u2014 agent aborted`
|
|
6646
7032
|
});
|
|
6647
7033
|
await worker2.emitEvent("turn_complete", {});
|
|
6648
7034
|
return -1;
|
|
@@ -6698,7 +7084,7 @@ var runDaemon = async (config, deps, signal) => {
|
|
|
6698
7084
|
log(`bin: ${claudeExecutable() ?? "(sdk bundled)"} cwd: ${config.worktreePath}`);
|
|
6699
7085
|
log(`runtime env keys: ${maskedEnvKeys(deps.env)}`);
|
|
6700
7086
|
const state = {
|
|
6701
|
-
firstSpawnDone: findTranscriptPath(config.agentSessionId) !== null,
|
|
7087
|
+
firstSpawnDone: config.agentKind === "codex" ? !config.agentSessionId.startsWith("pending:") : findTranscriptPath(config.agentSessionId) !== null,
|
|
6702
7088
|
seen: /* @__PURE__ */ new Set()
|
|
6703
7089
|
};
|
|
6704
7090
|
const pendingQueue = [];
|
|
@@ -6866,6 +7252,7 @@ var sessionRunCommand = defineCommand({
|
|
|
6866
7252
|
server,
|
|
6867
7253
|
sessionId,
|
|
6868
7254
|
name: s.name,
|
|
7255
|
+
agentKind: s.agentKind,
|
|
6869
7256
|
agentSessionId: s.agentSessionId,
|
|
6870
7257
|
worktreePath: s.worktreePath
|
|
6871
7258
|
};
|
|
@@ -7147,7 +7534,7 @@ var task = defineCommand({
|
|
|
7147
7534
|
}
|
|
7148
7535
|
});
|
|
7149
7536
|
|
|
7150
|
-
// src/commands/worker.ts
|
|
7537
|
+
// src/commands/worker/index.ts
|
|
7151
7538
|
import { hostname as osHostname } from "node:os";
|
|
7152
7539
|
|
|
7153
7540
|
// src/worker/watchdog.ts
|
|
@@ -7408,12 +7795,13 @@ var createSessionSupervisor = (deps) => {
|
|
|
7408
7795
|
const session2 = await client.sessions.get(sessionId);
|
|
7409
7796
|
let worktreePath = session2.worktreePath;
|
|
7410
7797
|
if (!session2.agentSessionId || !worktreePath) {
|
|
7411
|
-
const
|
|
7412
|
-
|
|
7798
|
+
const sessionCode = randomUUID();
|
|
7799
|
+
const agentSessionId = session2.agentKind === "codex" ? `pending:${sessionCode}` : sessionCode;
|
|
7800
|
+
worktreePath = join7(worktreeDir, slug(`${name}-${sessionCode.slice(0, 8)}`));
|
|
7413
7801
|
createWorktree({
|
|
7414
7802
|
repo,
|
|
7415
7803
|
worktreePath,
|
|
7416
|
-
sessionCode:
|
|
7804
|
+
sessionCode: sessionCode.slice(0, 8),
|
|
7417
7805
|
base: repoHeadBranch(repo)
|
|
7418
7806
|
});
|
|
7419
7807
|
await client.sessions.materialize(sessionId, { agentSessionId, worktreePath }, cfg.apiToken);
|
|
@@ -7448,6 +7836,8 @@ var createSessionSupervisor = (deps) => {
|
|
|
7448
7836
|
log(`deleted session #${sessionId} (removed worktree)`);
|
|
7449
7837
|
};
|
|
7450
7838
|
const title = async (sessionId, agentSessionId, worktreePath) => {
|
|
7839
|
+
const session2 = await client.sessions.get(sessionId);
|
|
7840
|
+
if (session2.agentKind !== "claude-code") return log(`title #${sessionId}: unsupported agent`);
|
|
7451
7841
|
const exchange = readFirstExchange(agentSessionId);
|
|
7452
7842
|
if (!exchange) return log(`title #${sessionId}: no transcript yet, skipping`);
|
|
7453
7843
|
const outcome = await generateTitle({
|
|
@@ -7694,7 +8084,7 @@ var readOrCreateMachineId = (path = machineIdPath()) => {
|
|
|
7694
8084
|
return id;
|
|
7695
8085
|
};
|
|
7696
8086
|
|
|
7697
|
-
// src/commands/worker.ts
|
|
8087
|
+
// src/commands/worker/index.ts
|
|
7698
8088
|
var resolveWorker = async (client, projectId, handle) => {
|
|
7699
8089
|
const asId = parseWorkerHandle(handle);
|
|
7700
8090
|
if (asId !== null) {
|
|
@@ -7705,9 +8095,15 @@ var resolveWorker = async (client, projectId, handle) => {
|
|
|
7705
8095
|
if (byName) return { id: byName.id, name: byName.name };
|
|
7706
8096
|
throw new Error(`worker "${handle}" not found in project ${projectId}`);
|
|
7707
8097
|
};
|
|
8098
|
+
var parseAgentKind = (value) => {
|
|
8099
|
+
const raw = typeof value === "string" && value.trim() ? value.trim() : "claude-code";
|
|
8100
|
+
if (raw === "claude-code" || raw === "codex") return raw;
|
|
8101
|
+
throw new Error(`invalid agent kind "${raw}" (expected claude-code or codex)`);
|
|
8102
|
+
};
|
|
7708
8103
|
var registerWorker = async (client, input, cfgPath = projectConfigPath()) => {
|
|
7709
8104
|
const out = await client.workers.register({
|
|
7710
8105
|
projectId: input.projectId,
|
|
8106
|
+
agentKind: input.agentKind,
|
|
7711
8107
|
machineId: input.machineId,
|
|
7712
8108
|
name: input.name,
|
|
7713
8109
|
hostname: input.hostname
|
|
@@ -7720,6 +8116,7 @@ var registerWorker = async (client, input, cfgPath = projectConfigPath()) => {
|
|
|
7720
8116
|
setWorker(cfgPath, {
|
|
7721
8117
|
id: out.worker.id,
|
|
7722
8118
|
name: out.worker.name,
|
|
8119
|
+
agentKind: out.worker.agentKind,
|
|
7723
8120
|
machineId: out.worker.machineId,
|
|
7724
8121
|
apiToken: out.apiToken
|
|
7725
8122
|
});
|
|
@@ -7740,6 +8137,10 @@ var worker = defineCommand({
|
|
|
7740
8137
|
type: "string",
|
|
7741
8138
|
description: "path to the worker config file (default: ./.baton.json)"
|
|
7742
8139
|
},
|
|
8140
|
+
agentKind: {
|
|
8141
|
+
type: "string",
|
|
8142
|
+
description: "agent engine for new sessions: claude-code or codex"
|
|
8143
|
+
},
|
|
7743
8144
|
...common
|
|
7744
8145
|
},
|
|
7745
8146
|
run: async ({ args }) => {
|
|
@@ -7756,6 +8157,7 @@ var worker = defineCommand({
|
|
|
7756
8157
|
const hostname = osHostname();
|
|
7757
8158
|
const machineId = readOrCreateMachineId();
|
|
7758
8159
|
const name = args.name ?? hostname;
|
|
8160
|
+
const agentKind = parseAgentKind(args.agentKind ?? process.env.BATON_AGENT_KIND);
|
|
7759
8161
|
const { out, configPath } = await registerWorker(
|
|
7760
8162
|
c,
|
|
7761
8163
|
{
|
|
@@ -7763,7 +8165,8 @@ var worker = defineCommand({
|
|
|
7763
8165
|
name,
|
|
7764
8166
|
server,
|
|
7765
8167
|
hostname,
|
|
7766
|
-
machineId
|
|
8168
|
+
machineId,
|
|
8169
|
+
agentKind
|
|
7767
8170
|
},
|
|
7768
8171
|
cfgPath
|
|
7769
8172
|
);
|
|
@@ -7772,6 +8175,7 @@ var worker = defineCommand({
|
|
|
7772
8175
|
return;
|
|
7773
8176
|
}
|
|
7774
8177
|
console.log(`worker #${out.worker.id} (${out.worker.name}) \u2014 ${out.outcome}`);
|
|
8178
|
+
console.log(` agentKind: ${out.worker.agentKind}`);
|
|
7775
8179
|
console.log(` hostname: ${out.worker.hostname}`);
|
|
7776
8180
|
console.log(` machineId: ${out.worker.machineId}`);
|
|
7777
8181
|
console.log(` machineId file: ${machineIdPath()}`);
|
|
@@ -7886,6 +8290,7 @@ var worker = defineCommand({
|
|
|
7886
8290
|
}
|
|
7887
8291
|
console.log(`worker #${worker2.id} (${worker2.name})`);
|
|
7888
8292
|
console.log(` machineId: ${worker2.machineId}`);
|
|
8293
|
+
console.log(` agentKind: ${worker2.agentKind ?? "claude-code"}`);
|
|
7889
8294
|
console.log(` server: ${cfg?.server}`);
|
|
7890
8295
|
}
|
|
7891
8296
|
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lesscap/baton-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"license": "MIT",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
5
8
|
"type": "module",
|
|
6
9
|
"description": "baton CLI — register/run a worker, manage projects/requirements/tasks/sessions",
|
|
7
10
|
"bin": {
|
|
@@ -23,6 +26,7 @@
|
|
|
23
26
|
},
|
|
24
27
|
"dependencies": {
|
|
25
28
|
"@anthropic-ai/claude-agent-sdk": "^0.3.161",
|
|
29
|
+
"@openai/codex-sdk": "^0.142.5",
|
|
26
30
|
"node-pty": "^1.1.0",
|
|
27
31
|
"ws": "^8.21.0"
|
|
28
32
|
},
|