@sma1lboy/kobe 0.5.16 → 0.5.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -5237,6 +5237,7 @@ function useKobeKeybindings(opts) {
5237
5237
  });
5238
5238
  const onFocusNext = opts.onFocusNext ?? (() => {});
5239
5239
  const onFocusPrev = opts.onFocusPrev ?? (() => {});
5240
+ const focusCycleEnabled = opts.focusCycleEnabled ?? (() => true);
5240
5241
  if (renderer) {
5241
5242
  const onSelection = () => {
5242
5243
  const text = renderer.getSelection()?.getSelectedText();
@@ -5275,13 +5276,16 @@ function useKobeKeybindings(opts) {
5275
5276
  ...bindByIds({
5276
5277
  "palette.open": () => palette.show(),
5277
5278
  "help.open": () => opts.onShowHelp(),
5278
- "focus.next": () => onFocusNext(),
5279
- "focus.prev": () => onFocusPrev(),
5280
5279
  "app.copy_or_quit": () => handleCtrlC()
5281
5280
  })
5282
5281
  ];
5283
5282
  });
5283
+ const focusCycleBindings = createMemo(() => bindByIds({
5284
+ "focus.next": () => onFocusNext(),
5285
+ "focus.prev": () => onFocusPrev()
5286
+ }));
5284
5287
  useBindings(() => ({ bindings: bindings() }));
5288
+ useBindings(() => ({ enabled: focusCycleEnabled(), bindings: focusCycleBindings() }));
5285
5289
  }
5286
5290
  var CTRL_C_QUIT_WINDOW_MS = 1500, ctrlCArmed, setCtrlCArmed, ctrlCArmTimer = null, KobeKeymap;
