@sma1lboy/kobe 0.5.16 → 0.5.18

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
@@ -2508,7 +2626,7 @@ var init_bridge = __esm(() => {
2508
2626
  init_server();
2509
2627
  });
2510
2628
 
2511
- // ../../node_modules/.bun/solid-js@1.9.10/node_modules/solid-js/dist/dev.js
2629
+ // ../../node_modules/.bun/solid-js@1.9.12/node_modules/solid-js/dist/dev.js
2512
2630
  function getContextId(count) {
2513
2631
  const num = String(count), len = num.length - 1;
2514
2632
  return sharedConfig.context.id + (len ? String.fromCharCode(96 + len) : "") + num;
@@ -3036,6 +3154,8 @@ function runComputation(node, value, time) {
3036
3154
  if (node.updatedAt != null && "observers" in node) {
3037
3155
  writeSignal(node, nextValue, true);
3038
3156
  } else if (Transition && Transition.running && node.pure) {
3157
+ if (!Transition.sources.has(node))
3158
+ node.value = nextValue;
3039
3159
  Transition.sources.add(node);
3040
3160
  node.tValue = nextValue;
3041
3161
  } else
@@ -3079,16 +3199,27 @@ function createComputation(fn, init, pure, state = STALE, options) {
3079
3199
  if (options && options.name)
3080
3200
  c.name = options.name;
3081
3201
  if (ExternalSourceConfig && c.fn) {
3202
+ const sourceFn = c.fn;
3082
3203
  const [track, trigger] = createSignal(undefined, {
3083
3204
  equals: false
3084
3205
  });
3085
- const ordinary = ExternalSourceConfig.factory(c.fn, trigger);
3206
+ const ordinary = ExternalSourceConfig.factory(sourceFn, trigger);
3086
3207
  onCleanup(() => ordinary.dispose());
3087
- const triggerInTransition = () => startTransition(trigger).then(() => inTransition.dispose());
3088
- const inTransition = ExternalSourceConfig.factory(c.fn, triggerInTransition);
3208
+ let inTransition;
3209
+ const triggerInTransition = () => startTransition(trigger).then(() => {
3210
+ if (inTransition) {
3211
+ inTransition.dispose();
3212
+ inTransition = undefined;
3213
+ }
3214
+ });
3089
3215
  c.fn = (x) => {
3090
3216
  track();
3091
- return Transition && Transition.running ? inTransition.track(x) : ordinary.track(x);
3217
+ if (Transition && Transition.running) {
3218
+ if (!inTransition)
3219
+ inTransition = ExternalSourceConfig.factory(sourceFn, triggerInTransition);
3220
+ return inTransition.track(x);
3221
+ }
3222
+ return ordinary.track(x);
3092
3223
  };
3093
3224
  }
3094
3225
  DevHooks.afterCreateOwner && DevHooks.afterCreateOwner(c);
@@ -3680,12 +3811,7 @@ var init_dev = __esm(() => {
3680
3811
  equals: equalFn
3681
3812
  };
3682
3813
  runEffects = runQueue;
3683
- UNOWNED = {
3684
- owned: null,
3685
- cleanups: null,
3686
- context: null,
3687
- owner: null
3688
- };
3814
+ UNOWNED = {};
3689
3815
  NO_INIT = {};
3690
3816
  DevHooks = {
3691
3817
  afterUpdate: null,
@@ -3761,7 +3887,7 @@ function allModels() {
3761
3887
  if (!caps)
3762
3888
  continue;
3763
3889
  for (const m of caps.models) {
3764
- const key = `${m.vendor}:${m.id}`;
3890
+ const key = `${m.vendor}:${m.id}:${m.effort ?? ""}`;
3765
3891
  if (seen.has(key))
3766
3892
  continue;
3767
3893
  seen.add(key);
@@ -3770,15 +3896,17 @@ function allModels() {
3770
3896
  }
3771
3897
  return out;
3772
3898
  }
3773
- function modelLabelFor(modelId) {
3899
+ function modelLabelFor(modelId, effort) {
3774
3900
  const resolved = modelId ?? defaultCapabilities.defaultModelId();
3775
3901
  for (const caps of Object.values(ENGINE_REGISTRY)) {
3776
3902
  if (!caps)
3777
3903
  continue;
3778
- const match = caps.models.find((m) => m.id === resolved);
3904
+ const match = caps.models.find((m) => m.id === resolved && (effort === undefined || m.effort === effort));
3779
3905
  if (match)
3780
3906
  return match.label;
3781
3907
  }
3908
+ if (effort)
3909
+ return `${resolved} \xB7 ${effort}`;
3782
3910
  return resolved;
3783
3911
  }
3784
3912
  var ENGINE_REGISTRY, ENGINE_IDENTITIES, defaultCapabilities, defaultIdentity;
@@ -3940,6 +4068,14 @@ function nextChatTabSeq(tabs) {
3940
4068
  max = t.seq;
3941
4069
  return max + 1;
3942
4070
  }
4071
+ function worktreeSlug(task) {
4072
+ if (task.kind === "main")
4073
+ return "";
4074
+ if (!task.worktreePath)
4075
+ return "";
4076
+ const match = task.worktreePath.match(/([^/\\]+)[/\\]*$/);
4077
+ return match ? match[1] ?? "" : "";
4078
+ }
3943
4079
  var toTaskId = (id) => id, DEFAULT_TASK_VENDOR = "claude";
3944
4080
 
3945
4081
  // src/orchestrator/index/ulid.ts
@@ -4354,6 +4490,548 @@ var init_session_pump = __esm(() => {
4354
4490
  init_core();
4355
4491
  });
4356
4492
 
4493
+ // src/orchestrator/worktree/animal-names.ts
4494
+ var ANIMAL_NAMES;
4495
+ var init_animal_names = __esm(() => {
4496
+ ANIMAL_NAMES = [
4497
+ "aardvark",
4498
+ "addax",
4499
+ "adder",
4500
+ "agouti",
4501
+ "albatross",
4502
+ "alpaca",
4503
+ "anaconda",
4504
+ "anchovy",
4505
+ "anglerfish",
4506
+ "anole",
4507
+ "anteater",
4508
+ "antelope",
4509
+ "ape",
4510
+ "argali",
4511
+ "armadillo",
4512
+ "avocet",
4513
+ "axolotl",
4514
+ "baboon",
4515
+ "badger",
4516
+ "banteng",
4517
+ "barracuda",
4518
+ "basilisk",
4519
+ "bass",
4520
+ "bat",
4521
+ "beagle",
4522
+ "bear",
4523
+ "beaver",
4524
+ "bee",
4525
+ "beetle",
4526
+ "beluga",
4527
+ "betta",
4528
+ "bison",
4529
+ "blackbird",
4530
+ "blenny",
4531
+ "bluebird",
4532
+ "bluegill",
4533
+ "boar",
4534
+ "bobcat",
4535
+ "bonito",
4536
+ "bovid",
4537
+ "buffalo",
4538
+ "bullfrog",
4539
+ "bunting",
4540
+ "bushbuck",
4541
+ "butterfly",
4542
+ "buzzard",
4543
+ "caiman",
4544
+ "camel",
4545
+ "canary",
4546
+ "capybara",
4547
+ "caracal",
4548
+ "cardinal",
4549
+ "caribou",
4550
+ "carp",
4551
+ "cassowary",
4552
+ "caterpillar",
4553
+ "catfish",
4554
+ "chameleon",
4555
+ "chamois",
4556
+ "char",
4557
+ "cheetah",
4558
+ "chickadee",
4559
+ "chimp",
4560
+ "chinchilla",
4561
+ "chipmunk",
4562
+ "chough",
4563
+ "cicada",
4564
+ "civet",
4565
+ "clam",
4566
+ "clownfish",
4567
+ "cobra",
4568
+ "cockatoo",
4569
+ "condor",
4570
+ "coot",
4571
+ "copperhead",
4572
+ "coral",
4573
+ "cormorant",
4574
+ "cougar",
4575
+ "coyote",
4576
+ "crab",
4577
+ "crane",
4578
+ "crawfish",
4579
+ "crayfish",
4580
+ "cricket",
4581
+ "crocodile",
4582
+ "crow",
4583
+ "cuckoo",
4584
+ "curlew",
4585
+ "cuttlefish",
4586
+ "deer",
4587
+ "dikdik",
4588
+ "dingo",
4589
+ "dolphin",
4590
+ "donkey",
4591
+ "dormouse",
4592
+ "dotterel",
4593
+ "dove",
4594
+ "dragonfly",
4595
+ "dromedary",
4596
+ "duck",
4597
+ "dugong",
4598
+ "dunlin",
4599
+ "eagle",
4600
+ "echidna",
4601
+ "eel",
4602
+ "egret",
4603
+ "eider",
4604
+ "eland",
4605
+ "elephant",
4606
+ "elk",
4607
+ "emu",
4608
+ "ermine",
4609
+ "falcon",
4610
+ "fawn",
4611
+ "ferret",
4612
+ "finch",
4613
+ "firefly",
4614
+ "flamingo",
4615
+ "flounder",
4616
+ "fox",
4617
+ "frog",
4618
+ "gadwall",
4619
+ "gannet",
4620
+ "gaur",
4621
+ "gazelle",
4622
+ "gecko",
4623
+ "gemsbok",
4624
+ "gerbil",
4625
+ "gharial",
4626
+ "gibbon",
4627
+ "gnu",
4628
+ "goat",
4629
+ "goby",
4630
+ "godwit",
4631
+ "goldfish",
4632
+ "goose",
4633
+ "gopher",
4634
+ "goral",
4635
+ "gorilla",
4636
+ "goshawk",
4637
+ "grackle",
4638
+ "grasshopper",
4639
+ "grayling",
4640
+ "grebe",
4641
+ "grouse",
4642
+ "guanaco",
4643
+ "guillemot",
4644
+ "guineafowl",
4645
+ "guppy",
4646
+ "halibut",
4647
+ "hammerhead",
4648
+ "hamster",
4649
+ "hare",
4650
+ "harrier",
4651
+ "hartebeest",
4652
+ "hawk",
4653
+ "hedgehog",
4654
+ "heron",
4655
+ "herring",
4656
+ "hippo",
4657
+ "hornbill",
4658
+ "hornet",
4659
+ "horse",
4660
+ "hummingbird",
4661
+ "hyena",
4662
+ "ibex",
4663
+ "ibis",
4664
+ "iguana",
4665
+ "impala",
4666
+ "indri",
4667
+ "jacana",
4668
+ "jackal",
4669
+ "jaguar",
4670
+ "jay",
4671
+ "jellyfish",
4672
+ "jerboa",
4673
+ "junco",
4674
+ "kakapo",
4675
+ "kangaroo",
4676
+ "kestrel",
4677
+ "killdeer",
4678
+ "kingfisher",
4679
+ "kinglet",
4680
+ "kite",
4681
+ "kiwi",
4682
+ "koala",
4683
+ "kookaburra",
4684
+ "krait",
4685
+ "krill",
4686
+ "kudu",
4687
+ "ladybug",
4688
+ "lamprey",
4689
+ "langur",
4690
+ "lapwing",
4691
+ "lark",
4692
+ "lemming",
4693
+ "lemur",
4694
+ "leopard",
4695
+ "limpet",
4696
+ "lion",
4697
+ "lionfish",
4698
+ "lizard",
4699
+ "llama",
4700
+ "lobster",
4701
+ "locust",
4702
+ "loon",
4703
+ "lorikeet",
4704
+ "loris",
4705
+ "lynx",
4706
+ "macaque",
4707
+ "macaw",
4708
+ "mackerel",
4709
+ "magpie",
4710
+ "mallard",
4711
+ "mamba",
4712
+ "mammoth",
4713
+ "manatee",
4714
+ "mandrill",
4715
+ "manta",
4716
+ "mantis",
4717
+ "marlin",
4718
+ "marmoset",
4719
+ "marmot",
4720
+ "marten",
4721
+ "meerkat",
4722
+ "merganser",
4723
+ "mink",
4724
+ "minnow",
4725
+ "mole",
4726
+ "mongoose",
4727
+ "monitor",
4728
+ "monkey",
4729
+ "moose",
4730
+ "moth",
4731
+ "mouflon",
4732
+ "mouse",
4733
+ "mudpuppy",
4734
+ "mule",
4735
+ "muntjac",
4736
+ "musk",
4737
+ "muskox",
4738
+ "muskrat",
4739
+ "mussel",
4740
+ "mustang",
4741
+ "narwhal",
4742
+ "newt",
4743
+ "nightingale",
4744
+ "numbat",
4745
+ "nuthatch",
4746
+ "nyala",
4747
+ "ocelot",
4748
+ "octopus",
4749
+ "okapi",
4750
+ "opossum",
4751
+ "orangutan",
4752
+ "orca",
4753
+ "oriole",
4754
+ "oryx",
4755
+ "osprey",
4756
+ "ostrich",
4757
+ "otter",
4758
+ "owl",
4759
+ "oyster",
4760
+ "oystercatcher",
4761
+ "paca",
4762
+ "panda",
4763
+ "pangolin",
4764
+ "panther",
4765
+ "parakeet",
4766
+ "parrot",
4767
+ "parrotfish",
4768
+ "partridge",
4769
+ "peafowl",
4770
+ "pelican",
4771
+ "penguin",
4772
+ "perch",
4773
+ "petrel",
4774
+ "pheasant",
4775
+ "pigeon",
4776
+ "pika",
4777
+ "pike",
4778
+ "pintail",
4779
+ "pipefish",
4780
+ "platypus",
4781
+ "plover",
4782
+ "pollock",
4783
+ "pony",
4784
+ "porcupine",
4785
+ "porpoise",
4786
+ "possum",
4787
+ "ptarmigan",
4788
+ "puffin",
4789
+ "puma",
4790
+ "pupfish",
4791
+ "python",
4792
+ "quail",
4793
+ "quetzal",
4794
+ "quokka",
4795
+ "quoll",
4796
+ "rabbit",
4797
+ "raccoon",
4798
+ "rail",
4799
+ "rat",
4800
+ "rattler",
4801
+ "raven",
4802
+ "ray",
4803
+ "redpoll",
4804
+ "reindeer",
4805
+ "remora",
4806
+ "rhino",
4807
+ "roadrunner",
4808
+ "robin",
4809
+ "rook",
4810
+ "sable",
4811
+ "sailfish",
4812
+ "salamander",
4813
+ "salmon",
4814
+ "sandpiper",
4815
+ "sardine",
4816
+ "scallop",
4817
+ "scaup",
4818
+ "scorpion",
4819
+ "seahorse",
4820
+ "seal",
4821
+ "serval",
4822
+ "shark",
4823
+ "shearwater",
4824
+ "shrew",
4825
+ "shrike",
4826
+ "shrimp",
4827
+ "siskin",
4828
+ "sitatunga",
4829
+ "skate",
4830
+ "skink",
4831
+ "skua",
4832
+ "skunk",
4833
+ "sloth",
4834
+ "smelt",
4835
+ "snail",
4836
+ "snipe",
4837
+ "solenodon",
4838
+ "sparrow",
4839
+ "spider",
4840
+ "springbok",
4841
+ "squid",
4842
+ "squirrel",
4843
+ "starfish",
4844
+ "starling",
4845
+ "stilt",
4846
+ "stingray",
4847
+ "stoat",
4848
+ "stork",
4849
+ "sunbird",
4850
+ "sunfish",
4851
+ "swallow",
4852
+ "swan",
4853
+ "swift",
4854
+ "swordfish",
4855
+ "tahr",
4856
+ "takin",
4857
+ "tamarin",
4858
+ "tanager",
4859
+ "tapir",
4860
+ "tarantula",
4861
+ "tarpon",
4862
+ "tarsier",
4863
+ "teal",
4864
+ "tenrec",
4865
+ "terrapin",
4866
+ "tern",
4867
+ "tetra",
4868
+ "thrasher",
4869
+ "thrush",
4870
+ "tiger",
4871
+ "toad",
4872
+ "tortoise",
4873
+ "toucan",
4874
+ "treecreeper",
4875
+ "treefrog",
4876
+ "trout",
4877
+ "tuatara",
4878
+ "tuna",
4879
+ "turkey",
4880
+ "turtle",
4881
+ "urchin",
4882
+ "urial",
4883
+ "vicuna",
4884
+ "viper",
4885
+ "vole",
4886
+ "vulture",
4887
+ "wagtail",
4888
+ "wallaby",
4889
+ "walleye",
4890
+ "walrus",
4891
+ "warbler",
4892
+ "warthog",
4893
+ "waterbuck",
4894
+ "weasel",
4895
+ "wildebeest",
4896
+ "wolf",
4897
+ "wolverine",
4898
+ "wombat",
4899
+ "woodcock",
4900
+ "woodpecker",
4901
+ "wrasse",
4902
+ "wren",
4903
+ "yak",
4904
+ "zebra",
4905
+ "zebu",
4906
+ "zorilla"
4907
+ ];
4908
+ });
4909
+
4910
+ // src/orchestrator/worktree/paths.ts
4911
+ import fs2 from "fs";
4912
+ import path7 from "path";
4913
+ function worktreeRootFor(repo) {
4914
+ if (!path7.isAbsolute(repo)) {
4915
+ throw new Error(`worktreeRootFor: repo must be an absolute path, got: ${repo}`);
4916
+ }
4917
+ return path7.join(repo, KOBE_WORKTREE_ROOT_SUBPATH);
4918
+ }
4919
+ function worktreePathFor(repo, slug) {
4920
+ if (!slug || /[/\\\0]/.test(slug)) {
4921
+ throw new Error(`worktreePathFor: invalid slug: ${JSON.stringify(slug)}`);
4922
+ }
4923
+ return path7.join(worktreeRootFor(repo), slug);
4924
+ }
4925
+ function listWorktreeDirNames(repo) {
4926
+ const root = worktreeRootFor(repo);
4927
+ try {
4928
+ return fs2.readdirSync(root, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
4929
+ } catch {
4930
+ return [];
4931
+ }
4932
+ }
4933
+ function isKobeManagedPath(repo, candidate) {
4934
+ if (!path7.isAbsolute(repo) || !path7.isAbsolute(candidate))
4935
+ return false;
4936
+ const root = canonicalize(worktreeRootFor(repo));
4937
+ const target = canonicalize(candidate);
4938
+ const rel = path7.relative(root, target);
4939
+ return rel !== "" && !rel.startsWith("..") && !path7.isAbsolute(rel);
4940
+ }
4941
+ function canonicalize(p) {
4942
+ try {
4943
+ return fs2.realpathSync(p);
4944
+ } catch {
4945
+ return path7.resolve(p);
4946
+ }
4947
+ }
4948
+ var KOBE_WORKTREE_ROOT_SUBPATH = ".claude/worktrees";
4949
+ var init_paths2 = () => {};
4950
+
4951
+ // src/orchestrator/worktree/slug-allocator.ts
4952
+ class SlugAllocator {
4953
+ activeSlugs;
4954
+ random;
4955
+ pool;
4956
+ pendingByRepo = new Map;
4957
+ chain = Promise.resolve();
4958
+ constructor(activeSlugs, options = {}) {
4959
+ this.activeSlugs = activeSlugs;
4960
+ this.random = options.random ?? Math.random;
4961
+ this.pool = options.pool ?? ANIMAL_NAMES;
4962
+ if (this.pool.length === 0) {
4963
+ throw new Error("SlugAllocator: animal pool cannot be empty");
4964
+ }
4965
+ }
4966
+ async allocate(repo) {
4967
+ const previous = this.chain;
4968
+ let release;
4969
+ this.chain = new Promise((resolve2) => {
4970
+ release = resolve2;
4971
+ });
4972
+ await previous;
4973
+ try {
4974
+ return this.pickLocked(repo);
4975
+ } finally {
4976
+ release();
4977
+ }
4978
+ }
4979
+ commit(repo, slug) {
4980
+ this.deletePending(repo, slug);
4981
+ }
4982
+ cancel(repo, slug) {
4983
+ this.deletePending(repo, slug);
4984
+ }
4985
+ pickLocked(repo) {
4986
+ const occupied = this.occupiedSlugs(repo);
4987
+ const candidates = this.pool.filter((n) => !occupied.has(n));
4988
+ if (candidates.length > 0) {
4989
+ const pick = candidates[Math.floor(this.random() * candidates.length)];
4990
+ this.addPending(repo, pick);
4991
+ return pick;
4992
+ }
4993
+ const base = this.pool[Math.floor(this.random() * this.pool.length)];
4994
+ for (let v = 2;; v++) {
4995
+ const candidate = `${base}-v${v}`;
4996
+ if (!occupied.has(candidate)) {
4997
+ this.addPending(repo, candidate);
4998
+ return candidate;
4999
+ }
5000
+ }
5001
+ }
5002
+ occupiedSlugs(repo) {
5003
+ const set = new Set(this.pendingByRepo.get(repo) ?? []);
5004
+ for (const slug of this.activeSlugs(repo)) {
5005
+ if (slug)
5006
+ set.add(slug);
5007
+ }
5008
+ for (const dir of listWorktreeDirNames(repo)) {
5009
+ set.add(dir);
5010
+ }
5011
+ return set;
5012
+ }
5013
+ addPending(repo, slug) {
5014
+ let pending = this.pendingByRepo.get(repo);
5015
+ if (!pending) {
5016
+ pending = new Set;
5017
+ this.pendingByRepo.set(repo, pending);
5018
+ }
5019
+ pending.add(slug);
5020
+ }
5021
+ deletePending(repo, slug) {
5022
+ const pending = this.pendingByRepo.get(repo);
5023
+ if (!pending)
5024
+ return;
5025
+ pending.delete(slug);
5026
+ if (pending.size === 0)
5027
+ this.pendingByRepo.delete(repo);
5028
+ }
5029
+ }
5030
+ var init_slug_allocator = __esm(() => {
5031
+ init_animal_names();
5032
+ init_paths2();
5033
+ });
5034
+
4357
5035
  // src/orchestrator/core.ts
4358
5036
  var exports_core = {};
4359
5037
  __export(exports_core, {
@@ -4416,6 +5094,8 @@ class Orchestrator {
4416
5094
  requestIdCounter = 0;
4417
5095
  sessionPump;
4418
5096
  pendingWorktreeOpts = new Map;
5097
+ slugAllocator;
5098
+ ensureWorktreeLatches = new Map;
4419
5099
  tasksAcc;
4420
5100
  setTasks;
4421
5101
  unsubscribeStore;
@@ -4445,6 +5125,7 @@ class Orchestrator {
4445
5125
  this.store = deps.store;
4446
5126
  this.worktrees = deps.worktrees;
4447
5127
  this.metadataSuggester = deps.metadataSuggester ?? new MetadataSuggester;
5128
+ 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
5129
  const [tasks, setTasks] = createSignal(this.store.list());
4449
5130
  this.tasksAcc = tasks;
4450
5131
  this.setTasks = (next) => setTasks(() => next);
@@ -4475,6 +5156,9 @@ class Orchestrator {
4475
5156
  modelForTab(task, tab, engine) {
4476
5157
  return tab.model ?? task.model ?? engine.capabilities.defaultModelId();
4477
5158
  }
5159
+ modelEffortForTab(task, tab) {
5160
+ return tab.modelEffort ?? task.modelEffort;
5161
+ }
4478
5162
  engineForTab(task, tab) {
4479
5163
  return this.engineForVendor(this.vendorForTab(task, tab));
4480
5164
  }
@@ -4639,26 +5323,49 @@ class Orchestrator {
4639
5323
  async ensureWorktree(task) {
4640
5324
  if (task.worktreePath)
4641
5325
  return task;
5326
+ const inflight = this.ensureWorktreeLatches.get(task.id);
5327
+ if (inflight) {
5328
+ await inflight;
5329
+ return this.requireTask(task.id);
5330
+ }
5331
+ const latch = this.doEnsureWorktree(task);
5332
+ this.ensureWorktreeLatches.set(task.id, latch);
5333
+ try {
5334
+ return await latch;
5335
+ } finally {
5336
+ this.ensureWorktreeLatches.delete(task.id);
5337
+ }
5338
+ }
5339
+ async doEnsureWorktree(task) {
4642
5340
  const opts = this.pendingWorktreeOpts.get(task.id);
4643
5341
  const branch = opts?.branch ?? `kobe/tmp-${task.id.slice(-8).toLowerCase()}`;
4644
5342
  const baseRef = opts?.baseRef;
5343
+ const slug = await this.slugAllocator.allocate(task.repo);
4645
5344
  let info;
4646
5345
  try {
4647
5346
  info = await this.worktrees.createForTask({
4648
5347
  repo: task.repo,
4649
- taskId: task.id,
5348
+ slug,
4650
5349
  branch,
4651
5350
  baseRef
4652
5351
  });
4653
5352
  } catch (err) {
5353
+ this.slugAllocator.cancel(task.repo, slug);
4654
5354
  const message = err instanceof Error ? err.message : String(err);
4655
5355
  throw new Error(summarizeWorktreeError(message, task.repo, baseRef ?? null), { cause: err });
4656
5356
  }
4657
- this.pendingWorktreeOpts.delete(task.id);
4658
- return await this.store.update(task.id, {
4659
- branch: info.branch,
4660
- worktreePath: info.path
4661
- });
5357
+ try {
5358
+ this.pendingWorktreeOpts.delete(task.id);
5359
+ const updated = await this.store.update(task.id, {
5360
+ branch: info.branch,
5361
+ worktreePath: info.path
5362
+ });
5363
+ this.slugAllocator.commit(task.repo, slug);
5364
+ return updated;
5365
+ } catch (err) {
5366
+ this.slugAllocator.cancel(task.repo, slug);
5367
+ throw err;
5368
+ }
4662
5369
  }
4663
5370
  async maybeRenameTempBranch(taskId, tabId, prompt) {
4664
5371
  if (!prompt || prompt.trim().length === 0)
@@ -4756,13 +5463,15 @@ class Orchestrator {
4756
5463
  }
4757
5464
  const engine = targetTab.sessionId ? await this.engineForTabRun(task, targetTab) : this.engineForTab(task, targetTab);
4758
5465
  const modelToUse = this.modelForTab(task, targetTab, engine);
5466
+ const modelEffortToUse = this.modelEffortForTab(task, targetTab);
4759
5467
  let handle;
4760
5468
  if (targetTab.sessionId) {
4761
5469
  handle = await engine.resume(targetTab.sessionId, promptToSend, {
4762
5470
  cwd: task.worktreePath,
4763
5471
  env: { KOBE_RESUME_CWD: task.worktreePath },
4764
5472
  permissionMode: task.permissionMode,
4765
- model: modelToUse
5473
+ model: modelToUse,
5474
+ modelEffort: modelEffortToUse
4766
5475
  });
4767
5476
  } else {
4768
5477
  let releaseLatch = () => {};
@@ -4773,7 +5482,8 @@ class Orchestrator {
4773
5482
  try {
4774
5483
  handle = await engine.spawn(task.worktreePath, promptToSend, {
4775
5484
  permissionMode: task.permissionMode,
4776
- model: modelToUse
5485
+ model: modelToUse,
5486
+ modelEffort: modelEffortToUse
4777
5487
  });
4778
5488
  await this.updateTab(task.id, targetTab.id, { sessionId: handle.sessionId });
4779
5489
  if (task.title === PLACEHOLDER_TASK_TITLE && prompt && prompt.trim().length > 0) {
@@ -4888,13 +5598,13 @@ class Orchestrator {
4888
5598
  return;
4889
5599
  await this.store.update(task.id, { permissionMode: mode });
4890
5600
  }
4891
- async setModel(id, model, tabId) {
5601
+ async setModel(id, model, tabId, modelEffort) {
4892
5602
  const task = this.requireTask(id);
4893
5603
  const tab = this.resolveTab(task, tabId);
4894
5604
  const vendor = model ? capabilitiesForModelId(model).vendorId : this.vendorForTab(task, tab);
4895
- if (tab.model === model && this.vendorForTab(task, tab) === vendor)
5605
+ if (tab.model === model && tab.modelEffort === modelEffort && this.vendorForTab(task, tab) === vendor)
4896
5606
  return;
4897
- await this.updateTab(task.id, tab.id, { model, vendor });
5607
+ await this.updateTab(task.id, tab.id, { model, modelEffort, vendor });
4898
5608
  }
4899
5609
  async setTitle(id, title) {
4900
5610
  const task = this.requireTask(id);
@@ -5268,6 +5978,7 @@ var init_core = __esm(() => {
5268
5978
  init_metadata_suggester();
5269
5979
  init_pr();
5270
5980
  init_session_pump();
5981
+ init_slug_allocator();
5271
5982
  IllegalTransitionError = class IllegalTransitionError extends Error {
5272
5983
  from;
5273
5984
  to;
@@ -5420,6 +6131,7 @@ class TaskIndexStore {
5420
6131
  seq: 1,
5421
6132
  createdAt: now,
5422
6133
  ...rest.model ? { model: rest.model } : {},
6134
+ ...rest.modelEffort ? { modelEffort: rest.modelEffort } : {},
5423
6135
  vendor: rest.vendor ?? DEFAULT_TASK_VENDOR
5424
6136
  }
5425
6137
  ];
@@ -5587,6 +6299,7 @@ function coerceTask(value) {
5587
6299
  createdAt: tt.createdAt,
5588
6300
  ...typeof tt.title === "string" ? { title: tt.title } : {},
5589
6301
  ...typeof tt.model === "string" ? { model: tt.model } : {},
6302
+ ...isModelEffortLevel(tt.modelEffort) ? { modelEffort: tt.modelEffort } : {},
5590
6303
  ...isVendorId(tt.vendor) ? { vendor: tt.vendor } : {}
5591
6304
  };
5592
6305
  tabs.push(tab);
@@ -5620,6 +6333,7 @@ function coerceTask(value) {
5620
6333
  kind: v.kind === "main" ? "main" : "task",
5621
6334
  permissionMode: isPermissionMode(v.permissionMode) ? v.permissionMode : undefined,
5622
6335
  model: typeof v.model === "string" ? v.model : undefined,
6336
+ modelEffort: isModelEffortLevel(v.modelEffort) ? v.modelEffort : undefined,
5623
6337
  vendor: resolveTaskVendor(v.vendor, typeof v.model === "string" ? v.model : undefined),
5624
6338
  createdAt: v.createdAt,
5625
6339
  updatedAt: v.updatedAt
@@ -5628,6 +6342,9 @@ function coerceTask(value) {
5628
6342
  function isPermissionMode(v) {
5629
6343
  return v === "default" || v === "plan";
5630
6344
  }
6345
+ function isModelEffortLevel(v) {
6346
+ return v === "none" || v === "minimal" || v === "low" || v === "medium" || v === "high" || v === "xhigh" || v === "max";
6347
+ }
5631
6348
  function isVendorId(v) {
5632
6349
  return typeof v === "string" && v in ENGINE_REGISTRY;
5633
6350
  }
@@ -5690,39 +6407,6 @@ var init_git = __esm(() => {
5690
6407
  };
5691
6408
  });
5692
6409
 
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
6410
  // src/orchestrator/worktree/manager.ts
5727
6411
  import fs3 from "fs";
5728
6412
  import path8 from "path";
@@ -5757,7 +6441,7 @@ class GitWorktreeManager {
5757
6441
  return info;
5758
6442
  }
5759
6443
  async createForTask(args) {
5760
- const target = worktreePathFor(args.repo, args.taskId);
6444
+ const target = worktreePathFor(args.repo, args.slug);
5761
6445
  return this.create(args.repo, args.branch, target, args.baseRef);
5762
6446
  }
5763
6447
  async remove(worktreePath, opts) {
@@ -6463,7 +7147,11 @@ async function startDaemonServer(orch, options = {}) {
6463
7147
  }
6464
7148
  case "task.model": {
6465
7149
  const taskId = requireString2(payload, "taskId");
6466
- await orch.setModel(taskId, optionalString2(payload, "model"), optionalString2(payload, "tabId"));
7150
+ const modelEffort = optionalString2(payload, "modelEffort");
7151
+ if (modelEffort !== undefined && modelEffort !== "none" && modelEffort !== "minimal" && modelEffort !== "low" && modelEffort !== "medium" && modelEffort !== "high" && modelEffort !== "xhigh" && modelEffort !== "max") {
7152
+ throw new Error("modelEffort must be a supported effort level");
7153
+ }
7154
+ await orch.setModel(taskId, optionalString2(payload, "model"), optionalString2(payload, "tabId"), modelEffort);
6467
7155
  broadcastTaskUpdated(orch, clients, taskId);
6468
7156
  return {};
6469
7157
  }