@sma1lboy/kobe 0.5.4 → 0.5.5

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
@@ -41,6 +41,7 @@ var init_env = () => {};
41
41
  var exports_repos = {};
42
42
  __export(exports_repos, {
43
43
  statePath: () => statePath,
44
+ sameRepoToplevel: () => sameRepoToplevel,
44
45
  resolveRepoRoot: () => resolveRepoRoot,
45
46
  removeSavedRepo: () => removeSavedRepo,
46
47
  normalizeSavedRepos: () => normalizeSavedRepos,
@@ -67,6 +68,19 @@ function resolveRepoRoot(absPath) {
67
68
  } catch {}
68
69
  return top;
69
70
  }
71
+ function sameRepoToplevel(a, b) {
72
+ if (a === b)
73
+ return true;
74
+ const topA = resolveRepoRoot(a);
75
+ const topB = resolveRepoRoot(b);
76
+ if (topA === topB)
77
+ return true;
78
+ try {
79
+ return realpathSync(topA) === realpathSync(topB);
80
+ } catch {
81
+ return false;
82
+ }
83
+ }
70
84
  function statePath() {
71
85
  return kvStatePath();
72
86
  }
@@ -5494,6 +5508,38 @@ var init_keybindings = __esm(() => {
5494
5508
  description: "Previous chat tab",
5495
5509
  hint: { keys: "ctrl+[", label: "prev tab" }
5496
5510
  },
5511
+ {
5512
+ id: "chat.question.nav",
5513
+ scope: "workspace",
5514
+ keys: ["j", "k", "down", "up"],
5515
+ category: "Workspace",
5516
+ description: "Move highlight in question picker",
5517
+ hint: { keys: "j/k", label: "pick" }
5518
+ },
5519
+ {
5520
+ id: "chat.question.toggle",
5521
+ scope: "workspace",
5522
+ keys: ["space"],
5523
+ category: "Workspace",
5524
+ description: "Toggle highlighted option in question picker",
5525
+ hint: { keys: "space", label: "toggle" }
5526
+ },
5527
+ {
5528
+ id: "chat.question.submit",
5529
+ scope: "workspace",
5530
+ keys: ["return"],
5531
+ category: "Workspace",
5532
+ description: "Advance / submit question picker",
5533
+ hint: { keys: "enter", label: "submit" }
5534
+ },
5535
+ {
5536
+ id: "chat.question.pick-number",
5537
+ scope: "workspace",
5538
+ keys: ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
5539
+ category: "Workspace",
5540
+ description: "Pick option by number in question picker",
5541
+ hint: { keys: "1-9", label: "pick" }
5542
+ },
5497
5543
  {
5498
5544
  id: "files.nav",
5499
5545
  scope: "files",
@@ -6543,7 +6589,7 @@ function FileLine(props) {
6543
6589
  insertNode(_el$3, _el$4);
6544
6590
  setProp(_el$3, "paddingLeft", 1);
6545
6591
  setProp(_el$3, "paddingRight", 1);
6546
- setProp(_el$4, "wrapMode", "none");
6592
+ setProp(_el$4, "wrapMode", "word");
6547
6593
  insert(_el$4, () => props.text || " ");
6548
6594
  effect((_$p) => setProp(_el$4, "fg", theme.text, _$p));
6549
6595
  return _el$3;
@@ -8825,7 +8871,7 @@ var init_package = __esm(() => {
8825
8871
  package_default = {
8826
8872
  $schema: "https://json.schemastore.org/package.json",
8827
8873
  name: "@sma1lboy/kobe",
8828
- version: "0.5.4",
8874
+ version: "0.5.5",
8829
8875
  description: "TUI orchestrator for Claude Code (codename)",
8830
8876
  type: "module",
8831
8877
  packageManager: "bun@1.3.13",
@@ -8853,6 +8899,7 @@ var init_package = __esm(() => {
8853
8899
  "dev:test": "bun run scripts/dev-fixture.ts && KOBE_DEV=1 KOBE_TEST_ENGINE=dev-fake KOBE_HOME_DIR=$PWD/.dev-fixture/home bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
8854
8900
  "dev:test:reset": "bun run scripts/dev-fixture.ts --reset",
8855
8901
  build: "bun run scripts/build.ts",
8902
+ compile: "bun run scripts/compile.ts",
8856
8903
  typecheck: "tsc --noEmit",
8857
8904
  test: "vitest run --passWithNoTests",
8858
8905
  "test:behavior": "vitest run test/behavior --passWithNoTests",
@@ -10047,8 +10094,12 @@ async function connectOrStartDaemon() {
10047
10094
  const client = new KobeDaemonClient(socketPath);
10048
10095
  if (await canConnect(client))
10049
10096
  return client;
10050
- const entry = resolveKobedEntry();
10051
- const child = spawn2(process.execPath, [entry, "start"], {
10097
+ const { entry, runWithBun } = resolveKobedEntry();
10098
+ const child = runWithBun ? spawn2(process.execPath, [entry, "start"], {
10099
+ detached: true,
10100
+ stdio: "ignore",
10101
+ env: process.env
10102
+ }) : spawn2(entry, ["start"], {
10052
10103
  detached: true,
10053
10104
  stdio: "ignore",
10054
10105
  env: process.env
@@ -10080,14 +10131,23 @@ async function canConnect(client) {
10080
10131
  }
10081
10132
  function resolveKobedEntry() {
10082
10133
  const here = fileURLToPath(import.meta.url);
10134
+ if (here.startsWith("/$bunfs") || here.startsWith("B:\\~BUN")) {
10135
+ const exeDir = dirname4(process.execPath);
10136
+ const ext = process.platform === "win32" ? ".exe" : "";
10137
+ const sibling = join8(exeDir, `kobed${ext}`);
10138
+ if (!existsSync4(sibling)) {
10139
+ throw new Error(`kobe: standalone build expected sibling kobed binary at ${sibling}; extract the full release tarball.`);
10140
+ }
10141
+ return { entry: sibling, runWithBun: false };
10142
+ }
10083
10143
  const dir = dirname4(here);
10084
10144
  const sourceEntry = resolve2(dir, "../bin/kobed.ts");
10085
10145
  if (existsSync4(sourceEntry))
10086
- return sourceEntry;
10146
+ return { entry: sourceEntry, runWithBun: true };
10087
10147
  const distEntry = join8(dirname4(process.argv[1] ?? here), "bin", "kobed.js");
10088
10148
  if (existsSync4(distEntry))
10089
- return distEntry;
10090
- return join8(process.cwd(), "dist", "bin", "kobed.js");
10149
+ return { entry: distEntry, runWithBun: true };
10150
+ return { entry: join8(process.cwd(), "dist", "bin", "kobed.js"), runWithBun: true };
10091
10151
  }
10092
10152
  var init_daemon_process = __esm(() => {
10093
10153
  init_paths2();
@@ -10628,13 +10688,13 @@ class Orchestrator {
10628
10688
  throw new Error("ensureMainTask: repo is required");
10629
10689
  const normalized = resolveRepoRoot(repo);
10630
10690
  const all = this.store.list();
10631
- const candidates = all.filter((t) => t.kind === "main" && (t.repo === normalized || resolveRepoRoot(t.repo) === normalized));
10691
+ const candidates = all.filter((t) => t.kind === "main" && sameRepoToplevel(t.repo, normalized));
10632
10692
  const winner = candidates.find((t) => t.repo === normalized) ?? candidates[0];
10633
10693
  if (winner) {
10634
10694
  for (const dup of candidates) {
10635
10695
  if (dup.id !== winner.id) {
10636
10696
  try {
10637
- await this.deleteTask(dup.id);
10697
+ await this.store.remove(dup.id);
10638
10698
  } catch (err) {
10639
10699
  console.error(`[kobe orchestrator] ensureMainTask: failed to remove duplicate ${dup.id}:`, err);
10640
10700
  }
@@ -11961,7 +12021,7 @@ function SettingsDialog(props) {
11961
12021
  }
11962
12022
  function bodyRowCount() {
11963
12023
  if (section() === "general")
11964
- return themeNames().length + 1 + FOCUS_ACCENT_SLOTS.length;
12024
+ return themeNames().length + 1 + FOCUS_ACCENT_SLOTS.length + 2;
11965
12025
  if (section() === "dev")
11966
12026
  return devRowCount();
11967
12027
  return 0;
@@ -11978,6 +12038,30 @@ function SettingsDialog(props) {
11978
12038
  return null;
11979
12039
  return i;
11980
12040
  }
12041
+ function toastRowIndex() {
12042
+ return themeNames().length + 1 + FOCUS_ACCENT_SLOTS.length;
12043
+ }
12044
+ function soundRowIndex() {
12045
+ return toastRowIndex() + 1;
12046
+ }
12047
+ function isToastRow() {
12048
+ return section() === "general" && bodyRow() === toastRowIndex();
12049
+ }
12050
+ function isSoundRow() {
12051
+ return section() === "general" && bodyRow() === soundRowIndex();
12052
+ }
12053
+ function toastEnabled() {
12054
+ return props.kv.get("notifications.toast.enabled", true) !== false;
12055
+ }
12056
+ function soundEnabled() {
12057
+ return props.kv.get("notifications.sound.enabled", true) !== false;
12058
+ }
12059
+ function toggleToast() {
12060
+ props.kv.set("notifications.toast.enabled", !toastEnabled());
12061
+ }
12062
+ function toggleSound() {
12063
+ props.kv.set("notifications.sound.enabled", !soundEnabled());
12064
+ }
11981
12065
  function moveCursor(delta) {
11982
12066
  if (level() === "sidebar") {
11983
12067
  const next2 = (cursor() + delta + SECTIONS.length) % SECTIONS.length;
@@ -12120,6 +12204,14 @@ function SettingsDialog(props) {
12120
12204
  themeCtx.setFocusAccent(slot);
12121
12205
  return;
12122
12206
  }
12207
+ if (isToastRow()) {
12208
+ toggleToast();
12209
+ return;
12210
+ }
12211
+ if (isSoundRow()) {
12212
+ toggleSound();
12213
+ return;
12214
+ }
12123
12215
  const name = themeNames()[bodyRow()];
12124
12216
  if (name)
12125
12217
  themeCtx.set(name);
@@ -12140,10 +12232,10 @@ function SettingsDialog(props) {
12140
12232
  ]
12141
12233
  }));
12142
12234
  return (() => {
12143
- var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$7 = createElement("box"), _el$8 = createElement("box"), _el$9 = createElement("box"), _el$36 = createElement("box"), _el$37 = createElement("text");
12235
+ var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$7 = createElement("box"), _el$8 = createElement("box"), _el$9 = createElement("box"), _el$47 = createElement("box"), _el$48 = createElement("text");
12144
12236
  insertNode(_el$, _el$2);
12145
12237
  insertNode(_el$, _el$7);
12146
- insertNode(_el$, _el$36);
12238
+ insertNode(_el$, _el$47);
12147
12239
  setProp(_el$, "paddingLeft", 2);
12148
12240
  setProp(_el$, "paddingRight", 2);
12149
12241
  setProp(_el$, "paddingBottom", 1);
@@ -12169,28 +12261,28 @@ function SettingsDialog(props) {
12169
12261
  const isSection = () => i() === cursor();
12170
12262
  const isSidebarFocused = () => isSection() && level() === "sidebar";
12171
12263
  return (() => {
12172
- var _el$39 = createElement("box"), _el$40 = createElement("text");
12173
- insertNode(_el$39, _el$40);
12174
- setProp(_el$39, "paddingLeft", 1);
12175
- setProp(_el$39, "paddingRight", 1);
12176
- setProp(_el$39, "onMouseUp", () => {
12264
+ var _el$50 = createElement("box"), _el$51 = createElement("text");
12265
+ insertNode(_el$50, _el$51);
12266
+ setProp(_el$50, "paddingLeft", 1);
12267
+ setProp(_el$50, "paddingRight", 1);
12268
+ setProp(_el$50, "onMouseUp", () => {
12177
12269
  switchSection(s.id);
12178
12270
  setLevel("sidebar");
12179
12271
  });
12180
- setProp(_el$40, "wrapMode", "none");
12181
- insert(_el$40, () => s.label);
12272
+ setProp(_el$51, "wrapMode", "none");
12273
+ insert(_el$51, () => s.label);
12182
12274
  effect((_p$) => {
12183
- var _v$21 = isSidebarFocused() ? theme.primary : undefined, _v$22 = isSidebarFocused() ? theme.selectedListItemText : isSection() ? theme.accent : theme.textMuted, _v$23 = isSection() ? TextAttributes8.BOLD : undefined;
12184
- _v$21 !== _p$.e && (_p$.e = setProp(_el$39, "backgroundColor", _v$21, _p$.e));
12185
- _v$22 !== _p$.t && (_p$.t = setProp(_el$40, "fg", _v$22, _p$.t));
12186
- _v$23 !== _p$.a && (_p$.a = setProp(_el$40, "attributes", _v$23, _p$.a));
12275
+ var _v$30 = isSidebarFocused() ? theme.primary : undefined, _v$31 = isSidebarFocused() ? theme.selectedListItemText : isSection() ? theme.accent : theme.textMuted, _v$32 = isSection() ? TextAttributes8.BOLD : undefined;
12276
+ _v$30 !== _p$.e && (_p$.e = setProp(_el$50, "backgroundColor", _v$30, _p$.e));
12277
+ _v$31 !== _p$.t && (_p$.t = setProp(_el$51, "fg", _v$31, _p$.t));
12278
+ _v$32 !== _p$.a && (_p$.a = setProp(_el$51, "attributes", _v$32, _p$.a));
12187
12279
  return _p$;
12188
12280
  }, {
12189
12281
  e: undefined,
12190
12282
  t: undefined,
12191
12283
  a: undefined
12192
12284
  });
12193
- return _el$39;
12285
+ return _el$50;
12194
12286
  })();
12195
12287
  }
12196
12288
  }));
@@ -12203,12 +12295,13 @@ function SettingsDialog(props) {
12203
12295
  return section() === "general";
12204
12296
  },
12205
12297
  get children() {
12206
- var _el$0 = createElement("box"), _el$1 = createElement("text"), _el$11 = createElement("text"), _el$13 = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("text"), _el$17 = createElement("text"), _el$19 = createElement("box"), _el$20 = createElement("text"), _el$21 = createElement("box"), _el$22 = createElement("text"), _el$24 = createElement("text");
12298
+ var _el$0 = createElement("box"), _el$1 = createElement("text"), _el$11 = createElement("text"), _el$13 = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("text"), _el$17 = createElement("text"), _el$19 = createElement("box"), _el$20 = createElement("text"), _el$21 = createElement("box"), _el$22 = createElement("text"), _el$24 = createElement("text"), _el$26 = createElement("box"), _el$27 = createElement("text"), _el$29 = createElement("text"), _el$31 = createElement("box"), _el$32 = createElement("text"), _el$33 = createTextNode(` Toast`), _el$34 = createElement("box"), _el$35 = createElement("text"), _el$36 = createTextNode(` Sound`);
12207
12299
  insertNode(_el$0, _el$1);
12208
12300
  insertNode(_el$0, _el$11);
12209
12301
  insertNode(_el$0, _el$13);
12210
12302
  insertNode(_el$0, _el$14);
12211
12303
  insertNode(_el$0, _el$21);
12304
+ insertNode(_el$0, _el$26);
12212
12305
  setProp(_el$0, "flexDirection", "column");
12213
12306
  setProp(_el$0, "gap", 1);
12214
12307
  insertNode(_el$1, createTextNode(`Theme`));
@@ -12223,33 +12316,33 @@ function SettingsDialog(props) {
12223
12316
  const isCursor = () => level() === "body" && bodyRow() === i();
12224
12317
  const isSelected = () => name === themeCtx.selected;
12225
12318
  return (() => {
12226
- var _el$41 = createElement("box"), _el$42 = createElement("text");
12227
- insertNode(_el$41, _el$42);
12228
- setProp(_el$41, "flexDirection", "row");
12229
- setProp(_el$41, "gap", 1);
12230
- setProp(_el$41, "paddingLeft", 1);
12231
- setProp(_el$41, "paddingRight", 1);
12232
- setProp(_el$41, "onMouseUp", () => {
12319
+ var _el$52 = createElement("box"), _el$53 = createElement("text");
12320
+ insertNode(_el$52, _el$53);
12321
+ setProp(_el$52, "flexDirection", "row");
12322
+ setProp(_el$52, "gap", 1);
12323
+ setProp(_el$52, "paddingLeft", 1);
12324
+ setProp(_el$52, "paddingRight", 1);
12325
+ setProp(_el$52, "onMouseUp", () => {
12233
12326
  setLevel("body");
12234
12327
  setBodyRow(i());
12235
12328
  setThemeCursor(i());
12236
12329
  themeCtx.set(name);
12237
12330
  });
12238
- setProp(_el$42, "wrapMode", "none");
12239
- insert(_el$42, () => isSelected() ? "\u25CF " : " ", null);
12240
- insert(_el$42, name, null);
12331
+ setProp(_el$53, "wrapMode", "none");
12332
+ insert(_el$53, () => isSelected() ? "\u25CF " : " ", null);
12333
+ insert(_el$53, name, null);
12241
12334
  effect((_p$) => {
12242
- var _v$24 = isCursor() ? theme.primary : undefined, _v$25 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.accent : theme.text, _v$26 = isCursor() || isSelected() ? TextAttributes8.BOLD : undefined;
12243
- _v$24 !== _p$.e && (_p$.e = setProp(_el$41, "backgroundColor", _v$24, _p$.e));
12244
- _v$25 !== _p$.t && (_p$.t = setProp(_el$42, "fg", _v$25, _p$.t));
12245
- _v$26 !== _p$.a && (_p$.a = setProp(_el$42, "attributes", _v$26, _p$.a));
12335
+ var _v$33 = isCursor() ? theme.primary : undefined, _v$34 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.accent : theme.text, _v$35 = isCursor() || isSelected() ? TextAttributes8.BOLD : undefined;
12336
+ _v$33 !== _p$.e && (_p$.e = setProp(_el$52, "backgroundColor", _v$33, _p$.e));
12337
+ _v$34 !== _p$.t && (_p$.t = setProp(_el$53, "fg", _v$34, _p$.t));
12338
+ _v$35 !== _p$.a && (_p$.a = setProp(_el$53, "attributes", _v$35, _p$.a));
12246
12339
  return _p$;
12247
12340
  }, {
12248
12341
  e: undefined,
12249
12342
  t: undefined,
12250
12343
  a: undefined
12251
12344
  });
12252
- return _el$41;
12345
+ return _el$52;
12253
12346
  })();
12254
12347
  }
12255
12348
  }));
@@ -12288,37 +12381,73 @@ function SettingsDialog(props) {
12288
12381
  const isCursor = () => level() === "body" && bodyRow() === rowIndex();
12289
12382
  const isSelected = () => themeCtx.focusAccent === slot;
12290
12383
  return (() => {
12291
- var _el$43 = createElement("box"), _el$44 = createElement("text");
12292
- insertNode(_el$43, _el$44);
12293
- setProp(_el$43, "flexDirection", "row");
12294
- setProp(_el$43, "gap", 1);
12295
- setProp(_el$43, "paddingLeft", 1);
12296
- setProp(_el$43, "paddingRight", 1);
12297
- setProp(_el$43, "onMouseUp", () => {
12384
+ var _el$54 = createElement("box"), _el$55 = createElement("text");
12385
+ insertNode(_el$54, _el$55);
12386
+ setProp(_el$54, "flexDirection", "row");
12387
+ setProp(_el$54, "gap", 1);
12388
+ setProp(_el$54, "paddingLeft", 1);
12389
+ setProp(_el$54, "paddingRight", 1);
12390
+ setProp(_el$54, "onMouseUp", () => {
12298
12391
  setLevel("body");
12299
12392
  setBodyRow(rowIndex());
12300
12393
  themeCtx.setFocusAccent(slot);
12301
12394
  });
12302
- setProp(_el$44, "wrapMode", "none");
12303
- insert(_el$44, () => isSelected() ? "\u25CF " : " ", null);
12304
- insert(_el$44, () => FOCUS_ACCENT_LABEL[slot], null);
12395
+ setProp(_el$55, "wrapMode", "none");
12396
+ insert(_el$55, () => isSelected() ? "\u25CF " : " ", null);
12397
+ insert(_el$55, () => FOCUS_ACCENT_LABEL[slot], null);
12305
12398
  effect((_p$) => {
12306
- var _v$27 = isCursor() ? theme.primary : undefined, _v$28 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.focusAccent : theme.text, _v$29 = isCursor() || isSelected() ? TextAttributes8.BOLD : undefined;
12307
- _v$27 !== _p$.e && (_p$.e = setProp(_el$43, "backgroundColor", _v$27, _p$.e));
12308
- _v$28 !== _p$.t && (_p$.t = setProp(_el$44, "fg", _v$28, _p$.t));
12309
- _v$29 !== _p$.a && (_p$.a = setProp(_el$44, "attributes", _v$29, _p$.a));
12399
+ var _v$36 = isCursor() ? theme.primary : undefined, _v$37 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.focusAccent : theme.text, _v$38 = isCursor() || isSelected() ? TextAttributes8.BOLD : undefined;
12400
+ _v$36 !== _p$.e && (_p$.e = setProp(_el$54, "backgroundColor", _v$36, _p$.e));
12401
+ _v$37 !== _p$.t && (_p$.t = setProp(_el$55, "fg", _v$37, _p$.t));
12402
+ _v$38 !== _p$.a && (_p$.a = setProp(_el$55, "attributes", _v$38, _p$.a));
12310
12403
  return _p$;
12311
12404
  }, {
12312
12405
  e: undefined,
12313
12406
  t: undefined,
12314
12407
  a: undefined
12315
12408
  });
12316
- return _el$43;
12409
+ return _el$54;
12317
12410
  })();
12318
12411
  }
12319
12412
  }), null);
12413
+ insertNode(_el$26, _el$27);
12414
+ insertNode(_el$26, _el$29);
12415
+ insertNode(_el$26, _el$31);
12416
+ insertNode(_el$26, _el$34);
12417
+ setProp(_el$26, "flexDirection", "column");
12418
+ setProp(_el$26, "gap", 0);
12419
+ setProp(_el$26, "paddingTop", 1);
12420
+ insertNode(_el$27, createTextNode(`Notifications`));
12421
+ insertNode(_el$29, createTextNode(`Fired when a background chat tab finishes or pauses on an approval. Toast = bottom-right popup; Sound = terminal bell + chime. Tab-chip unread dot is always on.`));
12422
+ setProp(_el$29, "wrapMode", "word");
12423
+ insertNode(_el$31, _el$32);
12424
+ setProp(_el$31, "flexDirection", "row");
12425
+ setProp(_el$31, "gap", 1);
12426
+ setProp(_el$31, "paddingLeft", 1);
12427
+ setProp(_el$31, "paddingRight", 1);
12428
+ setProp(_el$31, "onMouseUp", () => {
12429
+ setLevel("body");
12430
+ setBodyRow(toastRowIndex());
12431
+ toggleToast();
12432
+ });
12433
+ insertNode(_el$32, _el$33);
12434
+ setProp(_el$32, "wrapMode", "none");
12435
+ insert(_el$32, () => toastEnabled() ? "[x]" : "[ ]", _el$33);
12436
+ insertNode(_el$34, _el$35);
12437
+ setProp(_el$34, "flexDirection", "row");
12438
+ setProp(_el$34, "gap", 1);
12439
+ setProp(_el$34, "paddingLeft", 1);
12440
+ setProp(_el$34, "paddingRight", 1);
12441
+ setProp(_el$34, "onMouseUp", () => {
12442
+ setLevel("body");
12443
+ setBodyRow(soundRowIndex());
12444
+ toggleSound();
12445
+ });
12446
+ insertNode(_el$35, _el$36);
12447
+ setProp(_el$35, "wrapMode", "none");
12448
+ insert(_el$35, () => soundEnabled() ? "[x]" : "[ ]", _el$36);
12320
12449
  effect((_p$) => {
12321
- var _v$ = theme.text, _v$2 = TextAttributes8.BOLD, _v$3 = theme.textMuted, _v$4 = theme.text, _v$5 = TextAttributes8.BOLD, _v$6 = theme.textMuted, _v$7 = isTransparentRow() ? theme.primary : undefined, _v$8 = isTransparentRow() ? theme.selectedListItemText : themeCtx.transparentBackground ? theme.accent : theme.textMuted, _v$9 = TextAttributes8.BOLD, _v$0 = theme.text, _v$1 = TextAttributes8.BOLD, _v$10 = theme.textMuted;
12450
+ var _v$ = theme.text, _v$2 = TextAttributes8.BOLD, _v$3 = theme.textMuted, _v$4 = theme.text, _v$5 = TextAttributes8.BOLD, _v$6 = theme.textMuted, _v$7 = isTransparentRow() ? theme.primary : undefined, _v$8 = isTransparentRow() ? theme.selectedListItemText : themeCtx.transparentBackground ? theme.accent : theme.textMuted, _v$9 = TextAttributes8.BOLD, _v$0 = theme.text, _v$1 = TextAttributes8.BOLD, _v$10 = theme.textMuted, _v$11 = theme.text, _v$12 = TextAttributes8.BOLD, _v$13 = theme.textMuted, _v$14 = isToastRow() ? theme.primary : undefined, _v$15 = isToastRow() ? theme.selectedListItemText : toastEnabled() ? theme.accent : theme.textMuted, _v$16 = TextAttributes8.BOLD, _v$17 = isSoundRow() ? theme.primary : undefined, _v$18 = isSoundRow() ? theme.selectedListItemText : soundEnabled() ? theme.accent : theme.textMuted, _v$19 = TextAttributes8.BOLD;
12322
12451
  _v$ !== _p$.e && (_p$.e = setProp(_el$1, "fg", _v$, _p$.e));
12323
12452
  _v$2 !== _p$.t && (_p$.t = setProp(_el$1, "attributes", _v$2, _p$.t));
12324
12453
  _v$3 !== _p$.a && (_p$.a = setProp(_el$11, "fg", _v$3, _p$.a));
@@ -12331,6 +12460,15 @@ function SettingsDialog(props) {
12331
12460
  _v$0 !== _p$.d && (_p$.d = setProp(_el$22, "fg", _v$0, _p$.d));
12332
12461
  _v$1 !== _p$.l && (_p$.l = setProp(_el$22, "attributes", _v$1, _p$.l));
12333
12462
  _v$10 !== _p$.u && (_p$.u = setProp(_el$24, "fg", _v$10, _p$.u));
12463
+ _v$11 !== _p$.c && (_p$.c = setProp(_el$27, "fg", _v$11, _p$.c));
12464
+ _v$12 !== _p$.w && (_p$.w = setProp(_el$27, "attributes", _v$12, _p$.w));
12465
+ _v$13 !== _p$.m && (_p$.m = setProp(_el$29, "fg", _v$13, _p$.m));
12466
+ _v$14 !== _p$.f && (_p$.f = setProp(_el$31, "backgroundColor", _v$14, _p$.f));
12467
+ _v$15 !== _p$.y && (_p$.y = setProp(_el$32, "fg", _v$15, _p$.y));
12468
+ _v$16 !== _p$.g && (_p$.g = setProp(_el$32, "attributes", _v$16, _p$.g));
12469
+ _v$17 !== _p$.p && (_p$.p = setProp(_el$34, "backgroundColor", _v$17, _p$.p));
12470
+ _v$18 !== _p$.b && (_p$.b = setProp(_el$35, "fg", _v$18, _p$.b));
12471
+ _v$19 !== _p$.T && (_p$.T = setProp(_el$35, "attributes", _v$19, _p$.T));
12334
12472
  return _p$;
12335
12473
  }, {
12336
12474
  e: undefined,
@@ -12344,7 +12482,16 @@ function SettingsDialog(props) {
12344
12482
  r: undefined,
12345
12483
  d: undefined,
12346
12484
  l: undefined,
12347
- u: undefined
12485
+ u: undefined,
12486
+ c: undefined,
12487
+ w: undefined,
12488
+ m: undefined,
12489
+ f: undefined,
12490
+ y: undefined,
12491
+ g: undefined,
12492
+ p: undefined,
12493
+ b: undefined,
12494
+ T: undefined
12348
12495
  });
12349
12496
  return _el$0;
12350
12497
  }
@@ -12354,119 +12501,119 @@ function SettingsDialog(props) {
12354
12501
  return section() === "dev";
12355
12502
  },
12356
12503
  get children() {
12357
- var _el$26 = createElement("box"), _el$27 = createElement("text"), _el$29 = createElement("text");
12358
- insertNode(_el$26, _el$27);
12359
- insertNode(_el$26, _el$29);
12360
- setProp(_el$26, "flexDirection", "column");
12361
- setProp(_el$26, "gap", 1);
12362
- insertNode(_el$27, createTextNode(`Reset UI state`));
12363
- insertNode(_el$29, createTextNode(`Clears ~/.config/kobe/state.json and ~/.kobe/tasks.json, then quits kobe \u2014 relaunch to start fresh. Working session / Archive lists, pane sizes, theme, model picks all reset. Worktrees on disk and Claude Code session history are not touched.`));
12364
- setProp(_el$29, "wrapMode", "word");
12365
- insert(_el$26, () => {
12504
+ var _el$37 = createElement("box"), _el$38 = createElement("text"), _el$40 = createElement("text");
12505
+ insertNode(_el$37, _el$38);
12506
+ insertNode(_el$37, _el$40);
12507
+ setProp(_el$37, "flexDirection", "column");
12508
+ setProp(_el$37, "gap", 1);
12509
+ insertNode(_el$38, createTextNode(`Reset UI state`));
12510
+ insertNode(_el$40, createTextNode(`Clears ~/.config/kobe/state.json and ~/.kobe/tasks.json, then quits kobe \u2014 relaunch to start fresh. Working session / Archive lists, pane sizes, theme, model picks all reset. Worktrees on disk and Claude Code session history are not touched.`));
12511
+ setProp(_el$40, "wrapMode", "word");
12512
+ insert(_el$37, () => {
12366
12513
  const isCursor = () => level() === "body" && bodyRow() === 0;
12367
12514
  return (() => {
12368
- var _el$45 = createElement("box"), _el$46 = createElement("text");
12369
- insertNode(_el$45, _el$46);
12370
- setProp(_el$45, "flexDirection", "row");
12371
- setProp(_el$45, "paddingLeft", 1);
12372
- setProp(_el$45, "paddingRight", 1);
12373
- setProp(_el$45, "onMouseUp", () => {
12515
+ var _el$56 = createElement("box"), _el$57 = createElement("text");
12516
+ insertNode(_el$56, _el$57);
12517
+ setProp(_el$56, "flexDirection", "row");
12518
+ setProp(_el$56, "paddingLeft", 1);
12519
+ setProp(_el$56, "paddingRight", 1);
12520
+ setProp(_el$56, "onMouseUp", () => {
12374
12521
  setLevel("body");
12375
12522
  setBodyRow(0);
12376
12523
  confirmReset();
12377
12524
  });
12378
- insertNode(_el$46, createTextNode(`[enter] Reset`));
12525
+ insertNode(_el$57, createTextNode(`[enter] Reset`));
12379
12526
  effect((_p$) => {
12380
- var _v$30 = isCursor() ? theme.primary : theme.backgroundElement, _v$31 = isCursor() ? theme.selectedListItemText : theme.warning, _v$32 = TextAttributes8.BOLD;
12381
- _v$30 !== _p$.e && (_p$.e = setProp(_el$45, "backgroundColor", _v$30, _p$.e));
12382
- _v$31 !== _p$.t && (_p$.t = setProp(_el$46, "fg", _v$31, _p$.t));
12383
- _v$32 !== _p$.a && (_p$.a = setProp(_el$46, "attributes", _v$32, _p$.a));
12527
+ var _v$39 = isCursor() ? theme.primary : theme.backgroundElement, _v$40 = isCursor() ? theme.selectedListItemText : theme.warning, _v$41 = TextAttributes8.BOLD;
12528
+ _v$39 !== _p$.e && (_p$.e = setProp(_el$56, "backgroundColor", _v$39, _p$.e));
12529
+ _v$40 !== _p$.t && (_p$.t = setProp(_el$57, "fg", _v$40, _p$.t));
12530
+ _v$41 !== _p$.a && (_p$.a = setProp(_el$57, "attributes", _v$41, _p$.a));
12384
12531
  return _p$;
12385
12532
  }, {
12386
12533
  e: undefined,
12387
12534
  t: undefined,
12388
12535
  a: undefined
12389
12536
  });
12390
- return _el$45;
12537
+ return _el$56;
12391
12538
  })();
12392
12539
  }, null);
12393
- insert(_el$26, createComponent2(Show, {
12540
+ insert(_el$37, createComponent2(Show, {
12394
12541
  when: hasDaemon,
12395
12542
  get children() {
12396
- var _el$31 = createElement("box"), _el$32 = createElement("text"), _el$34 = createElement("text");
12397
- insertNode(_el$31, _el$32);
12398
- insertNode(_el$31, _el$34);
12399
- setProp(_el$31, "flexDirection", "column");
12400
- setProp(_el$31, "gap", 0);
12401
- setProp(_el$31, "paddingTop", 1);
12402
- insertNode(_el$32, createTextNode(`Restart backend`));
12403
- insertNode(_el$34, createTextNode(`Stops the kobed daemon and quits this kobe window so the next launch spawns a fresh daemon \u2014 picks up daemon / orchestrator / engine edits without a process kill. Other attached kobe windows will lose their connection too.`));
12404
- setProp(_el$34, "wrapMode", "word");
12405
- insert(_el$31, () => {
12543
+ var _el$42 = createElement("box"), _el$43 = createElement("text"), _el$45 = createElement("text");
12544
+ insertNode(_el$42, _el$43);
12545
+ insertNode(_el$42, _el$45);
12546
+ setProp(_el$42, "flexDirection", "column");
12547
+ setProp(_el$42, "gap", 0);
12548
+ setProp(_el$42, "paddingTop", 1);
12549
+ insertNode(_el$43, createTextNode(`Restart backend`));
12550
+ insertNode(_el$45, createTextNode(`Stops the kobed daemon and quits this kobe window so the next launch spawns a fresh daemon \u2014 picks up daemon / orchestrator / engine edits without a process kill. Other attached kobe windows will lose their connection too.`));
12551
+ setProp(_el$45, "wrapMode", "word");
12552
+ insert(_el$42, () => {
12406
12553
  const isCursor = () => level() === "body" && bodyRow() === 1;
12407
12554
  return (() => {
12408
- var _el$48 = createElement("box"), _el$49 = createElement("text");
12409
- insertNode(_el$48, _el$49);
12410
- setProp(_el$48, "flexDirection", "row");
12411
- setProp(_el$48, "paddingLeft", 1);
12412
- setProp(_el$48, "paddingRight", 1);
12413
- setProp(_el$48, "onMouseUp", () => {
12555
+ var _el$59 = createElement("box"), _el$60 = createElement("text");
12556
+ insertNode(_el$59, _el$60);
12557
+ setProp(_el$59, "flexDirection", "row");
12558
+ setProp(_el$59, "paddingLeft", 1);
12559
+ setProp(_el$59, "paddingRight", 1);
12560
+ setProp(_el$59, "onMouseUp", () => {
12414
12561
  setLevel("body");
12415
12562
  setBodyRow(1);
12416
12563
  confirmRestartDaemon();
12417
12564
  });
12418
- insertNode(_el$49, createTextNode(`[enter] Restart`));
12565
+ insertNode(_el$60, createTextNode(`[enter] Restart`));
12419
12566
  effect((_p$) => {
12420
- var _v$33 = isCursor() ? theme.primary : theme.backgroundElement, _v$34 = isCursor() ? theme.selectedListItemText : theme.accent, _v$35 = TextAttributes8.BOLD;
12421
- _v$33 !== _p$.e && (_p$.e = setProp(_el$48, "backgroundColor", _v$33, _p$.e));
12422
- _v$34 !== _p$.t && (_p$.t = setProp(_el$49, "fg", _v$34, _p$.t));
12423
- _v$35 !== _p$.a && (_p$.a = setProp(_el$49, "attributes", _v$35, _p$.a));
12567
+ var _v$42 = isCursor() ? theme.primary : theme.backgroundElement, _v$43 = isCursor() ? theme.selectedListItemText : theme.accent, _v$44 = TextAttributes8.BOLD;
12568
+ _v$42 !== _p$.e && (_p$.e = setProp(_el$59, "backgroundColor", _v$42, _p$.e));
12569
+ _v$43 !== _p$.t && (_p$.t = setProp(_el$60, "fg", _v$43, _p$.t));
12570
+ _v$44 !== _p$.a && (_p$.a = setProp(_el$60, "attributes", _v$44, _p$.a));
12424
12571
  return _p$;
12425
12572
  }, {
12426
12573
  e: undefined,
12427
12574
  t: undefined,
12428
12575
  a: undefined
12429
12576
  });
12430
- return _el$48;
12577
+ return _el$59;
12431
12578
  })();
12432
12579
  }, null);
12433
12580
  effect((_p$) => {
12434
- var _v$11 = theme.text, _v$12 = TextAttributes8.BOLD, _v$13 = theme.textMuted;
12435
- _v$11 !== _p$.e && (_p$.e = setProp(_el$32, "fg", _v$11, _p$.e));
12436
- _v$12 !== _p$.t && (_p$.t = setProp(_el$32, "attributes", _v$12, _p$.t));
12437
- _v$13 !== _p$.a && (_p$.a = setProp(_el$34, "fg", _v$13, _p$.a));
12581
+ var _v$20 = theme.text, _v$21 = TextAttributes8.BOLD, _v$22 = theme.textMuted;
12582
+ _v$20 !== _p$.e && (_p$.e = setProp(_el$43, "fg", _v$20, _p$.e));
12583
+ _v$21 !== _p$.t && (_p$.t = setProp(_el$43, "attributes", _v$21, _p$.t));
12584
+ _v$22 !== _p$.a && (_p$.a = setProp(_el$45, "fg", _v$22, _p$.a));
12438
12585
  return _p$;
12439
12586
  }, {
12440
12587
  e: undefined,
12441
12588
  t: undefined,
12442
12589
  a: undefined
12443
12590
  });
12444
- return _el$31;
12591
+ return _el$42;
12445
12592
  }
12446
12593
  }), null);
12447
12594
  effect((_p$) => {
12448
- var _v$14 = theme.text, _v$15 = TextAttributes8.BOLD, _v$16 = theme.textMuted;
12449
- _v$14 !== _p$.e && (_p$.e = setProp(_el$27, "fg", _v$14, _p$.e));
12450
- _v$15 !== _p$.t && (_p$.t = setProp(_el$27, "attributes", _v$15, _p$.t));
12451
- _v$16 !== _p$.a && (_p$.a = setProp(_el$29, "fg", _v$16, _p$.a));
12595
+ var _v$23 = theme.text, _v$24 = TextAttributes8.BOLD, _v$25 = theme.textMuted;
12596
+ _v$23 !== _p$.e && (_p$.e = setProp(_el$38, "fg", _v$23, _p$.e));
12597
+ _v$24 !== _p$.t && (_p$.t = setProp(_el$38, "attributes", _v$24, _p$.t));
12598
+ _v$25 !== _p$.a && (_p$.a = setProp(_el$40, "fg", _v$25, _p$.a));
12452
12599
  return _p$;
12453
12600
  }, {
12454
12601
  e: undefined,
12455
12602
  t: undefined,
12456
12603
  a: undefined
12457
12604
  });
12458
- return _el$26;
12605
+ return _el$37;
12459
12606
  }
12460
12607
  }), null);
12461
- insertNode(_el$36, _el$37);
12462
- setProp(_el$36, "paddingTop", 0);
12463
- insertNode(_el$37, createTextNode(`j/k pick \xB7 h/l switch level \xB7 enter activate \xB7 esc close`));
12608
+ insertNode(_el$47, _el$48);
12609
+ setProp(_el$47, "paddingTop", 0);
12610
+ insertNode(_el$48, createTextNode(`j/k pick \xB7 h/l switch level \xB7 enter activate \xB7 esc close`));
12464
12611
  effect((_p$) => {
12465
- var _v$17 = TextAttributes8.BOLD, _v$18 = theme.text, _v$19 = theme.textMuted, _v$20 = theme.textMuted;
12466
- _v$17 !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$17, _p$.e));
12467
- _v$18 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$18, _p$.t));
12468
- _v$19 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$19, _p$.a));
12469
- _v$20 !== _p$.o && (_p$.o = setProp(_el$37, "fg", _v$20, _p$.o));
12612
+ var _v$26 = TextAttributes8.BOLD, _v$27 = theme.text, _v$28 = theme.textMuted, _v$29 = theme.textMuted;
12613
+ _v$26 !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$26, _p$.e));
12614
+ _v$27 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$27, _p$.t));
12615
+ _v$28 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$28, _p$.a));
12616
+ _v$29 !== _p$.o && (_p$.o = setProp(_el$48, "fg", _v$29, _p$.o));
12470
12617
  return _p$;
12471
12618
  }, {
12472
12619
  e: undefined,
@@ -12600,8 +12747,261 @@ var init_app_keymap = __esm(() => {
12600
12747
  init_dialog_confirm();
12601
12748
  });
12602
12749
 
12750
+ // src/tui/asset/pulse.wav
12751
+ var pulse_default = "../pulse-n3cq1btw.wav";
12752
+ var init_pulse = () => {};
12753
+
12754
+ // src/tui/lib/sound.ts
12755
+ import { existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
12756
+ import { tmpdir as tmpdir2 } from "os";
12757
+ import { basename as basename3, isAbsolute, join as join11, resolve as resolve3 } from "path";
12758
+ function args(player, file, volume) {
12759
+ if (player === "ffplay")
12760
+ return [player, "-autoexit", "-nodisp", "-af", `volume=${volume}`, file];
12761
+ if (player === "mpv")
12762
+ return [player, "--no-video", "--audio-display=no", "--volume", String(Math.round(volume * 100)), file];
12763
+ if (player === "mpg123" || player === "mpg321")
12764
+ return [player, "-g", String(Math.round(volume * 100)), file];
12765
+ if (player === "mplayer")
12766
+ return [player, "-vo", "null", "-volume", String(Math.round(volume * 100)), file];
12767
+ if (player === "afplay" || player === "omxplayer" || player === "aplay" || player === "cmdmp3")
12768
+ return [player, file];
12769
+ if (player === "play")
12770
+ return [player, "-v", String(volume), file];
12771
+ if (player === "cvlc")
12772
+ return [player, `--gain=${volume}`, "--play-and-exit", file];
12773
+ return [player, "-c", `(New-Object Media.SoundPlayer '${file.replace(/'/g, "''")}').PlaySync()`];
12774
+ }
12775
+ function pickPlayer() {
12776
+ if (cachedPlayer !== undefined)
12777
+ return cachedPlayer;
12778
+ const path6 = process.env.PATH ?? "";
12779
+ const segments = path6.split(":").filter(Boolean);
12780
+ cachedPlayer = PLAYERS.find((p) => segments.some((dir) => existsSync5(join11(dir, p)))) ?? null;
12781
+ return cachedPlayer;
12782
+ }
12783
+ async function ensureAsset() {
12784
+ cachedPath ??= (async () => {
12785
+ mkdirSync3(DIR, { recursive: true });
12786
+ const dest = join11(DIR, basename3(pulseAsset));
12787
+ const out = Bun.file(dest);
12788
+ if (await out.exists())
12789
+ return dest;
12790
+ await Bun.write(out, Bun.file(pulseAsset));
12791
+ return dest;
12792
+ })();
12793
+ return cachedPath;
12794
+ }
12795
+ function pulse(volume = 0.4) {
12796
+ const player = pickPlayer();
12797
+ if (!player)
12798
+ return;
12799
+ ensureAsset().then((path6) => {
12800
+ try {
12801
+ const proc = Bun.spawn(args(player, path6, volume), {
12802
+ stdin: "ignore",
12803
+ stdout: "ignore",
12804
+ stderr: "ignore"
12805
+ });
12806
+ proc.unref?.();
12807
+ } catch {}
12808
+ }).catch(() => {
12809
+ return;
12810
+ });
12811
+ }
12812
+ var pulseAsset, DIR, PLAYERS, cachedPlayer, cachedPath;
12813
+ var init_sound = __esm(() => {
12814
+ init_pulse();
12815
+ pulseAsset = isAbsolute(pulse_default) ? pulse_default : resolve3(import.meta.dir, pulse_default);
12816
+ DIR = join11(tmpdir2(), "kobe-sfx");
12817
+ PLAYERS = [
12818
+ "ffplay",
12819
+ "mpv",
12820
+ "mpg123",
12821
+ "mpg321",
12822
+ "mplayer",
12823
+ "afplay",
12824
+ "play",
12825
+ "omxplayer",
12826
+ "aplay",
12827
+ "cmdmp3",
12828
+ "cvlc",
12829
+ "powershell.exe"
12830
+ ];
12831
+ });
12832
+
12833
+ // src/tui/context/kv.tsx
12834
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync5, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
12835
+ import { homedir as homedir7 } from "os";
12836
+ import { dirname as dirname5, join as join12 } from "path";
12837
+ function loadInitial() {
12838
+ try {
12839
+ const text = readFileSync5(STATE_PATH, "utf8");
12840
+ const parsed = JSON.parse(text);
12841
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
12842
+ return parsed;
12843
+ }
12844
+ } catch {}
12845
+ return {};
12846
+ }
12847
+ var STATE_PATH, WRITE_DEBOUNCE_MS = 250, useKV, KVProvider;
12848
+ var init_kv = __esm(() => {
12849
+ init_dev2();
12850
+ init_helper();
12851
+ STATE_PATH = join12(homedir7(), ".config", "kobe", "state.json");
12852
+ ({
12853
+ use: useKV,
12854
+ provider: KVProvider
12855
+ } = createSimpleContext({
12856
+ name: "KV",
12857
+ init: () => {
12858
+ const [store2, setStore2] = createStore(loadInitial());
12859
+ let writeTimer = null;
12860
+ function scheduleWrite() {
12861
+ if (writeTimer)
12862
+ clearTimeout(writeTimer);
12863
+ writeTimer = setTimeout(() => {
12864
+ writeTimer = null;
12865
+ try {
12866
+ mkdirSync4(dirname5(STATE_PATH), {
12867
+ recursive: true
12868
+ });
12869
+ const tmp = `${STATE_PATH}.tmp`;
12870
+ writeFileSync3(tmp, JSON.stringify(store2, null, 2), "utf8");
12871
+ renameSync2(tmp, STATE_PATH);
12872
+ } catch (err) {
12873
+ console.error("[kobe] kv write failed:", err);
12874
+ }
12875
+ }, WRITE_DEBOUNCE_MS);
12876
+ }
12877
+ const result = {
12878
+ get ready() {
12879
+ return true;
12880
+ },
12881
+ get store() {
12882
+ return store2;
12883
+ },
12884
+ signal(name, defaultValue) {
12885
+ if (store2[name] === undefined)
12886
+ setStore2(name, defaultValue);
12887
+ return [() => result.get(name), (next) => result.set(name, next)];
12888
+ },
12889
+ get(key, defaultValue) {
12890
+ return store2[key] ?? defaultValue;
12891
+ },
12892
+ set(key, value) {
12893
+ setStore2(key, value);
12894
+ scheduleWrite();
12895
+ },
12896
+ clear() {
12897
+ for (const k of Object.keys(store2))
12898
+ setStore2(k, undefined);
12899
+ if (writeTimer) {
12900
+ clearTimeout(writeTimer);
12901
+ writeTimer = null;
12902
+ }
12903
+ try {
12904
+ mkdirSync4(dirname5(STATE_PATH), {
12905
+ recursive: true
12906
+ });
12907
+ const tmp = `${STATE_PATH}.tmp`;
12908
+ writeFileSync3(tmp, JSON.stringify(store2, null, 2), "utf8");
12909
+ renameSync2(tmp, STATE_PATH);
12910
+ } catch (err) {
12911
+ console.error("[kobe] kv clear write failed:", err);
12912
+ }
12913
+ }
12914
+ };
12915
+ return result;
12916
+ }
12917
+ }));
12918
+ });
12919
+
12920
+ // src/tui/context/notifications.tsx
12921
+ function unreadKey(taskId, tabId) {
12922
+ return `${taskId}:${tabId}`;
12923
+ }
12924
+ function NotificationsProvider(props) {
12925
+ const kv = useKV();
12926
+ const [toasts, setToasts] = createSignal([]);
12927
+ const [unread, setUnread] = createSignal(new Map);
12928
+ let counter = 0;
12929
+ function notify(input) {
12930
+ setUnread((prev) => {
12931
+ const next = new Map(prev);
12932
+ const key = unreadKey(input.taskId, input.tabId);
12933
+ const existing = prev.get(key);
12934
+ if (existing === "needs_input")
12935
+ return prev;
12936
+ next.set(key, input.kind);
12937
+ return next;
12938
+ });
12939
+ if (kv.get("notifications.sound.enabled", true) !== false) {
12940
+ try {
12941
+ process.stdout.write("\x07");
12942
+ } catch {}
12943
+ pulse();
12944
+ }
12945
+ if (kv.get("notifications.toast.enabled", true) !== false) {
12946
+ const id = ++counter;
12947
+ const toast = {
12948
+ id,
12949
+ kind: input.kind,
12950
+ taskId: input.taskId,
12951
+ tabId: input.tabId,
12952
+ title: input.title
12953
+ };
12954
+ setToasts((prev) => [...prev, toast]);
12955
+ setTimeout(() => dismiss(id), TOAST_DURATION_MS);
12956
+ }
12957
+ }
12958
+ function dismiss(id) {
12959
+ setToasts((prev) => prev.filter((t) => t.id !== id));
12960
+ }
12961
+ function markRead(taskId, tabId) {
12962
+ setUnread((prev) => {
12963
+ const key = unreadKey(taskId, tabId);
12964
+ if (!prev.has(key))
12965
+ return prev;
12966
+ const next = new Map(prev);
12967
+ next.delete(key);
12968
+ return next;
12969
+ });
12970
+ }
12971
+ const value = {
12972
+ toasts,
12973
+ unread,
12974
+ notify,
12975
+ dismiss,
12976
+ markRead
12977
+ };
12978
+ return createComponent2(ctx3.Provider, {
12979
+ value,
12980
+ get children() {
12981
+ return props.children;
12982
+ }
12983
+ });
12984
+ }
12985
+ function useNotifications() {
12986
+ const value = useContext(ctx3);
12987
+ if (!value)
12988
+ throw new Error("useNotifications must be used within a NotificationsProvider");
12989
+ return value;
12990
+ }
12991
+ function notificationKey(taskId, tabId) {
12992
+ return unreadKey(taskId, tabId);
12993
+ }
12994
+ var TOAST_DURATION_MS = 4500, ctx3;
12995
+ var init_notifications = __esm(() => {
12996
+ init_solid();
12997
+ init_dev();
12998
+ init_sound();
12999
+ init_kv();
13000
+ ctx3 = createContext();
13001
+ });
13002
+
12603
13003
  // src/tui/component/center-tab-strip.tsx
12604
- import { basename as basename3 } from "path";
13004
+ import { basename as basename4 } from "path";
12605
13005
  import { TextAttributes as TextAttributes9 } from "@opentui/core";
12606
13006
  function CenterTabStrip(props) {
12607
13007
  const {
@@ -12668,6 +13068,14 @@ function CenterTabStrip(props) {
12668
13068
  return theme.success;
12669
13069
  return theme.textMuted;
12670
13070
  };
13071
+ const unreadKind = () => {
13072
+ const taskId = props.activeTaskId();
13073
+ if (!taskId)
13074
+ return;
13075
+ return props.unread().get(notificationKey(taskId, tab.id));
13076
+ };
13077
+ const showUnread = () => !isPrimary() && unreadKind() !== undefined;
13078
+ const unreadColor = () => unreadKind() === "needs_input" ? theme.warning : theme.success;
12671
13079
  return (() => {
12672
13080
  var _el$5 = createElement("box"), _el$7 = createElement("text");
12673
13081
  insertNode(_el$5, _el$7);
@@ -12694,6 +13102,18 @@ function CenterTabStrip(props) {
12694
13102
  }), _el$7);
12695
13103
  setProp(_el$7, "wrapMode", "none");
12696
13104
  insert(_el$7, () => chatTabLabel(tab));
13105
+ insert(_el$5, createComponent2(Show, {
13106
+ get when() {
13107
+ return showUnread();
13108
+ },
13109
+ get children() {
13110
+ var _el$8 = createElement("text");
13111
+ insertNode(_el$8, createTextNode(`\u25CF`));
13112
+ setProp(_el$8, "wrapMode", "none");
13113
+ effect((_$p) => setProp(_el$8, "fg", unreadColor(), _$p));
13114
+ return _el$8;
13115
+ }
13116
+ }), null);
12697
13117
  effect((_p$) => {
12698
13118
  var _v$4 = isPrimary() ? theme.primary : theme.backgroundElement, _v$5 = isPrimary() ? theme.selectedListItemText : isVisibleButOther() ? theme.text : theme.textMuted, _v$6 = isPrimary() ? TextAttributes9.BOLD : undefined;
12699
13119
  _v$4 !== _p$.e && (_p$.e = setProp(_el$5, "backgroundColor", _v$4, _p$.e));
@@ -12718,24 +13138,24 @@ function CenterTabStrip(props) {
12718
13138
  children: (file) => {
12719
13139
  const isActive = () => !props.isChatActive();
12720
13140
  return (() => {
12721
- var _el$8 = createElement("box"), _el$9 = createElement("text"), _el$0 = createElement("text");
12722
- insertNode(_el$8, _el$9);
12723
- insertNode(_el$8, _el$0);
12724
- setProp(_el$8, "flexDirection", "row");
12725
- setProp(_el$8, "gap", 1);
12726
- setProp(_el$8, "paddingLeft", 1);
12727
- setProp(_el$8, "paddingRight", 1);
12728
- setProp(_el$8, "onMouseUp", () => props.onSelectFile(file()));
12729
- setProp(_el$9, "wrapMode", "none");
12730
- insert(_el$9, () => basename3(file()));
12731
- insertNode(_el$0, createTextNode(`x`));
12732
- setProp(_el$0, "onMouseUp", () => queueMicrotask(() => props.onCloseFile(file())));
13141
+ var _el$0 = createElement("box"), _el$1 = createElement("text"), _el$10 = createElement("text");
13142
+ insertNode(_el$0, _el$1);
13143
+ insertNode(_el$0, _el$10);
13144
+ setProp(_el$0, "flexDirection", "row");
13145
+ setProp(_el$0, "gap", 1);
13146
+ setProp(_el$0, "paddingLeft", 1);
13147
+ setProp(_el$0, "paddingRight", 1);
13148
+ setProp(_el$0, "onMouseUp", () => props.onSelectFile(file()));
13149
+ setProp(_el$1, "wrapMode", "none");
13150
+ insert(_el$1, () => basename4(file()));
13151
+ insertNode(_el$10, createTextNode(`x`));
13152
+ setProp(_el$10, "onMouseUp", () => queueMicrotask(() => props.onCloseFile(file())));
12733
13153
  effect((_p$) => {
12734
13154
  var _v$7 = isActive() ? theme.primary : theme.backgroundElement, _v$8 = isActive() ? theme.selectedListItemText : theme.text, _v$9 = isActive() ? TextAttributes9.BOLD : undefined, _v$0 = isActive() ? theme.selectedListItemText : theme.textMuted;
12735
- _v$7 !== _p$.e && (_p$.e = setProp(_el$8, "backgroundColor", _v$7, _p$.e));
12736
- _v$8 !== _p$.t && (_p$.t = setProp(_el$9, "fg", _v$8, _p$.t));
12737
- _v$9 !== _p$.a && (_p$.a = setProp(_el$9, "attributes", _v$9, _p$.a));
12738
- _v$0 !== _p$.o && (_p$.o = setProp(_el$0, "fg", _v$0, _p$.o));
13155
+ _v$7 !== _p$.e && (_p$.e = setProp(_el$0, "backgroundColor", _v$7, _p$.e));
13156
+ _v$8 !== _p$.t && (_p$.t = setProp(_el$1, "fg", _v$8, _p$.t));
13157
+ _v$9 !== _p$.a && (_p$.a = setProp(_el$1, "attributes", _v$9, _p$.a));
13158
+ _v$0 !== _p$.o && (_p$.o = setProp(_el$10, "fg", _v$0, _p$.o));
12739
13159
  return _p$;
12740
13160
  }, {
12741
13161
  e: undefined,
@@ -12743,7 +13163,7 @@ function CenterTabStrip(props) {
12743
13163
  a: undefined,
12744
13164
  o: undefined
12745
13165
  });
12746
- return _el$8;
13166
+ return _el$0;
12747
13167
  })();
12748
13168
  }
12749
13169
  }), null);
@@ -12761,6 +13181,7 @@ var init_center_tab_strip = __esm(() => {
12761
13181
  init_solid();
12762
13182
  init_dev();
12763
13183
  init_core();
13184
+ init_notifications();
12764
13185
  init_theme();
12765
13186
  });
12766
13187
 
@@ -13252,11 +13673,11 @@ function FocusProvider(props) {
13252
13673
  });
13253
13674
  }
13254
13675
  function useFocus() {
13255
- const ctx3 = useContext(FocusContext);
13256
- if (!ctx3) {
13676
+ const ctx4 = useContext(FocusContext);
13677
+ if (!ctx4) {
13257
13678
  throw new Error("useFocus: must be called inside <FocusProvider>. See src/tui/context/focus.tsx.");
13258
13679
  }
13259
- return ctx3;
13680
+ return ctx4;
13260
13681
  }
13261
13682
  var PANE_ORDER, FocusContext;
13262
13683
  var init_focus = __esm(() => {
@@ -13416,8 +13837,95 @@ var init_status_bar = __esm(() => {
13416
13837
  init_theme();
13417
13838
  });
13418
13839
 
13419
- // src/tui/component/create-pr-button.tsx
13840
+ // src/tui/component/toast-overlay.tsx
13420
13841
  import { TextAttributes as TextAttributes13 } from "@opentui/core";
13842
+ function ToastOverlay() {
13843
+ const {
13844
+ theme
13845
+ } = useTheme();
13846
+ const dims = useTerminalDimensions();
13847
+ const notif = useNotifications();
13848
+ const visibleToasts = () => notif.toasts().slice(-MAX_VISIBLE);
13849
+ const left = () => Math.max(0, dims().width - CHIP_WIDTH - RIGHT_MARGIN);
13850
+ const top = () => Math.max(0, dims().height - BOTTOM_MARGIN - MAX_VISIBLE - 1);
13851
+ return createComponent2(Show, {
13852
+ get when() {
13853
+ return notif.toasts().length > 0;
13854
+ },
13855
+ get children() {
13856
+ var _el$ = createElement("box");
13857
+ setProp(_el$, "position", "absolute");
13858
+ setProp(_el$, "zIndex", 2500);
13859
+ setProp(_el$, "width", 40);
13860
+ setProp(_el$, "flexDirection", "column");
13861
+ setProp(_el$, "gap", 0);
13862
+ insert(_el$, createComponent2(For, {
13863
+ get each() {
13864
+ return visibleToasts();
13865
+ },
13866
+ children: (toast) => {
13867
+ const bg = () => toast.kind === "needs_input" ? theme.warning : theme.success;
13868
+ const fg = () => theme.selectedListItemText;
13869
+ const prefix = () => toast.kind === "needs_input" ? "?" : "\u2713";
13870
+ return (() => {
13871
+ var _el$2 = createElement("box"), _el$3 = createElement("text"), _el$4 = createElement("text");
13872
+ insertNode(_el$2, _el$3);
13873
+ insertNode(_el$2, _el$4);
13874
+ setProp(_el$2, "flexDirection", "row");
13875
+ setProp(_el$2, "gap", 1);
13876
+ setProp(_el$2, "paddingLeft", 1);
13877
+ setProp(_el$2, "paddingRight", 1);
13878
+ setProp(_el$2, "onMouseUp", () => notif.dismiss(toast.id));
13879
+ setProp(_el$3, "wrapMode", "none");
13880
+ insert(_el$3, prefix);
13881
+ setProp(_el$4, "wrapMode", "none");
13882
+ insert(_el$4, () => toast.title);
13883
+ effect((_p$) => {
13884
+ var _v$3 = bg(), _v$4 = fg(), _v$5 = TextAttributes13.BOLD, _v$6 = fg();
13885
+ _v$3 !== _p$.e && (_p$.e = setProp(_el$2, "backgroundColor", _v$3, _p$.e));
13886
+ _v$4 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$4, _p$.t));
13887
+ _v$5 !== _p$.a && (_p$.a = setProp(_el$3, "attributes", _v$5, _p$.a));
13888
+ _v$6 !== _p$.o && (_p$.o = setProp(_el$4, "fg", _v$6, _p$.o));
13889
+ return _p$;
13890
+ }, {
13891
+ e: undefined,
13892
+ t: undefined,
13893
+ a: undefined,
13894
+ o: undefined
13895
+ });
13896
+ return _el$2;
13897
+ })();
13898
+ }
13899
+ }));
13900
+ effect((_p$) => {
13901
+ var _v$ = left(), _v$2 = top();
13902
+ _v$ !== _p$.e && (_p$.e = setProp(_el$, "left", _v$, _p$.e));
13903
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$, "top", _v$2, _p$.t));
13904
+ return _p$;
13905
+ }, {
13906
+ e: undefined,
13907
+ t: undefined
13908
+ });
13909
+ return _el$;
13910
+ }
13911
+ });
13912
+ }
13913
+ var MAX_VISIBLE = 4, CHIP_WIDTH = 40, RIGHT_MARGIN = 2, BOTTOM_MARGIN = 2;
13914
+ var init_toast_overlay = __esm(() => {
13915
+ init_solid();
13916
+ init_solid();
13917
+ init_solid();
13918
+ init_solid();
13919
+ init_solid();
13920
+ init_solid();
13921
+ init_solid();
13922
+ init_dev();
13923
+ init_notifications();
13924
+ init_theme();
13925
+ });
13926
+
13927
+ // src/tui/component/create-pr-button.tsx
13928
+ import { TextAttributes as TextAttributes14 } from "@opentui/core";
13421
13929
  function isEnabled(task) {
13422
13930
  if (!task)
13423
13931
  return false;
@@ -13454,7 +13962,7 @@ function CreatePRButton(props) {
13454
13962
  insertNode(_el$4, createTextNode(`Create PR`));
13455
13963
  setProp(_el$4, "wrapMode", "none");
13456
13964
  effect((_p$) => {
13457
- var _v$ = enabled() ? onClick : undefined, _v$2 = bracketColor(), _v$3 = TextAttributes13.BOLD, _v$4 = labelColor();
13965
+ var _v$ = enabled() ? onClick : undefined, _v$2 = bracketColor(), _v$3 = TextAttributes14.BOLD, _v$4 = labelColor();
13458
13966
  _v$ !== _p$.e && (_p$.e = setProp(_el$, "onMouseUp", _v$, _p$.e));
13459
13967
  _v$2 !== _p$.t && (_p$.t = setProp(_el$2, "fg", _v$2, _p$.t));
13460
13968
  _v$3 !== _p$.a && (_p$.a = setProp(_el$2, "attributes", _v$3, _p$.a));
@@ -13744,7 +14252,7 @@ var init_markdown_parser = __esm(() => {
13744
14252
  });
13745
14253
 
13746
14254
  // src/tui/panes/chat/Markdown.tsx
13747
- import { TextAttributes as TextAttributes14 } from "@opentui/core";
14255
+ import { TextAttributes as TextAttributes15 } from "@opentui/core";
13748
14256
  function InlineSpans(props) {
13749
14257
  const {
13750
14258
  theme
@@ -13774,7 +14282,7 @@ function InlineSpans(props) {
13774
14282
  insert(_el$3, () => t.text, _el$5);
13775
14283
  effect((_$p) => setProp(_el$3, "style", {
13776
14284
  fg: theme.accent,
13777
- attributes: TextAttributes14.DIM
14285
+ attributes: TextAttributes15.DIM
13778
14286
  }, _$p));
13779
14287
  return _el$3;
13780
14288
  })();
@@ -13786,7 +14294,7 @@ function InlineSpans(props) {
13786
14294
  insert(_el$6, () => showUrl ? t.text : t.href);
13787
14295
  effect((_$p) => setProp(_el$6, "style", {
13788
14296
  fg: theme.accent,
13789
- attributes: TextAttributes14.UNDERLINE
14297
+ attributes: TextAttributes15.UNDERLINE
13790
14298
  }, _$p));
13791
14299
  return _el$6;
13792
14300
  })(), createComponent2(Show, {
@@ -13798,7 +14306,7 @@ function InlineSpans(props) {
13798
14306
  insert(_el$7, () => t.href, _el$9);
13799
14307
  effect((_$p) => setProp(_el$7, "style", {
13800
14308
  fg: theme.textMuted,
13801
- attributes: TextAttributes14.DIM
14309
+ attributes: TextAttributes15.DIM
13802
14310
  }, _$p));
13803
14311
  return _el$7;
13804
14312
  }
@@ -13975,7 +14483,7 @@ function VerticalTable(props) {
13975
14483
  var _el$20 = createElement("text");
13976
14484
  insertNode(_el$20, createTextNode(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
13977
14485
  effect((_p$) => {
13978
- var _v$4 = theme.textMuted, _v$5 = TextAttributes14.DIM;
14486
+ var _v$4 = theme.textMuted, _v$5 = TextAttributes15.DIM;
13979
14487
  _v$4 !== _p$.e && (_p$.e = setProp(_el$20, "fg", _v$4, _p$.e));
13980
14488
  _v$5 !== _p$.t && (_p$.t = setProp(_el$20, "attributes", _v$5, _p$.t));
13981
14489
  return _p$;
@@ -14066,7 +14574,7 @@ function BlockNode(props) {
14066
14574
  })();
14067
14575
  }
14068
14576
  if (b.kind === "heading") {
14069
- const attrs = b.level === 1 ? TextAttributes14.BOLD | TextAttributes14.UNDERLINE : TextAttributes14.BOLD;
14577
+ const attrs = b.level === 1 ? TextAttributes15.BOLD | TextAttributes15.UNDERLINE : TextAttributes15.BOLD;
14070
14578
  const fg = b.level <= 2 ? theme.accent : theme.text;
14071
14579
  const tokens = parseInline(b.text);
14072
14580
  return (() => {
@@ -14092,7 +14600,7 @@ function BlockNode(props) {
14092
14600
  const checkbox = item.checked ? "[x] " : "[ ] ";
14093
14601
  const bullet = b.ordered ? `${b.start + idx()}. ` : "\u2022 ";
14094
14602
  const prefix = isTask ? checkbox : bullet;
14095
- const labelAttrs = isTask && item.checked ? TextAttributes14.DIM : 0;
14603
+ const labelAttrs = isTask && item.checked ? TextAttributes15.DIM : 0;
14096
14604
  return (() => {
14097
14605
  var _el$30 = createElement("text"), _el$31 = createElement("span");
14098
14606
  insertNode(_el$30, _el$31);
@@ -14139,9 +14647,9 @@ function BlockNode(props) {
14139
14647
  }
14140
14648
  }), null);
14141
14649
  effect((_p$) => {
14142
- var _v$10 = theme.textMuted, _v$11 = TextAttributes14.ITALIC, _v$12 = {
14650
+ var _v$10 = theme.textMuted, _v$11 = TextAttributes15.ITALIC, _v$12 = {
14143
14651
  fg: theme.textMuted,
14144
- attributes: TextAttributes14.DIM
14652
+ attributes: TextAttributes15.DIM
14145
14653
  };
14146
14654
  _v$10 !== _p$.e && (_p$.e = setProp(_el$33, "fg", _v$10, _p$.e));
14147
14655
  _v$11 !== _p$.t && (_p$.t = setProp(_el$33, "attributes", _v$11, _p$.t));
@@ -14183,7 +14691,7 @@ function BlockNode(props) {
14183
14691
  var _el$37 = createElement("text");
14184
14692
  insert(_el$37, () => b.lang);
14185
14693
  effect((_p$) => {
14186
- var _v$13 = theme.textMuted, _v$14 = TextAttributes14.DIM;
14694
+ var _v$13 = theme.textMuted, _v$14 = TextAttributes15.DIM;
14187
14695
  _v$13 !== _p$.e && (_p$.e = setProp(_el$37, "fg", _v$13, _p$.e));
14188
14696
  _v$14 !== _p$.t && (_p$.t = setProp(_el$37, "attributes", _v$14, _p$.t));
14189
14697
  return _p$;
@@ -14243,7 +14751,7 @@ var init_Markdown = __esm(() => {
14243
14751
  });
14244
14752
 
14245
14753
  // src/tui/component/update-dialog.tsx
14246
- import { TextAttributes as TextAttributes15 } from "@opentui/core";
14754
+ import { TextAttributes as TextAttributes16 } from "@opentui/core";
14247
14755
  function UpdateDialog(props) {
14248
14756
  const dialog = useDialog();
14249
14757
  const {
@@ -14358,7 +14866,7 @@ function UpdateDialog(props) {
14358
14866
  }
14359
14867
  }));
14360
14868
  effect((_p$) => {
14361
- var _v$ = TextAttributes15.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted, _v$5 = theme.textMuted, _v$6 = theme.warning, _v$7 = TextAttributes15.BOLD, _v$8 = theme.textMuted, _v$9 = theme.accent, _v$0 = TextAttributes15.BOLD, _v$1 = theme.textMuted;
14869
+ var _v$ = TextAttributes16.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted, _v$5 = theme.textMuted, _v$6 = theme.warning, _v$7 = TextAttributes16.BOLD, _v$8 = theme.textMuted, _v$9 = theme.accent, _v$0 = TextAttributes16.BOLD, _v$1 = theme.textMuted;
14362
14870
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
14363
14871
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
14364
14872
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -14409,7 +14917,7 @@ var init_update_dialog = __esm(() => {
14409
14917
  });
14410
14918
 
14411
14919
  // src/tui/component/top-bar.tsx
14412
- import { TextAttributes as TextAttributes16 } from "@opentui/core";
14920
+ import { TextAttributes as TextAttributes17 } from "@opentui/core";
14413
14921
  function TopBar(props) {
14414
14922
  const {
14415
14923
  theme
@@ -14450,7 +14958,7 @@ function TopBar(props) {
14450
14958
  });
14451
14959
  insert(_el$7, () => props.updateInfo()?.latest, _el$9);
14452
14960
  effect((_p$) => {
14453
- var _v$ = theme.warning, _v$2 = TextAttributes16.BOLD;
14961
+ var _v$ = theme.warning, _v$2 = TextAttributes17.BOLD;
14454
14962
  _v$ !== _p$.e && (_p$.e = setProp(_el$7, "fg", _v$, _p$.e));
14455
14963
  _v$2 !== _p$.t && (_p$.t = setProp(_el$7, "attributes", _v$2, _p$.t));
14456
14964
  return _p$;
@@ -14476,7 +14984,7 @@ function TopBar(props) {
14476
14984
  setProp(_el$1, "wrapMode", "none");
14477
14985
  insert(_el$1, () => props.activeTask()?.branch);
14478
14986
  effect((_p$) => {
14479
- var _v$3 = theme.text, _v$4 = TextAttributes16.BOLD;
14987
+ var _v$3 = theme.text, _v$4 = TextAttributes17.BOLD;
14480
14988
  _v$3 !== _p$.e && (_p$.e = setProp(_el$1, "fg", _v$3, _p$.e));
14481
14989
  _v$4 !== _p$.t && (_p$.t = setProp(_el$1, "attributes", _v$4, _p$.t));
14482
14990
  return _p$;
@@ -14501,7 +15009,7 @@ function TopBar(props) {
14501
15009
  }
14502
15010
  }));
14503
15011
  effect((_p$) => {
14504
- var _v$5 = theme.primary, _v$6 = TextAttributes16.BOLD, _v$7 = theme.textMuted;
15012
+ var _v$5 = theme.primary, _v$6 = TextAttributes17.BOLD, _v$7 = theme.textMuted;
14505
15013
  _v$5 !== _p$.e && (_p$.e = setProp(_el$3, "fg", _v$5, _p$.e));
14506
15014
  _v$6 !== _p$.t && (_p$.t = setProp(_el$3, "attributes", _v$6, _p$.t));
14507
15015
  _v$7 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$7, _p$.a));
@@ -14530,93 +15038,6 @@ var init_top_bar = __esm(() => {
14530
15038
  init_update_dialog();
14531
15039
  });
14532
15040
 
14533
- // src/tui/context/kv.tsx
14534
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
14535
- import { homedir as homedir7 } from "os";
14536
- import { dirname as dirname5, join as join11 } from "path";
14537
- function loadInitial() {
14538
- try {
14539
- const text = readFileSync5(STATE_PATH, "utf8");
14540
- const parsed = JSON.parse(text);
14541
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
14542
- return parsed;
14543
- }
14544
- } catch {}
14545
- return {};
14546
- }
14547
- var STATE_PATH, WRITE_DEBOUNCE_MS = 250, useKV, KVProvider;
14548
- var init_kv = __esm(() => {
14549
- init_dev2();
14550
- init_helper();
14551
- STATE_PATH = join11(homedir7(), ".config", "kobe", "state.json");
14552
- ({
14553
- use: useKV,
14554
- provider: KVProvider
14555
- } = createSimpleContext({
14556
- name: "KV",
14557
- init: () => {
14558
- const [store2, setStore2] = createStore(loadInitial());
14559
- let writeTimer = null;
14560
- function scheduleWrite() {
14561
- if (writeTimer)
14562
- clearTimeout(writeTimer);
14563
- writeTimer = setTimeout(() => {
14564
- writeTimer = null;
14565
- try {
14566
- mkdirSync3(dirname5(STATE_PATH), {
14567
- recursive: true
14568
- });
14569
- const tmp = `${STATE_PATH}.tmp`;
14570
- writeFileSync3(tmp, JSON.stringify(store2, null, 2), "utf8");
14571
- renameSync2(tmp, STATE_PATH);
14572
- } catch (err) {
14573
- console.error("[kobe] kv write failed:", err);
14574
- }
14575
- }, WRITE_DEBOUNCE_MS);
14576
- }
14577
- const result = {
14578
- get ready() {
14579
- return true;
14580
- },
14581
- get store() {
14582
- return store2;
14583
- },
14584
- signal(name, defaultValue) {
14585
- if (store2[name] === undefined)
14586
- setStore2(name, defaultValue);
14587
- return [() => result.get(name), (next) => result.set(name, next)];
14588
- },
14589
- get(key, defaultValue) {
14590
- return store2[key] ?? defaultValue;
14591
- },
14592
- set(key, value) {
14593
- setStore2(key, value);
14594
- scheduleWrite();
14595
- },
14596
- clear() {
14597
- for (const k of Object.keys(store2))
14598
- setStore2(k, undefined);
14599
- if (writeTimer) {
14600
- clearTimeout(writeTimer);
14601
- writeTimer = null;
14602
- }
14603
- try {
14604
- mkdirSync3(dirname5(STATE_PATH), {
14605
- recursive: true
14606
- });
14607
- const tmp = `${STATE_PATH}.tmp`;
14608
- writeFileSync3(tmp, JSON.stringify(store2, null, 2), "utf8");
14609
- renameSync2(tmp, STATE_PATH);
14610
- } catch (err) {
14611
- console.error("[kobe] kv clear write failed:", err);
14612
- }
14613
- }
14614
- };
14615
- return result;
14616
- }
14617
- }));
14618
- });
14619
-
14620
15041
  // src/tui/context/sync.tsx
14621
15042
  var EMPTY, useSync, SyncProvider;
14622
15043
  var init_sync = __esm(() => {
@@ -14832,17 +15253,17 @@ class SessionRegistry {
14832
15253
  }
14833
15254
  }
14834
15255
  function waitForExit(proc) {
14835
- return new Promise((resolve3) => {
15256
+ return new Promise((resolve4) => {
14836
15257
  if (proc.exitCode !== null || proc.signalCode !== null) {
14837
- resolve3();
15258
+ resolve4();
14838
15259
  return;
14839
15260
  }
14840
- proc.once("close", () => resolve3());
14841
- proc.once("exit", () => resolve3());
15261
+ proc.once("close", () => resolve4());
15262
+ proc.once("exit", () => resolve4());
14842
15263
  });
14843
15264
  }
14844
15265
  function delay(ms) {
14845
- return new Promise((resolve3) => setTimeout(resolve3, ms));
15266
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
14846
15267
  }
14847
15268
 
14848
15269
  // src/engine/claude-code-local/sessions.ts
@@ -14943,8 +15364,8 @@ var init_sessions = __esm(() => {
14943
15364
  // src/engine/claude-code-local/spawn.ts
14944
15365
  import { spawn as spawn4 } from "child_process";
14945
15366
  function spawnClaudeProcess(opts) {
14946
- const args = buildArgs(opts);
14947
- const proc = spawn4(opts.binaryPath, args, {
15367
+ const args2 = buildArgs(opts);
15368
+ const proc = spawn4(opts.binaryPath, args2, {
14948
15369
  cwd: opts.cwd,
14949
15370
  env: { ...process.env, ...opts.env ?? {} },
14950
15371
  stdio: ["pipe", "pipe", "pipe"]
@@ -14953,30 +15374,30 @@ function spawnClaudeProcess(opts) {
14953
15374
  proc,
14954
15375
  stdout: proc.stdout,
14955
15376
  stderr: proc.stderr,
14956
- args
15377
+ args: args2
14957
15378
  };
14958
15379
  }
14959
15380
  function buildArgs(opts) {
14960
- const args = [];
15381
+ const args2 = [];
14961
15382
  if (opts.resumeSessionId) {
14962
- args.push("--resume", opts.resumeSessionId);
15383
+ args2.push("--resume", opts.resumeSessionId);
14963
15384
  }
14964
- args.push("-p", opts.prompt);
15385
+ args2.push("-p", opts.prompt);
14965
15386
  if (opts.model) {
14966
- args.push("--model", opts.model);
15387
+ args2.push("--model", opts.model);
14967
15388
  }
14968
15389
  if (opts.permissionMode) {
14969
- args.push("--permission-mode", opts.permissionMode);
15390
+ args2.push("--permission-mode", opts.permissionMode);
14970
15391
  }
14971
- args.push("--output-format", "stream-json", "--verbose");
15392
+ args2.push("--output-format", "stream-json", "--verbose");
14972
15393
  const mcpConfig = process.env.KOBE_MCP_CONFIG;
14973
15394
  if (mcpConfig && mcpConfig.length > 0) {
14974
- args.push("--mcp-config", mcpConfig);
15395
+ args2.push("--mcp-config", mcpConfig);
14975
15396
  }
14976
15397
  if (opts.extraArgs && opts.extraArgs.length > 0) {
14977
- args.push(...opts.extraArgs);
15398
+ args2.push(...opts.extraArgs);
14978
15399
  }
14979
- return args;
15400
+ return args2;
14980
15401
  }
14981
15402
  var init_spawn = () => {};
14982
15403
 
@@ -15150,7 +15571,7 @@ class ClaudeCodeLocal {
15150
15571
  }
15151
15572
  if (session.closed)
15152
15573
  return;
15153
- await new Promise((resolve3) => session.waiters.push(resolve3));
15574
+ await new Promise((resolve4) => session.waiters.push(resolve4));
15154
15575
  }
15155
15576
  }
15156
15577
  };
@@ -15174,17 +15595,17 @@ class ClaudeCodeLocal {
15174
15595
  this.running.delete(sid);
15175
15596
  }
15176
15597
  }
15177
- async start(args) {
15598
+ async start(args2) {
15178
15599
  const binaryPath = await this.binaryPathResolver();
15179
- const cliPermissionMode = args.opts?.permissionMode === "plan" ? "plan" : "bypassPermissions";
15600
+ const cliPermissionMode = args2.opts?.permissionMode === "plan" ? "plan" : "bypassPermissions";
15180
15601
  const spawned = spawnClaudeProcess({
15181
15602
  binaryPath,
15182
- cwd: args.cwd,
15183
- prompt: args.prompt,
15184
- model: args.opts?.model,
15603
+ cwd: args2.cwd,
15604
+ prompt: args2.prompt,
15605
+ model: args2.opts?.model,
15185
15606
  permissionMode: cliPermissionMode,
15186
- env: args.opts?.env,
15187
- resumeSessionId: args.resumeSessionId
15607
+ env: args2.opts?.env,
15608
+ resumeSessionId: args2.resumeSessionId
15188
15609
  });
15189
15610
  let resolveHandle = () => {};
15190
15611
  let rejectHandle = () => {};
@@ -15201,7 +15622,7 @@ class ClaudeCodeLocal {
15201
15622
  bound = true;
15202
15623
  session = {
15203
15624
  sessionId,
15204
- cwd: args.cwd,
15625
+ cwd: args2.cwd,
15205
15626
  spawned,
15206
15627
  queue,
15207
15628
  waiters: [],
@@ -15210,15 +15631,15 @@ class ClaudeCodeLocal {
15210
15631
  this.running.set(sessionId, session);
15211
15632
  this.registry.register({
15212
15633
  sessionId,
15213
- cwd: args.cwd,
15634
+ cwd: args2.cwd,
15214
15635
  proc: spawned.proc,
15215
15636
  startedAt: Date.now()
15216
15637
  });
15217
- resolveHandle({ sessionId, cwd: args.cwd });
15638
+ resolveHandle({ sessionId, cwd: args2.cwd });
15218
15639
  };
15219
- if (args.resumeSessionId) {
15640
+ if (args2.resumeSessionId) {
15220
15641
  try {
15221
- bind(args.resumeSessionId);
15642
+ bind(args2.resumeSessionId);
15222
15643
  } catch (err) {
15223
15644
  try {
15224
15645
  spawned.proc.kill("SIGKILL");
@@ -15345,7 +15766,7 @@ class FakeAIEngine {
15345
15766
  }
15346
15767
  if (q.closed)
15347
15768
  return;
15348
- await new Promise((resolve3) => q.waiters.push(resolve3));
15769
+ await new Promise((resolve4) => q.waiters.push(resolve4));
15349
15770
  }
15350
15771
  }
15351
15772
  };
@@ -15641,7 +16062,7 @@ async function mountFakeEngineServer(fake) {
15641
16062
  }
15642
16063
  });
15643
16064
  });
15644
- await new Promise((resolve3) => server.listen(port, "127.0.0.1", () => resolve3()));
16065
+ await new Promise((resolve4) => server.listen(port, "127.0.0.1", () => resolve4()));
15645
16066
  server.unref();
15646
16067
  }
15647
16068
  var init_engine_bootstrap = __esm(() => {
@@ -15669,6 +16090,65 @@ function formatPlanUsageCompact(usage) {
15669
16090
  return `Plan ${parts.join(" \xB7 ")}`;
15670
16091
  }
15671
16092
 
16093
+ // src/tui/lib/use-completion-notifications.ts
16094
+ function tabLabel2(tasks, taskId, tabId) {
16095
+ const task = tasks.find((t) => t.id === taskId);
16096
+ if (!task)
16097
+ return "chat tab";
16098
+ const tab = task.tabs.find((t) => t.id === tabId);
16099
+ const tabName = tab?.title && tab.title.length > 0 ? tab.title : tab ? `chat ${tab.seq}` : "chat";
16100
+ return `${task.title} \u203A ${tabName}`;
16101
+ }
16102
+ function useCompletionNotifications(deps) {
16103
+ let prev = new Map;
16104
+ createEffect(() => {
16105
+ const curr = deps.chatRunState();
16106
+ const visible = deps.visibleTabKey();
16107
+ const tasks = deps.tasks();
16108
+ for (const [key, state] of prev) {
16109
+ const next = curr.get(key);
16110
+ if (state === "running" && next === "awaiting_input") {
16111
+ if (key === visible)
16112
+ continue;
16113
+ const [taskId, tabId] = splitKey(key);
16114
+ if (!taskId || !tabId)
16115
+ continue;
16116
+ deps.notifications.notify({
16117
+ kind: "needs_input",
16118
+ taskId,
16119
+ tabId,
16120
+ title: tabLabel2(tasks, taskId, tabId)
16121
+ });
16122
+ continue;
16123
+ }
16124
+ if ((state === "running" || state === "awaiting_input") && next === undefined) {
16125
+ if (key === visible)
16126
+ continue;
16127
+ const [taskId, tabId] = splitKey(key);
16128
+ if (!taskId || !tabId)
16129
+ continue;
16130
+ deps.notifications.notify({
16131
+ kind: "done",
16132
+ taskId,
16133
+ tabId,
16134
+ title: tabLabel2(tasks, taskId, tabId)
16135
+ });
16136
+ }
16137
+ }
16138
+ prev = curr;
16139
+ });
16140
+ }
16141
+ function splitKey(key) {
16142
+ const idx = key.indexOf(":");
16143
+ if (idx < 0)
16144
+ return [null, null];
16145
+ return [key.slice(0, idx), key.slice(idx + 1)];
16146
+ }
16147
+ var init_use_completion_notifications = __esm(() => {
16148
+ init_dev();
16149
+ init_core();
16150
+ });
16151
+
15672
16152
  // src/tui/lib/use-pane-sizes.ts
15673
16153
  function usePaneSizes(kv) {
15674
16154
  const dims = useTerminalDimensions();
@@ -15856,7 +16336,7 @@ var DEFAULT_BASE_REF = "main", PICKER_MAX_VISIBLE = 8;
15856
16336
  var init_state2 = () => {};
15857
16337
 
15858
16338
  // src/tui/component/new-task-dialog/dialog.tsx
15859
- import { TextAttributes as TextAttributes17 } from "@opentui/core";
16339
+ import { TextAttributes as TextAttributes18 } from "@opentui/core";
15860
16340
  function NewTaskDialogView(props) {
15861
16341
  const dialog = useDialog();
15862
16342
  const {
@@ -16023,7 +16503,7 @@ function NewTaskDialogView(props) {
16023
16503
  insert(_el$36, path8, null);
16024
16504
  insert(_el$36, () => isCurrentDir() ? " (current dir)" : "", null);
16025
16505
  effect((_p$) => {
16026
- var _v$10 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$11 = isCursor() ? TextAttributes17.BOLD : undefined;
16506
+ var _v$10 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$11 = isCursor() ? TextAttributes18.BOLD : undefined;
16027
16507
  _v$10 !== _p$.e && (_p$.e = setProp(_el$36, "fg", _v$10, _p$.e));
16028
16508
  _v$11 !== _p$.t && (_p$.t = setProp(_el$36, "attributes", _v$11, _p$.t));
16029
16509
  return _p$;
@@ -16143,7 +16623,7 @@ function NewTaskDialogView(props) {
16143
16623
  insert(_el$37, () => isCursor() ? "\u25B8 " : " ", null);
16144
16624
  insert(_el$37, name, null);
16145
16625
  effect((_p$) => {
16146
- var _v$12 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$13 = isCursor() ? TextAttributes17.BOLD : undefined;
16626
+ var _v$12 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$13 = isCursor() ? TextAttributes18.BOLD : undefined;
16147
16627
  _v$12 !== _p$.e && (_p$.e = setProp(_el$37, "fg", _v$12, _p$.e));
16148
16628
  _v$13 !== _p$.t && (_p$.t = setProp(_el$37, "attributes", _v$13, _p$.t));
16149
16629
  return _p$;
@@ -16176,7 +16656,7 @@ function NewTaskDialogView(props) {
16176
16656
  setProp(_el$33, "paddingBottom", 1);
16177
16657
  insertNode(_el$34, createTextNode(`\u2191\u2193 pick \xB7 enter select \xB7 tab next field \xB7 esc cancel`));
16178
16658
  effect((_p$) => {
16179
- var _v$ = TextAttributes17.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = field() === "repoCustom" ? theme.accent : theme.textMuted, _v$5 = repo(), _v$6 = props.defaultRepo, _v$7 = field() === "repoCustom", _v$8 = field() === "baseRef" ? theme.accent : theme.textMuted, _v$9 = baseRef(), _v$0 = field() === "baseRef", _v$1 = theme.textMuted;
16659
+ var _v$ = TextAttributes18.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = field() === "repoCustom" ? theme.accent : theme.textMuted, _v$5 = repo(), _v$6 = props.defaultRepo, _v$7 = field() === "repoCustom", _v$8 = field() === "baseRef" ? theme.accent : theme.textMuted, _v$9 = baseRef(), _v$0 = field() === "baseRef", _v$1 = theme.textMuted;
16180
16660
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
16181
16661
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
16182
16662
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -16223,13 +16703,13 @@ var init_dialog2 = __esm(() => {
16223
16703
 
16224
16704
  // src/tui/component/new-task-dialog/index.tsx
16225
16705
  function show(dialog, defaultRepo, savedRepos) {
16226
- return new Promise((resolve3) => {
16706
+ return new Promise((resolve4) => {
16227
16707
  dialog.replace(() => createComponent2(NewTaskDialogView, {
16228
16708
  defaultRepo,
16229
16709
  savedRepos,
16230
- onSubmit: (v) => resolve3(v),
16231
- onCancel: () => resolve3(undefined)
16232
- }), () => resolve3(undefined));
16710
+ onSubmit: (v) => resolve4(v),
16711
+ onCancel: () => resolve4(undefined)
16712
+ }), () => resolve4(undefined));
16233
16713
  dialog.setSize("medium");
16234
16714
  });
16235
16715
  }
@@ -16244,7 +16724,7 @@ var init_new_task_dialog = __esm(() => {
16244
16724
  });
16245
16725
 
16246
16726
  // src/tui/component/rename-task-dialog/dialog.tsx
16247
- import { TextAttributes as TextAttributes18 } from "@opentui/core";
16727
+ import { TextAttributes as TextAttributes19 } from "@opentui/core";
16248
16728
  function RenameTaskDialogView(props) {
16249
16729
  const dialog = useDialog();
16250
16730
  const {
@@ -16284,7 +16764,7 @@ function RenameTaskDialogView(props) {
16284
16764
  setProp(_el$0, "paddingBottom", 1);
16285
16765
  insertNode(_el$1, createTextNode(`enter rename \xB7 esc cancel`));
16286
16766
  effect((_p$) => {
16287
- var _v$ = TextAttributes18.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.accent, _v$5 = title(), _v$6 = props.currentTitle, _v$7 = theme.textMuted;
16767
+ var _v$ = TextAttributes19.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.accent, _v$5 = title(), _v$6 = props.currentTitle, _v$7 = theme.textMuted;
16288
16768
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
16289
16769
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
16290
16770
  _v$3 !== _p$.a && (_p$.a = setProp(_el$4, "fg", _v$3, _p$.a));
@@ -16321,15 +16801,15 @@ var init_dialog3 = __esm(() => {
16321
16801
 
16322
16802
  // src/tui/component/rename-task-dialog/index.tsx
16323
16803
  function show2(dialog, currentTitle, opts = {}) {
16324
- return new Promise((resolve3) => {
16804
+ return new Promise((resolve4) => {
16325
16805
  dialog.replace(() => createComponent2(RenameTaskDialogView, {
16326
16806
  currentTitle,
16327
16807
  get dialogTitle() {
16328
16808
  return opts.dialogTitle;
16329
16809
  },
16330
- onSubmit: (v) => resolve3(v),
16331
- onCancel: () => resolve3(undefined)
16332
- }), () => resolve3(undefined));
16810
+ onSubmit: (v) => resolve4(v),
16811
+ onCancel: () => resolve4(undefined)
16812
+ }), () => resolve4(undefined));
16333
16813
  });
16334
16814
  }
16335
16815
  var RenameTaskDialog;
@@ -16607,7 +17087,7 @@ var init_use_workspace_tabs = __esm(() => {
16607
17087
  });
16608
17088
 
16609
17089
  // src/tui/component/resume-dialog.tsx
16610
- import { TextAttributes as TextAttributes19 } from "@opentui/core";
17090
+ import { TextAttributes as TextAttributes20 } from "@opentui/core";
16611
17091
  function ResumeDialog(props) {
16612
17092
  const dialog = useDialog();
16613
17093
  const {
@@ -16754,7 +17234,7 @@ function ResumeDialog(props) {
16754
17234
  setProp(_el$9, "paddingBottom", 1);
16755
17235
  insertNode(_el$0, createTextNode(`j/k or \u2191\u2193 navigate \u2022 enter resume \u2022 esc dismiss`));
16756
17236
  effect((_p$) => {
16757
- var _v$ = TextAttributes19.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
17237
+ var _v$ = TextAttributes20.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
16758
17238
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
16759
17239
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
16760
17240
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -16893,10 +17373,10 @@ var init_history2 = __esm(() => {
16893
17373
 
16894
17374
  // src/tui/panes/chat/composer/image-paste.ts
16895
17375
  import { randomUUID } from "crypto";
16896
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
16897
- import { join as join12 } from "path";
17376
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "fs";
17377
+ import { join as join13 } from "path";
16898
17378
  function pastedImagesDir() {
16899
- return join12(kobeStateDir(), "pasted-images");
17379
+ return join13(kobeStateDir(), "pasted-images");
16900
17380
  }
16901
17381
 
16902
17382
  class ImagePasteRegistry {
@@ -16905,7 +17385,7 @@ class ImagePasteRegistry {
16905
17385
  saveBytes(bytes, mimeType) {
16906
17386
  const ext = mimeTypeToExt(mimeType);
16907
17387
  const absPath = mintPath(ext);
16908
- mkdirSync4(pastedImagesDir(), { recursive: true });
17388
+ mkdirSync5(pastedImagesDir(), { recursive: true });
16909
17389
  writeFileSync4(absPath, bytes);
16910
17390
  return this.register(absPath);
16911
17391
  }
@@ -16913,7 +17393,7 @@ class ImagePasteRegistry {
16913
17393
  if (!clipboardImageSupported())
16914
17394
  return null;
16915
17395
  const absPath = mintPath(".png");
16916
- mkdirSync4(pastedImagesDir(), { recursive: true });
17396
+ mkdirSync5(pastedImagesDir(), { recursive: true });
16917
17397
  const meta = readClipboardImageToFile(absPath);
16918
17398
  if (!meta)
16919
17399
  return null;
@@ -16976,7 +17456,7 @@ function mimeTypeToExt(mimeType) {
16976
17456
  return ".png";
16977
17457
  }
16978
17458
  function mintPath(ext) {
16979
- return join12(pastedImagesDir(), `${randomUUID()}${ext}`);
17459
+ return join13(pastedImagesDir(), `${randomUUID()}${ext}`);
16980
17460
  }
16981
17461
  var IMAGE_TOKEN_RE;
16982
17462
  var init_image_paste = __esm(() => {
@@ -17079,7 +17559,7 @@ var init_mention = __esm(() => {
17079
17559
  });
17080
17560
 
17081
17561
  // src/tui/panes/chat/Composer.tsx
17082
- import { TextAttributes as TextAttributes20 } from "@opentui/core";
17562
+ import { TextAttributes as TextAttributes21 } from "@opentui/core";
17083
17563
  function resolvePlaceholder(opts) {
17084
17564
  if (!opts.hasTask)
17085
17565
  return opts.noTaskMessage ?? "(no task \u2014 press n to create)";
@@ -17173,21 +17653,21 @@ function Composer(props) {
17173
17653
  return findMentionContext(liveBuffer(), liveCursor());
17174
17654
  });
17175
17655
  createEffect(() => {
17176
- const ctx3 = mentionContext();
17656
+ const ctx4 = mentionContext();
17177
17657
  const dismissed = mentionDismissedAt();
17178
17658
  if (dismissed === null)
17179
17659
  return;
17180
- if (!ctx3 || ctx3.atPos !== dismissed)
17660
+ if (!ctx4 || ctx4.atPos !== dismissed)
17181
17661
  setMentionDismissedAt(null);
17182
17662
  });
17183
17663
  const MENTION_MAX_VISIBLE = 8;
17184
17664
  const mentionMatches = createMemo(() => {
17185
- const ctx3 = mentionContext();
17186
- if (!ctx3)
17665
+ const ctx4 = mentionContext();
17666
+ if (!ctx4)
17187
17667
  return [];
17188
- if (mentionDismissedAt() === ctx3.atPos)
17668
+ if (mentionDismissedAt() === ctx4.atPos)
17189
17669
  return [];
17190
- return filterMentionMatches(mentionFiles(), ctx3.query, MENTION_MAX_VISIBLE * 4);
17670
+ return filterMentionMatches(mentionFiles(), ctx4.query, MENTION_MAX_VISIBLE * 4);
17191
17671
  });
17192
17672
  const mentionOpen = createMemo(() => !slashOpen() && mentionMatches().length > 0);
17193
17673
  createEffect(() => {
@@ -17216,11 +17696,11 @@ function Composer(props) {
17216
17696
  });
17217
17697
  function insertMentionSelection(path8) {
17218
17698
  const ref = textareaRef;
17219
- const ctx3 = mentionContext();
17220
- if (!ref || !ctx3)
17699
+ const ctx4 = mentionContext();
17700
+ if (!ref || !ctx4)
17221
17701
  return;
17222
17702
  const cursor = ref.cursorOffset;
17223
- ref.setSelection(ctx3.atPos, cursor);
17703
+ ref.setSelection(ctx4.atPos, cursor);
17224
17704
  ref.deleteSelection();
17225
17705
  const inserted = `@${path8} `;
17226
17706
  ref.insertText(inserted);
@@ -17456,9 +17936,9 @@ function Composer(props) {
17456
17936
  }
17457
17937
  }
17458
17938
  if (key.name === "escape") {
17459
- const ctx3 = mentionContext();
17460
- if (ctx3)
17461
- setMentionDismissedAt(ctx3.atPos);
17939
+ const ctx4 = mentionContext();
17940
+ if (ctx4)
17941
+ setMentionDismissedAt(ctx4.atPos);
17462
17942
  key.preventDefault();
17463
17943
  return;
17464
17944
  }
@@ -17647,7 +18127,7 @@ function Composer(props) {
17647
18127
  }
17648
18128
  }), null);
17649
18129
  effect((_p$) => {
17650
- var _v$20 = active() ? theme.primary : theme.text, _v$21 = active() ? TextAttributes20.BOLD : undefined;
18130
+ var _v$20 = active() ? theme.primary : theme.text, _v$21 = active() ? TextAttributes21.BOLD : undefined;
17651
18131
  _v$20 !== _p$.e && (_p$.e = setProp(_el$28, "fg", _v$20, _p$.e));
17652
18132
  _v$21 !== _p$.t && (_p$.t = setProp(_el$28, "attributes", _v$21, _p$.t));
17653
18133
  return _p$;
@@ -17754,7 +18234,7 @@ function Composer(props) {
17754
18234
  }
17755
18235
  }), null);
17756
18236
  effect((_p$) => {
17757
- var _v$22 = active() ? theme.primary : theme.text, _v$23 = active() ? TextAttributes20.BOLD : undefined;
18237
+ var _v$22 = active() ? theme.primary : theme.text, _v$23 = active() ? TextAttributes21.BOLD : undefined;
17758
18238
  _v$22 !== _p$.e && (_p$.e = setProp(_el$31, "fg", _v$22, _p$.e));
17759
18239
  _v$23 !== _p$.t && (_p$.t = setProp(_el$31, "attributes", _v$23, _p$.t));
17760
18240
  return _p$;
@@ -18588,7 +19068,7 @@ function summarizeGlob(input, output, done) {
18588
19068
  }
18589
19069
 
18590
19070
  // src/tui/panes/chat/MessageList.tsx
18591
- import { TextAttributes as TextAttributes21 } from "@opentui/core";
19071
+ import { TextAttributes as TextAttributes22 } from "@opentui/core";
18592
19072
  function previewToolInput(input) {
18593
19073
  if (input == null)
18594
19074
  return "";
@@ -18636,11 +19116,11 @@ function UserRow(props) {
18636
19116
  const text = props.text;
18637
19117
  const cmd = extractTag(text, COMMAND_NAME_TAG);
18638
19118
  if (cmd) {
18639
- const args = extractTag(text, COMMAND_ARGS_TAG) ?? "";
19119
+ const args2 = extractTag(text, COMMAND_ARGS_TAG) ?? "";
18640
19120
  return {
18641
19121
  kind: "command",
18642
19122
  command: cmd,
18643
- args
19123
+ args: args2
18644
19124
  };
18645
19125
  }
18646
19126
  const stdout = extractTag(text, LOCAL_COMMAND_STDOUT_TAG);
@@ -18684,7 +19164,7 @@ function UserRow(props) {
18684
19164
  })() : null;
18685
19165
  })(), null);
18686
19166
  effect((_p$) => {
18687
- var _v$ = theme.accent, _v$2 = TextAttributes21.BOLD, _v$3 = theme.primary, _v$4 = TextAttributes21.BOLD;
19167
+ var _v$ = theme.accent, _v$2 = TextAttributes22.BOLD, _v$3 = theme.primary, _v$4 = TextAttributes22.BOLD;
18688
19168
  _v$ !== _p$.e && (_p$.e = setProp(_el$2, "fg", _v$, _p$.e));
18689
19169
  _v$2 !== _p$.t && (_p$.t = setProp(_el$2, "attributes", _v$2, _p$.t));
18690
19170
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -18764,7 +19244,7 @@ function UserRow(props) {
18764
19244
  setProp(_el$21, "flexGrow", 1);
18765
19245
  insert(_el$22, () => view.text);
18766
19246
  effect((_p$) => {
18767
- var _v$9 = theme.accent, _v$0 = TextAttributes21.BOLD, _v$1 = theme.text;
19247
+ var _v$9 = theme.accent, _v$0 = TextAttributes22.BOLD, _v$1 = theme.text;
18768
19248
  _v$9 !== _p$.e && (_p$.e = setProp(_el$19, "fg", _v$9, _p$.e));
18769
19249
  _v$0 !== _p$.t && (_p$.t = setProp(_el$19, "attributes", _v$0, _p$.t));
18770
19250
  _v$1 !== _p$.a && (_p$.a = setProp(_el$22, "fg", _v$1, _p$.a));
@@ -18800,7 +19280,7 @@ function AssistantRow(props) {
18800
19280
  }
18801
19281
  }));
18802
19282
  effect((_p$) => {
18803
- var _v$10 = theme.accent, _v$11 = TextAttributes21.BOLD;
19283
+ var _v$10 = theme.accent, _v$11 = TextAttributes22.BOLD;
18804
19284
  _v$10 !== _p$.e && (_p$.e = setProp(_el$25, "fg", _v$10, _p$.e));
18805
19285
  _v$11 !== _p$.t && (_p$.t = setProp(_el$25, "attributes", _v$11, _p$.t));
18806
19286
  return _p$;
@@ -18875,7 +19355,7 @@ function ToolRow(props) {
18875
19355
  }), null);
18876
19356
  effect((_p$) => {
18877
19357
  var _v$18 = theme.text, _v$19 = {
18878
- attributes: TextAttributes21.BOLD
19358
+ attributes: TextAttributes22.BOLD
18879
19359
  };
18880
19360
  _v$18 !== _p$.e && (_p$.e = setProp(_el$45, "fg", _v$18, _p$.e));
18881
19361
  _v$19 !== _p$.t && (_p$.t = setProp(_el$46, "style", _v$19, _p$.t));
@@ -19043,7 +19523,7 @@ function ToolRow(props) {
19043
19523
  }
19044
19524
  }), null);
19045
19525
  effect((_p$) => {
19046
- var _v$16 = prefixColor(), _v$17 = TextAttributes21.BOLD;
19526
+ var _v$16 = prefixColor(), _v$17 = TextAttributes22.BOLD;
19047
19527
  _v$16 !== _p$.e && (_p$.e = setProp(_el$29, "fg", _v$16, _p$.e));
19048
19528
  _v$17 !== _p$.t && (_p$.t = setProp(_el$29, "attributes", _v$17, _p$.t));
19049
19529
  return _p$;
@@ -19282,7 +19762,7 @@ function BashBanner(props) {
19282
19762
  }
19283
19763
  }), null);
19284
19764
  effect((_p$) => {
19285
- var _v$28 = theme.accent, _v$29 = TextAttributes21.BOLD, _v$30 = theme.text;
19765
+ var _v$28 = theme.accent, _v$29 = TextAttributes22.BOLD, _v$30 = theme.text;
19286
19766
  _v$28 !== _p$.e && (_p$.e = setProp(_el$73, "fg", _v$28, _p$.e));
19287
19767
  _v$29 !== _p$.t && (_p$.t = setProp(_el$73, "attributes", _v$29, _p$.t));
19288
19768
  _v$30 !== _p$.a && (_p$.a = setProp(_el$76, "fg", _v$30, _p$.a));
@@ -19370,7 +19850,7 @@ function ReadGrepGlobBanner(props) {
19370
19850
  }), null);
19371
19851
  effect((_p$) => {
19372
19852
  var _v$31 = theme.text, _v$32 = {
19373
- attributes: TextAttributes21.BOLD
19853
+ attributes: TextAttributes22.BOLD
19374
19854
  };
19375
19855
  _v$31 !== _p$.e && (_p$.e = setProp(_el$81, "fg", _v$31, _p$.e));
19376
19856
  _v$32 !== _p$.t && (_p$.t = setProp(_el$82, "style", _v$32, _p$.t));
@@ -19399,7 +19879,7 @@ function SystemRow(props) {
19399
19879
  setProp(_el$87, "flexGrow", 1);
19400
19880
  insert(_el$88, () => props.text);
19401
19881
  effect((_p$) => {
19402
- var _v$33 = theme.textMuted, _v$34 = TextAttributes21.DIM, _v$35 = isError() ? theme.error : theme.textMuted;
19882
+ var _v$33 = theme.textMuted, _v$34 = TextAttributes22.DIM, _v$35 = isError() ? theme.error : theme.textMuted;
19403
19883
  _v$33 !== _p$.e && (_p$.e = setProp(_el$85, "fg", _v$33, _p$.e));
19404
19884
  _v$34 !== _p$.t && (_p$.t = setProp(_el$85, "attributes", _v$34, _p$.t));
19405
19885
  _v$35 !== _p$.a && (_p$.a = setProp(_el$88, "fg", _v$35, _p$.a));
@@ -19489,7 +19969,7 @@ function ApprovalRow(props) {
19489
19969
  insertNode(_el$103, _el$105);
19490
19970
  insert(_el$103, () => r().status, _el$105);
19491
19971
  effect((_p$) => {
19492
- var _v$44 = r().status === "approved" ? theme.success : theme.error, _v$45 = TextAttributes21.BOLD;
19972
+ var _v$44 = r().status === "approved" ? theme.success : theme.error, _v$45 = TextAttributes22.BOLD;
19493
19973
  _v$44 !== _p$.e && (_p$.e = setProp(_el$103, "fg", _v$44, _p$.e));
19494
19974
  _v$45 !== _p$.t && (_p$.t = setProp(_el$103, "attributes", _v$45, _p$.t));
19495
19975
  return _p$;
@@ -19506,7 +19986,7 @@ function ApprovalRow(props) {
19506
19986
  insertNode(_el$99, createTextNode(`[ Approve ]`));
19507
19987
  setProp(_el$99, "onMouseUp", () => props.onApprove(true));
19508
19988
  effect((_p$) => {
19509
- var _v$36 = theme.success, _v$37 = TextAttributes21.BOLD;
19989
+ var _v$36 = theme.success, _v$37 = TextAttributes22.BOLD;
19510
19990
  _v$36 !== _p$.e && (_p$.e = setProp(_el$99, "fg", _v$36, _p$.e));
19511
19991
  _v$37 !== _p$.t && (_p$.t = setProp(_el$99, "attributes", _v$37, _p$.t));
19512
19992
  return _p$;
@@ -19520,7 +20000,7 @@ function ApprovalRow(props) {
19520
20000
  insertNode(_el$101, createTextNode(`[ Reject ]`));
19521
20001
  setProp(_el$101, "onMouseUp", () => props.onApprove(false));
19522
20002
  effect((_p$) => {
19523
- var _v$38 = theme.error, _v$39 = TextAttributes21.BOLD;
20003
+ var _v$38 = theme.error, _v$39 = TextAttributes22.BOLD;
19524
20004
  _v$38 !== _p$.e && (_p$.e = setProp(_el$101, "fg", _v$38, _p$.e));
19525
20005
  _v$39 !== _p$.t && (_p$.t = setProp(_el$101, "attributes", _v$39, _p$.t));
19526
20006
  return _p$;
@@ -19533,7 +20013,7 @@ function ApprovalRow(props) {
19533
20013
  }
19534
20014
  }));
19535
20015
  effect((_p$) => {
19536
- var _v$40 = headerColor(), _v$41 = TextAttributes21.BOLD, _v$42 = headerColor(), _v$43 = TextAttributes21.BOLD;
20016
+ var _v$40 = headerColor(), _v$41 = TextAttributes22.BOLD, _v$42 = headerColor(), _v$43 = TextAttributes22.BOLD;
19537
20017
  _v$40 !== _p$.e && (_p$.e = setProp(_el$91, "fg", _v$40, _p$.e));
19538
20018
  _v$41 !== _p$.t && (_p$.t = setProp(_el$91, "attributes", _v$41, _p$.t));
19539
20019
  _v$42 !== _p$.a && (_p$.a = setProp(_el$92, "fg", _v$42, _p$.a));
@@ -19555,9 +20035,35 @@ function QuestionRow(props) {
19555
20035
  const r = () => props.row;
19556
20036
  const isAnswered = () => r().answers !== null;
19557
20037
  const [selections, setSelections] = createSignal({});
20038
+ const [otherText, setOtherText] = createSignal({});
20039
+ const [currentIndex, setCurrentIndex] = createSignal(0);
19558
20040
  function pickedFor(questionText) {
19559
20041
  return selections()[questionText] ?? new Set;
19560
20042
  }
20043
+ function customTextFor(questionText) {
20044
+ return otherText()[questionText] ?? "";
20045
+ }
20046
+ function setCustomText(questionText, value) {
20047
+ const sanitized = value.replace(/[\r\n]+/g, "");
20048
+ setOtherText((prev) => ({
20049
+ ...prev,
20050
+ [questionText]: sanitized
20051
+ }));
20052
+ }
20053
+ function currentOtherActive() {
20054
+ if (isAnswered())
20055
+ return false;
20056
+ const q = r().questions[currentIndex()];
20057
+ if (!q)
20058
+ return false;
20059
+ return pickedFor(q.question).has(OTHER_SENTINEL);
20060
+ }
20061
+ createEffect(() => {
20062
+ props.onClaimComposerFocus?.(currentOtherActive());
20063
+ });
20064
+ onCleanup(() => {
20065
+ props.onClaimComposerFocus?.(false);
20066
+ });
19561
20067
  function toggle(questionText, multi, label) {
19562
20068
  setSelections((prev) => {
19563
20069
  const cur = new Set(prev[questionText] ?? []);
@@ -19580,9 +20086,34 @@ function QuestionRow(props) {
19580
20086
  };
19581
20087
  });
19582
20088
  }
20089
+ function renderedAnswerFor(q) {
20090
+ const picked = pickedFor(q.question);
20091
+ const ordered = [];
20092
+ for (const o of q.options) {
20093
+ if (picked.has(o.label))
20094
+ ordered.push(o.label);
20095
+ }
20096
+ if (picked.has(OTHER_SENTINEL)) {
20097
+ const txt = customTextFor(q.question).trim();
20098
+ if (txt)
20099
+ ordered.push(txt);
20100
+ }
20101
+ return ordered.join(", ");
20102
+ }
20103
+ function isQuestionComplete(qIdx) {
20104
+ const q = r().questions[qIdx];
20105
+ if (!q)
20106
+ return false;
20107
+ const picked = pickedFor(q.question);
20108
+ if (picked.size === 0)
20109
+ return false;
20110
+ if (picked.has(OTHER_SENTINEL) && customTextFor(q.question).trim().length === 0)
20111
+ return false;
20112
+ return true;
20113
+ }
19583
20114
  const allAnswered = () => {
19584
- for (const q of r().questions) {
19585
- if (pickedFor(q.question).size === 0)
20115
+ for (let i = 0;i < r().questions.length; i++) {
20116
+ if (!isQuestionComplete(i))
19586
20117
  return false;
19587
20118
  }
19588
20119
  return true;
@@ -19592,16 +20123,73 @@ function QuestionRow(props) {
19592
20123
  return;
19593
20124
  const answers = {};
19594
20125
  for (const q of r().questions) {
19595
- const picked = Array.from(pickedFor(q.question));
19596
- const ordered = q.options.map((o) => o.label).filter((l) => picked.includes(l));
19597
- answers[q.question] = ordered.join(", ");
20126
+ answers[q.question] = renderedAnswerFor(q);
19598
20127
  }
19599
20128
  props.onAnswer(answers);
19600
20129
  }
20130
+ function advanceOrSubmit() {
20131
+ if (isAnswered())
20132
+ return;
20133
+ const i = currentIndex();
20134
+ if (!isQuestionComplete(i))
20135
+ return;
20136
+ if (i >= r().questions.length - 1) {
20137
+ submit();
20138
+ } else {
20139
+ setCurrentIndex(i + 1);
20140
+ }
20141
+ }
20142
+ const [highlighted, setHighlighted] = createSignal(0);
20143
+ createEffect(() => {
20144
+ currentIndex();
20145
+ setHighlighted(0);
20146
+ });
20147
+ function toggleByIndex(qIdx, optIdx) {
20148
+ const q = r().questions[qIdx];
20149
+ if (!q)
20150
+ return;
20151
+ if (optIdx === q.options.length) {
20152
+ toggle(q.question, q.multiSelect, OTHER_SENTINEL);
20153
+ } else {
20154
+ const opt = q.options[optIdx];
20155
+ if (opt)
20156
+ toggle(q.question, q.multiSelect, opt.label);
20157
+ }
20158
+ }
20159
+ useBindings(() => ({
20160
+ enabled: !isAnswered() && !currentOtherActive() && (props.chatFocused?.() ?? true),
20161
+ bindings: bindByIds({
20162
+ "chat.question.nav": (evt) => {
20163
+ const q = r().questions[currentIndex()];
20164
+ if (!q)
20165
+ return;
20166
+ const max = q.options.length;
20167
+ if (evt.name === "j" || evt.name === "down") {
20168
+ setHighlighted((i) => Math.min(i + 1, max));
20169
+ } else if (evt.name === "k" || evt.name === "up") {
20170
+ setHighlighted((i) => Math.max(i - 1, 0));
20171
+ }
20172
+ },
20173
+ "chat.question.toggle": () => toggleByIndex(currentIndex(), highlighted()),
20174
+ "chat.question.submit": () => advanceOrSubmit(),
20175
+ "chat.question.pick-number": (evt) => {
20176
+ const n = Number.parseInt(evt.name ?? "", 10);
20177
+ if (!Number.isFinite(n) || n < 1)
20178
+ return;
20179
+ const q = r().questions[currentIndex()];
20180
+ if (!q)
20181
+ return;
20182
+ const idx = n - 1;
20183
+ if (idx > q.options.length)
20184
+ return;
20185
+ setHighlighted(idx);
20186
+ toggleByIndex(currentIndex(), idx);
20187
+ }
20188
+ })
20189
+ }));
19601
20190
  return (() => {
19602
- var _el$106 = createElement("box"), _el$107 = createElement("box"), _el$108 = createElement("text"), _el$110 = createElement("text"), _el$111 = createElement("box");
20191
+ var _el$106 = createElement("box"), _el$107 = createElement("box"), _el$108 = createElement("text"), _el$110 = createElement("text");
19603
20192
  insertNode(_el$106, _el$107);
19604
- insertNode(_el$106, _el$111);
19605
20193
  setProp(_el$106, "paddingTop", 1);
19606
20194
  setProp(_el$106, "flexDirection", "column");
19607
20195
  setProp(_el$106, "gap", 0);
@@ -19615,184 +20203,302 @@ function QuestionRow(props) {
19615
20203
  get each() {
19616
20204
  return r().questions;
19617
20205
  },
19618
- children: (q) => {
20206
+ children: (q, index) => {
19619
20207
  const finalAnswer = () => r().answers?.[q.question] ?? null;
19620
20208
  const picked = () => pickedFor(q.question);
19621
- return (() => {
19622
- var _el$116 = createElement("box"), _el$117 = createElement("box"), _el$121 = createElement("text");
19623
- insertNode(_el$116, _el$117);
19624
- setProp(_el$116, "paddingLeft", 2);
19625
- setProp(_el$116, "paddingTop", 1);
19626
- setProp(_el$116, "flexDirection", "column");
19627
- setProp(_el$116, "gap", 0);
19628
- insertNode(_el$117, _el$121);
19629
- setProp(_el$117, "flexDirection", "row");
19630
- setProp(_el$117, "gap", 1);
19631
- insert(_el$117, createComponent2(Show, {
19632
- get when() {
19633
- return q.header;
19634
- },
19635
- get children() {
19636
- var _el$118 = createElement("text"), _el$119 = createTextNode(`[`), _el$120 = createTextNode(`]`);
19637
- insertNode(_el$118, _el$119);
19638
- insertNode(_el$118, _el$120);
19639
- insert(_el$118, () => q.header, _el$120);
19640
- effect((_p$) => {
19641
- var _v$52 = theme.accent, _v$53 = TextAttributes21.BOLD;
19642
- _v$52 !== _p$.e && (_p$.e = setProp(_el$118, "fg", _v$52, _p$.e));
19643
- _v$53 !== _p$.t && (_p$.t = setProp(_el$118, "attributes", _v$53, _p$.t));
19644
- return _p$;
19645
- }, {
19646
- e: undefined,
19647
- t: undefined
19648
- });
19649
- return _el$118;
19650
- }
19651
- }), _el$121);
19652
- insert(_el$121, () => q.question);
19653
- insert(_el$117, createComponent2(Show, {
19654
- get when() {
19655
- return q.multiSelect;
19656
- },
19657
- get children() {
19658
- var _el$122 = createElement("text");
19659
- insertNode(_el$122, createTextNode(`(pick any)`));
19660
- effect((_$p) => setProp(_el$122, "fg", theme.textMuted, _$p));
19661
- return _el$122;
19662
- }
19663
- }), null);
19664
- insert(_el$116, createComponent2(Show, {
19665
- get when() {
19666
- return isAnswered();
19667
- },
19668
- get children() {
19669
- var _el$124 = createElement("box"), _el$125 = createElement("text"), _el$126 = createTextNode(`\u23BF `);
19670
- insertNode(_el$124, _el$125);
19671
- setProp(_el$124, "paddingLeft", 2);
19672
- insertNode(_el$125, _el$126);
19673
- insert(_el$125, (() => {
19674
- var _c$2 = memo2(() => !!(finalAnswer() && finalAnswer().length > 0));
19675
- return () => _c$2() ? finalAnswer() : "(no answer)";
19676
- })(), null);
19677
- effect((_$p) => setProp(_el$125, "fg", theme.success, _$p));
19678
- return _el$124;
19679
- }
19680
- }), null);
19681
- insert(_el$116, createComponent2(Show, {
19682
- get when() {
19683
- return !isAnswered();
19684
- },
19685
- get children() {
19686
- var _el$127 = createElement("box");
19687
- setProp(_el$127, "paddingLeft", 2);
19688
- setProp(_el$127, "flexDirection", "column");
19689
- insert(_el$127, createComponent2(For, {
19690
- get each() {
19691
- return q.options;
19692
- },
19693
- children: (opt) => {
19694
- const isPicked = () => picked().has(opt.label);
19695
- const glyph = () => q.multiSelect ? isPicked() ? "[x]" : "[ ]" : isPicked() ? "(\u2022)" : "( )";
19696
- return (() => {
19697
- var _el$128 = createElement("box"), _el$129 = createElement("text"), _el$130 = createElement("box"), _el$131 = createElement("text");
19698
- insertNode(_el$128, _el$129);
19699
- insertNode(_el$128, _el$130);
19700
- setProp(_el$128, "flexDirection", "row");
19701
- setProp(_el$128, "gap", 1);
19702
- setProp(_el$128, "onMouseUp", () => toggle(q.question, q.multiSelect, opt.label));
19703
- insert(_el$129, glyph);
19704
- insertNode(_el$130, _el$131);
19705
- setProp(_el$130, "flexGrow", 1);
19706
- setProp(_el$130, "flexDirection", "column");
19707
- insert(_el$131, () => opt.label);
19708
- insert(_el$130, createComponent2(Show, {
19709
- get when() {
19710
- return opt.description;
19711
- },
19712
- get children() {
19713
- var _el$132 = createElement("text");
19714
- insert(_el$132, () => opt.description);
19715
- effect((_$p) => setProp(_el$132, "fg", theme.textMuted, _$p));
19716
- return _el$132;
19717
- }
19718
- }), null);
20209
+ const isCurrent = () => !isAnswered() && index() === currentIndex();
20210
+ const isPast = () => !isAnswered() && index() < currentIndex();
20211
+ const isFuture = () => !isAnswered() && index() > currentIndex();
20212
+ const isLast = () => index() === r().questions.length - 1;
20213
+ const buttonLabel = () => isLast() ? "[ Submit ]" : "[ Next ]";
20214
+ return createComponent2(Show, {
20215
+ get when() {
20216
+ return !isFuture();
20217
+ },
20218
+ get children() {
20219
+ var _el$114 = createElement("box"), _el$115 = createElement("box"), _el$119 = createElement("text");
20220
+ insertNode(_el$114, _el$115);
20221
+ setProp(_el$114, "paddingLeft", 2);
20222
+ setProp(_el$114, "paddingTop", 1);
20223
+ setProp(_el$114, "flexDirection", "column");
20224
+ setProp(_el$114, "gap", 0);
20225
+ insertNode(_el$115, _el$119);
20226
+ setProp(_el$115, "flexDirection", "row");
20227
+ setProp(_el$115, "gap", 1);
20228
+ insert(_el$115, createComponent2(Show, {
20229
+ get when() {
20230
+ return q.header;
20231
+ },
20232
+ get children() {
20233
+ var _el$116 = createElement("text"), _el$117 = createTextNode(`[`), _el$118 = createTextNode(`]`);
20234
+ insertNode(_el$116, _el$117);
20235
+ insertNode(_el$116, _el$118);
20236
+ insert(_el$116, () => q.header, _el$118);
20237
+ effect((_p$) => {
20238
+ var _v$52 = theme.accent, _v$53 = TextAttributes22.BOLD;
20239
+ _v$52 !== _p$.e && (_p$.e = setProp(_el$116, "fg", _v$52, _p$.e));
20240
+ _v$53 !== _p$.t && (_p$.t = setProp(_el$116, "attributes", _v$53, _p$.t));
20241
+ return _p$;
20242
+ }, {
20243
+ e: undefined,
20244
+ t: undefined
20245
+ });
20246
+ return _el$116;
20247
+ }
20248
+ }), _el$119);
20249
+ insert(_el$119, () => q.question);
20250
+ insert(_el$115, createComponent2(Show, {
20251
+ get when() {
20252
+ return memo2(() => !!q.multiSelect)() && isCurrent();
20253
+ },
20254
+ get children() {
20255
+ var _el$120 = createElement("text");
20256
+ insertNode(_el$120, createTextNode(`(pick any)`));
20257
+ effect((_$p) => setProp(_el$120, "fg", theme.textMuted, _$p));
20258
+ return _el$120;
20259
+ }
20260
+ }), null);
20261
+ insert(_el$115, createComponent2(Show, {
20262
+ get when() {
20263
+ return isPast();
20264
+ },
20265
+ get children() {
20266
+ var _el$122 = createElement("text");
20267
+ insertNode(_el$122, createTextNode(`(click to edit)`));
20268
+ effect((_$p) => setProp(_el$122, "fg", theme.textMuted, _$p));
20269
+ return _el$122;
20270
+ }
20271
+ }), null);
20272
+ insert(_el$114, createComponent2(Show, {
20273
+ get when() {
20274
+ return isAnswered();
20275
+ },
20276
+ get children() {
20277
+ var _el$124 = createElement("box"), _el$125 = createElement("text"), _el$126 = createTextNode(`\u23BF `);
20278
+ insertNode(_el$124, _el$125);
20279
+ setProp(_el$124, "paddingLeft", 2);
20280
+ insertNode(_el$125, _el$126);
20281
+ insert(_el$125, (() => {
20282
+ var _c$2 = memo2(() => !!(finalAnswer() && finalAnswer().length > 0));
20283
+ return () => _c$2() ? finalAnswer() : "(no answer)";
20284
+ })(), null);
20285
+ effect((_$p) => setProp(_el$125, "fg", theme.success, _$p));
20286
+ return _el$124;
20287
+ }
20288
+ }), null);
20289
+ insert(_el$114, createComponent2(Show, {
20290
+ get when() {
20291
+ return isPast();
20292
+ },
20293
+ get children() {
20294
+ var _el$127 = createElement("box"), _el$128 = createElement("text"), _el$129 = createTextNode(`\u23BF `);
20295
+ insertNode(_el$127, _el$128);
20296
+ setProp(_el$127, "paddingLeft", 2);
20297
+ insertNode(_el$128, _el$129);
20298
+ insert(_el$128, (() => {
20299
+ var _c$3 = memo2(() => renderedAnswerFor(q).length > 0);
20300
+ return () => _c$3() ? renderedAnswerFor(q) : "(no answer)";
20301
+ })(), null);
20302
+ effect((_$p) => setProp(_el$128, "fg", theme.textMuted, _$p));
20303
+ return _el$127;
20304
+ }
20305
+ }), null);
20306
+ insert(_el$114, createComponent2(Show, {
20307
+ get when() {
20308
+ return isCurrent();
20309
+ },
20310
+ get children() {
20311
+ var _el$130 = createElement("box"), _el$131 = createElement("box"), _el$132 = createElement("text");
20312
+ insertNode(_el$130, _el$131);
20313
+ setProp(_el$130, "paddingLeft", 2);
20314
+ setProp(_el$130, "flexDirection", "column");
20315
+ insert(_el$130, createComponent2(For, {
20316
+ get each() {
20317
+ return q.options;
20318
+ },
20319
+ children: (opt, optIndex) => {
20320
+ const isPicked = () => picked().has(opt.label);
20321
+ const isHl = () => highlighted() === optIndex();
20322
+ const glyph = () => q.multiSelect ? isPicked() ? "[x]" : "[ ]" : isPicked() ? "(\u2022)" : "( )";
20323
+ const digitChip = () => optIndex() < 9 ? `${optIndex() + 1}.` : " ";
20324
+ return (() => {
20325
+ var _el$135 = createElement("box"), _el$136 = createElement("text"), _el$137 = createElement("text"), _el$138 = createElement("text"), _el$139 = createElement("box"), _el$140 = createElement("text");
20326
+ insertNode(_el$135, _el$136);
20327
+ insertNode(_el$135, _el$137);
20328
+ insertNode(_el$135, _el$138);
20329
+ insertNode(_el$135, _el$139);
20330
+ setProp(_el$135, "flexDirection", "row");
20331
+ setProp(_el$135, "gap", 1);
20332
+ setProp(_el$135, "onMouseUp", () => toggle(q.question, q.multiSelect, opt.label));
20333
+ insert(_el$136, () => isHl() ? ">" : " ");
20334
+ insert(_el$137, digitChip);
20335
+ insert(_el$138, glyph);
20336
+ insertNode(_el$139, _el$140);
20337
+ setProp(_el$139, "flexGrow", 1);
20338
+ setProp(_el$139, "flexDirection", "column");
20339
+ insert(_el$140, () => opt.label);
20340
+ insert(_el$139, createComponent2(Show, {
20341
+ get when() {
20342
+ return opt.description;
20343
+ },
20344
+ get children() {
20345
+ var _el$141 = createElement("text");
20346
+ insert(_el$141, () => opt.description);
20347
+ effect((_$p) => setProp(_el$141, "fg", theme.textMuted, _$p));
20348
+ return _el$141;
20349
+ }
20350
+ }), null);
20351
+ effect((_p$) => {
20352
+ var _v$58 = isHl() ? theme.accent : theme.textMuted, _v$59 = TextAttributes22.BOLD, _v$60 = theme.textMuted, _v$61 = isPicked() ? theme.accent : theme.textMuted, _v$62 = TextAttributes22.BOLD, _v$63 = theme.text;
20353
+ _v$58 !== _p$.e && (_p$.e = setProp(_el$136, "fg", _v$58, _p$.e));
20354
+ _v$59 !== _p$.t && (_p$.t = setProp(_el$136, "attributes", _v$59, _p$.t));
20355
+ _v$60 !== _p$.a && (_p$.a = setProp(_el$137, "fg", _v$60, _p$.a));
20356
+ _v$61 !== _p$.o && (_p$.o = setProp(_el$138, "fg", _v$61, _p$.o));
20357
+ _v$62 !== _p$.i && (_p$.i = setProp(_el$138, "attributes", _v$62, _p$.i));
20358
+ _v$63 !== _p$.n && (_p$.n = setProp(_el$140, "fg", _v$63, _p$.n));
20359
+ return _p$;
20360
+ }, {
20361
+ e: undefined,
20362
+ t: undefined,
20363
+ a: undefined,
20364
+ o: undefined,
20365
+ i: undefined,
20366
+ n: undefined
20367
+ });
20368
+ return _el$135;
20369
+ })();
20370
+ }
20371
+ }), _el$131);
20372
+ insert(_el$130, () => {
20373
+ const otherPicked = () => picked().has(OTHER_SENTINEL);
20374
+ const otherIdx = q.options.length;
20375
+ const isOtherHl = () => highlighted() === otherIdx;
20376
+ const otherGlyph = () => q.multiSelect ? otherPicked() ? "[x]" : "[ ]" : otherPicked() ? "(\u2022)" : "( )";
20377
+ const otherDigitChip = () => otherIdx < 9 ? `${otherIdx + 1}.` : " ";
20378
+ return [(() => {
20379
+ var _el$142 = createElement("box"), _el$143 = createElement("text"), _el$144 = createElement("text"), _el$145 = createElement("text"), _el$146 = createElement("box"), _el$147 = createElement("text"), _el$149 = createElement("text");
20380
+ insertNode(_el$142, _el$143);
20381
+ insertNode(_el$142, _el$144);
20382
+ insertNode(_el$142, _el$145);
20383
+ insertNode(_el$142, _el$146);
20384
+ setProp(_el$142, "flexDirection", "row");
20385
+ setProp(_el$142, "gap", 1);
20386
+ setProp(_el$142, "onMouseUp", () => toggle(q.question, q.multiSelect, OTHER_SENTINEL));
20387
+ insert(_el$143, () => isOtherHl() ? ">" : " ");
20388
+ insert(_el$144, otherDigitChip);
20389
+ insert(_el$145, otherGlyph);
20390
+ insertNode(_el$146, _el$147);
20391
+ insertNode(_el$146, _el$149);
20392
+ setProp(_el$146, "flexGrow", 1);
20393
+ setProp(_el$146, "flexDirection", "column");
20394
+ insertNode(_el$147, createTextNode(`Other`));
20395
+ insertNode(_el$149, createTextNode(`Type your own answer`));
19719
20396
  effect((_p$) => {
19720
- var _v$54 = isPicked() ? theme.accent : theme.textMuted, _v$55 = TextAttributes21.BOLD, _v$56 = theme.text;
19721
- _v$54 !== _p$.e && (_p$.e = setProp(_el$129, "fg", _v$54, _p$.e));
19722
- _v$55 !== _p$.t && (_p$.t = setProp(_el$129, "attributes", _v$55, _p$.t));
19723
- _v$56 !== _p$.a && (_p$.a = setProp(_el$131, "fg", _v$56, _p$.a));
20397
+ var _v$64 = isOtherHl() ? theme.accent : theme.textMuted, _v$65 = TextAttributes22.BOLD, _v$66 = theme.textMuted, _v$67 = otherPicked() ? theme.accent : theme.textMuted, _v$68 = TextAttributes22.BOLD, _v$69 = theme.text, _v$70 = theme.textMuted;
20398
+ _v$64 !== _p$.e && (_p$.e = setProp(_el$143, "fg", _v$64, _p$.e));
20399
+ _v$65 !== _p$.t && (_p$.t = setProp(_el$143, "attributes", _v$65, _p$.t));
20400
+ _v$66 !== _p$.a && (_p$.a = setProp(_el$144, "fg", _v$66, _p$.a));
20401
+ _v$67 !== _p$.o && (_p$.o = setProp(_el$145, "fg", _v$67, _p$.o));
20402
+ _v$68 !== _p$.i && (_p$.i = setProp(_el$145, "attributes", _v$68, _p$.i));
20403
+ _v$69 !== _p$.n && (_p$.n = setProp(_el$147, "fg", _v$69, _p$.n));
20404
+ _v$70 !== _p$.s && (_p$.s = setProp(_el$149, "fg", _v$70, _p$.s));
19724
20405
  return _p$;
19725
20406
  }, {
19726
20407
  e: undefined,
19727
20408
  t: undefined,
19728
- a: undefined
20409
+ a: undefined,
20410
+ o: undefined,
20411
+ i: undefined,
20412
+ n: undefined,
20413
+ s: undefined
19729
20414
  });
19730
- return _el$128;
19731
- })();
19732
- }
19733
- }));
19734
- return _el$127;
19735
- }
19736
- }), null);
19737
- effect((_$p) => setProp(_el$121, "fg", theme.text, _$p));
19738
- return _el$116;
19739
- })();
20415
+ return _el$142;
20416
+ })(), createComponent2(Show, {
20417
+ get when() {
20418
+ return otherPicked();
20419
+ },
20420
+ get children() {
20421
+ var _el$151 = createElement("box"), _el$152 = createElement("input");
20422
+ insertNode(_el$151, _el$152);
20423
+ setProp(_el$151, "paddingLeft", 4);
20424
+ setProp(_el$151, "paddingTop", 0);
20425
+ setProp(_el$152, "placeholder", "type your answer\u2026");
20426
+ setProp(_el$152, "focused", true);
20427
+ setProp(_el$152, "onInput", (v) => setCustomText(q.question, v));
20428
+ setProp(_el$152, "onSubmit", () => advanceOrSubmit());
20429
+ effect((_$p) => setProp(_el$152, "value", customTextFor(q.question), _$p));
20430
+ return _el$151;
20431
+ }
20432
+ })];
20433
+ }, _el$131);
20434
+ insertNode(_el$131, _el$132);
20435
+ setProp(_el$131, "paddingLeft", 0);
20436
+ setProp(_el$131, "paddingTop", 1);
20437
+ setProp(_el$131, "flexDirection", "row");
20438
+ setProp(_el$131, "gap", 2);
20439
+ setProp(_el$132, "onMouseUp", () => advanceOrSubmit());
20440
+ insert(_el$132, buttonLabel);
20441
+ insert(_el$131, createComponent2(Show, {
20442
+ get when() {
20443
+ return !isQuestionComplete(index());
20444
+ },
20445
+ get children() {
20446
+ var _el$133 = createElement("text");
20447
+ insertNode(_el$133, createTextNode(`(pick an option to continue)`));
20448
+ effect((_$p) => setProp(_el$133, "fg", theme.textMuted, _$p));
20449
+ return _el$133;
20450
+ }
20451
+ }), null);
20452
+ effect((_p$) => {
20453
+ var _v$54 = isQuestionComplete(index()) ? theme.success : theme.textMuted, _v$55 = TextAttributes22.BOLD;
20454
+ _v$54 !== _p$.e && (_p$.e = setProp(_el$132, "fg", _v$54, _p$.e));
20455
+ _v$55 !== _p$.t && (_p$.t = setProp(_el$132, "attributes", _v$55, _p$.t));
20456
+ return _p$;
20457
+ }, {
20458
+ e: undefined,
20459
+ t: undefined
20460
+ });
20461
+ return _el$130;
20462
+ }
20463
+ }), null);
20464
+ effect((_p$) => {
20465
+ var _v$56 = isPast() ? () => setCurrentIndex(index()) : undefined, _v$57 = isPast() ? theme.textMuted : theme.text;
20466
+ _v$56 !== _p$.e && (_p$.e = setProp(_el$114, "onMouseUp", _v$56, _p$.e));
20467
+ _v$57 !== _p$.t && (_p$.t = setProp(_el$119, "fg", _v$57, _p$.t));
20468
+ return _p$;
20469
+ }, {
20470
+ e: undefined,
20471
+ t: undefined
20472
+ });
20473
+ return _el$114;
20474
+ }
20475
+ });
19740
20476
  }
19741
- }), _el$111);
19742
- setProp(_el$111, "paddingLeft", 2);
19743
- setProp(_el$111, "paddingTop", 1);
19744
- setProp(_el$111, "flexDirection", "row");
19745
- setProp(_el$111, "gap", 2);
19746
- insert(_el$111, createComponent2(Show, {
20477
+ }), null);
20478
+ insert(_el$106, createComponent2(Show, {
19747
20479
  get when() {
19748
- return !isAnswered();
19749
- },
19750
- get fallback() {
19751
- return (() => {
19752
- var _el$133 = createElement("text");
19753
- insertNode(_el$133, createTextNode(`[submitted]`));
19754
- effect((_p$) => {
19755
- var _v$57 = theme.success, _v$58 = TextAttributes21.BOLD;
19756
- _v$57 !== _p$.e && (_p$.e = setProp(_el$133, "fg", _v$57, _p$.e));
19757
- _v$58 !== _p$.t && (_p$.t = setProp(_el$133, "attributes", _v$58, _p$.t));
19758
- return _p$;
19759
- }, {
19760
- e: undefined,
19761
- t: undefined
19762
- });
19763
- return _el$133;
19764
- })();
20480
+ return isAnswered();
19765
20481
  },
19766
20482
  get children() {
19767
- return [(() => {
19768
- var _el$112 = createElement("text");
19769
- insertNode(_el$112, createTextNode(`[ Submit ]`));
19770
- setProp(_el$112, "onMouseUp", () => submit());
19771
- effect((_p$) => {
19772
- var _v$46 = allAnswered() ? theme.success : theme.textMuted, _v$47 = TextAttributes21.BOLD;
19773
- _v$46 !== _p$.e && (_p$.e = setProp(_el$112, "fg", _v$46, _p$.e));
19774
- _v$47 !== _p$.t && (_p$.t = setProp(_el$112, "attributes", _v$47, _p$.t));
19775
- return _p$;
19776
- }, {
19777
- e: undefined,
19778
- t: undefined
19779
- });
19780
- return _el$112;
19781
- })(), createComponent2(Show, {
19782
- get when() {
19783
- return !allAnswered();
19784
- },
19785
- get children() {
19786
- var _el$114 = createElement("text");
19787
- insertNode(_el$114, createTextNode(`(answer all questions to enable)`));
19788
- effect((_$p) => setProp(_el$114, "fg", theme.textMuted, _$p));
19789
- return _el$114;
19790
- }
19791
- })];
20483
+ var _el$111 = createElement("box"), _el$112 = createElement("text");
20484
+ insertNode(_el$111, _el$112);
20485
+ setProp(_el$111, "paddingLeft", 2);
20486
+ setProp(_el$111, "paddingTop", 1);
20487
+ insertNode(_el$112, createTextNode(`[submitted]`));
20488
+ effect((_p$) => {
20489
+ var _v$46 = theme.success, _v$47 = TextAttributes22.BOLD;
20490
+ _v$46 !== _p$.e && (_p$.e = setProp(_el$112, "fg", _v$46, _p$.e));
20491
+ _v$47 !== _p$.t && (_p$.t = setProp(_el$112, "attributes", _v$47, _p$.t));
20492
+ return _p$;
20493
+ }, {
20494
+ e: undefined,
20495
+ t: undefined
20496
+ });
20497
+ return _el$111;
19792
20498
  }
19793
- }));
20499
+ }), null);
19794
20500
  effect((_p$) => {
19795
- var _v$48 = theme.warning, _v$49 = TextAttributes21.BOLD, _v$50 = theme.warning, _v$51 = TextAttributes21.BOLD;
20501
+ var _v$48 = theme.warning, _v$49 = TextAttributes22.BOLD, _v$50 = theme.warning, _v$51 = TextAttributes22.BOLD;
19796
20502
  _v$48 !== _p$.e && (_p$.e = setProp(_el$108, "fg", _v$48, _p$.e));
19797
20503
  _v$49 !== _p$.t && (_p$.t = setProp(_el$108, "attributes", _v$49, _p$.t));
19798
20504
  _v$50 !== _p$.a && (_p$.a = setProp(_el$110, "fg", _v$50, _p$.a));
@@ -19812,23 +20518,23 @@ function MessageList(props) {
19812
20518
  theme
19813
20519
  } = useTheme();
19814
20520
  return (() => {
19815
- var _el$135 = createElement("box");
19816
- setProp(_el$135, "flexDirection", "column");
19817
- setProp(_el$135, "gap", 0);
19818
- insert(_el$135, createComponent2(Show, {
20521
+ var _el$153 = createElement("box");
20522
+ setProp(_el$153, "flexDirection", "column");
20523
+ setProp(_el$153, "gap", 0);
20524
+ insert(_el$153, createComponent2(Show, {
19819
20525
  get when() {
19820
20526
  return memo2(() => props.messages.length === 0)() && props.showEmptyPlaceholder;
19821
20527
  },
19822
20528
  get children() {
19823
- var _el$136 = createElement("box"), _el$137 = createElement("text");
19824
- insertNode(_el$136, _el$137);
19825
- setProp(_el$136, "paddingTop", 2);
19826
- insertNode(_el$137, createTextNode(`Type a prompt below.`));
19827
- effect((_$p) => setProp(_el$137, "fg", theme.textMuted, _$p));
19828
- return _el$136;
20529
+ var _el$154 = createElement("box"), _el$155 = createElement("text");
20530
+ insertNode(_el$154, _el$155);
20531
+ setProp(_el$154, "paddingTop", 2);
20532
+ insertNode(_el$155, createTextNode(`Type a prompt below.`));
20533
+ effect((_$p) => setProp(_el$155, "fg", theme.textMuted, _$p));
20534
+ return _el$154;
19829
20535
  }
19830
20536
  }), null);
19831
- insert(_el$135, createComponent2(For, {
20537
+ insert(_el$153, createComponent2(For, {
19832
20538
  get each() {
19833
20539
  return groupRenderItems(props.messages, props.expandedFoldStartIndex);
19834
20540
  },
@@ -19878,7 +20584,13 @@ function MessageList(props) {
19878
20584
  if (row.kind === "question") {
19879
20585
  return createComponent2(QuestionRow, {
19880
20586
  row,
19881
- onAnswer: (answers) => props.onAnswer?.(row.requestId, answers)
20587
+ onAnswer: (answers) => props.onAnswer?.(row.requestId, answers),
20588
+ get onClaimComposerFocus() {
20589
+ return props.onClaimComposerFocus;
20590
+ },
20591
+ get chatFocused() {
20592
+ return props.chatFocused;
20593
+ }
19882
20594
  });
19883
20595
  }
19884
20596
  return createComponent2(ToolRow, {
@@ -19891,35 +20603,35 @@ function MessageList(props) {
19891
20603
  });
19892
20604
  }
19893
20605
  }), null);
19894
- insert(_el$135, createComponent2(Show, {
20606
+ insert(_el$153, createComponent2(Show, {
19895
20607
  get when() {
19896
20608
  return props.error;
19897
20609
  },
19898
20610
  get children() {
19899
- var _el$139 = createElement("box"), _el$140 = createElement("text"), _el$142 = createElement("text"), _el$143 = createTextNode(`error: `);
19900
- insertNode(_el$139, _el$140);
19901
- insertNode(_el$139, _el$142);
19902
- setProp(_el$139, "paddingTop", 1);
19903
- setProp(_el$139, "flexDirection", "row");
19904
- setProp(_el$139, "gap", 1);
19905
- insertNode(_el$140, createTextNode(`\u203B`));
19906
- insertNode(_el$142, _el$143);
19907
- insert(_el$142, () => props.error, null);
20611
+ var _el$157 = createElement("box"), _el$158 = createElement("text"), _el$160 = createElement("text"), _el$161 = createTextNode(`error: `);
20612
+ insertNode(_el$157, _el$158);
20613
+ insertNode(_el$157, _el$160);
20614
+ setProp(_el$157, "paddingTop", 1);
20615
+ setProp(_el$157, "flexDirection", "row");
20616
+ setProp(_el$157, "gap", 1);
20617
+ insertNode(_el$158, createTextNode(`\u203B`));
20618
+ insertNode(_el$160, _el$161);
20619
+ insert(_el$160, () => props.error, null);
19908
20620
  effect((_p$) => {
19909
- var _v$59 = theme.error, _v$60 = TextAttributes21.BOLD, _v$61 = theme.error;
19910
- _v$59 !== _p$.e && (_p$.e = setProp(_el$140, "fg", _v$59, _p$.e));
19911
- _v$60 !== _p$.t && (_p$.t = setProp(_el$140, "attributes", _v$60, _p$.t));
19912
- _v$61 !== _p$.a && (_p$.a = setProp(_el$142, "fg", _v$61, _p$.a));
20621
+ var _v$71 = theme.error, _v$72 = TextAttributes22.BOLD, _v$73 = theme.error;
20622
+ _v$71 !== _p$.e && (_p$.e = setProp(_el$158, "fg", _v$71, _p$.e));
20623
+ _v$72 !== _p$.t && (_p$.t = setProp(_el$158, "attributes", _v$72, _p$.t));
20624
+ _v$73 !== _p$.a && (_p$.a = setProp(_el$160, "fg", _v$73, _p$.a));
19913
20625
  return _p$;
19914
20626
  }, {
19915
20627
  e: undefined,
19916
20628
  t: undefined,
19917
20629
  a: undefined
19918
20630
  });
19919
- return _el$139;
20631
+ return _el$157;
19920
20632
  }
19921
20633
  }), null);
19922
- return _el$135;
20634
+ return _el$153;
19923
20635
  })();
19924
20636
  }
19925
20637
  function groupRenderItems(messages, expandedFoldStartIndex = null) {
@@ -20050,32 +20762,32 @@ function ToolFoldRow(props) {
20050
20762
  const glyph = () => props.inFlight ? "\u273B" : props.expanded ? "\u25BC" : "\u25B6";
20051
20763
  const fg = () => props.inFlight ? theme.warning : theme.textMuted;
20052
20764
  return (() => {
20053
- var _el$144 = createElement("box"), _el$145 = createElement("text"), _el$146 = createElement("box"), _el$147 = createElement("text");
20054
- insertNode(_el$144, _el$145);
20055
- insertNode(_el$144, _el$146);
20056
- setProp(_el$144, "paddingTop", 1);
20057
- setProp(_el$144, "flexDirection", "row");
20058
- setProp(_el$144, "gap", 1);
20059
- setProp(_el$144, "onMouseUp", () => props.onToggle());
20060
- insert(_el$145, glyph);
20061
- insertNode(_el$146, _el$147);
20062
- setProp(_el$146, "flexGrow", 1);
20063
- insert(_el$147, () => props.summary);
20765
+ var _el$162 = createElement("box"), _el$163 = createElement("text"), _el$164 = createElement("box"), _el$165 = createElement("text");
20766
+ insertNode(_el$162, _el$163);
20767
+ insertNode(_el$162, _el$164);
20768
+ setProp(_el$162, "paddingTop", 1);
20769
+ setProp(_el$162, "flexDirection", "row");
20770
+ setProp(_el$162, "gap", 1);
20771
+ setProp(_el$162, "onMouseUp", () => props.onToggle());
20772
+ insert(_el$163, glyph);
20773
+ insertNode(_el$164, _el$165);
20774
+ setProp(_el$164, "flexGrow", 1);
20775
+ insert(_el$165, () => props.summary);
20064
20776
  effect((_p$) => {
20065
- var _v$62 = fg(), _v$63 = TextAttributes21.DIM, _v$64 = theme.textMuted;
20066
- _v$62 !== _p$.e && (_p$.e = setProp(_el$145, "fg", _v$62, _p$.e));
20067
- _v$63 !== _p$.t && (_p$.t = setProp(_el$145, "attributes", _v$63, _p$.t));
20068
- _v$64 !== _p$.a && (_p$.a = setProp(_el$147, "fg", _v$64, _p$.a));
20777
+ var _v$74 = fg(), _v$75 = TextAttributes22.DIM, _v$76 = theme.textMuted;
20778
+ _v$74 !== _p$.e && (_p$.e = setProp(_el$163, "fg", _v$74, _p$.e));
20779
+ _v$75 !== _p$.t && (_p$.t = setProp(_el$163, "attributes", _v$75, _p$.t));
20780
+ _v$76 !== _p$.a && (_p$.a = setProp(_el$165, "fg", _v$76, _p$.a));
20069
20781
  return _p$;
20070
20782
  }, {
20071
20783
  e: undefined,
20072
20784
  t: undefined,
20073
20785
  a: undefined
20074
20786
  });
20075
- return _el$144;
20787
+ return _el$162;
20076
20788
  })();
20077
20789
  }
20078
- var BLACK_CIRCLE, TOOL_FOLD_THRESHOLD = 3;
20790
+ var BLACK_CIRCLE, OTHER_SENTINEL = "__kobe_other__", TOOL_FOLD_THRESHOLD = 3;
20079
20791
  var init_MessageList = __esm(() => {
20080
20792
  init_solid();
20081
20793
  init_solid();
@@ -20086,7 +20798,9 @@ var init_MessageList = __esm(() => {
20086
20798
  init_solid();
20087
20799
  init_solid();
20088
20800
  init_dev();
20801
+ init_keybindings();
20089
20802
  init_theme();
20803
+ init_keymap();
20090
20804
  init_Markdown();
20091
20805
  init_image_paste();
20092
20806
  BLACK_CIRCLE = process.platform === "darwin" ? "\u23FA" : "\u25CF";
@@ -20125,7 +20839,7 @@ var init_models = __esm(() => {
20125
20839
  });
20126
20840
 
20127
20841
  // src/tui/panes/chat/composer/ModelPicker.tsx
20128
- import { TextAttributes as TextAttributes22 } from "@opentui/core";
20842
+ import { TextAttributes as TextAttributes23 } from "@opentui/core";
20129
20843
  function ModelPicker(props) {
20130
20844
  const dialog = useDialog();
20131
20845
  const {
@@ -20205,7 +20919,7 @@ function ModelPicker(props) {
20205
20919
  })() : null;
20206
20920
  })(), null);
20207
20921
  effect((_p$) => {
20208
- var _v$5 = active() ? theme.primary : undefined, _v$6 = active() ? theme.selectedListItemText : theme.text, _v$7 = active() ? TextAttributes22.BOLD : undefined;
20922
+ var _v$5 = active() ? theme.primary : undefined, _v$6 = active() ? theme.selectedListItemText : theme.text, _v$7 = active() ? TextAttributes23.BOLD : undefined;
20209
20923
  _v$5 !== _p$.e && (_p$.e = setProp(_el$1, "backgroundColor", _v$5, _p$.e));
20210
20924
  _v$6 !== _p$.t && (_p$.t = setProp(_el$10, "fg", _v$6, _p$.t));
20211
20925
  _v$7 !== _p$.a && (_p$.a = setProp(_el$10, "attributes", _v$7, _p$.a));
@@ -20223,7 +20937,7 @@ function ModelPicker(props) {
20223
20937
  setProp(_el$8, "paddingBottom", 1);
20224
20938
  insertNode(_el$9, createTextNode(`\u2191\u2193 pick \xB7 enter select \xB7 esc cancel`));
20225
20939
  effect((_p$) => {
20226
- var _v$ = TextAttributes22.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
20940
+ var _v$ = TextAttributes23.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
20227
20941
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
20228
20942
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
20229
20943
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -20253,12 +20967,12 @@ var init_ModelPicker = __esm(() => {
20253
20967
  init_dialog();
20254
20968
  init_models();
20255
20969
  ModelPicker.show = (dialog, current) => {
20256
- return new Promise((resolve3) => {
20970
+ return new Promise((resolve4) => {
20257
20971
  dialog.replace(() => createComponent2(ModelPicker, {
20258
20972
  current,
20259
- onPick: (id) => resolve3(id),
20260
- onCancel: () => resolve3(undefined)
20261
- }), () => resolve3(undefined));
20973
+ onPick: (id) => resolve4(id),
20974
+ onCancel: () => resolve4(undefined)
20975
+ }), () => resolve4(undefined));
20262
20976
  });
20263
20977
  };
20264
20978
  });
@@ -20266,7 +20980,7 @@ var init_ModelPicker = __esm(() => {
20266
20980
  // src/tui/panes/chat/composer/user-slashes.ts
20267
20981
  import { readFile as readFile6, readdir as readdir3, stat as stat3 } from "fs/promises";
20268
20982
  import { homedir as homedir10 } from "os";
20269
- import { join as join13 } from "path";
20983
+ import { join as join14 } from "path";
20270
20984
  function resolveHome() {
20271
20985
  return process.env.HOME ?? homedir10();
20272
20986
  }
@@ -20372,7 +21086,7 @@ async function scanCommandsDir(dir) {
20372
21086
  for (const entry of entries) {
20373
21087
  if (!entry.endsWith(".md"))
20374
21088
  continue;
20375
- const full = join13(dir, entry);
21089
+ const full = join14(dir, entry);
20376
21090
  if (!await isFile(full))
20377
21091
  continue;
20378
21092
  const name = entry.slice(0, -3);
@@ -20385,10 +21099,10 @@ async function scanSkillsDir(dir) {
20385
21099
  const entries = await safeReaddir(dir);
20386
21100
  const out = [];
20387
21101
  for (const entry of entries) {
20388
- const sub = join13(dir, entry);
21102
+ const sub = join14(dir, entry);
20389
21103
  if (!await isDir(sub))
20390
21104
  continue;
20391
- const skillMd = join13(sub, "SKILL.md");
21105
+ const skillMd = join14(sub, "SKILL.md");
20392
21106
  if (!await isFile(skillMd))
20393
21107
  continue;
20394
21108
  const description = await tryReadDescription(skillMd) ?? "";
@@ -20398,8 +21112,8 @@ async function scanSkillsDir(dir) {
20398
21112
  }
20399
21113
  async function scanBasePath(claudeDir) {
20400
21114
  const [skills, commands] = await Promise.all([
20401
- scanSkillsDir(join13(claudeDir, "skills")),
20402
- scanCommandsDir(join13(claudeDir, "commands"))
21115
+ scanSkillsDir(join14(claudeDir, "skills")),
21116
+ scanCommandsDir(join14(claudeDir, "commands"))
20403
21117
  ]);
20404
21118
  const map = new Map;
20405
21119
  for (const e of skills)
@@ -20409,8 +21123,8 @@ async function scanBasePath(claudeDir) {
20409
21123
  return [...map.values()];
20410
21124
  }
20411
21125
  async function loadUserSlashes(worktreePath) {
20412
- const projectScan = worktreePath ? scanBasePath(join13(worktreePath, ".claude")) : Promise.resolve([]);
20413
- const globalScan = scanBasePath(join13(resolveHome(), ".claude"));
21126
+ const projectScan = worktreePath ? scanBasePath(join14(worktreePath, ".claude")) : Promise.resolve([]);
21127
+ const globalScan = scanBasePath(join14(resolveHome(), ".claude"));
20414
21128
  const [project, global] = await Promise.all([projectScan, globalScan]);
20415
21129
  const map = new Map;
20416
21130
  for (const e of global)
@@ -20987,7 +21701,7 @@ var init_use_chat_session = __esm(() => {
20987
21701
  });
20988
21702
 
20989
21703
  // src/tui/panes/chat/Chat.tsx
20990
- import { TextAttributes as TextAttributes23 } from "@opentui/core";
21704
+ import { TextAttributes as TextAttributes24 } from "@opentui/core";
20991
21705
  function Chat(props) {
20992
21706
  const {
20993
21707
  theme
@@ -21069,28 +21783,40 @@ function Chat(props) {
21069
21783
  createEffect(on(contextMeterLabel, (label) => {
21070
21784
  props.onContextMeter?.(label ?? null);
21071
21785
  }));
21072
- const taskStatus = createMemo(() => {
21786
+ const activeTask = createMemo(() => {
21073
21787
  const id = props.taskId();
21074
21788
  if (!id)
21075
21789
  return;
21076
- return tasksAcc().find((t) => t.id === id)?.status;
21790
+ return tasksAcc().find((t) => t.id === id);
21077
21791
  });
21792
+ const taskStatus = () => activeTask()?.status;
21078
21793
  const isCanceled = () => taskStatus() === "canceled";
21079
- const hasPendingInput = createMemo(() => {
21794
+ const isArchived = () => activeTask()?.archived === true;
21795
+ function findPending() {
21080
21796
  const msgs = activeState().messages;
21081
21797
  for (let i = msgs.length - 1;i >= 0; i--) {
21082
21798
  const m = msgs[i];
21083
21799
  if (!m)
21084
21800
  continue;
21085
21801
  if (m.kind === "approval")
21086
- return m.status === "pending";
21802
+ return m.status === "pending" ? m : null;
21087
21803
  if (m.kind === "question")
21088
- return m.answers === null;
21804
+ return m.answers === null ? m : null;
21089
21805
  if (m.kind === "user" || m.kind === "assistant")
21090
- return false;
21806
+ return null;
21091
21807
  }
21092
- return false;
21808
+ return null;
21809
+ }
21810
+ const pendingApproval = createMemo(() => {
21811
+ const p = findPending();
21812
+ return p?.kind === "approval" ? p : null;
21093
21813
  });
21814
+ const pendingQuestion = createMemo(() => {
21815
+ const p = findPending();
21816
+ return p?.kind === "question" ? p : null;
21817
+ });
21818
+ const hasPendingInput = createMemo(() => pendingApproval() !== null || pendingQuestion() !== null);
21819
+ const [questionInlineFocus, setQuestionInlineFocus] = createSignal(false);
21094
21820
  const permissionMode = createMemo(() => {
21095
21821
  const id = props.taskId();
21096
21822
  if (!id)
@@ -21421,6 +22147,24 @@ function Chat(props) {
21421
22147
  toggleExpandLastTool();
21422
22148
  return;
21423
22149
  }
22150
+ const q = pendingQuestion();
22151
+ if (q) {
22152
+ const taskId = props.taskId();
22153
+ if (!taskId)
22154
+ return;
22155
+ const answers = {};
22156
+ for (const entry of q.questions) {
22157
+ answers[entry.question] = trimmed;
22158
+ }
22159
+ props.orchestrator.respondToInput(taskId, q.requestId, {
22160
+ kind: "ask_question",
22161
+ answers
22162
+ }).catch((err) => {
22163
+ patchActiveState((s) => pushSystemError(s, `respondToInput failed: ${stringifyErr2(err)}`));
22164
+ });
22165
+ setDraft("");
22166
+ return;
22167
+ }
21424
22168
  send(trimmed, mode);
21425
22169
  }
21426
22170
  return (() => {
@@ -21498,7 +22242,9 @@ function Chat(props) {
21498
22242
  }).catch((err) => {
21499
22243
  patchActiveState((s) => pushSystemError(s, `respondToInput failed: ${stringifyErr2(err)}`));
21500
22244
  });
21501
- }
22245
+ },
22246
+ onClaimComposerFocus: setQuestionInlineFocus,
22247
+ chatFocused: () => props.focused?.() ?? false
21502
22248
  }));
21503
22249
  effect((_$p) => setProp(_el$5, "verticalScrollbarOptions", {
21504
22250
  trackOptions: {
@@ -21537,33 +22283,38 @@ function Chat(props) {
21537
22283
  });
21538
22284
  }
21539
22285
  }), null);
21540
- insert(_el$, createComponent2(Composer, {
21541
- get draft() {
21542
- return draft();
21543
- },
21544
- onDraftChange: setDraft,
21545
- get isStreaming() {
21546
- return activeState().isStreaming;
21547
- },
21548
- get hasTask() {
21549
- return memo2(() => !!(props.taskId() !== undefined && !isCanceled()))() && !hasPendingInput();
21550
- },
21551
- get noTaskMessage() {
21552
- return memo2(() => !!isCanceled())() ? "(task canceled \u2014 pick another or press ctrl+n to create)" : hasPendingInput() ? "(answer the prompt above to continue)" : undefined;
21553
- },
21554
- onSubmit: handleComposerSubmit,
21555
- get focused() {
21556
- return props.focused;
21557
- },
21558
- get historyKey() {
21559
- return activeTabId() ?? props.taskId();
22286
+ insert(_el$, createComponent2(Show, {
22287
+ get when() {
22288
+ return !pendingQuestion();
21560
22289
  },
21561
- slashes,
21562
- permissionMode,
21563
- onCyclePermissionMode: cyclePermissionMode,
21564
- modelLabel,
21565
- onChooseModel: () => void chooseModel(),
21566
- worktreePath
22290
+ get children() {
22291
+ return createComponent2(Composer, {
22292
+ get draft() {
22293
+ return draft();
22294
+ },
22295
+ onDraftChange: setDraft,
22296
+ get isStreaming() {
22297
+ return activeState().isStreaming;
22298
+ },
22299
+ get hasTask() {
22300
+ return memo2(() => !!(props.taskId() !== undefined && !isArchived() && !isCanceled()))() && !pendingApproval();
22301
+ },
22302
+ get noTaskMessage() {
22303
+ return memo2(() => !!isArchived())() ? "(archived \u2014 unarchive to resume)" : memo2(() => !!isCanceled())() ? "(task canceled \u2014 pick another or press ctrl+n to create)" : pendingApproval() ? "(answer the prompt above to continue)" : undefined;
22304
+ },
22305
+ onSubmit: handleComposerSubmit,
22306
+ focused: () => (props.focused?.() ?? false) && !questionInlineFocus(),
22307
+ get historyKey() {
22308
+ return activeTabId() ?? props.taskId();
22309
+ },
22310
+ slashes,
22311
+ permissionMode,
22312
+ onCyclePermissionMode: cyclePermissionMode,
22313
+ modelLabel,
22314
+ onChooseModel: () => void chooseModel(),
22315
+ worktreePath
22316
+ });
22317
+ }
21567
22318
  }), null);
21568
22319
  return _el$;
21569
22320
  })();
@@ -21618,7 +22369,7 @@ function QueuedPromptList(props) {
21618
22369
  insertNode(_el$19, createTextNode(`[x]`));
21619
22370
  setProp(_el$19, "onMouseUp", () => props.onCancel(entry.id));
21620
22371
  effect((_p$) => {
21621
- var _v$4 = theme.textMuted, _v$5 = TextAttributes23.BOLD, _v$6 = theme.textMuted, _v$7 = theme.text, _v$8 = theme.error, _v$9 = TextAttributes23.BOLD;
22372
+ var _v$4 = theme.textMuted, _v$5 = TextAttributes24.BOLD, _v$6 = theme.textMuted, _v$7 = theme.text, _v$8 = theme.error, _v$9 = TextAttributes24.BOLD;
21622
22373
  _v$4 !== _p$.e && (_p$.e = setProp(_el$11, "fg", _v$4, _p$.e));
21623
22374
  _v$5 !== _p$.t && (_p$.t = setProp(_el$11, "attributes", _v$5, _p$.t));
21624
22375
  _v$6 !== _p$.a && (_p$.a = setProp(_el$14, "fg", _v$6, _p$.a));
@@ -21651,7 +22402,7 @@ function QueuedPromptList(props) {
21651
22402
  insertNode(_el$9, createTextNode(`+`));
21652
22403
  insert(_el$1, () => `\u2026 ${hidden()} more queued`);
21653
22404
  effect((_p$) => {
21654
- var _v$ = theme.textMuted, _v$2 = TextAttributes23.BOLD, _v$3 = theme.textMuted;
22405
+ var _v$ = theme.textMuted, _v$2 = TextAttributes24.BOLD, _v$3 = theme.textMuted;
21655
22406
  _v$ !== _p$.e && (_p$.e = setProp(_el$9, "fg", _v$, _p$.e));
21656
22407
  _v$2 !== _p$.t && (_p$.t = setProp(_el$9, "attributes", _v$2, _p$.t));
21657
22408
  _v$3 !== _p$.a && (_p$.a = setProp(_el$1, "fg", _v$3, _p$.a));
@@ -21697,7 +22448,7 @@ var init_Chat = __esm(() => {
21697
22448
  });
21698
22449
 
21699
22450
  // src/tui/component/sidebar.tsx
21700
- import { TextAttributes as TextAttributes24 } from "@opentui/core";
22451
+ import { TextAttributes as TextAttributes25 } from "@opentui/core";
21701
22452
  function Sidebar(props) {
21702
22453
  const {
21703
22454
  theme
@@ -21723,7 +22474,7 @@ function Sidebar(props) {
21723
22474
  setProp(_el$2, "paddingBottom", 1);
21724
22475
  insert(_el$3, () => props.title);
21725
22476
  effect((_p$) => {
21726
- var _v$ = theme.text, _v$2 = TextAttributes24.BOLD;
22477
+ var _v$ = theme.text, _v$2 = TextAttributes25.BOLD;
21727
22478
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "fg", _v$, _p$.e));
21728
22479
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "attributes", _v$2, _p$.t));
21729
22480
  return _p$;
@@ -21982,7 +22733,7 @@ var init_keys4 = __esm(() => {
21982
22733
  });
21983
22734
 
21984
22735
  // src/tui/panes/sidebar/Sidebar.tsx
21985
- import { TextAttributes as TextAttributes25 } from "@opentui/core";
22736
+ import { TextAttributes as TextAttributes26 } from "@opentui/core";
21986
22737
  function Sidebar2(props) {
21987
22738
  const {
21988
22739
  theme
@@ -22074,7 +22825,7 @@ function Sidebar2(props) {
22074
22825
  return () => _c$() ? `[ ${tab.label} ]` : tab.label;
22075
22826
  })());
22076
22827
  effect((_p$) => {
22077
- var _v$7 = active() ? theme.primary : theme.textMuted, _v$8 = active() ? TextAttributes25.BOLD : undefined;
22828
+ var _v$7 = active() ? theme.primary : theme.textMuted, _v$8 = active() ? TextAttributes26.BOLD : undefined;
22078
22829
  _v$7 !== _p$.e && (_p$.e = setProp(_el$13, "fg", _v$7, _p$.e));
22079
22830
  _v$8 !== _p$.t && (_p$.t = setProp(_el$13, "attributes", _v$8, _p$.t));
22080
22831
  return _p$;
@@ -22169,7 +22920,7 @@ function Sidebar2(props) {
22169
22920
  }
22170
22921
  }), null);
22171
22922
  effect((_p$) => {
22172
- var _v$9 = isCursor() ? theme.primary : isSelected() ? theme.backgroundElement : undefined, _v$0 = isCursor() ? theme.selectedListItemText : badgeColor(), _v$1 = isCursor() ? theme.selectedListItemText : theme.text, _v$10 = (isMain || isSelected() && !isCursor()) && !isCursor() ? TextAttributes25.BOLD : undefined;
22923
+ var _v$9 = isCursor() ? theme.primary : isSelected() ? theme.backgroundElement : undefined, _v$0 = isCursor() ? theme.selectedListItemText : badgeColor(), _v$1 = isCursor() ? theme.selectedListItemText : theme.text, _v$10 = (isMain || isSelected() && !isCursor()) && !isCursor() ? TextAttributes26.BOLD : undefined;
22173
22924
  _v$9 !== _p$.e && (_p$.e = setProp(_el$14, "backgroundColor", _v$9, _p$.e));
22174
22925
  _v$0 !== _p$.t && (_p$.t = setProp(_el$15, "fg", _v$0, _p$.t));
22175
22926
  _v$1 !== _p$.a && (_p$.a = setProp(_el$16, "fg", _v$1, _p$.a));
@@ -22207,7 +22958,7 @@ function Sidebar2(props) {
22207
22958
  setProp(_el$11, "wrapMode", "none");
22208
22959
  setProp(_el$11, "onMouseUp", () => props.onAddTask?.());
22209
22960
  effect((_p$) => {
22210
- var _v$ = props.width ? props.width() : SIDEBAR_WIDTH, _v$2 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$3 = TextAttributes25.BOLD, _v$4 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$5 = TextAttributes25.BOLD, _v$6 = theme.textMuted;
22961
+ var _v$ = props.width ? props.width() : SIDEBAR_WIDTH, _v$2 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$3 = TextAttributes26.BOLD, _v$4 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$5 = TextAttributes26.BOLD, _v$6 = theme.textMuted;
22211
22962
  _v$ !== _p$.e && (_p$.e = setProp(_el$, "width", _v$, _p$.e));
22212
22963
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
22213
22964
  _v$3 !== _p$.a && (_p$.a = setProp(_el$3, "attributes", _v$3, _p$.a));
@@ -22306,17 +23057,17 @@ async function startBridgeServer(orch, socketPath) {
22306
23057
  });
22307
23058
  conn.on("error", () => {});
22308
23059
  });
22309
- await new Promise((resolve3, reject) => {
23060
+ await new Promise((resolve4, reject) => {
22310
23061
  server.once("error", reject);
22311
23062
  server.listen(socketPath, () => {
22312
23063
  server.removeListener("error", reject);
22313
- resolve3();
23064
+ resolve4();
22314
23065
  });
22315
23066
  });
22316
23067
  return {
22317
23068
  socketPath,
22318
23069
  async close() {
22319
- await new Promise((resolve3) => server.close(() => resolve3()));
23070
+ await new Promise((resolve4) => server.close(() => resolve4()));
22320
23071
  await unlink3(socketPath).catch(() => {});
22321
23072
  }
22322
23073
  };
@@ -22410,13 +23161,13 @@ __export(exports_bridge, {
22410
23161
  });
22411
23162
  import { writeFile as writeFile3 } from "fs/promises";
22412
23163
  import { homedir as homedir11 } from "os";
22413
- import { join as join14 } from "path";
23164
+ import { join as join15 } from "path";
22414
23165
  import { fileURLToPath as fileURLToPath2 } from "url";
22415
23166
  async function startBridge(orch, opts = {}) {
22416
23167
  const home = opts.homeDir ?? process.env.KOBE_HOME_DIR ?? homedir11();
22417
- const runDir = join14(home, ".kobe", "run");
22418
- const socketPath = join14(runDir, `bridge-${process.pid}.sock`);
22419
- const mcpConfigPath = join14(runDir, `mcp-${process.pid}.json`);
23168
+ const runDir = join15(home, ".kobe", "run");
23169
+ const socketPath = join15(runDir, `bridge-${process.pid}.sock`);
23170
+ const mcpConfigPath = join15(runDir, `mcp-${process.pid}.json`);
22420
23171
  const server = await startBridgeServer(orch, socketPath);
22421
23172
  const moduleExt = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
22422
23173
  const entry = fileURLToPath2(new URL(`../../cli/index${moduleExt}`, import.meta.url));
@@ -22444,7 +23195,7 @@ var init_bridge = __esm(() => {
22444
23195
 
22445
23196
  // src/tui/app.tsx
22446
23197
  import { homedir as homedir12 } from "os";
22447
- import { join as join15 } from "path";
23198
+ import { join as join16 } from "path";
22448
23199
  function Shell(props) {
22449
23200
  const themeCtx = useTheme();
22450
23201
  const {
@@ -22452,6 +23203,7 @@ function Shell(props) {
22452
23203
  } = themeCtx;
22453
23204
  const dialog = useDialog();
22454
23205
  const kv = useKV();
23206
+ const notifications = useNotifications();
22455
23207
  useThemePersistence(themeCtx, kv);
22456
23208
  const tasksAcc = props.orchestrator.tasksSignal();
22457
23209
  const chatRunStateAcc = props.orchestrator.chatRunStateSignal();
@@ -22545,8 +23297,8 @@ function Shell(props) {
22545
23297
  } = workspaceTabs;
22546
23298
  const workspaceAsideRight = createMemo(() => {
22547
23299
  const plan = workspacePlanAside();
22548
- const ctx3 = isChatTabActive() ? workspaceContextAside() : null;
22549
- const parts = [plan, ctx3].filter((v) => Boolean(v));
23300
+ const ctx4 = isChatTabActive() ? workspaceContextAside() : null;
23301
+ const parts = [plan, ctx4].filter((v) => Boolean(v));
22550
23302
  if (parts.length === 0)
22551
23303
  return;
22552
23304
  return parts.join(" \u2022 ");
@@ -22610,6 +23362,30 @@ function Shell(props) {
22610
23362
  renderer,
22611
23363
  activeTask
22612
23364
  });
23365
+ const visibleTabKey = createMemo(() => {
23366
+ const taskId = selectedId();
23367
+ const tabId = activeChatTabIdAcc();
23368
+ if (!taskId || !tabId)
23369
+ return null;
23370
+ if (!isChatTabActive())
23371
+ return null;
23372
+ return chatRunStateKey(taskId, tabId);
23373
+ });
23374
+ useCompletionNotifications({
23375
+ chatRunState: chatRunStateAcc,
23376
+ tasks: tasksAcc,
23377
+ visibleTabKey,
23378
+ notifications
23379
+ });
23380
+ createEffect(() => {
23381
+ const key = visibleTabKey();
23382
+ if (!key)
23383
+ return;
23384
+ const idx = key.indexOf(":");
23385
+ if (idx < 0)
23386
+ return;
23387
+ notifications.markRead(key.slice(0, idx), key.slice(idx + 1));
23388
+ });
22613
23389
  useTestSideChannel({
22614
23390
  orchestrator: props.orchestrator,
22615
23391
  activeTask
@@ -22696,6 +23472,9 @@ function Shell(props) {
22696
23472
  activeChatTabId: activeChatTabIdAcc,
22697
23473
  activeTaskId: taskIdAcc,
22698
23474
  chatRunState: chatRunStateAcc,
23475
+ get unread() {
23476
+ return notifications.unread;
23477
+ },
22699
23478
  onSelectChat: selectChatTab,
22700
23479
  onSelectChatTab: selectChatTabById,
22701
23480
  onSelectFile: selectFileTab,
@@ -22805,6 +23584,7 @@ function Shell(props) {
22805
23584
  }
22806
23585
  }));
22807
23586
  insert(_el$, createComponent2(StatusBar, {}), null);
23587
+ insert(_el$, createComponent2(ToastOverlay, {}), null);
22808
23588
  effect((_p$) => {
22809
23589
  var _v$ = theme.backgroundPanel, _v$2 = workspaceWidth(), _v$3 = theme.backgroundPanel, _v$4 = filesHeight();
22810
23590
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "backgroundColor", _v$, _p$.e));
@@ -22828,15 +23608,19 @@ function App(props) {
22828
23608
  get children() {
22829
23609
  return createComponent2(KVProvider, {
22830
23610
  get children() {
22831
- return createComponent2(SyncProvider, {
23611
+ return createComponent2(NotificationsProvider, {
22832
23612
  get children() {
22833
- return createComponent2(DialogProvider, {
23613
+ return createComponent2(SyncProvider, {
22834
23614
  get children() {
22835
- return createComponent2(CommandPaletteProvider, {
23615
+ return createComponent2(DialogProvider, {
22836
23616
  get children() {
22837
- return createComponent2(FocusProvider, {
23617
+ return createComponent2(CommandPaletteProvider, {
22838
23618
  get children() {
22839
- return createComponent2(Shell, props);
23619
+ return createComponent2(FocusProvider, {
23620
+ get children() {
23621
+ return createComponent2(Shell, props);
23622
+ }
23623
+ });
22840
23624
  }
22841
23625
  });
22842
23626
  }
@@ -22926,15 +23710,18 @@ var init_app = __esm(() => {
22926
23710
  init_pane_header();
22927
23711
  init_resizable_edge();
22928
23712
  init_status_bar();
23713
+ init_toast_overlay();
22929
23714
  init_top_bar();
22930
23715
  init_command_palette();
22931
23716
  init_focus();
22932
23717
  init_keybindings();
22933
23718
  init_kv();
23719
+ init_notifications();
22934
23720
  init_sync();
22935
23721
  init_theme();
22936
23722
  init_loader();
22937
23723
  init_engine_bootstrap();
23724
+ init_use_completion_notifications();
22938
23725
  init_use_pane_sizes();
22939
23726
  init_use_task_actions();
22940
23727
  init_use_theme_persistence();
@@ -22952,7 +23739,7 @@ var exports_tui = {};
22952
23739
  __export(exports_tui, {
22953
23740
  startTui: () => startTui
22954
23741
  });
22955
- import { TextAttributes as TextAttributes26 } from "@opentui/core";
23742
+ import { TextAttributes as TextAttributes27 } from "@opentui/core";
22956
23743
  function HelpHint() {
22957
23744
  const {
22958
23745
  theme
@@ -23026,7 +23813,7 @@ function Banner() {
23026
23813
  insert(_el$20, selected);
23027
23814
  insert(_el$12, createComponent2(HelpHint, {}), null);
23028
23815
  effect((_p$) => {
23029
- var _v$7 = theme.primary, _v$8 = TextAttributes26.BOLD, _v$9 = theme.borderActive, _v$0 = theme.text, _v$1 = theme.textMuted, _v$10 = {
23816
+ var _v$7 = theme.primary, _v$8 = TextAttributes27.BOLD, _v$9 = theme.borderActive, _v$0 = theme.text, _v$1 = theme.textMuted, _v$10 = {
23030
23817
  fg: theme.accent
23031
23818
  };
23032
23819
  _v$7 !== _p$.e && (_p$.e = setProp(_el$13, "fg", _v$7, _p$.e));
@@ -23143,9 +23930,9 @@ var init_tui = __esm(() => {
23143
23930
  });
23144
23931
 
23145
23932
  // src/cli/index.ts
23146
- import { resolve as resolve3 } from "path";
23933
+ import { resolve as resolve4 } from "path";
23147
23934
  async function runAddSubcommand(arg) {
23148
- const target = resolve3(process.cwd(), arg && arg.length > 0 ? arg : ".");
23935
+ const target = resolve4(process.cwd(), arg && arg.length > 0 ? arg : ".");
23149
23936
  const { addSavedRepo: addSavedRepo2 } = await Promise.resolve().then(() => (init_repos(), exports_repos));
23150
23937
  const result = addSavedRepo2(target);
23151
23938
  if (result.added) {