5287
5291
  var init_keybindings = __esm(() => {
@@ -14756,6 +14760,16 @@ var init_binary = __esm(() => {
14756
14760
  });
14757
14761
 
14758
14762
  // src/engine/claude-code-local/models.ts
14763
+ function opus47EffortChoices(id, label) {
14764
+ return CLAUDE_OPUS_EFFORT_LEVELS.map((effort) => ({
14765
+ vendor: "claude",
14766
+ id,
14767
+ effort,
14768
+ level: effort,
14769
+ label: `${label} \xB7 ${effort}`,
14770
+ hint: effort === "max" ? "deepest reasoning" : `${effort} effort`
14771
+ }));
14772
+ }
14759
14773
  function parseContextWindowSize(modelIdentifier) {
14760
14774
  const delimitedMatch = /(?:\(|\[)\s*(\d+(?:[,_]\d+)*(?:\.\d+)?)\s*([km])\s*(?:\)|\])/i.exec(modelIdentifier);
14761
14775
  if (delimitedMatch?.[1] && delimitedMatch[2]) {
@@ -14785,11 +14799,20 @@ function claudeContextWindowFor(modelId) {
14785
14799
  return LONG_CTX;
14786
14800
  return STD_CTX;
14787
14801
  }
14788
- var CLAUDE_MODELS, LONG_CTX = 1e6, STD_CTX = 200000;
14802
+ var CLAUDE_OPUS_EFFORT_LEVELS, CLAUDE_MODELS, LONG_CTX = 1e6, STD_CTX = 200000;
14789
14803
  var init_models = __esm(() => {
14804
+ CLAUDE_OPUS_EFFORT_LEVELS = [
14805
+ "low",
14806
+ "medium",
14807
+ "high",
14808
+ "xhigh",
14809
+ "max"
14810
+ ];
14790
14811
  CLAUDE_MODELS = [
14791
14812
  { vendor: "claude", id: "claude-opus-4-7[1m]", label: "Opus 4.7 1M", hint: "long context, default" },
14813
+ ...opus47EffortChoices("claude-opus-4-7[1m]", "Opus 4.7 1M"),
14792
14814
  { vendor: "claude", id: "claude-opus-4-7", label: "Opus 4.7", hint: "most capable, slowest" },
14815
+ ...opus47EffortChoices("claude-opus-4-7", "Opus 4.7"),
14793
14816
  { vendor: "claude", id: "claude-sonnet-4-6[1m]", label: "sonnet 4.6 (1M)", hint: "long context" },
14794
14817
  { vendor: "claude", id: "claude-sonnet-4-6", label: "sonnet 4.6" },
14795
14818
  { vendor: "claude", id: "claude-haiku-4-5-20251001", label: "haiku 4.5", hint: "fastest, cheapest" }
@@ -14839,6 +14862,10 @@ var init_capabilities = __esm(() => {
14839
14862
  vendorId: "claude",
14840
14863
  label: "Claude Code",
14841
14864
  models: CLAUDE_MODELS,
14865
+ permissionModes: [
14866
+ { id: "default", label: "default" },
14867
+ { id: "plan", label: "plan mode" }
14868
+ ],
14842
14869
  defaultModelId: resolveClaudeDefaultModelId,
14843
14870
  contextWindowFor: claudeContextWindowFor
14844
14871
  };
@@ -14855,10 +14882,25 @@ var init_capabilities = __esm(() => {
14855
14882
  function codexContextWindowFor(_modelId) {
14856
14883
  return DEFAULT_CTX;
14857
14884
  }
14858
- var CODEX_MODELS, CODEX_FALLBACK_DEFAULT_MODEL_ID = "gpt-5.4-mini", DEFAULT_CTX = 400000;
14885
+ var CODEX_GPT55_EFFORT_LEVELS, CODEX_MODELS, CODEX_FALLBACK_DEFAULT_MODEL_ID = "gpt-5.4-mini", DEFAULT_CTX = 400000;
14859
14886
  var init_models2 = __esm(() => {
14887
+ CODEX_GPT55_EFFORT_LEVELS = [
14888
+ "none",
14889
+ "low",
14890
+ "medium",
14891
+ "high",
14892
+ "xhigh"
14893
+ ];
14860
14894
  CODEX_MODELS = [
14861
14895
  { vendor: "codex", id: "gpt-5.5", label: "GPT-5.5", hint: "latest, ChatGPT-account compatible" },
14896
+ ...CODEX_GPT55_EFFORT_LEVELS.map((effort) => ({
14897
+ vendor: "codex",
14898
+ id: "gpt-5.5",
14899
+ effort,
14900
+ level: effort,
14901
+ label: `GPT-5.5 \xB7 ${effort}`,
14902
+ hint: effort === "none" ? "no reasoning effort" : `${effort} reasoning`
14903
+ })),
14862
14904
  { vendor: "codex", id: "gpt-5.4", label: "GPT-5.4", hint: "stable" },
14863
14905
  { vendor: "codex", id: "gpt-5.4-mini", label: "GPT-5.4 mini", hint: "fastest, always supported" }
14864
14906
  ];
@@ -14910,6 +14952,10 @@ var init_capabilities2 = __esm(() => {
14910
14952
  vendorId: "codex",
14911
14953
  label: "Codex",
14912
14954
  models: CODEX_MODELS,
14955
+ permissionModes: [
14956
+ { id: "default", label: "full access" },
14957
+ { id: "plan", label: "plan mode" }
14958
+ ],
14913
14959
  defaultModelId: resolveCodexDefaultModelId,
14914
14960
  contextWindowFor: codexContextWindowFor
14915
14961
  };
@@ -14947,7 +14993,7 @@ function allModels() {
14947
14993
  if (!caps)
14948
14994
  continue;
14949
14995
  for (const m2 of caps.models) {
14950
- const key = `${m2.vendor}:${m2.id}`;
14996
+ const key = `${m2.vendor}:${m2.id}:${m2.effort ?? ""}`;
14951
14997
  if (seen.has(key))
14952
14998
  continue;
14953
14999
  seen.add(key);
@@ -14956,15 +15002,17 @@ function allModels() {
14956
15002
  }
14957
15003
  return out;
14958
15004
  }
14959
- function modelLabelFor(modelId) {
15005
+ function modelLabelFor(modelId, effort) {
14960
15006
  const resolved = modelId ?? defaultCapabilities.defaultModelId();
14961
15007
  for (const caps of Object.values(ENGINE_REGISTRY)) {
14962
15008
  if (!caps)
14963
15009
  continue;
14964
- const match = caps.models.find((m2) => m2.id === resolved);
15010
+ const match = caps.models.find((m2) => m2.id === resolved && (effort === undefined || m2.effort === effort));
14965
15011
  if (match)
14966
15012
  return match.label;
14967
15013
  }
15014
+ if (effort)
15015
+ return `${resolved} \xB7 ${effort}`;
14968
15016
  return resolved;
14969
15017
  }
14970
15018
  var ENGINE_REGISTRY, ENGINE_IDENTITIES, defaultCapabilities, defaultIdentity;
@@ -14991,6 +15039,14 @@ function nextChatTabSeq(tabs) {
14991
15039
  max = t2.seq;
14992
15040
  return max + 1;
14993
15041
  }
15042
+ function worktreeSlug(task) {
15043
+ if (task.kind === "main")
15044
+ return "";
15045
+ if (!task.worktreePath)
15046
+ return "";
15047
+ const match = task.worktreePath.match(/([^/\\]+)[/\\]*$/);
15048
+ return match ? match[1] ?? "" : "";
15049
+ }
14994
15050
  var toTaskId = (id) => id, DEFAULT_TASK_VENDOR = "claude";
14995
15051
 
14996
15052
  // src/orchestrator/index/ulid.ts
@@ -15166,6 +15222,7 @@ class TaskIndexStore {
15166
15222
  seq: 1,
15167
15223
  createdAt: now,
15168
15224
  ...rest.model ? { model: rest.model } : {},
15225
+ ...rest.modelEffort ? { modelEffort: rest.modelEffort } : {},
15169
15226
  vendor: rest.vendor ?? DEFAULT_TASK_VENDOR
15170
15227
  }
15171
15228
  ];
@@ -15333,6 +15390,7 @@ function coerceTask(value) {
15333
15390
  createdAt: tt.createdAt,
15334
15391
  ...typeof tt.title === "string" ? { title: tt.title } : {},
15335
15392
  ...typeof tt.model === "string" ? { model: tt.model } : {},
15393
+ ...isModelEffortLevel(tt.modelEffort) ? { modelEffort: tt.modelEffort } : {},
15336
15394
  ...isVendorId(tt.vendor) ? { vendor: tt.vendor } : {}
15337
15395
  };
15338
15396
  tabs.push(tab);
@@ -15366,6 +15424,7 @@ function coerceTask(value) {
15366
15424
  kind: v2.kind === "main" ? "main" : "task",
15367
15425
  permissionMode: isPermissionMode(v2.permissionMode) ? v2.permissionMode : undefined,
15368
15426
  model: typeof v2.model === "string" ? v2.model : undefined,
15427
+ modelEffort: isModelEffortLevel(v2.modelEffort) ? v2.modelEffort : undefined,
15369
15428
  vendor: resolveTaskVendor(v2.vendor, typeof v2.model === "string" ? v2.model : undefined),
15370
15429
  createdAt: v2.createdAt,
15371
15430
  updatedAt: v2.updatedAt
@@ -15374,6 +15433,9 @@ function coerceTask(value) {
15374
15433
  function isPermissionMode(v2) {
15375
15434
  return v2 === "default" || v2 === "plan";
15376
15435
  }
15436
+ function isModelEffortLevel(v2) {
15437
+ return v2 === "none" || v2 === "minimal" || v2 === "low" || v2 === "medium" || v2 === "high" || v2 === "xhigh" || v2 === "max";
15438
+ }
15377
15439
  function isVendorId(v2) {
15378
15440
  return typeof v2 === "string" && v2 in ENGINE_REGISTRY;
15379
15441
  }
@@ -15403,11 +15465,19 @@ function worktreeRootFor(repo) {
15403
15465
  }
15404
15466
  return path4.join(repo, KOBE_WORKTREE_ROOT_SUBPATH);
15405
15467
  }
15406
- function worktreePathFor(repo, taskId) {
15407
- if (!taskId || /[/\\\0]/.test(taskId)) {
15408
- throw new Error(`worktreePathFor: invalid taskId: ${JSON.stringify(taskId)}`);
15468
+ function worktreePathFor(repo, slug) {
15469
+ if (!slug || /[/\\\0]/.test(slug)) {
15470
+ throw new Error(`worktreePathFor: invalid slug: ${JSON.stringify(slug)}`);
15471
+ }
15472
+ return path4.join(worktreeRootFor(repo), slug);
15473
+ }
15474
+ function listWorktreeDirNames(repo) {
15475
+ const root = worktreeRootFor(repo);
15476
+ try {
15477
+ return fs2.readdirSync(root, { withFileTypes: true }).filter((e2) => e2.isDirectory()).map((e2) => e2.name);
15478
+ } catch {
15479
+ return [];
15409
15480
  }
15410
- return path4.join(worktreeRootFor(repo), taskId);
15411
15481
  }
15412
15482
  function isKobeManagedPath(repo, candidate) {
15413
15483
  if (!path4.isAbsolute(repo) || !path4.isAbsolute(candidate))
@@ -15433,7 +15503,7 @@ var init_package = __esm(() => {
15433
15503
  package_default = {
15434
15504
  $schema: "https://json.schemastore.org/package.json",
15435
15505
  name: "@sma1lboy/kobe",
15436
- version: "0.5.16",
15506
+ version: "0.5.17",
15437
15507
  description: "TUI orchestrator for Claude Code (codename)",
15438
15508
  type: "module",
15439
15509
  packageManager: "bun@1.3.13",
@@ -15723,19 +15793,6 @@ function dirSize(root) {
15723
15793
  }
15724
15794
  return total;
15725
15795
  }
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
15796
  function tailLines(path5, n2) {
15740
15797
  try {
15741
15798
  const text = __require("fs").readFileSync(path5, "utf8");
@@ -15841,8 +15898,7 @@ async function buildDiagnoseReport() {
15841
15898
  const onDiskByRepo = new Map;
15842
15899
  for (const repo of repos) {
15843
15900
  try {
15844
- const root = worktreeRootFor(repo);
15845
- onDiskByRepo.set(repo, listWorktreeDirs(root));
15901
+ onDiskByRepo.set(repo, listWorktreeDirNames(repo));
15846
15902
  } catch (err) {
15847
15903
  lines.push(formatKv("scan-error:", `${repo}: ${err.message}`));
15848
15904
  onDiskByRepo.set(repo, []);
@@ -16563,6 +16619,7 @@ function serializeTask(task) {
16563
16619
  pinned: task.pinned ?? false,
16564
16620
  permissionMode: task.permissionMode,
16565
16621
  model: task.model,
16622
+ modelEffort: task.modelEffort,
16566
16623
  vendor: task.vendor,
16567
16624
  createdAt: task.createdAt,
16568
16625
  updatedAt: task.updatedAt
@@ -17184,6 +17241,507 @@ var init_session_pump = __esm(() => {
17184
17241
  init_core();
17185
17242
  });
17186
17243
 
17244
+ // src/orchestrator/worktree/animal-names.ts
17245
+ var ANIMAL_NAMES;
17246
+ var init_animal_names = __esm(() => {
17247
+ ANIMAL_NAMES = [
17248
+ "aardvark",
17249
+ "addax",
17250
+ "adder",
17251
+ "agouti",
17252
+ "albatross",
17253
+ "alpaca",
17254
+ "anaconda",
17255
+ "anchovy",
17256
+ "anglerfish",
17257
+ "anole",
17258
+ "anteater",
17259
+ "antelope",
17260
+ "ape",
17261
+ "argali",
17262
+ "armadillo",
17263
+ "avocet",
17264
+ "axolotl",
17265
+ "baboon",
17266
+ "badger",
17267
+ "banteng",
17268
+ "barracuda",
17269
+ "basilisk",
17270
+ "bass",
17271
+ "bat",
17272
+ "beagle",
17273
+ "bear",
17274
+ "beaver",
17275
+ "bee",
17276
+ "beetle",
17277
+ "beluga",
17278
+ "betta",
17279
+ "bison",
17280
+ "blackbird",
17281
+ "blenny",
17282
+ "bluebird",
17283
+ "bluegill",
17284
+ "boar",
17285
+ "bobcat",
17286
+ "bonito",
17287
+ "bovid",
17288
+ "buffalo",
17289
+ "bullfrog",
17290
+ "bunting",
17291
+ "bushbuck",
17292
+ "butterfly",
17293
+ "buzzard",
17294
+ "caiman",
17295
+ "camel",
17296
+ "canary",
17297
+ "capybara",
17298
+ "caracal",
17299
+ "cardinal",
17300
+ "caribou",
17301
+ "carp",
17302
+ "cassowary",
17303
+ "caterpillar",
17304
+ "catfish",
17305
+ "chameleon",
17306
+ "chamois",
17307
+ "char",
17308
+ "cheetah",
17309
+ "chickadee",
17310
+ "chimp",
17311
+ "chinchilla",
17312
+ "chipmunk",
17313
+ "chough",
17314
+ "cicada",
17315
+ "civet",
17316
+ "clam",
17317
+ "clownfish",
17318
+ "cobra",
17319
+ "cockatoo",
17320
+ "condor",
17321
+ "coot",
17322
+ "copperhead",
17323
+ "coral",
17324
+ "cormorant",
17325
+ "cougar",
17326
+ "coyote",
17327
+ "crab",
17328
+ "crane",
17329
+ "crawfish",
17330
+ "crayfish",
17331
+ "cricket",
17332
+ "crocodile",
17333
+ "crow",
17334
+ "cuckoo",
17335
+ "curlew",
17336
+ "cuttlefish",
17337
+ "deer",
17338
+ "dikdik",
17339
+ "dingo",
17340
+ "dolphin",
17341
+ "donkey",
17342
+ "dormouse",
17343
+ "dotterel",
17344
+ "dove",
17345
+ "dragonfly",
17346
+ "dromedary",
17347
+ "duck",
17348
+ "dugong",
17349
+ "dunlin",
17350
+ "eagle",
17351
+ "echidna",
17352
+ "eel",
17353
+ "egret",
17354
+ "eider",
17355
+ "eland",
17356
+ "elephant",
17357
+ "elk",
17358
+ "emu",
17359
+ "ermine",
17360
+ "falcon",
17361
+ "fawn",
17362
+ "ferret",
17363
+ "finch",
17364
+ "firefly",
17365
+ "flamingo",
17366
+ "flounder",
17367
+ "fox",
17368
+ "frog",
17369
+ "gadwall",
17370
+ "gannet",
17371
+ "gaur",
17372
+ "gazelle",
17373
+ "gecko",
17374
+ "gemsbok",
17375
+ "gerbil",
17376
+ "gharial",
17377
+ "gibbon",
17378
+ "gnu",
17379
+ "goat",
17380
+ "goby",
17381
+ "godwit",
17382
+ "goldfish",
17383
+ "goose",
17384
+ "gopher",
17385
+ "goral",
17386
+ "gorilla",
17387
+ "goshawk",
17388
+ "grackle",
17389
+ "grasshopper",
17390
+ "grayling",
17391
+ "grebe",
17392
+ "grouse",
17393
+ "guanaco",
17394
+ "guillemot",
17395
+ "guineafowl",
17396
+ "guppy",
17397
+ "halibut",
17398
+ "hammerhead",
17399
+ "hamster",
17400
+ "hare",
17401
+ "harrier",
17402
+ "hartebeest",
17403
+ "hawk",
17404
+ "hedgehog",
17405
+ "heron",
17406
+ "herring",
17407
+ "hippo",
17408
+ "hornbill",
17409
+ "hornet",
17410
+ "horse",
17411
+ "hummingbird",
17412
+ "hyena",
17413
+ "ibex",
17414
+ "ibis",
17415
+ "iguana",
17416
+ "impala",
17417
+ "indri",
17418
+ "jacana",
17419
+ "jackal",
17420
+ "jaguar",
17421
+ "jay",
17422
+ "jellyfish",
17423
+ "jerboa",
17424
+ "junco",
17425
+ "kakapo",
17426
+ "kangaroo",
17427
+ "kestrel",
17428
+ "killdeer",
17429
+ "kingfisher",
17430
+ "kinglet",
17431
+ "kite",
17432
+ "kiwi",
17433
+ "koala",
17434
+ "kookaburra",
17435
+ "krait",
17436
+ "krill",
17437
+ "kudu",
17438
+ "ladybug",
17439
+ "lamprey",
17440
+ "langur",
17441
+ "lapwing",
17442
+ "lark",
17443
+ "lemming",
17444
+ "lemur",
17445
+ "leopard",
17446
+ "limpet",
17447
+ "lion",
17448
+ "lionfish",
17449
+ "lizard",
17450
+ "llama",
17451
+ "lobster",
17452
+ "locust",
17453
+ "loon",
17454
+ "lorikeet",
17455
+ "loris",
17456
+ "lynx",
17457
+ "macaque",
17458
+ "macaw",
17459
+ "mackerel",
17460
+ "magpie",
17461
+ "mallard",
17462
+ "mamba",
17463
+ "mammoth",
17464
+ "manatee",
17465
+ "mandrill",
17466
+ "manta",
17467
+ "mantis",
17468
+ "marlin",
17469
+ "marmoset",
17470
+ "marmot",
17471
+ "marten",
17472
+ "meerkat",
17473
+ "merganser",
17474
+ "mink",
17475
+ "minnow",
17476
+ "mole",
17477
+ "mongoose",
17478
+ "monitor",
17479
+ "monkey",
17480
+ "moose",
17481
+ "moth",
17482
+ "mouflon",
17483
+ "mouse",
17484
+ "mudpuppy",
17485
+ "mule",
17486
+ "muntjac",
17487
+ "musk",
17488
+ "muskox",
17489
+ "muskrat",
17490
+ "mussel",
17491
+ "mustang",
17492
+ "narwhal",
17493
+ "newt",
17494
+ "nightingale",
17495
+ "numbat",
17496
+ "nuthatch",
17497
+ "nyala",
17498
+ "ocelot",
17499
+ "octopus",
17500
+ "okapi",
17501
+ "opossum",
17502
+ "orangutan",
17503
+ "orca",
17504
+ "oriole",
17505
+ "oryx",
17506
+ "osprey",
17507
+ "ostrich",
17508
+ "otter",
17509
+ "owl",
17510
+ "oyster",
17511
+ "oystercatcher",
17512
+ "paca",
17513
+ "panda",
17514
+ "pangolin",
17515
+ "panther",
17516
+ "parakeet",
17517
+ "parrot",
17518
+ "parrotfish",
17519
+ "partridge",
17520
+ "peafowl",
17521
+ "pelican",
17522
+ "penguin",
17523
+ "perch",
17524
+ "petrel",
17525
+ "pheasant",
17526
+ "pigeon",
17527
+ "pika",
17528
+ "pike",
17529
+ "pintail",
17530
+ "pipefish",
17531
+ "platypus",
17532
+ "plover",
17533
+ "pollock",
17534
+ "pony",
17535
+ "porcupine",
17536
+ "porpoise",
17537
+ "possum",
17538
+ "ptarmigan",
17539
+ "puffin",
17540
+ "puma",
17541
+ "pupfish",
17542
+ "python",
17543
+ "quail",
17544
+ "quetzal",
17545
+ "quokka",
17546
+ "quoll",
17547
+ "rabbit",
17548
+ "raccoon",
17549
+ "rail",
17550
+ "rat",
17551
+ "rattler",
17552
+ "raven",
17553
+ "ray",
17554
+ "redpoll",
17555
+ "reindeer",
17556
+ "remora",
17557
+ "rhino",
17558
+ "roadrunner",
17559
+ "robin",
17560
+ "rook",
17561
+ "sable",
17562
+ "sailfish",
17563
+ "salamander",
17564
+ "salmon",
17565
+ "sandpiper",
17566
+ "sardine",
17567
+ "scallop",
17568
+ "scaup",
17569
+ "scorpion",
17570
+ "seahorse",
17571
+ "seal",
17572
+ "serval",
17573
+ "shark",
17574
+ "shearwater",
17575
+ "shrew",
17576
+ "shrike",
17577
+ "shrimp",
17578
+ "siskin",
17579
+ "sitatunga",
17580
+ "skate",
17581
+ "skink",
17582
+ "skua",
17583
+ "skunk",
17584
+ "sloth",
17585
+ "smelt",
17586
+ "snail",
17587
+ "snipe",
17588
+ "solenodon",
17589
+ "sparrow",
17590
+ "spider",
17591
+ "springbok",
17592
+ "squid",
17593
+ "squirrel",
17594
+ "starfish",
17595
+ "starling",
17596
+ "stilt",
17597
+ "stingray",
17598
+ "stoat",
17599
+ "stork",
17600
+ "sunbird",
17601
+ "sunfish",
17602
+ "swallow",
17603
+ "swan",
17604
+ "swift",
17605
+ "swordfish",
17606
+ "tahr",
17607
+ "takin",
17608
+ "tamarin",
17609
+ "tanager",
17610
+ "tapir",
17611
+ "tarantula",
17612
+ "tarpon",
17613
+ "tarsier",
17614
+ "teal",
17615
+ "tenrec",
17616
+ "terrapin",
17617
+ "tern",
17618
+ "tetra",
17619
+ "thrasher",
17620
+ "thrush",
17621
+ "tiger",
17622
+ "toad",
17623
+ "tortoise",
17624
+ "toucan",
17625
+ "treecreeper",
17626
+ "treefrog",
17627
+ "trout",
17628
+ "tuatara",
17629
+ "tuna",
17630
+ "turkey",
17631
+ "turtle",
17632
+ "urchin",
17633
+ "urial",
17634
+ "vicuna",
17635
+ "viper",
17636
+ "vole",
17637
+ "vulture",
17638
+ "wagtail",
17639
+ "wallaby",
17640
+ "walleye",
17641
+ "walrus",
17642
+ "warbler",
17643
+ "warthog",
17644
+ "waterbuck",
17645
+ "weasel",
17646
+ "wildebeest",
17647
+ "wolf",
17648
+ "wolverine",
17649
+ "wombat",
17650
+ "woodcock",
17651
+ "woodpecker",
17652
+ "wrasse",
17653
+ "wren",
17654
+ "yak",
17655
+ "zebra",
17656
+ "zebu",
17657
+ "zorilla"
17658
+ ];
17659
+ });
17660
+
17661
+ // src/orchestrator/worktree/slug-allocator.ts
17662
+ class SlugAllocator {
17663
+ activeSlugs;
17664
+ random;
17665
+ pool;
17666
+ pendingByRepo = new Map;
17667
+ chain = Promise.resolve();
17668
+ constructor(activeSlugs, options = {}) {
17669
+ this.activeSlugs = activeSlugs;
17670
+ this.random = options.random ?? Math.random;
17671
+ this.pool = options.pool ?? ANIMAL_NAMES;
17672
+ if (this.pool.length === 0) {
17673
+ throw new Error("SlugAllocator: animal pool cannot be empty");
17674
+ }
17675
+ }
17676
+ async allocate(repo) {
17677
+ const previous = this.chain;
17678
+ let release;
17679
+ this.chain = new Promise((resolve3) => {
17680
+ release = resolve3;
17681
+ });
17682
+ await previous;
17683
+ try {
17684
+ return this.pickLocked(repo);
17685
+ } finally {
17686
+ release();
17687
+ }
17688
+ }
17689
+ commit(repo, slug) {
17690
+ this.deletePending(repo, slug);
17691
+ }
17692
+ cancel(repo, slug) {
17693
+ this.deletePending(repo, slug);
17694
+ }
17695
+ pickLocked(repo) {
17696
+ const occupied = this.occupiedSlugs(repo);
17697
+ const candidates = this.pool.filter((n2) => !occupied.has(n2));
17698
+ if (candidates.length > 0) {
17699
+ const pick = candidates[Math.floor(this.random() * candidates.length)];
17700
+ this.addPending(repo, pick);
17701
+ return pick;
17702
+ }
17703
+ const base = this.pool[Math.floor(this.random() * this.pool.length)];
17704
+ for (let v2 = 2;; v2++) {
17705
+ const candidate = `${base}-v${v2}`;
17706
+ if (!occupied.has(candidate)) {
17707
+ this.addPending(repo, candidate);
17708
+ return candidate;
17709
+ }
17710
+ }
17711
+ }
17712
+ occupiedSlugs(repo) {
17713
+ const set = new Set(this.pendingByRepo.get(repo) ?? []);
17714
+ for (const slug of this.activeSlugs(repo)) {
17715
+ if (slug)
17716
+ set.add(slug);
17717
+ }
17718
+ for (const dir of listWorktreeDirNames(repo)) {
17719
+ set.add(dir);
17720
+ }
17721
+ return set;
17722
+ }
17723
+ addPending(repo, slug) {
17724
+ let pending = this.pendingByRepo.get(repo);
17725
+ if (!pending) {
17726
+ pending = new Set;
17727
+ this.pendingByRepo.set(repo, pending);
17728
+ }
17729
+ pending.add(slug);
17730
+ }
17731
+ deletePending(repo, slug) {
17732
+ const pending = this.pendingByRepo.get(repo);
17733
+ if (!pending)
17734
+ return;
17735
+ pending.delete(slug);
17736
+ if (pending.size === 0)
17737
+ this.pendingByRepo.delete(repo);
17738
+ }
17739
+ }
17740
+ var init_slug_allocator = __esm(() => {
17741
+ init_animal_names();
17742
+ init_paths();
17743
+ });
17744
+
17187
17745
  // src/orchestrator/core.ts
17188
17746
  var exports_core = {};
17189
17747
  __export(exports_core, {
@@ -17246,6 +17804,8 @@ class Orchestrator {
17246
17804
  requestIdCounter = 0;
17247
17805
  sessionPump;
17248
17806
  pendingWorktreeOpts = new Map;
17807
+ slugAllocator;
17808
+ ensureWorktreeLatches = new Map;
17249
17809
  tasksAcc;
17250
17810
  setTasks;
17251
17811
  unsubscribeStore;
@@ -17275,6 +17835,7 @@ class Orchestrator {
17275
17835
  this.store = deps.store;
17276
17836
  this.worktrees = deps.worktrees;
17277
17837
  this.metadataSuggester = deps.metadataSuggester ?? new MetadataSuggester;
17838
+ 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
17839
  const [tasks, setTasks] = createSignal(this.store.list());
17279
17840
  this.tasksAcc = tasks;
17280
17841
  this.setTasks = (next) => setTasks(() => next);
@@ -17305,6 +17866,9 @@ class Orchestrator {
17305
17866
  modelForTab(task, tab, engine3) {
17306
17867
  return tab.model ?? task.model ?? engine3.capabilities.defaultModelId();
17307
17868
  }
17869
+ modelEffortForTab(task, tab) {
17870
+ return tab.modelEffort ?? task.modelEffort;
17871
+ }
17308
17872
  engineForTab(task, tab) {
17309
17873
  return this.engineForVendor(this.vendorForTab(task, tab));
17310
17874
  }
@@ -17469,26 +18033,49 @@ class Orchestrator {
17469
18033
  async ensureWorktree(task) {
17470
18034
  if (task.worktreePath)
17471
18035
  return task;
18036
+ const inflight = this.ensureWorktreeLatches.get(task.id);
18037
+ if (inflight) {
18038
+ await inflight;
18039
+ return this.requireTask(task.id);
18040
+ }
18041
+ const latch = this.doEnsureWorktree(task);
18042
+ this.ensureWorktreeLatches.set(task.id, latch);
18043
+ try {
18044
+ return await latch;
18045
+ } finally {
18046
+ this.ensureWorktreeLatches.delete(task.id);
18047
+ }
18048
+ }
18049
+ async doEnsureWorktree(task) {
17472
18050
  const opts = this.pendingWorktreeOpts.get(task.id);
17473
18051
  const branch = opts?.branch ?? `kobe/tmp-${task.id.slice(-8).toLowerCase()}`;
17474
18052
  const baseRef = opts?.baseRef;
18053
+ const slug = await this.slugAllocator.allocate(task.repo);
17475
18054
  let info;
17476
18055
  try {
17477
18056
  info = await this.worktrees.createForTask({
17478
18057
  repo: task.repo,
17479
- taskId: task.id,
18058
+ slug,
17480
18059
  branch,
17481
18060
  baseRef
17482
18061
  });
17483
18062
  } catch (err) {
18063
+ this.slugAllocator.cancel(task.repo, slug);
17484
18064
  const message = err instanceof Error ? err.message : String(err);
17485
18065
  throw new Error(summarizeWorktreeError(message, task.repo, baseRef ?? null), { cause: err });
17486
18066
  }
17487
- this.pendingWorktreeOpts.delete(task.id);
17488
- return await this.store.update(task.id, {
17489
- branch: info.branch,
17490
- worktreePath: info.path
17491
- });
18067
+ try {
18068
+ this.pendingWorktreeOpts.delete(task.id);
18069
+ const updated = await this.store.update(task.id, {
18070
+ branch: info.branch,
18071
+ worktreePath: info.path
18072
+ });
18073
+ this.slugAllocator.commit(task.repo, slug);
18074
+ return updated;
18075
+ } catch (err) {
18076
+ this.slugAllocator.cancel(task.repo, slug);
18077
+ throw err;
18078
+ }
17492
18079
  }
17493
18080
  async maybeRenameTempBranch(taskId, tabId, prompt) {
17494
18081
  if (!prompt || prompt.trim().length === 0)
@@ -17586,13 +18173,15 @@ class Orchestrator {
17586
18173
  }
17587
18174
  const engine3 = targetTab.sessionId ? await this.engineForTabRun(task, targetTab) : this.engineForTab(task, targetTab);
17588
18175
  const modelToUse = this.modelForTab(task, targetTab, engine3);
18176
+ const modelEffortToUse = this.modelEffortForTab(task, targetTab);
17589
18177
  let handle;
17590
18178
  if (targetTab.sessionId) {
17591
18179
  handle = await engine3.resume(targetTab.sessionId, promptToSend, {
17592
18180
  cwd: task.worktreePath,
17593
18181
  env: { KOBE_RESUME_CWD: task.worktreePath },
17594
18182
  permissionMode: task.permissionMode,
17595
- model: modelToUse
18183
+ model: modelToUse,
18184
+ modelEffort: modelEffortToUse
17596
18185
  });
17597
18186
  } else {
17598
18187
  let releaseLatch = () => {};
@@ -17603,7 +18192,8 @@ class Orchestrator {
17603
18192
  try {
17604
18193
  handle = await engine3.spawn(task.worktreePath, promptToSend, {
17605
18194
  permissionMode: task.permissionMode,
17606
- model: modelToUse
18195
+ model: modelToUse,
18196
+ modelEffort: modelEffortToUse
17607
18197
  });
17608
18198
  await this.updateTab(task.id, targetTab.id, { sessionId: handle.sessionId });
17609
18199
  if (task.title === PLACEHOLDER_TASK_TITLE && prompt && prompt.trim().length > 0) {
@@ -17718,13 +18308,13 @@ class Orchestrator {
17718
18308
  return;
17719
18309
  await this.store.update(task.id, { permissionMode: mode });
17720
18310
  }
17721
- async setModel(id, model, tabId) {
18311
+ async setModel(id, model, tabId, modelEffort) {
17722
18312
  const task = this.requireTask(id);
17723
18313
  const tab = this.resolveTab(task, tabId);
17724
18314
  const vendor = model ? capabilitiesForModelId(model).vendorId : this.vendorForTab(task, tab);
17725
- if (tab.model === model && this.vendorForTab(task, tab) === vendor)
18315
+ if (tab.model === model && tab.modelEffort === modelEffort && this.vendorForTab(task, tab) === vendor)
17726
18316
  return;
17727
- await this.updateTab(task.id, tab.id, { model, vendor });
18317
+ await this.updateTab(task.id, tab.id, { model, modelEffort, vendor });
17728
18318
  }
17729
18319
  async setTitle(id, title) {
17730
18320
  const task = this.requireTask(id);
@@ -18098,6 +18688,7 @@ var init_core = __esm(() => {
18098
18688
  init_metadata_suggester();
18099
18689
  init_pr();
18100
18690
  init_session_pump();
18691
+ init_slug_allocator();
18101
18692
  IllegalTransitionError = class IllegalTransitionError extends Error {
18102
18693
  from;
18103
18694
  to;
@@ -18293,8 +18884,8 @@ class RemoteOrchestrator {
18293
18884
  async setPermissionMode(taskId, mode) {
18294
18885
  await this.client.request("task.permissionMode", { taskId, mode });
18295
18886
  }
18296
- async setModel(taskId, model, tabId) {
18297
- await this.client.request("task.model", { taskId, model, tabId });
18887
+ async setModel(taskId, model, tabId, modelEffort) {
18888
+ await this.client.request("task.model", { taskId, model, tabId, modelEffort });
18298
18889
  }
18299
18890
  async createTab(taskId, opts = {}) {
18300
18891
  const res = await this.client.request("chat.tab.create", { taskId, title: opts.title });
@@ -18554,7 +19145,7 @@ class GitWorktreeManager {
18554
19145
  return info;
18555
19146
  }
18556
19147
  async createForTask(args) {
18557
- const target = worktreePathFor(args.repo, args.taskId);
19148
+ const target = worktreePathFor(args.repo, args.slug);
18558
19149
  return this.create(args.repo, args.branch, target, args.baseRef);
18559
19150
  }
18560
19151
  async remove(worktreePath, opts) {
@@ -20303,6 +20894,17 @@ var init_notifications = __esm(() => {
20303
20894
  ctx3 = createContext();
20304
20895
  });
20305
20896
 
20897
+ // src/tui/component/center-tab-strip-parts.ts
20898
+ function chatTabMarkerKind(input) {
20899
+ if (input.runState === "running")
20900
+ return "running";
20901
+ if (input.runState === "awaiting_input")
20902
+ return "awaiting_input";
20903
+ if (input.isPrimary || input.unreadKind === undefined)
20904
+ return null;
20905
+ return input.unreadKind === "needs_input" ? "unread_needs_input" : "unread_done";
20906
+ }
20907
+
20306
20908
  // src/tui/component/center-tab-strip.tsx
20307
20909
  import { basename as basename3 } from "path";
20308
20910
  import { TextAttributes as TextAttributes8 } from "@opentui/core";
@@ -20359,29 +20961,28 @@ function CenterTabStrip(props) {
20359
20961
  return;
20360
20962
  return props.chatRunState().get(chatRunStateKey(taskId, tab.id));
20361
20963
  };
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
20964
  const unreadKind = () => {
20375
20965
  const taskId = props.activeTaskId();
20376
20966
  if (!taskId)
20377
20967
  return;
20378
20968
  return props.unread().get(notificationKey(taskId, tab.id));
20379
20969
  };
20380
- const showUnread = () => !isPrimary() && unreadKind() !== undefined;
20381
- const unreadColor = () => unreadKind() === "needs_input" ? theme.warning : theme.success;
20970
+ const markerKind = () => chatTabMarkerKind({
20971
+ runState: runState(),
20972
+ unreadKind: unreadKind(),
20973
+ isPrimary: isPrimary()
20974
+ });
20975
+ const markerColor = () => {
20976
+ const kind = markerKind();
20977
+ if (kind === "awaiting_input" || kind === "unread_needs_input")
20978
+ return theme.warning;
20979
+ if (kind === "running" || kind === "unread_done")
20980
+ return theme.success;
20981
+ return theme.textMuted;
20982
+ };
20382
20983
  return (() => {
20383
- var _el$5 = createElement("box"), _el$7 = createElement("text");
20384
- insertNode(_el$5, _el$7);
20984
+ var _el$5 = createElement("box"), _el$8 = createElement("text");
20985
+ insertNode(_el$5, _el$8);
20385
20986
  setProp(_el$5, "flexDirection", "row");
20386
20987
  setProp(_el$5, "gap", 1);
20387
20988
  setProp(_el$5, "paddingLeft", 1);
@@ -20393,35 +20994,23 @@ function CenterTabStrip(props) {
20393
20994
  });
20394
20995
  insert(_el$5, createComponent2(Show, {
20395
20996
  get when() {
20396
- return dotGlyph().length > 0;
20997
+ return markerKind() !== null;
20397
20998
  },
20398
20999
  get children() {
20399
21000
  var _el$6 = createElement("text");
21001
+ insertNode(_el$6, createTextNode(`\u25CF`));
20400
21002
  setProp(_el$6, "wrapMode", "none");
20401
- insert(_el$6, dotGlyph);
20402
- effect((_$p) => setProp(_el$6, "fg", dotColor(), _$p));
21003
+ effect((_$p) => setProp(_el$6, "fg", markerColor(), _$p));
20403
21004
  return _el$6;
20404
21005
  }
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);
21006
+ }), _el$8);
21007
+ setProp(_el$8, "wrapMode", "none");
21008
+ insert(_el$8, () => chatTabLabel(tab));
20420
21009
  effect((_p$) => {
20421
21010
  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
21011
  _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));
21012
+ _v$5 !== _p$.t && (_p$.t = setProp(_el$8, "fg", _v$5, _p$.t));
21013
+ _v$6 !== _p$.a && (_p$.a = setProp(_el$8, "attributes", _v$6, _p$.a));
20425
21014
  return _p$;
20426
21015
  }, {
20427
21016
  e: undefined,
@@ -20441,24 +21030,24 @@ function CenterTabStrip(props) {
20441
21030
  children: (file) => {
20442
21031
  const isActive = () => !props.isChatActive();
20443
21032
  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())));
21033
+ var _el$9 = createElement("box"), _el$0 = createElement("text"), _el$1 = createElement("text");
21034
+ insertNode(_el$9, _el$0);
21035
+ insertNode(_el$9, _el$1);
21036
+ setProp(_el$9, "flexDirection", "row");
21037
+ setProp(_el$9, "gap", 1);
21038
+ setProp(_el$9, "paddingLeft", 1);
21039
+ setProp(_el$9, "paddingRight", 1);
21040
+ setProp(_el$9, "onMouseUp", () => props.onSelectFile(file()));
21041
+ setProp(_el$0, "wrapMode", "none");
21042
+ insert(_el$0, () => basename3(file()));
21043
+ insertNode(_el$1, createTextNode(`x`));
21044
+ setProp(_el$1, "onMouseUp", () => queueMicrotask(() => props.onCloseFile(file())));
20456
21045
  effect((_p$) => {
20457
21046
  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));
21047
+ _v$7 !== _p$.e && (_p$.e = setProp(_el$9, "backgroundColor", _v$7, _p$.e));
21048
+ _v$8 !== _p$.t && (_p$.t = setProp(_el$0, "fg", _v$8, _p$.t));
21049
+ _v$9 !== _p$.a && (_p$.a = setProp(_el$0, "attributes", _v$9, _p$.a));
21050
+ _v$0 !== _p$.o && (_p$.o = setProp(_el$1, "fg", _v$0, _p$.o));
20462
21051
  return _p$;
20463
21052
  }, {
20464
21053
  e: undefined,
@@ -20466,7 +21055,7 @@ function CenterTabStrip(props) {
20466
21055
  a: undefined,
20467
21056
  o: undefined
20468
21057
  });
20469
- return _el$0;
21058
+ return _el$9;
20470
21059
  })();
20471
21060
  }
20472
21061
  }), null);
@@ -21893,6 +22482,19 @@ var init_open_worktree_button = __esm(() => {
21893
22482
  init_worktree_opener();
21894
22483
  });
21895
22484
 
22485
+ // src/tui/component/top-bar-helpers.ts
22486
+ function formatSessionIdLabel(sessionId) {
22487
+ if (!sessionId)
22488
+ return null;
22489
+ return `sid ${sessionId}`;
22490
+ }
22491
+ function activeTaskSessionId(task, activeChatTabId) {
22492
+ if (!task)
22493
+ return null;
22494
+ const tabId = activeChatTabId ?? task.activeTabId;
22495
+ return task.tabs.find((tab) => tab.id === tabId)?.sessionId ?? null;
22496
+ }
22497
+
21896
22498
  // src/tui/panes/chat/markdown-parser.ts
21897
22499
  function splitTableRow(line) {
21898
22500
  const trimmed = line.trim().replace(/^\||\|$/g, "");
@@ -22846,6 +23448,7 @@ function TopBar(props) {
22846
23448
  const remoteOrch = props.orchestrator instanceof RemoteOrchestrator ? props.orchestrator : null;
22847
23449
  const rcBridge = props.orchestrator.rcBridgeSignal();
22848
23450
  const isBridgeOn = () => rcBridge().state === "running" || rcBridge().state === "starting";
23451
+ const sessionIdLabel = createMemo(() => formatSessionIdLabel(activeTaskSessionId(props.activeTask(), props.activeChatTabId?.())));
22849
23452
  async function confirmUpdate() {
22850
23453
  const info = props.updateInfo();
22851
23454
  if (!info?.hasUpdate)
@@ -22880,10 +23483,10 @@ function TopBar(props) {
22880
23483
  process.exit(code);
22881
23484
  }
22882
23485
  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");
23486
+ 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
23487
  insertNode(_el$, _el$2);
22885
23488
  insertNode(_el$, _el$13);
22886
- insertNode(_el$, _el$15);
23489
+ insertNode(_el$, _el$16);
22887
23490
  setProp(_el$, "flexDirection", "row");
22888
23491
  setProp(_el$, "paddingLeft", 2);
22889
23492
  setProp(_el$, "paddingRight", 2);
@@ -22975,19 +23578,19 @@ function TopBar(props) {
22975
23578
  },
22976
23579
  get fallback() {
22977
23580
  return (() => {
22978
- var _el$16 = createElement("text");
22979
- insertNode(_el$16, createTextNode(`daemon disconnected`));
22980
- setProp(_el$16, "wrapMode", "none");
23581
+ var _el$17 = createElement("text");
23582
+ insertNode(_el$17, createTextNode(`daemon disconnected`));
23583
+ setProp(_el$17, "wrapMode", "none");
22981
23584
  effect((_p$) => {
22982
23585
  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));
23586
+ _v$0 !== _p$.e && (_p$.e = setProp(_el$17, "fg", _v$0, _p$.e));
23587
+ _v$1 !== _p$.t && (_p$.t = setProp(_el$17, "attributes", _v$1, _p$.t));
22985
23588
  return _p$;
22986
23589
  }, {
22987
23590
  e: undefined,
22988
23591
  t: undefined
22989
23592
  });
22990
- return _el$16;
23593
+ return _el$17;
22991
23594
  })();
22992
23595
  },
22993
23596
  get children() {
@@ -22996,13 +23599,29 @@ function TopBar(props) {
22996
23599
  return props.activeTask() !== undefined;
22997
23600
  },
22998
23601
  get children() {
22999
- var _el$14 = createElement("text");
23000
- setProp(_el$14, "wrapMode", "none");
23001
- insert(_el$14, () => props.activeTask()?.branch);
23602
+ var _el$14 = createElement("box"), _el$15 = createElement("text");
23603
+ insertNode(_el$14, _el$15);
23604
+ setProp(_el$14, "flexDirection", "row");
23605
+ setProp(_el$14, "gap", 2);
23606
+ setProp(_el$14, "justifyContent", "center");
23607
+ setProp(_el$15, "wrapMode", "none");
23608
+ insert(_el$15, () => props.activeTask()?.branch);
23609
+ insert(_el$14, createComponent2(Show, {
23610
+ get when() {
23611
+ return sessionIdLabel();
23612
+ },
23613
+ children: (label) => (() => {
23614
+ var _el$19 = createElement("text");
23615
+ setProp(_el$19, "wrapMode", "none");
23616
+ insert(_el$19, label);
23617
+ effect((_$p) => setProp(_el$19, "fg", theme.textMuted, _$p));
23618
+ return _el$19;
23619
+ })()
23620
+ }), null);
23002
23621
  effect((_p$) => {
23003
23622
  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));
23623
+ _v$5 !== _p$.e && (_p$.e = setProp(_el$15, "fg", _v$5, _p$.e));
23624
+ _v$6 !== _p$.t && (_p$.t = setProp(_el$15, "attributes", _v$6, _p$.t));
23006
23625
  return _p$;
23007
23626
  }, {
23008
23627
  e: undefined,
@@ -23013,13 +23632,13 @@ function TopBar(props) {
23013
23632
  });
23014
23633
  }
23015
23634
  }));
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, {
23635
+ setProp(_el$16, "flexDirection", "row");
23636
+ setProp(_el$16, "flexGrow", 1);
23637
+ setProp(_el$16, "flexShrink", 1);
23638
+ setProp(_el$16, "flexBasis", 0);
23639
+ setProp(_el$16, "gap", 2);
23640
+ setProp(_el$16, "justifyContent", "flex-end");
23641
+ insert(_el$16, createComponent2(OpenWorktreeButton, {
23023
23642
  get activeTask() {
23024
23643
  return props.activeTask;
23025
23644
  },
@@ -23027,7 +23646,7 @@ function TopBar(props) {
23027
23646
  return props.worktreeOpener;
23028
23647
  }
23029
23648
  }), null);
23030
- insert(_el$15, createComponent2(CreatePRButton, {
23649
+ insert(_el$16, createComponent2(CreatePRButton, {
23031
23650
  get orchestrator() {
23032
23651
  return props.orchestrator;
23033
23652
  },
@@ -23451,7 +24070,12 @@ class SessionRegistry {
23451
24070
  }
23452
24071
  this.handles.set(handle.sessionId, handle);
23453
24072
  }
23454
- unregister(sessionId) {
24073
+ unregister(sessionId, proc) {
24074
+ if (proc) {
24075
+ const existing = this.handles.get(sessionId);
24076
+ if (existing && existing.proc !== proc)
24077
+ return;
24078
+ }
23455
24079
  this.handles.delete(sessionId);
23456
24080
  }
23457
24081
  get(sessionId) {
@@ -23611,6 +24235,9 @@ function buildArgs(opts) {
23611
24235
  if (opts.model) {
23612
24236
  args2.push("--model", opts.model);
23613
24237
  }
24238
+ if (opts.modelEffort) {
24239
+ args2.push("--effort", opts.modelEffort);
24240
+ }
23614
24241
  if (opts.permissionMode) {
23615
24242
  args2.push("--permission-mode", opts.permissionMode);
23616
24243
  }
@@ -23847,6 +24474,7 @@ class ClaudeCodeLocal {
23847
24474
  cwd: args2.cwd,
23848
24475
  prompt: args2.prompt,
23849
24476
  model: args2.opts?.model,
24477
+ modelEffort: args2.opts?.modelEffort,
23850
24478
  permissionMode: cliPermissionMode,
23851
24479
  env: args2.opts?.env,
23852
24480
  resumeSessionId: args2.resumeSessionId
@@ -23922,7 +24550,7 @@ class ClaudeCodeLocal {
23922
24550
  if (session) {
23923
24551
  session.closed = true;
23924
24552
  this.notify(session);
23925
- this.registry.unregister(session.sessionId);
24553
+ this.registry.unregister(session.sessionId, spawned.proc);
23926
24554
  }
23927
24555
  if (!bound) {
23928
24556
  rejectHandle(new Error("claude exited without emitting a session id"));
@@ -23998,6 +24626,36 @@ function isObject4(v2) {
23998
24626
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
23999
24627
  }
24000
24628
 
24629
+ // src/engine/codex-local/synthetic.ts
24630
+ function isSyntheticCodexUserRow(blocks) {
24631
+ if (blocks.length === 0)
24632
+ return false;
24633
+ for (const b2 of blocks) {
24634
+ if (b2.type !== "text")
24635
+ return false;
24636
+ const t2 = (b2.text ?? "").trim();
24637
+ if (!isEnvironmentContextEnvelope(t2) && !isInstructionsEnvelope(t2))
24638
+ return false;
24639
+ }
24640
+ return true;
24641
+ }
24642
+ function visibleCodexUserText(content) {
24643
+ const blocks = normalizeCodexContent(content);
24644
+ if (isSyntheticCodexUserRow(blocks))
24645
+ return null;
24646
+ const text = blocks.filter((b2) => b2.type === "text").map((b2) => b2.text).join(" ").trim();
24647
+ return text.length > 0 ? text : null;
24648
+ }
24649
+ function isEnvironmentContextEnvelope(text) {
24650
+ return text.startsWith("<environment_context>") && text.endsWith("</environment_context>");
24651
+ }
24652
+ function isInstructionsEnvelope(text) {
24653
+ return text.startsWith("# AGENTS.md instructions for ") && text.includes(`
24654
+ <INSTRUCTIONS>
24655
+ `) && text.endsWith("</INSTRUCTIONS>");
24656
+ }
24657
+ var init_synthetic = () => {};
24658
+
24001
24659
  // src/engine/codex-local/history.ts
24002
24660
  import { readFile as readFile5, readdir as readdir3, unlink as unlink3 } from "fs/promises";
24003
24661
  import { homedir as homedir13 } from "os";
@@ -24092,7 +24750,7 @@ function parseJsonl2(raw, sessionId) {
24092
24750
  if (role !== "user" && role !== "assistant" && role !== "system")
24093
24751
  continue;
24094
24752
  const blocks = normalizeCodexContent(payload.content);
24095
- if (role === "user" && isEnvironmentContextEnvelope(blocks))
24753
+ if (role === "user" && isSyntheticCodexUserRow(blocks))
24096
24754
  continue;
24097
24755
  const ts = typeof parsed.timestamp === "string" ? parsed.timestamp : new Date().toISOString();
24098
24756
  out.push({ role, blocks, timestamp: ts, sessionId });
@@ -24124,7 +24782,7 @@ function deriveCodexUsageMetrics(raw) {
24124
24782
  const payload = isObject5(parsed.payload) ? parsed.payload : undefined;
24125
24783
  if (payload?.type === "message" && payload.role === "user" && timestampMs !== null) {
24126
24784
  const blocks = normalizeCodexContent(payload.content);
24127
- if (!isEnvironmentContextEnvelope(blocks))
24785
+ if (!isSyntheticCodexUserRow(blocks))
24128
24786
  lastUserTimestampMs = timestampMs;
24129
24787
  }
24130
24788
  continue;
@@ -24200,23 +24858,12 @@ function mergedDurationMs(intervals) {
24200
24858
  function numberOr(v2, fallback) {
24201
24859
  return typeof v2 === "number" && Number.isFinite(v2) ? v2 : fallback;
24202
24860
  }
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
24861
  function isObject5(v2) {
24216
24862
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
24217
24863
  }
24218
24864
  var defaultDeps6;
24219
24865
  var init_history2 = __esm(() => {
24866
+ init_synthetic();
24220
24867
  defaultDeps6 = {
24221
24868
  sessionsDir() {
24222
24869
  return path11.join(homedir13(), ".codex", "sessions");
@@ -24271,47 +24918,46 @@ async function tryReadMeta(file) {
24271
24918
  return null;
24272
24919
  try {
24273
24920
  let buf = "";
24274
- let lineCount = 0;
24275
24921
  const processLine = (line) => {
24276
- lineCount++;
24277
24922
  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
- }
24923
+ if (!parsed)
24924
+ return;
24925
+ if (parsed.type === "session_meta") {
24926
+ const payload = parsed.payload;
24927
+ if (isObject6(payload)) {
24928
+ if (typeof payload.id === "string")
24929
+ sessionId = payload.id;
24930
+ if (typeof payload.cwd === "string")
24931
+ cwd = payload.cwd;
24932
+ }
24933
+ return;
24934
+ }
24935
+ if (parsed.type === "response_item" && isObject6(parsed.payload)) {
24936
+ const p2 = parsed.payload;
24937
+ if (p2.type === "message") {
24938
+ messageCount++;
24939
+ if (!firstUser && p2.role === "user") {
24940
+ const text = visibleCodexUserText(p2.content);
24941
+ if (text)
24942
+ firstUser = text.slice(0, PREVIEW_CHAR_CAP);
24294
24943
  }
24295
24944
  }
24296
24945
  }
24297
- return lineCount >= PREVIEW_HEAD_LINES;
24298
24946
  };
24299
24947
  const reader = handle.createReadStream({ encoding: "utf8" });
24300
- outer:
24301
- for await (const chunk of reader) {
24302
- buf += chunk;
24303
- let nl = buf.indexOf(`
24948
+ for await (const chunk of reader) {
24949
+ buf += chunk;
24950
+ let nl = buf.indexOf(`
24304
24951
  `);
24305
- while (nl !== -1) {
24306
- const line = buf.slice(0, nl);
24307
- buf = buf.slice(nl + 1);
24308
- nl = buf.indexOf(`
24952
+ while (nl !== -1) {
24953
+ const line = buf.slice(0, nl);
24954
+ buf = buf.slice(nl + 1);
24955
+ nl = buf.indexOf(`
24309
24956
  `);
24310
- if (processLine(line))
24311
- break outer;
24312
- }
24957
+ processLine(line);
24313
24958
  }
24314
- if (lineCount < PREVIEW_HEAD_LINES && buf.trim())
24959
+ }
24960
+ if (buf.trim())
24315
24961
  processLine(buf);
24316
24962
  } finally {
24317
24963
  await handle.close().catch(() => {});
@@ -24337,29 +24983,13 @@ function safeParse(line) {
24337
24983
  return null;
24338
24984
  }
24339
24985
  }
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
24986
  function isObject6(v2) {
24358
24987
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
24359
24988
  }
24360
- var PREVIEW_HEAD_LINES = 40, PREVIEW_CHAR_CAP = 200;
24989
+ var PREVIEW_CHAR_CAP = 200;
24361
24990
  var init_sessions2 = __esm(() => {
24362
24991
  init_history2();
24992
+ init_synthetic();
24363
24993
  });
24364
24994
 
24365
24995
  // src/engine/codex-local/spawn.ts
@@ -24391,6 +25021,9 @@ function buildArgs2(opts) {
24391
25021
  if (opts.model) {
24392
25022
  args2.push("-m", opts.model);
24393
25023
  }
25024
+ if (opts.modelEffort) {
25025
+ args2.push("-c", `model_reasoning_effort="${opts.modelEffort}"`);
25026
+ }
24394
25027
  if (!isResume) {
24395
25028
  args2.push("-C", opts.cwd);
24396
25029
  if (opts.permissionMode === "plan")
@@ -24428,8 +25061,8 @@ async function* parseStreamJson2(lines, opts = {}) {
24428
25061
  const type = typeof msg.type === "string" ? msg.type : undefined;
24429
25062
  if (!type)
24430
25063
  continue;
24431
- if (type === "thread.started") {
24432
- const sid = typeof msg.thread_id === "string" ? msg.thread_id : undefined;
25064
+ if (type === "session_meta" || type === "thread.started") {
25065
+ const sid = codexSessionId(msg);
24433
25066
  if (sid && !sessionIdEmitted) {
24434
25067
  sessionIdEmitted = true;
24435
25068
  opts.onSessionId?.(sid);
@@ -24515,6 +25148,15 @@ async function* readLines2(stream) {
24515
25148
  function isObject7(v2) {
24516
25149
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
24517
25150
  }
25151
+ function codexSessionId(msg) {
25152
+ if (msg.type === "session_meta") {
25153
+ const payload = isObject7(msg.payload) ? msg.payload : undefined;
25154
+ const id2 = payload?.id;
25155
+ return typeof id2 === "string" && id2.length > 0 ? id2 : undefined;
25156
+ }
25157
+ const id = msg.thread_id;
25158
+ return typeof id === "string" && id.length > 0 ? id : undefined;
25159
+ }
24518
25160
  function numberOr2(v2, fallback) {
24519
25161
  return typeof v2 === "number" && Number.isFinite(v2) ? v2 : fallback;
24520
25162
  }
@@ -24603,6 +25245,7 @@ class CodexLocal {
24603
25245
  cwd: args2.cwd,
24604
25246
  prompt: args2.prompt,
24605
25247
  model: args2.opts?.model,
25248
+ modelEffort: args2.opts?.modelEffort,
24606
25249
  permissionMode: args2.opts?.permissionMode,
24607
25250
  env: args2.opts?.env,
24608
25251
  resumeSessionId: args2.resumeSessionId
@@ -24616,9 +25259,18 @@ class CodexLocal {
24616
25259
  const queue = [];
24617
25260
  let session;
24618
25261
  let bound = false;
25262
+ let stderrTail = "";
24619
25263
  const bind = (sessionId) => {
24620
- if (bound)
25264
+ if (bound) {
25265
+ if (session && session.sessionId !== sessionId) {
25266
+ queue.push({
25267
+ type: "error",
25268
+ message: `codex resumed to a different session id (got ${sessionId}, expected ${session.sessionId})`
25269
+ });
25270
+ this.notify(session);
25271
+ }
24621
25272
  return;
25273
+ }
24622
25274
  bound = true;
24623
25275
  session = {
24624
25276
  sessionId,
@@ -24650,6 +25302,25 @@ class CodexLocal {
24650
25302
  throw err;
24651
25303
  }
24652
25304
  }
25305
+ captureStderrTail(spawned.stderr, (chunk) => {
25306
+ stderrTail = (stderrTail + chunk).slice(-STDERR_TAIL_CAP);
25307
+ });
25308
+ const exitInfo = {
25309
+ code: null,
25310
+ signal: null,
25311
+ seen: false
25312
+ };
25313
+ const exitObserved = new Promise((resolve4) => {
25314
+ spawned.proc.once("exit", (code, signal) => {
25315
+ exitInfo.code = code;
25316
+ exitInfo.signal = signal;
25317
+ exitInfo.seen = true;
25318
+ if (!bound) {
25319
+ rejectHandle(new Error(formatExitMsg("codex exited before session id was captured", code, signal, stderrTail)));
25320
+ }
25321
+ resolve4();
25322
+ });
25323
+ });
24653
25324
  (async () => {
24654
25325
  const events = parseStreamJson2(readLines2(spawned.stdout), {
24655
25326
  onSessionId: (sid) => bind(sid)
@@ -24660,6 +25331,9 @@ class CodexLocal {
24660
25331
  queue.push(enriched);
24661
25332
  if (session)
24662
25333
  this.notify(session);
25334
+ if ((enriched.type === "done" || enriched.type === "error") && session) {
25335
+ this.registry.unregister(session.sessionId, spawned.proc);
25336
+ }
24663
25337
  }
24664
25338
  } catch (err) {
24665
25339
  const ev = {
@@ -24670,27 +25344,32 @@ class CodexLocal {
24670
25344
  if (session)
24671
25345
  this.notify(session);
24672
25346
  } finally {
25347
+ await Promise.race([exitObserved, new Promise((r2) => setTimeout(r2, 500))]);
24673
25348
  if (session) {
25349
+ const code = exitInfo.code;
25350
+ const lastEv = queue[queue.length - 1];
25351
+ if (exitInfo.seen && typeof code === "number" && code !== 0 && lastEv?.type !== "error") {
25352
+ queue.push({
25353
+ type: "error",
25354
+ message: formatExitMsg("codex exited", code, exitInfo.signal, stderrTail)
25355
+ });
25356
+ }
24674
25357
  session.closed = true;
24675
25358
  this.notify(session);
24676
- this.registry.unregister(session.sessionId);
24677
- this.running.delete(session.sessionId);
25359
+ this.registry.unregister(session.sessionId, spawned.proc);
25360
+ if (this.running.get(session.sessionId) === session) {
25361
+ this.running.delete(session.sessionId);
25362
+ }
24678
25363
  }
24679
25364
  if (!bound) {
24680
25365
  rejectHandle(new Error("codex exited without emitting a session id"));
24681
25366
  }
24682
25367
  }
24683
25368
  })();
24684
- drainStream2(spawned.stderr);
24685
25369
  spawned.proc.once("error", (err) => {
24686
25370
  if (!bound)
24687
25371
  rejectHandle(err);
24688
25372
  });
24689
- spawned.proc.once("exit", () => {
24690
- if (!bound) {
24691
- rejectHandle(new Error("codex exited before session id was captured"));
24692
- }
24693
- });
24694
25373
  return handlePromise;
24695
25374
  }
24696
25375
  notify(session) {
@@ -24700,22 +25379,37 @@ class CodexLocal {
24700
25379
  w2();
24701
25380
  }
24702
25381
  }
24703
- function drainStream2(stream) {
25382
+ function captureStderrTail(stream, onChunk) {
24704
25383
  const s2 = stream;
24705
- s2.on("data", () => {});
25384
+ s2.on("data", (chunk) => {
25385
+ onChunk(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
25386
+ });
24706
25387
  s2.on("error", () => {});
24707
25388
  }
25389
+ function formatExitMsg(prefix, code, signal, stderrTail) {
25390
+ const parts = [prefix];
25391
+ if (typeof code === "number")
25392
+ parts.push(`(code=${code}${signal ? `, signal=${signal}` : ""})`);
25393
+ else if (signal)
25394
+ parts.push(`(signal=${signal})`);
25395
+ const detail = stderrTail.trim().split(/\r?\n/).filter(Boolean).slice(-3).join(" | ");
25396
+ if (detail)
25397
+ parts.push(`: ${detail}`);
25398
+ return parts.join(" ").replace(/ : /, ": ");
25399
+ }
24708
25400
  function enrichUsageEvent2(ev, startedAtIso) {
24709
25401
  if (ev.type !== "usage")
24710
25402
  return ev;
24711
25403
  return { type: "usage", ...withTotalSpeedForTurn(ev, startedAtIso, new Date().toISOString()) };
24712
25404
  }
25405
+ var STDERR_TAIL_CAP;
24713
25406
  var init_codex_local = __esm(() => {
24714
25407
  init_binary2();
24715
25408
  init_capabilities2();
24716
25409
  init_history2();
24717
25410
  init_sessions2();
24718
25411
  init_spawn2();
25412
+ STDERR_TAIL_CAP = 4 * 1024;
24719
25413
  });
24720
25414
 
24721
25415
  // test/behavior/fake-engine.ts
@@ -26675,6 +27369,11 @@ var init_keybindings2 = __esm(() => {
26675
27369
  ];
26676
27370
  });
26677
27371
 
27372
+ // src/tui/panes/chat/composer/keys.ts
27373
+ function isPermissionModeCycleKey(key) {
27374
+ return key.name === "tab" && key.shift === true || key.name === "backtab";
27375
+ }
27376
+
26678
27377
  // src/tui/panes/chat/composer/mention.ts
26679
27378
  async function getWorktreeFiles(worktreePath) {
26680
27379
  const cached3 = fileListCache.get(worktreePath);
@@ -26758,15 +27457,17 @@ var init_mention = __esm(() => {
26758
27457
  fileListCache = new Map;
26759
27458
  });
26760
27459
 
26761
- // src/tui/panes/chat/Composer.tsx
26762
- import { TextAttributes as TextAttributes22 } from "@opentui/core";
27460
+ // src/tui/panes/chat/composer/placeholder.ts
26763
27461
  function resolvePlaceholder(opts) {
26764
27462
  if (!opts.hasTask)
26765
27463
  return opts.noTaskMessage ?? "(no task \u2014 press n to create)";
26766
27464
  if (opts.isStreaming)
26767
- return "(streaming \u2014 enter to queue, ctrl+enter to steer)";
27465
+ return "";
26768
27466
  return opts.inputPlaceholder ?? "Ask Claude\u2026";
26769
27467
  }
27468
+
27469
+ // src/tui/panes/chat/Composer.tsx
27470
+ import { TextAttributes as TextAttributes22 } from "@opentui/core";
26770
27471
  function Composer(props) {
26771
27472
  const {
26772
27473
  theme
@@ -27089,7 +27790,7 @@ function Composer(props) {
27089
27790
  key.preventDefault();
27090
27791
  return;
27091
27792
  }
27092
- if (key.name === "tab" && key.shift) {
27793
+ if (isPermissionModeCycleKey(key)) {
27093
27794
  if (props.onCyclePermissionMode) {
27094
27795
  props.onCyclePermissionMode();
27095
27796
  key.preventDefault();
@@ -27230,10 +27931,11 @@ function Composer(props) {
27230
27931
  };
27231
27932
  const footerHint = () => pasteHint() ?? streamingNotice();
27232
27933
  const modelLabel = () => props.modelLabel?.() ?? "";
27934
+ const permissionModeLabel = () => props.permissionModeLabel?.() ?? (props.permissionMode?.() === "plan" ? "plan mode" : "default");
27233
27935
  const modeBadge = createMemo(() => {
27234
27936
  const mode = props.permissionMode?.();
27235
27937
  return mode === "plan" ? {
27236
- label: "plan mode",
27938
+ label: permissionModeLabel(),
27237
27939
  tone: "primary"
27238
27940
  } : null;
27239
27941
  });
@@ -27258,9 +27960,9 @@ function Composer(props) {
27258
27960
  return theme.border;
27259
27961
  };
27260
27962
  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");
27963
+ 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
27964
  insertNode(_el$, _el$14);
27263
- insertNode(_el$, _el$30);
27965
+ insertNode(_el$, _el$32);
27264
27966
  setProp(_el$, "flexShrink", 0);
27265
27967
  setProp(_el$, "flexDirection", "column");
27266
27968
  setProp(_el$, "paddingTop", 1);
@@ -27307,35 +28009,35 @@ function Composer(props) {
27307
28009
  return idx >= 0 ? match.displayPath.slice(0, idx) : "";
27308
28010
  };
27309
28011
  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, {
28012
+ var _el$34 = createElement("box"), _el$35 = createElement("text");
28013
+ insertNode(_el$34, _el$35);
28014
+ setProp(_el$34, "flexDirection", "row");
28015
+ setProp(_el$34, "gap", 2);
28016
+ setProp(_el$35, "wrapMode", "none");
28017
+ insert(_el$35, () => active() ? "\u25B8 " : " ", null);
28018
+ insert(_el$35, filename, null);
28019
+ insert(_el$34, createComponent2(Show, {
27318
28020
  get when() {
27319
28021
  return directory().length > 0;
27320
28022
  },
27321
28023
  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;
28024
+ var _el$36 = createElement("text");
28025
+ setProp(_el$36, "wrapMode", "none");
28026
+ insert(_el$36, directory);
28027
+ effect((_$p) => setProp(_el$36, "fg", theme.textMuted, _$p));
28028
+ return _el$36;
27327
28029
  }
27328
28030
  }), null);
27329
28031
  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));
28032
+ var _v$24 = active() ? theme.primary : theme.text, _v$25 = active() ? TextAttributes22.BOLD : undefined;
28033
+ _v$24 !== _p$.e && (_p$.e = setProp(_el$35, "fg", _v$24, _p$.e));
28034
+ _v$25 !== _p$.t && (_p$.t = setProp(_el$35, "attributes", _v$25, _p$.t));
27333
28035
  return _p$;
27334
28036
  }, {
27335
28037
  e: undefined,
27336
28038
  t: undefined
27337
28039
  });
27338
- return _el$32;
28040
+ return _el$34;
27339
28041
  })();
27340
28042
  }
27341
28043
  }), null);
@@ -27402,47 +28104,47 @@ function Composer(props) {
27402
28104
  const absoluteIndex = () => slashWindow().start + i2();
27403
28105
  const active = () => absoluteIndex() === slashCursor();
27404
28106
  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, {
28107
+ var _el$37 = createElement("box"), _el$38 = createElement("text");
28108
+ insertNode(_el$37, _el$38);
28109
+ setProp(_el$37, "flexDirection", "row");
28110
+ setProp(_el$37, "gap", 2);
28111
+ setProp(_el$38, "wrapMode", "none");
28112
+ insert(_el$38, () => active() ? "\u25B8 " : " ", null);
28113
+ insert(_el$38, () => entry.display, null);
28114
+ insert(_el$37, createComponent2(Show, {
27413
28115
  get when() {
27414
28116
  return entry.source === "user";
27415
28117
  },
27416
28118
  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;
28119
+ var _el$39 = createElement("text");
28120
+ insertNode(_el$39, createTextNode(`user`));
28121
+ setProp(_el$39, "wrapMode", "none");
28122
+ effect((_$p) => setProp(_el$39, "fg", theme.textMuted, _$p));
28123
+ return _el$39;
27422
28124
  }
27423
28125
  }), null);
27424
- insert(_el$35, createComponent2(Show, {
28126
+ insert(_el$37, createComponent2(Show, {
27425
28127
  get when() {
27426
28128
  return entry.description;
27427
28129
  },
27428
28130
  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;
28131
+ var _el$41 = createElement("text");
28132
+ setProp(_el$41, "wrapMode", "none");
28133
+ insert(_el$41, () => entry.description);
28134
+ effect((_$p) => setProp(_el$41, "fg", theme.textMuted, _$p));
28135
+ return _el$41;
27434
28136
  }
27435
28137
  }), null);
27436
28138
  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));
28139
+ var _v$26 = active() ? theme.primary : theme.text, _v$27 = active() ? TextAttributes22.BOLD : undefined;
28140
+ _v$26 !== _p$.e && (_p$.e = setProp(_el$38, "fg", _v$26, _p$.e));
28141
+ _v$27 !== _p$.t && (_p$.t = setProp(_el$38, "attributes", _v$27, _p$.t));
27440
28142
  return _p$;
27441
28143
  }, {
27442
28144
  e: undefined,
27443
28145
  t: undefined
27444
28146
  });
27445
- return _el$35;
28147
+ return _el$37;
27446
28148
  })();
27447
28149
  }
27448
28150
  }), null);
@@ -27496,37 +28198,37 @@ function Composer(props) {
27496
28198
  return (props.queue?.() ?? []).slice(0, QUEUE_VISIBLE_CAP);
27497
28199
  },
27498
28200
  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));
28201
+ 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");
28202
+ insertNode(_el$42, _el$43);
28203
+ insertNode(_el$42, _el$45);
28204
+ insertNode(_el$42, _el$48);
28205
+ insertNode(_el$42, _el$50);
28206
+ insertNode(_el$42, _el$52);
28207
+ setProp(_el$42, "flexDirection", "row");
28208
+ setProp(_el$42, "gap", 1);
28209
+ setProp(_el$42, "alignItems", "flex-start");
28210
+ insertNode(_el$43, createTextNode(`+`));
28211
+ insertNode(_el$45, _el$46);
28212
+ insertNode(_el$45, _el$47);
28213
+ setProp(_el$45, "wrapMode", "none");
28214
+ insert(_el$45, () => idx() === 0 ? " (next)" : "", _el$47);
28215
+ insertNode(_el$48, _el$49);
28216
+ setProp(_el$48, "flexGrow", 1);
28217
+ insert(_el$49, () => entry.text);
28218
+ insertNode(_el$50, createTextNode(`[\u25B6]`));
28219
+ setProp(_el$50, "onMouseUp", () => props.onSendQueuedNow?.(entry.id));
28220
+ insertNode(_el$52, createTextNode(`[x]`));
28221
+ setProp(_el$52, "onMouseUp", () => props.onCancelQueued?.(entry.id));
27520
28222
  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));
28223
+ 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;
28224
+ _v$28 !== _p$.e && (_p$.e = setProp(_el$43, "fg", _v$28, _p$.e));
28225
+ _v$29 !== _p$.t && (_p$.t = setProp(_el$43, "attributes", _v$29, _p$.t));
28226
+ _v$30 !== _p$.a && (_p$.a = setProp(_el$45, "fg", _v$30, _p$.a));
28227
+ _v$31 !== _p$.o && (_p$.o = setProp(_el$49, "fg", _v$31, _p$.o));
28228
+ _v$32 !== _p$.i && (_p$.i = setProp(_el$50, "fg", _v$32, _p$.i));
28229
+ _v$33 !== _p$.n && (_p$.n = setProp(_el$50, "attributes", _v$33, _p$.n));
28230
+ _v$34 !== _p$.s && (_p$.s = setProp(_el$52, "fg", _v$34, _p$.s));
28231
+ _v$35 !== _p$.h && (_p$.h = setProp(_el$52, "attributes", _v$35, _p$.h));
27530
28232
  return _p$;
27531
28233
  }, {
27532
28234
  e: undefined,
@@ -27538,7 +28240,7 @@ function Composer(props) {
27538
28240
  s: undefined,
27539
28241
  h: undefined
27540
28242
  });
27541
- return _el$40;
28243
+ return _el$42;
27542
28244
  })()
27543
28245
  }), null);
27544
28246
  insert(_el$16, createComponent2(Show, {
@@ -27587,10 +28289,10 @@ function Composer(props) {
27587
28289
  },
27588
28290
  get fallback() {
27589
28291
  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;
28292
+ var _el$54 = createElement("text");
28293
+ insert(_el$54, () => props.noTaskMessage ?? "(no task \u2014 press n to create)");
28294
+ effect((_$p) => setProp(_el$54, "fg", theme.textMuted, _$p));
28295
+ return _el$54;
27594
28296
  })();
27595
28297
  },
27596
28298
  get children() {
@@ -27636,7 +28338,7 @@ function Composer(props) {
27636
28338
  return props.hasTask;
27637
28339
  },
27638
28340
  get children() {
27639
- var _el$25 = createElement("box"), _el$26 = createElement("text"), _el$27 = createElement("box"), _el$28 = createElement("box"), _el$29 = createElement("text");
28341
+ 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
28342
  insertNode(_el$25, _el$26);
27641
28343
  insertNode(_el$25, _el$27);
27642
28344
  setProp(_el$25, "flexDirection", "row");
@@ -27646,64 +28348,62 @@ function Composer(props) {
27646
28348
  setProp(_el$26, "wrapMode", "none");
27647
28349
  insert(_el$26, footerHint);
27648
28350
  insertNode(_el$27, _el$28);
28351
+ insertNode(_el$27, _el$30);
27649
28352
  setProp(_el$27, "flexDirection", "row");
27650
28353
  setProp(_el$27, "gap", 2);
27651
28354
  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
28355
  insertNode(_el$28, _el$29);
27665
28356
  setProp(_el$28, "flexDirection", "row");
27666
28357
  setProp(_el$28, "flexShrink", 0);
27667
- setProp(_el$28, "onMouseUp", () => props.onChooseModel?.());
28358
+ setProp(_el$28, "onMouseUp", () => props.onCyclePermissionMode?.());
27668
28359
  setProp(_el$29, "wrapMode", "none");
27669
- insert(_el$29, modelLabel, null);
27670
- insert(_el$29, () => props.onChooseModel ? " \u25BE" : "", null);
28360
+ insert(_el$29, permissionModeLabel, null);
28361
+ insert(_el$29, () => props.onCyclePermissionMode ? " \u25BE" : "", null);
28362
+ insertNode(_el$30, _el$31);
28363
+ setProp(_el$30, "flexDirection", "row");
28364
+ setProp(_el$30, "flexShrink", 0);
28365
+ setProp(_el$30, "onMouseUp", () => props.onChooseModel?.());
28366
+ setProp(_el$31, "wrapMode", "none");
28367
+ insert(_el$31, modelLabel, null);
28368
+ insert(_el$31, () => props.onChooseModel ? " \u25BE" : "", null);
27671
28369
  effect((_p$) => {
27672
- var _v$13 = props.isStreaming ? theme.accent : theme.textMuted, _v$14 = theme.textMuted;
28370
+ var _v$13 = props.isStreaming ? theme.accent : theme.textMuted, _v$14 = modeBadge() ? toneColor("primary") : theme.textMuted, _v$15 = theme.textMuted;
27673
28371
  _v$13 !== _p$.e && (_p$.e = setProp(_el$26, "fg", _v$13, _p$.e));
27674
28372
  _v$14 !== _p$.t && (_p$.t = setProp(_el$29, "fg", _v$14, _p$.t));
28373
+ _v$15 !== _p$.a && (_p$.a = setProp(_el$31, "fg", _v$15, _p$.a));
27675
28374
  return _p$;
27676
28375
  }, {
27677
28376
  e: undefined,
27678
- t: undefined
28377
+ t: undefined,
28378
+ a: undefined
27679
28379
  });
27680
28380
  return _el$25;
27681
28381
  }
27682
28382
  }), 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"]);
28383
+ insertNode(_el$32, _el$33);
28384
+ setProp(_el$32, "height", 1);
28385
+ setProp(_el$32, "border", ["left"]);
28386
+ setProp(_el$33, "height", 1);
28387
+ setProp(_el$33, "border", ["bottom"]);
27688
28388
  effect((_p$) => {
27689
- var _v$15 = railColor(), _v$16 = {
28389
+ var _v$16 = railColor(), _v$17 = {
27690
28390
  ...SplitBorder.customBorderChars,
27691
28391
  bottomLeft: "\u2579"
27692
- }, _v$17 = theme.backgroundElement, _v$18 = props.isStreaming ? theme.accent : theme.primary, _v$19 = railColor(), _v$20 = {
28392
+ }, _v$18 = theme.backgroundElement, _v$19 = props.isStreaming ? theme.accent : theme.primary, _v$20 = railColor(), _v$21 = {
27693
28393
  ...EmptyBorder,
27694
28394
  vertical: theme.backgroundElement.a !== 0 ? "\u2579" : " "
27695
- }, _v$21 = theme.backgroundElement, _v$22 = {
28395
+ }, _v$22 = theme.backgroundElement, _v$23 = {
27696
28396
  ...EmptyBorder,
27697
28397
  horizontal: theme.backgroundElement.a !== 0 ? "\u2580" : " "
27698
28398
  };
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));
28399
+ _v$16 !== _p$.e && (_p$.e = setProp(_el$14, "borderColor", _v$16, _p$.e));
28400
+ _v$17 !== _p$.t && (_p$.t = setProp(_el$14, "customBorderChars", _v$17, _p$.t));
28401
+ _v$18 !== _p$.a && (_p$.a = setProp(_el$15, "backgroundColor", _v$18, _p$.a));
28402
+ _v$19 !== _p$.o && (_p$.o = setProp(_el$22, "fg", _v$19, _p$.o));
28403
+ _v$20 !== _p$.i && (_p$.i = setProp(_el$32, "borderColor", _v$20, _p$.i));
28404
+ _v$21 !== _p$.n && (_p$.n = setProp(_el$32, "customBorderChars", _v$21, _p$.n));
28405
+ _v$22 !== _p$.s && (_p$.s = setProp(_el$33, "borderColor", _v$22, _p$.s));
28406
+ _v$23 !== _p$.h && (_p$.h = setProp(_el$33, "customBorderChars", _v$23, _p$.h));
27707
28407
  return _p$;
27708
28408
  }, {
27709
28409
  e: undefined,
@@ -30092,6 +30792,25 @@ var init_MessageList = __esm(() => {
30092
30792
  BLACK_CIRCLE = process.platform === "darwin" ? "\u23FA" : "\u25CF";
30093
30793
  });
30094
30794
 
30795
+ // src/tui/panes/chat/composer/model-picker-row.ts
30796
+ function modelPickerRowParts(choice) {
30797
+ const caps = getCapabilities(choice.vendor);
30798
+ return {
30799
+ level: choice.level ?? "level1",
30800
+ vendor: choice.vendor,
30801
+ engine: caps.label,
30802
+ from: "catalog",
30803
+ model: choice.label,
30804
+ hint: choice.hint
30805
+ };
30806
+ }
30807
+ function modelPickerMetaLabel(parts) {
30808
+ return `${parts.level} ${parts.vendor} ${parts.engine} from ${parts.from}`;
30809
+ }
30810
+ var init_model_picker_row = __esm(() => {
30811
+ init_registry2();
30812
+ });
30813
+
30095
30814
  // src/tui/panes/chat/composer/ModelPicker.tsx
30096
30815
  import { TextAttributes as TextAttributes24 } from "@opentui/core";
30097
30816
  function ModelPicker(props) {
@@ -30101,13 +30820,16 @@ function ModelPicker(props) {
30101
30820
  } = useTheme();
30102
30821
  const choices = createMemo(() => allModels());
30103
30822
  const seed = props.current ?? defaultCapabilities.defaultModelId();
30104
- const initial = choices().findIndex((m2) => m2.id === seed);
30823
+ const initial = choices().findIndex((m2) => m2.id === seed && m2.effort === props.currentEffort);
30105
30824
  const [cursor, setCursor] = createSignal(initial >= 0 ? initial : 0);
30106
30825
  function commit() {
30107
30826
  const choice = choices()[cursor()];
30108
30827
  if (!choice)
30109
30828
  return;
30110
- props.onPick(choice.id);
30829
+ props.onPick({
30830
+ id: choice.id,
30831
+ effort: choice.effort
30832
+ });
30111
30833
  dialog.clear();
30112
30834
  }
30113
30835
  useBindings(() => ({
@@ -30171,9 +30893,11 @@ function ModelPicker(props) {
30171
30893
  },
30172
30894
  children: (choice, i2) => {
30173
30895
  const active = () => i2() === cursor();
30896
+ const parts = () => modelPickerRowParts(choice);
30174
30897
  return (() => {
30175
- var _el$1 = createElement("box"), _el$10 = createElement("text");
30898
+ var _el$1 = createElement("box"), _el$10 = createElement("text"), _el$11 = createElement("text");
30176
30899
  insertNode(_el$1, _el$10);
30900
+ insertNode(_el$1, _el$11);
30177
30901
  setProp(_el$1, "flexDirection", "row");
30178
30902
  setProp(_el$1, "gap", 2);
30179
30903
  setProp(_el$1, "paddingLeft", 1);
@@ -30184,27 +30908,33 @@ function ModelPicker(props) {
30184
30908
  });
30185
30909
  setProp(_el$10, "wrapMode", "none");
30186
30910
  insert(_el$10, () => active() ? "\u25B8 " : " ", null);
30187
- insert(_el$10, () => choice.label, null);
30911
+ insert(_el$10, () => modelPickerMetaLabel(parts()), null);
30912
+ setProp(_el$11, "wrapMode", "none");
30913
+ insert(_el$11, () => parts().model);
30188
30914
  insert(_el$1, (() => {
30189
- var _c$ = memo2(() => !!choice.hint);
30915
+ var _c$ = memo2(() => !!parts().hint);
30190
30916
  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;
30917
+ var _el$12 = createElement("text");
30918
+ setProp(_el$12, "wrapMode", "none");
30919
+ insert(_el$12, () => parts().hint);
30920
+ effect((_$p) => setProp(_el$12, "fg", active() ? theme.selectedListItemText : theme.textMuted, _$p));
30921
+ return _el$12;
30196
30922
  })() : null;
30197
30923
  })(), null);
30198
30924
  effect((_p$) => {
30199
- var _v$5 = active() ? theme.primary : undefined, _v$6 = active() ? theme.selectedListItemText : theme.text, _v$7 = active() ? TextAttributes24.BOLD : undefined;
30925
+ 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
30926
  _v$5 !== _p$.e && (_p$.e = setProp(_el$1, "backgroundColor", _v$5, _p$.e));
30201
30927
  _v$6 !== _p$.t && (_p$.t = setProp(_el$10, "fg", _v$6, _p$.t));
30202
30928
  _v$7 !== _p$.a && (_p$.a = setProp(_el$10, "attributes", _v$7, _p$.a));
30929
+ _v$8 !== _p$.o && (_p$.o = setProp(_el$11, "fg", _v$8, _p$.o));
30930
+ _v$9 !== _p$.i && (_p$.i = setProp(_el$11, "attributes", _v$9, _p$.i));
30203
30931
  return _p$;
30204
30932
  }, {
30205
30933
  e: undefined,
30206
30934
  t: undefined,
30207
- a: undefined
30935
+ a: undefined,
30936
+ o: undefined,
30937
+ i: undefined
30208
30938
  });
30209
30939
  return _el$1;
30210
30940
  })();
@@ -30243,17 +30973,25 @@ var init_ModelPicker = __esm(() => {
30243
30973
  init_theme();
30244
30974
  init_keymap();
30245
30975
  init_dialog();
30246
- ModelPicker.show = (dialog, current) => {
30976
+ init_model_picker_row();
30977
+ ModelPicker.show = (dialog, current, currentEffort) => {
30247
30978
  return new Promise((resolve4) => {
30248
30979
  dialog.replace(() => createComponent2(ModelPicker, {
30249
30980
  current,
30250
- onPick: (id) => resolve4(id),
30981
+ currentEffort,
30982
+ onPick: (choice) => resolve4(choice),
30251
30983
  onCancel: () => resolve4(undefined)
30252
30984
  }), () => resolve4(undefined));
30253
30985
  });
30254
30986
  };
30255
30987
  });
30256
30988
 
30989
+ // src/tui/panes/chat/composer/permission-mode.ts
30990
+ function permissionModeLabel(capabilities, mode) {
30991
+ const id = mode ?? "default";
30992
+ return capabilities.permissionModes.find((m2) => m2.id === id)?.label ?? id;
30993
+ }
30994
+
30257
30995
  // src/tui/panes/chat/composer/user-slashes.ts
30258
30996
  import { readFile as readFile6, readdir as readdir4, stat as stat4 } from "fs/promises";
30259
30997
  import { homedir as homedir15 } from "os";
@@ -31086,29 +31824,40 @@ function Chat(props) {
31086
31824
  const tab = task?.tabs.find((t2) => t2.id === activeTabId());
31087
31825
  return tab?.model ?? task?.model;
31088
31826
  });
31827
+ const modelEffort = createMemo(() => {
31828
+ const id = props.taskId();
31829
+ if (!id)
31830
+ return;
31831
+ const task = tasksAcc().find((t2) => t2.id === id);
31832
+ const tab = task?.tabs.find((t2) => t2.id === activeTabId());
31833
+ return tab?.modelEffort ?? task?.modelEffort;
31834
+ });
31089
31835
  const worktreePath = createMemo(() => {
31090
31836
  const id = props.taskId();
31091
31837
  if (!id)
31092
31838
  return;
31093
31839
  return tasksAcc().find((t2) => t2.id === id)?.worktreePath ?? undefined;
31094
31840
  });
31095
- const modelLabel = createMemo(() => modelLabelFor(modelId()));
31096
- const inputPlaceholder = createMemo(() => {
31841
+ const modelLabel = createMemo(() => modelLabelFor(modelId(), modelEffort()));
31842
+ const activeVendor = createMemo(() => {
31097
31843
  const id = props.taskId();
31098
31844
  const task = id ? tasksAcc().find((t2) => t2.id === id) : undefined;
31099
31845
  const tab = task?.tabs.find((t2) => t2.id === activeTabId());
31100
- const vendor = tab?.vendor ?? task?.vendor ?? "claude";
31101
- return getIdentity(vendor).inputPlaceholder;
31846
+ return tab?.vendor ?? task?.vendor ?? "claude";
31847
+ });
31848
+ const permissionModeText = createMemo(() => permissionModeLabel(getCapabilities(activeVendor()), permissionMode()));
31849
+ const inputPlaceholder = createMemo(() => {
31850
+ return getIdentity(activeVendor()).inputPlaceholder;
31102
31851
  });
31103
31852
  async function chooseModel() {
31104
31853
  const id = props.taskId();
31105
31854
  if (!id)
31106
31855
  return;
31107
31856
  const tabId = activeTabId() ?? undefined;
31108
- const result = await ModelPicker.show(dialog, modelId());
31857
+ const result = await ModelPicker.show(dialog, modelId(), modelEffort());
31109
31858
  if (result === undefined)
31110
31859
  return;
31111
- await props.orchestrator.setModel(id, result, tabId).catch((err) => {
31860
+ await props.orchestrator.setModel(id, result.id, tabId, result.effort).catch((err) => {
31112
31861
  console.error("[kobe] setModel failed:", err);
31113
31862
  });
31114
31863
  }
@@ -31594,6 +32343,7 @@ function Chat(props) {
31594
32343
  },
31595
32344
  slashes,
31596
32345
  permissionMode,
32346
+ permissionModeLabel: permissionModeText,
31597
32347
  onCyclePermissionMode: cyclePermissionMode,
31598
32348
  modelLabel,
31599
32349
  inputPlaceholder,
@@ -32616,7 +33366,8 @@ Try again or quit?`;
32616
33366
  onFocusPrev: () => {
32617
33367
  if (focusedPane() !== "workspace")
32618
33368
  focus.cycle(-1);
32619
- }
33369
+ },
33370
+ focusCycleEnabled: () => focusedPane() !== "workspace"
32620
33371
  });
32621
33372
  const {
32622
33373
  openNewTaskFlow,