@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/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" && isEnvironmentContextEnvelope(blocks))
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 (!isEnvironmentContextEnvelope(blocks))
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
- if (parsed.type === "session_meta") {
1890
- const payload = parsed.payload;
1891
- if (isObject6(payload)) {
1892
- if (typeof payload.id === "string")
1893
- sessionId = payload.id;
1894
- if (typeof payload.cwd === "string")
1895
- cwd = payload.cwd;
1896
- }
1897
- } else if (parsed.type === "response_item" && isObject6(parsed.payload)) {
1898
- const p = parsed.payload;
1899
- if (p.type === "message") {
1900
- messageCount++;
1901
- if (!firstUser && p.role === "user") {
1902
- firstUser = extractText(p.content)?.slice(0, PREVIEW_CHAR_CAP) ?? null;
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
- outer:
1911
- for await (const chunk of reader) {
1912
- buf += chunk;
1913
- let nl = buf.indexOf(`
1982
+ for await (const chunk of reader) {
1983
+ buf += chunk;
1984
+ let nl = buf.indexOf(`
1914
1985
  `);
1915
- while (nl !== -1) {
1916
- const line = buf.slice(0, nl);
1917
- buf = buf.slice(nl + 1);
1918
- nl = buf.indexOf(`
1986
+ while (nl !== -1) {
1987
+ const line = buf.slice(0, nl);
1988
+ buf = buf.slice(nl + 1);
1989
+ nl = buf.indexOf(`
1919
1990
  `);
1920
- if (processLine(line))
1921
- break outer;
1922
- }
1991
+ processLine(line);
1923
1992
  }
1924
- if (lineCount < PREVIEW_HEAD_LINES && buf.trim())
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 PREVIEW_HEAD_LINES = 40, PREVIEW_CHAR_CAP = 200;
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 = typeof msg.thread_id === "string" ? msg.thread_id : undefined;
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.delete(session.sessionId);
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 drainStream2(stream) {
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
- taskId: task.id,
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
- this.pendingWorktreeOpts.delete(task.id);
4658
- return await this.store.update(task.id, {
4659
- branch: info.branch,
4660
- worktreePath: info.path
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.taskId);
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
- await orch.setModel(taskId, optionalString2(payload, "model"), optionalString2(payload, "tabId"));
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
  }