@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/cli/index.js CHANGED
@@ -182,7 +182,7 @@ var init_repos = __esm(() => {
182
182
  init_env();
183
183
  });
184
184
 
185
- // ../../node_modules/.bun/solid-js@1.9.10/node_modules/solid-js/dist/dev.js
185
+ // ../../node_modules/.bun/solid-js@1.9.12/node_modules/solid-js/dist/dev.js
186
186
  function getContextId(count) {
187
187
  const num = String(count), len = num.length - 1;
188
188
  return sharedConfig.context.id + (len ? String.fromCharCode(96 + len) : "") + num;
@@ -710,6 +710,8 @@ function runComputation(node, value, time) {
710
710
  if (node.updatedAt != null && "observers" in node) {
711
711
  writeSignal(node, nextValue, true);
712
712
  } else if (Transition && Transition.running && node.pure) {
713
+ if (!Transition.sources.has(node))
714
+ node.value = nextValue;
713
715
  Transition.sources.add(node);
714
716
  node.tValue = nextValue;
715
717
  } else
@@ -753,16 +755,27 @@ function createComputation(fn, init, pure, state = STALE, options) {
753
755
  if (options && options.name)
754
756
  c.name = options.name;
755
757
  if (ExternalSourceConfig && c.fn) {
758
+ const sourceFn = c.fn;
756
759
  const [track, trigger] = createSignal(undefined, {
757
760
  equals: false
758
761
  });
759
- const ordinary = ExternalSourceConfig.factory(c.fn, trigger);
762
+ const ordinary = ExternalSourceConfig.factory(sourceFn, trigger);
760
763
  onCleanup(() => ordinary.dispose());
761
- const triggerInTransition = () => startTransition(trigger).then(() => inTransition.dispose());
762
- const inTransition = ExternalSourceConfig.factory(c.fn, triggerInTransition);
764
+ let inTransition;
765
+ const triggerInTransition = () => startTransition(trigger).then(() => {
766
+ if (inTransition) {
767
+ inTransition.dispose();
768
+ inTransition = undefined;
769
+ }
770
+ });
763
771
  c.fn = (x) => {
764
772
  track();
765
- return Transition && Transition.running ? inTransition.track(x) : ordinary.track(x);
773
+ if (Transition && Transition.running) {
774
+ if (!inTransition)
775
+ inTransition = ExternalSourceConfig.factory(sourceFn, triggerInTransition);
776
+ return inTransition.track(x);
777
+ }
778
+ return ordinary.track(x);
766
779
  };
767
780
  }
768
781
  DevHooks.afterCreateOwner && DevHooks.afterCreateOwner(c);
@@ -1354,12 +1367,7 @@ var init_dev = __esm(() => {
1354
1367
  equals: equalFn
1355
1368
  };
1356
1369
  runEffects = runQueue;
1357
- UNOWNED = {
1358
- owned: null,
1359
- cleanups: null,
1360
- context: null,
1361
- owner: null
1362
- };
1370
+ UNOWNED = {};
1363
1371
  NO_INIT = {};
1364
1372
  DevHooks = {
1365
1373
  afterUpdate: null,
@@ -1817,7 +1825,7 @@ var init_esm = __esm(() => {
1817
1825
  })(EncodingMode || (EncodingMode = {}));
1818
1826
  });
1819
1827
 
1820
- // ../../node_modules/.bun/@opentui+solid@0.2.4+ddd5ad692ec39e82/node_modules/@opentui/solid/index.js
1828
+ // ../../node_modules/.bun/@opentui+solid@0.2.4+f38a454781f02d2a/node_modules/@opentui/solid/index.js
1821
1829
  import { CliRenderer, createCliRenderer, engine as engine2 } from "@opentui/core";
1822
1830
  import { createTestRenderer } from "@opentui/core/testing";
1823
1831
  import {
@@ -2686,7 +2694,7 @@ var init_solid = __esm(() => {
2686
2694
  });
2687
2695
  });
2688
2696
 
2689
- // ../../node_modules/.bun/solid-js@1.9.10/node_modules/solid-js/store/dist/dev.js
2697
+ // ../../node_modules/.bun/solid-js@1.9.12/node_modules/solid-js/store/dist/dev.js
2690
2698
  function wrap$1(value) {
2691
2699
  let p = value[$PROXY];
2692
2700
  if (!p) {
@@ -5237,6 +5245,7 @@ function useKobeKeybindings(opts) {
5237
5245
  });
5238
5246
  const onFocusNext = opts.onFocusNext ?? (() => {});
5239
5247
  const onFocusPrev = opts.onFocusPrev ?? (() => {});
5248
+ const focusCycleEnabled = opts.focusCycleEnabled ?? (() => true);
5240
5249
  if (renderer) {
5241
5250
  const onSelection = () => {
5242
5251
  const text = renderer.getSelection()?.getSelectedText();
@@ -5275,13 +5284,16 @@ function useKobeKeybindings(opts) {
5275
5284
  ...bindByIds({
5276
5285
  "palette.open": () => palette.show(),
5277
5286
  "help.open": () => opts.onShowHelp(),
5278
- "focus.next": () => onFocusNext(),
5279
- "focus.prev": () => onFocusPrev(),
5280
5287
  "app.copy_or_quit": () => handleCtrlC()
5281
5288
  })
5282
5289
  ];
5283
5290
  });
5291
+ const focusCycleBindings = createMemo(() => bindByIds({
5292
+ "focus.next": () => onFocusNext(),
5293
+ "focus.prev": () => onFocusPrev()
5294
+ }));
5284
5295
  useBindings(() => ({ bindings: bindings() }));
5296
+ useBindings(() => ({ enabled: focusCycleEnabled(), bindings: focusCycleBindings() }));
5285
5297
  }
5286
5298
  var CTRL_C_QUIT_WINDOW_MS = 1500, ctrlCArmed, setCtrlCArmed, ctrlCArmTimer = null, KobeKeymap;
5287
5299
  var init_keybindings = __esm(() => {
@@ -14756,6 +14768,16 @@ var init_binary = __esm(() => {
14756
14768
  });
14757
14769
 
14758
14770
  // src/engine/claude-code-local/models.ts
14771
+ function opus47EffortChoices(id, label) {
14772
+ return CLAUDE_OPUS_EFFORT_LEVELS.map((effort) => ({
14773
+ vendor: "claude",
14774
+ id,
14775
+ effort,
14776
+ level: effort,
14777
+ label: `${label} \xB7 ${effort}`,
14778
+ hint: effort === "max" ? "deepest reasoning" : `${effort} effort`
14779
+ }));
14780
+ }
14759
14781
  function parseContextWindowSize(modelIdentifier) {
14760
14782
  const delimitedMatch = /(?:\(|\[)\s*(\d+(?:[,_]\d+)*(?:\.\d+)?)\s*([km])\s*(?:\)|\])/i.exec(modelIdentifier);
14761
14783
  if (delimitedMatch?.[1] && delimitedMatch[2]) {
@@ -14785,11 +14807,20 @@ function claudeContextWindowFor(modelId) {
14785
14807
  return LONG_CTX;
14786
14808
  return STD_CTX;
14787
14809
  }
14788
- var CLAUDE_MODELS, LONG_CTX = 1e6, STD_CTX = 200000;
14810
+ var CLAUDE_OPUS_EFFORT_LEVELS, CLAUDE_MODELS, LONG_CTX = 1e6, STD_CTX = 200000;
14789
14811
  var init_models = __esm(() => {
14812
+ CLAUDE_OPUS_EFFORT_LEVELS = [
14813
+ "low",
14814
+ "medium",
14815
+ "high",
14816
+ "xhigh",
14817
+ "max"
14818
+ ];
14790
14819
  CLAUDE_MODELS = [
14791
14820
  { vendor: "claude", id: "claude-opus-4-7[1m]", label: "Opus 4.7 1M", hint: "long context, default" },
14821
+ ...opus47EffortChoices("claude-opus-4-7[1m]", "Opus 4.7 1M"),
14792
14822
  { vendor: "claude", id: "claude-opus-4-7", label: "Opus 4.7", hint: "most capable, slowest" },
14823
+ ...opus47EffortChoices("claude-opus-4-7", "Opus 4.7"),
14793
14824
  { vendor: "claude", id: "claude-sonnet-4-6[1m]", label: "sonnet 4.6 (1M)", hint: "long context" },
14794
14825
  { vendor: "claude", id: "claude-sonnet-4-6", label: "sonnet 4.6" },
14795
14826
  { vendor: "claude", id: "claude-haiku-4-5-20251001", label: "haiku 4.5", hint: "fastest, cheapest" }
@@ -14839,6 +14870,10 @@ var init_capabilities = __esm(() => {
14839
14870
  vendorId: "claude",
14840
14871
  label: "Claude Code",
14841
14872
  models: CLAUDE_MODELS,
14873
+ permissionModes: [
14874
+ { id: "default", label: "default" },
14875
+ { id: "plan", label: "plan mode" }
14876
+ ],
14842
14877
  defaultModelId: resolveClaudeDefaultModelId,
14843
14878
  contextWindowFor: claudeContextWindowFor
14844
14879
  };
@@ -14855,10 +14890,25 @@ var init_capabilities = __esm(() => {
14855
14890
  function codexContextWindowFor(_modelId) {
14856
14891
  return DEFAULT_CTX;
14857
14892
  }
14858
- var CODEX_MODELS, CODEX_FALLBACK_DEFAULT_MODEL_ID = "gpt-5.4-mini", DEFAULT_CTX = 400000;
14893
+ var CODEX_GPT55_EFFORT_LEVELS, CODEX_MODELS, CODEX_FALLBACK_DEFAULT_MODEL_ID = "gpt-5.4-mini", DEFAULT_CTX = 400000;
14859
14894
  var init_models2 = __esm(() => {
14895
+ CODEX_GPT55_EFFORT_LEVELS = [
14896
+ "none",
14897
+ "low",
14898
+ "medium",
14899
+ "high",
14900
+ "xhigh"
14901
+ ];
14860
14902
  CODEX_MODELS = [
14861
14903
  { vendor: "codex", id: "gpt-5.5", label: "GPT-5.5", hint: "latest, ChatGPT-account compatible" },
14904
+ ...CODEX_GPT55_EFFORT_LEVELS.map((effort) => ({
14905
+ vendor: "codex",
14906
+ id: "gpt-5.5",
14907
+ effort,
14908
+ level: effort,
14909
+ label: `GPT-5.5 \xB7 ${effort}`,
14910
+ hint: effort === "none" ? "no reasoning effort" : `${effort} reasoning`
14911
+ })),
14862
14912
  { vendor: "codex", id: "gpt-5.4", label: "GPT-5.4", hint: "stable" },
14863
14913
  { vendor: "codex", id: "gpt-5.4-mini", label: "GPT-5.4 mini", hint: "fastest, always supported" }
14864
14914
  ];
@@ -14910,6 +14960,10 @@ var init_capabilities2 = __esm(() => {
14910
14960
  vendorId: "codex",
14911
14961
  label: "Codex",
14912
14962
  models: CODEX_MODELS,
14963
+ permissionModes: [
14964
+ { id: "default", label: "full access" },
14965
+ { id: "plan", label: "plan mode" }
14966
+ ],
14913
14967
  defaultModelId: resolveCodexDefaultModelId,
14914
14968
  contextWindowFor: codexContextWindowFor
14915
14969
  };
@@ -14947,7 +15001,7 @@ function allModels() {
14947
15001
  if (!caps)
14948
15002
  continue;
14949
15003
  for (const m2 of caps.models) {
14950
- const key = `${m2.vendor}:${m2.id}`;
15004
+ const key = `${m2.vendor}:${m2.id}:${m2.effort ?? ""}`;
14951
15005
  if (seen.has(key))
14952
15006
  continue;
14953
15007
  seen.add(key);
@@ -14956,15 +15010,17 @@ function allModels() {
14956
15010
  }
14957
15011
  return out;
14958
15012
  }
14959
- function modelLabelFor(modelId) {
15013
+ function modelLabelFor(modelId, effort) {
14960
15014
  const resolved = modelId ?? defaultCapabilities.defaultModelId();
14961
15015
  for (const caps of Object.values(ENGINE_REGISTRY)) {
14962
15016
  if (!caps)
14963
15017
  continue;
14964
- const match = caps.models.find((m2) => m2.id === resolved);
15018
+ const match = caps.models.find((m2) => m2.id === resolved && (effort === undefined || m2.effort === effort));
14965
15019
  if (match)
14966
15020
  return match.label;
14967
15021
  }
15022
+ if (effort)
15023
+ return `${resolved} \xB7 ${effort}`;
14968
15024
  return resolved;
14969
15025
  }
14970
15026
  var ENGINE_REGISTRY, ENGINE_IDENTITIES, defaultCapabilities, defaultIdentity;
@@ -14991,6 +15047,14 @@ function nextChatTabSeq(tabs) {
14991
15047
  max = t2.seq;
14992
15048
  return max + 1;
14993
15049
  }
15050
+ function worktreeSlug(task) {
15051
+ if (task.kind === "main")
15052
+ return "";
15053
+ if (!task.worktreePath)
15054
+ return "";
15055
+ const match = task.worktreePath.match(/([^/\\]+)[/\\]*$/);
15056
+ return match ? match[1] ?? "" : "";
15057
+ }
14994
15058
  var toTaskId = (id) => id, DEFAULT_TASK_VENDOR = "claude";
14995
15059
 
14996
15060
  // src/orchestrator/index/ulid.ts
@@ -15166,6 +15230,7 @@ class TaskIndexStore {
15166
15230
  seq: 1,
15167
15231
  createdAt: now,
15168
15232
  ...rest.model ? { model: rest.model } : {},
15233
+ ...rest.modelEffort ? { modelEffort: rest.modelEffort } : {},
15169
15234
  vendor: rest.vendor ?? DEFAULT_TASK_VENDOR
15170
15235
  }
15171
15236
  ];
@@ -15333,6 +15398,7 @@ function coerceTask(value) {
15333
15398
  createdAt: tt.createdAt,
15334
15399
  ...typeof tt.title === "string" ? { title: tt.title } : {},
15335
15400
  ...typeof tt.model === "string" ? { model: tt.model } : {},
15401
+ ...isModelEffortLevel(tt.modelEffort) ? { modelEffort: tt.modelEffort } : {},
15336
15402
  ...isVendorId(tt.vendor) ? { vendor: tt.vendor } : {}
15337
15403
  };
15338
15404
  tabs.push(tab);
@@ -15366,6 +15432,7 @@ function coerceTask(value) {
15366
15432
  kind: v2.kind === "main" ? "main" : "task",
15367
15433
  permissionMode: isPermissionMode(v2.permissionMode) ? v2.permissionMode : undefined,
15368
15434
  model: typeof v2.model === "string" ? v2.model : undefined,
15435
+ modelEffort: isModelEffortLevel(v2.modelEffort) ? v2.modelEffort : undefined,
15369
15436
  vendor: resolveTaskVendor(v2.vendor, typeof v2.model === "string" ? v2.model : undefined),
15370
15437
  createdAt: v2.createdAt,
15371
15438
  updatedAt: v2.updatedAt
@@ -15374,6 +15441,9 @@ function coerceTask(value) {
15374
15441
  function isPermissionMode(v2) {
15375
15442
  return v2 === "default" || v2 === "plan";
15376
15443
  }
15444
+ function isModelEffortLevel(v2) {
15445
+ return v2 === "none" || v2 === "minimal" || v2 === "low" || v2 === "medium" || v2 === "high" || v2 === "xhigh" || v2 === "max";
15446
+ }
15377
15447
  function isVendorId(v2) {
15378
15448
  return typeof v2 === "string" && v2 in ENGINE_REGISTRY;
15379
15449
  }
@@ -15403,11 +15473,19 @@ function worktreeRootFor(repo) {
15403
15473
  }
15404
15474
  return path4.join(repo, KOBE_WORKTREE_ROOT_SUBPATH);
15405
15475
  }
15406
- function worktreePathFor(repo, taskId) {
15407
- if (!taskId || /[/\\\0]/.test(taskId)) {
15408
- throw new Error(`worktreePathFor: invalid taskId: ${JSON.stringify(taskId)}`);
15476
+ function worktreePathFor(repo, slug) {
15477
+ if (!slug || /[/\\\0]/.test(slug)) {
15478
+ throw new Error(`worktreePathFor: invalid slug: ${JSON.stringify(slug)}`);
15479
+ }
15480
+ return path4.join(worktreeRootFor(repo), slug);
15481
+ }
15482
+ function listWorktreeDirNames(repo) {
15483
+ const root = worktreeRootFor(repo);
15484
+ try {
15485
+ return fs2.readdirSync(root, { withFileTypes: true }).filter((e2) => e2.isDirectory()).map((e2) => e2.name);
15486
+ } catch {
15487
+ return [];
15409
15488
  }
15410
- return path4.join(worktreeRootFor(repo), taskId);
15411
15489
  }
15412
15490
  function isKobeManagedPath(repo, candidate) {
15413
15491
  if (!path4.isAbsolute(repo) || !path4.isAbsolute(candidate))
@@ -15433,7 +15511,7 @@ var init_package = __esm(() => {
15433
15511
  package_default = {
15434
15512
  $schema: "https://json.schemastore.org/package.json",
15435
15513
  name: "@sma1lboy/kobe",
15436
- version: "0.5.16",
15514
+ version: "0.5.18",
15437
15515
  description: "TUI orchestrator for Claude Code (codename)",
15438
15516
  type: "module",
15439
15517
  packageManager: "bun@1.3.13",
@@ -15478,7 +15556,7 @@ var init_package = __esm(() => {
15478
15556
  "@opentui/core": "0.2.4",
15479
15557
  "@opentui/solid": "0.2.4",
15480
15558
  "@xterm/headless": "^6.0.0",
15481
- "solid-js": "1.9.10"
15559
+ "solid-js": "1.9.12"
15482
15560
  },
15483
15561
  devDependencies: {
15484
15562
  "@biomejs/biome": "1.9.4",
@@ -15723,19 +15801,6 @@ function dirSize(root) {
15723
15801
  }
15724
15802
  return total;
15725
15803
  }
15726
- function listWorktreeDirs(root) {
15727
- try {
15728
- return readdirSync(root).filter((n2) => {
15729
- try {
15730
- return statSync2(join5(root, n2)).isDirectory();
15731
- } catch {
15732
- return false;
15733
- }
15734
- });
15735
- } catch {
15736
- return [];
15737
- }
15738
- }
15739
15804
  function tailLines(path5, n2) {
15740
15805
  try {
15741
15806
  const text = __require("fs").readFileSync(path5, "utf8");
@@ -15841,8 +15906,7 @@ async function buildDiagnoseReport() {
15841
15906
  const onDiskByRepo = new Map;
15842
15907
  for (const repo of repos) {
15843
15908
  try {
15844
- const root = worktreeRootFor(repo);
15845
- onDiskByRepo.set(repo, listWorktreeDirs(root));
15909
+ onDiskByRepo.set(repo, listWorktreeDirNames(repo));
15846
15910
  } catch (err) {
15847
15911
  lines.push(formatKv("scan-error:", `${repo}: ${err.message}`));
15848
15912
  onDiskByRepo.set(repo, []);
@@ -16563,6 +16627,7 @@ function serializeTask(task) {
16563
16627
  pinned: task.pinned ?? false,
16564
16628
  permissionMode: task.permissionMode,
16565
16629
  model: task.model,
16630
+ modelEffort: task.modelEffort,
16566
16631
  vendor: task.vendor,
16567
16632
  createdAt: task.createdAt,
16568
16633
  updatedAt: task.updatedAt
@@ -17184,6 +17249,507 @@ var init_session_pump = __esm(() => {
17184
17249
  init_core();
17185
17250
  });
17186
17251
 
17252
+ // src/orchestrator/worktree/animal-names.ts
17253
+ var ANIMAL_NAMES;
17254
+ var init_animal_names = __esm(() => {
17255
+ ANIMAL_NAMES = [
17256
+ "aardvark",
17257
+ "addax",
17258
+ "adder",
17259
+ "agouti",
17260
+ "albatross",
17261
+ "alpaca",
17262
+ "anaconda",
17263
+ "anchovy",
17264
+ "anglerfish",
17265
+ "anole",
17266
+ "anteater",
17267
+ "antelope",
17268
+ "ape",
17269
+ "argali",
17270
+ "armadillo",
17271
+ "avocet",
17272
+ "axolotl",
17273
+ "baboon",
17274
+ "badger",
17275
+ "banteng",
17276
+ "barracuda",
17277
+ "basilisk",
17278
+ "bass",
17279
+ "bat",
17280
+ "beagle",
17281
+ "bear",
17282
+ "beaver",
17283
+ "bee",
17284
+ "beetle",
17285
+ "beluga",
17286
+ "betta",
17287
+ "bison",
17288
+ "blackbird",
17289
+ "blenny",
17290
+ "bluebird",
17291
+ "bluegill",
17292
+ "boar",
17293
+ "bobcat",
17294
+ "bonito",
17295
+ "bovid",
17296
+ "buffalo",
17297
+ "bullfrog",
17298
+ "bunting",
17299
+ "bushbuck",
17300
+ "butterfly",
17301
+ "buzzard",
17302
+ "caiman",
17303
+ "camel",
17304
+ "canary",
17305
+ "capybara",
17306
+ "caracal",
17307
+ "cardinal",
17308
+ "caribou",
17309
+ "carp",
17310
+ "cassowary",
17311
+ "caterpillar",
17312
+ "catfish",
17313
+ "chameleon",
17314
+ "chamois",
17315
+ "char",
17316
+ "cheetah",
17317
+ "chickadee",
17318
+ "chimp",
17319
+ "chinchilla",
17320
+ "chipmunk",
17321
+ "chough",
17322
+ "cicada",
17323
+ "civet",
17324
+ "clam",
17325
+ "clownfish",
17326
+ "cobra",
17327
+ "cockatoo",
17328
+ "condor",
17329
+ "coot",
17330
+ "copperhead",
17331
+ "coral",
17332
+ "cormorant",
17333
+ "cougar",
17334
+ "coyote",
17335
+ "crab",
17336
+ "crane",
17337
+ "crawfish",
17338
+ "crayfish",
17339
+ "cricket",
17340
+ "crocodile",
17341
+ "crow",
17342
+ "cuckoo",
17343
+ "curlew",
17344
+ "cuttlefish",
17345
+ "deer",
17346
+ "dikdik",
17347
+ "dingo",
17348
+ "dolphin",
17349
+ "donkey",
17350
+ "dormouse",
17351
+ "dotterel",
17352
+ "dove",
17353
+ "dragonfly",
17354
+ "dromedary",
17355
+ "duck",
17356
+ "dugong",
17357
+ "dunlin",
17358
+ "eagle",
17359
+ "echidna",
17360
+ "eel",
17361
+ "egret",
17362
+ "eider",
17363
+ "eland",
17364
+ "elephant",
17365
+ "elk",
17366
+ "emu",
17367
+ "ermine",
17368
+ "falcon",
17369
+ "fawn",
17370
+ "ferret",
17371
+ "finch",
17372
+ "firefly",
17373
+ "flamingo",
17374
+ "flounder",
17375
+ "fox",
17376
+ "frog",
17377
+ "gadwall",
17378
+ "gannet",
17379
+ "gaur",
17380
+ "gazelle",
17381
+ "gecko",
17382
+ "gemsbok",
17383
+ "gerbil",
17384
+ "gharial",
17385
+ "gibbon",
17386
+ "gnu",
17387
+ "goat",
17388
+ "goby",
17389
+ "godwit",
17390
+ "goldfish",
17391
+ "goose",
17392
+ "gopher",
17393
+ "goral",
17394
+ "gorilla",
17395
+ "goshawk",
17396
+ "grackle",
17397
+ "grasshopper",
17398
+ "grayling",
17399
+ "grebe",
17400
+ "grouse",
17401
+ "guanaco",
17402
+ "guillemot",
17403
+ "guineafowl",
17404
+ "guppy",
17405
+ "halibut",
17406
+ "hammerhead",
17407
+ "hamster",
17408
+ "hare",
17409
+ "harrier",
17410
+ "hartebeest",
17411
+ "hawk",
17412
+ "hedgehog",
17413
+ "heron",
17414
+ "herring",
17415
+ "hippo",
17416
+ "hornbill",
17417
+ "hornet",
17418
+ "horse",
17419
+ "hummingbird",
17420
+ "hyena",
17421
+ "ibex",
17422
+ "ibis",
17423
+ "iguana",
17424
+ "impala",
17425
+ "indri",
17426
+ "jacana",
17427
+ "jackal",
17428
+ "jaguar",
17429
+ "jay",
17430
+ "jellyfish",
17431
+ "jerboa",
17432
+ "junco",
17433
+ "kakapo",
17434
+ "kangaroo",
17435
+ "kestrel",
17436
+ "killdeer",
17437
+ "kingfisher",
17438
+ "kinglet",
17439
+ "kite",
17440
+ "kiwi",
17441
+ "koala",
17442
+ "kookaburra",
17443
+ "krait",
17444
+ "krill",
17445
+ "kudu",
17446
+ "ladybug",
17447
+ "lamprey",
17448
+ "langur",
17449
+ "lapwing",
17450
+ "lark",
17451
+ "lemming",
17452
+ "lemur",
17453
+ "leopard",
17454
+ "limpet",
17455
+ "lion",
17456
+ "lionfish",
17457
+ "lizard",
17458
+ "llama",
17459
+ "lobster",
17460
+ "locust",
17461
+ "loon",
17462
+ "lorikeet",
17463
+ "loris",
17464
+ "lynx",
17465
+ "macaque",
17466
+ "macaw",
17467
+ "mackerel",
17468
+ "magpie",
17469
+ "mallard",
17470
+ "mamba",
17471
+ "mammoth",
17472
+ "manatee",
17473
+ "mandrill",
17474
+ "manta",
17475
+ "mantis",
17476
+ "marlin",
17477
+ "marmoset",
17478
+ "marmot",
17479
+ "marten",
17480
+ "meerkat",
17481
+ "merganser",
17482
+ "mink",
17483
+ "minnow",
17484
+ "mole",
17485
+ "mongoose",
17486
+ "monitor",
17487
+ "monkey",
17488
+ "moose",
17489
+ "moth",
17490
+ "mouflon",
17491
+ "mouse",
17492
+ "mudpuppy",
17493
+ "mule",
17494
+ "muntjac",
17495
+ "musk",
17496
+ "muskox",
17497
+ "muskrat",
17498
+ "mussel",
17499
+ "mustang",
17500
+ "narwhal",
17501
+ "newt",
17502
+ "nightingale",
17503
+ "numbat",
17504
+ "nuthatch",
17505
+ "nyala",
17506
+ "ocelot",
17507
+ "octopus",
17508
+ "okapi",
17509
+ "opossum",
17510
+ "orangutan",
17511
+ "orca",
17512
+ "oriole",
17513
+ "oryx",
17514
+ "osprey",
17515
+ "ostrich",
17516
+ "otter",
17517
+ "owl",
17518
+ "oyster",
17519
+ "oystercatcher",
17520
+ "paca",
17521
+ "panda",
17522
+ "pangolin",
17523
+ "panther",
17524
+ "parakeet",
17525
+ "parrot",
17526
+ "parrotfish",
17527
+ "partridge",
17528
+ "peafowl",
17529
+ "pelican",
17530
+ "penguin",
17531
+ "perch",
17532
+ "petrel",
17533
+ "pheasant",
17534
+ "pigeon",
17535
+ "pika",
17536
+ "pike",
17537
+ "pintail",
17538
+ "pipefish",
17539
+ "platypus",
17540
+ "plover",
17541
+ "pollock",
17542
+ "pony",
17543
+ "porcupine",
17544
+ "porpoise",
17545
+ "possum",
17546
+ "ptarmigan",
17547
+ "puffin",
17548
+ "puma",
17549
+ "pupfish",
17550
+ "python",
17551
+ "quail",
17552
+ "quetzal",
17553
+ "quokka",
17554
+ "quoll",
17555
+ "rabbit",
17556
+ "raccoon",
17557
+ "rail",
17558
+ "rat",
17559
+ "rattler",
17560
+ "raven",
17561
+ "ray",
17562
+ "redpoll",
17563
+ "reindeer",
17564
+ "remora",
17565
+ "rhino",
17566
+ "roadrunner",
17567
+ "robin",
17568
+ "rook",
17569
+ "sable",
17570
+ "sailfish",
17571
+ "salamander",
17572
+ "salmon",
17573
+ "sandpiper",
17574
+ "sardine",
17575
+ "scallop",
17576
+ "scaup",
17577
+ "scorpion",
17578
+ "seahorse",
17579
+ "seal",
17580
+ "serval",
17581
+ "shark",
17582
+ "shearwater",
17583
+ "shrew",
17584
+ "shrike",
17585
+ "shrimp",
17586
+ "siskin",
17587
+ "sitatunga",
17588
+ "skate",
17589
+ "skink",
17590
+ "skua",
17591
+ "skunk",
17592
+ "sloth",
17593
+ "smelt",
17594
+ "snail",
17595
+ "snipe",
17596
+ "solenodon",
17597
+ "sparrow",
17598
+ "spider",
17599
+ "springbok",
17600
+ "squid",
17601
+ "squirrel",
17602
+ "starfish",
17603
+ "starling",
17604
+ "stilt",
17605
+ "stingray",
17606
+ "stoat",
17607
+ "stork",
17608
+ "sunbird",
17609
+ "sunfish",
17610
+ "swallow",
17611
+ "swan",
17612
+ "swift",
17613
+ "swordfish",
17614
+ "tahr",
17615
+ "takin",
17616
+ "tamarin",
17617
+ "tanager",
17618
+ "tapir",
17619
+ "tarantula",
17620
+ "tarpon",
17621
+ "tarsier",
17622
+ "teal",
17623
+ "tenrec",
17624
+ "terrapin",
17625
+ "tern",
17626
+ "tetra",
17627
+ "thrasher",
17628
+ "thrush",
17629
+ "tiger",
17630
+ "toad",
17631
+ "tortoise",
17632
+ "toucan",
17633
+ "treecreeper",
17634
+ "treefrog",
17635
+ "trout",
17636
+ "tuatara",
17637
+ "tuna",
17638
+ "turkey",
17639
+ "turtle",
17640
+ "urchin",
17641
+ "urial",
17642
+ "vicuna",
17643
+ "viper",
17644
+ "vole",
17645
+ "vulture",
17646
+ "wagtail",
17647
+ "wallaby",
17648
+ "walleye",
17649
+ "walrus",
17650
+ "warbler",
17651
+ "warthog",
17652
+ "waterbuck",
17653
+ "weasel",
17654
+ "wildebeest",
17655
+ "wolf",
17656
+ "wolverine",
17657
+ "wombat",
17658
+ "woodcock",
17659
+ "woodpecker",
17660
+ "wrasse",
17661
+ "wren",
17662
+ "yak",
17663
+ "zebra",
17664
+ "zebu",
17665
+ "zorilla"
17666
+ ];
17667
+ });
17668
+
17669
+ // src/orchestrator/worktree/slug-allocator.ts
17670
+ class SlugAllocator {
17671
+ activeSlugs;
17672
+ random;
17673
+ pool;
17674
+ pendingByRepo = new Map;
17675
+ chain = Promise.resolve();
17676
+ constructor(activeSlugs, options = {}) {
17677
+ this.activeSlugs = activeSlugs;
17678
+ this.random = options.random ?? Math.random;
17679
+ this.pool = options.pool ?? ANIMAL_NAMES;
17680
+ if (this.pool.length === 0) {
17681
+ throw new Error("SlugAllocator: animal pool cannot be empty");
17682
+ }
17683
+ }
17684
+ async allocate(repo) {
17685
+ const previous = this.chain;
17686
+ let release;
17687
+ this.chain = new Promise((resolve3) => {
17688
+ release = resolve3;
17689
+ });
17690
+ await previous;
17691
+ try {
17692
+ return this.pickLocked(repo);
17693
+ } finally {
17694
+ release();
17695
+ }
17696
+ }
17697
+ commit(repo, slug) {
17698
+ this.deletePending(repo, slug);
17699
+ }
17700
+ cancel(repo, slug) {
17701
+ this.deletePending(repo, slug);
17702
+ }
17703
+ pickLocked(repo) {
17704
+ const occupied = this.occupiedSlugs(repo);
17705
+ const candidates = this.pool.filter((n2) => !occupied.has(n2));
17706
+ if (candidates.length > 0) {
17707
+ const pick = candidates[Math.floor(this.random() * candidates.length)];
17708
+ this.addPending(repo, pick);
17709
+ return pick;
17710
+ }
17711
+ const base = this.pool[Math.floor(this.random() * this.pool.length)];
17712
+ for (let v2 = 2;; v2++) {
17713
+ const candidate = `${base}-v${v2}`;
17714
+ if (!occupied.has(candidate)) {
17715
+ this.addPending(repo, candidate);
17716
+ return candidate;
17717
+ }
17718
+ }
17719
+ }
17720
+ occupiedSlugs(repo) {
17721
+ const set = new Set(this.pendingByRepo.get(repo) ?? []);
17722
+ for (const slug of this.activeSlugs(repo)) {
17723
+ if (slug)
17724
+ set.add(slug);
17725
+ }
17726
+ for (const dir of listWorktreeDirNames(repo)) {
17727
+ set.add(dir);
17728
+ }
17729
+ return set;
17730
+ }
17731
+ addPending(repo, slug) {
17732
+ let pending = this.pendingByRepo.get(repo);
17733
+ if (!pending) {
17734
+ pending = new Set;
17735
+ this.pendingByRepo.set(repo, pending);
17736
+ }
17737
+ pending.add(slug);
17738
+ }
17739
+ deletePending(repo, slug) {
17740
+ const pending = this.pendingByRepo.get(repo);
17741
+ if (!pending)
17742
+ return;
17743
+ pending.delete(slug);
17744
+ if (pending.size === 0)
17745
+ this.pendingByRepo.delete(repo);
17746
+ }
17747
+ }
17748
+ var init_slug_allocator = __esm(() => {
17749
+ init_animal_names();
17750
+ init_paths();
17751
+ });
17752
+
17187
17753
  // src/orchestrator/core.ts
17188
17754
  var exports_core = {};
17189
17755
  __export(exports_core, {
@@ -17246,6 +17812,8 @@ class Orchestrator {
17246
17812
  requestIdCounter = 0;
17247
17813
  sessionPump;
17248
17814
  pendingWorktreeOpts = new Map;
17815
+ slugAllocator;
17816
+ ensureWorktreeLatches = new Map;
17249
17817
  tasksAcc;
17250
17818
  setTasks;
17251
17819
  unsubscribeStore;
@@ -17275,6 +17843,7 @@ class Orchestrator {
17275
17843
  this.store = deps.store;
17276
17844
  this.worktrees = deps.worktrees;
17277
17845
  this.metadataSuggester = deps.metadataSuggester ?? new MetadataSuggester;
17846
+ this.slugAllocator = new SlugAllocator((repo) => this.store.list().filter((t2) => t2.repo === repo && !t2.archived).map((t2) => worktreeSlug(t2)).filter((s2) => s2.length > 0));
17278
17847
  const [tasks, setTasks] = createSignal(this.store.list());
17279
17848
  this.tasksAcc = tasks;
17280
17849
  this.setTasks = (next) => setTasks(() => next);
@@ -17305,6 +17874,9 @@ class Orchestrator {
17305
17874
  modelForTab(task, tab, engine3) {
17306
17875
  return tab.model ?? task.model ?? engine3.capabilities.defaultModelId();
17307
17876
  }
17877
+ modelEffortForTab(task, tab) {
17878
+ return tab.modelEffort ?? task.modelEffort;
17879
+ }
17308
17880
  engineForTab(task, tab) {
17309
17881
  return this.engineForVendor(this.vendorForTab(task, tab));
17310
17882
  }
@@ -17469,26 +18041,49 @@ class Orchestrator {
17469
18041
  async ensureWorktree(task) {
17470
18042
  if (task.worktreePath)
17471
18043
  return task;
18044
+ const inflight = this.ensureWorktreeLatches.get(task.id);
18045
+ if (inflight) {
18046
+ await inflight;
18047
+ return this.requireTask(task.id);
18048
+ }
18049
+ const latch = this.doEnsureWorktree(task);
18050
+ this.ensureWorktreeLatches.set(task.id, latch);
18051
+ try {
18052
+ return await latch;
18053
+ } finally {
18054
+ this.ensureWorktreeLatches.delete(task.id);
18055
+ }
18056
+ }
18057
+ async doEnsureWorktree(task) {
17472
18058
  const opts = this.pendingWorktreeOpts.get(task.id);
17473
18059
  const branch = opts?.branch ?? `kobe/tmp-${task.id.slice(-8).toLowerCase()}`;
17474
18060
  const baseRef = opts?.baseRef;
18061
+ const slug = await this.slugAllocator.allocate(task.repo);
17475
18062
  let info;
17476
18063
  try {
17477
18064
  info = await this.worktrees.createForTask({
17478
18065
  repo: task.repo,
17479
- taskId: task.id,
18066
+ slug,
17480
18067
  branch,
17481
18068
  baseRef
17482
18069
  });
17483
18070
  } catch (err) {
18071
+ this.slugAllocator.cancel(task.repo, slug);
17484
18072
  const message = err instanceof Error ? err.message : String(err);
17485
18073
  throw new Error(summarizeWorktreeError(message, task.repo, baseRef ?? null), { cause: err });
17486
18074
  }
17487
- this.pendingWorktreeOpts.delete(task.id);
17488
- return await this.store.update(task.id, {
17489
- branch: info.branch,
17490
- worktreePath: info.path
17491
- });
18075
+ try {
18076
+ this.pendingWorktreeOpts.delete(task.id);
18077
+ const updated = await this.store.update(task.id, {
18078
+ branch: info.branch,
18079
+ worktreePath: info.path
18080
+ });
18081
+ this.slugAllocator.commit(task.repo, slug);
18082
+ return updated;
18083
+ } catch (err) {
18084
+ this.slugAllocator.cancel(task.repo, slug);
18085
+ throw err;
18086
+ }
17492
18087
  }
17493
18088
  async maybeRenameTempBranch(taskId, tabId, prompt) {
17494
18089
  if (!prompt || prompt.trim().length === 0)
@@ -17586,13 +18181,15 @@ class Orchestrator {
17586
18181
  }
17587
18182
  const engine3 = targetTab.sessionId ? await this.engineForTabRun(task, targetTab) : this.engineForTab(task, targetTab);
17588
18183
  const modelToUse = this.modelForTab(task, targetTab, engine3);
18184
+ const modelEffortToUse = this.modelEffortForTab(task, targetTab);
17589
18185
  let handle;
17590
18186
  if (targetTab.sessionId) {
17591
18187
  handle = await engine3.resume(targetTab.sessionId, promptToSend, {
17592
18188
  cwd: task.worktreePath,
17593
18189
  env: { KOBE_RESUME_CWD: task.worktreePath },
17594
18190
  permissionMode: task.permissionMode,
17595
- model: modelToUse
18191
+ model: modelToUse,
18192
+ modelEffort: modelEffortToUse
17596
18193
  });
17597
18194
  } else {
17598
18195
  let releaseLatch = () => {};
@@ -17603,7 +18200,8 @@ class Orchestrator {
17603
18200
  try {
17604
18201
  handle = await engine3.spawn(task.worktreePath, promptToSend, {
17605
18202
  permissionMode: task.permissionMode,
17606
- model: modelToUse
18203
+ model: modelToUse,
18204
+ modelEffort: modelEffortToUse
17607
18205
  });
17608
18206
  await this.updateTab(task.id, targetTab.id, { sessionId: handle.sessionId });
17609
18207
  if (task.title === PLACEHOLDER_TASK_TITLE && prompt && prompt.trim().length > 0) {
@@ -17718,13 +18316,13 @@ class Orchestrator {
17718
18316
  return;
17719
18317
  await this.store.update(task.id, { permissionMode: mode });
17720
18318
  }
17721
- async setModel(id, model, tabId) {
18319
+ async setModel(id, model, tabId, modelEffort) {
17722
18320
  const task = this.requireTask(id);
17723
18321
  const tab = this.resolveTab(task, tabId);
17724
18322
  const vendor = model ? capabilitiesForModelId(model).vendorId : this.vendorForTab(task, tab);
17725
- if (tab.model === model && this.vendorForTab(task, tab) === vendor)
18323
+ if (tab.model === model && tab.modelEffort === modelEffort && this.vendorForTab(task, tab) === vendor)
17726
18324
  return;
17727
- await this.updateTab(task.id, tab.id, { model, vendor });
18325
+ await this.updateTab(task.id, tab.id, { model, modelEffort, vendor });
17728
18326
  }
17729
18327
  async setTitle(id, title) {
17730
18328
  const task = this.requireTask(id);
@@ -18098,6 +18696,7 @@ var init_core = __esm(() => {
18098
18696
  init_metadata_suggester();
18099
18697
  init_pr();
18100
18698
  init_session_pump();
18699
+ init_slug_allocator();
18101
18700
  IllegalTransitionError = class IllegalTransitionError extends Error {
18102
18701
  from;
18103
18702
  to;
@@ -18293,8 +18892,8 @@ class RemoteOrchestrator {
18293
18892
  async setPermissionMode(taskId, mode) {
18294
18893
  await this.client.request("task.permissionMode", { taskId, mode });
18295
18894
  }
18296
- async setModel(taskId, model, tabId) {
18297
- await this.client.request("task.model", { taskId, model, tabId });
18895
+ async setModel(taskId, model, tabId, modelEffort) {
18896
+ await this.client.request("task.model", { taskId, model, tabId, modelEffort });
18298
18897
  }
18299
18898
  async createTab(taskId, opts = {}) {
18300
18899
  const res = await this.client.request("chat.tab.create", { taskId, title: opts.title });
@@ -18554,7 +19153,7 @@ class GitWorktreeManager {
18554
19153
  return info;
18555
19154
  }
18556
19155
  async createForTask(args) {
18557
- const target = worktreePathFor(args.repo, args.taskId);
19156
+ const target = worktreePathFor(args.repo, args.slug);
18558
19157
  return this.create(args.repo, args.branch, target, args.baseRef);
18559
19158
  }
18560
19159
  async remove(worktreePath, opts) {
@@ -20303,6 +20902,17 @@ var init_notifications = __esm(() => {
20303
20902
  ctx3 = createContext();
20304
20903
  });
20305
20904
 
20905
+ // src/tui/component/center-tab-strip-parts.ts
20906
+ function chatTabMarkerKind(input) {
20907
+ if (input.runState === "running")
20908
+ return "running";
20909
+ if (input.runState === "awaiting_input")
20910
+ return "awaiting_input";
20911
+ if (input.isPrimary || input.unreadKind === undefined)
20912
+ return null;
20913
+ return input.unreadKind === "needs_input" ? "unread_needs_input" : "unread_done";
20914
+ }
20915
+
20306
20916
  // src/tui/component/center-tab-strip.tsx
20307
20917
  import { basename as basename3 } from "path";
20308
20918
  import { TextAttributes as TextAttributes8 } from "@opentui/core";
@@ -20359,29 +20969,28 @@ function CenterTabStrip(props) {
20359
20969
  return;
20360
20970
  return props.chatRunState().get(chatRunStateKey(taskId, tab.id));
20361
20971
  };
20362
- const dotGlyph = () => {
20363
- const s2 = runState();
20364
- return s2 === "running" || s2 === "awaiting_input" ? "\u25CF" : "";
20365
- };
20366
- const dotColor = () => {
20367
- const s2 = runState();
20368
- if (s2 === "awaiting_input")
20369
- return theme.warning;
20370
- if (s2 === "running")
20371
- return theme.success;
20372
- return theme.textMuted;
20373
- };
20374
20972
  const unreadKind = () => {
20375
20973
  const taskId = props.activeTaskId();
20376
20974
  if (!taskId)
20377
20975
  return;
20378
20976
  return props.unread().get(notificationKey(taskId, tab.id));
20379
20977
  };
20380
- const showUnread = () => !isPrimary() && unreadKind() !== undefined;
20381
- const unreadColor = () => unreadKind() === "needs_input" ? theme.warning : theme.success;
20978
+ const markerKind = () => chatTabMarkerKind({
20979
+ runState: runState(),
20980
+ unreadKind: unreadKind(),
20981
+ isPrimary: isPrimary()
20982
+ });
20983
+ const markerColor = () => {
20984
+ const kind = markerKind();
20985
+ if (kind === "awaiting_input" || kind === "unread_needs_input")
20986
+ return theme.warning;
20987
+ if (kind === "running" || kind === "unread_done")
20988
+ return theme.success;
20989
+ return theme.textMuted;
20990
+ };
20382
20991
  return (() => {
20383
- var _el$5 = createElement("box"), _el$7 = createElement("text");
20384
- insertNode(_el$5, _el$7);
20992
+ var _el$5 = createElement("box"), _el$8 = createElement("text");
20993
+ insertNode(_el$5, _el$8);
20385
20994
  setProp(_el$5, "flexDirection", "row");
20386
20995
  setProp(_el$5, "gap", 1);
20387
20996
  setProp(_el$5, "paddingLeft", 1);
@@ -20393,35 +21002,23 @@ function CenterTabStrip(props) {
20393
21002
  });
20394
21003
  insert(_el$5, createComponent2(Show, {
20395
21004
  get when() {
20396
- return dotGlyph().length > 0;
21005
+ return markerKind() !== null;
20397
21006
  },
20398
21007
  get children() {
20399
21008
  var _el$6 = createElement("text");
21009
+ insertNode(_el$6, createTextNode(`\u25CF`));
20400
21010
  setProp(_el$6, "wrapMode", "none");
20401
- insert(_el$6, dotGlyph);
20402
- effect((_$p) => setProp(_el$6, "fg", dotColor(), _$p));
21011
+ effect((_$p) => setProp(_el$6, "fg", markerColor(), _$p));
20403
21012
  return _el$6;
20404
21013
  }
20405
- }), _el$7);
20406
- setProp(_el$7, "wrapMode", "none");
20407
- insert(_el$7, () => chatTabLabel(tab));
20408
- insert(_el$5, createComponent2(Show, {
20409
- get when() {
20410
- return showUnread();
20411
- },
20412
- get children() {
20413
- var _el$8 = createElement("text");
20414
- insertNode(_el$8, createTextNode(`\u25CF`));
20415
- setProp(_el$8, "wrapMode", "none");
20416
- effect((_$p) => setProp(_el$8, "fg", unreadColor(), _$p));
20417
- return _el$8;
20418
- }
20419
- }), null);
21014
+ }), _el$8);
21015
+ setProp(_el$8, "wrapMode", "none");
21016
+ insert(_el$8, () => chatTabLabel(tab));
20420
21017
  effect((_p$) => {
20421
21018
  var _v$4 = isPrimary() ? theme.primary : theme.backgroundElement, _v$5 = isPrimary() ? theme.selectedListItemText : isVisibleButOther() ? theme.text : theme.textMuted, _v$6 = isPrimary() ? TextAttributes8.BOLD : undefined;
20422
21019
  _v$4 !== _p$.e && (_p$.e = setProp(_el$5, "backgroundColor", _v$4, _p$.e));
20423
- _v$5 !== _p$.t && (_p$.t = setProp(_el$7, "fg", _v$5, _p$.t));
20424
- _v$6 !== _p$.a && (_p$.a = setProp(_el$7, "attributes", _v$6, _p$.a));
21020
+ _v$5 !== _p$.t && (_p$.t = setProp(_el$8, "fg", _v$5, _p$.t));
21021
+ _v$6 !== _p$.a && (_p$.a = setProp(_el$8, "attributes", _v$6, _p$.a));
20425
21022
  return _p$;
20426
21023
  }, {
20427
21024
  e: undefined,
@@ -20441,24 +21038,24 @@ function CenterTabStrip(props) {
20441
21038
  children: (file) => {
20442
21039
  const isActive = () => !props.isChatActive();
20443
21040
  return (() => {
20444
- var _el$0 = createElement("box"), _el$1 = createElement("text"), _el$10 = createElement("text");
20445
- insertNode(_el$0, _el$1);
20446
- insertNode(_el$0, _el$10);
20447
- setProp(_el$0, "flexDirection", "row");
20448
- setProp(_el$0, "gap", 1);
20449
- setProp(_el$0, "paddingLeft", 1);
20450
- setProp(_el$0, "paddingRight", 1);
20451
- setProp(_el$0, "onMouseUp", () => props.onSelectFile(file()));
20452
- setProp(_el$1, "wrapMode", "none");
20453
- insert(_el$1, () => basename3(file()));
20454
- insertNode(_el$10, createTextNode(`x`));
20455
- setProp(_el$10, "onMouseUp", () => queueMicrotask(() => props.onCloseFile(file())));
21041
+ var _el$9 = createElement("box"), _el$0 = createElement("text"), _el$1 = createElement("text");
21042
+ insertNode(_el$9, _el$0);
21043
+ insertNode(_el$9, _el$1);
21044
+ setProp(_el$9, "flexDirection", "row");
21045
+ setProp(_el$9, "gap", 1);
21046
+ setProp(_el$9, "paddingLeft", 1);
21047
+ setProp(_el$9, "paddingRight", 1);
21048
+ setProp(_el$9, "onMouseUp", () => props.onSelectFile(file()));
21049
+ setProp(_el$0, "wrapMode", "none");
21050
+ insert(_el$0, () => basename3(file()));
21051
+ insertNode(_el$1, createTextNode(`x`));
21052
+ setProp(_el$1, "onMouseUp", () => queueMicrotask(() => props.onCloseFile(file())));
20456
21053
  effect((_p$) => {
20457
21054
  var _v$7 = isActive() ? theme.primary : theme.backgroundElement, _v$8 = isActive() ? theme.selectedListItemText : theme.text, _v$9 = isActive() ? TextAttributes8.BOLD : undefined, _v$0 = isActive() ? theme.selectedListItemText : theme.textMuted;
20458
- _v$7 !== _p$.e && (_p$.e = setProp(_el$0, "backgroundColor", _v$7, _p$.e));
20459
- _v$8 !== _p$.t && (_p$.t = setProp(_el$1, "fg", _v$8, _p$.t));
20460
- _v$9 !== _p$.a && (_p$.a = setProp(_el$1, "attributes", _v$9, _p$.a));
20461
- _v$0 !== _p$.o && (_p$.o = setProp(_el$10, "fg", _v$0, _p$.o));
21055
+ _v$7 !== _p$.e && (_p$.e = setProp(_el$9, "backgroundColor", _v$7, _p$.e));
21056
+ _v$8 !== _p$.t && (_p$.t = setProp(_el$0, "fg", _v$8, _p$.t));
21057
+ _v$9 !== _p$.a && (_p$.a = setProp(_el$0, "attributes", _v$9, _p$.a));
21058
+ _v$0 !== _p$.o && (_p$.o = setProp(_el$1, "fg", _v$0, _p$.o));
20462
21059
  return _p$;
20463
21060
  }, {
20464
21061
  e: undefined,
@@ -20466,7 +21063,7 @@ function CenterTabStrip(props) {
20466
21063
  a: undefined,
20467
21064
  o: undefined
20468
21065
  });
20469
- return _el$0;
21066
+ return _el$9;
20470
21067
  })();
20471
21068
  }
20472
21069
  }), null);
@@ -21893,6 +22490,19 @@ var init_open_worktree_button = __esm(() => {
21893
22490
  init_worktree_opener();
21894
22491
  });
21895
22492
 
22493
+ // src/tui/component/top-bar-helpers.ts
22494
+ function formatSessionIdLabel(sessionId) {
22495
+ if (!sessionId)
22496
+ return null;
22497
+ return `sid ${sessionId}`;
22498
+ }
22499
+ function activeTaskSessionId(task, activeChatTabId) {
22500
+ if (!task)
22501
+ return null;
22502
+ const tabId = activeChatTabId ?? task.activeTabId;
22503
+ return task.tabs.find((tab) => tab.id === tabId)?.sessionId ?? null;
22504
+ }
22505
+
21896
22506
  // src/tui/panes/chat/markdown-parser.ts
21897
22507
  function splitTableRow(line) {
21898
22508
  const trimmed = line.trim().replace(/^\||\|$/g, "");
@@ -22846,6 +23456,7 @@ function TopBar(props) {
22846
23456
  const remoteOrch = props.orchestrator instanceof RemoteOrchestrator ? props.orchestrator : null;
22847
23457
  const rcBridge = props.orchestrator.rcBridgeSignal();
22848
23458
  const isBridgeOn = () => rcBridge().state === "running" || rcBridge().state === "starting";
23459
+ const sessionIdLabel = createMemo(() => formatSessionIdLabel(activeTaskSessionId(props.activeTask(), props.activeChatTabId?.())));
22849
23460
  async function confirmUpdate() {
22850
23461
  const info = props.updateInfo();
22851
23462
  if (!info?.hasUpdate)
@@ -22880,10 +23491,10 @@ function TopBar(props) {
22880
23491
  process.exit(code);
22881
23492
  }
22882
23493
  return (() => {
22883
- var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$6 = createTextNode(`v`), _el$13 = createElement("box"), _el$15 = createElement("box");
23494
+ var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$6 = createTextNode(`v`), _el$13 = createElement("box"), _el$16 = createElement("box");
22884
23495
  insertNode(_el$, _el$2);
22885
23496
  insertNode(_el$, _el$13);
22886
- insertNode(_el$, _el$15);
23497
+ insertNode(_el$, _el$16);
22887
23498
  setProp(_el$, "flexDirection", "row");
22888
23499
  setProp(_el$, "paddingLeft", 2);
22889
23500
  setProp(_el$, "paddingRight", 2);
@@ -22975,19 +23586,19 @@ function TopBar(props) {
22975
23586
  },
22976
23587
  get fallback() {
22977
23588
  return (() => {
22978
- var _el$16 = createElement("text");
22979
- insertNode(_el$16, createTextNode(`daemon disconnected`));
22980
- setProp(_el$16, "wrapMode", "none");
23589
+ var _el$17 = createElement("text");
23590
+ insertNode(_el$17, createTextNode(`daemon disconnected`));
23591
+ setProp(_el$17, "wrapMode", "none");
22981
23592
  effect((_p$) => {
22982
23593
  var _v$0 = theme.error, _v$1 = TextAttributes18.BOLD;
22983
- _v$0 !== _p$.e && (_p$.e = setProp(_el$16, "fg", _v$0, _p$.e));
22984
- _v$1 !== _p$.t && (_p$.t = setProp(_el$16, "attributes", _v$1, _p$.t));
23594
+ _v$0 !== _p$.e && (_p$.e = setProp(_el$17, "fg", _v$0, _p$.e));
23595
+ _v$1 !== _p$.t && (_p$.t = setProp(_el$17, "attributes", _v$1, _p$.t));
22985
23596
  return _p$;
22986
23597
  }, {
22987
23598
  e: undefined,
22988
23599
  t: undefined
22989
23600
  });
22990
- return _el$16;
23601
+ return _el$17;
22991
23602
  })();
22992
23603
  },
22993
23604
  get children() {
@@ -22996,13 +23607,29 @@ function TopBar(props) {
22996
23607
  return props.activeTask() !== undefined;
22997
23608
  },
22998
23609
  get children() {
22999
- var _el$14 = createElement("text");
23000
- setProp(_el$14, "wrapMode", "none");
23001
- insert(_el$14, () => props.activeTask()?.branch);
23610
+ var _el$14 = createElement("box"), _el$15 = createElement("text");
23611
+ insertNode(_el$14, _el$15);
23612
+ setProp(_el$14, "flexDirection", "row");
23613
+ setProp(_el$14, "gap", 2);
23614
+ setProp(_el$14, "justifyContent", "center");
23615
+ setProp(_el$15, "wrapMode", "none");
23616
+ insert(_el$15, () => props.activeTask()?.branch);
23617
+ insert(_el$14, createComponent2(Show, {
23618
+ get when() {
23619
+ return sessionIdLabel();
23620
+ },
23621
+ children: (label) => (() => {
23622
+ var _el$19 = createElement("text");
23623
+ setProp(_el$19, "wrapMode", "none");
23624
+ insert(_el$19, label);
23625
+ effect((_$p) => setProp(_el$19, "fg", theme.textMuted, _$p));
23626
+ return _el$19;
23627
+ })()
23628
+ }), null);
23002
23629
  effect((_p$) => {
23003
23630
  var _v$5 = theme.text, _v$6 = TextAttributes18.BOLD;
23004
- _v$5 !== _p$.e && (_p$.e = setProp(_el$14, "fg", _v$5, _p$.e));
23005
- _v$6 !== _p$.t && (_p$.t = setProp(_el$14, "attributes", _v$6, _p$.t));
23631
+ _v$5 !== _p$.e && (_p$.e = setProp(_el$15, "fg", _v$5, _p$.e));
23632
+ _v$6 !== _p$.t && (_p$.t = setProp(_el$15, "attributes", _v$6, _p$.t));
23006
23633
  return _p$;
23007
23634
  }, {
23008
23635
  e: undefined,
@@ -23013,13 +23640,13 @@ function TopBar(props) {
23013
23640
  });
23014
23641
  }
23015
23642
  }));
23016
- setProp(_el$15, "flexDirection", "row");
23017
- setProp(_el$15, "flexGrow", 1);
23018
- setProp(_el$15, "flexShrink", 1);
23019
- setProp(_el$15, "flexBasis", 0);
23020
- setProp(_el$15, "gap", 2);
23021
- setProp(_el$15, "justifyContent", "flex-end");
23022
- insert(_el$15, createComponent2(OpenWorktreeButton, {
23643
+ setProp(_el$16, "flexDirection", "row");
23644
+ setProp(_el$16, "flexGrow", 1);
23645
+ setProp(_el$16, "flexShrink", 1);
23646
+ setProp(_el$16, "flexBasis", 0);
23647
+ setProp(_el$16, "gap", 2);
23648
+ setProp(_el$16, "justifyContent", "flex-end");
23649
+ insert(_el$16, createComponent2(OpenWorktreeButton, {
23023
23650
  get activeTask() {
23024
23651
  return props.activeTask;
23025
23652
  },
@@ -23027,7 +23654,7 @@ function TopBar(props) {
23027
23654
  return props.worktreeOpener;
23028
23655
  }
23029
23656
  }), null);
23030
- insert(_el$15, createComponent2(CreatePRButton, {
23657
+ insert(_el$16, createComponent2(CreatePRButton, {
23031
23658
  get orchestrator() {
23032
23659
  return props.orchestrator;
23033
23660
  },
@@ -23451,7 +24078,12 @@ class SessionRegistry {
23451
24078
  }
23452
24079
  this.handles.set(handle.sessionId, handle);
23453
24080
  }
23454
- unregister(sessionId) {
24081
+ unregister(sessionId, proc) {
24082
+ if (proc) {
24083
+ const existing = this.handles.get(sessionId);
24084
+ if (existing && existing.proc !== proc)
24085
+ return;
24086
+ }
23455
24087
  this.handles.delete(sessionId);
23456
24088
  }
23457
24089
  get(sessionId) {
@@ -23611,6 +24243,9 @@ function buildArgs(opts) {
23611
24243
  if (opts.model) {
23612
24244
  args2.push("--model", opts.model);
23613
24245
  }
24246
+ if (opts.modelEffort) {
24247
+ args2.push("--effort", opts.modelEffort);
24248
+ }
23614
24249
  if (opts.permissionMode) {
23615
24250
  args2.push("--permission-mode", opts.permissionMode);
23616
24251
  }
@@ -23847,6 +24482,7 @@ class ClaudeCodeLocal {
23847
24482
  cwd: args2.cwd,
23848
24483
  prompt: args2.prompt,
23849
24484
  model: args2.opts?.model,
24485
+ modelEffort: args2.opts?.modelEffort,
23850
24486
  permissionMode: cliPermissionMode,
23851
24487
  env: args2.opts?.env,
23852
24488
  resumeSessionId: args2.resumeSessionId
@@ -23922,7 +24558,7 @@ class ClaudeCodeLocal {
23922
24558
  if (session) {
23923
24559
  session.closed = true;
23924
24560
  this.notify(session);
23925
- this.registry.unregister(session.sessionId);
24561
+ this.registry.unregister(session.sessionId, spawned.proc);
23926
24562
  }
23927
24563
  if (!bound) {
23928
24564
  rejectHandle(new Error("claude exited without emitting a session id"));
@@ -23998,6 +24634,36 @@ function isObject4(v2) {
23998
24634
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
23999
24635
  }
24000
24636
 
24637
+ // src/engine/codex-local/synthetic.ts
24638
+ function isSyntheticCodexUserRow(blocks) {
24639
+ if (blocks.length === 0)
24640
+ return false;
24641
+ for (const b2 of blocks) {
24642
+ if (b2.type !== "text")
24643
+ return false;
24644
+ const t2 = (b2.text ?? "").trim();
24645
+ if (!isEnvironmentContextEnvelope(t2) && !isInstructionsEnvelope(t2))
24646
+ return false;
24647
+ }
24648
+ return true;
24649
+ }
24650
+ function visibleCodexUserText(content) {
24651
+ const blocks = normalizeCodexContent(content);
24652
+ if (isSyntheticCodexUserRow(blocks))
24653
+ return null;
24654
+ const text = blocks.filter((b2) => b2.type === "text").map((b2) => b2.text).join(" ").trim();
24655
+ return text.length > 0 ? text : null;
24656
+ }
24657
+ function isEnvironmentContextEnvelope(text) {
24658
+ return text.startsWith("<environment_context>") && text.endsWith("</environment_context>");
24659
+ }
24660
+ function isInstructionsEnvelope(text) {
24661
+ return text.startsWith("# AGENTS.md instructions for ") && text.includes(`
24662
+ <INSTRUCTIONS>
24663
+ `) && text.endsWith("</INSTRUCTIONS>");
24664
+ }
24665
+ var init_synthetic = () => {};
24666
+
24001
24667
  // src/engine/codex-local/history.ts
24002
24668
  import { readFile as readFile5, readdir as readdir3, unlink as unlink3 } from "fs/promises";
24003
24669
  import { homedir as homedir13 } from "os";
@@ -24092,7 +24758,7 @@ function parseJsonl2(raw, sessionId) {
24092
24758
  if (role !== "user" && role !== "assistant" && role !== "system")
24093
24759
  continue;
24094
24760
  const blocks = normalizeCodexContent(payload.content);
24095
- if (role === "user" && isEnvironmentContextEnvelope(blocks))
24761
+ if (role === "user" && isSyntheticCodexUserRow(blocks))
24096
24762
  continue;
24097
24763
  const ts = typeof parsed.timestamp === "string" ? parsed.timestamp : new Date().toISOString();
24098
24764
  out.push({ role, blocks, timestamp: ts, sessionId });
@@ -24124,7 +24790,7 @@ function deriveCodexUsageMetrics(raw) {
24124
24790
  const payload = isObject5(parsed.payload) ? parsed.payload : undefined;
24125
24791
  if (payload?.type === "message" && payload.role === "user" && timestampMs !== null) {
24126
24792
  const blocks = normalizeCodexContent(payload.content);
24127
- if (!isEnvironmentContextEnvelope(blocks))
24793
+ if (!isSyntheticCodexUserRow(blocks))
24128
24794
  lastUserTimestampMs = timestampMs;
24129
24795
  }
24130
24796
  continue;
@@ -24200,23 +24866,12 @@ function mergedDurationMs(intervals) {
24200
24866
  function numberOr(v2, fallback) {
24201
24867
  return typeof v2 === "number" && Number.isFinite(v2) ? v2 : fallback;
24202
24868
  }
24203
- function isEnvironmentContextEnvelope(blocks) {
24204
- if (blocks.length === 0)
24205
- return false;
24206
- for (const b2 of blocks) {
24207
- if (b2.type !== "text")
24208
- return false;
24209
- const t2 = (b2.text ?? "").trim();
24210
- if (!t2.startsWith("<environment_context>") || !t2.endsWith("</environment_context>"))
24211
- return false;
24212
- }
24213
- return true;
24214
- }
24215
24869
  function isObject5(v2) {
24216
24870
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
24217
24871
  }
24218
24872
  var defaultDeps6;
24219
24873
  var init_history2 = __esm(() => {
24874
+ init_synthetic();
24220
24875
  defaultDeps6 = {
24221
24876
  sessionsDir() {
24222
24877
  return path11.join(homedir13(), ".codex", "sessions");
@@ -24271,47 +24926,46 @@ async function tryReadMeta(file) {
24271
24926
  return null;
24272
24927
  try {
24273
24928
  let buf = "";
24274
- let lineCount = 0;
24275
24929
  const processLine = (line) => {
24276
- lineCount++;
24277
24930
  const parsed = safeParse(line);
24278
- if (parsed) {
24279
- if (parsed.type === "session_meta") {
24280
- const payload = parsed.payload;
24281
- if (isObject6(payload)) {
24282
- if (typeof payload.id === "string")
24283
- sessionId = payload.id;
24284
- if (typeof payload.cwd === "string")
24285
- cwd = payload.cwd;
24286
- }
24287
- } else if (parsed.type === "response_item" && isObject6(parsed.payload)) {
24288
- const p2 = parsed.payload;
24289
- if (p2.type === "message") {
24290
- messageCount++;
24291
- if (!firstUser && p2.role === "user") {
24292
- firstUser = extractText(p2.content)?.slice(0, PREVIEW_CHAR_CAP) ?? null;
24293
- }
24931
+ if (!parsed)
24932
+ return;
24933
+ if (parsed.type === "session_meta") {
24934
+ const payload = parsed.payload;
24935
+ if (isObject6(payload)) {
24936
+ if (typeof payload.id === "string")
24937
+ sessionId = payload.id;
24938
+ if (typeof payload.cwd === "string")
24939
+ cwd = payload.cwd;
24940
+ }
24941
+ return;
24942
+ }
24943
+ if (parsed.type === "response_item" && isObject6(parsed.payload)) {
24944
+ const p2 = parsed.payload;
24945
+ if (p2.type === "message") {
24946
+ messageCount++;
24947
+ if (!firstUser && p2.role === "user") {
24948
+ const text = visibleCodexUserText(p2.content);
24949
+ if (text)
24950
+ firstUser = text.slice(0, PREVIEW_CHAR_CAP);
24294
24951
  }
24295
24952
  }
24296
24953
  }
24297
- return lineCount >= PREVIEW_HEAD_LINES;
24298
24954
  };
24299
24955
  const reader = handle.createReadStream({ encoding: "utf8" });
24300
- outer:
24301
- for await (const chunk of reader) {
24302
- buf += chunk;
24303
- let nl = buf.indexOf(`
24956
+ for await (const chunk of reader) {
24957
+ buf += chunk;
24958
+ let nl = buf.indexOf(`
24304
24959
  `);
24305
- while (nl !== -1) {
24306
- const line = buf.slice(0, nl);
24307
- buf = buf.slice(nl + 1);
24308
- nl = buf.indexOf(`
24960
+ while (nl !== -1) {
24961
+ const line = buf.slice(0, nl);
24962
+ buf = buf.slice(nl + 1);
24963
+ nl = buf.indexOf(`
24309
24964
  `);
24310
- if (processLine(line))
24311
- break outer;
24312
- }
24965
+ processLine(line);
24313
24966
  }
24314
- if (lineCount < PREVIEW_HEAD_LINES && buf.trim())
24967
+ }
24968
+ if (buf.trim())
24315
24969
  processLine(buf);
24316
24970
  } finally {
24317
24971
  await handle.close().catch(() => {});
@@ -24337,29 +24991,13 @@ function safeParse(line) {
24337
24991
  return null;
24338
24992
  }
24339
24993
  }
24340
- function extractText(content) {
24341
- if (typeof content === "string")
24342
- return content;
24343
- if (!Array.isArray(content))
24344
- return null;
24345
- for (const item of content) {
24346
- if (typeof item === "string" && item.length > 0)
24347
- return item;
24348
- if (isObject6(item)) {
24349
- const t2 = item.type;
24350
- if ((t2 === "input_text" || t2 === "output_text" || t2 === "text") && typeof item.text === "string") {
24351
- return item.text;
24352
- }
24353
- }
24354
- }
24355
- return null;
24356
- }
24357
24994
  function isObject6(v2) {
24358
24995
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
24359
24996
  }
24360
- var PREVIEW_HEAD_LINES = 40, PREVIEW_CHAR_CAP = 200;
24997
+ var PREVIEW_CHAR_CAP = 200;
24361
24998
  var init_sessions2 = __esm(() => {
24362
24999
  init_history2();
25000
+ init_synthetic();
24363
25001
  });
24364
25002
 
24365
25003
  // src/engine/codex-local/spawn.ts
@@ -24391,6 +25029,9 @@ function buildArgs2(opts) {
24391
25029
  if (opts.model) {
24392
25030
  args2.push("-m", opts.model);
24393
25031
  }
25032
+ if (opts.modelEffort) {
25033
+ args2.push("-c", `model_reasoning_effort="${opts.modelEffort}"`);
25034
+ }
24394
25035
  if (!isResume) {
24395
25036
  args2.push("-C", opts.cwd);
24396
25037
  if (opts.permissionMode === "plan")
@@ -24428,8 +25069,8 @@ async function* parseStreamJson2(lines, opts = {}) {
24428
25069
  const type = typeof msg.type === "string" ? msg.type : undefined;
24429
25070
  if (!type)
24430
25071
  continue;
24431
- if (type === "thread.started") {
24432
- const sid = typeof msg.thread_id === "string" ? msg.thread_id : undefined;
25072
+ if (type === "session_meta" || type === "thread.started") {
25073
+ const sid = codexSessionId(msg);
24433
25074
  if (sid && !sessionIdEmitted) {
24434
25075
  sessionIdEmitted = true;
24435
25076
  opts.onSessionId?.(sid);
@@ -24515,6 +25156,15 @@ async function* readLines2(stream) {
24515
25156
  function isObject7(v2) {
24516
25157
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
24517
25158
  }
25159
+ function codexSessionId(msg) {
25160
+ if (msg.type === "session_meta") {
25161
+ const payload = isObject7(msg.payload) ? msg.payload : undefined;
25162
+ const id2 = payload?.id;
25163
+ return typeof id2 === "string" && id2.length > 0 ? id2 : undefined;
25164
+ }
25165
+ const id = msg.thread_id;
25166
+ return typeof id === "string" && id.length > 0 ? id : undefined;
25167
+ }
24518
25168
  function numberOr2(v2, fallback) {
24519
25169
  return typeof v2 === "number" && Number.isFinite(v2) ? v2 : fallback;
24520
25170
  }
@@ -24603,6 +25253,7 @@ class CodexLocal {
24603
25253
  cwd: args2.cwd,
24604
25254
  prompt: args2.prompt,
24605
25255
  model: args2.opts?.model,
25256
+ modelEffort: args2.opts?.modelEffort,
24606
25257
  permissionMode: args2.opts?.permissionMode,
24607
25258
  env: args2.opts?.env,
24608
25259
  resumeSessionId: args2.resumeSessionId
@@ -24616,9 +25267,18 @@ class CodexLocal {
24616
25267
  const queue = [];
24617
25268
  let session;
24618
25269
  let bound = false;
25270
+ let stderrTail = "";
24619
25271
  const bind = (sessionId) => {
24620
- if (bound)
25272
+ if (bound) {
25273
+ if (session && session.sessionId !== sessionId) {
25274
+ queue.push({
25275
+ type: "error",
25276
+ message: `codex resumed to a different session id (got ${sessionId}, expected ${session.sessionId})`
25277
+ });
25278
+ this.notify(session);
25279
+ }
24621
25280
  return;
25281
+ }
24622
25282
  bound = true;
24623
25283
  session = {
24624
25284
  sessionId,
@@ -24650,6 +25310,25 @@ class CodexLocal {
24650
25310
  throw err;
24651
25311
  }
24652
25312
  }
25313
+ captureStderrTail(spawned.stderr, (chunk) => {
25314
+ stderrTail = (stderrTail + chunk).slice(-STDERR_TAIL_CAP);
25315
+ });
25316
+ const exitInfo = {
25317
+ code: null,
25318
+ signal: null,
25319
+ seen: false
25320
+ };
25321
+ const exitObserved = new Promise((resolve4) => {
25322
+ spawned.proc.once("exit", (code, signal) => {
25323
+ exitInfo.code = code;
25324
+ exitInfo.signal = signal;
25325
+ exitInfo.seen = true;
25326
+ if (!bound) {
25327
+ rejectHandle(new Error(formatExitMsg("codex exited before session id was captured", code, signal, stderrTail)));
25328
+ }
25329
+ resolve4();
25330
+ });
25331
+ });
24653
25332
  (async () => {
24654
25333
  const events = parseStreamJson2(readLines2(spawned.stdout), {
24655
25334
  onSessionId: (sid) => bind(sid)
@@ -24660,6 +25339,9 @@ class CodexLocal {
24660
25339
  queue.push(enriched);
24661
25340
  if (session)
24662
25341
  this.notify(session);
25342
+ if ((enriched.type === "done" || enriched.type === "error") && session) {
25343
+ this.registry.unregister(session.sessionId, spawned.proc);
25344
+ }
24663
25345
  }
24664
25346
  } catch (err) {
24665
25347
  const ev = {
@@ -24670,27 +25352,32 @@ class CodexLocal {
24670
25352
  if (session)
24671
25353
  this.notify(session);
24672
25354
  } finally {
25355
+ await Promise.race([exitObserved, new Promise((r2) => setTimeout(r2, 500))]);
24673
25356
  if (session) {
25357
+ const code = exitInfo.code;
25358
+ const lastEv = queue[queue.length - 1];
25359
+ if (exitInfo.seen && typeof code === "number" && code !== 0 && lastEv?.type !== "error") {
25360
+ queue.push({
25361
+ type: "error",
25362
+ message: formatExitMsg("codex exited", code, exitInfo.signal, stderrTail)
25363
+ });
25364
+ }
24674
25365
  session.closed = true;
24675
25366
  this.notify(session);
24676
- this.registry.unregister(session.sessionId);
24677
- this.running.delete(session.sessionId);
25367
+ this.registry.unregister(session.sessionId, spawned.proc);
25368
+ if (this.running.get(session.sessionId) === session) {
25369
+ this.running.delete(session.sessionId);
25370
+ }
24678
25371
  }
24679
25372
  if (!bound) {
24680
25373
  rejectHandle(new Error("codex exited without emitting a session id"));
24681
25374
  }
24682
25375
  }
24683
25376
  })();
24684
- drainStream2(spawned.stderr);
24685
25377
  spawned.proc.once("error", (err) => {
24686
25378
  if (!bound)
24687
25379
  rejectHandle(err);
24688
25380
  });
24689
- spawned.proc.once("exit", () => {
24690
- if (!bound) {
24691
- rejectHandle(new Error("codex exited before session id was captured"));
24692
- }
24693
- });
24694
25381
  return handlePromise;
24695
25382
  }
24696
25383
  notify(session) {
@@ -24700,22 +25387,37 @@ class CodexLocal {
24700
25387
  w2();
24701
25388
  }
24702
25389
  }
24703
- function drainStream2(stream) {
25390
+ function captureStderrTail(stream, onChunk) {
24704
25391
  const s2 = stream;
24705
- s2.on("data", () => {});
25392
+ s2.on("data", (chunk) => {
25393
+ onChunk(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
25394
+ });
24706
25395
  s2.on("error", () => {});
24707
25396
  }
25397
+ function formatExitMsg(prefix, code, signal, stderrTail) {
25398
+ const parts = [prefix];
25399
+ if (typeof code === "number")
25400
+ parts.push(`(code=${code}${signal ? `, signal=${signal}` : ""})`);
25401
+ else if (signal)
25402
+ parts.push(`(signal=${signal})`);
25403
+ const detail = stderrTail.trim().split(/\r?\n/).filter(Boolean).slice(-3).join(" | ");
25404
+ if (detail)
25405
+ parts.push(`: ${detail}`);
25406
+ return parts.join(" ").replace(/ : /, ": ");
25407
+ }
24708
25408
  function enrichUsageEvent2(ev, startedAtIso) {
24709
25409
  if (ev.type !== "usage")
24710
25410
  return ev;
24711
25411
  return { type: "usage", ...withTotalSpeedForTurn(ev, startedAtIso, new Date().toISOString()) };
24712
25412
  }
25413
+ var STDERR_TAIL_CAP;
24713
25414
  var init_codex_local = __esm(() => {
24714
25415
  init_binary2();
24715
25416
  init_capabilities2();
24716
25417
  init_history2();
24717
25418
  init_sessions2();
24718
25419
  init_spawn2();
25420
+ STDERR_TAIL_CAP = 4 * 1024;
24719
25421
  });
24720
25422
 
24721
25423
  // test/behavior/fake-engine.ts
@@ -26675,6 +27377,11 @@ var init_keybindings2 = __esm(() => {
26675
27377
  ];
26676
27378
  });
26677
27379
 
27380
+ // src/tui/panes/chat/composer/keys.ts
27381
+ function isPermissionModeCycleKey(key) {
27382
+ return key.name === "tab" && key.shift === true || key.name === "backtab";
27383
+ }
27384
+
26678
27385
  // src/tui/panes/chat/composer/mention.ts
26679
27386
  async function getWorktreeFiles(worktreePath) {
26680
27387
  const cached3 = fileListCache.get(worktreePath);
@@ -26758,15 +27465,17 @@ var init_mention = __esm(() => {
26758
27465
  fileListCache = new Map;
26759
27466
  });
26760
27467
 
26761
- // src/tui/panes/chat/Composer.tsx
26762
- import { TextAttributes as TextAttributes22 } from "@opentui/core";
27468
+ // src/tui/panes/chat/composer/placeholder.ts
26763
27469
  function resolvePlaceholder(opts) {
26764
27470
  if (!opts.hasTask)
26765
27471
  return opts.noTaskMessage ?? "(no task \u2014 press n to create)";
26766
27472
  if (opts.isStreaming)
26767
- return "(streaming \u2014 enter to queue, ctrl+enter to steer)";
27473
+ return "";
26768
27474
  return opts.inputPlaceholder ?? "Ask Claude\u2026";
26769
27475
  }
27476
+
27477
+ // src/tui/panes/chat/Composer.tsx
27478
+ import { TextAttributes as TextAttributes22 } from "@opentui/core";
26770
27479
  function Composer(props) {
26771
27480
  const {
26772
27481
  theme
@@ -27089,7 +27798,7 @@ function Composer(props) {
27089
27798
  key.preventDefault();
27090
27799
  return;
27091
27800
  }
27092
- if (key.name === "tab" && key.shift) {
27801
+ if (isPermissionModeCycleKey(key)) {
27093
27802
  if (props.onCyclePermissionMode) {
27094
27803
  props.onCyclePermissionMode();
27095
27804
  key.preventDefault();
@@ -27230,10 +27939,11 @@ function Composer(props) {
27230
27939
  };
27231
27940
  const footerHint = () => pasteHint() ?? streamingNotice();
27232
27941
  const modelLabel = () => props.modelLabel?.() ?? "";
27942
+ const permissionModeLabel = () => props.permissionModeLabel?.() ?? (props.permissionMode?.() === "plan" ? "plan mode" : "default");
27233
27943
  const modeBadge = createMemo(() => {
27234
27944
  const mode = props.permissionMode?.();
27235
27945
  return mode === "plan" ? {
27236
- label: "plan mode",
27946
+ label: permissionModeLabel(),
27237
27947
  tone: "primary"
27238
27948
  } : null;
27239
27949
  });
@@ -27258,9 +27968,9 @@ function Composer(props) {
27258
27968
  return theme.border;
27259
27969
  };
27260
27970
  return (() => {
27261
- var _el$ = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("box"), _el$21 = createElement("box"), _el$22 = createElement("text"), _el$23 = createElement("box"), _el$30 = createElement("box"), _el$31 = createElement("box");
27971
+ var _el$ = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("box"), _el$21 = createElement("box"), _el$22 = createElement("text"), _el$23 = createElement("box"), _el$32 = createElement("box"), _el$33 = createElement("box");
27262
27972
  insertNode(_el$, _el$14);
27263
- insertNode(_el$, _el$30);
27973
+ insertNode(_el$, _el$32);
27264
27974
  setProp(_el$, "flexShrink", 0);
27265
27975
  setProp(_el$, "flexDirection", "column");
27266
27976
  setProp(_el$, "paddingTop", 1);
@@ -27307,35 +28017,35 @@ function Composer(props) {
27307
28017
  return idx >= 0 ? match.displayPath.slice(0, idx) : "";
27308
28018
  };
27309
28019
  return (() => {
27310
- var _el$32 = createElement("box"), _el$33 = createElement("text");
27311
- insertNode(_el$32, _el$33);
27312
- setProp(_el$32, "flexDirection", "row");
27313
- setProp(_el$32, "gap", 2);
27314
- setProp(_el$33, "wrapMode", "none");
27315
- insert(_el$33, () => active() ? "\u25B8 " : " ", null);
27316
- insert(_el$33, filename, null);
27317
- insert(_el$32, createComponent2(Show, {
28020
+ var _el$34 = createElement("box"), _el$35 = createElement("text");
28021
+ insertNode(_el$34, _el$35);
28022
+ setProp(_el$34, "flexDirection", "row");
28023
+ setProp(_el$34, "gap", 2);
28024
+ setProp(_el$35, "wrapMode", "none");
28025
+ insert(_el$35, () => active() ? "\u25B8 " : " ", null);
28026
+ insert(_el$35, filename, null);
28027
+ insert(_el$34, createComponent2(Show, {
27318
28028
  get when() {
27319
28029
  return directory().length > 0;
27320
28030
  },
27321
28031
  get children() {
27322
- var _el$34 = createElement("text");
27323
- setProp(_el$34, "wrapMode", "none");
27324
- insert(_el$34, directory);
27325
- effect((_$p) => setProp(_el$34, "fg", theme.textMuted, _$p));
27326
- return _el$34;
28032
+ var _el$36 = createElement("text");
28033
+ setProp(_el$36, "wrapMode", "none");
28034
+ insert(_el$36, directory);
28035
+ effect((_$p) => setProp(_el$36, "fg", theme.textMuted, _$p));
28036
+ return _el$36;
27327
28037
  }
27328
28038
  }), null);
27329
28039
  effect((_p$) => {
27330
- var _v$23 = active() ? theme.primary : theme.text, _v$24 = active() ? TextAttributes22.BOLD : undefined;
27331
- _v$23 !== _p$.e && (_p$.e = setProp(_el$33, "fg", _v$23, _p$.e));
27332
- _v$24 !== _p$.t && (_p$.t = setProp(_el$33, "attributes", _v$24, _p$.t));
28040
+ var _v$24 = active() ? theme.primary : theme.text, _v$25 = active() ? TextAttributes22.BOLD : undefined;
28041
+ _v$24 !== _p$.e && (_p$.e = setProp(_el$35, "fg", _v$24, _p$.e));
28042
+ _v$25 !== _p$.t && (_p$.t = setProp(_el$35, "attributes", _v$25, _p$.t));
27333
28043
  return _p$;
27334
28044
  }, {
27335
28045
  e: undefined,
27336
28046
  t: undefined
27337
28047
  });
27338
- return _el$32;
28048
+ return _el$34;
27339
28049
  })();
27340
28050
  }
27341
28051
  }), null);
@@ -27402,47 +28112,47 @@ function Composer(props) {
27402
28112
  const absoluteIndex = () => slashWindow().start + i2();
27403
28113
  const active = () => absoluteIndex() === slashCursor();
27404
28114
  return (() => {
27405
- var _el$35 = createElement("box"), _el$36 = createElement("text");
27406
- insertNode(_el$35, _el$36);
27407
- setProp(_el$35, "flexDirection", "row");
27408
- setProp(_el$35, "gap", 2);
27409
- setProp(_el$36, "wrapMode", "none");
27410
- insert(_el$36, () => active() ? "\u25B8 " : " ", null);
27411
- insert(_el$36, () => entry.display, null);
27412
- insert(_el$35, createComponent2(Show, {
28115
+ var _el$37 = createElement("box"), _el$38 = createElement("text");
28116
+ insertNode(_el$37, _el$38);
28117
+ setProp(_el$37, "flexDirection", "row");
28118
+ setProp(_el$37, "gap", 2);
28119
+ setProp(_el$38, "wrapMode", "none");
28120
+ insert(_el$38, () => active() ? "\u25B8 " : " ", null);
28121
+ insert(_el$38, () => entry.display, null);
28122
+ insert(_el$37, createComponent2(Show, {
27413
28123
  get when() {
27414
28124
  return entry.source === "user";
27415
28125
  },
27416
28126
  get children() {
27417
- var _el$37 = createElement("text");
27418
- insertNode(_el$37, createTextNode(`user`));
27419
- setProp(_el$37, "wrapMode", "none");
27420
- effect((_$p) => setProp(_el$37, "fg", theme.textMuted, _$p));
27421
- return _el$37;
28127
+ var _el$39 = createElement("text");
28128
+ insertNode(_el$39, createTextNode(`user`));
28129
+ setProp(_el$39, "wrapMode", "none");
28130
+ effect((_$p) => setProp(_el$39, "fg", theme.textMuted, _$p));
28131
+ return _el$39;
27422
28132
  }
27423
28133
  }), null);
27424
- insert(_el$35, createComponent2(Show, {
28134
+ insert(_el$37, createComponent2(Show, {
27425
28135
  get when() {
27426
28136
  return entry.description;
27427
28137
  },
27428
28138
  get children() {
27429
- var _el$39 = createElement("text");
27430
- setProp(_el$39, "wrapMode", "none");
27431
- insert(_el$39, () => entry.description);
27432
- effect((_$p) => setProp(_el$39, "fg", theme.textMuted, _$p));
27433
- return _el$39;
28139
+ var _el$41 = createElement("text");
28140
+ setProp(_el$41, "wrapMode", "none");
28141
+ insert(_el$41, () => entry.description);
28142
+ effect((_$p) => setProp(_el$41, "fg", theme.textMuted, _$p));
28143
+ return _el$41;
27434
28144
  }
27435
28145
  }), null);
27436
28146
  effect((_p$) => {
27437
- var _v$25 = active() ? theme.primary : theme.text, _v$26 = active() ? TextAttributes22.BOLD : undefined;
27438
- _v$25 !== _p$.e && (_p$.e = setProp(_el$36, "fg", _v$25, _p$.e));
27439
- _v$26 !== _p$.t && (_p$.t = setProp(_el$36, "attributes", _v$26, _p$.t));
28147
+ var _v$26 = active() ? theme.primary : theme.text, _v$27 = active() ? TextAttributes22.BOLD : undefined;
28148
+ _v$26 !== _p$.e && (_p$.e = setProp(_el$38, "fg", _v$26, _p$.e));
28149
+ _v$27 !== _p$.t && (_p$.t = setProp(_el$38, "attributes", _v$27, _p$.t));
27440
28150
  return _p$;
27441
28151
  }, {
27442
28152
  e: undefined,
27443
28153
  t: undefined
27444
28154
  });
27445
- return _el$35;
28155
+ return _el$37;
27446
28156
  })();
27447
28157
  }
27448
28158
  }), null);
@@ -27496,37 +28206,37 @@ function Composer(props) {
27496
28206
  return (props.queue?.() ?? []).slice(0, QUEUE_VISIBLE_CAP);
27497
28207
  },
27498
28208
  children: (entry, idx) => (() => {
27499
- var _el$40 = createElement("box"), _el$41 = createElement("text"), _el$43 = createElement("text"), _el$44 = createTextNode(`queued`), _el$45 = createTextNode(`:`), _el$46 = createElement("box"), _el$47 = createElement("text"), _el$48 = createElement("text"), _el$50 = createElement("text");
27500
- insertNode(_el$40, _el$41);
27501
- insertNode(_el$40, _el$43);
27502
- insertNode(_el$40, _el$46);
27503
- insertNode(_el$40, _el$48);
27504
- insertNode(_el$40, _el$50);
27505
- setProp(_el$40, "flexDirection", "row");
27506
- setProp(_el$40, "gap", 1);
27507
- setProp(_el$40, "alignItems", "flex-start");
27508
- insertNode(_el$41, createTextNode(`+`));
27509
- insertNode(_el$43, _el$44);
27510
- insertNode(_el$43, _el$45);
27511
- setProp(_el$43, "wrapMode", "none");
27512
- insert(_el$43, () => idx() === 0 ? " (next)" : "", _el$45);
27513
- insertNode(_el$46, _el$47);
27514
- setProp(_el$46, "flexGrow", 1);
27515
- insert(_el$47, () => entry.text);
27516
- insertNode(_el$48, createTextNode(`[\u25B6]`));
27517
- setProp(_el$48, "onMouseUp", () => props.onSendQueuedNow?.(entry.id));
27518
- insertNode(_el$50, createTextNode(`[x]`));
27519
- setProp(_el$50, "onMouseUp", () => props.onCancelQueued?.(entry.id));
28209
+ var _el$42 = createElement("box"), _el$43 = createElement("text"), _el$45 = createElement("text"), _el$46 = createTextNode(`queued`), _el$47 = createTextNode(`:`), _el$48 = createElement("box"), _el$49 = createElement("text"), _el$50 = createElement("text"), _el$52 = createElement("text");
28210
+ insertNode(_el$42, _el$43);
28211
+ insertNode(_el$42, _el$45);
28212
+ insertNode(_el$42, _el$48);
28213
+ insertNode(_el$42, _el$50);
28214
+ insertNode(_el$42, _el$52);
28215
+ setProp(_el$42, "flexDirection", "row");
28216
+ setProp(_el$42, "gap", 1);
28217
+ setProp(_el$42, "alignItems", "flex-start");
28218
+ insertNode(_el$43, createTextNode(`+`));
28219
+ insertNode(_el$45, _el$46);
28220
+ insertNode(_el$45, _el$47);
28221
+ setProp(_el$45, "wrapMode", "none");
28222
+ insert(_el$45, () => idx() === 0 ? " (next)" : "", _el$47);
28223
+ insertNode(_el$48, _el$49);
28224
+ setProp(_el$48, "flexGrow", 1);
28225
+ insert(_el$49, () => entry.text);
28226
+ insertNode(_el$50, createTextNode(`[\u25B6]`));
28227
+ setProp(_el$50, "onMouseUp", () => props.onSendQueuedNow?.(entry.id));
28228
+ insertNode(_el$52, createTextNode(`[x]`));
28229
+ setProp(_el$52, "onMouseUp", () => props.onCancelQueued?.(entry.id));
27520
28230
  effect((_p$) => {
27521
- var _v$27 = theme.textMuted, _v$28 = TextAttributes22.BOLD, _v$29 = theme.textMuted, _v$30 = theme.text, _v$31 = theme.primary, _v$32 = TextAttributes22.BOLD, _v$33 = theme.error, _v$34 = TextAttributes22.BOLD;
27522
- _v$27 !== _p$.e && (_p$.e = setProp(_el$41, "fg", _v$27, _p$.e));
27523
- _v$28 !== _p$.t && (_p$.t = setProp(_el$41, "attributes", _v$28, _p$.t));
27524
- _v$29 !== _p$.a && (_p$.a = setProp(_el$43, "fg", _v$29, _p$.a));
27525
- _v$30 !== _p$.o && (_p$.o = setProp(_el$47, "fg", _v$30, _p$.o));
27526
- _v$31 !== _p$.i && (_p$.i = setProp(_el$48, "fg", _v$31, _p$.i));
27527
- _v$32 !== _p$.n && (_p$.n = setProp(_el$48, "attributes", _v$32, _p$.n));
27528
- _v$33 !== _p$.s && (_p$.s = setProp(_el$50, "fg", _v$33, _p$.s));
27529
- _v$34 !== _p$.h && (_p$.h = setProp(_el$50, "attributes", _v$34, _p$.h));
28231
+ var _v$28 = theme.textMuted, _v$29 = TextAttributes22.BOLD, _v$30 = theme.textMuted, _v$31 = theme.text, _v$32 = theme.primary, _v$33 = TextAttributes22.BOLD, _v$34 = theme.error, _v$35 = TextAttributes22.BOLD;
28232
+ _v$28 !== _p$.e && (_p$.e = setProp(_el$43, "fg", _v$28, _p$.e));
28233
+ _v$29 !== _p$.t && (_p$.t = setProp(_el$43, "attributes", _v$29, _p$.t));
28234
+ _v$30 !== _p$.a && (_p$.a = setProp(_el$45, "fg", _v$30, _p$.a));
28235
+ _v$31 !== _p$.o && (_p$.o = setProp(_el$49, "fg", _v$31, _p$.o));
28236
+ _v$32 !== _p$.i && (_p$.i = setProp(_el$50, "fg", _v$32, _p$.i));
28237
+ _v$33 !== _p$.n && (_p$.n = setProp(_el$50, "attributes", _v$33, _p$.n));
28238
+ _v$34 !== _p$.s && (_p$.s = setProp(_el$52, "fg", _v$34, _p$.s));
28239
+ _v$35 !== _p$.h && (_p$.h = setProp(_el$52, "attributes", _v$35, _p$.h));
27530
28240
  return _p$;
27531
28241
  }, {
27532
28242
  e: undefined,
@@ -27538,7 +28248,7 @@ function Composer(props) {
27538
28248
  s: undefined,
27539
28249
  h: undefined
27540
28250
  });
27541
- return _el$40;
28251
+ return _el$42;
27542
28252
  })()
27543
28253
  }), null);
27544
28254
  insert(_el$16, createComponent2(Show, {
@@ -27587,10 +28297,10 @@ function Composer(props) {
27587
28297
  },
27588
28298
  get fallback() {
27589
28299
  return (() => {
27590
- var _el$52 = createElement("text");
27591
- insert(_el$52, () => props.noTaskMessage ?? "(no task \u2014 press n to create)");
27592
- effect((_$p) => setProp(_el$52, "fg", theme.textMuted, _$p));
27593
- return _el$52;
28300
+ var _el$54 = createElement("text");
28301
+ insert(_el$54, () => props.noTaskMessage ?? "(no task \u2014 press n to create)");
28302
+ effect((_$p) => setProp(_el$54, "fg", theme.textMuted, _$p));
28303
+ return _el$54;
27594
28304
  })();
27595
28305
  },
27596
28306
  get children() {
@@ -27636,7 +28346,7 @@ function Composer(props) {
27636
28346
  return props.hasTask;
27637
28347
  },
27638
28348
  get children() {
27639
- var _el$25 = createElement("box"), _el$26 = createElement("text"), _el$27 = createElement("box"), _el$28 = createElement("box"), _el$29 = createElement("text");
28349
+ var _el$25 = createElement("box"), _el$26 = createElement("text"), _el$27 = createElement("box"), _el$28 = createElement("box"), _el$29 = createElement("text"), _el$30 = createElement("box"), _el$31 = createElement("text");
27640
28350
  insertNode(_el$25, _el$26);
27641
28351
  insertNode(_el$25, _el$27);
27642
28352
  setProp(_el$25, "flexDirection", "row");
@@ -27646,64 +28356,62 @@ function Composer(props) {
27646
28356
  setProp(_el$26, "wrapMode", "none");
27647
28357
  insert(_el$26, footerHint);
27648
28358
  insertNode(_el$27, _el$28);
28359
+ insertNode(_el$27, _el$30);
27649
28360
  setProp(_el$27, "flexDirection", "row");
27650
28361
  setProp(_el$27, "gap", 2);
27651
28362
  setProp(_el$27, "flexShrink", 0);
27652
- insert(_el$27, createComponent2(Show, {
27653
- get when() {
27654
- return modeBadge();
27655
- },
27656
- children: (badge) => (() => {
27657
- var _el$53 = createElement("text");
27658
- setProp(_el$53, "wrapMode", "none");
27659
- insert(_el$53, () => badge().label);
27660
- effect((_$p) => setProp(_el$53, "fg", toneColor(badge().tone), _$p));
27661
- return _el$53;
27662
- })()
27663
- }), _el$28);
27664
28363
  insertNode(_el$28, _el$29);
27665
28364
  setProp(_el$28, "flexDirection", "row");
27666
28365
  setProp(_el$28, "flexShrink", 0);
27667
- setProp(_el$28, "onMouseUp", () => props.onChooseModel?.());
28366
+ setProp(_el$28, "onMouseUp", () => props.onCyclePermissionMode?.());
27668
28367
  setProp(_el$29, "wrapMode", "none");
27669
- insert(_el$29, modelLabel, null);
27670
- insert(_el$29, () => props.onChooseModel ? " \u25BE" : "", null);
28368
+ insert(_el$29, permissionModeLabel, null);
28369
+ insert(_el$29, () => props.onCyclePermissionMode ? " \u25BE" : "", null);
28370
+ insertNode(_el$30, _el$31);
28371
+ setProp(_el$30, "flexDirection", "row");
28372
+ setProp(_el$30, "flexShrink", 0);
28373
+ setProp(_el$30, "onMouseUp", () => props.onChooseModel?.());
28374
+ setProp(_el$31, "wrapMode", "none");
28375
+ insert(_el$31, modelLabel, null);
28376
+ insert(_el$31, () => props.onChooseModel ? " \u25BE" : "", null);
27671
28377
  effect((_p$) => {
27672
- var _v$13 = props.isStreaming ? theme.accent : theme.textMuted, _v$14 = theme.textMuted;
28378
+ var _v$13 = props.isStreaming ? theme.accent : theme.textMuted, _v$14 = modeBadge() ? toneColor("primary") : theme.textMuted, _v$15 = theme.textMuted;
27673
28379
  _v$13 !== _p$.e && (_p$.e = setProp(_el$26, "fg", _v$13, _p$.e));
27674
28380
  _v$14 !== _p$.t && (_p$.t = setProp(_el$29, "fg", _v$14, _p$.t));
28381
+ _v$15 !== _p$.a && (_p$.a = setProp(_el$31, "fg", _v$15, _p$.a));
27675
28382
  return _p$;
27676
28383
  }, {
27677
28384
  e: undefined,
27678
- t: undefined
28385
+ t: undefined,
28386
+ a: undefined
27679
28387
  });
27680
28388
  return _el$25;
27681
28389
  }
27682
28390
  }), null);
27683
- insertNode(_el$30, _el$31);
27684
- setProp(_el$30, "height", 1);
27685
- setProp(_el$30, "border", ["left"]);
27686
- setProp(_el$31, "height", 1);
27687
- setProp(_el$31, "border", ["bottom"]);
28391
+ insertNode(_el$32, _el$33);
28392
+ setProp(_el$32, "height", 1);
28393
+ setProp(_el$32, "border", ["left"]);
28394
+ setProp(_el$33, "height", 1);
28395
+ setProp(_el$33, "border", ["bottom"]);
27688
28396
  effect((_p$) => {
27689
- var _v$15 = railColor(), _v$16 = {
28397
+ var _v$16 = railColor(), _v$17 = {
27690
28398
  ...SplitBorder.customBorderChars,
27691
28399
  bottomLeft: "\u2579"
27692
- }, _v$17 = theme.backgroundElement, _v$18 = props.isStreaming ? theme.accent : theme.primary, _v$19 = railColor(), _v$20 = {
28400
+ }, _v$18 = theme.backgroundElement, _v$19 = props.isStreaming ? theme.accent : theme.primary, _v$20 = railColor(), _v$21 = {
27693
28401
  ...EmptyBorder,
27694
28402
  vertical: theme.backgroundElement.a !== 0 ? "\u2579" : " "
27695
- }, _v$21 = theme.backgroundElement, _v$22 = {
28403
+ }, _v$22 = theme.backgroundElement, _v$23 = {
27696
28404
  ...EmptyBorder,
27697
28405
  horizontal: theme.backgroundElement.a !== 0 ? "\u2580" : " "
27698
28406
  };
27699
- _v$15 !== _p$.e && (_p$.e = setProp(_el$14, "borderColor", _v$15, _p$.e));
27700
- _v$16 !== _p$.t && (_p$.t = setProp(_el$14, "customBorderChars", _v$16, _p$.t));
27701
- _v$17 !== _p$.a && (_p$.a = setProp(_el$15, "backgroundColor", _v$17, _p$.a));
27702
- _v$18 !== _p$.o && (_p$.o = setProp(_el$22, "fg", _v$18, _p$.o));
27703
- _v$19 !== _p$.i && (_p$.i = setProp(_el$30, "borderColor", _v$19, _p$.i));
27704
- _v$20 !== _p$.n && (_p$.n = setProp(_el$30, "customBorderChars", _v$20, _p$.n));
27705
- _v$21 !== _p$.s && (_p$.s = setProp(_el$31, "borderColor", _v$21, _p$.s));
27706
- _v$22 !== _p$.h && (_p$.h = setProp(_el$31, "customBorderChars", _v$22, _p$.h));
28407
+ _v$16 !== _p$.e && (_p$.e = setProp(_el$14, "borderColor", _v$16, _p$.e));
28408
+ _v$17 !== _p$.t && (_p$.t = setProp(_el$14, "customBorderChars", _v$17, _p$.t));
28409
+ _v$18 !== _p$.a && (_p$.a = setProp(_el$15, "backgroundColor", _v$18, _p$.a));
28410
+ _v$19 !== _p$.o && (_p$.o = setProp(_el$22, "fg", _v$19, _p$.o));
28411
+ _v$20 !== _p$.i && (_p$.i = setProp(_el$32, "borderColor", _v$20, _p$.i));
28412
+ _v$21 !== _p$.n && (_p$.n = setProp(_el$32, "customBorderChars", _v$21, _p$.n));
28413
+ _v$22 !== _p$.s && (_p$.s = setProp(_el$33, "borderColor", _v$22, _p$.s));
28414
+ _v$23 !== _p$.h && (_p$.h = setProp(_el$33, "customBorderChars", _v$23, _p$.h));
27707
28415
  return _p$;
27708
28416
  }, {
27709
28417
  e: undefined,
@@ -30092,6 +30800,25 @@ var init_MessageList = __esm(() => {
30092
30800
  BLACK_CIRCLE = process.platform === "darwin" ? "\u23FA" : "\u25CF";
30093
30801
  });
30094
30802
 
30803
+ // src/tui/panes/chat/composer/model-picker-row.ts
30804
+ function modelPickerRowParts(choice) {
30805
+ const caps = getCapabilities(choice.vendor);
30806
+ return {
30807
+ level: choice.level ?? "level1",
30808
+ vendor: choice.vendor,
30809
+ engine: caps.label,
30810
+ from: "catalog",
30811
+ model: choice.label,
30812
+ hint: choice.hint
30813
+ };
30814
+ }
30815
+ function modelPickerMetaLabel(parts) {
30816
+ return `${parts.level} ${parts.vendor} ${parts.engine} from ${parts.from}`;
30817
+ }
30818
+ var init_model_picker_row = __esm(() => {
30819
+ init_registry2();
30820
+ });
30821
+
30095
30822
  // src/tui/panes/chat/composer/ModelPicker.tsx
30096
30823
  import { TextAttributes as TextAttributes24 } from "@opentui/core";
30097
30824
  function ModelPicker(props) {
@@ -30101,13 +30828,16 @@ function ModelPicker(props) {
30101
30828
  } = useTheme();
30102
30829
  const choices = createMemo(() => allModels());
30103
30830
  const seed = props.current ?? defaultCapabilities.defaultModelId();
30104
- const initial = choices().findIndex((m2) => m2.id === seed);
30831
+ const initial = choices().findIndex((m2) => m2.id === seed && m2.effort === props.currentEffort);
30105
30832
  const [cursor, setCursor] = createSignal(initial >= 0 ? initial : 0);
30106
30833
  function commit() {
30107
30834
  const choice = choices()[cursor()];
30108
30835
  if (!choice)
30109
30836
  return;
30110
- props.onPick(choice.id);
30837
+ props.onPick({
30838
+ id: choice.id,
30839
+ effort: choice.effort
30840
+ });
30111
30841
  dialog.clear();
30112
30842
  }
30113
30843
  useBindings(() => ({
@@ -30171,9 +30901,11 @@ function ModelPicker(props) {
30171
30901
  },
30172
30902
  children: (choice, i2) => {
30173
30903
  const active = () => i2() === cursor();
30904
+ const parts = () => modelPickerRowParts(choice);
30174
30905
  return (() => {
30175
- var _el$1 = createElement("box"), _el$10 = createElement("text");
30906
+ var _el$1 = createElement("box"), _el$10 = createElement("text"), _el$11 = createElement("text");
30176
30907
  insertNode(_el$1, _el$10);
30908
+ insertNode(_el$1, _el$11);
30177
30909
  setProp(_el$1, "flexDirection", "row");
30178
30910
  setProp(_el$1, "gap", 2);
30179
30911
  setProp(_el$1, "paddingLeft", 1);
@@ -30184,27 +30916,33 @@ function ModelPicker(props) {
30184
30916
  });
30185
30917
  setProp(_el$10, "wrapMode", "none");
30186
30918
  insert(_el$10, () => active() ? "\u25B8 " : " ", null);
30187
- insert(_el$10, () => choice.label, null);
30919
+ insert(_el$10, () => modelPickerMetaLabel(parts()), null);
30920
+ setProp(_el$11, "wrapMode", "none");
30921
+ insert(_el$11, () => parts().model);
30188
30922
  insert(_el$1, (() => {
30189
- var _c$ = memo2(() => !!choice.hint);
30923
+ var _c$ = memo2(() => !!parts().hint);
30190
30924
  return () => _c$() ? (() => {
30191
- var _el$11 = createElement("text");
30192
- setProp(_el$11, "wrapMode", "none");
30193
- insert(_el$11, () => choice.hint);
30194
- effect((_$p) => setProp(_el$11, "fg", active() ? theme.selectedListItemText : theme.textMuted, _$p));
30195
- return _el$11;
30925
+ var _el$12 = createElement("text");
30926
+ setProp(_el$12, "wrapMode", "none");
30927
+ insert(_el$12, () => parts().hint);
30928
+ effect((_$p) => setProp(_el$12, "fg", active() ? theme.selectedListItemText : theme.textMuted, _$p));
30929
+ return _el$12;
30196
30930
  })() : null;
30197
30931
  })(), null);
30198
30932
  effect((_p$) => {
30199
- var _v$5 = active() ? theme.primary : undefined, _v$6 = active() ? theme.selectedListItemText : theme.text, _v$7 = active() ? TextAttributes24.BOLD : undefined;
30933
+ var _v$5 = active() ? theme.primary : undefined, _v$6 = active() ? theme.selectedListItemText : theme.text, _v$7 = active() ? TextAttributes24.BOLD : undefined, _v$8 = active() ? theme.selectedListItemText : theme.text, _v$9 = active() ? TextAttributes24.BOLD : undefined;
30200
30934
  _v$5 !== _p$.e && (_p$.e = setProp(_el$1, "backgroundColor", _v$5, _p$.e));
30201
30935
  _v$6 !== _p$.t && (_p$.t = setProp(_el$10, "fg", _v$6, _p$.t));
30202
30936
  _v$7 !== _p$.a && (_p$.a = setProp(_el$10, "attributes", _v$7, _p$.a));
30937
+ _v$8 !== _p$.o && (_p$.o = setProp(_el$11, "fg", _v$8, _p$.o));
30938
+ _v$9 !== _p$.i && (_p$.i = setProp(_el$11, "attributes", _v$9, _p$.i));
30203
30939
  return _p$;
30204
30940
  }, {
30205
30941
  e: undefined,
30206
30942
  t: undefined,
30207
- a: undefined
30943
+ a: undefined,
30944
+ o: undefined,
30945
+ i: undefined
30208
30946
  });
30209
30947
  return _el$1;
30210
30948
  })();
@@ -30243,17 +30981,25 @@ var init_ModelPicker = __esm(() => {
30243
30981
  init_theme();
30244
30982
  init_keymap();
30245
30983
  init_dialog();
30246
- ModelPicker.show = (dialog, current) => {
30984
+ init_model_picker_row();
30985
+ ModelPicker.show = (dialog, current, currentEffort) => {
30247
30986
  return new Promise((resolve4) => {
30248
30987
  dialog.replace(() => createComponent2(ModelPicker, {
30249
30988
  current,
30250
- onPick: (id) => resolve4(id),
30989
+ currentEffort,
30990
+ onPick: (choice) => resolve4(choice),
30251
30991
  onCancel: () => resolve4(undefined)
30252
30992
  }), () => resolve4(undefined));
30253
30993
  });
30254
30994
  };
30255
30995
  });
30256
30996
 
30997
+ // src/tui/panes/chat/composer/permission-mode.ts
30998
+ function permissionModeLabel(capabilities, mode) {
30999
+ const id = mode ?? "default";
31000
+ return capabilities.permissionModes.find((m2) => m2.id === id)?.label ?? id;
31001
+ }
31002
+
30257
31003
  // src/tui/panes/chat/composer/user-slashes.ts
30258
31004
  import { readFile as readFile6, readdir as readdir4, stat as stat4 } from "fs/promises";
30259
31005
  import { homedir as homedir15 } from "os";
@@ -31086,29 +31832,40 @@ function Chat(props) {
31086
31832
  const tab = task?.tabs.find((t2) => t2.id === activeTabId());
31087
31833
  return tab?.model ?? task?.model;
31088
31834
  });
31835
+ const modelEffort = createMemo(() => {
31836
+ const id = props.taskId();
31837
+ if (!id)
31838
+ return;
31839
+ const task = tasksAcc().find((t2) => t2.id === id);
31840
+ const tab = task?.tabs.find((t2) => t2.id === activeTabId());
31841
+ return tab?.modelEffort ?? task?.modelEffort;
31842
+ });
31089
31843
  const worktreePath = createMemo(() => {
31090
31844
  const id = props.taskId();
31091
31845
  if (!id)
31092
31846
  return;
31093
31847
  return tasksAcc().find((t2) => t2.id === id)?.worktreePath ?? undefined;
31094
31848
  });
31095
- const modelLabel = createMemo(() => modelLabelFor(modelId()));
31096
- const inputPlaceholder = createMemo(() => {
31849
+ const modelLabel = createMemo(() => modelLabelFor(modelId(), modelEffort()));
31850
+ const activeVendor = createMemo(() => {
31097
31851
  const id = props.taskId();
31098
31852
  const task = id ? tasksAcc().find((t2) => t2.id === id) : undefined;
31099
31853
  const tab = task?.tabs.find((t2) => t2.id === activeTabId());
31100
- const vendor = tab?.vendor ?? task?.vendor ?? "claude";
31101
- return getIdentity(vendor).inputPlaceholder;
31854
+ return tab?.vendor ?? task?.vendor ?? "claude";
31855
+ });
31856
+ const permissionModeText = createMemo(() => permissionModeLabel(getCapabilities(activeVendor()), permissionMode()));
31857
+ const inputPlaceholder = createMemo(() => {
31858
+ return getIdentity(activeVendor()).inputPlaceholder;
31102
31859
  });
31103
31860
  async function chooseModel() {
31104
31861
  const id = props.taskId();
31105
31862
  if (!id)
31106
31863
  return;
31107
31864
  const tabId = activeTabId() ?? undefined;
31108
- const result = await ModelPicker.show(dialog, modelId());
31865
+ const result = await ModelPicker.show(dialog, modelId(), modelEffort());
31109
31866
  if (result === undefined)
31110
31867
  return;
31111
- await props.orchestrator.setModel(id, result, tabId).catch((err) => {
31868
+ await props.orchestrator.setModel(id, result.id, tabId, result.effort).catch((err) => {
31112
31869
  console.error("[kobe] setModel failed:", err);
31113
31870
  });
31114
31871
  }
@@ -31594,6 +32351,7 @@ function Chat(props) {
31594
32351
  },
31595
32352
  slashes,
31596
32353
  permissionMode,
32354
+ permissionModeLabel: permissionModeText,
31597
32355
  onCyclePermissionMode: cyclePermissionMode,
31598
32356
  modelLabel,
31599
32357
  inputPlaceholder,
@@ -32616,7 +33374,8 @@ Try again or quit?`;
32616
33374
  onFocusPrev: () => {
32617
33375
  if (focusedPane() !== "workspace")
32618
33376
  focus.cycle(-1);
32619
- }
33377
+ },
33378
+ focusCycleEnabled: () => focusedPane() !== "workspace"
32620
33379
  });
32621
33380
  const {
32622
33381
  openNewTaskFlow,