@lesscap/baton-cli 0.4.1 → 0.4.3
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 +1014 -83
- package/package.json +5 -1
- package/scripts/postinstall.mjs +18 -9
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
|
|
@@ -4777,30 +4777,30 @@ import { join } from "node:path";
|
|
|
4777
4777
|
var PROJECT_CONFIG_NAME = ".baton.json";
|
|
4778
4778
|
var projectConfigPath = (cwd = process.cwd()) => join(cwd, PROJECT_CONFIG_NAME);
|
|
4779
4779
|
var configPathFromArgs = (args, cwd) => args.config ?? projectConfigPath(cwd);
|
|
4780
|
-
var loadProjectConfig = (
|
|
4780
|
+
var loadProjectConfig = (path3) => {
|
|
4781
4781
|
try {
|
|
4782
|
-
return JSON.parse(readFileSync(
|
|
4782
|
+
return JSON.parse(readFileSync(path3, "utf8"));
|
|
4783
4783
|
} catch (err) {
|
|
4784
|
-
const cause = err.code === "ENOENT" ? `not found at ${
|
|
4784
|
+
const cause = err.code === "ENOENT" ? `not found at ${path3}` : String(err);
|
|
4785
4785
|
throw new Error(`${PROJECT_CONFIG_NAME} ${cause} \u2014 run \`baton init\` first`);
|
|
4786
4786
|
}
|
|
4787
4787
|
};
|
|
4788
|
-
var loadProjectConfigOrNull = (
|
|
4789
|
-
if (!existsSync(
|
|
4788
|
+
var loadProjectConfigOrNull = (path3) => {
|
|
4789
|
+
if (!existsSync(path3)) return null;
|
|
4790
4790
|
try {
|
|
4791
|
-
return JSON.parse(readFileSync(
|
|
4791
|
+
return JSON.parse(readFileSync(path3, "utf8"));
|
|
4792
4792
|
} catch {
|
|
4793
4793
|
return null;
|
|
4794
4794
|
}
|
|
4795
4795
|
};
|
|
4796
|
-
var saveProjectConfig = (
|
|
4797
|
-
writeFileSync(
|
|
4796
|
+
var saveProjectConfig = (path3, config) => {
|
|
4797
|
+
writeFileSync(path3, `${JSON.stringify(config, null, 2)}
|
|
4798
4798
|
`, "utf8");
|
|
4799
4799
|
};
|
|
4800
|
-
var patch = (
|
|
4801
|
-
saveProjectConfig(
|
|
4800
|
+
var patch = (path3, fn) => {
|
|
4801
|
+
saveProjectConfig(path3, fn(loadProjectConfig(path3)));
|
|
4802
4802
|
};
|
|
4803
|
-
var setWorker = (
|
|
4803
|
+
var setWorker = (path3, w) => patch(path3, (cfg) => ({ ...cfg, worker: w }));
|
|
4804
4804
|
var requireBase = (cfg) => {
|
|
4805
4805
|
if (!cfg.server || !cfg.project || !cfg.worker)
|
|
4806
4806
|
throw new Error("project-config missing server/project/worker \u2014 run `baton worker register`");
|
|
@@ -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
|
|
|
@@ -5554,7 +5566,7 @@ var BY_EXT = {
|
|
|
5554
5566
|
".json": "application/json",
|
|
5555
5567
|
".csv": "text/csv"
|
|
5556
5568
|
};
|
|
5557
|
-
var contentTypeForPath = (
|
|
5569
|
+
var contentTypeForPath = (path3) => BY_EXT[extname(path3).toLowerCase()] ?? "application/octet-stream";
|
|
5558
5570
|
|
|
5559
5571
|
// src/commands/attach.ts
|
|
5560
5572
|
import { openAsBlob } from "node:fs";
|
|
@@ -5562,12 +5574,12 @@ import { basename } from "node:path";
|
|
|
5562
5574
|
var attachPaths = (raw) => (raw === void 0 ? [] : Array.isArray(raw) ? raw : [raw]).flatMap((p) => p.split(",")).map((p) => p.trim()).filter(Boolean);
|
|
5563
5575
|
var uploadAttachments = async (client, sessionId, paths) => {
|
|
5564
5576
|
const out = [];
|
|
5565
|
-
for (const
|
|
5566
|
-
const body = await openAsBlob(
|
|
5577
|
+
for (const path3 of paths) {
|
|
5578
|
+
const body = await openAsBlob(path3, { type: contentTypeForPath(path3) });
|
|
5567
5579
|
out.push(
|
|
5568
5580
|
await client.sessions.uploadAttachment(sessionId, {
|
|
5569
|
-
filename: basename(
|
|
5570
|
-
contentType: contentTypeForPath(
|
|
5581
|
+
filename: basename(path3),
|
|
5582
|
+
contentType: contentTypeForPath(path3),
|
|
5571
5583
|
body
|
|
5572
5584
|
})
|
|
5573
5585
|
);
|
|
@@ -5600,12 +5612,12 @@ var sendCommand = defineCommand({
|
|
|
5600
5612
|
if (text === void 0 && args.file) text = readFileSync2(args.file, "utf8");
|
|
5601
5613
|
if (text === void 0 && !process.stdin.isTTY) text = await readStdin();
|
|
5602
5614
|
const attachments = [];
|
|
5603
|
-
for (const
|
|
5615
|
+
for (const path3 of attachPaths(args.attach)) {
|
|
5604
5616
|
attachments.push(
|
|
5605
5617
|
await client.uploadAttachment(args.channel, {
|
|
5606
|
-
filename: basename2(
|
|
5607
|
-
contentType: contentTypeForPath(
|
|
5608
|
-
body: await openAsBlob2(
|
|
5618
|
+
filename: basename2(path3),
|
|
5619
|
+
contentType: contentTypeForPath(path3),
|
|
5620
|
+
body: await openAsBlob2(path3, { type: contentTypeForPath(path3) })
|
|
5609
5621
|
})
|
|
5610
5622
|
);
|
|
5611
5623
|
}
|
|
@@ -6451,10 +6463,10 @@ var parseFirstExchange = (content) => {
|
|
|
6451
6463
|
return userText || assistantText ? { userText, assistantText } : null;
|
|
6452
6464
|
};
|
|
6453
6465
|
var readFirstExchange = (agentSessionId) => {
|
|
6454
|
-
const
|
|
6455
|
-
if (!
|
|
6466
|
+
const path3 = findTranscriptPath(agentSessionId);
|
|
6467
|
+
if (!path3) return null;
|
|
6456
6468
|
try {
|
|
6457
|
-
return parseFirstExchange(readFileSync4(
|
|
6469
|
+
return parseFirstExchange(readFileSync4(path3, "utf8"));
|
|
6458
6470
|
} catch {
|
|
6459
6471
|
return null;
|
|
6460
6472
|
}
|
|
@@ -6511,6 +6523,687 @@ var augmentPrompt = (text, relPaths, labels) => {
|
|
|
6511
6523
|
${text}` : header;
|
|
6512
6524
|
};
|
|
6513
6525
|
|
|
6526
|
+
// ../../node_modules/.pnpm/@openai+codex-sdk@0.142.5/node_modules/@openai/codex-sdk/dist/index.js
|
|
6527
|
+
import { promises as fs } from "fs";
|
|
6528
|
+
import os from "os";
|
|
6529
|
+
import path from "path";
|
|
6530
|
+
import { spawn } from "child_process";
|
|
6531
|
+
import { statSync as statSync2 } from "fs";
|
|
6532
|
+
import path2 from "path";
|
|
6533
|
+
import readline2 from "readline";
|
|
6534
|
+
import { createRequire } from "module";
|
|
6535
|
+
async function createOutputSchemaFile(schema) {
|
|
6536
|
+
if (schema === void 0) {
|
|
6537
|
+
return { cleanup: async () => {
|
|
6538
|
+
} };
|
|
6539
|
+
}
|
|
6540
|
+
if (!isJsonObject(schema)) {
|
|
6541
|
+
throw new Error("outputSchema must be a plain JSON object");
|
|
6542
|
+
}
|
|
6543
|
+
const schemaDir = await fs.mkdtemp(path.join(os.tmpdir(), "codex-output-schema-"));
|
|
6544
|
+
const schemaPath = path.join(schemaDir, "schema.json");
|
|
6545
|
+
const cleanup = async () => {
|
|
6546
|
+
try {
|
|
6547
|
+
await fs.rm(schemaDir, { recursive: true, force: true });
|
|
6548
|
+
} catch {
|
|
6549
|
+
}
|
|
6550
|
+
};
|
|
6551
|
+
try {
|
|
6552
|
+
await fs.writeFile(schemaPath, JSON.stringify(schema), "utf8");
|
|
6553
|
+
return { schemaPath, cleanup };
|
|
6554
|
+
} catch (error) {
|
|
6555
|
+
await cleanup();
|
|
6556
|
+
throw error;
|
|
6557
|
+
}
|
|
6558
|
+
}
|
|
6559
|
+
function isJsonObject(value) {
|
|
6560
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6561
|
+
}
|
|
6562
|
+
var Thread = class {
|
|
6563
|
+
_exec;
|
|
6564
|
+
_options;
|
|
6565
|
+
_id;
|
|
6566
|
+
_threadOptions;
|
|
6567
|
+
/** Returns the ID of the thread. Populated after the first turn starts. */
|
|
6568
|
+
get id() {
|
|
6569
|
+
return this._id;
|
|
6570
|
+
}
|
|
6571
|
+
/* @internal */
|
|
6572
|
+
constructor(exec, options, threadOptions, id = null) {
|
|
6573
|
+
this._exec = exec;
|
|
6574
|
+
this._options = options;
|
|
6575
|
+
this._id = id;
|
|
6576
|
+
this._threadOptions = threadOptions;
|
|
6577
|
+
}
|
|
6578
|
+
/** Provides the input to the agent and streams events as they are produced during the turn. */
|
|
6579
|
+
async runStreamed(input, turnOptions = {}) {
|
|
6580
|
+
return { events: this.runStreamedInternal(input, turnOptions) };
|
|
6581
|
+
}
|
|
6582
|
+
async *runStreamedInternal(input, turnOptions = {}) {
|
|
6583
|
+
const { schemaPath, cleanup } = await createOutputSchemaFile(turnOptions.outputSchema);
|
|
6584
|
+
const options = this._threadOptions;
|
|
6585
|
+
const { prompt, images } = normalizeInput(input);
|
|
6586
|
+
const generator = this._exec.run({
|
|
6587
|
+
input: prompt,
|
|
6588
|
+
baseUrl: this._options.baseUrl,
|
|
6589
|
+
apiKey: this._options.apiKey,
|
|
6590
|
+
threadId: this._id,
|
|
6591
|
+
images,
|
|
6592
|
+
model: options?.model,
|
|
6593
|
+
sandboxMode: options?.sandboxMode,
|
|
6594
|
+
workingDirectory: options?.workingDirectory,
|
|
6595
|
+
skipGitRepoCheck: options?.skipGitRepoCheck,
|
|
6596
|
+
outputSchemaFile: schemaPath,
|
|
6597
|
+
modelReasoningEffort: options?.modelReasoningEffort,
|
|
6598
|
+
signal: turnOptions.signal,
|
|
6599
|
+
networkAccessEnabled: options?.networkAccessEnabled,
|
|
6600
|
+
webSearchMode: options?.webSearchMode,
|
|
6601
|
+
webSearchEnabled: options?.webSearchEnabled,
|
|
6602
|
+
approvalPolicy: options?.approvalPolicy,
|
|
6603
|
+
additionalDirectories: options?.additionalDirectories
|
|
6604
|
+
});
|
|
6605
|
+
try {
|
|
6606
|
+
for await (const item of generator) {
|
|
6607
|
+
let parsed;
|
|
6608
|
+
try {
|
|
6609
|
+
parsed = JSON.parse(item);
|
|
6610
|
+
} catch (error) {
|
|
6611
|
+
throw new Error(`Failed to parse item: ${item}`, { cause: error });
|
|
6612
|
+
}
|
|
6613
|
+
if (parsed.type === "thread.started") {
|
|
6614
|
+
this._id = parsed.thread_id;
|
|
6615
|
+
}
|
|
6616
|
+
yield parsed;
|
|
6617
|
+
}
|
|
6618
|
+
} finally {
|
|
6619
|
+
await cleanup();
|
|
6620
|
+
}
|
|
6621
|
+
}
|
|
6622
|
+
/** Provides the input to the agent and returns the completed turn. */
|
|
6623
|
+
async run(input, turnOptions = {}) {
|
|
6624
|
+
const generator = this.runStreamedInternal(input, turnOptions);
|
|
6625
|
+
const items = [];
|
|
6626
|
+
let finalResponse = "";
|
|
6627
|
+
let usage = null;
|
|
6628
|
+
let turnFailure = null;
|
|
6629
|
+
for await (const event of generator) {
|
|
6630
|
+
if (event.type === "item.completed") {
|
|
6631
|
+
if (event.item.type === "agent_message") {
|
|
6632
|
+
finalResponse = event.item.text;
|
|
6633
|
+
}
|
|
6634
|
+
items.push(event.item);
|
|
6635
|
+
} else if (event.type === "turn.completed") {
|
|
6636
|
+
usage = event.usage;
|
|
6637
|
+
} else if (event.type === "turn.failed") {
|
|
6638
|
+
turnFailure = event.error;
|
|
6639
|
+
break;
|
|
6640
|
+
}
|
|
6641
|
+
}
|
|
6642
|
+
if (turnFailure) {
|
|
6643
|
+
throw new Error(turnFailure.message);
|
|
6644
|
+
}
|
|
6645
|
+
return { items, finalResponse, usage };
|
|
6646
|
+
}
|
|
6647
|
+
};
|
|
6648
|
+
function normalizeInput(input) {
|
|
6649
|
+
if (typeof input === "string") {
|
|
6650
|
+
return { prompt: input, images: [] };
|
|
6651
|
+
}
|
|
6652
|
+
const promptParts = [];
|
|
6653
|
+
const images = [];
|
|
6654
|
+
for (const item of input) {
|
|
6655
|
+
if (item.type === "text") {
|
|
6656
|
+
promptParts.push(item.text);
|
|
6657
|
+
} else if (item.type === "local_image") {
|
|
6658
|
+
images.push(item.path);
|
|
6659
|
+
}
|
|
6660
|
+
}
|
|
6661
|
+
return { prompt: promptParts.join("\n\n"), images };
|
|
6662
|
+
}
|
|
6663
|
+
var INTERNAL_ORIGINATOR_ENV = "CODEX_INTERNAL_ORIGINATOR_OVERRIDE";
|
|
6664
|
+
var TYPESCRIPT_SDK_ORIGINATOR = "codex_sdk_ts";
|
|
6665
|
+
var CODEX_NPM_NAME = "@openai/codex";
|
|
6666
|
+
var PLATFORM_PACKAGE_BY_TARGET = {
|
|
6667
|
+
"x86_64-unknown-linux-musl": "@openai/codex-linux-x64",
|
|
6668
|
+
"aarch64-unknown-linux-musl": "@openai/codex-linux-arm64",
|
|
6669
|
+
"x86_64-apple-darwin": "@openai/codex-darwin-x64",
|
|
6670
|
+
"aarch64-apple-darwin": "@openai/codex-darwin-arm64",
|
|
6671
|
+
"x86_64-pc-windows-msvc": "@openai/codex-win32-x64",
|
|
6672
|
+
"aarch64-pc-windows-msvc": "@openai/codex-win32-arm64"
|
|
6673
|
+
};
|
|
6674
|
+
var moduleRequire = createRequire(import.meta.url);
|
|
6675
|
+
var CodexExec = class {
|
|
6676
|
+
executablePath;
|
|
6677
|
+
pathDirs;
|
|
6678
|
+
envOverride;
|
|
6679
|
+
configOverrides;
|
|
6680
|
+
constructor(executablePath = null, env, configOverrides) {
|
|
6681
|
+
if (executablePath) {
|
|
6682
|
+
this.executablePath = executablePath;
|
|
6683
|
+
this.pathDirs = [];
|
|
6684
|
+
} else {
|
|
6685
|
+
const resolved = findCodexPath();
|
|
6686
|
+
this.executablePath = resolved.executablePath;
|
|
6687
|
+
this.pathDirs = resolved.pathDirs;
|
|
6688
|
+
}
|
|
6689
|
+
this.envOverride = env;
|
|
6690
|
+
this.configOverrides = configOverrides;
|
|
6691
|
+
}
|
|
6692
|
+
async *run(args) {
|
|
6693
|
+
const commandArgs = ["exec", "--experimental-json"];
|
|
6694
|
+
if (this.configOverrides) {
|
|
6695
|
+
for (const override of serializeConfigOverrides(this.configOverrides)) {
|
|
6696
|
+
commandArgs.push("--config", override);
|
|
6697
|
+
}
|
|
6698
|
+
}
|
|
6699
|
+
if (args.baseUrl) {
|
|
6700
|
+
commandArgs.push(
|
|
6701
|
+
"--config",
|
|
6702
|
+
`openai_base_url=${toTomlValue(args.baseUrl, "openai_base_url")}`
|
|
6703
|
+
);
|
|
6704
|
+
}
|
|
6705
|
+
if (args.model) {
|
|
6706
|
+
commandArgs.push("--model", args.model);
|
|
6707
|
+
}
|
|
6708
|
+
if (args.sandboxMode) {
|
|
6709
|
+
commandArgs.push("--sandbox", args.sandboxMode);
|
|
6710
|
+
}
|
|
6711
|
+
if (args.workingDirectory) {
|
|
6712
|
+
commandArgs.push("--cd", args.workingDirectory);
|
|
6713
|
+
}
|
|
6714
|
+
if (args.additionalDirectories?.length) {
|
|
6715
|
+
for (const dir of args.additionalDirectories) {
|
|
6716
|
+
commandArgs.push("--add-dir", dir);
|
|
6717
|
+
}
|
|
6718
|
+
}
|
|
6719
|
+
if (args.skipGitRepoCheck) {
|
|
6720
|
+
commandArgs.push("--skip-git-repo-check");
|
|
6721
|
+
}
|
|
6722
|
+
if (args.outputSchemaFile) {
|
|
6723
|
+
commandArgs.push("--output-schema", args.outputSchemaFile);
|
|
6724
|
+
}
|
|
6725
|
+
if (args.modelReasoningEffort) {
|
|
6726
|
+
commandArgs.push("--config", `model_reasoning_effort="${args.modelReasoningEffort}"`);
|
|
6727
|
+
}
|
|
6728
|
+
if (args.networkAccessEnabled !== void 0) {
|
|
6729
|
+
commandArgs.push(
|
|
6730
|
+
"--config",
|
|
6731
|
+
`sandbox_workspace_write.network_access=${args.networkAccessEnabled}`
|
|
6732
|
+
);
|
|
6733
|
+
}
|
|
6734
|
+
if (args.webSearchMode) {
|
|
6735
|
+
commandArgs.push("--config", `web_search="${args.webSearchMode}"`);
|
|
6736
|
+
} else if (args.webSearchEnabled === true) {
|
|
6737
|
+
commandArgs.push("--config", `web_search="live"`);
|
|
6738
|
+
} else if (args.webSearchEnabled === false) {
|
|
6739
|
+
commandArgs.push("--config", `web_search="disabled"`);
|
|
6740
|
+
}
|
|
6741
|
+
if (args.approvalPolicy) {
|
|
6742
|
+
commandArgs.push("--config", `approval_policy="${args.approvalPolicy}"`);
|
|
6743
|
+
}
|
|
6744
|
+
if (args.threadId) {
|
|
6745
|
+
commandArgs.push("resume", args.threadId);
|
|
6746
|
+
}
|
|
6747
|
+
if (args.images?.length) {
|
|
6748
|
+
for (const image of args.images) {
|
|
6749
|
+
commandArgs.push("--image", image);
|
|
6750
|
+
}
|
|
6751
|
+
}
|
|
6752
|
+
const env = {};
|
|
6753
|
+
if (this.envOverride) {
|
|
6754
|
+
Object.assign(env, this.envOverride);
|
|
6755
|
+
} else {
|
|
6756
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
6757
|
+
if (value !== void 0) {
|
|
6758
|
+
env[key] = value;
|
|
6759
|
+
}
|
|
6760
|
+
}
|
|
6761
|
+
}
|
|
6762
|
+
if (!env[INTERNAL_ORIGINATOR_ENV]) {
|
|
6763
|
+
env[INTERNAL_ORIGINATOR_ENV] = TYPESCRIPT_SDK_ORIGINATOR;
|
|
6764
|
+
}
|
|
6765
|
+
if (args.apiKey) {
|
|
6766
|
+
env.CODEX_API_KEY = args.apiKey;
|
|
6767
|
+
}
|
|
6768
|
+
if (this.pathDirs.length > 0) {
|
|
6769
|
+
prependPathDirs(env, this.pathDirs);
|
|
6770
|
+
}
|
|
6771
|
+
const child = spawn(this.executablePath, commandArgs, {
|
|
6772
|
+
env,
|
|
6773
|
+
signal: args.signal
|
|
6774
|
+
});
|
|
6775
|
+
let spawnError = null;
|
|
6776
|
+
child.once("error", (err) => spawnError = err);
|
|
6777
|
+
if (!child.stdin) {
|
|
6778
|
+
child.kill();
|
|
6779
|
+
throw new Error("Child process has no stdin");
|
|
6780
|
+
}
|
|
6781
|
+
child.stdin.write(args.input);
|
|
6782
|
+
child.stdin.end();
|
|
6783
|
+
if (!child.stdout) {
|
|
6784
|
+
child.kill();
|
|
6785
|
+
throw new Error("Child process has no stdout");
|
|
6786
|
+
}
|
|
6787
|
+
const stderrChunks = [];
|
|
6788
|
+
if (child.stderr) {
|
|
6789
|
+
child.stderr.on("data", (data) => {
|
|
6790
|
+
stderrChunks.push(data);
|
|
6791
|
+
});
|
|
6792
|
+
}
|
|
6793
|
+
const exitPromise = new Promise(
|
|
6794
|
+
(resolve2) => {
|
|
6795
|
+
child.once("exit", (code, signal) => {
|
|
6796
|
+
resolve2({ code, signal });
|
|
6797
|
+
});
|
|
6798
|
+
}
|
|
6799
|
+
);
|
|
6800
|
+
const rl = readline2.createInterface({
|
|
6801
|
+
input: child.stdout,
|
|
6802
|
+
crlfDelay: Infinity
|
|
6803
|
+
});
|
|
6804
|
+
try {
|
|
6805
|
+
for await (const line of rl) {
|
|
6806
|
+
yield line;
|
|
6807
|
+
}
|
|
6808
|
+
if (spawnError) throw spawnError;
|
|
6809
|
+
const { code, signal } = await exitPromise;
|
|
6810
|
+
if (code !== 0 || signal) {
|
|
6811
|
+
const stderrBuffer = Buffer.concat(stderrChunks);
|
|
6812
|
+
const detail = signal ? `signal ${signal}` : `code ${code ?? 1}`;
|
|
6813
|
+
throw new Error(`Codex Exec exited with ${detail}: ${stderrBuffer.toString("utf8")}`);
|
|
6814
|
+
}
|
|
6815
|
+
} finally {
|
|
6816
|
+
rl.close();
|
|
6817
|
+
child.removeAllListeners();
|
|
6818
|
+
try {
|
|
6819
|
+
if (!child.killed) child.kill();
|
|
6820
|
+
} catch {
|
|
6821
|
+
}
|
|
6822
|
+
}
|
|
6823
|
+
}
|
|
6824
|
+
};
|
|
6825
|
+
function serializeConfigOverrides(configOverrides) {
|
|
6826
|
+
const overrides = [];
|
|
6827
|
+
flattenConfigOverrides(configOverrides, "", overrides);
|
|
6828
|
+
return overrides;
|
|
6829
|
+
}
|
|
6830
|
+
function flattenConfigOverrides(value, prefix, overrides) {
|
|
6831
|
+
if (!isPlainObject(value)) {
|
|
6832
|
+
if (prefix) {
|
|
6833
|
+
overrides.push(`${prefix}=${toTomlValue(value, prefix)}`);
|
|
6834
|
+
return;
|
|
6835
|
+
} else {
|
|
6836
|
+
throw new Error("Codex config overrides must be a plain object");
|
|
6837
|
+
}
|
|
6838
|
+
}
|
|
6839
|
+
const entries = Object.entries(value);
|
|
6840
|
+
if (!prefix && entries.length === 0) {
|
|
6841
|
+
return;
|
|
6842
|
+
}
|
|
6843
|
+
if (prefix && entries.length === 0) {
|
|
6844
|
+
overrides.push(`${prefix}={}`);
|
|
6845
|
+
return;
|
|
6846
|
+
}
|
|
6847
|
+
for (const [key, child] of entries) {
|
|
6848
|
+
if (!key) {
|
|
6849
|
+
throw new Error("Codex config override keys must be non-empty strings");
|
|
6850
|
+
}
|
|
6851
|
+
if (child === void 0) {
|
|
6852
|
+
continue;
|
|
6853
|
+
}
|
|
6854
|
+
const path3 = prefix ? `${prefix}.${key}` : key;
|
|
6855
|
+
if (isPlainObject(child)) {
|
|
6856
|
+
flattenConfigOverrides(child, path3, overrides);
|
|
6857
|
+
} else {
|
|
6858
|
+
overrides.push(`${path3}=${toTomlValue(child, path3)}`);
|
|
6859
|
+
}
|
|
6860
|
+
}
|
|
6861
|
+
}
|
|
6862
|
+
function toTomlValue(value, path3) {
|
|
6863
|
+
if (typeof value === "string") {
|
|
6864
|
+
return JSON.stringify(value);
|
|
6865
|
+
} else if (typeof value === "number") {
|
|
6866
|
+
if (!Number.isFinite(value)) {
|
|
6867
|
+
throw new Error(`Codex config override at ${path3} must be a finite number`);
|
|
6868
|
+
}
|
|
6869
|
+
return `${value}`;
|
|
6870
|
+
} else if (typeof value === "boolean") {
|
|
6871
|
+
return value ? "true" : "false";
|
|
6872
|
+
} else if (Array.isArray(value)) {
|
|
6873
|
+
const rendered = value.map((item, index) => toTomlValue(item, `${path3}[${index}]`));
|
|
6874
|
+
return `[${rendered.join(", ")}]`;
|
|
6875
|
+
} else if (isPlainObject(value)) {
|
|
6876
|
+
const parts = [];
|
|
6877
|
+
for (const [key, child] of Object.entries(value)) {
|
|
6878
|
+
if (!key) {
|
|
6879
|
+
throw new Error("Codex config override keys must be non-empty strings");
|
|
6880
|
+
}
|
|
6881
|
+
if (child === void 0) {
|
|
6882
|
+
continue;
|
|
6883
|
+
}
|
|
6884
|
+
parts.push(`${formatTomlKey(key)} = ${toTomlValue(child, `${path3}.${key}`)}`);
|
|
6885
|
+
}
|
|
6886
|
+
return `{${parts.join(", ")}}`;
|
|
6887
|
+
} else if (value === null) {
|
|
6888
|
+
throw new Error(`Codex config override at ${path3} cannot be null`);
|
|
6889
|
+
} else {
|
|
6890
|
+
const typeName = typeof value;
|
|
6891
|
+
throw new Error(`Unsupported Codex config override value at ${path3}: ${typeName}`);
|
|
6892
|
+
}
|
|
6893
|
+
}
|
|
6894
|
+
var TOML_BARE_KEY = /^[A-Za-z0-9_-]+$/;
|
|
6895
|
+
function formatTomlKey(key) {
|
|
6896
|
+
return TOML_BARE_KEY.test(key) ? key : JSON.stringify(key);
|
|
6897
|
+
}
|
|
6898
|
+
function isPlainObject(value) {
|
|
6899
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6900
|
+
}
|
|
6901
|
+
function findCodexPath() {
|
|
6902
|
+
const { platform, arch } = process;
|
|
6903
|
+
let targetTriple = null;
|
|
6904
|
+
switch (platform) {
|
|
6905
|
+
case "linux":
|
|
6906
|
+
case "android":
|
|
6907
|
+
switch (arch) {
|
|
6908
|
+
case "x64":
|
|
6909
|
+
targetTriple = "x86_64-unknown-linux-musl";
|
|
6910
|
+
break;
|
|
6911
|
+
case "arm64":
|
|
6912
|
+
targetTriple = "aarch64-unknown-linux-musl";
|
|
6913
|
+
break;
|
|
6914
|
+
default:
|
|
6915
|
+
break;
|
|
6916
|
+
}
|
|
6917
|
+
break;
|
|
6918
|
+
case "darwin":
|
|
6919
|
+
switch (arch) {
|
|
6920
|
+
case "x64":
|
|
6921
|
+
targetTriple = "x86_64-apple-darwin";
|
|
6922
|
+
break;
|
|
6923
|
+
case "arm64":
|
|
6924
|
+
targetTriple = "aarch64-apple-darwin";
|
|
6925
|
+
break;
|
|
6926
|
+
default:
|
|
6927
|
+
break;
|
|
6928
|
+
}
|
|
6929
|
+
break;
|
|
6930
|
+
case "win32":
|
|
6931
|
+
switch (arch) {
|
|
6932
|
+
case "x64":
|
|
6933
|
+
targetTriple = "x86_64-pc-windows-msvc";
|
|
6934
|
+
break;
|
|
6935
|
+
case "arm64":
|
|
6936
|
+
targetTriple = "aarch64-pc-windows-msvc";
|
|
6937
|
+
break;
|
|
6938
|
+
default:
|
|
6939
|
+
break;
|
|
6940
|
+
}
|
|
6941
|
+
break;
|
|
6942
|
+
default:
|
|
6943
|
+
break;
|
|
6944
|
+
}
|
|
6945
|
+
if (!targetTriple) {
|
|
6946
|
+
throw new Error(`Unsupported platform: ${platform} (${arch})`);
|
|
6947
|
+
}
|
|
6948
|
+
const platformPackage = PLATFORM_PACKAGE_BY_TARGET[targetTriple];
|
|
6949
|
+
if (!platformPackage) {
|
|
6950
|
+
throw new Error(`Unsupported target triple: ${targetTriple}`);
|
|
6951
|
+
}
|
|
6952
|
+
let vendorRoot;
|
|
6953
|
+
try {
|
|
6954
|
+
const codexPackageJsonPath = moduleRequire.resolve(`${CODEX_NPM_NAME}/package.json`);
|
|
6955
|
+
const codexRequire = createRequire(codexPackageJsonPath);
|
|
6956
|
+
const platformPackageJsonPath = codexRequire.resolve(`${platformPackage}/package.json`);
|
|
6957
|
+
vendorRoot = path2.join(path2.dirname(platformPackageJsonPath), "vendor");
|
|
6958
|
+
} catch {
|
|
6959
|
+
throw new Error(
|
|
6960
|
+
`Unable to locate Codex CLI binaries. Ensure ${CODEX_NPM_NAME} is installed with optional dependencies.`
|
|
6961
|
+
);
|
|
6962
|
+
}
|
|
6963
|
+
const codexBinaryName = process.platform === "win32" ? "codex.exe" : "codex";
|
|
6964
|
+
const nativePackage = resolveNativePackage(vendorRoot, targetTriple, codexBinaryName);
|
|
6965
|
+
if (!nativePackage) {
|
|
6966
|
+
throw new Error(
|
|
6967
|
+
`Unable to locate Codex CLI binaries for ${targetTriple}. Ensure ${CODEX_NPM_NAME} is installed with optional dependencies.`
|
|
6968
|
+
);
|
|
6969
|
+
}
|
|
6970
|
+
return nativePackage;
|
|
6971
|
+
}
|
|
6972
|
+
function resolveNativePackage(vendorRoot, targetTriple, codexBinaryName) {
|
|
6973
|
+
const packageRoot = path2.join(vendorRoot, targetTriple);
|
|
6974
|
+
const packageBinaryPath = path2.join(packageRoot, "bin", codexBinaryName);
|
|
6975
|
+
if (isFile(packageBinaryPath) && isFile(path2.join(packageRoot, "codex-package.json"))) {
|
|
6976
|
+
return {
|
|
6977
|
+
executablePath: packageBinaryPath,
|
|
6978
|
+
pathDirs: existingDirs(path2.join(packageRoot, "codex-path"))
|
|
6979
|
+
};
|
|
6980
|
+
}
|
|
6981
|
+
const legacyBinaryPath = path2.join(packageRoot, "codex", codexBinaryName);
|
|
6982
|
+
if (isFile(legacyBinaryPath)) {
|
|
6983
|
+
return {
|
|
6984
|
+
executablePath: legacyBinaryPath,
|
|
6985
|
+
pathDirs: existingDirs(path2.join(packageRoot, "path"))
|
|
6986
|
+
};
|
|
6987
|
+
}
|
|
6988
|
+
return null;
|
|
6989
|
+
}
|
|
6990
|
+
function existingDirs(...dirs) {
|
|
6991
|
+
return dirs.filter(isDirectory);
|
|
6992
|
+
}
|
|
6993
|
+
function prependPathDirs(env, pathDirs, platform = process.platform) {
|
|
6994
|
+
const pathKey = pathEnvKey(env, platform);
|
|
6995
|
+
if (platform === "win32") {
|
|
6996
|
+
for (const key of Object.keys(env)) {
|
|
6997
|
+
if (key.toLowerCase() === "path" && key !== pathKey) {
|
|
6998
|
+
delete env[key];
|
|
6999
|
+
}
|
|
7000
|
+
}
|
|
7001
|
+
}
|
|
7002
|
+
const existingEntries = (env[pathKey] ?? "").split(path2.delimiter).filter((entry) => entry.length > 0 && !pathDirs.includes(entry));
|
|
7003
|
+
env[pathKey] = [...pathDirs, ...existingEntries].join(path2.delimiter);
|
|
7004
|
+
}
|
|
7005
|
+
function pathEnvKey(env, platform) {
|
|
7006
|
+
if (platform !== "win32") {
|
|
7007
|
+
return "PATH";
|
|
7008
|
+
}
|
|
7009
|
+
const matchingKeys = Object.keys(env).filter((key) => key.toLowerCase() === "path");
|
|
7010
|
+
return matchingKeys.includes("Path") ? "Path" : matchingKeys.at(-1) ?? "PATH";
|
|
7011
|
+
}
|
|
7012
|
+
function isFile(filePath) {
|
|
7013
|
+
try {
|
|
7014
|
+
return statSync2(filePath).isFile();
|
|
7015
|
+
} catch {
|
|
7016
|
+
return false;
|
|
7017
|
+
}
|
|
7018
|
+
}
|
|
7019
|
+
function isDirectory(filePath) {
|
|
7020
|
+
try {
|
|
7021
|
+
return statSync2(filePath).isDirectory();
|
|
7022
|
+
} catch {
|
|
7023
|
+
return false;
|
|
7024
|
+
}
|
|
7025
|
+
}
|
|
7026
|
+
var Codex = class {
|
|
7027
|
+
exec;
|
|
7028
|
+
options;
|
|
7029
|
+
constructor(options = {}) {
|
|
7030
|
+
const { codexPathOverride, env, config } = options;
|
|
7031
|
+
this.exec = new CodexExec(codexPathOverride, env, config);
|
|
7032
|
+
this.options = options;
|
|
7033
|
+
}
|
|
7034
|
+
/**
|
|
7035
|
+
* Starts a new conversation with an agent.
|
|
7036
|
+
* @returns A new thread instance.
|
|
7037
|
+
*/
|
|
7038
|
+
startThread(options = {}) {
|
|
7039
|
+
return new Thread(this.exec, this.options, options);
|
|
7040
|
+
}
|
|
7041
|
+
/**
|
|
7042
|
+
* Resumes a conversation with an agent based on the thread id.
|
|
7043
|
+
* Threads are persisted in ~/.codex/sessions.
|
|
7044
|
+
*
|
|
7045
|
+
* @param id The id of the thread to resume.
|
|
7046
|
+
* @returns A new thread instance.
|
|
7047
|
+
*/
|
|
7048
|
+
resumeThread(id, options = {}) {
|
|
7049
|
+
return new Thread(this.exec, this.options, options, id);
|
|
7050
|
+
}
|
|
7051
|
+
};
|
|
7052
|
+
|
|
7053
|
+
// src/session/runner/codex.ts
|
|
7054
|
+
var isRecord2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
7055
|
+
var str = (v) => typeof v === "string" ? v : void 0;
|
|
7056
|
+
var compactEnv = (env) => {
|
|
7057
|
+
if (!env) return void 0;
|
|
7058
|
+
const out = {};
|
|
7059
|
+
for (const [key, value] of Object.entries(env)) {
|
|
7060
|
+
if (value !== void 0) out[key] = value;
|
|
7061
|
+
}
|
|
7062
|
+
return out;
|
|
7063
|
+
};
|
|
7064
|
+
var statusOf = (v) => v === "in_progress" || v === "failed" || v === "completed" ? v : "completed";
|
|
7065
|
+
var itemId = (item) => str(item.id) ?? `${str(item.type) ?? "item"}-${Math.random().toString(36).slice(2)}`;
|
|
7066
|
+
var todoItems = (raw) => Array.isArray(raw) ? raw.filter(isRecord2).map((todo) => ({
|
|
7067
|
+
text: str(todo.text) ?? str(todo.content) ?? "",
|
|
7068
|
+
completed: todo.completed === true || todo.status === "completed"
|
|
7069
|
+
})) : [];
|
|
7070
|
+
var fileKind = (v) => v === "add" || v === "delete" || v === "update" ? v : "update";
|
|
7071
|
+
var toAgentItem = (raw) => {
|
|
7072
|
+
if (!isRecord2(raw)) {
|
|
7073
|
+
return {
|
|
7074
|
+
type: "error",
|
|
7075
|
+
id: "bad-item",
|
|
7076
|
+
status: "failed",
|
|
7077
|
+
message: "codex item was not an object"
|
|
7078
|
+
};
|
|
7079
|
+
}
|
|
7080
|
+
const type = str(raw.type);
|
|
7081
|
+
const id = itemId(raw);
|
|
7082
|
+
const status = statusOf(raw.status);
|
|
7083
|
+
if (type === "agent_message") {
|
|
7084
|
+
return { type, id, status, text: str(raw.text) ?? str(raw.message) ?? "" };
|
|
7085
|
+
}
|
|
7086
|
+
if (type === "reasoning") {
|
|
7087
|
+
return { type, id, status, text: str(raw.text) ?? str(raw.summary) ?? "" };
|
|
7088
|
+
}
|
|
7089
|
+
if (type === "command_execution") {
|
|
7090
|
+
return {
|
|
7091
|
+
type,
|
|
7092
|
+
id,
|
|
7093
|
+
status,
|
|
7094
|
+
command: str(raw.command) ?? "",
|
|
7095
|
+
output: str(raw.aggregated_output) ?? str(raw.output) ?? "",
|
|
7096
|
+
exitCode: typeof raw.exit_code === "number" ? raw.exit_code : void 0
|
|
7097
|
+
};
|
|
7098
|
+
}
|
|
7099
|
+
if (type === "file_change") {
|
|
7100
|
+
const changes = Array.isArray(raw.changes) ? raw.changes.filter(isRecord2).map((change) => ({
|
|
7101
|
+
path: str(change.path) ?? "",
|
|
7102
|
+
kind: fileKind(change.kind)
|
|
7103
|
+
})) : [];
|
|
7104
|
+
return { type, id, status, changes };
|
|
7105
|
+
}
|
|
7106
|
+
if (type === "mcp_tool_call") {
|
|
7107
|
+
return {
|
|
7108
|
+
type,
|
|
7109
|
+
id,
|
|
7110
|
+
status,
|
|
7111
|
+
server: str(raw.server) ?? "",
|
|
7112
|
+
tool: str(raw.tool) ?? str(raw.name) ?? "",
|
|
7113
|
+
arguments: raw.arguments ?? raw.input ?? null,
|
|
7114
|
+
output: raw.result ?? raw.output ?? raw.error,
|
|
7115
|
+
isError: raw.is_error === true || raw.error !== void 0
|
|
7116
|
+
};
|
|
7117
|
+
}
|
|
7118
|
+
if (type === "web_search") {
|
|
7119
|
+
return { type, id, status, query: str(raw.query) ?? "" };
|
|
7120
|
+
}
|
|
7121
|
+
if (type === "todo_list") {
|
|
7122
|
+
return { type, id, status, items: todoItems(raw.items) };
|
|
7123
|
+
}
|
|
7124
|
+
if (type === "error") {
|
|
7125
|
+
return { type, id, status: "failed", message: str(raw.message) ?? "codex error" };
|
|
7126
|
+
}
|
|
7127
|
+
return {
|
|
7128
|
+
type: "tool_call",
|
|
7129
|
+
id,
|
|
7130
|
+
status,
|
|
7131
|
+
name: str(raw.name) ?? type ?? "codex_item",
|
|
7132
|
+
input: raw,
|
|
7133
|
+
output: raw.output
|
|
7134
|
+
};
|
|
7135
|
+
};
|
|
7136
|
+
var usageOf = (raw) => {
|
|
7137
|
+
if (!isRecord2(raw)) return void 0;
|
|
7138
|
+
return {
|
|
7139
|
+
inputTokens: typeof raw.input_tokens === "number" ? raw.input_tokens : void 0,
|
|
7140
|
+
cachedInputTokens: typeof raw.cached_input_tokens === "number" ? raw.cached_input_tokens : void 0,
|
|
7141
|
+
outputTokens: typeof raw.output_tokens === "number" ? raw.output_tokens : void 0,
|
|
7142
|
+
reasoningOutputTokens: typeof raw.reasoning_output_tokens === "number" ? raw.reasoning_output_tokens : void 0
|
|
7143
|
+
};
|
|
7144
|
+
};
|
|
7145
|
+
var toAgentEvent = (raw) => {
|
|
7146
|
+
if (!isRecord2(raw)) return { type: "raw", raw };
|
|
7147
|
+
const type = str(raw.type);
|
|
7148
|
+
if (type === "thread.started") {
|
|
7149
|
+
return {
|
|
7150
|
+
type,
|
|
7151
|
+
sessionId: str(raw.thread_id) ?? str(raw.sessionId) ?? "",
|
|
7152
|
+
model: str(raw.model),
|
|
7153
|
+
raw
|
|
7154
|
+
};
|
|
7155
|
+
}
|
|
7156
|
+
if (type === "turn.started") return { type, raw };
|
|
7157
|
+
if ((type === "item.started" || type === "item.updated" || type === "item.completed") && raw.item !== void 0) {
|
|
7158
|
+
return { type, item: toAgentItem(raw.item), raw };
|
|
7159
|
+
}
|
|
7160
|
+
if (type === "turn.completed") return { type, usage: usageOf(raw.usage), raw };
|
|
7161
|
+
if (type === "turn.failed") {
|
|
7162
|
+
const error = isRecord2(raw.error) ? raw.error : raw;
|
|
7163
|
+
return { type, error: { message: str(error.message) ?? "codex turn failed" }, raw };
|
|
7164
|
+
}
|
|
7165
|
+
if (type === "error") return { type, message: str(raw.message) ?? "codex error", raw };
|
|
7166
|
+
return { type: "raw", raw };
|
|
7167
|
+
};
|
|
7168
|
+
var withPlanPrefix = (input) => {
|
|
7169
|
+
const prefix = "Plan mode: inspect and propose a plan only. Do not edit files or run mutating commands.\n\n";
|
|
7170
|
+
if (typeof input === "string") return `${prefix}${input}`;
|
|
7171
|
+
return input.map(
|
|
7172
|
+
(entry, i) => i === 0 && entry.type === "text" ? { ...entry, text: `${prefix}${entry.text}` } : entry
|
|
7173
|
+
);
|
|
7174
|
+
};
|
|
7175
|
+
async function* startCodexEvents(config, input, worker2, opts) {
|
|
7176
|
+
const env = compactEnv(buildSdkEnv(opts.envOverlay));
|
|
7177
|
+
const codex = new Codex(env ? { env } : void 0);
|
|
7178
|
+
const resuming = !config.agentSessionId.startsWith("pending:");
|
|
7179
|
+
const addDirs = additionalDirs();
|
|
7180
|
+
const threadOptions = {
|
|
7181
|
+
workingDirectory: config.worktreePath,
|
|
7182
|
+
skipGitRepoCheck: true,
|
|
7183
|
+
sandboxMode: opts.planMode ? "read-only" : "workspace-write",
|
|
7184
|
+
approvalPolicy: "never",
|
|
7185
|
+
...opts.model ? { model: opts.model } : {},
|
|
7186
|
+
...addDirs ? { additionalDirectories: addDirs } : {}
|
|
7187
|
+
};
|
|
7188
|
+
const thread = resuming ? codex.resumeThread(config.agentSessionId, threadOptions) : codex.startThread(threadOptions);
|
|
7189
|
+
const runInput = opts.planMode ? withPlanPrefix(input) : input;
|
|
7190
|
+
const { events } = await thread.runStreamed(runInput, {
|
|
7191
|
+
...opts.signal ? { signal: opts.signal } : {}
|
|
7192
|
+
});
|
|
7193
|
+
for await (const raw of events) {
|
|
7194
|
+
const event = toAgentEvent(raw);
|
|
7195
|
+
if (event.type === "thread.started" && !resuming && event.sessionId) {
|
|
7196
|
+
config.agentSessionId = event.sessionId;
|
|
7197
|
+
await worker2.materialize({
|
|
7198
|
+
agentSessionId: event.sessionId,
|
|
7199
|
+
worktreePath: config.worktreePath
|
|
7200
|
+
});
|
|
7201
|
+
opts.log(`[codex] thread ${event.sessionId}`);
|
|
7202
|
+
}
|
|
7203
|
+
yield event;
|
|
7204
|
+
}
|
|
7205
|
+
}
|
|
7206
|
+
|
|
6514
7207
|
// src/session/runner/query.ts
|
|
6515
7208
|
var startQuery = (config, text, resuming, queryFn, abortController, log, { envOverlay, planMode = false, model } = {}) => {
|
|
6516
7209
|
const env = buildSdkEnv(envOverlay);
|
|
@@ -6539,21 +7232,223 @@ var startQuery = (config, text, resuming, queryFn, abortController, log, { envOv
|
|
|
6539
7232
|
};
|
|
6540
7233
|
|
|
6541
7234
|
// src/session/runner/stream.ts
|
|
6542
|
-
var
|
|
7235
|
+
var streamAgentEvents = async (events, worker2) => {
|
|
6543
7236
|
let result = null;
|
|
6544
|
-
for await (const
|
|
6545
|
-
await worker2.emitEvent("
|
|
6546
|
-
if (
|
|
7237
|
+
for await (const event of events) {
|
|
7238
|
+
await worker2.emitEvent("agent_event", event);
|
|
7239
|
+
if (event.type === "turn.completed") {
|
|
7240
|
+
result = {
|
|
7241
|
+
subtype: event.subtype ?? "success",
|
|
7242
|
+
isError: false,
|
|
7243
|
+
resultText: ""
|
|
7244
|
+
};
|
|
7245
|
+
} else if (event.type === "turn.failed") {
|
|
7246
|
+
result = {
|
|
7247
|
+
subtype: event.error.subtype ?? "error",
|
|
7248
|
+
isError: true,
|
|
7249
|
+
resultText: event.error.message
|
|
7250
|
+
};
|
|
7251
|
+
}
|
|
6547
7252
|
}
|
|
6548
7253
|
return result;
|
|
6549
7254
|
};
|
|
6550
|
-
var
|
|
7255
|
+
var streamClaudeSdkEvents = (messages, worker2) => streamAgentEvents(claudeToAgentEvents(messages), worker2);
|
|
7256
|
+
var isRecord3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
7257
|
+
var str2 = (v) => typeof v === "string" ? v : void 0;
|
|
7258
|
+
var messageContent = (payload) => {
|
|
7259
|
+
const msg = payload.message;
|
|
7260
|
+
if (!isRecord3(msg) || !Array.isArray(msg.content)) return [];
|
|
7261
|
+
return msg.content.filter(isRecord3);
|
|
7262
|
+
};
|
|
7263
|
+
var textFromToolResult = (raw) => {
|
|
7264
|
+
const c = raw.content;
|
|
7265
|
+
if (typeof c === "string") return c;
|
|
7266
|
+
if (Array.isArray(c)) {
|
|
7267
|
+
return c.map((b) => isRecord3(b) && typeof b.text === "string" ? b.text : JSON.stringify(b)).join("\n");
|
|
7268
|
+
}
|
|
7269
|
+
return JSON.stringify(c ?? "");
|
|
7270
|
+
};
|
|
7271
|
+
var commandOf = (input) => {
|
|
7272
|
+
if (!isRecord3(input)) return "";
|
|
7273
|
+
return str2(input.command) ?? str2(input.cmd) ?? "";
|
|
7274
|
+
};
|
|
7275
|
+
var pathOf = (input) => {
|
|
7276
|
+
if (!isRecord3(input)) return void 0;
|
|
7277
|
+
return str2(input.file_path) ?? str2(input.path);
|
|
7278
|
+
};
|
|
7279
|
+
var fileKindOf = (name) => name === "Delete" ? "delete" : "update";
|
|
7280
|
+
var todoItems2 = (input) => {
|
|
7281
|
+
if (!isRecord3(input) || !Array.isArray(input.todos)) return [];
|
|
7282
|
+
return input.todos.filter(isRecord3).map((todo) => ({
|
|
7283
|
+
text: str2(todo.content) ?? str2(todo.text) ?? "",
|
|
7284
|
+
completed: todo.status === "completed" || todo.completed === true
|
|
7285
|
+
}));
|
|
7286
|
+
};
|
|
7287
|
+
var mcpParts = (name) => {
|
|
7288
|
+
const match = /^mcp__(.+?)__(.+)$/.exec(name);
|
|
7289
|
+
return match ? { server: match[1] ?? "", tool: match[2] ?? "" } : null;
|
|
7290
|
+
};
|
|
7291
|
+
var startedItemFromToolUse = (block) => {
|
|
7292
|
+
const id = str2(block.id) ?? `tool-${Math.random().toString(36).slice(2)}`;
|
|
7293
|
+
const name = str2(block.name) ?? "tool";
|
|
7294
|
+
const input = block.input ?? null;
|
|
7295
|
+
if (name === "Bash") {
|
|
7296
|
+
return {
|
|
7297
|
+
type: "command_execution",
|
|
7298
|
+
id,
|
|
7299
|
+
status: "in_progress",
|
|
7300
|
+
command: commandOf(input),
|
|
7301
|
+
output: ""
|
|
7302
|
+
};
|
|
7303
|
+
}
|
|
7304
|
+
if (name === "Edit" || name === "Write" || name === "MultiEdit" || name === "Delete") {
|
|
7305
|
+
const path3 = pathOf(input);
|
|
7306
|
+
return {
|
|
7307
|
+
type: "file_change",
|
|
7308
|
+
id,
|
|
7309
|
+
status: "in_progress",
|
|
7310
|
+
changes: path3 ? [{ path: path3, kind: fileKindOf(name) }] : []
|
|
7311
|
+
};
|
|
7312
|
+
}
|
|
7313
|
+
const mcp = mcpParts(name);
|
|
7314
|
+
if (mcp) {
|
|
7315
|
+
return {
|
|
7316
|
+
type: "mcp_tool_call",
|
|
7317
|
+
id,
|
|
7318
|
+
status: "in_progress",
|
|
7319
|
+
server: mcp.server,
|
|
7320
|
+
tool: mcp.tool,
|
|
7321
|
+
arguments: input
|
|
7322
|
+
};
|
|
7323
|
+
}
|
|
7324
|
+
if (name === "WebSearch" || name === "web_search") {
|
|
7325
|
+
return {
|
|
7326
|
+
type: "web_search",
|
|
7327
|
+
id,
|
|
7328
|
+
status: "in_progress",
|
|
7329
|
+
query: isRecord3(input) ? str2(input.query) ?? "" : ""
|
|
7330
|
+
};
|
|
7331
|
+
}
|
|
7332
|
+
if (name === "TodoWrite") {
|
|
7333
|
+
return { type: "todo_list", id, status: "in_progress", items: todoItems2(input) };
|
|
7334
|
+
}
|
|
7335
|
+
return { type: "tool_call", id, status: "in_progress", name, input };
|
|
7336
|
+
};
|
|
7337
|
+
var completeItem = (item, output, isError) => {
|
|
7338
|
+
if (item.type === "command_execution")
|
|
7339
|
+
return { ...item, status: isError ? "failed" : "completed", output };
|
|
7340
|
+
if (item.type === "mcp_tool_call")
|
|
7341
|
+
return { ...item, status: isError ? "failed" : "completed", output, isError };
|
|
7342
|
+
if (item.type === "tool_call")
|
|
7343
|
+
return { ...item, status: isError ? "failed" : "completed", output, isError };
|
|
7344
|
+
return { ...item, status: isError ? "failed" : "completed" };
|
|
7345
|
+
};
|
|
7346
|
+
var resultEvent = (message) => {
|
|
6551
7347
|
const rec = message;
|
|
6552
|
-
const subtype =
|
|
7348
|
+
const subtype = str2(rec.subtype) ?? "unknown";
|
|
6553
7349
|
const isError = rec.is_error === true || subtype !== "success";
|
|
6554
|
-
const resultText =
|
|
6555
|
-
|
|
7350
|
+
const resultText = str2(rec.result) ?? "";
|
|
7351
|
+
const usage = {
|
|
7352
|
+
numTurns: typeof rec.num_turns === "number" ? rec.num_turns : void 0,
|
|
7353
|
+
totalCostUsd: typeof rec.total_cost_usd === "number" ? rec.total_cost_usd : void 0,
|
|
7354
|
+
durationMs: typeof rec.duration_ms === "number" ? rec.duration_ms : void 0
|
|
7355
|
+
};
|
|
7356
|
+
return isError ? {
|
|
7357
|
+
type: "turn.failed",
|
|
7358
|
+
error: { message: resultText || `claude result: ${subtype}`, subtype },
|
|
7359
|
+
usage,
|
|
7360
|
+
raw: message
|
|
7361
|
+
} : { type: "turn.completed", subtype, usage, raw: message };
|
|
6556
7362
|
};
|
|
7363
|
+
async function* claudeToAgentEvents(messages) {
|
|
7364
|
+
const pendingTools = /* @__PURE__ */ new Map();
|
|
7365
|
+
let systemEmitted = false;
|
|
7366
|
+
let textSeq = 0;
|
|
7367
|
+
let reasoningSeq = 0;
|
|
7368
|
+
for await (const message of messages) {
|
|
7369
|
+
const p = message;
|
|
7370
|
+
if (message.type === "system") {
|
|
7371
|
+
if (!systemEmitted) {
|
|
7372
|
+
systemEmitted = true;
|
|
7373
|
+
yield {
|
|
7374
|
+
type: "thread.started",
|
|
7375
|
+
sessionId: str2(p.session_id) ?? "",
|
|
7376
|
+
model: str2(p.model) ?? (isRecord3(p.model_info) ? str2(p.model_info.id) : void 0),
|
|
7377
|
+
raw: message
|
|
7378
|
+
};
|
|
7379
|
+
yield { type: "turn.started", raw: message };
|
|
7380
|
+
}
|
|
7381
|
+
continue;
|
|
7382
|
+
}
|
|
7383
|
+
if (message.type === "assistant") {
|
|
7384
|
+
for (const block of messageContent(p)) {
|
|
7385
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
7386
|
+
yield {
|
|
7387
|
+
type: "item.completed",
|
|
7388
|
+
item: {
|
|
7389
|
+
type: "agent_message",
|
|
7390
|
+
id: `assistant-${++textSeq}`,
|
|
7391
|
+
status: "completed",
|
|
7392
|
+
text: block.text
|
|
7393
|
+
},
|
|
7394
|
+
raw: block
|
|
7395
|
+
};
|
|
7396
|
+
} else if (block.type === "thinking" && typeof block.thinking === "string") {
|
|
7397
|
+
const text = block.thinking.trim();
|
|
7398
|
+
if (text) {
|
|
7399
|
+
yield {
|
|
7400
|
+
type: "item.completed",
|
|
7401
|
+
item: {
|
|
7402
|
+
type: "reasoning",
|
|
7403
|
+
id: `reasoning-${++reasoningSeq}`,
|
|
7404
|
+
status: "completed",
|
|
7405
|
+
text
|
|
7406
|
+
},
|
|
7407
|
+
raw: block
|
|
7408
|
+
};
|
|
7409
|
+
}
|
|
7410
|
+
} else if (block.type === "tool_use" || block.type === "server_tool_use") {
|
|
7411
|
+
const item = startedItemFromToolUse(block);
|
|
7412
|
+
pendingTools.set(item.id, item);
|
|
7413
|
+
yield { type: "item.started", item, raw: block };
|
|
7414
|
+
} else if (block.type === "tool_result") {
|
|
7415
|
+
const id = str2(block.tool_use_id) ?? "";
|
|
7416
|
+
const item = pendingTools.get(id);
|
|
7417
|
+
if (item) {
|
|
7418
|
+
const completed = completeItem(item, textFromToolResult(block), block.is_error === true);
|
|
7419
|
+
pendingTools.set(id, completed);
|
|
7420
|
+
yield { type: "item.completed", item: completed, raw: block };
|
|
7421
|
+
} else {
|
|
7422
|
+
yield { type: "raw", raw: block };
|
|
7423
|
+
}
|
|
7424
|
+
} else {
|
|
7425
|
+
yield { type: "raw", raw: block };
|
|
7426
|
+
}
|
|
7427
|
+
}
|
|
7428
|
+
continue;
|
|
7429
|
+
}
|
|
7430
|
+
if (message.type === "user") {
|
|
7431
|
+
for (const block of messageContent(p)) {
|
|
7432
|
+
if (block.type !== "tool_result") continue;
|
|
7433
|
+
const id = str2(block.tool_use_id) ?? "";
|
|
7434
|
+
const item = pendingTools.get(id);
|
|
7435
|
+
if (!item) {
|
|
7436
|
+
yield { type: "raw", raw: block };
|
|
7437
|
+
continue;
|
|
7438
|
+
}
|
|
7439
|
+
const completed = completeItem(item, textFromToolResult(block), block.is_error === true);
|
|
7440
|
+
pendingTools.set(id, completed);
|
|
7441
|
+
yield { type: "item.completed", item: completed, raw: block };
|
|
7442
|
+
}
|
|
7443
|
+
continue;
|
|
7444
|
+
}
|
|
7445
|
+
if (message.type === "result") {
|
|
7446
|
+
yield resultEvent(message);
|
|
7447
|
+
continue;
|
|
7448
|
+
}
|
|
7449
|
+
yield { type: "raw", raw: message };
|
|
7450
|
+
}
|
|
7451
|
+
}
|
|
6557
7452
|
|
|
6558
7453
|
// src/session/runner/turn.ts
|
|
6559
7454
|
var turnTimeoutMs = () => Number(process.env.BATON_TURN_TIMEOUT_MS) || 30 * 6e4;
|
|
@@ -6563,14 +7458,14 @@ var ABORTED = /* @__PURE__ */ Symbol("turn-aborted");
|
|
|
6563
7458
|
var finalizeTurn = async (result, worker2, log) => {
|
|
6564
7459
|
if (!result) {
|
|
6565
7460
|
log("[exit] stream ended with no result");
|
|
6566
|
-
await worker2.emitEvent("turn_error", { message: "
|
|
7461
|
+
await worker2.emitEvent("turn_error", { message: "agent produced no result" });
|
|
6567
7462
|
await worker2.emitEvent("turn_complete", {});
|
|
6568
7463
|
return -1;
|
|
6569
7464
|
}
|
|
6570
7465
|
log(`[exit] subtype=${result.subtype} isError=${result.isError}`);
|
|
6571
7466
|
if (result.isError) {
|
|
6572
7467
|
await worker2.emitEvent("turn_error", {
|
|
6573
|
-
message: result.resultText || `
|
|
7468
|
+
message: result.resultText || `agent result: ${result.subtype}`,
|
|
6574
7469
|
subtype: result.subtype
|
|
6575
7470
|
});
|
|
6576
7471
|
}
|
|
@@ -6578,7 +7473,7 @@ var finalizeTurn = async (result, worker2, log) => {
|
|
|
6578
7473
|
return result.isError ? 1 : 0;
|
|
6579
7474
|
};
|
|
6580
7475
|
var buildPrompt = async (config, rawText, attachments, log, fetchImpl) => {
|
|
6581
|
-
if (attachments.length === 0) return rawText;
|
|
7476
|
+
if (attachments.length === 0) return { text: rawText, input: rawText };
|
|
6582
7477
|
const relPaths = await materializeAttachments({
|
|
6583
7478
|
worktreePath: config.worktreePath,
|
|
6584
7479
|
serverBase: config.server,
|
|
@@ -6586,7 +7481,13 @@ var buildPrompt = async (config, rawText, attachments, log, fetchImpl) => {
|
|
|
6586
7481
|
fetchImpl
|
|
6587
7482
|
});
|
|
6588
7483
|
log(`[attach] downloaded ${relPaths.length} file(s) \u2192 ${config.worktreePath}/attachments`);
|
|
6589
|
-
|
|
7484
|
+
const labels = labelAttachments(attachments);
|
|
7485
|
+
const text = augmentPrompt(rawText, relPaths, labels);
|
|
7486
|
+
const images = relPaths.flatMap((relPath, i) => {
|
|
7487
|
+
const att = attachments[i];
|
|
7488
|
+
return att?.contentType.startsWith("image/") ? [{ type: "local_image", path: `${config.worktreePath}/${relPath}` }] : [];
|
|
7489
|
+
});
|
|
7490
|
+
return images.length > 0 ? { text, input: [{ type: "text", text }, ...images] } : { text, input: text };
|
|
6590
7491
|
};
|
|
6591
7492
|
var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => console.log(m), envOverlay, fetchImpl, externalSignal) => {
|
|
6592
7493
|
await worker2.emitEvent("turn_start", { messageId: msg.id });
|
|
@@ -6599,9 +7500,9 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
6599
7500
|
await worker2.emitEvent("turn_error", { message: "user_message missing text and attachments" });
|
|
6600
7501
|
return -1;
|
|
6601
7502
|
}
|
|
6602
|
-
let
|
|
7503
|
+
let built;
|
|
6603
7504
|
try {
|
|
6604
|
-
|
|
7505
|
+
built = await buildPrompt(config, rawText, attachments, log, fetchImpl);
|
|
6605
7506
|
} catch (err) {
|
|
6606
7507
|
const message = err instanceof Error ? err.message : String(err);
|
|
6607
7508
|
await worker2.emitEvent("turn_error", { message: `attachment download failed: ${message}` });
|
|
@@ -6622,12 +7523,23 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
6622
7523
|
heartbeat = setInterval(() => {
|
|
6623
7524
|
void worker2.emitEvent("turn_heartbeat", {}).catch((e) => log(`[heartbeat] ${String(e)}`));
|
|
6624
7525
|
}, heartbeatMs());
|
|
6625
|
-
const
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
7526
|
+
const consume = config.agentKind === "codex" ? streamAgentEvents(
|
|
7527
|
+
startCodexEvents(config, built.input, worker2, {
|
|
7528
|
+
envOverlay,
|
|
7529
|
+
planMode,
|
|
7530
|
+
model,
|
|
7531
|
+
signal: abort.signal,
|
|
7532
|
+
log
|
|
7533
|
+
}),
|
|
7534
|
+
worker2
|
|
7535
|
+
) : streamClaudeSdkEvents(
|
|
7536
|
+
startQuery(config, built.text, resuming, queryFn, abort, log, {
|
|
7537
|
+
envOverlay,
|
|
7538
|
+
planMode,
|
|
7539
|
+
model
|
|
7540
|
+
}),
|
|
7541
|
+
worker2
|
|
7542
|
+
);
|
|
6631
7543
|
void consume.catch(() => {
|
|
6632
7544
|
});
|
|
6633
7545
|
const outcome = await Promise.race([consume, timeout, interrupted]);
|
|
@@ -6639,10 +7551,10 @@ var runTurn = async (config, worker2, msg, resuming, queryFn, log = (m) => conso
|
|
|
6639
7551
|
return -1;
|
|
6640
7552
|
}
|
|
6641
7553
|
if (outcome === TIMEOUT) {
|
|
6642
|
-
log(`[watchdog] turn exceeded ${ceiling}ms \u2014 aborting
|
|
7554
|
+
log(`[watchdog] turn exceeded ${ceiling}ms \u2014 aborting agent`);
|
|
6643
7555
|
abort.abort();
|
|
6644
7556
|
await worker2.emitEvent("turn_error", {
|
|
6645
|
-
message: `turn exceeded ${ceiling}ms \u2014
|
|
7557
|
+
message: `turn exceeded ${ceiling}ms \u2014 agent aborted`
|
|
6646
7558
|
});
|
|
6647
7559
|
await worker2.emitEvent("turn_complete", {});
|
|
6648
7560
|
return -1;
|
|
@@ -6698,7 +7610,7 @@ var runDaemon = async (config, deps, signal) => {
|
|
|
6698
7610
|
log(`bin: ${claudeExecutable() ?? "(sdk bundled)"} cwd: ${config.worktreePath}`);
|
|
6699
7611
|
log(`runtime env keys: ${maskedEnvKeys(deps.env)}`);
|
|
6700
7612
|
const state = {
|
|
6701
|
-
firstSpawnDone: findTranscriptPath(config.agentSessionId) !== null,
|
|
7613
|
+
firstSpawnDone: config.agentKind === "codex" ? !config.agentSessionId.startsWith("pending:") : findTranscriptPath(config.agentSessionId) !== null,
|
|
6702
7614
|
seen: /* @__PURE__ */ new Set()
|
|
6703
7615
|
};
|
|
6704
7616
|
const pendingQueue = [];
|
|
@@ -6866,6 +7778,7 @@ var sessionRunCommand = defineCommand({
|
|
|
6866
7778
|
server,
|
|
6867
7779
|
sessionId,
|
|
6868
7780
|
name: s.name,
|
|
7781
|
+
agentKind: s.agentKind,
|
|
6869
7782
|
agentSessionId: s.agentSessionId,
|
|
6870
7783
|
worktreePath: s.worktreePath
|
|
6871
7784
|
};
|
|
@@ -7147,7 +8060,7 @@ var task = defineCommand({
|
|
|
7147
8060
|
}
|
|
7148
8061
|
});
|
|
7149
8062
|
|
|
7150
|
-
// src/commands/worker.ts
|
|
8063
|
+
// src/commands/worker/index.ts
|
|
7151
8064
|
import { hostname as osHostname } from "node:os";
|
|
7152
8065
|
|
|
7153
8066
|
// src/worker/watchdog.ts
|
|
@@ -7202,7 +8115,7 @@ var createLiveness = (deps) => {
|
|
|
7202
8115
|
};
|
|
7203
8116
|
|
|
7204
8117
|
// src/worker/session-supervisor.ts
|
|
7205
|
-
import { spawn } from "node:child_process";
|
|
8118
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
7206
8119
|
import { randomUUID } from "node:crypto";
|
|
7207
8120
|
import { existsSync as existsSync5 } from "node:fs";
|
|
7208
8121
|
import { dirname as dirname2, join as join7 } from "node:path";
|
|
@@ -7335,12 +8248,12 @@ var ensureExcluded = (repo, pattern) => {
|
|
|
7335
8248
|
});
|
|
7336
8249
|
if (r.status !== 0) return;
|
|
7337
8250
|
const rel = r.stdout.trim();
|
|
7338
|
-
const
|
|
7339
|
-
const current = existsSync4(
|
|
8251
|
+
const path3 = isAbsolute2(rel) ? rel : resolve(repo, rel);
|
|
8252
|
+
const current = existsSync4(path3) ? readFileSync5(path3, "utf8") : "";
|
|
7340
8253
|
if (current.split("\n").includes(pattern)) return;
|
|
7341
|
-
mkdirSync3(dirname(
|
|
8254
|
+
mkdirSync3(dirname(path3), { recursive: true });
|
|
7342
8255
|
const sep = current === "" || current.endsWith("\n") ? "" : "\n";
|
|
7343
|
-
appendFileSync(
|
|
8256
|
+
appendFileSync(path3, `${sep}${pattern}
|
|
7344
8257
|
`, "utf8");
|
|
7345
8258
|
} catch {
|
|
7346
8259
|
}
|
|
@@ -7387,7 +8300,7 @@ var createSessionSupervisor = (deps) => {
|
|
|
7387
8300
|
const children = /* @__PURE__ */ new Map();
|
|
7388
8301
|
const spawnChild = (sessionId, worktreePath) => {
|
|
7389
8302
|
if (children.has(sessionId)) return;
|
|
7390
|
-
const child =
|
|
8303
|
+
const child = spawn2(process.execPath, [binPath(), "session", "run", String(sessionId)], {
|
|
7391
8304
|
detached: true,
|
|
7392
8305
|
stdio: "inherit",
|
|
7393
8306
|
env: { ...process.env, BATON_SERVER: cfg.server, BATON_WORKER_TOKEN: cfg.apiToken }
|
|
@@ -7408,12 +8321,13 @@ var createSessionSupervisor = (deps) => {
|
|
|
7408
8321
|
const session2 = await client.sessions.get(sessionId);
|
|
7409
8322
|
let worktreePath = session2.worktreePath;
|
|
7410
8323
|
if (!session2.agentSessionId || !worktreePath) {
|
|
7411
|
-
const
|
|
7412
|
-
|
|
8324
|
+
const sessionCode = randomUUID();
|
|
8325
|
+
const agentSessionId = session2.agentKind === "codex" ? `pending:${sessionCode}` : sessionCode;
|
|
8326
|
+
worktreePath = join7(worktreeDir, slug(`${name}-${sessionCode.slice(0, 8)}`));
|
|
7413
8327
|
createWorktree({
|
|
7414
8328
|
repo,
|
|
7415
8329
|
worktreePath,
|
|
7416
|
-
sessionCode:
|
|
8330
|
+
sessionCode: sessionCode.slice(0, 8),
|
|
7417
8331
|
base: repoHeadBranch(repo)
|
|
7418
8332
|
});
|
|
7419
8333
|
await client.sessions.materialize(sessionId, { agentSessionId, worktreePath }, cfg.apiToken);
|
|
@@ -7448,6 +8362,8 @@ var createSessionSupervisor = (deps) => {
|
|
|
7448
8362
|
log(`deleted session #${sessionId} (removed worktree)`);
|
|
7449
8363
|
};
|
|
7450
8364
|
const title = async (sessionId, agentSessionId, worktreePath) => {
|
|
8365
|
+
const session2 = await client.sessions.get(sessionId);
|
|
8366
|
+
if (session2.agentKind !== "claude-code") return log(`title #${sessionId}: unsupported agent`);
|
|
7451
8367
|
const exchange = readFirstExchange(agentSessionId);
|
|
7452
8368
|
if (!exchange) return log(`title #${sessionId}: no transcript yet, skipping`);
|
|
7453
8369
|
const outcome = await generateTitle({
|
|
@@ -7490,7 +8406,7 @@ var createSessionSupervisor = (deps) => {
|
|
|
7490
8406
|
|
|
7491
8407
|
// src/worker/terminal-manager.ts
|
|
7492
8408
|
import { existsSync as existsSync7 } from "node:fs";
|
|
7493
|
-
import { spawn as
|
|
8409
|
+
import { spawn as spawn3 } from "node-pty";
|
|
7494
8410
|
|
|
7495
8411
|
// ../../node_modules/.pnpm/ws@8.21.0/node_modules/ws/wrapper.mjs
|
|
7496
8412
|
var import_stream2 = __toESM(require_stream(), 1);
|
|
@@ -7529,7 +8445,7 @@ var createTerminalManager = (deps) => {
|
|
|
7529
8445
|
return;
|
|
7530
8446
|
}
|
|
7531
8447
|
const claudeBin = process.env.BATON_CLAUDE_BIN ?? "claude";
|
|
7532
|
-
const term =
|
|
8448
|
+
const term = spawn3(claudeBin, ptyArgs(agentSessionId, hasSessionJsonl(agentSessionId)), {
|
|
7533
8449
|
name: "xterm-color",
|
|
7534
8450
|
cols: 80,
|
|
7535
8451
|
rows: 24,
|
|
@@ -7682,19 +8598,19 @@ import { existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as rea
|
|
|
7682
8598
|
import { homedir as homedir4 } from "node:os";
|
|
7683
8599
|
import { dirname as dirname3, join as join9 } from "node:path";
|
|
7684
8600
|
var machineIdPath = (env = process.env) => join9(env.XDG_DATA_HOME ?? join9(env.HOME ?? homedir4(), ".local/share"), "baton", "machine-id");
|
|
7685
|
-
var readOrCreateMachineId = (
|
|
7686
|
-
if (existsSync8(
|
|
7687
|
-
const s = readFileSync6(
|
|
8601
|
+
var readOrCreateMachineId = (path3 = machineIdPath()) => {
|
|
8602
|
+
if (existsSync8(path3)) {
|
|
8603
|
+
const s = readFileSync6(path3, "utf8").trim();
|
|
7688
8604
|
if (s) return s;
|
|
7689
8605
|
}
|
|
7690
8606
|
const id = randomUUID2();
|
|
7691
|
-
mkdirSync4(dirname3(
|
|
7692
|
-
writeFileSync5(
|
|
8607
|
+
mkdirSync4(dirname3(path3), { recursive: true });
|
|
8608
|
+
writeFileSync5(path3, `${id}
|
|
7693
8609
|
`, "utf8");
|
|
7694
8610
|
return id;
|
|
7695
8611
|
};
|
|
7696
8612
|
|
|
7697
|
-
// src/commands/worker.ts
|
|
8613
|
+
// src/commands/worker/index.ts
|
|
7698
8614
|
var resolveWorker = async (client, projectId, handle) => {
|
|
7699
8615
|
const asId = parseWorkerHandle(handle);
|
|
7700
8616
|
if (asId !== null) {
|
|
@@ -7705,9 +8621,15 @@ var resolveWorker = async (client, projectId, handle) => {
|
|
|
7705
8621
|
if (byName) return { id: byName.id, name: byName.name };
|
|
7706
8622
|
throw new Error(`worker "${handle}" not found in project ${projectId}`);
|
|
7707
8623
|
};
|
|
8624
|
+
var parseAgentKind = (value) => {
|
|
8625
|
+
const raw = typeof value === "string" && value.trim() ? value.trim() : "claude-code";
|
|
8626
|
+
if (raw === "claude-code" || raw === "codex") return raw;
|
|
8627
|
+
throw new Error(`invalid agent kind "${raw}" (expected claude-code or codex)`);
|
|
8628
|
+
};
|
|
7708
8629
|
var registerWorker = async (client, input, cfgPath = projectConfigPath()) => {
|
|
7709
8630
|
const out = await client.workers.register({
|
|
7710
8631
|
projectId: input.projectId,
|
|
8632
|
+
agentKind: input.agentKind,
|
|
7711
8633
|
machineId: input.machineId,
|
|
7712
8634
|
name: input.name,
|
|
7713
8635
|
hostname: input.hostname
|
|
@@ -7720,6 +8642,7 @@ var registerWorker = async (client, input, cfgPath = projectConfigPath()) => {
|
|
|
7720
8642
|
setWorker(cfgPath, {
|
|
7721
8643
|
id: out.worker.id,
|
|
7722
8644
|
name: out.worker.name,
|
|
8645
|
+
agentKind: out.worker.agentKind,
|
|
7723
8646
|
machineId: out.worker.machineId,
|
|
7724
8647
|
apiToken: out.apiToken
|
|
7725
8648
|
});
|
|
@@ -7740,6 +8663,10 @@ var worker = defineCommand({
|
|
|
7740
8663
|
type: "string",
|
|
7741
8664
|
description: "path to the worker config file (default: ./.baton.json)"
|
|
7742
8665
|
},
|
|
8666
|
+
agentKind: {
|
|
8667
|
+
type: "string",
|
|
8668
|
+
description: "agent engine for new sessions: claude-code or codex"
|
|
8669
|
+
},
|
|
7743
8670
|
...common
|
|
7744
8671
|
},
|
|
7745
8672
|
run: async ({ args }) => {
|
|
@@ -7756,6 +8683,7 @@ var worker = defineCommand({
|
|
|
7756
8683
|
const hostname = osHostname();
|
|
7757
8684
|
const machineId = readOrCreateMachineId();
|
|
7758
8685
|
const name = args.name ?? hostname;
|
|
8686
|
+
const agentKind = parseAgentKind(args.agentKind ?? process.env.BATON_AGENT_KIND);
|
|
7759
8687
|
const { out, configPath } = await registerWorker(
|
|
7760
8688
|
c,
|
|
7761
8689
|
{
|
|
@@ -7763,7 +8691,8 @@ var worker = defineCommand({
|
|
|
7763
8691
|
name,
|
|
7764
8692
|
server,
|
|
7765
8693
|
hostname,
|
|
7766
|
-
machineId
|
|
8694
|
+
machineId,
|
|
8695
|
+
agentKind
|
|
7767
8696
|
},
|
|
7768
8697
|
cfgPath
|
|
7769
8698
|
);
|
|
@@ -7772,6 +8701,7 @@ var worker = defineCommand({
|
|
|
7772
8701
|
return;
|
|
7773
8702
|
}
|
|
7774
8703
|
console.log(`worker #${out.worker.id} (${out.worker.name}) \u2014 ${out.outcome}`);
|
|
8704
|
+
console.log(` agentKind: ${out.worker.agentKind}`);
|
|
7775
8705
|
console.log(` hostname: ${out.worker.hostname}`);
|
|
7776
8706
|
console.log(` machineId: ${out.worker.machineId}`);
|
|
7777
8707
|
console.log(` machineId file: ${machineIdPath()}`);
|
|
@@ -7886,6 +8816,7 @@ var worker = defineCommand({
|
|
|
7886
8816
|
}
|
|
7887
8817
|
console.log(`worker #${worker2.id} (${worker2.name})`);
|
|
7888
8818
|
console.log(` machineId: ${worker2.machineId}`);
|
|
8819
|
+
console.log(` agentKind: ${worker2.agentKind ?? "claude-code"}`);
|
|
7889
8820
|
console.log(` server: ${cfg?.server}`);
|
|
7890
8821
|
}
|
|
7891
8822
|
})
|