@sma1lboy/kobe 0.5.16 → 0.5.17
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/README.md +23 -9
- package/dist/bin/kobed.js +809 -129
- package/dist/cli/index.js +1081 -330
- package/package.json +1 -1
package/dist/bin/kobed.js
CHANGED
|
@@ -99,6 +99,7 @@ function serializeTask(task) {
|
|
|
99
99
|
pinned: task.pinned ?? false,
|
|
100
100
|
permissionMode: task.permissionMode,
|
|
101
101
|
model: task.model,
|
|
102
|
+
modelEffort: task.modelEffort,
|
|
102
103
|
vendor: task.vendor,
|
|
103
104
|
createdAt: task.createdAt,
|
|
104
105
|
updatedAt: task.updatedAt
|
|
@@ -552,6 +553,16 @@ var init_binary = __esm(() => {
|
|
|
552
553
|
});
|
|
553
554
|
|
|
554
555
|
// src/engine/claude-code-local/models.ts
|
|
556
|
+
function opus47EffortChoices(id, label) {
|
|
557
|
+
return CLAUDE_OPUS_EFFORT_LEVELS.map((effort) => ({
|
|
558
|
+
vendor: "claude",
|
|
559
|
+
id,
|
|
560
|
+
effort,
|
|
561
|
+
level: effort,
|
|
562
|
+
label: `${label} \xB7 ${effort}`,
|
|
563
|
+
hint: effort === "max" ? "deepest reasoning" : `${effort} effort`
|
|
564
|
+
}));
|
|
565
|
+
}
|
|
555
566
|
function parseContextWindowSize(modelIdentifier) {
|
|
556
567
|
const delimitedMatch = /(?:\(|\[)\s*(\d+(?:[,_]\d+)*(?:\.\d+)?)\s*([km])\s*(?:\)|\])/i.exec(modelIdentifier);
|
|
557
568
|
if (delimitedMatch?.[1] && delimitedMatch[2]) {
|
|
@@ -581,11 +592,20 @@ function claudeContextWindowFor(modelId) {
|
|
|
581
592
|
return LONG_CTX;
|
|
582
593
|
return STD_CTX;
|
|
583
594
|
}
|
|
584
|
-
var CLAUDE_MODELS, LONG_CTX = 1e6, STD_CTX = 200000;
|
|
595
|
+
var CLAUDE_OPUS_EFFORT_LEVELS, CLAUDE_MODELS, LONG_CTX = 1e6, STD_CTX = 200000;
|
|
585
596
|
var init_models = __esm(() => {
|
|
597
|
+
CLAUDE_OPUS_EFFORT_LEVELS = [
|
|
598
|
+
"low",
|
|
599
|
+
"medium",
|
|
600
|
+
"high",
|
|
601
|
+
"xhigh",
|
|
602
|
+
"max"
|
|
603
|
+
];
|
|
586
604
|
CLAUDE_MODELS = [
|
|
587
605
|
{ vendor: "claude", id: "claude-opus-4-7[1m]", label: "Opus 4.7 1M", hint: "long context, default" },
|
|
606
|
+
...opus47EffortChoices("claude-opus-4-7[1m]", "Opus 4.7 1M"),
|
|
588
607
|
{ vendor: "claude", id: "claude-opus-4-7", label: "Opus 4.7", hint: "most capable, slowest" },
|
|
608
|
+
...opus47EffortChoices("claude-opus-4-7", "Opus 4.7"),
|
|
589
609
|
{ vendor: "claude", id: "claude-sonnet-4-6[1m]", label: "sonnet 4.6 (1M)", hint: "long context" },
|
|
590
610
|
{ vendor: "claude", id: "claude-sonnet-4-6", label: "sonnet 4.6" },
|
|
591
611
|
{ vendor: "claude", id: "claude-haiku-4-5-20251001", label: "haiku 4.5", hint: "fastest, cheapest" }
|
|
@@ -635,6 +655,10 @@ var init_capabilities = __esm(() => {
|
|
|
635
655
|
vendorId: "claude",
|
|
636
656
|
label: "Claude Code",
|
|
637
657
|
models: CLAUDE_MODELS,
|
|
658
|
+
permissionModes: [
|
|
659
|
+
{ id: "default", label: "default" },
|
|
660
|
+
{ id: "plan", label: "plan mode" }
|
|
661
|
+
],
|
|
638
662
|
defaultModelId: resolveClaudeDefaultModelId,
|
|
639
663
|
contextWindowFor: claudeContextWindowFor
|
|
640
664
|
};
|
|
@@ -902,7 +926,12 @@ class SessionRegistry {
|
|
|
902
926
|
}
|
|
903
927
|
this.handles.set(handle.sessionId, handle);
|
|
904
928
|
}
|
|
905
|
-
unregister(sessionId) {
|
|
929
|
+
unregister(sessionId, proc) {
|
|
930
|
+
if (proc) {
|
|
931
|
+
const existing = this.handles.get(sessionId);
|
|
932
|
+
if (existing && existing.proc !== proc)
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
906
935
|
this.handles.delete(sessionId);
|
|
907
936
|
}
|
|
908
937
|
get(sessionId) {
|
|
@@ -1062,6 +1091,9 @@ function buildArgs(opts) {
|
|
|
1062
1091
|
if (opts.model) {
|
|
1063
1092
|
args.push("--model", opts.model);
|
|
1064
1093
|
}
|
|
1094
|
+
if (opts.modelEffort) {
|
|
1095
|
+
args.push("--effort", opts.modelEffort);
|
|
1096
|
+
}
|
|
1065
1097
|
if (opts.permissionMode) {
|
|
1066
1098
|
args.push("--permission-mode", opts.permissionMode);
|
|
1067
1099
|
}
|
|
@@ -1298,6 +1330,7 @@ class ClaudeCodeLocal {
|
|
|
1298
1330
|
cwd: args.cwd,
|
|
1299
1331
|
prompt: args.prompt,
|
|
1300
1332
|
model: args.opts?.model,
|
|
1333
|
+
modelEffort: args.opts?.modelEffort,
|
|
1301
1334
|
permissionMode: cliPermissionMode,
|
|
1302
1335
|
env: args.opts?.env,
|
|
1303
1336
|
resumeSessionId: args.resumeSessionId
|
|
@@ -1373,7 +1406,7 @@ class ClaudeCodeLocal {
|
|
|
1373
1406
|
if (session) {
|
|
1374
1407
|
session.closed = true;
|
|
1375
1408
|
this.notify(session);
|
|
1376
|
-
this.registry.unregister(session.sessionId);
|
|
1409
|
+
this.registry.unregister(session.sessionId, spawned.proc);
|
|
1377
1410
|
}
|
|
1378
1411
|
if (!bound) {
|
|
1379
1412
|
rejectHandle(new Error("claude exited without emitting a session id"));
|
|
@@ -1509,10 +1542,25 @@ var init_binary2 = __esm(() => {
|
|
|
1509
1542
|
function codexContextWindowFor(_modelId) {
|
|
1510
1543
|
return DEFAULT_CTX;
|
|
1511
1544
|
}
|
|
1512
|
-
var CODEX_MODELS, CODEX_FALLBACK_DEFAULT_MODEL_ID = "gpt-5.4-mini", DEFAULT_CTX = 400000;
|
|
1545
|
+
var CODEX_GPT55_EFFORT_LEVELS, CODEX_MODELS, CODEX_FALLBACK_DEFAULT_MODEL_ID = "gpt-5.4-mini", DEFAULT_CTX = 400000;
|
|
1513
1546
|
var init_models2 = __esm(() => {
|
|
1547
|
+
CODEX_GPT55_EFFORT_LEVELS = [
|
|
1548
|
+
"none",
|
|
1549
|
+
"low",
|
|
1550
|
+
"medium",
|
|
1551
|
+
"high",
|
|
1552
|
+
"xhigh"
|
|
1553
|
+
];
|
|
1514
1554
|
CODEX_MODELS = [
|
|
1515
1555
|
{ vendor: "codex", id: "gpt-5.5", label: "GPT-5.5", hint: "latest, ChatGPT-account compatible" },
|
|
1556
|
+
...CODEX_GPT55_EFFORT_LEVELS.map((effort) => ({
|
|
1557
|
+
vendor: "codex",
|
|
1558
|
+
id: "gpt-5.5",
|
|
1559
|
+
effort,
|
|
1560
|
+
level: effort,
|
|
1561
|
+
label: `GPT-5.5 \xB7 ${effort}`,
|
|
1562
|
+
hint: effort === "none" ? "no reasoning effort" : `${effort} reasoning`
|
|
1563
|
+
})),
|
|
1516
1564
|
{ vendor: "codex", id: "gpt-5.4", label: "GPT-5.4", hint: "stable" },
|
|
1517
1565
|
{ vendor: "codex", id: "gpt-5.4-mini", label: "GPT-5.4 mini", hint: "fastest, always supported" }
|
|
1518
1566
|
];
|
|
@@ -1564,6 +1612,10 @@ var init_capabilities2 = __esm(() => {
|
|
|
1564
1612
|
vendorId: "codex",
|
|
1565
1613
|
label: "Codex",
|
|
1566
1614
|
models: CODEX_MODELS,
|
|
1615
|
+
permissionModes: [
|
|
1616
|
+
{ id: "default", label: "full access" },
|
|
1617
|
+
{ id: "plan", label: "plan mode" }
|
|
1618
|
+
],
|
|
1567
1619
|
defaultModelId: resolveCodexDefaultModelId,
|
|
1568
1620
|
contextWindowFor: codexContextWindowFor
|
|
1569
1621
|
};
|
|
@@ -1608,6 +1660,36 @@ function isObject4(v) {
|
|
|
1608
1660
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1609
1661
|
}
|
|
1610
1662
|
|
|
1663
|
+
// src/engine/codex-local/synthetic.ts
|
|
1664
|
+
function isSyntheticCodexUserRow(blocks) {
|
|
1665
|
+
if (blocks.length === 0)
|
|
1666
|
+
return false;
|
|
1667
|
+
for (const b of blocks) {
|
|
1668
|
+
if (b.type !== "text")
|
|
1669
|
+
return false;
|
|
1670
|
+
const t = (b.text ?? "").trim();
|
|
1671
|
+
if (!isEnvironmentContextEnvelope(t) && !isInstructionsEnvelope(t))
|
|
1672
|
+
return false;
|
|
1673
|
+
}
|
|
1674
|
+
return true;
|
|
1675
|
+
}
|
|
1676
|
+
function visibleCodexUserText(content) {
|
|
1677
|
+
const blocks = normalizeCodexContent(content);
|
|
1678
|
+
if (isSyntheticCodexUserRow(blocks))
|
|
1679
|
+
return null;
|
|
1680
|
+
const text = blocks.filter((b) => b.type === "text").map((b) => b.text).join(" ").trim();
|
|
1681
|
+
return text.length > 0 ? text : null;
|
|
1682
|
+
}
|
|
1683
|
+
function isEnvironmentContextEnvelope(text) {
|
|
1684
|
+
return text.startsWith("<environment_context>") && text.endsWith("</environment_context>");
|
|
1685
|
+
}
|
|
1686
|
+
function isInstructionsEnvelope(text) {
|
|
1687
|
+
return text.startsWith("# AGENTS.md instructions for ") && text.includes(`
|
|
1688
|
+
<INSTRUCTIONS>
|
|
1689
|
+
`) && text.endsWith("</INSTRUCTIONS>");
|
|
1690
|
+
}
|
|
1691
|
+
var init_synthetic = () => {};
|
|
1692
|
+
|
|
1611
1693
|
// src/engine/codex-local/history.ts
|
|
1612
1694
|
import { readFile as readFile3, readdir as readdir3, unlink as unlink2 } from "fs/promises";
|
|
1613
1695
|
import { homedir as homedir8 } from "os";
|
|
@@ -1702,7 +1784,7 @@ function parseJsonl2(raw, sessionId) {
|
|
|
1702
1784
|
if (role !== "user" && role !== "assistant" && role !== "system")
|
|
1703
1785
|
continue;
|
|
1704
1786
|
const blocks = normalizeCodexContent(payload.content);
|
|
1705
|
-
if (role === "user" &&
|
|
1787
|
+
if (role === "user" && isSyntheticCodexUserRow(blocks))
|
|
1706
1788
|
continue;
|
|
1707
1789
|
const ts = typeof parsed.timestamp === "string" ? parsed.timestamp : new Date().toISOString();
|
|
1708
1790
|
out.push({ role, blocks, timestamp: ts, sessionId });
|
|
@@ -1734,7 +1816,7 @@ function deriveCodexUsageMetrics(raw) {
|
|
|
1734
1816
|
const payload = isObject5(parsed.payload) ? parsed.payload : undefined;
|
|
1735
1817
|
if (payload?.type === "message" && payload.role === "user" && timestampMs !== null) {
|
|
1736
1818
|
const blocks = normalizeCodexContent(payload.content);
|
|
1737
|
-
if (!
|
|
1819
|
+
if (!isSyntheticCodexUserRow(blocks))
|
|
1738
1820
|
lastUserTimestampMs = timestampMs;
|
|
1739
1821
|
}
|
|
1740
1822
|
continue;
|
|
@@ -1810,23 +1892,12 @@ function mergedDurationMs(intervals) {
|
|
|
1810
1892
|
function numberOr(v, fallback) {
|
|
1811
1893
|
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
1812
1894
|
}
|
|
1813
|
-
function isEnvironmentContextEnvelope(blocks) {
|
|
1814
|
-
if (blocks.length === 0)
|
|
1815
|
-
return false;
|
|
1816
|
-
for (const b of blocks) {
|
|
1817
|
-
if (b.type !== "text")
|
|
1818
|
-
return false;
|
|
1819
|
-
const t = (b.text ?? "").trim();
|
|
1820
|
-
if (!t.startsWith("<environment_context>") || !t.endsWith("</environment_context>"))
|
|
1821
|
-
return false;
|
|
1822
|
-
}
|
|
1823
|
-
return true;
|
|
1824
|
-
}
|
|
1825
1895
|
function isObject5(v) {
|
|
1826
1896
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1827
1897
|
}
|
|
1828
1898
|
var defaultDeps5;
|
|
1829
1899
|
var init_history2 = __esm(() => {
|
|
1900
|
+
init_synthetic();
|
|
1830
1901
|
defaultDeps5 = {
|
|
1831
1902
|
sessionsDir() {
|
|
1832
1903
|
return path5.join(homedir8(), ".codex", "sessions");
|
|
@@ -1881,47 +1952,46 @@ async function tryReadMeta(file) {
|
|
|
1881
1952
|
return null;
|
|
1882
1953
|
try {
|
|
1883
1954
|
let buf = "";
|
|
1884
|
-
let lineCount = 0;
|
|
1885
1955
|
const processLine = (line) => {
|
|
1886
|
-
lineCount++;
|
|
1887
1956
|
const parsed = safeParse(line);
|
|
1888
|
-
if (parsed)
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
}
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1957
|
+
if (!parsed)
|
|
1958
|
+
return;
|
|
1959
|
+
if (parsed.type === "session_meta") {
|
|
1960
|
+
const payload = parsed.payload;
|
|
1961
|
+
if (isObject6(payload)) {
|
|
1962
|
+
if (typeof payload.id === "string")
|
|
1963
|
+
sessionId = payload.id;
|
|
1964
|
+
if (typeof payload.cwd === "string")
|
|
1965
|
+
cwd = payload.cwd;
|
|
1966
|
+
}
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1969
|
+
if (parsed.type === "response_item" && isObject6(parsed.payload)) {
|
|
1970
|
+
const p = parsed.payload;
|
|
1971
|
+
if (p.type === "message") {
|
|
1972
|
+
messageCount++;
|
|
1973
|
+
if (!firstUser && p.role === "user") {
|
|
1974
|
+
const text = visibleCodexUserText(p.content);
|
|
1975
|
+
if (text)
|
|
1976
|
+
firstUser = text.slice(0, PREVIEW_CHAR_CAP);
|
|
1904
1977
|
}
|
|
1905
1978
|
}
|
|
1906
1979
|
}
|
|
1907
|
-
return lineCount >= PREVIEW_HEAD_LINES;
|
|
1908
1980
|
};
|
|
1909
1981
|
const reader = handle.createReadStream({ encoding: "utf8" });
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
let nl = buf.indexOf(`
|
|
1982
|
+
for await (const chunk of reader) {
|
|
1983
|
+
buf += chunk;
|
|
1984
|
+
let nl = buf.indexOf(`
|
|
1914
1985
|
`);
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1986
|
+
while (nl !== -1) {
|
|
1987
|
+
const line = buf.slice(0, nl);
|
|
1988
|
+
buf = buf.slice(nl + 1);
|
|
1989
|
+
nl = buf.indexOf(`
|
|
1919
1990
|
`);
|
|
1920
|
-
|
|
1921
|
-
break outer;
|
|
1922
|
-
}
|
|
1991
|
+
processLine(line);
|
|
1923
1992
|
}
|
|
1924
|
-
|
|
1993
|
+
}
|
|
1994
|
+
if (buf.trim())
|
|
1925
1995
|
processLine(buf);
|
|
1926
1996
|
} finally {
|
|
1927
1997
|
await handle.close().catch(() => {});
|
|
@@ -1947,29 +2017,13 @@ function safeParse(line) {
|
|
|
1947
2017
|
return null;
|
|
1948
2018
|
}
|
|
1949
2019
|
}
|
|
1950
|
-
function extractText(content) {
|
|
1951
|
-
if (typeof content === "string")
|
|
1952
|
-
return content;
|
|
1953
|
-
if (!Array.isArray(content))
|
|
1954
|
-
return null;
|
|
1955
|
-
for (const item of content) {
|
|
1956
|
-
if (typeof item === "string" && item.length > 0)
|
|
1957
|
-
return item;
|
|
1958
|
-
if (isObject6(item)) {
|
|
1959
|
-
const t = item.type;
|
|
1960
|
-
if ((t === "input_text" || t === "output_text" || t === "text") && typeof item.text === "string") {
|
|
1961
|
-
return item.text;
|
|
1962
|
-
}
|
|
1963
|
-
}
|
|
1964
|
-
}
|
|
1965
|
-
return null;
|
|
1966
|
-
}
|
|
1967
2020
|
function isObject6(v) {
|
|
1968
2021
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1969
2022
|
}
|
|
1970
|
-
var
|
|
2023
|
+
var PREVIEW_CHAR_CAP = 200;
|
|
1971
2024
|
var init_sessions2 = __esm(() => {
|
|
1972
2025
|
init_history2();
|
|
2026
|
+
init_synthetic();
|
|
1973
2027
|
});
|
|
1974
2028
|
|
|
1975
2029
|
// src/engine/codex-local/spawn.ts
|
|
@@ -2001,6 +2055,9 @@ function buildArgs2(opts) {
|
|
|
2001
2055
|
if (opts.model) {
|
|
2002
2056
|
args.push("-m", opts.model);
|
|
2003
2057
|
}
|
|
2058
|
+
if (opts.modelEffort) {
|
|
2059
|
+
args.push("-c", `model_reasoning_effort="${opts.modelEffort}"`);
|
|
2060
|
+
}
|
|
2004
2061
|
if (!isResume) {
|
|
2005
2062
|
args.push("-C", opts.cwd);
|
|
2006
2063
|
if (opts.permissionMode === "plan")
|
|
@@ -2038,8 +2095,8 @@ async function* parseStreamJson2(lines, opts = {}) {
|
|
|
2038
2095
|
const type = typeof msg.type === "string" ? msg.type : undefined;
|
|
2039
2096
|
if (!type)
|
|
2040
2097
|
continue;
|
|
2041
|
-
if (type === "thread.started") {
|
|
2042
|
-
const sid =
|
|
2098
|
+
if (type === "session_meta" || type === "thread.started") {
|
|
2099
|
+
const sid = codexSessionId(msg);
|
|
2043
2100
|
if (sid && !sessionIdEmitted) {
|
|
2044
2101
|
sessionIdEmitted = true;
|
|
2045
2102
|
opts.onSessionId?.(sid);
|
|
@@ -2125,6 +2182,15 @@ async function* readLines2(stream) {
|
|
|
2125
2182
|
function isObject7(v) {
|
|
2126
2183
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2127
2184
|
}
|
|
2185
|
+
function codexSessionId(msg) {
|
|
2186
|
+
if (msg.type === "session_meta") {
|
|
2187
|
+
const payload = isObject7(msg.payload) ? msg.payload : undefined;
|
|
2188
|
+
const id2 = payload?.id;
|
|
2189
|
+
return typeof id2 === "string" && id2.length > 0 ? id2 : undefined;
|
|
2190
|
+
}
|
|
2191
|
+
const id = msg.thread_id;
|
|
2192
|
+
return typeof id === "string" && id.length > 0 ? id : undefined;
|
|
2193
|
+
}
|
|
2128
2194
|
function numberOr2(v, fallback) {
|
|
2129
2195
|
return typeof v === "number" && Number.isFinite(v) ? v : fallback;
|
|
2130
2196
|
}
|
|
@@ -2213,6 +2279,7 @@ class CodexLocal {
|
|
|
2213
2279
|
cwd: args.cwd,
|
|
2214
2280
|
prompt: args.prompt,
|
|
2215
2281
|
model: args.opts?.model,
|
|
2282
|
+
modelEffort: args.opts?.modelEffort,
|
|
2216
2283
|
permissionMode: args.opts?.permissionMode,
|
|
2217
2284
|
env: args.opts?.env,
|
|
2218
2285
|
resumeSessionId: args.resumeSessionId
|
|
@@ -2226,9 +2293,18 @@ class CodexLocal {
|
|
|
2226
2293
|
const queue = [];
|
|
2227
2294
|
let session;
|
|
2228
2295
|
let bound = false;
|
|
2296
|
+
let stderrTail = "";
|
|
2229
2297
|
const bind = (sessionId) => {
|
|
2230
|
-
if (bound)
|
|
2298
|
+
if (bound) {
|
|
2299
|
+
if (session && session.sessionId !== sessionId) {
|
|
2300
|
+
queue.push({
|
|
2301
|
+
type: "error",
|
|
2302
|
+
message: `codex resumed to a different session id (got ${sessionId}, expected ${session.sessionId})`
|
|
2303
|
+
});
|
|
2304
|
+
this.notify(session);
|
|
2305
|
+
}
|
|
2231
2306
|
return;
|
|
2307
|
+
}
|
|
2232
2308
|
bound = true;
|
|
2233
2309
|
session = {
|
|
2234
2310
|
sessionId,
|
|
@@ -2260,6 +2336,25 @@ class CodexLocal {
|
|
|
2260
2336
|
throw err;
|
|
2261
2337
|
}
|
|
2262
2338
|
}
|
|
2339
|
+
captureStderrTail(spawned.stderr, (chunk) => {
|
|
2340
|
+
stderrTail = (stderrTail + chunk).slice(-STDERR_TAIL_CAP);
|
|
2341
|
+
});
|
|
2342
|
+
const exitInfo = {
|
|
2343
|
+
code: null,
|
|
2344
|
+
signal: null,
|
|
2345
|
+
seen: false
|
|
2346
|
+
};
|
|
2347
|
+
const exitObserved = new Promise((resolve2) => {
|
|
2348
|
+
spawned.proc.once("exit", (code, signal) => {
|
|
2349
|
+
exitInfo.code = code;
|
|
2350
|
+
exitInfo.signal = signal;
|
|
2351
|
+
exitInfo.seen = true;
|
|
2352
|
+
if (!bound) {
|
|
2353
|
+
rejectHandle(new Error(formatExitMsg("codex exited before session id was captured", code, signal, stderrTail)));
|
|
2354
|
+
}
|
|
2355
|
+
resolve2();
|
|
2356
|
+
});
|
|
2357
|
+
});
|
|
2263
2358
|
(async () => {
|
|
2264
2359
|
const events = parseStreamJson2(readLines2(spawned.stdout), {
|
|
2265
2360
|
onSessionId: (sid) => bind(sid)
|
|
@@ -2270,6 +2365,9 @@ class CodexLocal {
|
|
|
2270
2365
|
queue.push(enriched);
|
|
2271
2366
|
if (session)
|
|
2272
2367
|
this.notify(session);
|
|
2368
|
+
if ((enriched.type === "done" || enriched.type === "error") && session) {
|
|
2369
|
+
this.registry.unregister(session.sessionId, spawned.proc);
|
|
2370
|
+
}
|
|
2273
2371
|
}
|
|
2274
2372
|
} catch (err) {
|
|
2275
2373
|
const ev = {
|
|
@@ -2280,27 +2378,32 @@ class CodexLocal {
|
|
|
2280
2378
|
if (session)
|
|
2281
2379
|
this.notify(session);
|
|
2282
2380
|
} finally {
|
|
2381
|
+
await Promise.race([exitObserved, new Promise((r) => setTimeout(r, 500))]);
|
|
2283
2382
|
if (session) {
|
|
2383
|
+
const code = exitInfo.code;
|
|
2384
|
+
const lastEv = queue[queue.length - 1];
|
|
2385
|
+
if (exitInfo.seen && typeof code === "number" && code !== 0 && lastEv?.type !== "error") {
|
|
2386
|
+
queue.push({
|
|
2387
|
+
type: "error",
|
|
2388
|
+
message: formatExitMsg("codex exited", code, exitInfo.signal, stderrTail)
|
|
2389
|
+
});
|
|
2390
|
+
}
|
|
2284
2391
|
session.closed = true;
|
|
2285
2392
|
this.notify(session);
|
|
2286
|
-
this.registry.unregister(session.sessionId);
|
|
2287
|
-
this.running.
|
|
2393
|
+
this.registry.unregister(session.sessionId, spawned.proc);
|
|
2394
|
+
if (this.running.get(session.sessionId) === session) {
|
|
2395
|
+
this.running.delete(session.sessionId);
|
|
2396
|
+
}
|
|
2288
2397
|
}
|
|
2289
2398
|
if (!bound) {
|
|
2290
2399
|
rejectHandle(new Error("codex exited without emitting a session id"));
|
|
2291
2400
|
}
|
|
2292
2401
|
}
|
|
2293
2402
|
})();
|
|
2294
|
-
drainStream2(spawned.stderr);
|
|
2295
2403
|
spawned.proc.once("error", (err) => {
|
|
2296
2404
|
if (!bound)
|
|
2297
2405
|
rejectHandle(err);
|
|
2298
2406
|
});
|
|
2299
|
-
spawned.proc.once("exit", () => {
|
|
2300
|
-
if (!bound) {
|
|
2301
|
-
rejectHandle(new Error("codex exited before session id was captured"));
|
|
2302
|
-
}
|
|
2303
|
-
});
|
|
2304
2407
|
return handlePromise;
|
|
2305
2408
|
}
|
|
2306
2409
|
notify(session) {
|
|
@@ -2310,22 +2413,37 @@ class CodexLocal {
|
|
|
2310
2413
|
w();
|
|
2311
2414
|
}
|
|
2312
2415
|
}
|
|
2313
|
-
function
|
|
2416
|
+
function captureStderrTail(stream, onChunk) {
|
|
2314
2417
|
const s = stream;
|
|
2315
|
-
s.on("data", () => {
|
|
2418
|
+
s.on("data", (chunk) => {
|
|
2419
|
+
onChunk(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
|
|
2420
|
+
});
|
|
2316
2421
|
s.on("error", () => {});
|
|
2317
2422
|
}
|
|
2423
|
+
function formatExitMsg(prefix, code, signal, stderrTail) {
|
|
2424
|
+
const parts = [prefix];
|
|
2425
|
+
if (typeof code === "number")
|
|
2426
|
+
parts.push(`(code=${code}${signal ? `, signal=${signal}` : ""})`);
|
|
2427
|
+
else if (signal)
|
|
2428
|
+
parts.push(`(signal=${signal})`);
|
|
2429
|
+
const detail = stderrTail.trim().split(/\r?\n/).filter(Boolean).slice(-3).join(" | ");
|
|
2430
|
+
if (detail)
|
|
2431
|
+
parts.push(`: ${detail}`);
|
|
2432
|
+
return parts.join(" ").replace(/ : /, ": ");
|
|
2433
|
+
}
|
|
2318
2434
|
function enrichUsageEvent2(ev, startedAtIso) {
|
|
2319
2435
|
if (ev.type !== "usage")
|
|
2320
2436
|
return ev;
|
|
2321
2437
|
return { type: "usage", ...withTotalSpeedForTurn(ev, startedAtIso, new Date().toISOString()) };
|
|
2322
2438
|
}
|
|
2439
|
+
var STDERR_TAIL_CAP;
|
|
2323
2440
|
var init_codex_local = __esm(() => {
|
|
2324
2441
|
init_binary2();
|
|
2325
2442
|
init_capabilities2();
|
|
2326
2443
|
init_history2();
|
|
2327
2444
|
init_sessions2();
|
|
2328
2445
|
init_spawn2();
|
|
2446
|
+
STDERR_TAIL_CAP = 4 * 1024;
|
|
2329
2447
|
});
|
|
2330
2448
|
|
|
2331
2449
|
// src/orchestrator/bridge/server.ts
|
|
@@ -3761,7 +3879,7 @@ function allModels() {
|
|
|
3761
3879
|
if (!caps)
|
|
3762
3880
|
continue;
|
|
3763
3881
|
for (const m of caps.models) {
|
|
3764
|
-
const key = `${m.vendor}:${m.id}`;
|
|
3882
|
+
const key = `${m.vendor}:${m.id}:${m.effort ?? ""}`;
|
|
3765
3883
|
if (seen.has(key))
|
|
3766
3884
|
continue;
|
|
3767
3885
|
seen.add(key);
|
|
@@ -3770,15 +3888,17 @@ function allModels() {
|
|
|
3770
3888
|
}
|
|
3771
3889
|
return out;
|
|
3772
3890
|
}
|
|
3773
|
-
function modelLabelFor(modelId) {
|
|
3891
|
+
function modelLabelFor(modelId, effort) {
|
|
3774
3892
|
const resolved = modelId ?? defaultCapabilities.defaultModelId();
|
|
3775
3893
|
for (const caps of Object.values(ENGINE_REGISTRY)) {
|
|
3776
3894
|
if (!caps)
|
|
3777
3895
|
continue;
|
|
3778
|
-
const match = caps.models.find((m) => m.id === resolved);
|
|
3896
|
+
const match = caps.models.find((m) => m.id === resolved && (effort === undefined || m.effort === effort));
|
|
3779
3897
|
if (match)
|
|
3780
3898
|
return match.label;
|
|
3781
3899
|
}
|
|
3900
|
+
if (effort)
|
|
3901
|
+
return `${resolved} \xB7 ${effort}`;
|
|
3782
3902
|
return resolved;
|
|
3783
3903
|
}
|
|
3784
3904
|
var ENGINE_REGISTRY, ENGINE_IDENTITIES, defaultCapabilities, defaultIdentity;
|
|
@@ -3940,6 +4060,14 @@ function nextChatTabSeq(tabs) {
|
|
|
3940
4060
|
max = t.seq;
|
|
3941
4061
|
return max + 1;
|
|
3942
4062
|
}
|
|
4063
|
+
function worktreeSlug(task) {
|
|
4064
|
+
if (task.kind === "main")
|
|
4065
|
+
return "";
|
|
4066
|
+
if (!task.worktreePath)
|
|
4067
|
+
return "";
|
|
4068
|
+
const match = task.worktreePath.match(/([^/\\]+)[/\\]*$/);
|
|
4069
|
+
return match ? match[1] ?? "" : "";
|
|
4070
|
+
}
|
|
3943
4071
|
var toTaskId = (id) => id, DEFAULT_TASK_VENDOR = "claude";
|
|
3944
4072
|
|
|
3945
4073
|
// src/orchestrator/index/ulid.ts
|
|
@@ -4354,6 +4482,548 @@ var init_session_pump = __esm(() => {
|
|
|
4354
4482
|
init_core();
|
|
4355
4483
|
});
|
|
4356
4484
|
|
|
4485
|
+
// src/orchestrator/worktree/animal-names.ts
|
|
4486
|
+
var ANIMAL_NAMES;
|
|
4487
|
+
var init_animal_names = __esm(() => {
|
|
4488
|
+
ANIMAL_NAMES = [
|
|
4489
|
+
"aardvark",
|
|
4490
|
+
"addax",
|
|
4491
|
+
"adder",
|
|
4492
|
+
"agouti",
|
|
4493
|
+
"albatross",
|
|
4494
|
+
"alpaca",
|
|
4495
|
+
"anaconda",
|
|
4496
|
+
"anchovy",
|
|
4497
|
+
"anglerfish",
|
|
4498
|
+
"anole",
|
|
4499
|
+
"anteater",
|
|
4500
|
+
"antelope",
|
|
4501
|
+
"ape",
|
|
4502
|
+
"argali",
|
|
4503
|
+
"armadillo",
|
|
4504
|
+
"avocet",
|
|
4505
|
+
"axolotl",
|
|
4506
|
+
"baboon",
|
|
4507
|
+
"badger",
|
|
4508
|
+
"banteng",
|
|
4509
|
+
"barracuda",
|
|
4510
|
+
"basilisk",
|
|
4511
|
+
"bass",
|
|
4512
|
+
"bat",
|
|
4513
|
+
"beagle",
|
|
4514
|
+
"bear",
|
|
4515
|
+
"beaver",
|
|
4516
|
+
"bee",
|
|
4517
|
+
"beetle",
|
|
4518
|
+
"beluga",
|
|
4519
|
+
"betta",
|
|
4520
|
+
"bison",
|
|
4521
|
+
"blackbird",
|
|
4522
|
+
"blenny",
|
|
4523
|
+
"bluebird",
|
|
4524
|
+
"bluegill",
|
|
4525
|
+
"boar",
|
|
4526
|
+
"bobcat",
|
|
4527
|
+
"bonito",
|
|
4528
|
+
"bovid",
|
|
4529
|
+
"buffalo",
|
|
4530
|
+
"bullfrog",
|
|
4531
|
+
"bunting",
|
|
4532
|
+
"bushbuck",
|
|
4533
|
+
"butterfly",
|
|
4534
|
+
"buzzard",
|
|
4535
|
+
"caiman",
|
|
4536
|
+
"camel",
|
|
4537
|
+
"canary",
|
|
4538
|
+
"capybara",
|
|
4539
|
+
"caracal",
|
|
4540
|
+
"cardinal",
|
|
4541
|
+
"caribou",
|
|
4542
|
+
"carp",
|
|
4543
|
+
"cassowary",
|
|
4544
|
+
"caterpillar",
|
|
4545
|
+
"catfish",
|
|
4546
|
+
"chameleon",
|
|
4547
|
+
"chamois",
|
|
4548
|
+
"char",
|
|
4549
|
+
"cheetah",
|
|
4550
|
+
"chickadee",
|
|
4551
|
+
"chimp",
|
|
4552
|
+
"chinchilla",
|
|
4553
|
+
"chipmunk",
|
|
4554
|
+
"chough",
|
|
4555
|
+
"cicada",
|
|
4556
|
+
"civet",
|
|
4557
|
+
"clam",
|
|
4558
|
+
"clownfish",
|
|
4559
|
+
"cobra",
|
|
4560
|
+
"cockatoo",
|
|
4561
|
+
"condor",
|
|
4562
|
+
"coot",
|
|
4563
|
+
"copperhead",
|
|
4564
|
+
"coral",
|
|
4565
|
+
"cormorant",
|
|
4566
|
+
"cougar",
|
|
4567
|
+
"coyote",
|
|
4568
|
+
"crab",
|
|
4569
|
+
"crane",
|
|
4570
|
+
"crawfish",
|
|
4571
|
+
"crayfish",
|
|
4572
|
+
"cricket",
|
|
4573
|
+
"crocodile",
|
|
4574
|
+
"crow",
|
|
4575
|
+
"cuckoo",
|
|
4576
|
+
"curlew",
|
|
4577
|
+
"cuttlefish",
|
|
4578
|
+
"deer",
|
|
4579
|
+
"dikdik",
|
|
4580
|
+
"dingo",
|
|
4581
|
+
"dolphin",
|
|
4582
|
+
"donkey",
|
|
4583
|
+
"dormouse",
|
|
4584
|
+
"dotterel",
|
|
4585
|
+
"dove",
|
|
4586
|
+
"dragonfly",
|
|
4587
|
+
"dromedary",
|
|
4588
|
+
"duck",
|
|
4589
|
+
"dugong",
|
|
4590
|
+
"dunlin",
|
|
4591
|
+
"eagle",
|
|
4592
|
+
"echidna",
|
|
4593
|
+
"eel",
|
|
4594
|
+
"egret",
|
|
4595
|
+
"eider",
|
|
4596
|
+
"eland",
|
|
4597
|
+
"elephant",
|
|
4598
|
+
"elk",
|
|
4599
|
+
"emu",
|
|
4600
|
+
"ermine",
|
|
4601
|
+
"falcon",
|
|
4602
|
+
"fawn",
|
|
4603
|
+
"ferret",
|
|
4604
|
+
"finch",
|
|
4605
|
+
"firefly",
|
|
4606
|
+
"flamingo",
|
|
4607
|
+
"flounder",
|
|
4608
|
+
"fox",
|
|
4609
|
+
"frog",
|
|
4610
|
+
"gadwall",
|
|
4611
|
+
"gannet",
|
|
4612
|
+
"gaur",
|
|
4613
|
+
"gazelle",
|
|
4614
|
+
"gecko",
|
|
4615
|
+
"gemsbok",
|
|
4616
|
+
"gerbil",
|
|
4617
|
+
"gharial",
|
|
4618
|
+
"gibbon",
|
|
4619
|
+
"gnu",
|
|
4620
|
+
"goat",
|
|
4621
|
+
"goby",
|
|
4622
|
+
"godwit",
|
|
4623
|
+
"goldfish",
|
|
4624
|
+
"goose",
|
|
4625
|
+
"gopher",
|
|
4626
|
+
"goral",
|
|
4627
|
+
"gorilla",
|
|
4628
|
+
"goshawk",
|
|
4629
|
+
"grackle",
|
|
4630
|
+
"grasshopper",
|
|
4631
|
+
"grayling",
|
|
4632
|
+
"grebe",
|
|
4633
|
+
"grouse",
|
|
4634
|
+
"guanaco",
|
|
4635
|
+
"guillemot",
|
|
4636
|
+
"guineafowl",
|
|
4637
|
+
"guppy",
|
|
4638
|
+
"halibut",
|
|
4639
|
+
"hammerhead",
|
|
4640
|
+
"hamster",
|
|
4641
|
+
"hare",
|
|
4642
|
+
"harrier",
|
|
4643
|
+
"hartebeest",
|
|
4644
|
+
"hawk",
|
|
4645
|
+
"hedgehog",
|
|
4646
|
+
"heron",
|
|
4647
|
+
"herring",
|
|
4648
|
+
"hippo",
|
|
4649
|
+
"hornbill",
|
|
4650
|
+
"hornet",
|
|
4651
|
+
"horse",
|
|
4652
|
+
"hummingbird",
|
|
4653
|
+
"hyena",
|
|
4654
|
+
"ibex",
|
|
4655
|
+
"ibis",
|
|
4656
|
+
"iguana",
|
|
4657
|
+
"impala",
|
|
4658
|
+
"indri",
|
|
4659
|
+
"jacana",
|
|
4660
|
+
"jackal",
|
|
4661
|
+
"jaguar",
|
|
4662
|
+
"jay",
|
|
4663
|
+
"jellyfish",
|
|
4664
|
+
"jerboa",
|
|
4665
|
+
"junco",
|
|
4666
|
+
"kakapo",
|
|
4667
|
+
"kangaroo",
|
|
4668
|
+
"kestrel",
|
|
4669
|
+
"killdeer",
|
|
4670
|
+
"kingfisher",
|
|
4671
|
+
"kinglet",
|
|
4672
|
+
"kite",
|
|
4673
|
+
"kiwi",
|
|
4674
|
+
"koala",
|
|
4675
|
+
"kookaburra",
|
|
4676
|
+
"krait",
|
|
4677
|
+
"krill",
|
|
4678
|
+
"kudu",
|
|
4679
|
+
"ladybug",
|
|
4680
|
+
"lamprey",
|
|
4681
|
+
"langur",
|
|
4682
|
+
"lapwing",
|
|
4683
|
+
"lark",
|
|
4684
|
+
"lemming",
|
|
4685
|
+
"lemur",
|
|
4686
|
+
"leopard",
|
|
4687
|
+
"limpet",
|
|
4688
|
+
"lion",
|
|
4689
|
+
"lionfish",
|
|
4690
|
+
"lizard",
|
|
4691
|
+
"llama",
|
|
4692
|
+
"lobster",
|
|
4693
|
+
"locust",
|
|
4694
|
+
"loon",
|
|
4695
|
+
"lorikeet",
|
|
4696
|
+
"loris",
|
|
4697
|
+
"lynx",
|
|
4698
|
+
"macaque",
|
|
4699
|
+
"macaw",
|
|
4700
|
+
"mackerel",
|
|
4701
|
+
"magpie",
|
|
4702
|
+
"mallard",
|
|
4703
|
+
"mamba",
|
|
4704
|
+
"mammoth",
|
|
4705
|
+
"manatee",
|
|
4706
|
+
"mandrill",
|
|
4707
|
+
"manta",
|
|
4708
|
+
"mantis",
|
|
4709
|
+
"marlin",
|
|
4710
|
+
"marmoset",
|
|
4711
|
+
"marmot",
|
|
4712
|
+
"marten",
|
|
4713
|
+
"meerkat",
|
|
4714
|
+
"merganser",
|
|
4715
|
+
"mink",
|
|
4716
|
+
"minnow",
|
|
4717
|
+
"mole",
|
|
4718
|
+
"mongoose",
|
|
4719
|
+
"monitor",
|
|
4720
|
+
"monkey",
|
|
4721
|
+
"moose",
|
|
4722
|
+
"moth",
|
|
4723
|
+
"mouflon",
|
|
4724
|
+
"mouse",
|
|
4725
|
+
"mudpuppy",
|
|
4726
|
+
"mule",
|
|
4727
|
+
"muntjac",
|
|
4728
|
+
"musk",
|
|
4729
|
+
"muskox",
|
|
4730
|
+
"muskrat",
|
|
4731
|
+
"mussel",
|
|
4732
|
+
"mustang",
|
|
4733
|
+
"narwhal",
|
|
4734
|
+
"newt",
|
|
4735
|
+
"nightingale",
|
|
4736
|
+
"numbat",
|
|
4737
|
+
"nuthatch",
|
|
4738
|
+
"nyala",
|
|
4739
|
+
"ocelot",
|
|
4740
|
+
"octopus",
|
|
4741
|
+
"okapi",
|
|
4742
|
+
"opossum",
|
|
4743
|
+
"orangutan",
|
|
4744
|
+
"orca",
|
|
4745
|
+
"oriole",
|
|
4746
|
+
"oryx",
|
|
4747
|
+
"osprey",
|
|
4748
|
+
"ostrich",
|
|
4749
|
+
"otter",
|
|
4750
|
+
"owl",
|
|
4751
|
+
"oyster",
|
|
4752
|
+
"oystercatcher",
|
|
4753
|
+
"paca",
|
|
4754
|
+
"panda",
|
|
4755
|
+
"pangolin",
|
|
4756
|
+
"panther",
|
|
4757
|
+
"parakeet",
|
|
4758
|
+
"parrot",
|
|
4759
|
+
"parrotfish",
|
|
4760
|
+
"partridge",
|
|
4761
|
+
"peafowl",
|
|
4762
|
+
"pelican",
|
|
4763
|
+
"penguin",
|
|
4764
|
+
"perch",
|
|
4765
|
+
"petrel",
|
|
4766
|
+
"pheasant",
|
|
4767
|
+
"pigeon",
|
|
4768
|
+
"pika",
|
|
4769
|
+
"pike",
|
|
4770
|
+
"pintail",
|
|
4771
|
+
"pipefish",
|
|
4772
|
+
"platypus",
|
|
4773
|
+
"plover",
|
|
4774
|
+
"pollock",
|
|
4775
|
+
"pony",
|
|
4776
|
+
"porcupine",
|
|
4777
|
+
"porpoise",
|
|
4778
|
+
"possum",
|
|
4779
|
+
"ptarmigan",
|
|
4780
|
+
"puffin",
|
|
4781
|
+
"puma",
|
|
4782
|
+
"pupfish",
|
|
4783
|
+
"python",
|
|
4784
|
+
"quail",
|
|
4785
|
+
"quetzal",
|
|
4786
|
+
"quokka",
|
|
4787
|
+
"quoll",
|
|
4788
|
+
"rabbit",
|
|
4789
|
+
"raccoon",
|
|
4790
|
+
"rail",
|
|
4791
|
+
"rat",
|
|
4792
|
+
"rattler",
|
|
4793
|
+
"raven",
|
|
4794
|
+
"ray",
|
|
4795
|
+
"redpoll",
|
|
4796
|
+
"reindeer",
|
|
4797
|
+
"remora",
|
|
4798
|
+
"rhino",
|
|
4799
|
+
"roadrunner",
|
|
4800
|
+
"robin",
|
|
4801
|
+
"rook",
|
|
4802
|
+
"sable",
|
|
4803
|
+
"sailfish",
|
|
4804
|
+
"salamander",
|
|
4805
|
+
"salmon",
|
|
4806
|
+
"sandpiper",
|
|
4807
|
+
"sardine",
|
|
4808
|
+
"scallop",
|
|
4809
|
+
"scaup",
|
|
4810
|
+
"scorpion",
|
|
4811
|
+
"seahorse",
|
|
4812
|
+
"seal",
|
|
4813
|
+
"serval",
|
|
4814
|
+
"shark",
|
|
4815
|
+
"shearwater",
|
|
4816
|
+
"shrew",
|
|
4817
|
+
"shrike",
|
|
4818
|
+
"shrimp",
|
|
4819
|
+
"siskin",
|
|
4820
|
+
"sitatunga",
|
|
4821
|
+
"skate",
|
|
4822
|
+
"skink",
|
|
4823
|
+
"skua",
|
|
4824
|
+
"skunk",
|
|
4825
|
+
"sloth",
|
|
4826
|
+
"smelt",
|
|
4827
|
+
"snail",
|
|
4828
|
+
"snipe",
|
|
4829
|
+
"solenodon",
|
|
4830
|
+
"sparrow",
|
|
4831
|
+
"spider",
|
|
4832
|
+
"springbok",
|
|
4833
|
+
"squid",
|
|
4834
|
+
"squirrel",
|
|
4835
|
+
"starfish",
|
|
4836
|
+
"starling",
|
|
4837
|
+
"stilt",
|
|
4838
|
+
"stingray",
|
|
4839
|
+
"stoat",
|
|
4840
|
+
"stork",
|
|
4841
|
+
"sunbird",
|
|
4842
|
+
"sunfish",
|
|
4843
|
+
"swallow",
|
|
4844
|
+
"swan",
|
|
4845
|
+
"swift",
|
|
4846
|
+
"swordfish",
|
|
4847
|
+
"tahr",
|
|
4848
|
+
"takin",
|
|
4849
|
+
"tamarin",
|
|
4850
|
+
"tanager",
|
|
4851
|
+
"tapir",
|
|
4852
|
+
"tarantula",
|
|
4853
|
+
"tarpon",
|
|
4854
|
+
"tarsier",
|
|
4855
|
+
"teal",
|
|
4856
|
+
"tenrec",
|
|
4857
|
+
"terrapin",
|
|
4858
|
+
"tern",
|
|
4859
|
+
"tetra",
|
|
4860
|
+
"thrasher",
|
|
4861
|
+
"thrush",
|
|
4862
|
+
"tiger",
|
|
4863
|
+
"toad",
|
|
4864
|
+
"tortoise",
|
|
4865
|
+
"toucan",
|
|
4866
|
+
"treecreeper",
|
|
4867
|
+
"treefrog",
|
|
4868
|
+
"trout",
|
|
4869
|
+
"tuatara",
|
|
4870
|
+
"tuna",
|
|
4871
|
+
"turkey",
|
|
4872
|
+
"turtle",
|
|
4873
|
+
"urchin",
|
|
4874
|
+
"urial",
|
|
4875
|
+
"vicuna",
|
|
4876
|
+
"viper",
|
|
4877
|
+
"vole",
|
|
4878
|
+
"vulture",
|
|
4879
|
+
"wagtail",
|
|
4880
|
+
"wallaby",
|
|
4881
|
+
"walleye",
|
|
4882
|
+
"walrus",
|
|
4883
|
+
"warbler",
|
|
4884
|
+
"warthog",
|
|
4885
|
+
"waterbuck",
|
|
4886
|
+
"weasel",
|
|
4887
|
+
"wildebeest",
|
|
4888
|
+
"wolf",
|
|
4889
|
+
"wolverine",
|
|
4890
|
+
"wombat",
|
|
4891
|
+
"woodcock",
|
|
4892
|
+
"woodpecker",
|
|
4893
|
+
"wrasse",
|
|
4894
|
+
"wren",
|
|
4895
|
+
"yak",
|
|
4896
|
+
"zebra",
|
|
4897
|
+
"zebu",
|
|
4898
|
+
"zorilla"
|
|
4899
|
+
];
|
|
4900
|
+
});
|
|
4901
|
+
|
|
4902
|
+
// src/orchestrator/worktree/paths.ts
|
|
4903
|
+
import fs2 from "fs";
|
|
4904
|
+
import path7 from "path";
|
|
4905
|
+
function worktreeRootFor(repo) {
|
|
4906
|
+
if (!path7.isAbsolute(repo)) {
|
|
4907
|
+
throw new Error(`worktreeRootFor: repo must be an absolute path, got: ${repo}`);
|
|
4908
|
+
}
|
|
4909
|
+
return path7.join(repo, KOBE_WORKTREE_ROOT_SUBPATH);
|
|
4910
|
+
}
|
|
4911
|
+
function worktreePathFor(repo, slug) {
|
|
4912
|
+
if (!slug || /[/\\\0]/.test(slug)) {
|
|
4913
|
+
throw new Error(`worktreePathFor: invalid slug: ${JSON.stringify(slug)}`);
|
|
4914
|
+
}
|
|
4915
|
+
return path7.join(worktreeRootFor(repo), slug);
|
|
4916
|
+
}
|
|
4917
|
+
function listWorktreeDirNames(repo) {
|
|
4918
|
+
const root = worktreeRootFor(repo);
|
|
4919
|
+
try {
|
|
4920
|
+
return fs2.readdirSync(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
4921
|
+
} catch {
|
|
4922
|
+
return [];
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
function isKobeManagedPath(repo, candidate) {
|
|
4926
|
+
if (!path7.isAbsolute(repo) || !path7.isAbsolute(candidate))
|
|
4927
|
+
return false;
|
|
4928
|
+
const root = canonicalize(worktreeRootFor(repo));
|
|
4929
|
+
const target = canonicalize(candidate);
|
|
4930
|
+
const rel = path7.relative(root, target);
|
|
4931
|
+
return rel !== "" && !rel.startsWith("..") && !path7.isAbsolute(rel);
|
|
4932
|
+
}
|
|
4933
|
+
function canonicalize(p) {
|
|
4934
|
+
try {
|
|
4935
|
+
return fs2.realpathSync(p);
|
|
4936
|
+
} catch {
|
|
4937
|
+
return path7.resolve(p);
|
|
4938
|
+
}
|
|
4939
|
+
}
|
|
4940
|
+
var KOBE_WORKTREE_ROOT_SUBPATH = ".claude/worktrees";
|
|
4941
|
+
var init_paths2 = () => {};
|
|
4942
|
+
|
|
4943
|
+
// src/orchestrator/worktree/slug-allocator.ts
|
|
4944
|
+
class SlugAllocator {
|
|
4945
|
+
activeSlugs;
|
|
4946
|
+
random;
|
|
4947
|
+
pool;
|
|
4948
|
+
pendingByRepo = new Map;
|
|
4949
|
+
chain = Promise.resolve();
|
|
4950
|
+
constructor(activeSlugs, options = {}) {
|
|
4951
|
+
this.activeSlugs = activeSlugs;
|
|
4952
|
+
this.random = options.random ?? Math.random;
|
|
4953
|
+
this.pool = options.pool ?? ANIMAL_NAMES;
|
|
4954
|
+
if (this.pool.length === 0) {
|
|
4955
|
+
throw new Error("SlugAllocator: animal pool cannot be empty");
|
|
4956
|
+
}
|
|
4957
|
+
}
|
|
4958
|
+
async allocate(repo) {
|
|
4959
|
+
const previous = this.chain;
|
|
4960
|
+
let release;
|
|
4961
|
+
this.chain = new Promise((resolve2) => {
|
|
4962
|
+
release = resolve2;
|
|
4963
|
+
});
|
|
4964
|
+
await previous;
|
|
4965
|
+
try {
|
|
4966
|
+
return this.pickLocked(repo);
|
|
4967
|
+
} finally {
|
|
4968
|
+
release();
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4971
|
+
commit(repo, slug) {
|
|
4972
|
+
this.deletePending(repo, slug);
|
|
4973
|
+
}
|
|
4974
|
+
cancel(repo, slug) {
|
|
4975
|
+
this.deletePending(repo, slug);
|
|
4976
|
+
}
|
|
4977
|
+
pickLocked(repo) {
|
|
4978
|
+
const occupied = this.occupiedSlugs(repo);
|
|
4979
|
+
const candidates = this.pool.filter((n) => !occupied.has(n));
|
|
4980
|
+
if (candidates.length > 0) {
|
|
4981
|
+
const pick = candidates[Math.floor(this.random() * candidates.length)];
|
|
4982
|
+
this.addPending(repo, pick);
|
|
4983
|
+
return pick;
|
|
4984
|
+
}
|
|
4985
|
+
const base = this.pool[Math.floor(this.random() * this.pool.length)];
|
|
4986
|
+
for (let v = 2;; v++) {
|
|
4987
|
+
const candidate = `${base}-v${v}`;
|
|
4988
|
+
if (!occupied.has(candidate)) {
|
|
4989
|
+
this.addPending(repo, candidate);
|
|
4990
|
+
return candidate;
|
|
4991
|
+
}
|
|
4992
|
+
}
|
|
4993
|
+
}
|
|
4994
|
+
occupiedSlugs(repo) {
|
|
4995
|
+
const set = new Set(this.pendingByRepo.get(repo) ?? []);
|
|
4996
|
+
for (const slug of this.activeSlugs(repo)) {
|
|
4997
|
+
if (slug)
|
|
4998
|
+
set.add(slug);
|
|
4999
|
+
}
|
|
5000
|
+
for (const dir of listWorktreeDirNames(repo)) {
|
|
5001
|
+
set.add(dir);
|
|
5002
|
+
}
|
|
5003
|
+
return set;
|
|
5004
|
+
}
|
|
5005
|
+
addPending(repo, slug) {
|
|
5006
|
+
let pending = this.pendingByRepo.get(repo);
|
|
5007
|
+
if (!pending) {
|
|
5008
|
+
pending = new Set;
|
|
5009
|
+
this.pendingByRepo.set(repo, pending);
|
|
5010
|
+
}
|
|
5011
|
+
pending.add(slug);
|
|
5012
|
+
}
|
|
5013
|
+
deletePending(repo, slug) {
|
|
5014
|
+
const pending = this.pendingByRepo.get(repo);
|
|
5015
|
+
if (!pending)
|
|
5016
|
+
return;
|
|
5017
|
+
pending.delete(slug);
|
|
5018
|
+
if (pending.size === 0)
|
|
5019
|
+
this.pendingByRepo.delete(repo);
|
|
5020
|
+
}
|
|
5021
|
+
}
|
|
5022
|
+
var init_slug_allocator = __esm(() => {
|
|
5023
|
+
init_animal_names();
|
|
5024
|
+
init_paths2();
|
|
5025
|
+
});
|
|
5026
|
+
|
|
4357
5027
|
// src/orchestrator/core.ts
|
|
4358
5028
|
var exports_core = {};
|
|
4359
5029
|
__export(exports_core, {
|
|
@@ -4416,6 +5086,8 @@ class Orchestrator {
|
|
|
4416
5086
|
requestIdCounter = 0;
|
|
4417
5087
|
sessionPump;
|
|
4418
5088
|
pendingWorktreeOpts = new Map;
|
|
5089
|
+
slugAllocator;
|
|
5090
|
+
ensureWorktreeLatches = new Map;
|
|
4419
5091
|
tasksAcc;
|
|
4420
5092
|
setTasks;
|
|
4421
5093
|
unsubscribeStore;
|
|
@@ -4445,6 +5117,7 @@ class Orchestrator {
|
|
|
4445
5117
|
this.store = deps.store;
|
|
4446
5118
|
this.worktrees = deps.worktrees;
|
|
4447
5119
|
this.metadataSuggester = deps.metadataSuggester ?? new MetadataSuggester;
|
|
5120
|
+
this.slugAllocator = new SlugAllocator((repo) => this.store.list().filter((t) => t.repo === repo && !t.archived).map((t) => worktreeSlug(t)).filter((s) => s.length > 0));
|
|
4448
5121
|
const [tasks, setTasks] = createSignal(this.store.list());
|
|
4449
5122
|
this.tasksAcc = tasks;
|
|
4450
5123
|
this.setTasks = (next) => setTasks(() => next);
|
|
@@ -4475,6 +5148,9 @@ class Orchestrator {
|
|
|
4475
5148
|
modelForTab(task, tab, engine) {
|
|
4476
5149
|
return tab.model ?? task.model ?? engine.capabilities.defaultModelId();
|
|
4477
5150
|
}
|
|
5151
|
+
modelEffortForTab(task, tab) {
|
|
5152
|
+
return tab.modelEffort ?? task.modelEffort;
|
|
5153
|
+
}
|
|
4478
5154
|
engineForTab(task, tab) {
|
|
4479
5155
|
return this.engineForVendor(this.vendorForTab(task, tab));
|
|
4480
5156
|
}
|
|
@@ -4639,26 +5315,49 @@ class Orchestrator {
|
|
|
4639
5315
|
async ensureWorktree(task) {
|
|
4640
5316
|
if (task.worktreePath)
|
|
4641
5317
|
return task;
|
|
5318
|
+
const inflight = this.ensureWorktreeLatches.get(task.id);
|
|
5319
|
+
if (inflight) {
|
|
5320
|
+
await inflight;
|
|
5321
|
+
return this.requireTask(task.id);
|
|
5322
|
+
}
|
|
5323
|
+
const latch = this.doEnsureWorktree(task);
|
|
5324
|
+
this.ensureWorktreeLatches.set(task.id, latch);
|
|
5325
|
+
try {
|
|
5326
|
+
return await latch;
|
|
5327
|
+
} finally {
|
|
5328
|
+
this.ensureWorktreeLatches.delete(task.id);
|
|
5329
|
+
}
|
|
5330
|
+
}
|
|
5331
|
+
async doEnsureWorktree(task) {
|
|
4642
5332
|
const opts = this.pendingWorktreeOpts.get(task.id);
|
|
4643
5333
|
const branch = opts?.branch ?? `kobe/tmp-${task.id.slice(-8).toLowerCase()}`;
|
|
4644
5334
|
const baseRef = opts?.baseRef;
|
|
5335
|
+
const slug = await this.slugAllocator.allocate(task.repo);
|
|
4645
5336
|
let info;
|
|
4646
5337
|
try {
|
|
4647
5338
|
info = await this.worktrees.createForTask({
|
|
4648
5339
|
repo: task.repo,
|
|
4649
|
-
|
|
5340
|
+
slug,
|
|
4650
5341
|
branch,
|
|
4651
5342
|
baseRef
|
|
4652
5343
|
});
|
|
4653
5344
|
} catch (err) {
|
|
5345
|
+
this.slugAllocator.cancel(task.repo, slug);
|
|
4654
5346
|
const message = err instanceof Error ? err.message : String(err);
|
|
4655
5347
|
throw new Error(summarizeWorktreeError(message, task.repo, baseRef ?? null), { cause: err });
|
|
4656
5348
|
}
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
5349
|
+
try {
|
|
5350
|
+
this.pendingWorktreeOpts.delete(task.id);
|
|
5351
|
+
const updated = await this.store.update(task.id, {
|
|
5352
|
+
branch: info.branch,
|
|
5353
|
+
worktreePath: info.path
|
|
5354
|
+
});
|
|
5355
|
+
this.slugAllocator.commit(task.repo, slug);
|
|
5356
|
+
return updated;
|
|
5357
|
+
} catch (err) {
|
|
5358
|
+
this.slugAllocator.cancel(task.repo, slug);
|
|
5359
|
+
throw err;
|
|
5360
|
+
}
|
|
4662
5361
|
}
|
|
4663
5362
|
async maybeRenameTempBranch(taskId, tabId, prompt) {
|
|
4664
5363
|
if (!prompt || prompt.trim().length === 0)
|
|
@@ -4756,13 +5455,15 @@ class Orchestrator {
|
|
|
4756
5455
|
}
|
|
4757
5456
|
const engine = targetTab.sessionId ? await this.engineForTabRun(task, targetTab) : this.engineForTab(task, targetTab);
|
|
4758
5457
|
const modelToUse = this.modelForTab(task, targetTab, engine);
|
|
5458
|
+
const modelEffortToUse = this.modelEffortForTab(task, targetTab);
|
|
4759
5459
|
let handle;
|
|
4760
5460
|
if (targetTab.sessionId) {
|
|
4761
5461
|
handle = await engine.resume(targetTab.sessionId, promptToSend, {
|
|
4762
5462
|
cwd: task.worktreePath,
|
|
4763
5463
|
env: { KOBE_RESUME_CWD: task.worktreePath },
|
|
4764
5464
|
permissionMode: task.permissionMode,
|
|
4765
|
-
model: modelToUse
|
|
5465
|
+
model: modelToUse,
|
|
5466
|
+
modelEffort: modelEffortToUse
|
|
4766
5467
|
});
|
|
4767
5468
|
} else {
|
|
4768
5469
|
let releaseLatch = () => {};
|
|
@@ -4773,7 +5474,8 @@ class Orchestrator {
|
|
|
4773
5474
|
try {
|
|
4774
5475
|
handle = await engine.spawn(task.worktreePath, promptToSend, {
|
|
4775
5476
|
permissionMode: task.permissionMode,
|
|
4776
|
-
model: modelToUse
|
|
5477
|
+
model: modelToUse,
|
|
5478
|
+
modelEffort: modelEffortToUse
|
|
4777
5479
|
});
|
|
4778
5480
|
await this.updateTab(task.id, targetTab.id, { sessionId: handle.sessionId });
|
|
4779
5481
|
if (task.title === PLACEHOLDER_TASK_TITLE && prompt && prompt.trim().length > 0) {
|
|
@@ -4888,13 +5590,13 @@ class Orchestrator {
|
|
|
4888
5590
|
return;
|
|
4889
5591
|
await this.store.update(task.id, { permissionMode: mode });
|
|
4890
5592
|
}
|
|
4891
|
-
async setModel(id, model, tabId) {
|
|
5593
|
+
async setModel(id, model, tabId, modelEffort) {
|
|
4892
5594
|
const task = this.requireTask(id);
|
|
4893
5595
|
const tab = this.resolveTab(task, tabId);
|
|
4894
5596
|
const vendor = model ? capabilitiesForModelId(model).vendorId : this.vendorForTab(task, tab);
|
|
4895
|
-
if (tab.model === model && this.vendorForTab(task, tab) === vendor)
|
|
5597
|
+
if (tab.model === model && tab.modelEffort === modelEffort && this.vendorForTab(task, tab) === vendor)
|
|
4896
5598
|
return;
|
|
4897
|
-
await this.updateTab(task.id, tab.id, { model, vendor });
|
|
5599
|
+
await this.updateTab(task.id, tab.id, { model, modelEffort, vendor });
|
|
4898
5600
|
}
|
|
4899
5601
|
async setTitle(id, title) {
|
|
4900
5602
|
const task = this.requireTask(id);
|
|
@@ -5268,6 +5970,7 @@ var init_core = __esm(() => {
|
|
|
5268
5970
|
init_metadata_suggester();
|
|
5269
5971
|
init_pr();
|
|
5270
5972
|
init_session_pump();
|
|
5973
|
+
init_slug_allocator();
|
|
5271
5974
|
IllegalTransitionError = class IllegalTransitionError extends Error {
|
|
5272
5975
|
from;
|
|
5273
5976
|
to;
|
|
@@ -5420,6 +6123,7 @@ class TaskIndexStore {
|
|
|
5420
6123
|
seq: 1,
|
|
5421
6124
|
createdAt: now,
|
|
5422
6125
|
...rest.model ? { model: rest.model } : {},
|
|
6126
|
+
...rest.modelEffort ? { modelEffort: rest.modelEffort } : {},
|
|
5423
6127
|
vendor: rest.vendor ?? DEFAULT_TASK_VENDOR
|
|
5424
6128
|
}
|
|
5425
6129
|
];
|
|
@@ -5587,6 +6291,7 @@ function coerceTask(value) {
|
|
|
5587
6291
|
createdAt: tt.createdAt,
|
|
5588
6292
|
...typeof tt.title === "string" ? { title: tt.title } : {},
|
|
5589
6293
|
...typeof tt.model === "string" ? { model: tt.model } : {},
|
|
6294
|
+
...isModelEffortLevel(tt.modelEffort) ? { modelEffort: tt.modelEffort } : {},
|
|
5590
6295
|
...isVendorId(tt.vendor) ? { vendor: tt.vendor } : {}
|
|
5591
6296
|
};
|
|
5592
6297
|
tabs.push(tab);
|
|
@@ -5620,6 +6325,7 @@ function coerceTask(value) {
|
|
|
5620
6325
|
kind: v.kind === "main" ? "main" : "task",
|
|
5621
6326
|
permissionMode: isPermissionMode(v.permissionMode) ? v.permissionMode : undefined,
|
|
5622
6327
|
model: typeof v.model === "string" ? v.model : undefined,
|
|
6328
|
+
modelEffort: isModelEffortLevel(v.modelEffort) ? v.modelEffort : undefined,
|
|
5623
6329
|
vendor: resolveTaskVendor(v.vendor, typeof v.model === "string" ? v.model : undefined),
|
|
5624
6330
|
createdAt: v.createdAt,
|
|
5625
6331
|
updatedAt: v.updatedAt
|
|
@@ -5628,6 +6334,9 @@ function coerceTask(value) {
|
|
|
5628
6334
|
function isPermissionMode(v) {
|
|
5629
6335
|
return v === "default" || v === "plan";
|
|
5630
6336
|
}
|
|
6337
|
+
function isModelEffortLevel(v) {
|
|
6338
|
+
return v === "none" || v === "minimal" || v === "low" || v === "medium" || v === "high" || v === "xhigh" || v === "max";
|
|
6339
|
+
}
|
|
5631
6340
|
function isVendorId(v) {
|
|
5632
6341
|
return typeof v === "string" && v in ENGINE_REGISTRY;
|
|
5633
6342
|
}
|
|
@@ -5690,39 +6399,6 @@ var init_git = __esm(() => {
|
|
|
5690
6399
|
};
|
|
5691
6400
|
});
|
|
5692
6401
|
|
|
5693
|
-
// src/orchestrator/worktree/paths.ts
|
|
5694
|
-
import fs2 from "fs";
|
|
5695
|
-
import path7 from "path";
|
|
5696
|
-
function worktreeRootFor(repo) {
|
|
5697
|
-
if (!path7.isAbsolute(repo)) {
|
|
5698
|
-
throw new Error(`worktreeRootFor: repo must be an absolute path, got: ${repo}`);
|
|
5699
|
-
}
|
|
5700
|
-
return path7.join(repo, KOBE_WORKTREE_ROOT_SUBPATH);
|
|
5701
|
-
}
|
|
5702
|
-
function worktreePathFor(repo, taskId) {
|
|
5703
|
-
if (!taskId || /[/\\\0]/.test(taskId)) {
|
|
5704
|
-
throw new Error(`worktreePathFor: invalid taskId: ${JSON.stringify(taskId)}`);
|
|
5705
|
-
}
|
|
5706
|
-
return path7.join(worktreeRootFor(repo), taskId);
|
|
5707
|
-
}
|
|
5708
|
-
function isKobeManagedPath(repo, candidate) {
|
|
5709
|
-
if (!path7.isAbsolute(repo) || !path7.isAbsolute(candidate))
|
|
5710
|
-
return false;
|
|
5711
|
-
const root = canonicalize(worktreeRootFor(repo));
|
|
5712
|
-
const target = canonicalize(candidate);
|
|
5713
|
-
const rel = path7.relative(root, target);
|
|
5714
|
-
return rel !== "" && !rel.startsWith("..") && !path7.isAbsolute(rel);
|
|
5715
|
-
}
|
|
5716
|
-
function canonicalize(p) {
|
|
5717
|
-
try {
|
|
5718
|
-
return fs2.realpathSync(p);
|
|
5719
|
-
} catch {
|
|
5720
|
-
return path7.resolve(p);
|
|
5721
|
-
}
|
|
5722
|
-
}
|
|
5723
|
-
var KOBE_WORKTREE_ROOT_SUBPATH = ".claude/worktrees";
|
|
5724
|
-
var init_paths2 = () => {};
|
|
5725
|
-
|
|
5726
6402
|
// src/orchestrator/worktree/manager.ts
|
|
5727
6403
|
import fs3 from "fs";
|
|
5728
6404
|
import path8 from "path";
|
|
@@ -5757,7 +6433,7 @@ class GitWorktreeManager {
|
|
|
5757
6433
|
return info;
|
|
5758
6434
|
}
|
|
5759
6435
|
async createForTask(args) {
|
|
5760
|
-
const target = worktreePathFor(args.repo, args.
|
|
6436
|
+
const target = worktreePathFor(args.repo, args.slug);
|
|
5761
6437
|
return this.create(args.repo, args.branch, target, args.baseRef);
|
|
5762
6438
|
}
|
|
5763
6439
|
async remove(worktreePath, opts) {
|
|
@@ -6463,7 +7139,11 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
6463
7139
|
}
|
|
6464
7140
|
case "task.model": {
|
|
6465
7141
|
const taskId = requireString2(payload, "taskId");
|
|
6466
|
-
|
|
7142
|
+
const modelEffort = optionalString2(payload, "modelEffort");
|
|
7143
|
+
if (modelEffort !== undefined && modelEffort !== "none" && modelEffort !== "minimal" && modelEffort !== "low" && modelEffort !== "medium" && modelEffort !== "high" && modelEffort !== "xhigh" && modelEffort !== "max") {
|
|
7144
|
+
throw new Error("modelEffort must be a supported effort level");
|
|
7145
|
+
}
|
|
7146
|
+
await orch.setModel(taskId, optionalString2(payload, "model"), optionalString2(payload, "tabId"), modelEffort);
|
|
6467
7147
|
broadcastTaskUpdated(orch, clients, taskId);
|
|
6468
7148
|
return {};
|
|
6469
7149
|
}
|