@sma1lboy/kobe 0.5.19 → 0.5.20

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
@@ -5643,6 +5643,14 @@ var init_keybindings = __esm(() => {
5643
5643
  category: "Terminal",
5644
5644
  description: "Scroll scrollback down"
5645
5645
  },
5646
+ {
5647
+ id: "terminal.reset",
5648
+ scope: "terminal",
5649
+ keys: ["f5"],
5650
+ category: "Terminal",
5651
+ description: "Reset terminal \u2014 kill the current shell and respawn",
5652
+ hint: { keys: "f5", label: "reset" }
5653
+ },
5646
5654
  {
5647
5655
  id: "dialog.cancel",
5648
5656
  scope: "global",
@@ -7494,6 +7502,130 @@ var init_preview_host = __esm(() => {
7494
7502
  init_preview();
7495
7503
  });
7496
7504
 
7505
+ // src/tui/ui/dialog-confirm.tsx
7506
+ import { TextAttributes as TextAttributes6 } from "@opentui/core";
7507
+ function titlecase(s) {
7508
+ if (!s)
7509
+ return s;
7510
+ return s.charAt(0).toUpperCase() + s.slice(1);
7511
+ }
7512
+ function DialogConfirm(props) {
7513
+ const dialog = useDialog();
7514
+ const {
7515
+ theme
7516
+ } = useTheme();
7517
+ const [store2, setStore2] = createStore({
7518
+ active: "confirm"
7519
+ });
7520
+ useBindings(() => ({
7521
+ bindings: [{
7522
+ key: "return",
7523
+ cmd: () => {
7524
+ if (store2.active === "confirm")
7525
+ props.onConfirm?.();
7526
+ if (store2.active === "cancel")
7527
+ props.onCancel?.();
7528
+ dialog.clear();
7529
+ }
7530
+ }, {
7531
+ key: "left",
7532
+ cmd: () => setStore2("active", store2.active === "confirm" ? "cancel" : "confirm")
7533
+ }, {
7534
+ key: "right",
7535
+ cmd: () => setStore2("active", store2.active === "confirm" ? "cancel" : "confirm")
7536
+ }]
7537
+ }));
7538
+ return (() => {
7539
+ var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$4 = createElement("text"), _el$6 = createElement("text"), _el$7 = createElement("box");
7540
+ insertNode(_el$, _el$2);
7541
+ insertNode(_el$, _el$6);
7542
+ insertNode(_el$, _el$7);
7543
+ setProp(_el$, "paddingLeft", 2);
7544
+ setProp(_el$, "paddingRight", 2);
7545
+ setProp(_el$, "paddingBottom", 1);
7546
+ setProp(_el$, "gap", 0);
7547
+ insertNode(_el$2, _el$3);
7548
+ insertNode(_el$2, _el$4);
7549
+ setProp(_el$2, "flexDirection", "row");
7550
+ setProp(_el$2, "justifyContent", "space-between");
7551
+ insert(_el$3, () => props.title);
7552
+ insertNode(_el$4, createTextNode(`esc`));
7553
+ setProp(_el$4, "onMouseUp", () => dialog.clear());
7554
+ insert(_el$6, () => props.message);
7555
+ setProp(_el$7, "flexDirection", "row");
7556
+ setProp(_el$7, "justifyContent", "flex-end");
7557
+ setProp(_el$7, "paddingTop", 1);
7558
+ insert(_el$7, createComponent2(For, {
7559
+ each: ["cancel", "confirm"],
7560
+ children: (key) => (() => {
7561
+ var _el$8 = createElement("box"), _el$9 = createElement("text");
7562
+ insertNode(_el$8, _el$9);
7563
+ setProp(_el$8, "paddingLeft", 1);
7564
+ setProp(_el$8, "paddingRight", 1);
7565
+ setProp(_el$8, "onMouseUp", () => {
7566
+ if (key === "confirm")
7567
+ props.onConfirm?.();
7568
+ if (key === "cancel")
7569
+ props.onCancel?.();
7570
+ dialog.clear();
7571
+ });
7572
+ insert(_el$9, () => titlecase(key === "cancel" ? props.label ?? key : props.confirmLabel ?? key));
7573
+ effect((_p$) => {
7574
+ var _v$5 = key === store2.active ? theme.primary : undefined, _v$6 = key === store2.active ? theme.selectedListItemText : theme.textMuted;
7575
+ _v$5 !== _p$.e && (_p$.e = setProp(_el$8, "backgroundColor", _v$5, _p$.e));
7576
+ _v$6 !== _p$.t && (_p$.t = setProp(_el$9, "fg", _v$6, _p$.t));
7577
+ return _p$;
7578
+ }, {
7579
+ e: undefined,
7580
+ t: undefined
7581
+ });
7582
+ return _el$8;
7583
+ })()
7584
+ }));
7585
+ effect((_p$) => {
7586
+ var _v$ = TextAttributes6.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
7587
+ _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
7588
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
7589
+ _v$3 !== _p$.a && (_p$.a = setProp(_el$4, "fg", _v$3, _p$.a));
7590
+ _v$4 !== _p$.o && (_p$.o = setProp(_el$6, "fg", _v$4, _p$.o));
7591
+ return _p$;
7592
+ }, {
7593
+ e: undefined,
7594
+ t: undefined,
7595
+ a: undefined,
7596
+ o: undefined
7597
+ });
7598
+ return _el$;
7599
+ })();
7600
+ }
7601
+ var init_dialog_confirm = __esm(() => {
7602
+ init_solid();
7603
+ init_solid();
7604
+ init_solid();
7605
+ init_solid();
7606
+ init_solid();
7607
+ init_solid();
7608
+ init_solid();
7609
+ init_dev();
7610
+ init_dev2();
7611
+ init_theme();
7612
+ init_keymap();
7613
+ init_dialog();
7614
+ DialogConfirm.show = (dialog, title, message, label, confirmLabel) => {
7615
+ return new Promise((resolve) => {
7616
+ dialog.replace(() => createComponent2(DialogConfirm, {
7617
+ title,
7618
+ message,
7619
+ onConfirm: () => resolve(true),
7620
+ onCancel: () => resolve(false),
7621
+ label,
7622
+ confirmLabel
7623
+ }), () => resolve(undefined));
7624
+ dialog.setSize("small");
7625
+ });
7626
+ };
7627
+ });
7628
+
7497
7629
  // src/tui/panes/terminal/keys-pure.ts
7498
7630
  function keyEventToShellBytes(evt) {
7499
7631
  const seq = evt.sequence;
@@ -7551,7 +7683,8 @@ var init_keys_pure = __esm(() => {
7551
7683
  "shift+tab",
7552
7684
  "f1",
7553
7685
  "ctrl+p",
7554
- "ctrl+,"
7686
+ "ctrl+,",
7687
+ "f5"
7555
7688
  ];
7556
7689
  PASSTHROUGH_NAMES = [
7557
7690
  ..."abcdefghijklmnopqrstuvwxyz".split(""),
@@ -7595,7 +7728,8 @@ function useTerminalBindings(opts) {
7595
7728
  const bindings = [];
7596
7729
  bindings.push(...bindByIds({
7597
7730
  "terminal.scroll-up": () => opts.scroll(-pageSize()),
7598
- "terminal.scroll-down": () => opts.scroll(pageSize())
7731
+ "terminal.scroll-down": () => opts.scroll(pageSize()),
7732
+ "terminal.reset": () => opts.reset()
7599
7733
  }));
7600
7734
  const reserved = new Set(RESERVED_GLOBAL_CHORDS);
7601
7735
  for (const name of PASSTHROUGH_NAMES) {
@@ -13713,6 +13847,10 @@ class PtyRegistry {
13713
13847
  for (const id of ids)
13714
13848
  this.release(id);
13715
13849
  }
13850
+ reset(taskId, cwd, opts = {}) {
13851
+ this.release(taskId);
13852
+ return this.acquire(taskId, cwd, opts);
13853
+ }
13716
13854
  get size() {
13717
13855
  return this.map.size;
13718
13856
  }
@@ -14356,6 +14494,11 @@ function Terminal(props) {
14356
14494
  setAcquireError(null);
14357
14495
  setPty(handle);
14358
14496
  setScrollOffset(0);
14497
+ }));
14498
+ createEffect(() => {
14499
+ const handle = pty();
14500
+ if (!handle || handle.killed)
14501
+ return;
14359
14502
  const unsubscribe = handle.onData((snap, c2) => {
14360
14503
  setSnapshot(snap);
14361
14504
  setCursor(c2);
@@ -14369,10 +14512,41 @@ function Terminal(props) {
14369
14512
  onCleanup(() => {
14370
14513
  unsubscribe();
14371
14514
  });
14372
- }));
14515
+ });
14373
14516
  onCleanup(() => {
14374
14517
  setPty(null);
14375
14518
  });
14519
+ const dialog = useDialog();
14520
+ const requestReset = () => {
14521
+ const handle = pty();
14522
+ if (!handle)
14523
+ return;
14524
+ const cwd = props.cwd();
14525
+ const taskId = props.taskId();
14526
+ const geometry = bodyGeometry();
14527
+ if (!cwd || !taskId || !geometry)
14528
+ return;
14529
+ const cwdAtClick = cwd;
14530
+ const taskIdAtClick = taskId;
14531
+ const geometryAtClick = geometry;
14532
+ DialogConfirm.show(dialog, "Reset terminal?", "The running shell will be killed and a fresh one will spawn at the worktree. Any in-flight processes (vim, htop, paused jobs) end immediately.", "cancel").then((ok) => {
14533
+ if (ok !== true)
14534
+ return;
14535
+ const reg = registry();
14536
+ if (props.taskId() !== taskIdAtClick || props.cwd() !== cwdAtClick)
14537
+ return;
14538
+ try {
14539
+ const fresh = reg.reset(taskIdAtClick, cwdAtClick, geometryAtClick);
14540
+ setPty(fresh);
14541
+ setSnapshot("");
14542
+ setCursor(null);
14543
+ setScrollOffset(0);
14544
+ } catch (err) {
14545
+ const message = err instanceof Error ? err.message : String(err);
14546
+ setAcquireError(message);
14547
+ }
14548
+ });
14549
+ };
14376
14550
  useTerminalBindings({
14377
14551
  focused,
14378
14552
  write: (data) => {
@@ -14383,7 +14557,8 @@ function Terminal(props) {
14383
14557
  },
14384
14558
  scroll: (lines) => {
14385
14559
  setScrollOffset((cur) => Math.max(0, cur - lines));
14386
- }
14560
+ },
14561
+ reset: requestReset
14387
14562
  });
14388
14563
  const parsedRows = createMemo(() => parseAnsiSnapshot(snapshot()));
14389
14564
  const visibleRange = createMemo(() => {
@@ -14570,6 +14745,8 @@ var init_Terminal = __esm(() => {
14570
14745
  init_solid();
14571
14746
  init_dev();
14572
14747
  init_theme();
14748
+ init_dialog();
14749
+ init_dialog_confirm();
14573
14750
  init_keys3();
14574
14751
  init_registry();
14575
14752
  init_sgr();
@@ -14888,9 +15065,9 @@ var init_capabilities = __esm(() => {
14888
15065
 
14889
15066
  // src/engine/codex-local/models.ts
14890
15067
  function codexContextWindowFor(_modelId) {
14891
- return DEFAULT_CTX;
15068
+ return 0;
14892
15069
  }
14893
- var CODEX_GPT55_EFFORT_LEVELS, CODEX_MODELS, CODEX_FALLBACK_DEFAULT_MODEL_ID = "gpt-5.4-mini", DEFAULT_CTX = 400000;
15070
+ var CODEX_GPT55_EFFORT_LEVELS, CODEX_MODELS, CODEX_FALLBACK_DEFAULT_MODEL_ID = "gpt-5.4-mini";
14894
15071
  var init_models2 = __esm(() => {
14895
15072
  CODEX_GPT55_EFFORT_LEVELS = [
14896
15073
  "none",
@@ -15511,7 +15688,7 @@ var init_package = __esm(() => {
15511
15688
  package_default = {
15512
15689
  $schema: "https://json.schemastore.org/package.json",
15513
15690
  name: "@sma1lboy/kobe",
15514
- version: "0.5.19",
15691
+ version: "0.5.20",
15515
15692
  description: "TUI orchestrator for Claude Code (codename)",
15516
15693
  type: "module",
15517
15694
  packageManager: "bun@1.3.13",
@@ -15535,10 +15712,10 @@ var init_package = __esm(() => {
15535
15712
  bun: ">=1.3.11"
15536
15713
  },
15537
15714
  scripts: {
15538
- dev: "KOBE_DEV=1 bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
15539
- "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",
15715
+ dev: "env KOBE_DEV=1 bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
15716
+ "dev:test": "bun run scripts/dev-fixture.ts && env 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",
15540
15717
  "dev:test:reset": "bun run scripts/dev-fixture.ts --reset",
15541
- "dev:sandbox": "mkdir -p .dev-sandbox/home && KOBE_DEV=1 KOBE_HOME_DIR=$PWD/.dev-sandbox/home bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
15718
+ "dev:sandbox": "mkdir -p .dev-sandbox/home && env KOBE_DEV=1 KOBE_HOME_DIR=$PWD/.dev-sandbox/home bun --preload @opentui/solid/preload --conditions=browser ./src/cli/index.ts",
15542
15719
  "dev:sandbox:reset": "bun run scripts/dev-sandbox.ts --reset",
15543
15720
  build: "bun run scripts/build.ts",
15544
15721
  compile: "bun run scripts/compile.ts",
@@ -16358,7 +16535,7 @@ class SocketClient {
16358
16535
  nextId = 1;
16359
16536
  pending = new Map;
16360
16537
  connected;
16361
- constructor(path5) {
16538
+ constructor(path5, onClose) {
16362
16539
  this.socket = connect(path5);
16363
16540
  this.connected = new Promise((resolve2, reject) => {
16364
16541
  this.socket.once("connect", resolve2);
@@ -16370,6 +16547,7 @@ class SocketClient {
16370
16547
  pending.reject(new Error("kobe bridge socket closed"));
16371
16548
  }
16372
16549
  this.pending.clear();
16550
+ onClose?.();
16373
16551
  });
16374
16552
  }
16375
16553
  onData(text) {
@@ -16514,8 +16692,27 @@ async function runMcpBridgeSubcommand(argv) {
16514
16692
  `);
16515
16693
  process.exit(2);
16516
16694
  }
16517
- const client = new SocketClient(socketPath);
16695
+ let exiting = false;
16696
+ const exitOnce = (code = 0) => {
16697
+ if (exiting)
16698
+ return;
16699
+ exiting = true;
16700
+ process.exit(code);
16701
+ };
16702
+ const initialPpid = process.ppid;
16703
+ const ppidWatcher = setInterval(() => {
16704
+ const current = process.ppid;
16705
+ if (current !== initialPpid || current === 1)
16706
+ exitOnce();
16707
+ }, 1000);
16708
+ ppidWatcher.unref?.();
16709
+ process.stdin.once("end", () => exitOnce());
16710
+ process.stdin.once("close", () => exitOnce());
16711
+ process.once("SIGTERM", () => exitOnce());
16712
+ process.once("SIGINT", () => exitOnce());
16713
+ const client = new SocketClient(socketPath, () => exitOnce());
16518
16714
  await runMcpStdioLoop(client);
16715
+ exitOnce();
16519
16716
  }
16520
16717
  var TOOLS, PROTOCOL_VERSION = "2024-11-05";
16521
16718
  var init_mcp_bridge = __esm(() => {
@@ -16593,6 +16790,9 @@ function fitSocketPath(naturalPath, homeDir2, role, pidTag) {
16593
16790
  throw new Error(`kobe socket path exceeds ${SOCKET_PATH_SAFETY_LIMIT} bytes even after fallback: ${fallback}`);
16594
16791
  }
16595
16792
  function defaultDaemonSocketPath(homeDir2) {
16793
+ const override = process.env.KOBE_DAEMON_SOCKET_PATH;
16794
+ if (override && override.length > 0)
16795
+ return override;
16596
16796
  const explicit = homeDir2 ?? process.env.KOBE_HOME_DIR;
16597
16797
  if (explicit && explicit.length > 0) {
16598
16798
  return fitSocketPath(join8(explicit, ".kobe", "daemon.sock"), explicit, "daemon");
@@ -16605,6 +16805,9 @@ function defaultDaemonSocketPath(homeDir2) {
16605
16805
  return fitSocketPath(join8(home, ".kobe", "daemon.sock"), home, "daemon");
16606
16806
  }
16607
16807
  function defaultDaemonPidPath(homeDir2 = process.env.KOBE_HOME_DIR ?? homedir7()) {
16808
+ const override = process.env.KOBE_DAEMON_PID_PATH;
16809
+ if (override && override.length > 0)
16810
+ return override;
16608
16811
  return join8(homeDir2, ".kobe", "daemon.pid");
16609
16812
  }
16610
16813
  var SOCKET_PATH_SAFETY_LIMIT = 100;
@@ -16708,7 +16911,11 @@ class KobeDaemonClient {
16708
16911
  this.socket = null;
16709
16912
  }
16710
16913
  forceDisconnect() {
16711
- this.socket?.destroy();
16914
+ const socket = this.socket;
16915
+ if (!socket)
16916
+ return;
16917
+ this.socket = null;
16918
+ socket.destroy();
16712
16919
  }
16713
16920
  on(name, handler) {
16714
16921
  let set = this.handlers.get(name);
@@ -16769,7 +16976,7 @@ class KobeDaemonClient {
16769
16976
  });
16770
16977
  }
16771
16978
  onSocketClose(which) {
16772
- if (this.socket !== which && this.socket !== null)
16979
+ if (this.socket !== which)
16773
16980
  return;
16774
16981
  this.socket = null;
16775
16982
  for (const pending of this.pending.values())
@@ -16828,6 +17035,8 @@ var init_client = () => {};
16828
17035
  // src/client/daemon-process.ts
16829
17036
  import { spawn as spawn3 } from "child_process";
16830
17037
  import { existsSync as existsSync4 } from "fs";
17038
+ import { unlink as unlink2 } from "fs/promises";
17039
+ import { homedir as homedir8 } from "os";
16831
17040
  import { dirname as dirname3, join as join9, resolve as resolve2 } from "path";
16832
17041
  import { fileURLToPath } from "url";
16833
17042
  async function ensureDaemonReachable() {
@@ -16860,6 +17069,53 @@ async function connectOrStartDaemon() {
16860
17069
  await client.connect();
16861
17070
  return client;
16862
17071
  }
17072
+ async function connectOrStartOwnedDaemon() {
17073
+ const homeDir2 = process.env.KOBE_HOME_DIR ?? homedir8();
17074
+ const socketPath = fitSocketPath(join9(homeDir2, ".kobe", `daemon-${process.pid}.sock`), homeDir2, "daemon", process.pid);
17075
+ const pidPath = join9(homeDir2, ".kobe", `daemon-${process.pid}.pid`);
17076
+ await ensureOwnedDaemonReachable(socketPath, pidPath);
17077
+ const client = new KobeDaemonClient(socketPath);
17078
+ await client.connect();
17079
+ return {
17080
+ client,
17081
+ socketPath,
17082
+ pidPath,
17083
+ stop: async () => {
17084
+ try {
17085
+ await client.request("daemon.stop");
17086
+ } catch {} finally {
17087
+ client.close();
17088
+ }
17089
+ }
17090
+ };
17091
+ }
17092
+ async function ensureOwnedDaemonReachable(socketPath, pidPath) {
17093
+ await unlink2(socketPath).catch(() => {});
17094
+ const { entry, runWithBun } = resolveKobedEntry();
17095
+ const env = {
17096
+ ...process.env,
17097
+ KOBE_DAEMON_SOCKET_PATH: socketPath,
17098
+ KOBE_DAEMON_PID_PATH: pidPath
17099
+ };
17100
+ const child = runWithBun ? spawn3(process.execPath, [entry, "start"], {
17101
+ detached: true,
17102
+ stdio: "ignore",
17103
+ env
17104
+ }) : spawn3(entry, ["start"], {
17105
+ detached: true,
17106
+ stdio: "ignore",
17107
+ env
17108
+ });
17109
+ child.unref();
17110
+ const deadline = Date.now() + 5000;
17111
+ while (Date.now() < deadline) {
17112
+ if (await testCanConnect(socketPath)) {
17113
+ return;
17114
+ }
17115
+ await new Promise((resolveTimer) => setTimeout(resolveTimer, 100));
17116
+ }
17117
+ throw new Error(`kobe: owned daemon did not start at ${socketPath}`);
17118
+ }
16863
17119
  async function testCanConnect(socketPath) {
16864
17120
  const probe = new KobeDaemonClient(socketPath);
16865
17121
  try {
@@ -18748,9 +19004,10 @@ class RemoteOrchestrator {
18748
19004
  setConnectionState;
18749
19005
  rcBridgeAcc;
18750
19006
  setRcBridge;
19007
+ ensureReachable;
18751
19008
  subscribers = new Map;
18752
19009
  pendingInputBroker = new InMemoryPendingInputBroker;
18753
- constructor(client) {
19010
+ constructor(client, options = {}) {
18754
19011
  this.client = client;
18755
19012
  const [tasks, setTasks] = createSignal([]);
18756
19013
  const [runState, setRunState] = createSignal(new Map);
@@ -18767,6 +19024,7 @@ class RemoteOrchestrator {
18767
19024
  this.setConnectionState = (next) => setConnectionState(() => next);
18768
19025
  this.rcBridgeAcc = rcBridge;
18769
19026
  this.setRcBridge = (next) => setRcBridge(() => next);
19027
+ this.ensureReachable = options.ensureReachable ?? ensureDaemonReachable;
18770
19028
  this.client.on("*", (frame) => this.handleEvent(frame.name, frame.payload));
18771
19029
  this.client.onLifecycle("close", () => this.setConnectionState("disconnected"));
18772
19030
  }
@@ -18813,7 +19071,7 @@ class RemoteOrchestrator {
18813
19071
  }
18814
19072
  async manualReconnect() {
18815
19073
  this.client.forceDisconnect();
18816
- await ensureDaemonReachable();
19074
+ await this.ensureReachable();
18817
19075
  for (const task of this.tasksAcc())
18818
19076
  this.pendingInputBroker.clearForTask(task.id);
18819
19077
  await this.init();
@@ -19317,7 +19575,7 @@ var init_manager = __esm(() => {
19317
19575
  // src/engine/codex-local/binary.ts
19318
19576
  import { spawnSync as spawnSync7 } from "child_process";
19319
19577
  import { existsSync as existsSync5, statSync as statSync3 } from "fs";
19320
- import { homedir as homedir8 } from "os";
19578
+ import { homedir as homedir9 } from "os";
19321
19579
  import path7 from "path";
19322
19580
  async function findCodexBinary(deps = defaultDeps2) {
19323
19581
  const checked = [];
@@ -19374,7 +19632,7 @@ var init_binary2 = __esm(() => {
19374
19632
  return process.env[name];
19375
19633
  },
19376
19634
  home() {
19377
- return homedir8();
19635
+ return homedir9();
19378
19636
  },
19379
19637
  which(name) {
19380
19638
  const cmd = process.platform === "win32" ? "where" : "which";
@@ -19404,7 +19662,7 @@ var init_binary2 = __esm(() => {
19404
19662
 
19405
19663
  // src/engine/account-detect.ts
19406
19664
  import { readFileSync as readFileSync6, statSync as statSync4 } from "fs";
19407
- import { homedir as homedir9 } from "os";
19665
+ import { homedir as homedir10 } from "os";
19408
19666
  import path8 from "path";
19409
19667
  function claudeGlobalConfigPath(env, home) {
19410
19668
  const override = env("CLAUDE_CONFIG_DIR")?.trim();
@@ -19558,7 +19816,7 @@ var init_account_detect = __esm(() => {
19558
19816
  return process.env[name];
19559
19817
  },
19560
19818
  home() {
19561
- return homedir9();
19819
+ return homedir10();
19562
19820
  },
19563
19821
  findClaudeBinary() {
19564
19822
  return findClaudeBinary();
@@ -19569,128 +19827,340 @@ var init_account_detect = __esm(() => {
19569
19827
  };
19570
19828
  });
19571
19829
 
19572
- // src/tui/ui/dialog-confirm.tsx
19573
- import { TextAttributes as TextAttributes6 } from "@opentui/core";
19574
- function titlecase(s2) {
19575
- if (!s2)
19576
- return s2;
19577
- return s2.charAt(0).toUpperCase() + s2.slice(1);
19830
+ // src/engine/codex-local/app-server.ts
19831
+ import { spawn as spawn5 } from "child_process";
19832
+ import { readFileSync as readFileSync7 } from "fs";
19833
+ function resolveCodexBackend(env = process.env, readPreference = readCodexBackendPreference) {
19834
+ if (env.KOBE_CODEX_BACKEND === "exec")
19835
+ return "exec";
19836
+ if (env.KOBE_CODEX_BACKEND === "app-server" || env.KOBE_CODEX_APP_SERVER === "1")
19837
+ return "app-server";
19838
+ return readPreference() ?? "app-server";
19839
+ }
19840
+ function readCodexBackendPreference() {
19841
+ try {
19842
+ const parsed = JSON.parse(readFileSync7(kvStatePath(), "utf8"));
19843
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
19844
+ return;
19845
+ const raw = parsed[CODEX_BACKEND_KV_KEY];
19846
+ if (raw === "exec" || raw === "app-server")
19847
+ return raw;
19848
+ } catch {}
19849
+ return;
19578
19850
  }
19579
- function DialogConfirm(props) {
19580
- const dialog = useDialog();
19581
- const {
19582
- theme
19583
- } = useTheme();
19584
- const [store2, setStore2] = createStore({
19585
- active: "confirm"
19851
+ function spawnCodexAppServerTurn(opts) {
19852
+ const args = buildAppServerArgs(opts);
19853
+ const proc = spawn5(opts.binaryPath, args, {
19854
+ cwd: opts.cwd,
19855
+ env: { ...process.env, ...opts.env ?? {} },
19856
+ stdio: ["pipe", "pipe", "pipe"]
19586
19857
  });
19587
- useBindings(() => ({
19588
- bindings: [{
19589
- key: "return",
19590
- cmd: () => {
19591
- if (store2.active === "confirm")
19592
- props.onConfirm?.();
19593
- if (store2.active === "cancel")
19594
- props.onCancel?.();
19595
- dialog.clear();
19596
- }
19597
- }, {
19598
- key: "left",
19599
- cmd: () => setStore2("active", store2.active === "confirm" ? "cancel" : "confirm")
19600
- }, {
19601
- key: "right",
19602
- cmd: () => setStore2("active", store2.active === "confirm" ? "cancel" : "confirm")
19603
- }]
19604
- }));
19605
- return (() => {
19606
- var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$4 = createElement("text"), _el$6 = createElement("text"), _el$7 = createElement("box");
19607
- insertNode(_el$, _el$2);
19608
- insertNode(_el$, _el$6);
19609
- insertNode(_el$, _el$7);
19610
- setProp(_el$, "paddingLeft", 2);
19611
- setProp(_el$, "paddingRight", 2);
19612
- setProp(_el$, "paddingBottom", 1);
19613
- setProp(_el$, "gap", 0);
19614
- insertNode(_el$2, _el$3);
19615
- insertNode(_el$2, _el$4);
19616
- setProp(_el$2, "flexDirection", "row");
19617
- setProp(_el$2, "justifyContent", "space-between");
19618
- insert(_el$3, () => props.title);
19619
- insertNode(_el$4, createTextNode(`esc`));
19620
- setProp(_el$4, "onMouseUp", () => dialog.clear());
19621
- insert(_el$6, () => props.message);
19622
- setProp(_el$7, "flexDirection", "row");
19623
- setProp(_el$7, "justifyContent", "flex-end");
19624
- setProp(_el$7, "paddingTop", 1);
19625
- insert(_el$7, createComponent2(For, {
19626
- each: ["cancel", "confirm"],
19627
- children: (key) => (() => {
19628
- var _el$8 = createElement("box"), _el$9 = createElement("text");
19629
- insertNode(_el$8, _el$9);
19630
- setProp(_el$8, "paddingLeft", 1);
19631
- setProp(_el$8, "paddingRight", 1);
19632
- setProp(_el$8, "onMouseUp", () => {
19633
- if (key === "confirm")
19634
- props.onConfirm?.();
19635
- if (key === "cancel")
19636
- props.onCancel?.();
19637
- dialog.clear();
19638
- });
19639
- insert(_el$9, () => titlecase(key === "cancel" ? props.label ?? key : props.confirmLabel ?? key));
19640
- effect((_p$) => {
19641
- var _v$5 = key === store2.active ? theme.primary : undefined, _v$6 = key === store2.active ? theme.selectedListItemText : theme.textMuted;
19642
- _v$5 !== _p$.e && (_p$.e = setProp(_el$8, "backgroundColor", _v$5, _p$.e));
19643
- _v$6 !== _p$.t && (_p$.t = setProp(_el$9, "fg", _v$6, _p$.t));
19644
- return _p$;
19645
- }, {
19646
- e: undefined,
19647
- t: undefined
19648
- });
19649
- return _el$8;
19650
- })()
19858
+ const rpc = new AppServerRpc(proc, opts);
19859
+ rpc.run();
19860
+ return {
19861
+ proc,
19862
+ stdout: proc.stdout,
19863
+ stderr: proc.stderr,
19864
+ args,
19865
+ ready: rpc.ready,
19866
+ closed: rpc.closed
19867
+ };
19868
+ }
19869
+ function buildAppServerArgs(opts) {
19870
+ const mode = permissionPayloads(opts.permissionMode);
19871
+ return ["app-server", "-c", `approval_policy="${mode.approvalPolicy}"`, "-c", `sandbox_mode="${mode.threadSandbox}"`];
19872
+ }
19873
+ function codexAppServerUsageToSnapshot(params) {
19874
+ const root = asObject(params);
19875
+ const tokenUsage = asObject(root?.tokenUsage ?? root?.token_usage);
19876
+ const last = asObject(tokenUsage?.last);
19877
+ if (!last)
19878
+ return null;
19879
+ const totalTokens = numberOr(last.totalTokens ?? last.total_tokens, 0);
19880
+ const inputTokens = numberOr(last.inputTokens ?? last.input_tokens, 0);
19881
+ const cachedInputTokens = numberOr(last.cachedInputTokens ?? last.cached_input_tokens, 0);
19882
+ const outputTokens = numberOr(last.outputTokens ?? last.output_tokens, 0);
19883
+ const contextWindow = numberOr(tokenUsage?.modelContextWindow ?? tokenUsage?.model_context_window, 0);
19884
+ if (totalTokens <= 0 && inputTokens <= 0 && outputTokens <= 0 && cachedInputTokens <= 0)
19885
+ return null;
19886
+ return {
19887
+ type: "usage",
19888
+ input_tokens: Math.max(0, inputTokens - cachedInputTokens),
19889
+ output_tokens: outputTokens,
19890
+ ...cachedInputTokens > 0 ? { cache_read_input_tokens: cachedInputTokens } : {},
19891
+ ...totalTokens > 0 ? { context_tokens: totalTokens } : {},
19892
+ ...contextWindow > 0 ? { context_window_tokens: contextWindow } : {}
19893
+ };
19894
+ }
19895
+ function codexAppServerItemNotificationToEvents(method, params) {
19896
+ if (method !== "item/started" && method !== "item/completed")
19897
+ return [];
19898
+ const p2 = asObject(params);
19899
+ const item = asObject(p2?.item);
19900
+ const itemType = typeof item?.type === "string" ? item.type : "tool";
19901
+ if (isNonToolTranscriptItem(itemType))
19902
+ return [];
19903
+ const payload = stripItemHousekeeping(item ?? {});
19904
+ if (method === "item/started")
19905
+ return [{ type: "tool.start", name: itemType, input: payload }];
19906
+ return [{ type: "tool.result", name: itemType, output: payload }];
19907
+ }
19908
+
19909
+ class AppServerRpc {
19910
+ proc;
19911
+ opts;
19912
+ pending = new Map;
19913
+ readBuffer = "";
19914
+ nextId = 1;
19915
+ readyResolve = () => {};
19916
+ readyReject = () => {};
19917
+ ready = new Promise((resolve3, reject) => {
19918
+ this.readyResolve = resolve3;
19919
+ this.readyReject = reject;
19920
+ });
19921
+ closed;
19922
+ constructor(proc, opts) {
19923
+ this.proc = proc;
19924
+ this.opts = opts;
19925
+ this.closed = new Promise((resolve3) => {
19926
+ proc.once("exit", (code, signal) => resolve3({ code, signal }));
19927
+ });
19928
+ proc.stdout.setEncoding("utf8");
19929
+ proc.stdout.on("data", (chunk) => this.onStdout(chunk));
19930
+ proc.stdout.on("error", () => {});
19931
+ proc.stderr.on("error", () => {});
19932
+ proc.once("error", (err) => {
19933
+ this.readyReject(err);
19934
+ this.rejectAll(err);
19935
+ });
19936
+ }
19937
+ async run() {
19938
+ try {
19939
+ await this.call("initialize", {
19940
+ clientInfo: {
19941
+ name: "kobe",
19942
+ title: "kobe",
19943
+ version: "0.0.0"
19944
+ },
19945
+ capabilities: { experimentalApi: true }
19946
+ });
19947
+ this.notify("initialized", undefined);
19948
+ const sessionId = this.opts.resumeSessionId ? await this.resumeThread(this.opts.resumeSessionId) : await this.startThread();
19949
+ this.opts.onSessionId(sessionId);
19950
+ this.readyResolve(sessionId);
19951
+ await this.startTurn(sessionId);
19952
+ } catch (err) {
19953
+ this.readyReject(err);
19954
+ this.opts.onEvent({ type: "error", message: `codex app-server failure: ${stringifyErr(err)}` });
19955
+ this.close();
19956
+ }
19957
+ }
19958
+ async startThread() {
19959
+ const mode = permissionPayloads(this.opts.permissionMode);
19960
+ const result = asObject(await this.call("thread/start", {
19961
+ cwd: this.opts.cwd,
19962
+ model: this.opts.model ?? null,
19963
+ approvalPolicy: mode.approvalPolicy,
19964
+ sandbox: mode.threadSandbox,
19965
+ ephemeral: false
19651
19966
  }));
19652
- effect((_p$) => {
19653
- var _v$ = TextAttributes6.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
19654
- _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
19655
- _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
19656
- _v$3 !== _p$.a && (_p$.a = setProp(_el$4, "fg", _v$3, _p$.a));
19657
- _v$4 !== _p$.o && (_p$.o = setProp(_el$6, "fg", _v$4, _p$.o));
19658
- return _p$;
19659
- }, {
19660
- e: undefined,
19661
- t: undefined,
19662
- a: undefined,
19663
- o: undefined
19967
+ const thread = asObject(result?.thread);
19968
+ const id = typeof thread?.id === "string" ? thread.id : undefined;
19969
+ if (!id)
19970
+ throw new Error("thread/start did not return a thread id");
19971
+ return id;
19972
+ }
19973
+ async resumeThread(sessionId) {
19974
+ const mode = permissionPayloads(this.opts.permissionMode);
19975
+ const result = asObject(await this.call("thread/resume", {
19976
+ threadId: sessionId,
19977
+ cwd: this.opts.cwd,
19978
+ model: this.opts.model ?? null,
19979
+ approvalPolicy: mode.approvalPolicy,
19980
+ sandbox: mode.threadSandbox
19981
+ }));
19982
+ const thread = asObject(result?.thread);
19983
+ const id = typeof thread?.id === "string" ? thread.id : undefined;
19984
+ if (!id)
19985
+ throw new Error("thread/resume did not return a thread id");
19986
+ return id;
19987
+ }
19988
+ async startTurn(sessionId) {
19989
+ const mode = permissionPayloads(this.opts.permissionMode);
19990
+ await this.call("turn/start", {
19991
+ threadId: sessionId,
19992
+ input: [{ type: "text", text: this.opts.prompt, text_elements: [] }],
19993
+ cwd: this.opts.cwd,
19994
+ model: this.opts.model ?? null,
19995
+ effort: this.opts.modelEffort ?? null,
19996
+ approvalPolicy: mode.approvalPolicy,
19997
+ sandboxPolicy: mode.turnSandboxPolicy
19664
19998
  });
19665
- return _el$;
19666
- })();
19667
- }
19668
- var init_dialog_confirm = __esm(() => {
19669
- init_solid();
19670
- init_solid();
19671
- init_solid();
19672
- init_solid();
19673
- init_solid();
19674
- init_solid();
19675
- init_solid();
19676
- init_dev();
19677
- init_dev2();
19678
- init_theme();
19679
- init_keymap();
19680
- init_dialog();
19681
- DialogConfirm.show = (dialog, title, message, label, confirmLabel) => {
19682
- return new Promise((resolve3) => {
19683
- dialog.replace(() => createComponent2(DialogConfirm, {
19684
- title,
19685
- message,
19686
- onConfirm: () => resolve3(true),
19687
- onCancel: () => resolve3(false),
19688
- label,
19689
- confirmLabel
19690
- }), () => resolve3(undefined));
19691
- dialog.setSize("small");
19999
+ }
20000
+ call(method, params) {
20001
+ const id = this.nextId++;
20002
+ this.send({ jsonrpc: "2.0", id, method, params });
20003
+ return new Promise((resolve3, reject) => {
20004
+ this.pending.set(id, { resolve: resolve3, reject });
20005
+ });
20006
+ }
20007
+ notify(method, params) {
20008
+ this.send(params === undefined ? { jsonrpc: "2.0", method } : { jsonrpc: "2.0", method, params });
20009
+ }
20010
+ send(payload) {
20011
+ this.proc.stdin.write(`${JSON.stringify(payload)}
20012
+ `);
20013
+ }
20014
+ onStdout(chunk) {
20015
+ this.readBuffer += chunk;
20016
+ let lineEnd = this.readBuffer.indexOf(`
20017
+ `);
20018
+ while (lineEnd !== -1) {
20019
+ const line = this.readBuffer.slice(0, lineEnd).trim();
20020
+ this.readBuffer = this.readBuffer.slice(lineEnd + 1);
20021
+ if (line.length > 0)
20022
+ this.handleLine(line);
20023
+ lineEnd = this.readBuffer.indexOf(`
20024
+ `);
20025
+ }
20026
+ }
20027
+ handleLine(line) {
20028
+ let msg;
20029
+ try {
20030
+ msg = JSON.parse(line);
20031
+ } catch {
20032
+ return;
20033
+ }
20034
+ const record = asObject(msg);
20035
+ if (!record)
20036
+ return;
20037
+ const id = typeof record.id === "number" ? record.id : undefined;
20038
+ const method = typeof record.method === "string" ? record.method : undefined;
20039
+ if (id !== undefined && this.pending.has(id)) {
20040
+ const pending = this.pending.get(id);
20041
+ this.pending.delete(id);
20042
+ if (!pending)
20043
+ return;
20044
+ const error = asObject(record.error);
20045
+ if (error)
20046
+ pending.reject(new Error(typeof error.message === "string" ? error.message : "app-server request failed"));
20047
+ else
20048
+ pending.resolve(record.result);
20049
+ return;
20050
+ }
20051
+ if (id !== undefined && method) {
20052
+ this.rejectServerRequest(id, method);
20053
+ return;
20054
+ }
20055
+ if (!method)
20056
+ return;
20057
+ this.handleNotification(method, record.params);
20058
+ }
20059
+ handleNotification(method, params) {
20060
+ if (method === "thread/tokenUsage/updated") {
20061
+ const usage = codexAppServerUsageToSnapshot(params);
20062
+ if (usage)
20063
+ this.opts.onEvent(usage);
20064
+ return;
20065
+ }
20066
+ if (method === "item/agentMessage/delta") {
20067
+ const p2 = asObject(params);
20068
+ const text = typeof p2?.delta === "string" ? p2.delta : typeof p2?.text === "string" ? p2.text : "";
20069
+ if (text)
20070
+ this.opts.onEvent({ type: "assistant.delta", text });
20071
+ return;
20072
+ }
20073
+ if (method === "item/started" || method === "item/completed") {
20074
+ for (const event of codexAppServerItemNotificationToEvents(method, params))
20075
+ this.opts.onEvent(event);
20076
+ return;
20077
+ }
20078
+ if (method === "turn/completed") {
20079
+ const p2 = asObject(params);
20080
+ const turn = asObject(p2?.turn);
20081
+ const error = turn?.error;
20082
+ if (error) {
20083
+ this.opts.onEvent({ type: "error", message: stringifyErr(error) });
20084
+ } else {
20085
+ this.opts.onEvent({ type: "done" });
20086
+ }
20087
+ this.close();
20088
+ return;
20089
+ }
20090
+ if (method === "error") {
20091
+ const p2 = asObject(params);
20092
+ const message = typeof p2?.message === "string" ? p2.message : "codex app-server emitted an error";
20093
+ this.opts.onEvent({ type: "error", message });
20094
+ this.close();
20095
+ }
20096
+ }
20097
+ rejectServerRequest(id, method) {
20098
+ this.send({
20099
+ jsonrpc: "2.0",
20100
+ id,
20101
+ error: {
20102
+ code: -32000,
20103
+ message: `kobe app-server backend does not handle server request ${method}`
20104
+ }
19692
20105
  });
20106
+ }
20107
+ close() {
20108
+ try {
20109
+ this.proc.stdin.end();
20110
+ } catch {}
20111
+ setTimeout(() => {
20112
+ if (!this.proc.killed) {
20113
+ try {
20114
+ this.proc.kill("SIGTERM");
20115
+ } catch {}
20116
+ }
20117
+ }, 50).unref();
20118
+ }
20119
+ rejectAll(err) {
20120
+ for (const pending of this.pending.values())
20121
+ pending.reject(err);
20122
+ this.pending.clear();
20123
+ }
20124
+ }
20125
+ function permissionPayloads(mode) {
20126
+ if (mode === "plan") {
20127
+ return {
20128
+ approvalPolicy: "never",
20129
+ threadSandbox: "read-only",
20130
+ turnSandboxPolicy: { type: "readOnly", networkAccess: true }
20131
+ };
20132
+ }
20133
+ return {
20134
+ approvalPolicy: "never",
20135
+ threadSandbox: "danger-full-access",
20136
+ turnSandboxPolicy: { type: "dangerFullAccess" }
19693
20137
  };
20138
+ }
20139
+ function asObject(v2) {
20140
+ return typeof v2 === "object" && v2 !== null && !Array.isArray(v2) ? v2 : null;
20141
+ }
20142
+ function numberOr(v2, fallback) {
20143
+ return typeof v2 === "number" && Number.isFinite(v2) ? v2 : fallback;
20144
+ }
20145
+ function stripItemHousekeeping(item) {
20146
+ const { id: _id, type: _type, ...rest } = item;
20147
+ return rest;
20148
+ }
20149
+ function isNonToolTranscriptItem(itemType) {
20150
+ return itemType === "agentMessage" || itemType === "agent_message" || itemType === "userMessage" || itemType === "user_message";
20151
+ }
20152
+ function stringifyErr(err) {
20153
+ if (err instanceof Error)
20154
+ return err.message;
20155
+ try {
20156
+ return JSON.stringify(err);
20157
+ } catch {
20158
+ return String(err);
20159
+ }
20160
+ }
20161
+ var CODEX_BACKEND_KV_KEY = "codex.backend";
20162
+ var init_app_server = __esm(() => {
20163
+ init_env();
19694
20164
  });
19695
20165
 
19696
20166
  // src/tui/component/settings-dialog.tsx
@@ -19745,6 +20215,8 @@ function SettingsDialog(props) {
19745
20215
  function bodyRowCount() {
19746
20216
  if (section() === "general")
19747
20217
  return themeNames().length + 1 + FOCUS_ACCENT_SLOTS.length + 2;
20218
+ if (section() === "codex")
20219
+ return CODEX_BACKENDS.length;
19748
20220
  if (section() === "dev")
19749
20221
  return devRowCount();
19750
20222
  if (section() === "accounts")
@@ -19787,6 +20259,21 @@ function SettingsDialog(props) {
19787
20259
  function toggleSound() {
19788
20260
  props.kv.set("notifications.sound.enabled", !soundEnabled());
19789
20261
  }
20262
+ function codexBackend() {
20263
+ const raw = props.kv.get(CODEX_BACKEND_KV_KEY, "app-server");
20264
+ return raw === "exec" || raw === "app-server" ? raw : "app-server";
20265
+ }
20266
+ function setCodexBackend(next) {
20267
+ props.kv.set(CODEX_BACKEND_KV_KEY, next);
20268
+ }
20269
+ function codexEnvOverride() {
20270
+ if (process.env.KOBE_CODEX_BACKEND === "exec")
20271
+ return "exec";
20272
+ if (process.env.KOBE_CODEX_BACKEND === "app-server" || process.env.KOBE_CODEX_APP_SERVER === "1") {
20273
+ return "app-server";
20274
+ }
20275
+ return null;
20276
+ }
19790
20277
  function moveCursor(delta) {
19791
20278
  if (level() === "sidebar") {
19792
20279
  const next2 = (cursor() + delta + SECTIONS.length) % SECTIONS.length;
@@ -19942,6 +20429,12 @@ function SettingsDialog(props) {
19942
20429
  themeCtx.set(name);
19943
20430
  return;
19944
20431
  }
20432
+ if (section() === "codex") {
20433
+ const backend = CODEX_BACKENDS[bodyRow()];
20434
+ if (backend)
20435
+ setCodexBackend(backend);
20436
+ return;
20437
+ }
19945
20438
  if (section() === "dev") {
19946
20439
  if (bodyRow() === 0)
19947
20440
  confirmReset();
@@ -19957,10 +20450,10 @@ function SettingsDialog(props) {
19957
20450
  ]
19958
20451
  }));
19959
20452
  return (() => {
19960
- 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$62 = createElement("box"), _el$63 = createElement("text");
20453
+ 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$70 = createElement("box"), _el$71 = createElement("text");
19961
20454
  insertNode(_el$, _el$2);
19962
20455
  insertNode(_el$, _el$7);
19963
- insertNode(_el$, _el$62);
20456
+ insertNode(_el$, _el$70);
19964
20457
  setProp(_el$, "paddingLeft", 2);
19965
20458
  setProp(_el$, "paddingRight", 2);
19966
20459
  setProp(_el$, "paddingBottom", 1);
@@ -19986,28 +20479,28 @@ function SettingsDialog(props) {
19986
20479
  const isSection = () => i2() === cursor();
19987
20480
  const isSidebarFocused = () => isSection() && level() === "sidebar";
19988
20481
  return (() => {
19989
- var _el$65 = createElement("box"), _el$66 = createElement("text");
19990
- insertNode(_el$65, _el$66);
19991
- setProp(_el$65, "paddingLeft", 1);
19992
- setProp(_el$65, "paddingRight", 1);
19993
- setProp(_el$65, "onMouseUp", () => {
20482
+ var _el$73 = createElement("box"), _el$74 = createElement("text");
20483
+ insertNode(_el$73, _el$74);
20484
+ setProp(_el$73, "paddingLeft", 1);
20485
+ setProp(_el$73, "paddingRight", 1);
20486
+ setProp(_el$73, "onMouseUp", () => {
19994
20487
  switchSection(s2.id);
19995
20488
  setLevel("sidebar");
19996
20489
  });
19997
- setProp(_el$66, "wrapMode", "none");
19998
- insert(_el$66, () => s2.label);
20490
+ setProp(_el$74, "wrapMode", "none");
20491
+ insert(_el$74, () => s2.label);
19999
20492
  effect((_p$) => {
20000
- var _v$37 = isSidebarFocused() ? theme.primary : undefined, _v$38 = isSidebarFocused() ? theme.selectedListItemText : isSection() ? theme.accent : theme.textMuted, _v$39 = isSection() ? TextAttributes7.BOLD : undefined;
20001
- _v$37 !== _p$.e && (_p$.e = setProp(_el$65, "backgroundColor", _v$37, _p$.e));
20002
- _v$38 !== _p$.t && (_p$.t = setProp(_el$66, "fg", _v$38, _p$.t));
20003
- _v$39 !== _p$.a && (_p$.a = setProp(_el$66, "attributes", _v$39, _p$.a));
20493
+ var _v$41 = isSidebarFocused() ? theme.primary : undefined, _v$42 = isSidebarFocused() ? theme.selectedListItemText : isSection() ? theme.accent : theme.textMuted, _v$43 = isSection() ? TextAttributes7.BOLD : undefined;
20494
+ _v$41 !== _p$.e && (_p$.e = setProp(_el$73, "backgroundColor", _v$41, _p$.e));
20495
+ _v$42 !== _p$.t && (_p$.t = setProp(_el$74, "fg", _v$42, _p$.t));
20496
+ _v$43 !== _p$.a && (_p$.a = setProp(_el$74, "attributes", _v$43, _p$.a));
20004
20497
  return _p$;
20005
20498
  }, {
20006
20499
  e: undefined,
20007
20500
  t: undefined,
20008
20501
  a: undefined
20009
20502
  });
20010
- return _el$65;
20503
+ return _el$73;
20011
20504
  })();
20012
20505
  }
20013
20506
  }));
@@ -20041,33 +20534,33 @@ function SettingsDialog(props) {
20041
20534
  const isCursor = () => level() === "body" && bodyRow() === i2();
20042
20535
  const isSelected = () => name === themeCtx.selected;
20043
20536
  return (() => {
20044
- var _el$67 = createElement("box"), _el$68 = createElement("text");
20045
- insertNode(_el$67, _el$68);
20046
- setProp(_el$67, "flexDirection", "row");
20047
- setProp(_el$67, "gap", 1);
20048
- setProp(_el$67, "paddingLeft", 1);
20049
- setProp(_el$67, "paddingRight", 1);
20050
- setProp(_el$67, "onMouseUp", () => {
20537
+ var _el$75 = createElement("box"), _el$76 = createElement("text");
20538
+ insertNode(_el$75, _el$76);
20539
+ setProp(_el$75, "flexDirection", "row");
20540
+ setProp(_el$75, "gap", 1);
20541
+ setProp(_el$75, "paddingLeft", 1);
20542
+ setProp(_el$75, "paddingRight", 1);
20543
+ setProp(_el$75, "onMouseUp", () => {
20051
20544
  setLevel("body");
20052
20545
  setBodyRow(i2());
20053
20546
  setThemeCursor(i2());
20054
20547
  themeCtx.set(name);
20055
20548
  });
20056
- setProp(_el$68, "wrapMode", "none");
20057
- insert(_el$68, () => isSelected() ? "\u25CF " : " ", null);
20058
- insert(_el$68, name, null);
20549
+ setProp(_el$76, "wrapMode", "none");
20550
+ insert(_el$76, () => isSelected() ? "\u25CF " : " ", null);
20551
+ insert(_el$76, name, null);
20059
20552
  effect((_p$) => {
20060
- var _v$40 = isCursor() ? theme.primary : undefined, _v$41 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.accent : theme.text, _v$42 = isCursor() || isSelected() ? TextAttributes7.BOLD : undefined;
20061
- _v$40 !== _p$.e && (_p$.e = setProp(_el$67, "backgroundColor", _v$40, _p$.e));
20062
- _v$41 !== _p$.t && (_p$.t = setProp(_el$68, "fg", _v$41, _p$.t));
20063
- _v$42 !== _p$.a && (_p$.a = setProp(_el$68, "attributes", _v$42, _p$.a));
20553
+ var _v$44 = isCursor() ? theme.primary : undefined, _v$45 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.accent : theme.text, _v$46 = isCursor() || isSelected() ? TextAttributes7.BOLD : undefined;
20554
+ _v$44 !== _p$.e && (_p$.e = setProp(_el$75, "backgroundColor", _v$44, _p$.e));
20555
+ _v$45 !== _p$.t && (_p$.t = setProp(_el$76, "fg", _v$45, _p$.t));
20556
+ _v$46 !== _p$.a && (_p$.a = setProp(_el$76, "attributes", _v$46, _p$.a));
20064
20557
  return _p$;
20065
20558
  }, {
20066
20559
  e: undefined,
20067
20560
  t: undefined,
20068
20561
  a: undefined
20069
20562
  });
20070
- return _el$67;
20563
+ return _el$75;
20071
20564
  })();
20072
20565
  }
20073
20566
  }));
@@ -20106,32 +20599,32 @@ function SettingsDialog(props) {
20106
20599
  const isCursor = () => level() === "body" && bodyRow() === rowIndex();
20107
20600
  const isSelected = () => themeCtx.focusAccent === slot;
20108
20601
  return (() => {
20109
- var _el$69 = createElement("box"), _el$70 = createElement("text");
20110
- insertNode(_el$69, _el$70);
20111
- setProp(_el$69, "flexDirection", "row");
20112
- setProp(_el$69, "gap", 1);
20113
- setProp(_el$69, "paddingLeft", 1);
20114
- setProp(_el$69, "paddingRight", 1);
20115
- setProp(_el$69, "onMouseUp", () => {
20602
+ var _el$77 = createElement("box"), _el$78 = createElement("text");
20603
+ insertNode(_el$77, _el$78);
20604
+ setProp(_el$77, "flexDirection", "row");
20605
+ setProp(_el$77, "gap", 1);
20606
+ setProp(_el$77, "paddingLeft", 1);
20607
+ setProp(_el$77, "paddingRight", 1);
20608
+ setProp(_el$77, "onMouseUp", () => {
20116
20609
  setLevel("body");
20117
20610
  setBodyRow(rowIndex());
20118
20611
  themeCtx.setFocusAccent(slot);
20119
20612
  });
20120
- setProp(_el$70, "wrapMode", "none");
20121
- insert(_el$70, () => isSelected() ? "\u25CF " : " ", null);
20122
- insert(_el$70, () => FOCUS_ACCENT_LABEL[slot], null);
20613
+ setProp(_el$78, "wrapMode", "none");
20614
+ insert(_el$78, () => isSelected() ? "\u25CF " : " ", null);
20615
+ insert(_el$78, () => FOCUS_ACCENT_LABEL[slot], null);
20123
20616
  effect((_p$) => {
20124
- var _v$43 = isCursor() ? theme.primary : undefined, _v$44 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.focusAccent : theme.text, _v$45 = isCursor() || isSelected() ? TextAttributes7.BOLD : undefined;
20125
- _v$43 !== _p$.e && (_p$.e = setProp(_el$69, "backgroundColor", _v$43, _p$.e));
20126
- _v$44 !== _p$.t && (_p$.t = setProp(_el$70, "fg", _v$44, _p$.t));
20127
- _v$45 !== _p$.a && (_p$.a = setProp(_el$70, "attributes", _v$45, _p$.a));
20617
+ var _v$47 = isCursor() ? theme.primary : undefined, _v$48 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.focusAccent : theme.text, _v$49 = isCursor() || isSelected() ? TextAttributes7.BOLD : undefined;
20618
+ _v$47 !== _p$.e && (_p$.e = setProp(_el$77, "backgroundColor", _v$47, _p$.e));
20619
+ _v$48 !== _p$.t && (_p$.t = setProp(_el$78, "fg", _v$48, _p$.t));
20620
+ _v$49 !== _p$.a && (_p$.a = setProp(_el$78, "attributes", _v$49, _p$.a));
20128
20621
  return _p$;
20129
20622
  }, {
20130
20623
  e: undefined,
20131
20624
  t: undefined,
20132
20625
  a: undefined
20133
20626
  });
20134
- return _el$69;
20627
+ return _el$77;
20135
20628
  })();
20136
20629
  }
20137
20630
  }), null);
@@ -20256,48 +20749,48 @@ function SettingsDialog(props) {
20256
20749
  return claudeStatus();
20257
20750
  },
20258
20751
  children: (s2) => (() => {
20259
- var _el$71 = createElement("box"), _el$72 = createElement("text");
20260
- insertNode(_el$71, _el$72);
20261
- setProp(_el$71, "flexDirection", "column");
20262
- setProp(_el$71, "gap", 0);
20263
- setProp(_el$72, "wrapMode", "word");
20264
- insert(_el$72, (() => {
20752
+ var _el$79 = createElement("box"), _el$80 = createElement("text");
20753
+ insertNode(_el$79, _el$80);
20754
+ setProp(_el$79, "flexDirection", "column");
20755
+ setProp(_el$79, "gap", 0);
20756
+ setProp(_el$80, "wrapMode", "word");
20757
+ insert(_el$80, (() => {
20265
20758
  var _c$ = memo2(() => !!s2().binary.found);
20266
20759
  return () => _c$() ? `Binary: ${s2().binary.path}` : `Binary: ${s2().binary.error}`;
20267
20760
  })());
20268
- insert(_el$71, () => {
20761
+ insert(_el$79, () => {
20269
20762
  const a2 = s2().account;
20270
20763
  if (a2.kind === "oauth") {
20271
20764
  const tail = [a2.organization, a2.billingType].filter((x2) => !!x2).join(" \xB7 ");
20272
20765
  return (() => {
20273
- var _el$73 = createElement("text");
20274
- setProp(_el$73, "wrapMode", "word");
20275
- insert(_el$73, () => `\u25CF Logged in: ${a2.email}${tail ? ` (${tail})` : ""}`);
20276
- effect((_$p) => setProp(_el$73, "fg", theme.success, _$p));
20277
- return _el$73;
20766
+ var _el$81 = createElement("text");
20767
+ setProp(_el$81, "wrapMode", "word");
20768
+ insert(_el$81, () => `\u25CF Logged in: ${a2.email}${tail ? ` (${tail})` : ""}`);
20769
+ effect((_$p) => setProp(_el$81, "fg", theme.success, _$p));
20770
+ return _el$81;
20278
20771
  })();
20279
20772
  }
20280
20773
  return (() => {
20281
- var _el$74 = createElement("text");
20282
- insertNode(_el$74, createTextNode(`\u25CB Not logged in`));
20283
- effect((_$p) => setProp(_el$74, "fg", theme.textMuted, _$p));
20284
- return _el$74;
20774
+ var _el$82 = createElement("text");
20775
+ insertNode(_el$82, createTextNode(`\u25CB Not logged in`));
20776
+ effect((_$p) => setProp(_el$82, "fg", theme.textMuted, _$p));
20777
+ return _el$82;
20285
20778
  })();
20286
20779
  }, null);
20287
- insert(_el$71, createComponent2(Show, {
20780
+ insert(_el$79, createComponent2(Show, {
20288
20781
  get when() {
20289
20782
  return s2().accountError;
20290
20783
  },
20291
20784
  children: (err) => (() => {
20292
- var _el$76 = createElement("text");
20293
- setProp(_el$76, "wrapMode", "word");
20294
- insert(_el$76, () => `! ${err()}`);
20295
- effect((_$p) => setProp(_el$76, "fg", theme.warning, _$p));
20296
- return _el$76;
20785
+ var _el$84 = createElement("text");
20786
+ setProp(_el$84, "wrapMode", "word");
20787
+ insert(_el$84, () => `! ${err()}`);
20788
+ effect((_$p) => setProp(_el$84, "fg", theme.warning, _$p));
20789
+ return _el$84;
20297
20790
  })()
20298
20791
  }), null);
20299
- effect((_$p) => setProp(_el$72, "fg", s2().binary.found ? theme.textMuted : theme.warning, _$p));
20300
- return _el$71;
20792
+ effect((_$p) => setProp(_el$80, "fg", s2().binary.found ? theme.textMuted : theme.warning, _$p));
20793
+ return _el$79;
20301
20794
  })()
20302
20795
  }), null);
20303
20796
  insertNode(_el$47, _el$48);
@@ -20320,55 +20813,55 @@ function SettingsDialog(props) {
20320
20813
  return codexStatus();
20321
20814
  },
20322
20815
  children: (s2) => (() => {
20323
- var _el$77 = createElement("box"), _el$78 = createElement("text");
20324
- insertNode(_el$77, _el$78);
20325
- setProp(_el$77, "flexDirection", "column");
20326
- setProp(_el$77, "gap", 0);
20327
- setProp(_el$78, "wrapMode", "word");
20328
- insert(_el$78, (() => {
20816
+ var _el$85 = createElement("box"), _el$86 = createElement("text");
20817
+ insertNode(_el$85, _el$86);
20818
+ setProp(_el$85, "flexDirection", "column");
20819
+ setProp(_el$85, "gap", 0);
20820
+ setProp(_el$86, "wrapMode", "word");
20821
+ insert(_el$86, (() => {
20329
20822
  var _c$2 = memo2(() => !!s2().binary.found);
20330
20823
  return () => _c$2() ? `Binary: ${s2().binary.path}` : `Binary: ${s2().binary.error}`;
20331
20824
  })());
20332
- insert(_el$77, () => {
20825
+ insert(_el$85, () => {
20333
20826
  const a2 = s2().account;
20334
20827
  if (a2.kind === "chatgpt") {
20335
20828
  return (() => {
20336
- var _el$79 = createElement("text");
20337
- setProp(_el$79, "wrapMode", "word");
20338
- insert(_el$79, () => `\u25CF ChatGPT login: ${a2.email}${a2.plan ? ` (${a2.plan})` : ""}`);
20339
- effect((_$p) => setProp(_el$79, "fg", theme.success, _$p));
20340
- return _el$79;
20829
+ var _el$87 = createElement("text");
20830
+ setProp(_el$87, "wrapMode", "word");
20831
+ insert(_el$87, () => `\u25CF ChatGPT login: ${a2.email}${a2.plan ? ` (${a2.plan})` : ""}`);
20832
+ effect((_$p) => setProp(_el$87, "fg", theme.success, _$p));
20833
+ return _el$87;
20341
20834
  })();
20342
20835
  }
20343
20836
  if (a2.kind === "apikey") {
20344
20837
  return (() => {
20345
- var _el$80 = createElement("text");
20346
- insertNode(_el$80, createTextNode(`\u25CF API key configured`));
20347
- effect((_$p) => setProp(_el$80, "fg", theme.success, _$p));
20348
- return _el$80;
20838
+ var _el$88 = createElement("text");
20839
+ insertNode(_el$88, createTextNode(`\u25CF API key configured`));
20840
+ effect((_$p) => setProp(_el$88, "fg", theme.success, _$p));
20841
+ return _el$88;
20349
20842
  })();
20350
20843
  }
20351
20844
  return (() => {
20352
- var _el$82 = createElement("text");
20353
- insertNode(_el$82, createTextNode(`\u25CB Not logged in`));
20354
- effect((_$p) => setProp(_el$82, "fg", theme.textMuted, _$p));
20355
- return _el$82;
20845
+ var _el$90 = createElement("text");
20846
+ insertNode(_el$90, createTextNode(`\u25CB Not logged in`));
20847
+ effect((_$p) => setProp(_el$90, "fg", theme.textMuted, _$p));
20848
+ return _el$90;
20356
20849
  })();
20357
20850
  }, null);
20358
- insert(_el$77, createComponent2(Show, {
20851
+ insert(_el$85, createComponent2(Show, {
20359
20852
  get when() {
20360
20853
  return s2().accountError;
20361
20854
  },
20362
20855
  children: (err) => (() => {
20363
- var _el$84 = createElement("text");
20364
- setProp(_el$84, "wrapMode", "word");
20365
- insert(_el$84, () => `! ${err()}`);
20366
- effect((_$p) => setProp(_el$84, "fg", theme.warning, _$p));
20367
- return _el$84;
20856
+ var _el$92 = createElement("text");
20857
+ setProp(_el$92, "wrapMode", "word");
20858
+ insert(_el$92, () => `! ${err()}`);
20859
+ effect((_$p) => setProp(_el$92, "fg", theme.warning, _$p));
20860
+ return _el$92;
20368
20861
  })()
20369
20862
  }), null);
20370
- effect((_$p) => setProp(_el$78, "fg", s2().binary.found ? theme.textMuted : theme.warning, _$p));
20371
- return _el$77;
20863
+ effect((_$p) => setProp(_el$86, "fg", s2().binary.found ? theme.textMuted : theme.warning, _$p));
20864
+ return _el$85;
20372
20865
  })()
20373
20866
  }), null);
20374
20867
  effect((_p$) => {
@@ -20395,122 +20888,208 @@ function SettingsDialog(props) {
20395
20888
  }), null);
20396
20889
  insert(_el$9, createComponent2(Show, {
20397
20890
  get when() {
20398
- return section() === "dev";
20891
+ return section() === "codex";
20399
20892
  },
20400
20893
  get children() {
20401
- var _el$52 = createElement("box"), _el$53 = createElement("text"), _el$55 = createElement("text");
20894
+ var _el$52 = createElement("box"), _el$53 = createElement("text"), _el$55 = createElement("text"), _el$57 = createElement("text"), _el$59 = createElement("box");
20402
20895
  insertNode(_el$52, _el$53);
20403
20896
  insertNode(_el$52, _el$55);
20897
+ insertNode(_el$52, _el$57);
20898
+ insertNode(_el$52, _el$59);
20404
20899
  setProp(_el$52, "flexDirection", "column");
20405
20900
  setProp(_el$52, "gap", 1);
20406
- insertNode(_el$53, createTextNode(`Reset UI state`));
20407
- insertNode(_el$55, 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.`));
20901
+ insertNode(_el$53, createTextNode(`Codex backend`));
20902
+ insertNode(_el$55, createTextNode(`App server is the default path: kobe talks to \`codex app-server\` over JSON-RPC, so sessions and token usage come from Codex directly. \`exec --json\` starts one Codex process per turn and resumes the saved session id; keep it as a fallback.`));
20408
20903
  setProp(_el$55, "wrapMode", "word");
20409
- insert(_el$52, () => {
20904
+ insert(_el$52, createComponent2(Show, {
20905
+ get when() {
20906
+ return codexEnvOverride();
20907
+ },
20908
+ children: (override) => (() => {
20909
+ var _el$93 = createElement("text");
20910
+ setProp(_el$93, "wrapMode", "word");
20911
+ insert(_el$93, () => `Environment override is active: ${override()}. Unset KOBE_CODEX_BACKEND / KOBE_CODEX_APP_SERVER before the saved setting is used.`);
20912
+ effect((_$p) => setProp(_el$93, "fg", theme.warning, _$p));
20913
+ return _el$93;
20914
+ })()
20915
+ }), _el$57);
20916
+ insertNode(_el$57, createTextNode(`Changing this setting applies after Restart backend or the next kobe launch.`));
20917
+ setProp(_el$57, "wrapMode", "word");
20918
+ setProp(_el$59, "flexDirection", "column");
20919
+ setProp(_el$59, "gap", 0);
20920
+ insert(_el$59, createComponent2(For, {
20921
+ each: CODEX_BACKENDS,
20922
+ children: (backend, i2) => {
20923
+ const isCursor = () => level() === "body" && bodyRow() === i2();
20924
+ const isSelected = () => codexBackend() === backend;
20925
+ return (() => {
20926
+ var _el$94 = createElement("box"), _el$95 = createElement("text"), _el$96 = createElement("text");
20927
+ insertNode(_el$94, _el$95);
20928
+ insertNode(_el$94, _el$96);
20929
+ setProp(_el$94, "flexDirection", "column");
20930
+ setProp(_el$94, "paddingLeft", 1);
20931
+ setProp(_el$94, "paddingRight", 1);
20932
+ setProp(_el$94, "onMouseUp", () => {
20933
+ setLevel("body");
20934
+ setBodyRow(i2());
20935
+ setCodexBackend(backend);
20936
+ });
20937
+ setProp(_el$95, "wrapMode", "none");
20938
+ insert(_el$95, () => isSelected() ? "\u25CF " : " ", null);
20939
+ insert(_el$95, () => CODEX_BACKEND_LABEL[backend], null);
20940
+ setProp(_el$96, "wrapMode", "word");
20941
+ insert(_el$96, () => CODEX_BACKEND_DESCRIPTION[backend]);
20942
+ effect((_p$) => {
20943
+ var _v$50 = isCursor() ? theme.primary : undefined, _v$51 = isCursor() ? theme.selectedListItemText : isSelected() ? theme.accent : theme.text, _v$52 = isCursor() || isSelected() ? TextAttributes7.BOLD : undefined, _v$53 = isCursor() ? theme.selectedListItemText : theme.textMuted;
20944
+ _v$50 !== _p$.e && (_p$.e = setProp(_el$94, "backgroundColor", _v$50, _p$.e));
20945
+ _v$51 !== _p$.t && (_p$.t = setProp(_el$95, "fg", _v$51, _p$.t));
20946
+ _v$52 !== _p$.a && (_p$.a = setProp(_el$95, "attributes", _v$52, _p$.a));
20947
+ _v$53 !== _p$.o && (_p$.o = setProp(_el$96, "fg", _v$53, _p$.o));
20948
+ return _p$;
20949
+ }, {
20950
+ e: undefined,
20951
+ t: undefined,
20952
+ a: undefined,
20953
+ o: undefined
20954
+ });
20955
+ return _el$94;
20956
+ })();
20957
+ }
20958
+ }));
20959
+ effect((_p$) => {
20960
+ var _v$27 = theme.text, _v$28 = TextAttributes7.BOLD, _v$29 = theme.textMuted, _v$30 = theme.textMuted;
20961
+ _v$27 !== _p$.e && (_p$.e = setProp(_el$53, "fg", _v$27, _p$.e));
20962
+ _v$28 !== _p$.t && (_p$.t = setProp(_el$53, "attributes", _v$28, _p$.t));
20963
+ _v$29 !== _p$.a && (_p$.a = setProp(_el$55, "fg", _v$29, _p$.a));
20964
+ _v$30 !== _p$.o && (_p$.o = setProp(_el$57, "fg", _v$30, _p$.o));
20965
+ return _p$;
20966
+ }, {
20967
+ e: undefined,
20968
+ t: undefined,
20969
+ a: undefined,
20970
+ o: undefined
20971
+ });
20972
+ return _el$52;
20973
+ }
20974
+ }), null);
20975
+ insert(_el$9, createComponent2(Show, {
20976
+ get when() {
20977
+ return section() === "dev";
20978
+ },
20979
+ get children() {
20980
+ var _el$60 = createElement("box"), _el$61 = createElement("text"), _el$63 = createElement("text");
20981
+ insertNode(_el$60, _el$61);
20982
+ insertNode(_el$60, _el$63);
20983
+ setProp(_el$60, "flexDirection", "column");
20984
+ setProp(_el$60, "gap", 1);
20985
+ insertNode(_el$61, createTextNode(`Reset UI state`));
20986
+ insertNode(_el$63, 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.`));
20987
+ setProp(_el$63, "wrapMode", "word");
20988
+ insert(_el$60, () => {
20410
20989
  const isCursor = () => level() === "body" && bodyRow() === 0;
20411
20990
  return (() => {
20412
- var _el$85 = createElement("box"), _el$86 = createElement("text");
20413
- insertNode(_el$85, _el$86);
20414
- setProp(_el$85, "flexDirection", "row");
20415
- setProp(_el$85, "paddingLeft", 1);
20416
- setProp(_el$85, "paddingRight", 1);
20417
- setProp(_el$85, "onMouseUp", () => {
20991
+ var _el$97 = createElement("box"), _el$98 = createElement("text");
20992
+ insertNode(_el$97, _el$98);
20993
+ setProp(_el$97, "flexDirection", "row");
20994
+ setProp(_el$97, "paddingLeft", 1);
20995
+ setProp(_el$97, "paddingRight", 1);
20996
+ setProp(_el$97, "onMouseUp", () => {
20418
20997
  setLevel("body");
20419
20998
  setBodyRow(0);
20420
20999
  confirmReset();
20421
21000
  });
20422
- insertNode(_el$86, createTextNode(`[enter] Reset`));
21001
+ insertNode(_el$98, createTextNode(`[enter] Reset`));
20423
21002
  effect((_p$) => {
20424
- var _v$46 = isCursor() ? theme.primary : theme.backgroundElement, _v$47 = isCursor() ? theme.selectedListItemText : theme.warning, _v$48 = TextAttributes7.BOLD;
20425
- _v$46 !== _p$.e && (_p$.e = setProp(_el$85, "backgroundColor", _v$46, _p$.e));
20426
- _v$47 !== _p$.t && (_p$.t = setProp(_el$86, "fg", _v$47, _p$.t));
20427
- _v$48 !== _p$.a && (_p$.a = setProp(_el$86, "attributes", _v$48, _p$.a));
21003
+ var _v$54 = isCursor() ? theme.primary : theme.backgroundElement, _v$55 = isCursor() ? theme.selectedListItemText : theme.warning, _v$56 = TextAttributes7.BOLD;
21004
+ _v$54 !== _p$.e && (_p$.e = setProp(_el$97, "backgroundColor", _v$54, _p$.e));
21005
+ _v$55 !== _p$.t && (_p$.t = setProp(_el$98, "fg", _v$55, _p$.t));
21006
+ _v$56 !== _p$.a && (_p$.a = setProp(_el$98, "attributes", _v$56, _p$.a));
20428
21007
  return _p$;
20429
21008
  }, {
20430
21009
  e: undefined,
20431
21010
  t: undefined,
20432
21011
  a: undefined
20433
21012
  });
20434
- return _el$85;
21013
+ return _el$97;
20435
21014
  })();
20436
21015
  }, null);
20437
- insert(_el$52, createComponent2(Show, {
21016
+ insert(_el$60, createComponent2(Show, {
20438
21017
  when: hasDaemon,
20439
21018
  get children() {
20440
- var _el$57 = createElement("box"), _el$58 = createElement("text"), _el$60 = createElement("text");
20441
- insertNode(_el$57, _el$58);
20442
- insertNode(_el$57, _el$60);
20443
- setProp(_el$57, "flexDirection", "column");
20444
- setProp(_el$57, "gap", 0);
20445
- setProp(_el$57, "paddingTop", 1);
20446
- insertNode(_el$58, createTextNode(`Restart backend`));
20447
- insertNode(_el$60, 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.`));
20448
- setProp(_el$60, "wrapMode", "word");
20449
- insert(_el$57, () => {
21019
+ var _el$65 = createElement("box"), _el$66 = createElement("text"), _el$68 = createElement("text");
21020
+ insertNode(_el$65, _el$66);
21021
+ insertNode(_el$65, _el$68);
21022
+ setProp(_el$65, "flexDirection", "column");
21023
+ setProp(_el$65, "gap", 0);
21024
+ setProp(_el$65, "paddingTop", 1);
21025
+ insertNode(_el$66, createTextNode(`Restart backend`));
21026
+ insertNode(_el$68, 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.`));
21027
+ setProp(_el$68, "wrapMode", "word");
21028
+ insert(_el$65, () => {
20450
21029
  const isCursor = () => level() === "body" && bodyRow() === 1;
20451
21030
  return (() => {
20452
- var _el$88 = createElement("box"), _el$89 = createElement("text");
20453
- insertNode(_el$88, _el$89);
20454
- setProp(_el$88, "flexDirection", "row");
20455
- setProp(_el$88, "paddingLeft", 1);
20456
- setProp(_el$88, "paddingRight", 1);
20457
- setProp(_el$88, "onMouseUp", () => {
21031
+ var _el$100 = createElement("box"), _el$101 = createElement("text");
21032
+ insertNode(_el$100, _el$101);
21033
+ setProp(_el$100, "flexDirection", "row");
21034
+ setProp(_el$100, "paddingLeft", 1);
21035
+ setProp(_el$100, "paddingRight", 1);
21036
+ setProp(_el$100, "onMouseUp", () => {
20458
21037
  setLevel("body");
20459
21038
  setBodyRow(1);
20460
21039
  confirmRestartDaemon();
20461
21040
  });
20462
- insertNode(_el$89, createTextNode(`[enter] Restart`));
21041
+ insertNode(_el$101, createTextNode(`[enter] Restart`));
20463
21042
  effect((_p$) => {
20464
- var _v$49 = isCursor() ? theme.primary : theme.backgroundElement, _v$50 = isCursor() ? theme.selectedListItemText : theme.accent, _v$51 = TextAttributes7.BOLD;
20465
- _v$49 !== _p$.e && (_p$.e = setProp(_el$88, "backgroundColor", _v$49, _p$.e));
20466
- _v$50 !== _p$.t && (_p$.t = setProp(_el$89, "fg", _v$50, _p$.t));
20467
- _v$51 !== _p$.a && (_p$.a = setProp(_el$89, "attributes", _v$51, _p$.a));
21043
+ var _v$57 = isCursor() ? theme.primary : theme.backgroundElement, _v$58 = isCursor() ? theme.selectedListItemText : theme.accent, _v$59 = TextAttributes7.BOLD;
21044
+ _v$57 !== _p$.e && (_p$.e = setProp(_el$100, "backgroundColor", _v$57, _p$.e));
21045
+ _v$58 !== _p$.t && (_p$.t = setProp(_el$101, "fg", _v$58, _p$.t));
21046
+ _v$59 !== _p$.a && (_p$.a = setProp(_el$101, "attributes", _v$59, _p$.a));
20468
21047
  return _p$;
20469
21048
  }, {
20470
21049
  e: undefined,
20471
21050
  t: undefined,
20472
21051
  a: undefined
20473
21052
  });
20474
- return _el$88;
21053
+ return _el$100;
20475
21054
  })();
20476
21055
  }, null);
20477
21056
  effect((_p$) => {
20478
- var _v$27 = theme.text, _v$28 = TextAttributes7.BOLD, _v$29 = theme.textMuted;
20479
- _v$27 !== _p$.e && (_p$.e = setProp(_el$58, "fg", _v$27, _p$.e));
20480
- _v$28 !== _p$.t && (_p$.t = setProp(_el$58, "attributes", _v$28, _p$.t));
20481
- _v$29 !== _p$.a && (_p$.a = setProp(_el$60, "fg", _v$29, _p$.a));
21057
+ var _v$31 = theme.text, _v$32 = TextAttributes7.BOLD, _v$33 = theme.textMuted;
21058
+ _v$31 !== _p$.e && (_p$.e = setProp(_el$66, "fg", _v$31, _p$.e));
21059
+ _v$32 !== _p$.t && (_p$.t = setProp(_el$66, "attributes", _v$32, _p$.t));
21060
+ _v$33 !== _p$.a && (_p$.a = setProp(_el$68, "fg", _v$33, _p$.a));
20482
21061
  return _p$;
20483
21062
  }, {
20484
21063
  e: undefined,
20485
21064
  t: undefined,
20486
21065
  a: undefined
20487
21066
  });
20488
- return _el$57;
21067
+ return _el$65;
20489
21068
  }
20490
21069
  }), null);
20491
21070
  effect((_p$) => {
20492
- var _v$30 = theme.text, _v$31 = TextAttributes7.BOLD, _v$32 = theme.textMuted;
20493
- _v$30 !== _p$.e && (_p$.e = setProp(_el$53, "fg", _v$30, _p$.e));
20494
- _v$31 !== _p$.t && (_p$.t = setProp(_el$53, "attributes", _v$31, _p$.t));
20495
- _v$32 !== _p$.a && (_p$.a = setProp(_el$55, "fg", _v$32, _p$.a));
21071
+ var _v$34 = theme.text, _v$35 = TextAttributes7.BOLD, _v$36 = theme.textMuted;
21072
+ _v$34 !== _p$.e && (_p$.e = setProp(_el$61, "fg", _v$34, _p$.e));
21073
+ _v$35 !== _p$.t && (_p$.t = setProp(_el$61, "attributes", _v$35, _p$.t));
21074
+ _v$36 !== _p$.a && (_p$.a = setProp(_el$63, "fg", _v$36, _p$.a));
20496
21075
  return _p$;
20497
21076
  }, {
20498
21077
  e: undefined,
20499
21078
  t: undefined,
20500
21079
  a: undefined
20501
21080
  });
20502
- return _el$52;
21081
+ return _el$60;
20503
21082
  }
20504
21083
  }), null);
20505
- insertNode(_el$62, _el$63);
20506
- setProp(_el$62, "paddingTop", 0);
20507
- insertNode(_el$63, createTextNode(`j/k pick \xB7 h/l switch level \xB7 enter activate \xB7 esc close`));
21084
+ insertNode(_el$70, _el$71);
21085
+ setProp(_el$70, "paddingTop", 0);
21086
+ insertNode(_el$71, createTextNode(`j/k pick \xB7 h/l switch level \xB7 enter activate \xB7 esc close`));
20508
21087
  effect((_p$) => {
20509
- var _v$33 = TextAttributes7.BOLD, _v$34 = theme.text, _v$35 = theme.textMuted, _v$36 = theme.textMuted;
20510
- _v$33 !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$33, _p$.e));
20511
- _v$34 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$34, _p$.t));
20512
- _v$35 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$35, _p$.a));
20513
- _v$36 !== _p$.o && (_p$.o = setProp(_el$63, "fg", _v$36, _p$.o));
21088
+ var _v$37 = TextAttributes7.BOLD, _v$38 = theme.text, _v$39 = theme.textMuted, _v$40 = theme.textMuted;
21089
+ _v$37 !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$37, _p$.e));
21090
+ _v$38 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$38, _p$.t));
21091
+ _v$39 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$39, _p$.a));
21092
+ _v$40 !== _p$.o && (_p$.o = setProp(_el$71, "fg", _v$40, _p$.o));
20514
21093
  return _p$;
20515
21094
  }, {
20516
21095
  e: undefined,
@@ -20521,7 +21100,7 @@ function SettingsDialog(props) {
20521
21100
  return _el$;
20522
21101
  })();
20523
21102
  }
20524
- var FOCUS_ACCENT_LABEL, SECTIONS;
21103
+ var FOCUS_ACCENT_LABEL, CODEX_BACKENDS, CODEX_BACKEND_LABEL, CODEX_BACKEND_DESCRIPTION, SECTIONS;
20525
21104
  var init_settings_dialog = __esm(() => {
20526
21105
  init_solid();
20527
21106
  init_solid();
@@ -20535,6 +21114,7 @@ var init_settings_dialog = __esm(() => {
20535
21114
  init_dev();
20536
21115
  init_remote_orchestrator();
20537
21116
  init_account_detect();
21117
+ init_app_server();
20538
21118
  init_env();
20539
21119
  init_theme();
20540
21120
  init_keymap();
@@ -20545,12 +21125,24 @@ var init_settings_dialog = __esm(() => {
20545
21125
  success: "Success (legacy green)",
20546
21126
  info: "Info (cool blue)"
20547
21127
  };
21128
+ CODEX_BACKENDS = ["app-server", "exec"];
21129
+ CODEX_BACKEND_LABEL = {
21130
+ "app-server": "App server (default)",
21131
+ exec: "exec --json"
21132
+ };
21133
+ CODEX_BACKEND_DESCRIPTION = {
21134
+ "app-server": "Codex app-server JSON-RPC; keeps official thread/session state and token usage.",
21135
+ exec: "Fallback path; starts codex exec --json for each turn and resumes the saved session id."
21136
+ };
20548
21137
  SECTIONS = [{
20549
21138
  id: "general",
20550
21139
  label: "General"
20551
21140
  }, {
20552
21141
  id: "accounts",
20553
21142
  label: "Accounts"
21143
+ }, {
21144
+ id: "codex",
21145
+ label: "Codex"
20554
21146
  }, {
20555
21147
  id: "dev",
20556
21148
  label: "Dev"
@@ -20607,12 +21199,16 @@ function useAppKeymap(deps) {
20607
21199
  "app.quit": () => {
20608
21200
  DialogConfirm.show(dialog, "Quit kobe?", "Any in-progress tasks will be detached.", "stay").then((ok) => {
20609
21201
  if (ok === true) {
20610
- try {
20611
- deps.renderer?.destroy();
20612
- } catch (err) {
20613
- console.error("kobe: renderer.destroy() failed during quit:", err);
21202
+ if (deps.onQuit)
21203
+ deps.onQuit();
21204
+ else {
21205
+ try {
21206
+ deps.renderer?.destroy();
21207
+ } catch (err) {
21208
+ console.error("kobe: renderer.destroy() failed during quit:", err);
21209
+ }
21210
+ process.exit(0);
20614
21211
  }
20615
- process.exit(0);
20616
21212
  }
20617
21213
  });
20618
21214
  }
@@ -20733,12 +21329,12 @@ var init_sound = __esm(() => {
20733
21329
  });
20734
21330
 
20735
21331
  // src/tui/context/kv.tsx
20736
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
20737
- import { homedir as homedir10 } from "os";
21332
+ import { mkdirSync as mkdirSync4, readFileSync as readFileSync8, renameSync as renameSync2, writeFileSync as writeFileSync3 } from "fs";
21333
+ import { homedir as homedir11 } from "os";
20738
21334
  import { dirname as dirname4, join as join12 } from "path";
20739
21335
  function loadInitial() {
20740
21336
  try {
20741
- const text = readFileSync7(STATE_PATH, "utf8");
21337
+ const text = readFileSync8(STATE_PATH, "utf8");
20742
21338
  const parsed = JSON.parse(text);
20743
21339
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
20744
21340
  return parsed;
@@ -20750,7 +21346,7 @@ var STATE_PATH, WRITE_DEBOUNCE_MS = 250, useKV, KVProvider;
20750
21346
  var init_kv = __esm(() => {
20751
21347
  init_dev2();
20752
21348
  init_helper();
20753
- STATE_PATH = join12(homedir10(), ".config", "kobe", "state.json");
21349
+ STATE_PATH = join12(homedir11(), ".config", "kobe", "state.json");
20754
21350
  ({
20755
21351
  use: useKV,
20756
21352
  provider: KVProvider
@@ -22324,7 +22920,7 @@ var init_create_pr_button = __esm(() => {
22324
22920
  });
22325
22921
 
22326
22922
  // src/tui/lib/worktree-opener.ts
22327
- import { spawn as spawn5 } from "child_process";
22923
+ import { spawn as spawn6 } from "child_process";
22328
22924
  import { existsSync as existsSync7 } from "fs";
22329
22925
  import { basename as basename4, delimiter, isAbsolute as isAbsolute2, join as join13 } from "path";
22330
22926
  function executableOnPath(command, env, exists) {
@@ -22383,7 +22979,7 @@ function buildOpenWorktreeCommand(worktreePath, opener) {
22383
22979
  function openWorktree(worktreePath, opener, deps = {}) {
22384
22980
  if (!worktreePath)
22385
22981
  return false;
22386
- const spawnFn = deps.spawn ?? spawn5;
22982
+ const spawnFn = deps.spawn ?? spawn6;
22387
22983
  const [command, args2] = buildOpenWorktreeCommand(worktreePath, opener);
22388
22984
  try {
22389
22985
  const child = spawnFn(command, args2, { detached: true, stdio: "ignore" });
@@ -23745,6 +24341,8 @@ var init_sync = __esm(() => {
23745
24341
 
23746
24342
  // src/session/usage-metrics.ts
23747
24343
  function totalContextTokens(u2) {
24344
+ if (typeof u2.context_tokens === "number" && Number.isFinite(u2.context_tokens))
24345
+ return Math.max(0, u2.context_tokens);
23748
24346
  return u2.input_tokens + (u2.cache_read_input_tokens ?? 0) + (u2.cache_creation_input_tokens ?? 0);
23749
24347
  }
23750
24348
  function parseTimestampMs(value) {
@@ -23871,8 +24469,8 @@ function normalizeClaudeContent(content) {
23871
24469
 
23872
24470
  // src/engine/claude-code-local/history.ts
23873
24471
  import { randomUUID } from "crypto";
23874
- import { appendFile, mkdir as mkdir2, readFile as readFile3, readdir, unlink as unlink2, writeFile as writeFile2 } from "fs/promises";
23875
- import { homedir as homedir11 } from "os";
24472
+ import { appendFile, mkdir as mkdir2, readFile as readFile3, readdir, unlink as unlink3, writeFile as writeFile2 } from "fs/promises";
24473
+ import { homedir as homedir12 } from "os";
23876
24474
  import path9 from "path";
23877
24475
  function encodeCwd(cwd) {
23878
24476
  return cwd.replace(/[/.]/g, "-");
@@ -23898,7 +24496,7 @@ async function deleteHistory(sessionId, deps = defaultDeps4) {
23898
24496
  for (const dir of projectDirs) {
23899
24497
  const candidate = path9.join(root, dir, `${sessionId}.jsonl`);
23900
24498
  try {
23901
- await unlink2(candidate);
24499
+ await unlink3(candidate);
23902
24500
  } catch (err) {
23903
24501
  if (err.code === "ENOENT")
23904
24502
  continue;
@@ -24042,7 +24640,7 @@ var defaultDeps4;
24042
24640
  var init_history = __esm(() => {
24043
24641
  defaultDeps4 = {
24044
24642
  projectsDir() {
24045
- return path9.join(homedir11(), ".claude", "projects");
24643
+ return path9.join(homedir12(), ".claude", "projects");
24046
24644
  },
24047
24645
  async readdir(p2) {
24048
24646
  try {
@@ -24131,7 +24729,7 @@ function delay(ms) {
24131
24729
 
24132
24730
  // src/engine/claude-code-local/sessions.ts
24133
24731
  import { readFile as readFile4, readdir as readdir2, stat as stat2 } from "fs/promises";
24134
- import { homedir as homedir12 } from "os";
24732
+ import { homedir as homedir13 } from "os";
24135
24733
  import path10 from "path";
24136
24734
  async function listSessionsForCwd(cwd, deps = defaultDeps5) {
24137
24735
  const projectDir = path10.join(deps.projectsDir(), encodeCwd(cwd));
@@ -24199,7 +24797,7 @@ var init_sessions = __esm(() => {
24199
24797
  init_history();
24200
24798
  defaultDeps5 = {
24201
24799
  projectsDir() {
24202
- return path10.join(homedir12(), ".claude", "projects");
24800
+ return path10.join(homedir13(), ".claude", "projects");
24203
24801
  },
24204
24802
  async readdir(p2) {
24205
24803
  try {
@@ -24219,10 +24817,10 @@ var init_sessions = __esm(() => {
24219
24817
  });
24220
24818
 
24221
24819
  // src/engine/claude-code-local/spawn.ts
24222
- import { spawn as spawn6 } from "child_process";
24820
+ import { spawn as spawn7 } from "child_process";
24223
24821
  function spawnClaudeProcess(opts) {
24224
24822
  const args2 = buildArgs(opts);
24225
- const proc = spawn6(opts.binaryPath, args2, {
24823
+ const proc = spawn7(opts.binaryPath, args2, {
24226
24824
  cwd: opts.cwd,
24227
24825
  env: { ...process.env, ...opts.env ?? {} },
24228
24826
  stdio: ["pipe", "pipe", "pipe"]
@@ -24273,7 +24871,7 @@ async function* parseStreamJson(lines, opts = {}) {
24273
24871
  try {
24274
24872
  msg = JSON.parse(line);
24275
24873
  } catch (err) {
24276
- yield { type: "error", message: `stream-json parse failed: ${stringifyErr(err)}` };
24874
+ yield { type: "error", message: `stream-json parse failed: ${stringifyErr2(err)}` };
24277
24875
  continue;
24278
24876
  }
24279
24877
  if (!isObject3(msg))
@@ -24390,7 +24988,7 @@ function extractContentBlocks(msg) {
24390
24988
  return inner.content;
24391
24989
  return [];
24392
24990
  }
24393
- function stringifyErr(err) {
24991
+ function stringifyErr2(err) {
24394
24992
  if (err instanceof Error)
24395
24993
  return err.message;
24396
24994
  try {
@@ -24664,9 +25262,31 @@ function isInstructionsEnvelope(text) {
24664
25262
  }
24665
25263
  var init_synthetic = () => {};
24666
25264
 
25265
+ // src/engine/codex-local/usage.ts
25266
+ function codexUsageToSnapshot(usage, opts = {}) {
25267
+ const totalInput = numberOr2(usage.input_tokens, 0);
25268
+ const cachedInput = numberOr2(usage.cached_input_tokens, 0);
25269
+ const output = numberOr2(usage.output_tokens, 0);
25270
+ const nonCachedInput = Math.max(0, totalInput - cachedInput);
25271
+ if (totalInput <= 0 && output <= 0 && cachedInput <= 0)
25272
+ return;
25273
+ return {
25274
+ input_tokens: nonCachedInput,
25275
+ output_tokens: output,
25276
+ ...cachedInput > 0 ? { cache_read_input_tokens: cachedInput } : {},
25277
+ ...validPositive(opts.contextWindowTokens) ? { context_window_tokens: opts.contextWindowTokens } : {}
25278
+ };
25279
+ }
25280
+ function numberOr2(v2, fallback) {
25281
+ return typeof v2 === "number" && Number.isFinite(v2) ? v2 : fallback;
25282
+ }
25283
+ function validPositive(v2) {
25284
+ return typeof v2 === "number" && Number.isFinite(v2) && v2 > 0;
25285
+ }
25286
+
24667
25287
  // src/engine/codex-local/history.ts
24668
- import { readFile as readFile5, readdir as readdir3, unlink as unlink3 } from "fs/promises";
24669
- import { homedir as homedir13 } from "os";
25288
+ import { readFile as readFile5, readdir as readdir3, unlink as unlink4 } from "fs/promises";
25289
+ import { homedir as homedir14 } from "os";
24670
25290
  import path11 from "path";
24671
25291
  async function listRolloutFiles(deps = defaultDeps6) {
24672
25292
  const root = deps.sessionsDir();
@@ -24716,7 +25336,7 @@ async function deleteHistory2(sessionId, deps = defaultDeps6) {
24716
25336
  if (!file)
24717
25337
  return;
24718
25338
  try {
24719
- await unlink3(file);
25339
+ await unlink4(file);
24720
25340
  } catch (err) {
24721
25341
  if (err.code === "ENOENT")
24722
25342
  return;
@@ -24768,10 +25388,6 @@ function parseJsonl2(raw, sessionId) {
24768
25388
  function deriveCodexUsageMetrics(raw) {
24769
25389
  let latestUsage;
24770
25390
  let latestUsageTimestampMs = null;
24771
- let lastUserTimestampMs = null;
24772
- let inputTokens = 0;
24773
- let outputTokens = 0;
24774
- const intervals = [];
24775
25391
  for (const line of raw.split(`
24776
25392
  `)) {
24777
25393
  const trimmed = line.trim();
@@ -24786,15 +25402,8 @@ function deriveCodexUsageMetrics(raw) {
24786
25402
  if (!isObject5(parsed))
24787
25403
  continue;
24788
25404
  const timestampMs = typeof parsed.timestamp === "string" ? parseTimestampMs2(parsed.timestamp) : null;
24789
- if (parsed.type === "response_item") {
24790
- const payload = isObject5(parsed.payload) ? parsed.payload : undefined;
24791
- if (payload?.type === "message" && payload.role === "user" && timestampMs !== null) {
24792
- const blocks = normalizeCodexContent(payload.content);
24793
- if (!isSyntheticCodexUserRow(blocks))
24794
- lastUserTimestampMs = timestampMs;
24795
- }
25405
+ if (parsed.type === "response_item")
24796
25406
  continue;
24797
- }
24798
25407
  if (parsed.type !== "turn.completed")
24799
25408
  continue;
24800
25409
  const usage = isObject5(parsed.usage) ? parsed.usage : undefined;
@@ -24809,63 +25418,13 @@ function deriveCodexUsageMetrics(raw) {
24809
25418
  } else if (latestUsage === undefined) {
24810
25419
  latestUsage = snapshot;
24811
25420
  }
24812
- inputTokens += snapshot.input_tokens;
24813
- outputTokens += snapshot.output_tokens;
24814
- if (timestampMs !== null && lastUserTimestampMs !== null && timestampMs > lastUserTimestampMs) {
24815
- intervals.push({ startMs: lastUserTimestampMs, endMs: timestampMs });
24816
- }
24817
25421
  }
24818
- if (!latestUsage)
24819
- return;
24820
- const durationMs2 = mergedDurationMs(intervals);
24821
- if (durationMs2 <= 0)
24822
- return latestUsage;
24823
- return {
24824
- ...latestUsage,
24825
- total_speed_tokens_per_second: (inputTokens + outputTokens) / (durationMs2 / 1000)
24826
- };
24827
- }
24828
- function codexUsageToSnapshot(usage) {
24829
- const input = numberOr(usage.input_tokens, 0);
24830
- const output = numberOr(usage.output_tokens, 0) + numberOr(usage.reasoning_output_tokens, 0);
24831
- const cacheRead = typeof usage.cached_input_tokens === "number" ? usage.cached_input_tokens : undefined;
24832
- if (input <= 0 && output <= 0 && cacheRead === undefined)
24833
- return;
24834
- return {
24835
- input_tokens: input,
24836
- output_tokens: output,
24837
- ...cacheRead !== undefined ? { cache_read_input_tokens: cacheRead } : {}
24838
- };
25422
+ return latestUsage;
24839
25423
  }
24840
25424
  function parseTimestampMs2(value) {
24841
25425
  const ms = new Date(value).getTime();
24842
25426
  return Number.isFinite(ms) ? ms : null;
24843
25427
  }
24844
- function mergedDurationMs(intervals) {
24845
- if (intervals.length === 0)
24846
- return 0;
24847
- const sorted = [...intervals].sort((a2, b2) => a2.startMs - b2.startMs);
24848
- let total = 0;
24849
- let current = sorted[0];
24850
- if (!current)
24851
- return 0;
24852
- for (let i2 = 1;i2 < sorted.length; i2++) {
24853
- const next = sorted[i2];
24854
- if (!next)
24855
- continue;
24856
- if (next.startMs <= current.endMs) {
24857
- current = { startMs: current.startMs, endMs: Math.max(current.endMs, next.endMs) };
24858
- } else {
24859
- total += current.endMs - current.startMs;
24860
- current = next;
24861
- }
24862
- }
24863
- total += current.endMs - current.startMs;
24864
- return total;
24865
- }
24866
- function numberOr(v2, fallback) {
24867
- return typeof v2 === "number" && Number.isFinite(v2) ? v2 : fallback;
24868
- }
24869
25428
  function isObject5(v2) {
24870
25429
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
24871
25430
  }
@@ -24874,7 +25433,7 @@ var init_history2 = __esm(() => {
24874
25433
  init_synthetic();
24875
25434
  defaultDeps6 = {
24876
25435
  sessionsDir() {
24877
- return path11.join(homedir13(), ".codex", "sessions");
25436
+ return path11.join(homedir14(), ".codex", "sessions");
24878
25437
  },
24879
25438
  async readdir(p2) {
24880
25439
  try {
@@ -24889,6 +25448,52 @@ var init_history2 = __esm(() => {
24889
25448
  };
24890
25449
  });
24891
25450
 
25451
+ // src/engine/codex-local/openrouter.ts
25452
+ async function resolveOpenRouterContextWindow(modelId) {
25453
+ const id = openRouterModelId(modelId);
25454
+ if (!id)
25455
+ return;
25456
+ const models = await loadOpenRouterModels();
25457
+ return models.get(id)?.contextLength;
25458
+ }
25459
+ function openRouterModelId(modelId) {
25460
+ const id = modelId?.trim();
25461
+ if (!id)
25462
+ return null;
25463
+ return id.includes("/") ? id : `openai/${id}`;
25464
+ }
25465
+ async function loadOpenRouterModels() {
25466
+ cachePromise ??= fetchOpenRouterModels().catch(() => new Map);
25467
+ return cachePromise;
25468
+ }
25469
+ async function fetchOpenRouterModels() {
25470
+ const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS2);
25471
+ const res = await fetch(MODELS_URL, {
25472
+ signal,
25473
+ headers: { "user-agent": "kobe-codex-openrouter-context" }
25474
+ });
25475
+ if (!res.ok)
25476
+ return new Map;
25477
+ const body = await res.json();
25478
+ if (!isObject6(body) || !Array.isArray(body.data))
25479
+ return new Map;
25480
+ const out = new Map;
25481
+ for (const item of body.data) {
25482
+ if (!isObject6(item))
25483
+ continue;
25484
+ const id = typeof item.id === "string" ? item.id : undefined;
25485
+ const contextLength = typeof item.context_length === "number" ? item.context_length : undefined;
25486
+ if (!id || !contextLength || !Number.isFinite(contextLength) || contextLength <= 0)
25487
+ continue;
25488
+ out.set(id, { id, contextLength });
25489
+ }
25490
+ return out;
25491
+ }
25492
+ function isObject6(v2) {
25493
+ return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
25494
+ }
25495
+ var MODELS_URL = "https://openrouter.ai/api/v1/models", FETCH_TIMEOUT_MS2 = 2500, cachePromise;
25496
+
24892
25497
  // src/engine/codex-local/sessions.ts
24893
25498
  import { open as open3, stat as stat3 } from "fs/promises";
24894
25499
  async function listSessionsForCwd2(cwd, deps) {
@@ -24932,7 +25537,7 @@ async function tryReadMeta(file) {
24932
25537
  return;
24933
25538
  if (parsed.type === "session_meta") {
24934
25539
  const payload = parsed.payload;
24935
- if (isObject6(payload)) {
25540
+ if (isObject7(payload)) {
24936
25541
  if (typeof payload.id === "string")
24937
25542
  sessionId = payload.id;
24938
25543
  if (typeof payload.cwd === "string")
@@ -24940,7 +25545,7 @@ async function tryReadMeta(file) {
24940
25545
  }
24941
25546
  return;
24942
25547
  }
24943
- if (parsed.type === "response_item" && isObject6(parsed.payload)) {
25548
+ if (parsed.type === "response_item" && isObject7(parsed.payload)) {
24944
25549
  const p2 = parsed.payload;
24945
25550
  if (p2.type === "message") {
24946
25551
  messageCount++;
@@ -24986,12 +25591,12 @@ function safeParse(line) {
24986
25591
  return null;
24987
25592
  try {
24988
25593
  const v2 = JSON.parse(t2);
24989
- return isObject6(v2) ? v2 : null;
25594
+ return isObject7(v2) ? v2 : null;
24990
25595
  } catch {
24991
25596
  return null;
24992
25597
  }
24993
25598
  }
24994
- function isObject6(v2) {
25599
+ function isObject7(v2) {
24995
25600
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
24996
25601
  }
24997
25602
  var PREVIEW_CHAR_CAP = 200;
@@ -25001,10 +25606,10 @@ var init_sessions2 = __esm(() => {
25001
25606
  });
25002
25607
 
25003
25608
  // src/engine/codex-local/spawn.ts
25004
- import { spawn as spawn7 } from "child_process";
25609
+ import { spawn as spawn8 } from "child_process";
25005
25610
  function spawnCodexProcess(opts) {
25006
25611
  const args2 = buildArgs2(opts);
25007
- const proc = spawn7(opts.binaryPath, args2, {
25612
+ const proc = spawn8(opts.binaryPath, args2, {
25008
25613
  cwd: opts.cwd,
25009
25614
  env: { ...process.env, ...opts.env ?? {} },
25010
25615
  stdio: ["pipe", "pipe", "pipe"]
@@ -25061,10 +25666,10 @@ async function* parseStreamJson2(lines, opts = {}) {
25061
25666
  try {
25062
25667
  msg = JSON.parse(line);
25063
25668
  } catch (err) {
25064
- yield { type: "error", message: `codex stream-json parse failed: ${stringifyErr2(err)}` };
25669
+ yield { type: "error", message: `codex stream-json parse failed: ${stringifyErr3(err)}` };
25065
25670
  continue;
25066
25671
  }
25067
- if (!isObject7(msg))
25672
+ if (!isObject8(msg))
25068
25673
  continue;
25069
25674
  const type = typeof msg.type === "string" ? msg.type : undefined;
25070
25675
  if (!type)
@@ -25080,7 +25685,7 @@ async function* parseStreamJson2(lines, opts = {}) {
25080
25685
  if (type === "turn.started")
25081
25686
  continue;
25082
25687
  if (type === "item.started" || type === "item.completed") {
25083
- const item = isObject7(msg.item) ? msg.item : undefined;
25688
+ const item = isObject8(msg.item) ? msg.item : undefined;
25084
25689
  if (!item)
25085
25690
  continue;
25086
25691
  const itemId = typeof item.id === "string" ? item.id : undefined;
@@ -25114,17 +25719,12 @@ async function* parseStreamJson2(lines, opts = {}) {
25114
25719
  continue;
25115
25720
  }
25116
25721
  if (type === "turn.completed") {
25117
- const usage = isObject7(msg.usage) ? msg.usage : undefined;
25722
+ const usage = isObject8(msg.usage) ? msg.usage : undefined;
25118
25723
  if (usage) {
25119
- const inTok = numberOr2(usage.input_tokens, 0);
25120
- const outTok = numberOr2(usage.output_tokens, 0) + numberOr2(usage.reasoning_output_tokens, 0);
25121
- const cacheRead = typeof usage.cached_input_tokens === "number" ? usage.cached_input_tokens : undefined;
25122
- yield {
25123
- type: "usage",
25124
- input_tokens: inTok,
25125
- output_tokens: outTok,
25126
- ...cacheRead !== undefined ? { cache_read_input_tokens: cacheRead } : {}
25127
- };
25724
+ const contextWindowTokens = await opts.contextWindowTokens?.();
25725
+ const snapshot = codexUsageToSnapshot(usage, { contextWindowTokens });
25726
+ if (snapshot)
25727
+ yield { type: "usage", ...snapshot };
25128
25728
  }
25129
25729
  yield { type: "done" };
25130
25730
  return;
@@ -25153,26 +25753,23 @@ async function* readLines2(stream) {
25153
25753
  if (buf.length > 0)
25154
25754
  yield buf;
25155
25755
  }
25156
- function isObject7(v2) {
25756
+ function isObject8(v2) {
25157
25757
  return typeof v2 === "object" && v2 !== null && !Array.isArray(v2);
25158
25758
  }
25159
25759
  function codexSessionId(msg) {
25160
25760
  if (msg.type === "session_meta") {
25161
- const payload = isObject7(msg.payload) ? msg.payload : undefined;
25761
+ const payload = isObject8(msg.payload) ? msg.payload : undefined;
25162
25762
  const id2 = payload?.id;
25163
25763
  return typeof id2 === "string" && id2.length > 0 ? id2 : undefined;
25164
25764
  }
25165
25765
  const id = msg.thread_id;
25166
25766
  return typeof id === "string" && id.length > 0 ? id : undefined;
25167
25767
  }
25168
- function numberOr2(v2, fallback) {
25169
- return typeof v2 === "number" && Number.isFinite(v2) ? v2 : fallback;
25170
- }
25171
25768
  function stripIdAndType(item) {
25172
25769
  const { id: _id, type: _type, ...rest } = item;
25173
25770
  return rest;
25174
25771
  }
25175
- function stringifyErr2(err) {
25772
+ function stringifyErr3(err) {
25176
25773
  if (err instanceof Error)
25177
25774
  return err.message;
25178
25775
  try {
@@ -25181,6 +25778,7 @@ function stringifyErr2(err) {
25181
25778
  return String(err);
25182
25779
  }
25183
25780
  }
25781
+ var init_stream = () => {};
25184
25782
 
25185
25783
  // src/engine/codex-local/index.ts
25186
25784
  class CodexLocal {
@@ -25190,9 +25788,11 @@ class CodexLocal {
25190
25788
  running = new Map;
25191
25789
  binaryPathResolver;
25192
25790
  stopGraceMs;
25791
+ backend;
25193
25792
  constructor(opts = {}) {
25194
25793
  this.binaryPathResolver = opts.binaryPathResolver ?? findCodexBinary;
25195
25794
  this.stopGraceMs = opts.stopGraceMs ?? 5000;
25795
+ this.backend = opts.backend ?? resolveCodexBackend();
25196
25796
  }
25197
25797
  async spawn(cwd, prompt, opts) {
25198
25798
  return this.start({ cwd, prompt, opts });
@@ -25247,7 +25847,100 @@ class CodexLocal {
25247
25847
  }
25248
25848
  }
25249
25849
  async start(args2) {
25850
+ if (this.backend === "app-server")
25851
+ return this.startAppServer(args2);
25852
+ return this.startExec(args2);
25853
+ }
25854
+ async startAppServer(args2) {
25855
+ const binaryPath = await this.binaryPathResolver();
25856
+ const queue = [];
25857
+ let session;
25858
+ let bound = false;
25859
+ let terminalSeen = false;
25860
+ let stderrTail = "";
25861
+ let resolveHandle = () => {};
25862
+ let rejectHandle = () => {};
25863
+ const handlePromise = new Promise((res, rej) => {
25864
+ resolveHandle = res;
25865
+ rejectHandle = rej;
25866
+ });
25867
+ const bind = (sessionId) => {
25868
+ if (bound)
25869
+ return;
25870
+ bound = true;
25871
+ session = {
25872
+ sessionId,
25873
+ cwd: args2.cwd,
25874
+ spawned,
25875
+ queue,
25876
+ waiters: [],
25877
+ closed: false,
25878
+ spawnedAtIso: new Date().toISOString()
25879
+ };
25880
+ this.running.set(sessionId, session);
25881
+ this.registry.register({
25882
+ sessionId,
25883
+ cwd: args2.cwd,
25884
+ proc: spawned.proc,
25885
+ startedAt: Date.now(),
25886
+ prompt: args2.prompt
25887
+ });
25888
+ resolveHandle({ sessionId, cwd: args2.cwd });
25889
+ };
25890
+ const emit = (ev) => {
25891
+ if (ev.type === "done" || ev.type === "error")
25892
+ terminalSeen = true;
25893
+ queue.push(ev);
25894
+ if (session) {
25895
+ this.notify(session);
25896
+ if (ev.type === "done" || ev.type === "error") {
25897
+ this.registry.unregister(session.sessionId, spawned.proc);
25898
+ }
25899
+ }
25900
+ };
25901
+ const spawned = spawnCodexAppServerTurn({
25902
+ binaryPath,
25903
+ cwd: args2.cwd,
25904
+ prompt: args2.prompt,
25905
+ model: args2.opts?.model,
25906
+ modelEffort: args2.opts?.modelEffort,
25907
+ permissionMode: args2.opts?.permissionMode,
25908
+ env: args2.opts?.env,
25909
+ resumeSessionId: args2.resumeSessionId,
25910
+ onSessionId: bind,
25911
+ onEvent: emit
25912
+ });
25913
+ captureStderrTail(spawned.stderr, (chunk) => {
25914
+ stderrTail = (stderrTail + chunk).slice(-STDERR_TAIL_CAP);
25915
+ });
25916
+ spawned.ready.catch((err) => {
25917
+ if (!bound)
25918
+ rejectHandle(err);
25919
+ });
25920
+ spawned.closed.then(({ code, signal }) => {
25921
+ if (session) {
25922
+ if (!terminalSeen && typeof code === "number" && code !== 0) {
25923
+ queue.push({
25924
+ type: "error",
25925
+ message: formatExitMsg("codex app-server exited", code, signal, stderrTail)
25926
+ });
25927
+ }
25928
+ session.closed = true;
25929
+ this.notify(session);
25930
+ this.registry.unregister(session.sessionId, spawned.proc);
25931
+ if (this.running.get(session.sessionId) === session) {
25932
+ this.running.delete(session.sessionId);
25933
+ }
25934
+ }
25935
+ if (!bound) {
25936
+ rejectHandle(new Error(formatExitMsg("codex app-server exited before session id was captured", code, signal, stderrTail)));
25937
+ }
25938
+ });
25939
+ return handlePromise;
25940
+ }
25941
+ async startExec(args2) {
25250
25942
  const binaryPath = await this.binaryPathResolver();
25943
+ const modelId = args2.opts?.model ?? codexCapabilities.defaultModelId();
25251
25944
  const spawned = spawnCodexProcess({
25252
25945
  binaryPath,
25253
25946
  cwd: args2.cwd,
@@ -25268,6 +25961,7 @@ class CodexLocal {
25268
25961
  let session;
25269
25962
  let bound = false;
25270
25963
  let stderrTail = "";
25964
+ const contextWindowPromise = resolveOpenRouterContextWindow(modelId);
25271
25965
  const bind = (sessionId) => {
25272
25966
  if (bound) {
25273
25967
  if (session && session.sessionId !== sessionId) {
@@ -25331,15 +26025,15 @@ class CodexLocal {
25331
26025
  });
25332
26026
  (async () => {
25333
26027
  const events = parseStreamJson2(readLines2(spawned.stdout), {
25334
- onSessionId: (sid) => bind(sid)
26028
+ onSessionId: (sid) => bind(sid),
26029
+ contextWindowTokens: () => contextWindowPromise
25335
26030
  });
25336
26031
  try {
25337
26032
  for await (const ev of events) {
25338
- const enriched = enrichUsageEvent2(ev, session?.spawnedAtIso);
25339
- queue.push(enriched);
26033
+ queue.push(ev);
25340
26034
  if (session)
25341
26035
  this.notify(session);
25342
- if ((enriched.type === "done" || enriched.type === "error") && session) {
26036
+ if ((ev.type === "done" || ev.type === "error") && session) {
25343
26037
  this.registry.unregister(session.sessionId, spawned.proc);
25344
26038
  }
25345
26039
  }
@@ -25405,18 +26099,15 @@ function formatExitMsg(prefix, code, signal, stderrTail) {
25405
26099
  parts.push(`: ${detail}`);
25406
26100
  return parts.join(" ").replace(/ : /, ": ");
25407
26101
  }
25408
- function enrichUsageEvent2(ev, startedAtIso) {
25409
- if (ev.type !== "usage")
25410
- return ev;
25411
- return { type: "usage", ...withTotalSpeedForTurn(ev, startedAtIso, new Date().toISOString()) };
25412
- }
25413
26102
  var STDERR_TAIL_CAP;
25414
26103
  var init_codex_local = __esm(() => {
26104
+ init_app_server();
25415
26105
  init_binary2();
25416
26106
  init_capabilities2();
25417
26107
  init_history2();
25418
26108
  init_sessions2();
25419
26109
  init_spawn2();
26110
+ init_stream();
25420
26111
  STDERR_TAIL_CAP = 4 * 1024;
25421
26112
  });
25422
26113
 
@@ -27488,6 +28179,8 @@ function Composer(props) {
27488
28179
  const [pasteHint, setPasteHint] = createSignal(null);
27489
28180
  const [liveBuffer, setLiveBuffer] = createSignal(props.draft ?? "");
27490
28181
  const [liveCursor, setLiveCursor] = createSignal(props.draft?.length ?? 0);
28182
+ const [bashMode, setBashMode] = createSignal(false);
28183
+ const bashAvailable = () => props.onBashCommand != null;
27491
28184
  const [slashCursor, setSlashCursor] = createSignal(0);
27492
28185
  const slashOpen = createMemo(() => {
27493
28186
  if (!props.slashes)
@@ -27793,6 +28486,16 @@ function Composer(props) {
27793
28486
  props.onDraftChange(newText);
27794
28487
  }
27795
28488
  function handleKeyDown(key) {
28489
+ if (bashAvailable() && !bashMode() && liveBuffer().length === 0 && key.sequence === "!" && !key.ctrl && !key.meta && !key.super) {
28490
+ setBashMode(true);
28491
+ key.preventDefault();
28492
+ return;
28493
+ }
28494
+ if (bashMode() && liveBuffer().length === 0 && (key.name === "backspace" || key.name === "escape") && !key.ctrl && !key.meta && !key.super) {
28495
+ setBashMode(false);
28496
+ key.preventDefault();
28497
+ return;
28498
+ }
27796
28499
  if (key.name === "return" && key.ctrl && !slashOpen()) {
27797
28500
  handleSubmit("steer");
27798
28501
  key.preventDefault();
@@ -27903,6 +28606,20 @@ function Composer(props) {
27903
28606
  return;
27904
28607
  const raw = ref.plainText;
27905
28608
  const trimmed = raw.trim();
28609
+ if (bashMode()) {
28610
+ const command = trimmed;
28611
+ if (command.length === 0)
28612
+ return;
28613
+ pushHistory(props.historyKey ?? "global", `!${command}`);
28614
+ ref.setText("");
28615
+ setBuffer("");
28616
+ setLiveBuffer("");
28617
+ props.onDraftChange("");
28618
+ setBashMode(false);
28619
+ resetHistoryNav();
28620
+ props.onBashCommand?.(command);
28621
+ return;
28622
+ }
27906
28623
  if (slashOpen()) {
27907
28624
  const matches = slashMatches();
27908
28625
  const entry = matches[slashCursor()];
@@ -27933,6 +28650,8 @@ function Composer(props) {
27933
28650
  const streamingNotice = () => {
27934
28651
  if (!props.hasTask)
27935
28652
  return "";
28653
+ if (bashMode())
28654
+ return props.isStreaming ? "bash mode \xB7 enter to queue" : "bash mode \xB7 enter to run";
27936
28655
  if (props.isStreaming)
27937
28656
  return "enter queue \xB7 ctrl+enter steer";
27938
28657
  return "";
@@ -27968,9 +28687,9 @@ function Composer(props) {
27968
28687
  return theme.border;
27969
28688
  };
27970
28689
  return (() => {
27971
- var _el$ = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("box"), _el$21 = createElement("box"), _el$22 = createElement("text"), _el$23 = createElement("box"), _el$32 = createElement("box"), _el$33 = createElement("box");
28690
+ var _el$ = createElement("box"), _el$14 = createElement("box"), _el$15 = createElement("box"), _el$21 = createElement("box"), _el$24 = createElement("box"), _el$33 = createElement("box"), _el$34 = createElement("box");
27972
28691
  insertNode(_el$, _el$14);
27973
- insertNode(_el$, _el$32);
28692
+ insertNode(_el$, _el$33);
27974
28693
  setProp(_el$, "flexShrink", 0);
27975
28694
  setProp(_el$, "flexDirection", "column");
27976
28695
  setProp(_el$, "paddingTop", 1);
@@ -28017,35 +28736,35 @@ function Composer(props) {
28017
28736
  return idx >= 0 ? match.displayPath.slice(0, idx) : "";
28018
28737
  };
28019
28738
  return (() => {
28020
- var _el$34 = createElement("box"), _el$35 = createElement("text");
28021
- insertNode(_el$34, _el$35);
28022
- setProp(_el$34, "flexDirection", "row");
28023
- setProp(_el$34, "gap", 2);
28024
- setProp(_el$35, "wrapMode", "none");
28025
- insert(_el$35, () => active() ? "\u25B8 " : " ", null);
28026
- insert(_el$35, filename, null);
28027
- insert(_el$34, createComponent2(Show, {
28739
+ var _el$35 = createElement("box"), _el$36 = createElement("text");
28740
+ insertNode(_el$35, _el$36);
28741
+ setProp(_el$35, "flexDirection", "row");
28742
+ setProp(_el$35, "gap", 2);
28743
+ setProp(_el$36, "wrapMode", "none");
28744
+ insert(_el$36, () => active() ? "\u25B8 " : " ", null);
28745
+ insert(_el$36, filename, null);
28746
+ insert(_el$35, createComponent2(Show, {
28028
28747
  get when() {
28029
28748
  return directory().length > 0;
28030
28749
  },
28031
28750
  get children() {
28032
- var _el$36 = createElement("text");
28033
- setProp(_el$36, "wrapMode", "none");
28034
- insert(_el$36, directory);
28035
- effect((_$p) => setProp(_el$36, "fg", theme.textMuted, _$p));
28036
- return _el$36;
28751
+ var _el$37 = createElement("text");
28752
+ setProp(_el$37, "wrapMode", "none");
28753
+ insert(_el$37, directory);
28754
+ effect((_$p) => setProp(_el$37, "fg", theme.textMuted, _$p));
28755
+ return _el$37;
28037
28756
  }
28038
28757
  }), null);
28039
28758
  effect((_p$) => {
28040
- var _v$24 = active() ? theme.primary : theme.text, _v$25 = active() ? TextAttributes22.BOLD : undefined;
28041
- _v$24 !== _p$.e && (_p$.e = setProp(_el$35, "fg", _v$24, _p$.e));
28042
- _v$25 !== _p$.t && (_p$.t = setProp(_el$35, "attributes", _v$25, _p$.t));
28759
+ var _v$25 = active() ? theme.primary : theme.text, _v$26 = active() ? TextAttributes22.BOLD : undefined;
28760
+ _v$25 !== _p$.e && (_p$.e = setProp(_el$36, "fg", _v$25, _p$.e));
28761
+ _v$26 !== _p$.t && (_p$.t = setProp(_el$36, "attributes", _v$26, _p$.t));
28043
28762
  return _p$;
28044
28763
  }, {
28045
28764
  e: undefined,
28046
28765
  t: undefined
28047
28766
  });
28048
- return _el$34;
28767
+ return _el$35;
28049
28768
  })();
28050
28769
  }
28051
28770
  }), null);
@@ -28112,47 +28831,47 @@ function Composer(props) {
28112
28831
  const absoluteIndex = () => slashWindow().start + i2();
28113
28832
  const active = () => absoluteIndex() === slashCursor();
28114
28833
  return (() => {
28115
- var _el$37 = createElement("box"), _el$38 = createElement("text");
28116
- insertNode(_el$37, _el$38);
28117
- setProp(_el$37, "flexDirection", "row");
28118
- setProp(_el$37, "gap", 2);
28119
- setProp(_el$38, "wrapMode", "none");
28120
- insert(_el$38, () => active() ? "\u25B8 " : " ", null);
28121
- insert(_el$38, () => entry.display, null);
28122
- insert(_el$37, createComponent2(Show, {
28834
+ var _el$38 = createElement("box"), _el$39 = createElement("text");
28835
+ insertNode(_el$38, _el$39);
28836
+ setProp(_el$38, "flexDirection", "row");
28837
+ setProp(_el$38, "gap", 2);
28838
+ setProp(_el$39, "wrapMode", "none");
28839
+ insert(_el$39, () => active() ? "\u25B8 " : " ", null);
28840
+ insert(_el$39, () => entry.display, null);
28841
+ insert(_el$38, createComponent2(Show, {
28123
28842
  get when() {
28124
28843
  return entry.source === "user";
28125
28844
  },
28126
28845
  get children() {
28127
- var _el$39 = createElement("text");
28128
- insertNode(_el$39, createTextNode(`user`));
28129
- setProp(_el$39, "wrapMode", "none");
28130
- effect((_$p) => setProp(_el$39, "fg", theme.textMuted, _$p));
28131
- return _el$39;
28846
+ var _el$40 = createElement("text");
28847
+ insertNode(_el$40, createTextNode(`user`));
28848
+ setProp(_el$40, "wrapMode", "none");
28849
+ effect((_$p) => setProp(_el$40, "fg", theme.textMuted, _$p));
28850
+ return _el$40;
28132
28851
  }
28133
28852
  }), null);
28134
- insert(_el$37, createComponent2(Show, {
28853
+ insert(_el$38, createComponent2(Show, {
28135
28854
  get when() {
28136
28855
  return entry.description;
28137
28856
  },
28138
28857
  get children() {
28139
- var _el$41 = createElement("text");
28140
- setProp(_el$41, "wrapMode", "none");
28141
- insert(_el$41, () => entry.description);
28142
- effect((_$p) => setProp(_el$41, "fg", theme.textMuted, _$p));
28143
- return _el$41;
28858
+ var _el$42 = createElement("text");
28859
+ setProp(_el$42, "wrapMode", "none");
28860
+ insert(_el$42, () => entry.description);
28861
+ effect((_$p) => setProp(_el$42, "fg", theme.textMuted, _$p));
28862
+ return _el$42;
28144
28863
  }
28145
28864
  }), null);
28146
28865
  effect((_p$) => {
28147
- var _v$26 = active() ? theme.primary : theme.text, _v$27 = active() ? TextAttributes22.BOLD : undefined;
28148
- _v$26 !== _p$.e && (_p$.e = setProp(_el$38, "fg", _v$26, _p$.e));
28149
- _v$27 !== _p$.t && (_p$.t = setProp(_el$38, "attributes", _v$27, _p$.t));
28866
+ var _v$27 = active() ? theme.primary : theme.text, _v$28 = active() ? TextAttributes22.BOLD : undefined;
28867
+ _v$27 !== _p$.e && (_p$.e = setProp(_el$39, "fg", _v$27, _p$.e));
28868
+ _v$28 !== _p$.t && (_p$.t = setProp(_el$39, "attributes", _v$28, _p$.t));
28150
28869
  return _p$;
28151
28870
  }, {
28152
28871
  e: undefined,
28153
28872
  t: undefined
28154
28873
  });
28155
- return _el$37;
28874
+ return _el$38;
28156
28875
  })();
28157
28876
  }
28158
28877
  }), null);
@@ -28206,37 +28925,52 @@ function Composer(props) {
28206
28925
  return (props.queue?.() ?? []).slice(0, QUEUE_VISIBLE_CAP);
28207
28926
  },
28208
28927
  children: (entry, idx) => (() => {
28209
- var _el$42 = createElement("box"), _el$43 = createElement("text"), _el$45 = createElement("text"), _el$46 = createTextNode(`queued`), _el$47 = createTextNode(`:`), _el$48 = createElement("box"), _el$49 = createElement("text"), _el$50 = createElement("text"), _el$52 = createElement("text");
28210
- insertNode(_el$42, _el$43);
28211
- insertNode(_el$42, _el$45);
28212
- insertNode(_el$42, _el$48);
28213
- insertNode(_el$42, _el$50);
28214
- insertNode(_el$42, _el$52);
28215
- setProp(_el$42, "flexDirection", "row");
28216
- setProp(_el$42, "gap", 1);
28217
- setProp(_el$42, "alignItems", "flex-start");
28218
- insertNode(_el$43, createTextNode(`+`));
28219
- insertNode(_el$45, _el$46);
28220
- insertNode(_el$45, _el$47);
28221
- setProp(_el$45, "wrapMode", "none");
28222
- insert(_el$45, () => idx() === 0 ? " (next)" : "", _el$47);
28223
- insertNode(_el$48, _el$49);
28224
- setProp(_el$48, "flexGrow", 1);
28225
- insert(_el$49, () => entry.text);
28226
- insertNode(_el$50, createTextNode(`[\u25B6]`));
28227
- setProp(_el$50, "onMouseUp", () => props.onSendQueuedNow?.(entry.id));
28228
- insertNode(_el$52, createTextNode(`[x]`));
28229
- setProp(_el$52, "onMouseUp", () => props.onCancelQueued?.(entry.id));
28928
+ var _el$43 = createElement("box"), _el$44 = createElement("text"), _el$46 = createElement("text"), _el$47 = createTextNode(`queued`), _el$48 = createTextNode(`:`), _el$51 = createElement("box"), _el$52 = createElement("text"), _el$53 = createElement("text"), _el$55 = createElement("text");
28929
+ insertNode(_el$43, _el$44);
28930
+ insertNode(_el$43, _el$46);
28931
+ insertNode(_el$43, _el$51);
28932
+ insertNode(_el$43, _el$53);
28933
+ insertNode(_el$43, _el$55);
28934
+ setProp(_el$43, "flexDirection", "row");
28935
+ setProp(_el$43, "gap", 1);
28936
+ setProp(_el$43, "alignItems", "flex-start");
28937
+ insertNode(_el$44, createTextNode(`+`));
28938
+ insertNode(_el$46, _el$47);
28939
+ insertNode(_el$46, _el$48);
28940
+ setProp(_el$46, "wrapMode", "none");
28941
+ insert(_el$46, () => idx() === 0 ? " (next)" : "", _el$48);
28942
+ insert(_el$43, createComponent2(Show, {
28943
+ get when() {
28944
+ return entry.kind === "bash";
28945
+ },
28946
+ get children() {
28947
+ var _el$49 = createElement("text");
28948
+ insertNode(_el$49, createTextNode(`(bash)`));
28949
+ setProp(_el$49, "wrapMode", "none");
28950
+ effect((_$p) => setProp(_el$49, "fg", theme.warning, _$p));
28951
+ return _el$49;
28952
+ }
28953
+ }), _el$51);
28954
+ insertNode(_el$51, _el$52);
28955
+ setProp(_el$51, "flexGrow", 1);
28956
+ insert(_el$52, (() => {
28957
+ var _c$ = memo2(() => entry.kind === "bash");
28958
+ return () => _c$() ? entry.command : entry.text;
28959
+ })());
28960
+ insertNode(_el$53, createTextNode(`[\u25B6]`));
28961
+ setProp(_el$53, "onMouseUp", () => props.onSendQueuedNow?.(entry.id));
28962
+ insertNode(_el$55, createTextNode(`[x]`));
28963
+ setProp(_el$55, "onMouseUp", () => props.onCancelQueued?.(entry.id));
28230
28964
  effect((_p$) => {
28231
- var _v$28 = theme.textMuted, _v$29 = TextAttributes22.BOLD, _v$30 = theme.textMuted, _v$31 = theme.text, _v$32 = theme.primary, _v$33 = TextAttributes22.BOLD, _v$34 = theme.error, _v$35 = TextAttributes22.BOLD;
28232
- _v$28 !== _p$.e && (_p$.e = setProp(_el$43, "fg", _v$28, _p$.e));
28233
- _v$29 !== _p$.t && (_p$.t = setProp(_el$43, "attributes", _v$29, _p$.t));
28234
- _v$30 !== _p$.a && (_p$.a = setProp(_el$45, "fg", _v$30, _p$.a));
28235
- _v$31 !== _p$.o && (_p$.o = setProp(_el$49, "fg", _v$31, _p$.o));
28236
- _v$32 !== _p$.i && (_p$.i = setProp(_el$50, "fg", _v$32, _p$.i));
28237
- _v$33 !== _p$.n && (_p$.n = setProp(_el$50, "attributes", _v$33, _p$.n));
28238
- _v$34 !== _p$.s && (_p$.s = setProp(_el$52, "fg", _v$34, _p$.s));
28239
- _v$35 !== _p$.h && (_p$.h = setProp(_el$52, "attributes", _v$35, _p$.h));
28965
+ var _v$29 = theme.textMuted, _v$30 = TextAttributes22.BOLD, _v$31 = theme.textMuted, _v$32 = theme.text, _v$33 = theme.primary, _v$34 = TextAttributes22.BOLD, _v$35 = theme.error, _v$36 = TextAttributes22.BOLD;
28966
+ _v$29 !== _p$.e && (_p$.e = setProp(_el$44, "fg", _v$29, _p$.e));
28967
+ _v$30 !== _p$.t && (_p$.t = setProp(_el$44, "attributes", _v$30, _p$.t));
28968
+ _v$31 !== _p$.a && (_p$.a = setProp(_el$46, "fg", _v$31, _p$.a));
28969
+ _v$32 !== _p$.o && (_p$.o = setProp(_el$52, "fg", _v$32, _p$.o));
28970
+ _v$33 !== _p$.i && (_p$.i = setProp(_el$53, "fg", _v$33, _p$.i));
28971
+ _v$34 !== _p$.n && (_p$.n = setProp(_el$53, "attributes", _v$34, _p$.n));
28972
+ _v$35 !== _p$.s && (_p$.s = setProp(_el$55, "fg", _v$35, _p$.s));
28973
+ _v$36 !== _p$.h && (_p$.h = setProp(_el$55, "attributes", _v$36, _p$.h));
28240
28974
  return _p$;
28241
28975
  }, {
28242
28976
  e: undefined,
@@ -28248,7 +28982,7 @@ function Composer(props) {
28248
28982
  s: undefined,
28249
28983
  h: undefined
28250
28984
  });
28251
- return _el$42;
28985
+ return _el$43;
28252
28986
  })()
28253
28987
  }), null);
28254
28988
  insert(_el$16, createComponent2(Show, {
@@ -28281,30 +29015,82 @@ function Composer(props) {
28281
29015
  return _el$16;
28282
29016
  }
28283
29017
  }), _el$21);
28284
- insertNode(_el$21, _el$22);
28285
- insertNode(_el$21, _el$23);
29018
+ insertNode(_el$21, _el$24);
28286
29019
  setProp(_el$21, "flexDirection", "row");
28287
29020
  setProp(_el$21, "gap", 1);
28288
29021
  setProp(_el$21, "alignItems", "flex-start");
28289
- insert(_el$22, () => props.isStreaming ? "\u2026" : ">");
28290
- setProp(_el$23, "flexGrow", 1);
28291
- setProp(_el$23, "flexShrink", 1);
28292
- setProp(_el$23, "maxHeight", 8);
28293
- setProp(_el$23, "minHeight", 1);
28294
- insert(_el$23, createComponent2(Show, {
29022
+ insert(_el$21, createComponent2(Show, {
29023
+ get when() {
29024
+ return memo2(() => !!bashMode())() && !props.isStreaming;
29025
+ },
29026
+ get fallback() {
29027
+ return createComponent2(Show, {
29028
+ get when() {
29029
+ return memo2(() => !!bashMode())() && props.isStreaming;
29030
+ },
29031
+ get fallback() {
29032
+ return (() => {
29033
+ var _el$62 = createElement("text");
29034
+ insert(_el$62, () => props.isStreaming ? "\u2026" : ">");
29035
+ effect((_$p) => setProp(_el$62, "fg", props.isStreaming ? theme.accent : theme.primary, _$p));
29036
+ return _el$62;
29037
+ })();
29038
+ },
29039
+ get children() {
29040
+ var _el$57 = createElement("box"), _el$58 = createElement("text"), _el$60 = createElement("text");
29041
+ insertNode(_el$57, _el$58);
29042
+ insertNode(_el$57, _el$60);
29043
+ setProp(_el$57, "flexDirection", "row");
29044
+ insertNode(_el$58, createTextNode(`\u2026`));
29045
+ insertNode(_el$60, createTextNode(`!`));
29046
+ effect((_p$) => {
29047
+ var { accent: _v$37, warning: _v$38 } = theme, _v$39 = TextAttributes22.BOLD;
29048
+ _v$37 !== _p$.e && (_p$.e = setProp(_el$58, "fg", _v$37, _p$.e));
29049
+ _v$38 !== _p$.t && (_p$.t = setProp(_el$60, "fg", _v$38, _p$.t));
29050
+ _v$39 !== _p$.a && (_p$.a = setProp(_el$60, "attributes", _v$39, _p$.a));
29051
+ return _p$;
29052
+ }, {
29053
+ e: undefined,
29054
+ t: undefined,
29055
+ a: undefined
29056
+ });
29057
+ return _el$57;
29058
+ }
29059
+ });
29060
+ },
29061
+ get children() {
29062
+ var _el$22 = createElement("text");
29063
+ insertNode(_el$22, createTextNode(`!`));
29064
+ effect((_p$) => {
29065
+ var _v$0 = theme.warning, _v$1 = TextAttributes22.BOLD;
29066
+ _v$0 !== _p$.e && (_p$.e = setProp(_el$22, "fg", _v$0, _p$.e));
29067
+ _v$1 !== _p$.t && (_p$.t = setProp(_el$22, "attributes", _v$1, _p$.t));
29068
+ return _p$;
29069
+ }, {
29070
+ e: undefined,
29071
+ t: undefined
29072
+ });
29073
+ return _el$22;
29074
+ }
29075
+ }), _el$24);
29076
+ setProp(_el$24, "flexGrow", 1);
29077
+ setProp(_el$24, "flexShrink", 1);
29078
+ setProp(_el$24, "maxHeight", 8);
29079
+ setProp(_el$24, "minHeight", 1);
29080
+ insert(_el$24, createComponent2(Show, {
28295
29081
  get when() {
28296
29082
  return props.hasTask;
28297
29083
  },
28298
29084
  get fallback() {
28299
29085
  return (() => {
28300
- var _el$54 = createElement("text");
28301
- insert(_el$54, () => props.noTaskMessage ?? "(no task \u2014 press n to create)");
28302
- effect((_$p) => setProp(_el$54, "fg", theme.textMuted, _$p));
28303
- return _el$54;
29086
+ var _el$63 = createElement("text");
29087
+ insert(_el$63, () => props.noTaskMessage ?? "(no task \u2014 press n to create)");
29088
+ effect((_$p) => setProp(_el$63, "fg", theme.textMuted, _$p));
29089
+ return _el$63;
28304
29090
  })();
28305
29091
  },
28306
29092
  get children() {
28307
- var _el$24 = createElement("textarea");
29093
+ var _el$25 = createElement("textarea");
28308
29094
  use((r2) => {
28309
29095
  textareaRef = r2;
28310
29096
  if (props.draft)
@@ -28312,24 +29098,24 @@ function Composer(props) {
28312
29098
  r2.onPaste = handlePaste;
28313
29099
  if (props.focused?.())
28314
29100
  r2.focus();
28315
- }, _el$24);
28316
- setProp(_el$24, "wrapMode", "word");
28317
- setProp(_el$24, "keyBindings", composerKeyBindings);
28318
- setProp(_el$24, "onContentChange", handleContentChange);
28319
- setProp(_el$24, "onKeyDown", handleKeyDown);
28320
- setProp(_el$24, "onSubmit", () => handleSubmit("auto"));
29101
+ }, _el$25);
29102
+ setProp(_el$25, "wrapMode", "word");
29103
+ setProp(_el$25, "keyBindings", composerKeyBindings);
29104
+ setProp(_el$25, "onContentChange", handleContentChange);
29105
+ setProp(_el$25, "onKeyDown", handleKeyDown);
29106
+ setProp(_el$25, "onSubmit", () => handleSubmit("auto"));
28321
29107
  effect((_p$) => {
28322
- var _v$0 = resolvePlaceholder({
29108
+ var _v$10 = resolvePlaceholder({
28323
29109
  isStreaming: props.isStreaming,
28324
29110
  hasTask: props.hasTask,
28325
29111
  noTaskMessage: props.noTaskMessage,
28326
29112
  inputPlaceholder: props.inputPlaceholder?.()
28327
- }), _v$1 = theme.textMuted, _v$10 = theme.text, _v$11 = theme.backgroundElement, _v$12 = theme.backgroundElement;
28328
- _v$0 !== _p$.e && (_p$.e = setProp(_el$24, "placeholder", _v$0, _p$.e));
28329
- _v$1 !== _p$.t && (_p$.t = setProp(_el$24, "placeholderColor", _v$1, _p$.t));
28330
- _v$10 !== _p$.a && (_p$.a = setProp(_el$24, "textColor", _v$10, _p$.a));
28331
- _v$11 !== _p$.o && (_p$.o = setProp(_el$24, "backgroundColor", _v$11, _p$.o));
28332
- _v$12 !== _p$.i && (_p$.i = setProp(_el$24, "focusedBackgroundColor", _v$12, _p$.i));
29113
+ }), _v$11 = theme.textMuted, _v$12 = theme.text, _v$13 = theme.backgroundElement, _v$14 = theme.backgroundElement;
29114
+ _v$10 !== _p$.e && (_p$.e = setProp(_el$25, "placeholder", _v$10, _p$.e));
29115
+ _v$11 !== _p$.t && (_p$.t = setProp(_el$25, "placeholderColor", _v$11, _p$.t));
29116
+ _v$12 !== _p$.a && (_p$.a = setProp(_el$25, "textColor", _v$12, _p$.a));
29117
+ _v$13 !== _p$.o && (_p$.o = setProp(_el$25, "backgroundColor", _v$13, _p$.o));
29118
+ _v$14 !== _p$.i && (_p$.i = setProp(_el$25, "focusedBackgroundColor", _v$14, _p$.i));
28333
29119
  return _p$;
28334
29120
  }, {
28335
29121
  e: undefined,
@@ -28338,7 +29124,7 @@ function Composer(props) {
28338
29124
  o: undefined,
28339
29125
  i: undefined
28340
29126
  });
28341
- return _el$24;
29127
+ return _el$25;
28342
29128
  }
28343
29129
  }));
28344
29130
  insert(_el$15, createComponent2(Show, {
@@ -28346,72 +29132,71 @@ function Composer(props) {
28346
29132
  return props.hasTask;
28347
29133
  },
28348
29134
  get children() {
28349
- var _el$25 = createElement("box"), _el$26 = createElement("text"), _el$27 = createElement("box"), _el$28 = createElement("box"), _el$29 = createElement("text"), _el$30 = createElement("box"), _el$31 = createElement("text");
28350
- insertNode(_el$25, _el$26);
28351
- insertNode(_el$25, _el$27);
28352
- setProp(_el$25, "flexDirection", "row");
28353
- setProp(_el$25, "justifyContent", "space-between");
28354
- setProp(_el$25, "paddingTop", 1);
28355
- setProp(_el$25, "flexShrink", 0);
28356
- setProp(_el$26, "wrapMode", "none");
28357
- insert(_el$26, footerHint);
28358
- insertNode(_el$27, _el$28);
28359
- insertNode(_el$27, _el$30);
28360
- setProp(_el$27, "flexDirection", "row");
28361
- setProp(_el$27, "gap", 2);
28362
- setProp(_el$27, "flexShrink", 0);
29135
+ var _el$26 = createElement("box"), _el$27 = createElement("text"), _el$28 = createElement("box"), _el$29 = createElement("box"), _el$30 = createElement("text"), _el$31 = createElement("box"), _el$32 = createElement("text");
29136
+ insertNode(_el$26, _el$27);
29137
+ insertNode(_el$26, _el$28);
29138
+ setProp(_el$26, "flexDirection", "row");
29139
+ setProp(_el$26, "justifyContent", "space-between");
29140
+ setProp(_el$26, "paddingTop", 1);
29141
+ setProp(_el$26, "flexShrink", 0);
29142
+ setProp(_el$27, "wrapMode", "none");
29143
+ insert(_el$27, footerHint);
28363
29144
  insertNode(_el$28, _el$29);
29145
+ insertNode(_el$28, _el$31);
28364
29146
  setProp(_el$28, "flexDirection", "row");
29147
+ setProp(_el$28, "gap", 2);
28365
29148
  setProp(_el$28, "flexShrink", 0);
28366
- setProp(_el$28, "onMouseUp", () => props.onCyclePermissionMode?.());
28367
- setProp(_el$29, "wrapMode", "none");
28368
- insert(_el$29, permissionModeLabel, null);
28369
- insert(_el$29, () => props.onCyclePermissionMode ? " \u25BE" : "", null);
28370
- insertNode(_el$30, _el$31);
28371
- setProp(_el$30, "flexDirection", "row");
28372
- setProp(_el$30, "flexShrink", 0);
28373
- setProp(_el$30, "onMouseUp", () => props.onChooseModel?.());
28374
- setProp(_el$31, "wrapMode", "none");
28375
- insert(_el$31, modelLabel, null);
28376
- insert(_el$31, () => props.onChooseModel ? " \u25BE" : "", null);
29149
+ insertNode(_el$29, _el$30);
29150
+ setProp(_el$29, "flexDirection", "row");
29151
+ setProp(_el$29, "flexShrink", 0);
29152
+ setProp(_el$29, "onMouseUp", () => props.onCyclePermissionMode?.());
29153
+ setProp(_el$30, "wrapMode", "none");
29154
+ insert(_el$30, permissionModeLabel, null);
29155
+ insert(_el$30, () => props.onCyclePermissionMode ? " \u25BE" : "", null);
29156
+ insertNode(_el$31, _el$32);
29157
+ setProp(_el$31, "flexDirection", "row");
29158
+ setProp(_el$31, "flexShrink", 0);
29159
+ setProp(_el$31, "onMouseUp", () => props.onChooseModel?.());
29160
+ setProp(_el$32, "wrapMode", "none");
29161
+ insert(_el$32, modelLabel, null);
29162
+ insert(_el$32, () => props.onChooseModel ? " \u25BE" : "", null);
28377
29163
  effect((_p$) => {
28378
- var _v$13 = props.isStreaming ? theme.accent : theme.textMuted, _v$14 = modeBadge() ? toneColor("primary") : theme.textMuted, _v$15 = theme.textMuted;
28379
- _v$13 !== _p$.e && (_p$.e = setProp(_el$26, "fg", _v$13, _p$.e));
28380
- _v$14 !== _p$.t && (_p$.t = setProp(_el$29, "fg", _v$14, _p$.t));
28381
- _v$15 !== _p$.a && (_p$.a = setProp(_el$31, "fg", _v$15, _p$.a));
29164
+ var _v$15 = props.isStreaming ? theme.accent : theme.textMuted, _v$16 = modeBadge() ? toneColor("primary") : theme.textMuted, _v$17 = theme.textMuted;
29165
+ _v$15 !== _p$.e && (_p$.e = setProp(_el$27, "fg", _v$15, _p$.e));
29166
+ _v$16 !== _p$.t && (_p$.t = setProp(_el$30, "fg", _v$16, _p$.t));
29167
+ _v$17 !== _p$.a && (_p$.a = setProp(_el$32, "fg", _v$17, _p$.a));
28382
29168
  return _p$;
28383
29169
  }, {
28384
29170
  e: undefined,
28385
29171
  t: undefined,
28386
29172
  a: undefined
28387
29173
  });
28388
- return _el$25;
29174
+ return _el$26;
28389
29175
  }
28390
29176
  }), null);
28391
- insertNode(_el$32, _el$33);
28392
- setProp(_el$32, "height", 1);
28393
- setProp(_el$32, "border", ["left"]);
29177
+ insertNode(_el$33, _el$34);
28394
29178
  setProp(_el$33, "height", 1);
28395
- setProp(_el$33, "border", ["bottom"]);
29179
+ setProp(_el$33, "border", ["left"]);
29180
+ setProp(_el$34, "height", 1);
29181
+ setProp(_el$34, "border", ["bottom"]);
28396
29182
  effect((_p$) => {
28397
- var _v$16 = railColor(), _v$17 = {
29183
+ var _v$18 = railColor(), _v$19 = {
28398
29184
  ...SplitBorder.customBorderChars,
28399
29185
  bottomLeft: "\u2579"
28400
- }, _v$18 = theme.backgroundElement, _v$19 = props.isStreaming ? theme.accent : theme.primary, _v$20 = railColor(), _v$21 = {
29186
+ }, _v$20 = theme.backgroundElement, _v$21 = railColor(), _v$22 = {
28401
29187
  ...EmptyBorder,
28402
29188
  vertical: theme.backgroundElement.a !== 0 ? "\u2579" : " "
28403
- }, _v$22 = theme.backgroundElement, _v$23 = {
29189
+ }, _v$23 = theme.backgroundElement, _v$24 = {
28404
29190
  ...EmptyBorder,
28405
29191
  horizontal: theme.backgroundElement.a !== 0 ? "\u2580" : " "
28406
29192
  };
28407
- _v$16 !== _p$.e && (_p$.e = setProp(_el$14, "borderColor", _v$16, _p$.e));
28408
- _v$17 !== _p$.t && (_p$.t = setProp(_el$14, "customBorderChars", _v$17, _p$.t));
28409
- _v$18 !== _p$.a && (_p$.a = setProp(_el$15, "backgroundColor", _v$18, _p$.a));
28410
- _v$19 !== _p$.o && (_p$.o = setProp(_el$22, "fg", _v$19, _p$.o));
28411
- _v$20 !== _p$.i && (_p$.i = setProp(_el$32, "borderColor", _v$20, _p$.i));
28412
- _v$21 !== _p$.n && (_p$.n = setProp(_el$32, "customBorderChars", _v$21, _p$.n));
28413
- _v$22 !== _p$.s && (_p$.s = setProp(_el$33, "borderColor", _v$22, _p$.s));
28414
- _v$23 !== _p$.h && (_p$.h = setProp(_el$33, "customBorderChars", _v$23, _p$.h));
29193
+ _v$18 !== _p$.e && (_p$.e = setProp(_el$14, "borderColor", _v$18, _p$.e));
29194
+ _v$19 !== _p$.t && (_p$.t = setProp(_el$14, "customBorderChars", _v$19, _p$.t));
29195
+ _v$20 !== _p$.a && (_p$.a = setProp(_el$15, "backgroundColor", _v$20, _p$.a));
29196
+ _v$21 !== _p$.o && (_p$.o = setProp(_el$33, "borderColor", _v$21, _p$.o));
29197
+ _v$22 !== _p$.i && (_p$.i = setProp(_el$33, "customBorderChars", _v$22, _p$.i));
29198
+ _v$23 !== _p$.n && (_p$.n = setProp(_el$34, "borderColor", _v$23, _p$.n));
29199
+ _v$24 !== _p$.s && (_p$.s = setProp(_el$34, "customBorderChars", _v$24, _p$.s));
28415
29200
  return _p$;
28416
29201
  }, {
28417
29202
  e: undefined,
@@ -28420,8 +29205,7 @@ function Composer(props) {
28420
29205
  o: undefined,
28421
29206
  i: undefined,
28422
29207
  n: undefined,
28423
- s: undefined,
28424
- h: undefined
29208
+ s: undefined
28425
29209
  });
28426
29210
  return _el$;
28427
29211
  })();
@@ -29894,27 +30678,119 @@ function ReadGrepGlobBanner(props) {
29894
30678
  return _el$81;
29895
30679
  })();
29896
30680
  }
29897
- function SystemRow(props) {
30681
+ function BashRow(props) {
29898
30682
  const {
29899
30683
  theme
29900
30684
  } = useTheme();
29901
- const isError = () => props.text.startsWith("error:") || props.text.startsWith("runTask failed");
30685
+ const r2 = () => props.row;
30686
+ const stdoutView = () => splitBashOutput(r2().stdout, -1);
30687
+ const stderrView = () => splitBashOutput(r2().stderr, -1);
30688
+ const statusText = () => {
30689
+ if (!r2().done)
30690
+ return "running\u2026";
30691
+ if (r2().signal !== null)
30692
+ return `interrupted (${r2().signal})`;
30693
+ const code = r2().exitCode;
30694
+ if (code === null)
30695
+ return "(no exit code)";
30696
+ if (code === 0)
30697
+ return null;
30698
+ return `exit ${code}`;
30699
+ };
30700
+ const statusColor = () => {
30701
+ if (!r2().done)
30702
+ return theme.textMuted;
30703
+ if (r2().signal !== null)
30704
+ return theme.error;
30705
+ return theme.error;
30706
+ };
29902
30707
  return (() => {
29903
- var _el$84 = createElement("box"), _el$85 = createElement("text"), _el$87 = createElement("box"), _el$88 = createElement("text");
30708
+ var _el$84 = createElement("box"), _el$85 = createElement("box"), _el$86 = createElement("text"), _el$88 = createElement("box"), _el$89 = createElement("text");
29904
30709
  insertNode(_el$84, _el$85);
29905
- insertNode(_el$84, _el$87);
29906
30710
  setProp(_el$84, "paddingTop", 1);
29907
- setProp(_el$84, "flexDirection", "row");
29908
- setProp(_el$84, "gap", 1);
29909
- insertNode(_el$85, createTextNode(`\u203B`));
29910
- insertNode(_el$87, _el$88);
29911
- setProp(_el$87, "flexGrow", 1);
29912
- insert(_el$88, () => props.text);
30711
+ setProp(_el$84, "flexDirection", "column");
30712
+ insertNode(_el$85, _el$86);
30713
+ insertNode(_el$85, _el$88);
30714
+ setProp(_el$85, "flexDirection", "row");
30715
+ setProp(_el$85, "gap", 1);
30716
+ insertNode(_el$86, createTextNode(`!`));
30717
+ setProp(_el$86, "wrapMode", "none");
30718
+ insertNode(_el$88, _el$89);
30719
+ setProp(_el$88, "flexGrow", 1);
30720
+ setProp(_el$89, "wrapMode", "none");
30721
+ insert(_el$89, () => r2().command || "(empty command)");
30722
+ insert(_el$84, createComponent2(Show, {
30723
+ get when() {
30724
+ return stdoutView().totalLines > 0;
30725
+ },
30726
+ get children() {
30727
+ var _el$90 = createElement("box");
30728
+ setProp(_el$90, "paddingLeft", 2);
30729
+ setProp(_el$90, "flexDirection", "column");
30730
+ insert(_el$90, createComponent2(For, {
30731
+ get each() {
30732
+ return stdoutView().visible;
30733
+ },
30734
+ children: (line) => (() => {
30735
+ var _el$94 = createElement("text");
30736
+ setProp(_el$94, "wrapMode", "none");
30737
+ insert(_el$94, line || " ");
30738
+ effect((_$p) => setProp(_el$94, "fg", theme.textMuted, _$p));
30739
+ return _el$94;
30740
+ })()
30741
+ }));
30742
+ return _el$90;
30743
+ }
30744
+ }), null);
30745
+ insert(_el$84, createComponent2(Show, {
30746
+ get when() {
30747
+ return stderrView().totalLines > 0;
30748
+ },
30749
+ get children() {
30750
+ var _el$91 = createElement("box");
30751
+ setProp(_el$91, "paddingLeft", 2);
30752
+ setProp(_el$91, "flexDirection", "column");
30753
+ insert(_el$91, createComponent2(For, {
30754
+ get each() {
30755
+ return stderrView().visible;
30756
+ },
30757
+ children: (line) => (() => {
30758
+ var _el$95 = createElement("text");
30759
+ setProp(_el$95, "wrapMode", "none");
30760
+ insert(_el$95, line || " ");
30761
+ effect((_$p) => setProp(_el$95, "fg", theme.error, _$p));
30762
+ return _el$95;
30763
+ })()
30764
+ }));
30765
+ return _el$91;
30766
+ }
30767
+ }), null);
30768
+ insert(_el$84, createComponent2(Show, {
30769
+ get when() {
30770
+ return statusText() != null;
30771
+ },
30772
+ get children() {
30773
+ var _el$92 = createElement("box"), _el$93 = createElement("text");
30774
+ insertNode(_el$92, _el$93);
30775
+ setProp(_el$92, "paddingLeft", 2);
30776
+ insert(_el$93, statusText);
30777
+ effect((_p$) => {
30778
+ var _v$33 = statusColor(), _v$34 = TextAttributes23.DIM;
30779
+ _v$33 !== _p$.e && (_p$.e = setProp(_el$93, "fg", _v$33, _p$.e));
30780
+ _v$34 !== _p$.t && (_p$.t = setProp(_el$93, "attributes", _v$34, _p$.t));
30781
+ return _p$;
30782
+ }, {
30783
+ e: undefined,
30784
+ t: undefined
30785
+ });
30786
+ return _el$92;
30787
+ }
30788
+ }), null);
29913
30789
  effect((_p$) => {
29914
- var _v$33 = theme.textMuted, _v$34 = TextAttributes23.DIM, _v$35 = isError() ? theme.error : theme.textMuted;
29915
- _v$33 !== _p$.e && (_p$.e = setProp(_el$85, "fg", _v$33, _p$.e));
29916
- _v$34 !== _p$.t && (_p$.t = setProp(_el$85, "attributes", _v$34, _p$.t));
29917
- _v$35 !== _p$.a && (_p$.a = setProp(_el$88, "fg", _v$35, _p$.a));
30790
+ var _v$35 = theme.warning, _v$36 = TextAttributes23.BOLD, _v$37 = theme.text;
30791
+ _v$35 !== _p$.e && (_p$.e = setProp(_el$86, "fg", _v$35, _p$.e));
30792
+ _v$36 !== _p$.t && (_p$.t = setProp(_el$86, "attributes", _v$36, _p$.t));
30793
+ _v$37 !== _p$.a && (_p$.a = setProp(_el$89, "fg", _v$37, _p$.a));
29918
30794
  return _p$;
29919
30795
  }, {
29920
30796
  e: undefined,
@@ -29924,6 +30800,36 @@ function SystemRow(props) {
29924
30800
  return _el$84;
29925
30801
  })();
29926
30802
  }
30803
+ function SystemRow(props) {
30804
+ const {
30805
+ theme
30806
+ } = useTheme();
30807
+ const isError = () => props.text.startsWith("error:") || props.text.startsWith("runTask failed");
30808
+ return (() => {
30809
+ var _el$96 = createElement("box"), _el$97 = createElement("text"), _el$99 = createElement("box"), _el$100 = createElement("text");
30810
+ insertNode(_el$96, _el$97);
30811
+ insertNode(_el$96, _el$99);
30812
+ setProp(_el$96, "paddingTop", 1);
30813
+ setProp(_el$96, "flexDirection", "row");
30814
+ setProp(_el$96, "gap", 1);
30815
+ insertNode(_el$97, createTextNode(`\u203B`));
30816
+ insertNode(_el$99, _el$100);
30817
+ setProp(_el$99, "flexGrow", 1);
30818
+ insert(_el$100, () => props.text);
30819
+ effect((_p$) => {
30820
+ var _v$38 = theme.textMuted, _v$39 = TextAttributes23.DIM, _v$40 = isError() ? theme.error : theme.textMuted;
30821
+ _v$38 !== _p$.e && (_p$.e = setProp(_el$97, "fg", _v$38, _p$.e));
30822
+ _v$39 !== _p$.t && (_p$.t = setProp(_el$97, "attributes", _v$39, _p$.t));
30823
+ _v$40 !== _p$.a && (_p$.a = setProp(_el$100, "fg", _v$40, _p$.a));
30824
+ return _p$;
30825
+ }, {
30826
+ e: undefined,
30827
+ t: undefined,
30828
+ a: undefined
30829
+ });
30830
+ return _el$96;
30831
+ })();
30832
+ }
29927
30833
  function ApprovalRow(props) {
29928
30834
  const {
29929
30835
  theme
@@ -29952,104 +30858,104 @@ function ApprovalRow(props) {
29952
30858
  return "\u25C6";
29953
30859
  };
29954
30860
  return (() => {
29955
- var _el$89 = createElement("box"), _el$90 = createElement("box"), _el$91 = createElement("text"), _el$92 = createElement("text"), _el$97 = createElement("box"), _el$98 = createElement("box");
29956
- insertNode(_el$89, _el$90);
29957
- insertNode(_el$89, _el$97);
29958
- insertNode(_el$89, _el$98);
29959
- setProp(_el$89, "paddingTop", 1);
29960
- setProp(_el$89, "flexDirection", "column");
29961
- setProp(_el$89, "gap", 0);
29962
- insertNode(_el$90, _el$91);
29963
- insertNode(_el$90, _el$92);
29964
- setProp(_el$90, "flexDirection", "row");
29965
- setProp(_el$90, "gap", 1);
29966
- insert(_el$91, headerGlyph);
29967
- insert(_el$92, headerText);
29968
- insert(_el$89, createComponent2(Show, {
30861
+ var _el$101 = createElement("box"), _el$102 = createElement("box"), _el$103 = createElement("text"), _el$104 = createElement("text"), _el$109 = createElement("box"), _el$110 = createElement("box");
30862
+ insertNode(_el$101, _el$102);
30863
+ insertNode(_el$101, _el$109);
30864
+ insertNode(_el$101, _el$110);
30865
+ setProp(_el$101, "paddingTop", 1);
30866
+ setProp(_el$101, "flexDirection", "column");
30867
+ setProp(_el$101, "gap", 0);
30868
+ insertNode(_el$102, _el$103);
30869
+ insertNode(_el$102, _el$104);
30870
+ setProp(_el$102, "flexDirection", "row");
30871
+ setProp(_el$102, "gap", 1);
30872
+ insert(_el$103, headerGlyph);
30873
+ insert(_el$104, headerText);
30874
+ insert(_el$101, createComponent2(Show, {
29969
30875
  get when() {
29970
30876
  return r2().filePath;
29971
30877
  },
29972
30878
  get children() {
29973
- var _el$93 = createElement("box"), _el$94 = createElement("text"), _el$95 = createTextNode(`\u23BF Plan file: `);
29974
- insertNode(_el$93, _el$94);
29975
- setProp(_el$93, "paddingLeft", 2);
29976
- insertNode(_el$94, _el$95);
29977
- insert(_el$94, () => r2().filePath, null);
29978
- effect((_$p) => setProp(_el$94, "fg", theme.textMuted, _$p));
29979
- return _el$93;
29980
- }
29981
- }), _el$97);
29982
- setProp(_el$97, "paddingLeft", 2);
29983
- setProp(_el$97, "paddingTop", 1);
29984
- insert(_el$97, createComponent2(Markdown, {
30879
+ var _el$105 = createElement("box"), _el$106 = createElement("text"), _el$107 = createTextNode(`\u23BF Plan file: `);
30880
+ insertNode(_el$105, _el$106);
30881
+ setProp(_el$105, "paddingLeft", 2);
30882
+ insertNode(_el$106, _el$107);
30883
+ insert(_el$106, () => r2().filePath, null);
30884
+ effect((_$p) => setProp(_el$106, "fg", theme.textMuted, _$p));
30885
+ return _el$105;
30886
+ }
30887
+ }), _el$109);
30888
+ setProp(_el$109, "paddingLeft", 2);
30889
+ setProp(_el$109, "paddingTop", 1);
30890
+ insert(_el$109, createComponent2(Markdown, {
29985
30891
  get source() {
29986
30892
  return r2().plan || "(empty plan)";
29987
30893
  }
29988
30894
  }));
29989
- setProp(_el$98, "paddingLeft", 2);
29990
- setProp(_el$98, "paddingTop", 1);
29991
- setProp(_el$98, "flexDirection", "row");
29992
- setProp(_el$98, "gap", 2);
29993
- insert(_el$98, createComponent2(Show, {
30895
+ setProp(_el$110, "paddingLeft", 2);
30896
+ setProp(_el$110, "paddingTop", 1);
30897
+ setProp(_el$110, "flexDirection", "row");
30898
+ setProp(_el$110, "gap", 2);
30899
+ insert(_el$110, createComponent2(Show, {
29994
30900
  get when() {
29995
30901
  return isPending();
29996
30902
  },
29997
30903
  get fallback() {
29998
30904
  return (() => {
29999
- var _el$103 = createElement("text"), _el$104 = createTextNode(`[`), _el$105 = createTextNode(`]`);
30000
- insertNode(_el$103, _el$104);
30001
- insertNode(_el$103, _el$105);
30002
- insert(_el$103, () => r2().status, _el$105);
30905
+ var _el$115 = createElement("text"), _el$116 = createTextNode(`[`), _el$117 = createTextNode(`]`);
30906
+ insertNode(_el$115, _el$116);
30907
+ insertNode(_el$115, _el$117);
30908
+ insert(_el$115, () => r2().status, _el$117);
30003
30909
  effect((_p$) => {
30004
- var _v$44 = r2().status === "approved" ? theme.success : theme.error, _v$45 = TextAttributes23.BOLD;
30005
- _v$44 !== _p$.e && (_p$.e = setProp(_el$103, "fg", _v$44, _p$.e));
30006
- _v$45 !== _p$.t && (_p$.t = setProp(_el$103, "attributes", _v$45, _p$.t));
30910
+ var _v$49 = r2().status === "approved" ? theme.success : theme.error, _v$50 = TextAttributes23.BOLD;
30911
+ _v$49 !== _p$.e && (_p$.e = setProp(_el$115, "fg", _v$49, _p$.e));
30912
+ _v$50 !== _p$.t && (_p$.t = setProp(_el$115, "attributes", _v$50, _p$.t));
30007
30913
  return _p$;
30008
30914
  }, {
30009
30915
  e: undefined,
30010
30916
  t: undefined
30011
30917
  });
30012
- return _el$103;
30918
+ return _el$115;
30013
30919
  })();
30014
30920
  },
30015
30921
  get children() {
30016
30922
  return [(() => {
30017
- var _el$99 = createElement("text");
30018
- insertNode(_el$99, createTextNode(`[ Approve ]`));
30019
- setProp(_el$99, "onMouseUp", () => props.onApprove(true));
30923
+ var _el$111 = createElement("text");
30924
+ insertNode(_el$111, createTextNode(`[ Approve ]`));
30925
+ setProp(_el$111, "onMouseUp", () => props.onApprove(true));
30020
30926
  effect((_p$) => {
30021
- var _v$36 = theme.success, _v$37 = TextAttributes23.BOLD;
30022
- _v$36 !== _p$.e && (_p$.e = setProp(_el$99, "fg", _v$36, _p$.e));
30023
- _v$37 !== _p$.t && (_p$.t = setProp(_el$99, "attributes", _v$37, _p$.t));
30927
+ var _v$41 = theme.success, _v$42 = TextAttributes23.BOLD;
30928
+ _v$41 !== _p$.e && (_p$.e = setProp(_el$111, "fg", _v$41, _p$.e));
30929
+ _v$42 !== _p$.t && (_p$.t = setProp(_el$111, "attributes", _v$42, _p$.t));
30024
30930
  return _p$;
30025
30931
  }, {
30026
30932
  e: undefined,
30027
30933
  t: undefined
30028
30934
  });
30029
- return _el$99;
30935
+ return _el$111;
30030
30936
  })(), (() => {
30031
- var _el$101 = createElement("text");
30032
- insertNode(_el$101, createTextNode(`[ Reject ]`));
30033
- setProp(_el$101, "onMouseUp", () => props.onApprove(false));
30937
+ var _el$113 = createElement("text");
30938
+ insertNode(_el$113, createTextNode(`[ Reject ]`));
30939
+ setProp(_el$113, "onMouseUp", () => props.onApprove(false));
30034
30940
  effect((_p$) => {
30035
- var _v$38 = theme.error, _v$39 = TextAttributes23.BOLD;
30036
- _v$38 !== _p$.e && (_p$.e = setProp(_el$101, "fg", _v$38, _p$.e));
30037
- _v$39 !== _p$.t && (_p$.t = setProp(_el$101, "attributes", _v$39, _p$.t));
30941
+ var _v$43 = theme.error, _v$44 = TextAttributes23.BOLD;
30942
+ _v$43 !== _p$.e && (_p$.e = setProp(_el$113, "fg", _v$43, _p$.e));
30943
+ _v$44 !== _p$.t && (_p$.t = setProp(_el$113, "attributes", _v$44, _p$.t));
30038
30944
  return _p$;
30039
30945
  }, {
30040
30946
  e: undefined,
30041
30947
  t: undefined
30042
30948
  });
30043
- return _el$101;
30949
+ return _el$113;
30044
30950
  })()];
30045
30951
  }
30046
30952
  }));
30047
30953
  effect((_p$) => {
30048
- var _v$40 = headerColor(), _v$41 = TextAttributes23.BOLD, _v$42 = headerColor(), _v$43 = TextAttributes23.BOLD;
30049
- _v$40 !== _p$.e && (_p$.e = setProp(_el$91, "fg", _v$40, _p$.e));
30050
- _v$41 !== _p$.t && (_p$.t = setProp(_el$91, "attributes", _v$41, _p$.t));
30051
- _v$42 !== _p$.a && (_p$.a = setProp(_el$92, "fg", _v$42, _p$.a));
30052
- _v$43 !== _p$.o && (_p$.o = setProp(_el$92, "attributes", _v$43, _p$.o));
30954
+ var _v$45 = headerColor(), _v$46 = TextAttributes23.BOLD, _v$47 = headerColor(), _v$48 = TextAttributes23.BOLD;
30955
+ _v$45 !== _p$.e && (_p$.e = setProp(_el$103, "fg", _v$45, _p$.e));
30956
+ _v$46 !== _p$.t && (_p$.t = setProp(_el$103, "attributes", _v$46, _p$.t));
30957
+ _v$47 !== _p$.a && (_p$.a = setProp(_el$104, "fg", _v$47, _p$.a));
30958
+ _v$48 !== _p$.o && (_p$.o = setProp(_el$104, "attributes", _v$48, _p$.o));
30053
30959
  return _p$;
30054
30960
  }, {
30055
30961
  e: undefined,
@@ -30057,7 +30963,7 @@ function ApprovalRow(props) {
30057
30963
  a: undefined,
30058
30964
  o: undefined
30059
30965
  });
30060
- return _el$89;
30966
+ return _el$101;
30061
30967
  })();
30062
30968
  }
30063
30969
  function QuestionRow(props) {
@@ -30220,18 +31126,18 @@ function QuestionRow(props) {
30220
31126
  })
30221
31127
  }));
30222
31128
  return (() => {
30223
- var _el$106 = createElement("box"), _el$107 = createElement("box"), _el$108 = createElement("text"), _el$110 = createElement("text");
30224
- insertNode(_el$106, _el$107);
30225
- setProp(_el$106, "paddingTop", 1);
30226
- setProp(_el$106, "flexDirection", "column");
30227
- setProp(_el$106, "gap", 0);
30228
- insertNode(_el$107, _el$108);
30229
- insertNode(_el$107, _el$110);
30230
- setProp(_el$107, "flexDirection", "row");
30231
- setProp(_el$107, "gap", 1);
30232
- insertNode(_el$108, createTextNode(`\u25C6`));
30233
- insert(_el$110, () => isAnswered() ? "Answered" : "Awaiting your answer");
30234
- insert(_el$106, createComponent2(For, {
31129
+ var _el$118 = createElement("box"), _el$119 = createElement("box"), _el$120 = createElement("text"), _el$122 = createElement("text");
31130
+ insertNode(_el$118, _el$119);
31131
+ setProp(_el$118, "paddingTop", 1);
31132
+ setProp(_el$118, "flexDirection", "column");
31133
+ setProp(_el$118, "gap", 0);
31134
+ insertNode(_el$119, _el$120);
31135
+ insertNode(_el$119, _el$122);
31136
+ setProp(_el$119, "flexDirection", "row");
31137
+ setProp(_el$119, "gap", 1);
31138
+ insertNode(_el$120, createTextNode(`\u25C6`));
31139
+ insert(_el$122, () => isAnswered() ? "Answered" : "Awaiting your answer");
31140
+ insert(_el$118, createComponent2(For, {
30235
31141
  get each() {
30236
31142
  return r2().questions;
30237
31143
  },
@@ -30248,103 +31154,103 @@ function QuestionRow(props) {
30248
31154
  return !isFuture();
30249
31155
  },
30250
31156
  get children() {
30251
- var _el$114 = createElement("box"), _el$115 = createElement("box"), _el$119 = createElement("text");
30252
- insertNode(_el$114, _el$115);
30253
- setProp(_el$114, "paddingLeft", 2);
30254
- setProp(_el$114, "paddingTop", 1);
30255
- setProp(_el$114, "flexDirection", "column");
30256
- setProp(_el$114, "gap", 0);
30257
- insertNode(_el$115, _el$119);
30258
- setProp(_el$115, "flexDirection", "row");
30259
- setProp(_el$115, "gap", 1);
30260
- insert(_el$115, createComponent2(Show, {
31157
+ var _el$126 = createElement("box"), _el$127 = createElement("box"), _el$131 = createElement("text");
31158
+ insertNode(_el$126, _el$127);
31159
+ setProp(_el$126, "paddingLeft", 2);
31160
+ setProp(_el$126, "paddingTop", 1);
31161
+ setProp(_el$126, "flexDirection", "column");
31162
+ setProp(_el$126, "gap", 0);
31163
+ insertNode(_el$127, _el$131);
31164
+ setProp(_el$127, "flexDirection", "row");
31165
+ setProp(_el$127, "gap", 1);
31166
+ insert(_el$127, createComponent2(Show, {
30261
31167
  get when() {
30262
31168
  return q2.header;
30263
31169
  },
30264
31170
  get children() {
30265
- var _el$116 = createElement("text"), _el$117 = createTextNode(`[`), _el$118 = createTextNode(`]`);
30266
- insertNode(_el$116, _el$117);
30267
- insertNode(_el$116, _el$118);
30268
- insert(_el$116, () => q2.header, _el$118);
31171
+ var _el$128 = createElement("text"), _el$129 = createTextNode(`[`), _el$130 = createTextNode(`]`);
31172
+ insertNode(_el$128, _el$129);
31173
+ insertNode(_el$128, _el$130);
31174
+ insert(_el$128, () => q2.header, _el$130);
30269
31175
  effect((_p$) => {
30270
- var _v$52 = theme.accent, _v$53 = TextAttributes23.BOLD;
30271
- _v$52 !== _p$.e && (_p$.e = setProp(_el$116, "fg", _v$52, _p$.e));
30272
- _v$53 !== _p$.t && (_p$.t = setProp(_el$116, "attributes", _v$53, _p$.t));
31176
+ var _v$57 = theme.accent, _v$58 = TextAttributes23.BOLD;
31177
+ _v$57 !== _p$.e && (_p$.e = setProp(_el$128, "fg", _v$57, _p$.e));
31178
+ _v$58 !== _p$.t && (_p$.t = setProp(_el$128, "attributes", _v$58, _p$.t));
30273
31179
  return _p$;
30274
31180
  }, {
30275
31181
  e: undefined,
30276
31182
  t: undefined
30277
31183
  });
30278
- return _el$116;
31184
+ return _el$128;
30279
31185
  }
30280
- }), _el$119);
30281
- insert(_el$119, () => q2.question);
30282
- insert(_el$115, createComponent2(Show, {
31186
+ }), _el$131);
31187
+ insert(_el$131, () => q2.question);
31188
+ insert(_el$127, createComponent2(Show, {
30283
31189
  get when() {
30284
31190
  return memo2(() => !!q2.multiSelect)() && isCurrent();
30285
31191
  },
30286
31192
  get children() {
30287
- var _el$120 = createElement("text");
30288
- insertNode(_el$120, createTextNode(`(pick any)`));
30289
- effect((_$p) => setProp(_el$120, "fg", theme.textMuted, _$p));
30290
- return _el$120;
31193
+ var _el$132 = createElement("text");
31194
+ insertNode(_el$132, createTextNode(`(pick any)`));
31195
+ effect((_$p) => setProp(_el$132, "fg", theme.textMuted, _$p));
31196
+ return _el$132;
30291
31197
  }
30292
31198
  }), null);
30293
- insert(_el$115, createComponent2(Show, {
31199
+ insert(_el$127, createComponent2(Show, {
30294
31200
  get when() {
30295
31201
  return isPast();
30296
31202
  },
30297
31203
  get children() {
30298
- var _el$122 = createElement("text");
30299
- insertNode(_el$122, createTextNode(`(click to edit)`));
30300
- effect((_$p) => setProp(_el$122, "fg", theme.textMuted, _$p));
30301
- return _el$122;
31204
+ var _el$134 = createElement("text");
31205
+ insertNode(_el$134, createTextNode(`(click to edit)`));
31206
+ effect((_$p) => setProp(_el$134, "fg", theme.textMuted, _$p));
31207
+ return _el$134;
30302
31208
  }
30303
31209
  }), null);
30304
- insert(_el$114, createComponent2(Show, {
31210
+ insert(_el$126, createComponent2(Show, {
30305
31211
  get when() {
30306
31212
  return isAnswered();
30307
31213
  },
30308
31214
  get children() {
30309
- var _el$124 = createElement("box"), _el$125 = createElement("text"), _el$126 = createTextNode(`\u23BF `);
30310
- insertNode(_el$124, _el$125);
30311
- setProp(_el$124, "paddingLeft", 2);
30312
- insertNode(_el$125, _el$126);
30313
- insert(_el$125, (() => {
31215
+ var _el$136 = createElement("box"), _el$137 = createElement("text"), _el$138 = createTextNode(`\u23BF `);
31216
+ insertNode(_el$136, _el$137);
31217
+ setProp(_el$136, "paddingLeft", 2);
31218
+ insertNode(_el$137, _el$138);
31219
+ insert(_el$137, (() => {
30314
31220
  var _c$2 = memo2(() => !!(finalAnswer() && finalAnswer().length > 0));
30315
31221
  return () => _c$2() ? finalAnswer() : "(no answer)";
30316
31222
  })(), null);
30317
- effect((_$p) => setProp(_el$125, "fg", theme.success, _$p));
30318
- return _el$124;
31223
+ effect((_$p) => setProp(_el$137, "fg", theme.success, _$p));
31224
+ return _el$136;
30319
31225
  }
30320
31226
  }), null);
30321
- insert(_el$114, createComponent2(Show, {
31227
+ insert(_el$126, createComponent2(Show, {
30322
31228
  get when() {
30323
31229
  return isPast();
30324
31230
  },
30325
31231
  get children() {
30326
- var _el$127 = createElement("box"), _el$128 = createElement("text"), _el$129 = createTextNode(`\u23BF `);
30327
- insertNode(_el$127, _el$128);
30328
- setProp(_el$127, "paddingLeft", 2);
30329
- insertNode(_el$128, _el$129);
30330
- insert(_el$128, (() => {
31232
+ var _el$139 = createElement("box"), _el$140 = createElement("text"), _el$141 = createTextNode(`\u23BF `);
31233
+ insertNode(_el$139, _el$140);
31234
+ setProp(_el$139, "paddingLeft", 2);
31235
+ insertNode(_el$140, _el$141);
31236
+ insert(_el$140, (() => {
30331
31237
  var _c$3 = memo2(() => renderedAnswerFor(q2).length > 0);
30332
31238
  return () => _c$3() ? renderedAnswerFor(q2) : "(no answer)";
30333
31239
  })(), null);
30334
- effect((_$p) => setProp(_el$128, "fg", theme.textMuted, _$p));
30335
- return _el$127;
31240
+ effect((_$p) => setProp(_el$140, "fg", theme.textMuted, _$p));
31241
+ return _el$139;
30336
31242
  }
30337
31243
  }), null);
30338
- insert(_el$114, createComponent2(Show, {
31244
+ insert(_el$126, createComponent2(Show, {
30339
31245
  get when() {
30340
31246
  return isCurrent();
30341
31247
  },
30342
31248
  get children() {
30343
- var _el$130 = createElement("box"), _el$131 = createElement("box"), _el$132 = createElement("text");
30344
- insertNode(_el$130, _el$131);
30345
- setProp(_el$130, "paddingLeft", 2);
30346
- setProp(_el$130, "flexDirection", "column");
30347
- insert(_el$130, createComponent2(For, {
31249
+ var _el$142 = createElement("box"), _el$143 = createElement("box"), _el$144 = createElement("text");
31250
+ insertNode(_el$142, _el$143);
31251
+ setProp(_el$142, "paddingLeft", 2);
31252
+ setProp(_el$142, "flexDirection", "column");
31253
+ insert(_el$142, createComponent2(For, {
30348
31254
  get each() {
30349
31255
  return q2.options;
30350
31256
  },
@@ -30354,40 +31260,40 @@ function QuestionRow(props) {
30354
31260
  const glyph = () => q2.multiSelect ? isPicked() ? "[x]" : "[ ]" : isPicked() ? "(\u2022)" : "( )";
30355
31261
  const digitChip = () => optIndex() < 9 ? `${optIndex() + 1}.` : " ";
30356
31262
  return (() => {
30357
- 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");
30358
- insertNode(_el$135, _el$136);
30359
- insertNode(_el$135, _el$137);
30360
- insertNode(_el$135, _el$138);
30361
- insertNode(_el$135, _el$139);
30362
- setProp(_el$135, "flexDirection", "row");
30363
- setProp(_el$135, "gap", 1);
30364
- setProp(_el$135, "onMouseUp", () => toggle(q2.question, q2.multiSelect, opt.label));
30365
- insert(_el$136, () => isHl() ? ">" : " ");
30366
- insert(_el$137, digitChip);
30367
- insert(_el$138, glyph);
30368
- insertNode(_el$139, _el$140);
30369
- setProp(_el$139, "flexGrow", 1);
30370
- setProp(_el$139, "flexDirection", "column");
30371
- insert(_el$140, () => opt.label);
30372
- insert(_el$139, createComponent2(Show, {
31263
+ var _el$147 = createElement("box"), _el$148 = createElement("text"), _el$149 = createElement("text"), _el$150 = createElement("text"), _el$151 = createElement("box"), _el$152 = createElement("text");
31264
+ insertNode(_el$147, _el$148);
31265
+ insertNode(_el$147, _el$149);
31266
+ insertNode(_el$147, _el$150);
31267
+ insertNode(_el$147, _el$151);
31268
+ setProp(_el$147, "flexDirection", "row");
31269
+ setProp(_el$147, "gap", 1);
31270
+ setProp(_el$147, "onMouseUp", () => toggle(q2.question, q2.multiSelect, opt.label));
31271
+ insert(_el$148, () => isHl() ? ">" : " ");
31272
+ insert(_el$149, digitChip);
31273
+ insert(_el$150, glyph);
31274
+ insertNode(_el$151, _el$152);
31275
+ setProp(_el$151, "flexGrow", 1);
31276
+ setProp(_el$151, "flexDirection", "column");
31277
+ insert(_el$152, () => opt.label);
31278
+ insert(_el$151, createComponent2(Show, {
30373
31279
  get when() {
30374
31280
  return opt.description;
30375
31281
  },
30376
31282
  get children() {
30377
- var _el$141 = createElement("text");
30378
- insert(_el$141, () => opt.description);
30379
- effect((_$p) => setProp(_el$141, "fg", theme.textMuted, _$p));
30380
- return _el$141;
31283
+ var _el$153 = createElement("text");
31284
+ insert(_el$153, () => opt.description);
31285
+ effect((_$p) => setProp(_el$153, "fg", theme.textMuted, _$p));
31286
+ return _el$153;
30381
31287
  }
30382
31288
  }), null);
30383
31289
  effect((_p$) => {
30384
- var _v$58 = isHl() ? theme.accent : theme.textMuted, _v$59 = TextAttributes23.BOLD, _v$60 = theme.textMuted, _v$61 = isPicked() ? theme.accent : theme.textMuted, _v$62 = TextAttributes23.BOLD, _v$63 = theme.text;
30385
- _v$58 !== _p$.e && (_p$.e = setProp(_el$136, "fg", _v$58, _p$.e));
30386
- _v$59 !== _p$.t && (_p$.t = setProp(_el$136, "attributes", _v$59, _p$.t));
30387
- _v$60 !== _p$.a && (_p$.a = setProp(_el$137, "fg", _v$60, _p$.a));
30388
- _v$61 !== _p$.o && (_p$.o = setProp(_el$138, "fg", _v$61, _p$.o));
30389
- _v$62 !== _p$.i && (_p$.i = setProp(_el$138, "attributes", _v$62, _p$.i));
30390
- _v$63 !== _p$.n && (_p$.n = setProp(_el$140, "fg", _v$63, _p$.n));
31290
+ var _v$63 = isHl() ? theme.accent : theme.textMuted, _v$64 = TextAttributes23.BOLD, _v$65 = theme.textMuted, _v$66 = isPicked() ? theme.accent : theme.textMuted, _v$67 = TextAttributes23.BOLD, _v$68 = theme.text;
31291
+ _v$63 !== _p$.e && (_p$.e = setProp(_el$148, "fg", _v$63, _p$.e));
31292
+ _v$64 !== _p$.t && (_p$.t = setProp(_el$148, "attributes", _v$64, _p$.t));
31293
+ _v$65 !== _p$.a && (_p$.a = setProp(_el$149, "fg", _v$65, _p$.a));
31294
+ _v$66 !== _p$.o && (_p$.o = setProp(_el$150, "fg", _v$66, _p$.o));
31295
+ _v$67 !== _p$.i && (_p$.i = setProp(_el$150, "attributes", _v$67, _p$.i));
31296
+ _v$68 !== _p$.n && (_p$.n = setProp(_el$152, "fg", _v$68, _p$.n));
30391
31297
  return _p$;
30392
31298
  }, {
30393
31299
  e: undefined,
@@ -30397,43 +31303,43 @@ function QuestionRow(props) {
30397
31303
  i: undefined,
30398
31304
  n: undefined
30399
31305
  });
30400
- return _el$135;
31306
+ return _el$147;
30401
31307
  })();
30402
31308
  }
30403
- }), _el$131);
30404
- insert(_el$130, () => {
31309
+ }), _el$143);
31310
+ insert(_el$142, () => {
30405
31311
  const otherPicked = () => picked().has(OTHER_SENTINEL);
30406
31312
  const otherIdx = q2.options.length;
30407
31313
  const isOtherHl = () => highlighted() === otherIdx;
30408
31314
  const otherGlyph = () => q2.multiSelect ? otherPicked() ? "[x]" : "[ ]" : otherPicked() ? "(\u2022)" : "( )";
30409
31315
  const otherDigitChip = () => otherIdx < 9 ? `${otherIdx + 1}.` : " ";
30410
31316
  return [(() => {
30411
- 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");
30412
- insertNode(_el$142, _el$143);
30413
- insertNode(_el$142, _el$144);
30414
- insertNode(_el$142, _el$145);
30415
- insertNode(_el$142, _el$146);
30416
- setProp(_el$142, "flexDirection", "row");
30417
- setProp(_el$142, "gap", 1);
30418
- setProp(_el$142, "onMouseUp", () => toggle(q2.question, q2.multiSelect, OTHER_SENTINEL));
30419
- insert(_el$143, () => isOtherHl() ? ">" : " ");
30420
- insert(_el$144, otherDigitChip);
30421
- insert(_el$145, otherGlyph);
30422
- insertNode(_el$146, _el$147);
30423
- insertNode(_el$146, _el$149);
30424
- setProp(_el$146, "flexGrow", 1);
30425
- setProp(_el$146, "flexDirection", "column");
30426
- insertNode(_el$147, createTextNode(`Other`));
30427
- insertNode(_el$149, createTextNode(`Type your own answer`));
31317
+ var _el$154 = createElement("box"), _el$155 = createElement("text"), _el$156 = createElement("text"), _el$157 = createElement("text"), _el$158 = createElement("box"), _el$159 = createElement("text"), _el$161 = createElement("text");
31318
+ insertNode(_el$154, _el$155);
31319
+ insertNode(_el$154, _el$156);
31320
+ insertNode(_el$154, _el$157);
31321
+ insertNode(_el$154, _el$158);
31322
+ setProp(_el$154, "flexDirection", "row");
31323
+ setProp(_el$154, "gap", 1);
31324
+ setProp(_el$154, "onMouseUp", () => toggle(q2.question, q2.multiSelect, OTHER_SENTINEL));
31325
+ insert(_el$155, () => isOtherHl() ? ">" : " ");
31326
+ insert(_el$156, otherDigitChip);
31327
+ insert(_el$157, otherGlyph);
31328
+ insertNode(_el$158, _el$159);
31329
+ insertNode(_el$158, _el$161);
31330
+ setProp(_el$158, "flexGrow", 1);
31331
+ setProp(_el$158, "flexDirection", "column");
31332
+ insertNode(_el$159, createTextNode(`Other`));
31333
+ insertNode(_el$161, createTextNode(`Type your own answer`));
30428
31334
  effect((_p$) => {
30429
- var _v$64 = isOtherHl() ? theme.accent : theme.textMuted, _v$65 = TextAttributes23.BOLD, _v$66 = theme.textMuted, _v$67 = otherPicked() ? theme.accent : theme.textMuted, _v$68 = TextAttributes23.BOLD, _v$69 = theme.text, _v$70 = theme.textMuted;
30430
- _v$64 !== _p$.e && (_p$.e = setProp(_el$143, "fg", _v$64, _p$.e));
30431
- _v$65 !== _p$.t && (_p$.t = setProp(_el$143, "attributes", _v$65, _p$.t));
30432
- _v$66 !== _p$.a && (_p$.a = setProp(_el$144, "fg", _v$66, _p$.a));
30433
- _v$67 !== _p$.o && (_p$.o = setProp(_el$145, "fg", _v$67, _p$.o));
30434
- _v$68 !== _p$.i && (_p$.i = setProp(_el$145, "attributes", _v$68, _p$.i));
30435
- _v$69 !== _p$.n && (_p$.n = setProp(_el$147, "fg", _v$69, _p$.n));
30436
- _v$70 !== _p$.s && (_p$.s = setProp(_el$149, "fg", _v$70, _p$.s));
31335
+ var _v$69 = isOtherHl() ? theme.accent : theme.textMuted, _v$70 = TextAttributes23.BOLD, _v$71 = theme.textMuted, _v$72 = otherPicked() ? theme.accent : theme.textMuted, _v$73 = TextAttributes23.BOLD, _v$74 = theme.text, _v$75 = theme.textMuted;
31336
+ _v$69 !== _p$.e && (_p$.e = setProp(_el$155, "fg", _v$69, _p$.e));
31337
+ _v$70 !== _p$.t && (_p$.t = setProp(_el$155, "attributes", _v$70, _p$.t));
31338
+ _v$71 !== _p$.a && (_p$.a = setProp(_el$156, "fg", _v$71, _p$.a));
31339
+ _v$72 !== _p$.o && (_p$.o = setProp(_el$157, "fg", _v$72, _p$.o));
31340
+ _v$73 !== _p$.i && (_p$.i = setProp(_el$157, "attributes", _v$73, _p$.i));
31341
+ _v$74 !== _p$.n && (_p$.n = setProp(_el$159, "fg", _v$74, _p$.n));
31342
+ _v$75 !== _p$.s && (_p$.s = setProp(_el$161, "fg", _v$75, _p$.s));
30437
31343
  return _p$;
30438
31344
  }, {
30439
31345
  e: undefined,
@@ -30444,97 +31350,97 @@ function QuestionRow(props) {
30444
31350
  n: undefined,
30445
31351
  s: undefined
30446
31352
  });
30447
- return _el$142;
31353
+ return _el$154;
30448
31354
  })(), createComponent2(Show, {
30449
31355
  get when() {
30450
31356
  return otherPicked();
30451
31357
  },
30452
31358
  get children() {
30453
- var _el$151 = createElement("box"), _el$152 = createElement("input");
30454
- insertNode(_el$151, _el$152);
30455
- setProp(_el$151, "paddingLeft", 4);
30456
- setProp(_el$151, "paddingTop", 0);
30457
- setProp(_el$152, "placeholder", "type your answer\u2026");
30458
- setProp(_el$152, "focused", true);
30459
- setProp(_el$152, "onInput", (v2) => setCustomText(q2.question, v2));
30460
- setProp(_el$152, "onSubmit", () => advanceOrSubmit());
30461
- effect((_$p) => setProp(_el$152, "value", customTextFor(q2.question), _$p));
30462
- return _el$151;
31359
+ var _el$163 = createElement("box"), _el$164 = createElement("input");
31360
+ insertNode(_el$163, _el$164);
31361
+ setProp(_el$163, "paddingLeft", 4);
31362
+ setProp(_el$163, "paddingTop", 0);
31363
+ setProp(_el$164, "placeholder", "type your answer\u2026");
31364
+ setProp(_el$164, "focused", true);
31365
+ setProp(_el$164, "onInput", (v2) => setCustomText(q2.question, v2));
31366
+ setProp(_el$164, "onSubmit", () => advanceOrSubmit());
31367
+ effect((_$p) => setProp(_el$164, "value", customTextFor(q2.question), _$p));
31368
+ return _el$163;
30463
31369
  }
30464
31370
  })];
30465
- }, _el$131);
30466
- insertNode(_el$131, _el$132);
30467
- setProp(_el$131, "paddingLeft", 0);
30468
- setProp(_el$131, "paddingTop", 1);
30469
- setProp(_el$131, "flexDirection", "row");
30470
- setProp(_el$131, "gap", 2);
30471
- setProp(_el$132, "onMouseUp", () => advanceOrSubmit());
30472
- insert(_el$132, buttonLabel);
30473
- insert(_el$131, createComponent2(Show, {
31371
+ }, _el$143);
31372
+ insertNode(_el$143, _el$144);
31373
+ setProp(_el$143, "paddingLeft", 0);
31374
+ setProp(_el$143, "paddingTop", 1);
31375
+ setProp(_el$143, "flexDirection", "row");
31376
+ setProp(_el$143, "gap", 2);
31377
+ setProp(_el$144, "onMouseUp", () => advanceOrSubmit());
31378
+ insert(_el$144, buttonLabel);
31379
+ insert(_el$143, createComponent2(Show, {
30474
31380
  get when() {
30475
31381
  return !isQuestionComplete(index());
30476
31382
  },
30477
31383
  get children() {
30478
- var _el$133 = createElement("text");
30479
- insertNode(_el$133, createTextNode(`(pick an option to continue)`));
30480
- effect((_$p) => setProp(_el$133, "fg", theme.textMuted, _$p));
30481
- return _el$133;
31384
+ var _el$145 = createElement("text");
31385
+ insertNode(_el$145, createTextNode(`(pick an option to continue)`));
31386
+ effect((_$p) => setProp(_el$145, "fg", theme.textMuted, _$p));
31387
+ return _el$145;
30482
31388
  }
30483
31389
  }), null);
30484
31390
  effect((_p$) => {
30485
- var _v$54 = isQuestionComplete(index()) ? theme.success : theme.textMuted, _v$55 = TextAttributes23.BOLD;
30486
- _v$54 !== _p$.e && (_p$.e = setProp(_el$132, "fg", _v$54, _p$.e));
30487
- _v$55 !== _p$.t && (_p$.t = setProp(_el$132, "attributes", _v$55, _p$.t));
31391
+ var _v$59 = isQuestionComplete(index()) ? theme.success : theme.textMuted, _v$60 = TextAttributes23.BOLD;
31392
+ _v$59 !== _p$.e && (_p$.e = setProp(_el$144, "fg", _v$59, _p$.e));
31393
+ _v$60 !== _p$.t && (_p$.t = setProp(_el$144, "attributes", _v$60, _p$.t));
30488
31394
  return _p$;
30489
31395
  }, {
30490
31396
  e: undefined,
30491
31397
  t: undefined
30492
31398
  });
30493
- return _el$130;
31399
+ return _el$142;
30494
31400
  }
30495
31401
  }), null);
30496
31402
  effect((_p$) => {
30497
- var _v$56 = isPast() ? () => setCurrentIndex(index()) : undefined, _v$57 = isPast() ? theme.textMuted : theme.text;
30498
- _v$56 !== _p$.e && (_p$.e = setProp(_el$114, "onMouseUp", _v$56, _p$.e));
30499
- _v$57 !== _p$.t && (_p$.t = setProp(_el$119, "fg", _v$57, _p$.t));
31403
+ var _v$61 = isPast() ? () => setCurrentIndex(index()) : undefined, _v$62 = isPast() ? theme.textMuted : theme.text;
31404
+ _v$61 !== _p$.e && (_p$.e = setProp(_el$126, "onMouseUp", _v$61, _p$.e));
31405
+ _v$62 !== _p$.t && (_p$.t = setProp(_el$131, "fg", _v$62, _p$.t));
30500
31406
  return _p$;
30501
31407
  }, {
30502
31408
  e: undefined,
30503
31409
  t: undefined
30504
31410
  });
30505
- return _el$114;
31411
+ return _el$126;
30506
31412
  }
30507
31413
  });
30508
31414
  }
30509
31415
  }), null);
30510
- insert(_el$106, createComponent2(Show, {
31416
+ insert(_el$118, createComponent2(Show, {
30511
31417
  get when() {
30512
31418
  return isAnswered();
30513
31419
  },
30514
31420
  get children() {
30515
- var _el$111 = createElement("box"), _el$112 = createElement("text");
30516
- insertNode(_el$111, _el$112);
30517
- setProp(_el$111, "paddingLeft", 2);
30518
- setProp(_el$111, "paddingTop", 1);
30519
- insertNode(_el$112, createTextNode(`[submitted]`));
31421
+ var _el$123 = createElement("box"), _el$124 = createElement("text");
31422
+ insertNode(_el$123, _el$124);
31423
+ setProp(_el$123, "paddingLeft", 2);
31424
+ setProp(_el$123, "paddingTop", 1);
31425
+ insertNode(_el$124, createTextNode(`[submitted]`));
30520
31426
  effect((_p$) => {
30521
- var _v$46 = theme.success, _v$47 = TextAttributes23.BOLD;
30522
- _v$46 !== _p$.e && (_p$.e = setProp(_el$112, "fg", _v$46, _p$.e));
30523
- _v$47 !== _p$.t && (_p$.t = setProp(_el$112, "attributes", _v$47, _p$.t));
31427
+ var _v$51 = theme.success, _v$52 = TextAttributes23.BOLD;
31428
+ _v$51 !== _p$.e && (_p$.e = setProp(_el$124, "fg", _v$51, _p$.e));
31429
+ _v$52 !== _p$.t && (_p$.t = setProp(_el$124, "attributes", _v$52, _p$.t));
30524
31430
  return _p$;
30525
31431
  }, {
30526
31432
  e: undefined,
30527
31433
  t: undefined
30528
31434
  });
30529
- return _el$111;
31435
+ return _el$123;
30530
31436
  }
30531
31437
  }), null);
30532
31438
  effect((_p$) => {
30533
- var _v$48 = theme.warning, _v$49 = TextAttributes23.BOLD, _v$50 = theme.warning, _v$51 = TextAttributes23.BOLD;
30534
- _v$48 !== _p$.e && (_p$.e = setProp(_el$108, "fg", _v$48, _p$.e));
30535
- _v$49 !== _p$.t && (_p$.t = setProp(_el$108, "attributes", _v$49, _p$.t));
30536
- _v$50 !== _p$.a && (_p$.a = setProp(_el$110, "fg", _v$50, _p$.a));
30537
- _v$51 !== _p$.o && (_p$.o = setProp(_el$110, "attributes", _v$51, _p$.o));
31439
+ var _v$53 = theme.warning, _v$54 = TextAttributes23.BOLD, _v$55 = theme.warning, _v$56 = TextAttributes23.BOLD;
31440
+ _v$53 !== _p$.e && (_p$.e = setProp(_el$120, "fg", _v$53, _p$.e));
31441
+ _v$54 !== _p$.t && (_p$.t = setProp(_el$120, "attributes", _v$54, _p$.t));
31442
+ _v$55 !== _p$.a && (_p$.a = setProp(_el$122, "fg", _v$55, _p$.a));
31443
+ _v$56 !== _p$.o && (_p$.o = setProp(_el$122, "attributes", _v$56, _p$.o));
30538
31444
  return _p$;
30539
31445
  }, {
30540
31446
  e: undefined,
@@ -30542,7 +31448,7 @@ function QuestionRow(props) {
30542
31448
  a: undefined,
30543
31449
  o: undefined
30544
31450
  });
30545
- return _el$106;
31451
+ return _el$118;
30546
31452
  })();
30547
31453
  }
30548
31454
  function MessageList(props) {
@@ -30550,23 +31456,23 @@ function MessageList(props) {
30550
31456
  theme
30551
31457
  } = useTheme();
30552
31458
  return (() => {
30553
- var _el$153 = createElement("box");
30554
- setProp(_el$153, "flexDirection", "column");
30555
- setProp(_el$153, "gap", 0);
30556
- insert(_el$153, createComponent2(Show, {
31459
+ var _el$165 = createElement("box");
31460
+ setProp(_el$165, "flexDirection", "column");
31461
+ setProp(_el$165, "gap", 0);
31462
+ insert(_el$165, createComponent2(Show, {
30557
31463
  get when() {
30558
31464
  return memo2(() => props.messages.length === 0)() && props.showEmptyPlaceholder;
30559
31465
  },
30560
31466
  get children() {
30561
- var _el$154 = createElement("box"), _el$155 = createElement("text");
30562
- insertNode(_el$154, _el$155);
30563
- setProp(_el$154, "paddingTop", 2);
30564
- insertNode(_el$155, createTextNode(`Type a prompt below.`));
30565
- effect((_$p) => setProp(_el$155, "fg", theme.textMuted, _$p));
30566
- return _el$154;
31467
+ var _el$166 = createElement("box"), _el$167 = createElement("text");
31468
+ insertNode(_el$166, _el$167);
31469
+ setProp(_el$166, "paddingTop", 2);
31470
+ insertNode(_el$167, createTextNode(`Type a prompt below.`));
31471
+ effect((_$p) => setProp(_el$167, "fg", theme.textMuted, _$p));
31472
+ return _el$166;
30567
31473
  }
30568
31474
  }), null);
30569
- insert(_el$153, createComponent2(For, {
31475
+ insert(_el$165, createComponent2(For, {
30570
31476
  get each() {
30571
31477
  return groupRenderItems(props.messages, props.expandedFoldStartIndex);
30572
31478
  },
@@ -30607,6 +31513,10 @@ function MessageList(props) {
30607
31513
  return row.text;
30608
31514
  }
30609
31515
  });
31516
+ if (row.kind === "bash")
31517
+ return createComponent2(BashRow, {
31518
+ row
31519
+ });
30610
31520
  if (row.kind === "approval") {
30611
31521
  return createComponent2(ApprovalRow, {
30612
31522
  row,
@@ -30635,7 +31545,7 @@ function MessageList(props) {
30635
31545
  });
30636
31546
  }
30637
31547
  }), null);
30638
- return _el$153;
31548
+ return _el$165;
30639
31549
  })();
30640
31550
  }
30641
31551
  function groupRenderItems(messages, expandedFoldStartIndex = null) {
@@ -30755,29 +31665,29 @@ function ToolFoldRow(props) {
30755
31665
  const glyph = () => props.inFlight ? "\u273B" : props.expanded ? "\u25BC" : "\u25B6";
30756
31666
  const fg = () => props.inFlight ? theme.warning : theme.textMuted;
30757
31667
  return (() => {
30758
- var _el$157 = createElement("box"), _el$158 = createElement("text"), _el$159 = createElement("box"), _el$160 = createElement("text");
30759
- insertNode(_el$157, _el$158);
30760
- insertNode(_el$157, _el$159);
30761
- setProp(_el$157, "paddingTop", 1);
30762
- setProp(_el$157, "flexDirection", "row");
30763
- setProp(_el$157, "gap", 1);
30764
- setProp(_el$157, "onMouseUp", () => props.onToggle());
30765
- insert(_el$158, glyph);
30766
- insertNode(_el$159, _el$160);
30767
- setProp(_el$159, "flexGrow", 1);
30768
- insert(_el$160, () => props.summary);
31668
+ var _el$169 = createElement("box"), _el$170 = createElement("text"), _el$171 = createElement("box"), _el$172 = createElement("text");
31669
+ insertNode(_el$169, _el$170);
31670
+ insertNode(_el$169, _el$171);
31671
+ setProp(_el$169, "paddingTop", 1);
31672
+ setProp(_el$169, "flexDirection", "row");
31673
+ setProp(_el$169, "gap", 1);
31674
+ setProp(_el$169, "onMouseUp", () => props.onToggle());
31675
+ insert(_el$170, glyph);
31676
+ insertNode(_el$171, _el$172);
31677
+ setProp(_el$171, "flexGrow", 1);
31678
+ insert(_el$172, () => props.summary);
30769
31679
  effect((_p$) => {
30770
- var _v$71 = fg(), _v$72 = TextAttributes23.DIM, _v$73 = theme.textMuted;
30771
- _v$71 !== _p$.e && (_p$.e = setProp(_el$158, "fg", _v$71, _p$.e));
30772
- _v$72 !== _p$.t && (_p$.t = setProp(_el$158, "attributes", _v$72, _p$.t));
30773
- _v$73 !== _p$.a && (_p$.a = setProp(_el$160, "fg", _v$73, _p$.a));
31680
+ var _v$76 = fg(), _v$77 = TextAttributes23.DIM, _v$78 = theme.textMuted;
31681
+ _v$76 !== _p$.e && (_p$.e = setProp(_el$170, "fg", _v$76, _p$.e));
31682
+ _v$77 !== _p$.t && (_p$.t = setProp(_el$170, "attributes", _v$77, _p$.t));
31683
+ _v$78 !== _p$.a && (_p$.a = setProp(_el$172, "fg", _v$78, _p$.a));
30774
31684
  return _p$;
30775
31685
  }, {
30776
31686
  e: undefined,
30777
31687
  t: undefined,
30778
31688
  a: undefined
30779
31689
  });
30780
- return _el$157;
31690
+ return _el$169;
30781
31691
  })();
30782
31692
  }
30783
31693
  var BLACK_CIRCLE, OTHER_SENTINEL = "__kobe_other__", TOOL_FOLD_THRESHOLD = 3;
@@ -30800,6 +31710,104 @@ var init_MessageList = __esm(() => {
30800
31710
  BLACK_CIRCLE = process.platform === "darwin" ? "\u23FA" : "\u25CF";
30801
31711
  });
30802
31712
 
31713
+ // src/tui/panes/chat/bash-mode.ts
31714
+ import { spawn as spawn9 } from "child_process";
31715
+ async function runBashCommand(opts) {
31716
+ const shell = resolveShell();
31717
+ return await new Promise((resolve4, reject) => {
31718
+ let child;
31719
+ try {
31720
+ child = spawn9(shell, ["-c", opts.command], {
31721
+ cwd: opts.cwd,
31722
+ stdio: ["ignore", "pipe", "pipe"],
31723
+ env: process.env,
31724
+ detached: false
31725
+ });
31726
+ } catch (err) {
31727
+ reject(err);
31728
+ return;
31729
+ }
31730
+ let timeoutHandle;
31731
+ let settled = false;
31732
+ const finish = (result) => {
31733
+ if (settled)
31734
+ return;
31735
+ settled = true;
31736
+ if (timeoutHandle)
31737
+ clearTimeout(timeoutHandle);
31738
+ opts.signal.removeEventListener("abort", onAbort);
31739
+ resolve4(result);
31740
+ };
31741
+ child.stdout?.setEncoding("utf8");
31742
+ child.stderr?.setEncoding("utf8");
31743
+ child.stdout?.on("data", (chunk) => {
31744
+ opts.onStdout(chunk);
31745
+ });
31746
+ child.stderr?.on("data", (chunk) => {
31747
+ opts.onStderr(chunk);
31748
+ });
31749
+ child.on("error", (err) => {
31750
+ opts.onStderr(`(kobe: failed to spawn ${shell}: ${err.message})
31751
+ `);
31752
+ finish({ exitCode: ABORT_EXIT_CODE, signal: null });
31753
+ });
31754
+ child.on("exit", (code, signal) => {
31755
+ finish({ exitCode: code, signal: signal ?? null });
31756
+ });
31757
+ const onAbort = () => {
31758
+ if (settled)
31759
+ return;
31760
+ try {
31761
+ child.kill("SIGTERM");
31762
+ } catch {}
31763
+ setTimeout(() => {
31764
+ if (settled)
31765
+ return;
31766
+ try {
31767
+ child.kill("SIGKILL");
31768
+ } catch {}
31769
+ }, 500).unref();
31770
+ };
31771
+ if (opts.signal.aborted) {
31772
+ onAbort();
31773
+ } else {
31774
+ opts.signal.addEventListener("abort", onAbort, { once: true });
31775
+ }
31776
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
31777
+ timeoutHandle = setTimeout(() => {
31778
+ if (settled)
31779
+ return;
31780
+ opts.onStderr(`(kobe: command timed out after ${Math.round(timeoutMs / 1000)}s)
31781
+ `);
31782
+ try {
31783
+ child.kill("SIGTERM");
31784
+ } catch {}
31785
+ setTimeout(() => {
31786
+ if (settled)
31787
+ return;
31788
+ try {
31789
+ child.kill("SIGKILL");
31790
+ } catch {}
31791
+ }, 500).unref();
31792
+ }, timeoutMs);
31793
+ timeoutHandle.unref();
31794
+ });
31795
+ }
31796
+ function resolveShell() {
31797
+ const override = process.env.KOBE_BASH_SHELL;
31798
+ if (override && override.length > 0)
31799
+ return override;
31800
+ const userShell = process.env.SHELL ?? "";
31801
+ const base = userShell.split("/").pop() ?? "";
31802
+ if (base === "bash" || base === "zsh")
31803
+ return userShell;
31804
+ return "/bin/bash";
31805
+ }
31806
+ var DEFAULT_TIMEOUT_MS, ABORT_EXIT_CODE = -1;
31807
+ var init_bash_mode = __esm(() => {
31808
+ DEFAULT_TIMEOUT_MS = 30 * 60 * 1000;
31809
+ });
31810
+
30803
31811
  // src/tui/panes/chat/composer/model-picker-row.ts
30804
31812
  function modelPickerModelOptions(choices) {
30805
31813
  const byKey = new Map;
@@ -31180,10 +32188,10 @@ function permissionModeLabel(capabilities, mode) {
31180
32188
 
31181
32189
  // src/tui/panes/chat/composer/user-slashes.ts
31182
32190
  import { readFile as readFile6, readdir as readdir4, stat as stat4 } from "fs/promises";
31183
- import { homedir as homedir15 } from "os";
32191
+ import { homedir as homedir16 } from "os";
31184
32192
  import { join as join15 } from "path";
31185
32193
  function resolveHome() {
31186
- return process.env.HOME ?? homedir15();
32194
+ return process.env.HOME ?? homedir16();
31187
32195
  }
31188
32196
  async function safeReaddir(path12) {
31189
32197
  try {
@@ -31358,13 +32366,14 @@ function formatTotalSpeed(tokensPerSecond) {
31358
32366
  function formatContextUsageCompact(u2, modelId, vendor) {
31359
32367
  const caps = vendor ? getCapabilities(vendor) : capabilitiesForModelId(modelId);
31360
32368
  const id = modelId ?? caps.defaultModelId();
31361
- const window2 = caps.contextWindowFor(id);
32369
+ const window2 = u2.context_window_tokens ?? caps.contextWindowFor(id);
31362
32370
  const total = totalContextTokens(u2);
31363
32371
  if (total <= 0 || window2 <= 0)
31364
32372
  return null;
31365
32373
  const pct2 = Math.min(100, Math.max(0, Math.round(total / window2 * 100)));
31366
32374
  const speed = formatTotalSpeed(u2.total_speed_tokens_per_second);
31367
- return [`${pct2}% \xB7 ${formatTokShort(total)}/${formatTokShort(window2)}`, speed].filter(Boolean).join(" \xB7 ");
32375
+ const totalLabel = `${u2.context_tokens_approximate ? "~" : ""}${formatTokShort(total)}`;
32376
+ return [`${pct2}% \xB7 ${totalLabel}/${formatTokShort(window2)}`, speed].filter(Boolean).join(" \xB7 ");
31368
32377
  }
31369
32378
  var init_context_meter = __esm(() => {
31370
32379
  init_registry2();
@@ -31427,7 +32436,16 @@ function enqueuePrompt(state, prompt, nowIso = new Date().toISOString()) {
31427
32436
  const id = `q-${nowIso}-${Math.random().toString(36).slice(2, 8)}`;
31428
32437
  return {
31429
32438
  ...state,
31430
- queue: [...state.queue, { id, text: prompt, ts: nowIso }]
32439
+ queue: [...state.queue, { id, kind: "prompt", text: prompt, ts: nowIso }]
32440
+ };
32441
+ }
32442
+ function enqueueBashCommand(state, command, nowIso = new Date().toISOString()) {
32443
+ if (state.queue.length >= QUEUE_SOFT_CAP)
32444
+ return state;
32445
+ const id = `q-${nowIso}-${Math.random().toString(36).slice(2, 8)}`;
32446
+ return {
32447
+ ...state,
32448
+ queue: [...state.queue, { id, kind: "bash", command, ts: nowIso }]
31431
32449
  };
31432
32450
  }
31433
32451
  function queueIsFull(state) {
@@ -31449,6 +32467,80 @@ function removeFromQueue(state, id) {
31449
32467
  return state;
31450
32468
  return { ...state, queue: next };
31451
32469
  }
32470
+ function pushBashRow(state, args2, nowIso = new Date().toISOString()) {
32471
+ return {
32472
+ ...state,
32473
+ messages: capMessages([
32474
+ ...state.messages,
32475
+ {
32476
+ kind: "bash",
32477
+ id: args2.id,
32478
+ command: args2.command,
32479
+ stdout: "",
32480
+ stderr: "",
32481
+ exitCode: null,
32482
+ signal: null,
32483
+ done: false,
32484
+ ts: nowIso
32485
+ }
32486
+ ], nowIso)
32487
+ };
32488
+ }
32489
+ function patchBashRow(state, id, patch) {
32490
+ const idx = findLastIndex(state.messages, (m2) => m2.kind === "bash" && m2.id === id);
32491
+ if (idx < 0)
32492
+ return state;
32493
+ const target = state.messages[idx];
32494
+ const next = state.messages.slice();
32495
+ next[idx] = {
32496
+ ...target,
32497
+ stdout: patch.stdoutAppend ? target.stdout + patch.stdoutAppend : target.stdout,
32498
+ stderr: patch.stderrAppend ? target.stderr + patch.stderrAppend : target.stderr,
32499
+ exitCode: patch.exitCode !== undefined ? patch.exitCode : target.exitCode,
32500
+ signal: patch.signal !== undefined ? patch.signal : target.signal,
32501
+ done: patch.done !== undefined ? patch.done : target.done
32502
+ };
32503
+ return { ...state, messages: next };
32504
+ }
32505
+ function pushPendingBashContext(state, ctx4) {
32506
+ const prev = state.pendingBashContext ?? [];
32507
+ return { ...state, pendingBashContext: [...prev, ctx4] };
32508
+ }
32509
+ function drainPendingBashContext(state) {
32510
+ const list = state.pendingBashContext ?? [];
32511
+ if (list.length === 0)
32512
+ return [state, []];
32513
+ const { pendingBashContext: _drop, ...rest } = state;
32514
+ return [{ ...rest }, list];
32515
+ }
32516
+ function formatBashContextPrefix(entries) {
32517
+ if (entries.length === 0)
32518
+ return "";
32519
+ const parts = [];
32520
+ for (const e2 of entries) {
32521
+ parts.push(`<bash-input>${escapeXml(e2.command)}</bash-input>`);
32522
+ if (e2.stdout.length > 0)
32523
+ parts.push(`<bash-stdout>${escapeXml(e2.stdout)}</bash-stdout>`);
32524
+ if (e2.stderr.length > 0)
32525
+ parts.push(`<bash-stderr>${escapeXml(e2.stderr)}</bash-stderr>`);
32526
+ }
32527
+ parts.push("");
32528
+ return parts.join(`
32529
+ `);
32530
+ }
32531
+ function escapeXml(s2) {
32532
+ return s2.replace(/[&<>"']/g, (c2) => {
32533
+ if (c2 === "&")
32534
+ return "&amp;";
32535
+ if (c2 === "<")
32536
+ return "&lt;";
32537
+ if (c2 === ">")
32538
+ return "&gt;";
32539
+ if (c2 === '"')
32540
+ return "&quot;";
32541
+ return "&apos;";
32542
+ });
32543
+ }
31452
32544
  function applyEvent(state, ev, nowIso = new Date().toISOString()) {
31453
32545
  switch (ev.type) {
31454
32546
  case "assistant.delta": {
@@ -31497,6 +32589,9 @@ function applyEvent(state, ev, nowIso = new Date().toISOString()) {
31497
32589
  output_tokens: ev.output_tokens,
31498
32590
  cache_read_input_tokens: ev.cache_read_input_tokens,
31499
32591
  cache_creation_input_tokens: ev.cache_creation_input_tokens,
32592
+ context_tokens: ev.context_tokens,
32593
+ context_tokens_approximate: ev.context_tokens_approximate,
32594
+ context_window_tokens: ev.context_window_tokens,
31500
32595
  total_speed_tokens_per_second: ev.total_speed_tokens_per_second
31501
32596
  }
31502
32597
  };
@@ -31510,15 +32605,20 @@ function applyEvent(state, ev, nowIso = new Date().toISOString()) {
31510
32605
  error: ev.message,
31511
32606
  messages: capMessages([...state.messages, { kind: "system", text: `error: ${ev.message}`, ts: nowIso }], nowIso)
31512
32607
  };
31513
- case "user.inject":
32608
+ case "user.inject": {
32609
+ const cleaned = cleanChatText(ev.text);
32610
+ if (cleaned.length === 0) {
32611
+ return { ...state, isStreaming: true, error: null, lastUsage: undefined, activeTurnStartedAt: nowIso };
32612
+ }
31514
32613
  return {
31515
32614
  ...state,
31516
32615
  isStreaming: true,
31517
32616
  error: null,
31518
32617
  lastUsage: undefined,
31519
32618
  activeTurnStartedAt: nowIso,
31520
- messages: capMessages([...state.messages, { kind: "user", text: ev.text, ts: nowIso }], nowIso)
32619
+ messages: capMessages([...state.messages, { kind: "user", text: cleaned, ts: nowIso }], nowIso)
31521
32620
  };
32621
+ }
31522
32622
  case "system.info":
31523
32623
  return {
31524
32624
  ...state,
@@ -31947,7 +33047,12 @@ function Chat(props) {
31947
33047
  const tab = task?.tabs.find((t2) => t2.id === tabId);
31948
33048
  const vendor = tab?.vendor ?? task?.vendor ?? "claude";
31949
33049
  const modelId2 = tab?.model ?? task?.model ?? getCapabilities(vendor).defaultModelId();
31950
- return formatContextUsageCompact(u2, modelId2, vendor);
33050
+ const displayUsage = vendor === "codex" && u2.context_window_tokens && !u2.context_tokens ? {
33051
+ ...u2,
33052
+ context_tokens: estimateContextTokensFromRows(st.messages),
33053
+ context_tokens_approximate: true
33054
+ } : u2;
33055
+ return formatContextUsageCompact(displayUsage, modelId2, vendor);
31951
33056
  });
31952
33057
  createEffect(on(contextMeterLabel, (label) => {
31953
33058
  props.onContextMeter?.(label ?? null);
@@ -31971,7 +33076,7 @@ function Chat(props) {
31971
33076
  return m2.status === "pending" ? m2 : null;
31972
33077
  if (m2.kind === "question")
31973
33078
  return m2.answers === null ? m2 : null;
31974
- if (m2.kind === "user" || m2.kind === "assistant")
33079
+ if (m2.kind === "user" || m2.kind === "assistant" || m2.kind === "bash")
31975
33080
  return null;
31976
33081
  }
31977
33082
  return null;
@@ -32096,7 +33201,7 @@ function Chat(props) {
32096
33201
  send(pp);
32097
33202
  });
32098
33203
  });
32099
- let dispatching = false;
33204
+ const [dispatching, setDispatching] = createSignal(false);
32100
33205
  createEffect(() => {
32101
33206
  const taskId = props.taskId();
32102
33207
  const tabId = activeTabId();
@@ -32109,15 +33214,15 @@ function Chat(props) {
32109
33214
  return;
32110
33215
  if (hasPendingInput())
32111
33216
  return;
32112
- if (dispatching)
33217
+ if (dispatching())
32113
33218
  return;
32114
33219
  queueMicrotask(async () => {
32115
- if (dispatching)
33220
+ if (dispatching())
32116
33221
  return;
32117
33222
  const cur = activeState();
32118
33223
  if (cur.isStreaming || cur.queue.length === 0)
32119
33224
  return;
32120
- dispatching = true;
33225
+ setDispatching(true);
32121
33226
  try {
32122
33227
  let head = null;
32123
33228
  patchActiveState((s2) => {
@@ -32128,16 +33233,116 @@ function Chat(props) {
32128
33233
  const dispatched = head;
32129
33234
  if (!dispatched)
32130
33235
  return;
33236
+ if (dispatched.kind === "bash") {
33237
+ await runBashLocally(dispatched.command);
33238
+ return;
33239
+ }
33240
+ const bashPrefix = drainBashContextPrefix();
33241
+ const finalText = bashPrefix.length > 0 ? bashPrefix + dispatched.text : dispatched.text;
32131
33242
  try {
32132
- await props.orchestrator.runTask(taskId, dispatched.text, tabId);
33243
+ await props.orchestrator.runTask(taskId, finalText, tabId);
32133
33244
  } catch (err) {
32134
- patchActiveState((s2) => pushSystemError(s2, `queued runTask failed: ${stringifyErr3(err)}`));
33245
+ patchActiveState((s2) => pushSystemError(s2, `queued runTask failed: ${stringifyErr4(err)}`));
32135
33246
  }
32136
33247
  } finally {
32137
- dispatching = false;
33248
+ setDispatching(false);
32138
33249
  }
32139
33250
  });
32140
33251
  });
33252
+ const bashAbortsByTab = new Map;
33253
+ onCleanup(() => {
33254
+ for (const ac of bashAbortsByTab.values())
33255
+ ac.abort();
33256
+ bashAbortsByTab.clear();
33257
+ });
33258
+ function handleBashCommand(command) {
33259
+ if (activeState().isStreaming) {
33260
+ const tabId = activeTabId();
33261
+ if (!tabId)
33262
+ return;
33263
+ if (queueIsFull(activeState())) {
33264
+ patchActiveState((s2) => pushSystemError(s2, `queue is full (max ${activeState().queue.length})`));
33265
+ return;
33266
+ }
33267
+ patchActiveState((s2) => enqueueBashCommand(s2, command));
33268
+ return;
33269
+ }
33270
+ runBashLocally(command);
33271
+ }
33272
+ async function runBashLocally(command) {
33273
+ const taskId = props.taskId();
33274
+ const tabId = activeTabId();
33275
+ if (!taskId || !tabId)
33276
+ return;
33277
+ const cwd = worktreePath();
33278
+ if (!cwd) {
33279
+ patchStateForTab(tabId, (s2) => pushSystemError(s2, "bash: task has no worktree yet"));
33280
+ return;
33281
+ }
33282
+ bashAbortsByTab.get(tabId)?.abort();
33283
+ const ac = new AbortController;
33284
+ bashAbortsByTab.set(tabId, ac);
33285
+ const id = `bash-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
33286
+ patchStateForTab(tabId, (s2) => pushBashRow(s2, {
33287
+ id,
33288
+ command
33289
+ }));
33290
+ let stdoutAcc = "";
33291
+ let stderrAcc = "";
33292
+ try {
33293
+ const result = await runBashCommand({
33294
+ command,
33295
+ cwd,
33296
+ onStdout: (chunk) => {
33297
+ stdoutAcc += chunk;
33298
+ patchStateForTab(tabId, (s2) => patchBashRow(s2, id, {
33299
+ stdoutAppend: chunk
33300
+ }));
33301
+ },
33302
+ onStderr: (chunk) => {
33303
+ stderrAcc += chunk;
33304
+ patchStateForTab(tabId, (s2) => patchBashRow(s2, id, {
33305
+ stderrAppend: chunk
33306
+ }));
33307
+ },
33308
+ signal: ac.signal
33309
+ });
33310
+ patchStateForTab(tabId, (s2) => patchBashRow(s2, id, {
33311
+ done: true,
33312
+ exitCode: result.exitCode,
33313
+ signal: result.signal
33314
+ }));
33315
+ if (!ac.signal.aborted) {
33316
+ patchStateForTab(tabId, (s2) => pushPendingBashContext(s2, {
33317
+ command,
33318
+ stdout: stdoutAcc,
33319
+ stderr: stderrAcc,
33320
+ exitCode: result.exitCode
33321
+ }));
33322
+ }
33323
+ } catch (err) {
33324
+ patchStateForTab(tabId, (s2) => patchBashRow(s2, id, {
33325
+ done: true,
33326
+ exitCode: -1,
33327
+ signal: null
33328
+ }));
33329
+ patchStateForTab(tabId, (s2) => pushSystemError(s2, `bash failed: ${stringifyErr4(err)}`));
33330
+ } finally {
33331
+ if (bashAbortsByTab.get(tabId) === ac)
33332
+ bashAbortsByTab.delete(tabId);
33333
+ }
33334
+ }
33335
+ function drainBashContextPrefix() {
33336
+ const ctxs = activeState().pendingBashContext ?? [];
33337
+ if (ctxs.length === 0)
33338
+ return "";
33339
+ const prefix = formatBashContextPrefix(ctxs);
33340
+ patchActiveState((s2) => {
33341
+ const [next] = drainPendingBashContext(s2);
33342
+ return next;
33343
+ });
33344
+ return prefix;
33345
+ }
32141
33346
  async function send(promptText, mode = "auto") {
32142
33347
  const text = (promptText ?? draft()).trim();
32143
33348
  const taskId = props.taskId();
@@ -32153,24 +33358,27 @@ function Chat(props) {
32153
33358
  try {
32154
33359
  await props.orchestrator.clearTab(taskId, tabId);
32155
33360
  } catch (err) {
32156
- patchActiveState((s2) => pushSystemError(s2, `/clear failed: ${stringifyErr3(err)}`));
33361
+ patchActiveState((s2) => pushSystemError(s2, `/clear failed: ${stringifyErr4(err)}`));
32157
33362
  }
32158
33363
  return;
32159
33364
  }
32160
33365
  const streaming = activeState().isStreaming;
33366
+ const immediate = !streaming || mode === "steer";
33367
+ const bashPrefix = immediate ? drainBashContextPrefix() : "";
33368
+ const dispatched = bashPrefix.length > 0 ? bashPrefix + text : text;
32161
33369
  if (streaming && mode === "steer") {
32162
33370
  setDraft("");
32163
- if (dispatching)
33371
+ if (dispatching())
32164
33372
  return;
32165
- dispatching = true;
33373
+ setDispatching(true);
32166
33374
  try {
32167
33375
  try {
32168
- await props.orchestrator.steerTask(taskId, text, tabId);
33376
+ await props.orchestrator.steerTask(taskId, dispatched, tabId);
32169
33377
  } catch (err) {
32170
- patchActiveState((s2) => pushSystemError(s2, `steer failed: ${stringifyErr3(err)}`));
33378
+ patchActiveState((s2) => pushSystemError(s2, `steer failed: ${stringifyErr4(err)}`));
32171
33379
  }
32172
33380
  } finally {
32173
- dispatching = false;
33381
+ setDispatching(false);
32174
33382
  }
32175
33383
  return;
32176
33384
  }
@@ -32185,9 +33393,9 @@ function Chat(props) {
32185
33393
  }
32186
33394
  setDraft("");
32187
33395
  try {
32188
- await props.orchestrator.runTask(taskId, text, tabId);
33396
+ await props.orchestrator.runTask(taskId, dispatched, tabId);
32189
33397
  } catch (err) {
32190
- patchActiveState((s2) => pushSystemError(s2, `runTask failed: ${stringifyErr3(err)}`));
33398
+ patchActiveState((s2) => pushSystemError(s2, `runTask failed: ${stringifyErr4(err)}`));
32191
33399
  }
32192
33400
  }
32193
33401
  function cancelQueued(id) {
@@ -32198,6 +33406,10 @@ function Chat(props) {
32198
33406
  if (!entry)
32199
33407
  return;
32200
33408
  patchActiveState((s2) => removeFromQueue(s2, id));
33409
+ if (entry.kind === "bash") {
33410
+ runBashLocally(entry.command);
33411
+ return;
33412
+ }
32201
33413
  send(entry.text, "steer");
32202
33414
  }
32203
33415
  async function newTab() {
@@ -32211,7 +33423,7 @@ function Chat(props) {
32211
33423
  setExpandedFoldStartIndex(null);
32212
33424
  props.orchestrator.setActiveTab(taskId, tab.id);
32213
33425
  } catch (err) {
32214
- patchActiveState((s2) => pushSystemError(s2, `createTab failed: ${stringifyErr3(err)}`));
33426
+ patchActiveState((s2) => pushSystemError(s2, `createTab failed: ${stringifyErr4(err)}`));
32215
33427
  }
32216
33428
  }
32217
33429
  async function closeActiveTab() {
@@ -32221,6 +33433,7 @@ function Chat(props) {
32221
33433
  return;
32222
33434
  if (tabs().length <= 1)
32223
33435
  return;
33436
+ bashAbortsByTab.get(tabId)?.abort();
32224
33437
  try {
32225
33438
  const nextActive = await props.orchestrator.closeTab(taskId, tabId);
32226
33439
  if (nextActive) {
@@ -32229,7 +33442,7 @@ function Chat(props) {
32229
33442
  setExpandedFoldStartIndex(null);
32230
33443
  }
32231
33444
  } catch (err) {
32232
- patchActiveState((s2) => pushSystemError(s2, `closeTab failed: ${stringifyErr3(err)}`));
33445
+ patchActiveState((s2) => pushSystemError(s2, `closeTab failed: ${stringifyErr4(err)}`));
32233
33446
  }
32234
33447
  }
32235
33448
  function selectTabByIndex(idx) {
@@ -32272,21 +33485,33 @@ function Chat(props) {
32272
33485
  }
32273
33486
  })
32274
33487
  }));
33488
+ const hasActiveBash = createMemo(() => {
33489
+ const msgs = activeState().messages;
33490
+ for (let i2 = msgs.length - 1;i2 >= 0; i2--) {
33491
+ const m2 = msgs[i2];
33492
+ if (!m2)
33493
+ continue;
33494
+ if (m2.kind === "bash")
33495
+ return !m2.done;
33496
+ }
33497
+ return false;
33498
+ });
32275
33499
  async function interruptStream() {
32276
33500
  const taskId = props.taskId();
32277
33501
  const tabId = activeTabId();
32278
33502
  if (!taskId || !tabId)
32279
33503
  return;
33504
+ bashAbortsByTab.get(tabId)?.abort();
32280
33505
  if (!activeState().isStreaming)
32281
33506
  return;
32282
33507
  try {
32283
33508
  await props.orchestrator.interruptTask(taskId, tabId);
32284
33509
  } catch (err) {
32285
- patchActiveState((s2) => pushSystemError(s2, `interrupt failed: ${stringifyErr3(err)}`));
33510
+ patchActiveState((s2) => pushSystemError(s2, `interrupt failed: ${stringifyErr4(err)}`));
32286
33511
  }
32287
33512
  }
32288
33513
  useBindings(() => ({
32289
- enabled: props.focused?.() === true && activeState().isStreaming && dialog.stack.length === 0,
33514
+ enabled: props.focused?.() === true && (activeState().isStreaming || hasActiveBash()) && dialog.stack.length === 0,
32290
33515
  bindings: [{
32291
33516
  key: "escape",
32292
33517
  cmd: () => void interruptStream()
@@ -32358,7 +33583,7 @@ function Chat(props) {
32358
33583
  kind: "ask_question",
32359
33584
  answers
32360
33585
  }).catch((err) => {
32361
- patchActiveState((s2) => pushSystemError(s2, `respondToInput failed: ${stringifyErr3(err)}`));
33586
+ patchActiveState((s2) => pushSystemError(s2, `respondToInput failed: ${stringifyErr4(err)}`));
32362
33587
  });
32363
33588
  setDraft("");
32364
33589
  return;
@@ -32424,7 +33649,7 @@ function Chat(props) {
32424
33649
  kind: "approve_plan",
32425
33650
  approve
32426
33651
  }).catch((err) => {
32427
- patchActiveState((s2) => pushSystemError(s2, `respondToInput failed: ${stringifyErr3(err)}`));
33652
+ patchActiveState((s2) => pushSystemError(s2, `respondToInput failed: ${stringifyErr4(err)}`));
32428
33653
  });
32429
33654
  },
32430
33655
  onAnswer: (requestId, answers) => {
@@ -32435,7 +33660,7 @@ function Chat(props) {
32435
33660
  kind: "ask_question",
32436
33661
  answers
32437
33662
  }).catch((err) => {
32438
- patchActiveState((s2) => pushSystemError(s2, `respondToInput failed: ${stringifyErr3(err)}`));
33663
+ patchActiveState((s2) => pushSystemError(s2, `respondToInput failed: ${stringifyErr4(err)}`));
32439
33664
  });
32440
33665
  },
32441
33666
  onClaimComposerFocus: setQuestionInlineFocus,
@@ -32537,14 +33762,50 @@ function Chat(props) {
32537
33762
  worktreePath,
32538
33763
  queue: () => activeState().queue,
32539
33764
  onCancelQueued: cancelQueued,
32540
- onSendQueuedNow: sendQueuedNow
33765
+ onSendQueuedNow: sendQueuedNow,
33766
+ onBashCommand: handleBashCommand
32541
33767
  });
32542
33768
  }
32543
33769
  }), null);
32544
33770
  return _el$;
32545
33771
  })();
32546
33772
  }
32547
- function stringifyErr3(err) {
33773
+ function estimateContextTokensFromRows(rows) {
33774
+ let chars = 0;
33775
+ for (const row of rows) {
33776
+ switch (row.kind) {
33777
+ case "user":
33778
+ case "assistant":
33779
+ case "system":
33780
+ chars += row.text.length;
33781
+ break;
33782
+ case "tool":
33783
+ chars += row.name.length;
33784
+ chars += stringifyForTokenEstimate(row.input).length;
33785
+ chars += stringifyForTokenEstimate(row.output).length;
33786
+ break;
33787
+ case "approval":
33788
+ chars += row.tool.length + row.plan.length;
33789
+ break;
33790
+ case "question":
33791
+ chars += row.questions.reduce((total, q2) => total + q2.question.length, 0);
33792
+ break;
33793
+ }
33794
+ }
33795
+ return Math.max(1, Math.round(chars / 4));
33796
+ }
33797
+ function stringifyForTokenEstimate(value) {
33798
+ if (value === undefined || value === null)
33799
+ return "";
33800
+ if (typeof value === "string")
33801
+ return value;
33802
+ try {
33803
+ return JSON.stringify(value);
33804
+ } catch {
33805
+ return String(value);
33806
+ }
33807
+ }
33808
+ function stringifyErr4(err) {
32548
33809
  if (err instanceof Error)
32549
33810
  return err.message;
32550
33811
  try {
@@ -32573,6 +33834,7 @@ var init_Chat = __esm(() => {
32573
33834
  init_Composer();
32574
33835
  init_Loading();
32575
33836
  init_MessageList();
33837
+ init_bash_mode();
32576
33838
  init_ModelPicker();
32577
33839
  init_builtin_slashes();
32578
33840
  init_user_slashes();
@@ -33162,12 +34424,12 @@ var init_Sidebar = __esm(() => {
33162
34424
  });
33163
34425
 
33164
34426
  // src/orchestrator/bridge/server.ts
33165
- import { mkdir as mkdir3, unlink as unlink4 } from "fs/promises";
34427
+ import { mkdir as mkdir3, unlink as unlink5 } from "fs/promises";
33166
34428
  import { createServer } from "net";
33167
34429
  import { dirname as dirname5 } from "path";
33168
34430
  async function startBridgeServer(orch, socketPath) {
33169
34431
  await mkdir3(dirname5(socketPath), { recursive: true });
33170
- await unlink4(socketPath).catch(() => {});
34432
+ await unlink5(socketPath).catch(() => {});
33171
34433
  const conns = new Set;
33172
34434
  const server = createServer((conn) => {
33173
34435
  conns.add(conn);
@@ -33208,7 +34470,7 @@ async function startBridgeServer(orch, socketPath) {
33208
34470
  conn.destroy();
33209
34471
  conns.clear();
33210
34472
  await new Promise((resolve4) => server.close(() => resolve4()));
33211
- await unlink4(socketPath).catch(() => {});
34473
+ await unlink5(socketPath).catch(() => {});
33212
34474
  }
33213
34475
  };
33214
34476
  }
@@ -33300,8 +34562,8 @@ __export(exports_bridge, {
33300
34562
  startBridge: () => startBridge,
33301
34563
  bridgeSocketPathForHome: () => bridgeSocketPathForHome
33302
34564
  });
33303
- import { mkdir as mkdir4, writeFile as writeFile3 } from "fs/promises";
33304
- import { homedir as homedir16 } from "os";
34565
+ import { mkdir as mkdir4, unlink as unlink6, writeFile as writeFile3 } from "fs/promises";
34566
+ import { homedir as homedir17 } from "os";
33305
34567
  import { join as join16 } from "path";
33306
34568
  import { fileURLToPath as fileURLToPath2 } from "url";
33307
34569
  function bridgeSocketPathForHome(home, pid = process.pid) {
@@ -33309,7 +34571,7 @@ function bridgeSocketPathForHome(home, pid = process.pid) {
33309
34571
  return fitSocketPath(join16(runDir, `bridge-${pid}.sock`), home, "bridge", pid);
33310
34572
  }
33311
34573
  async function startBridge(orch, opts = {}) {
33312
- const home = opts.homeDir ?? process.env.KOBE_HOME_DIR ?? homedir16();
34574
+ const home = opts.homeDir ?? process.env.KOBE_HOME_DIR ?? homedir17();
33313
34575
  const runDir = join16(home, ".kobe", "run");
33314
34576
  const socketPath = bridgeSocketPathForHome(home);
33315
34577
  const mcpConfigPath = join16(runDir, `mcp-${process.pid}.json`);
@@ -33333,6 +34595,7 @@ async function startBridge(orch, opts = {}) {
33333
34595
  mcpConfigPath,
33334
34596
  async close() {
33335
34597
  await server.close();
34598
+ await unlink6(mcpConfigPath).catch(() => {});
33336
34599
  }
33337
34600
  };
33338
34601
  }
@@ -33342,7 +34605,7 @@ var init_bridge = __esm(() => {
33342
34605
  });
33343
34606
 
33344
34607
  // src/tui/app.tsx
33345
- import { homedir as homedir17 } from "os";
34608
+ import { homedir as homedir18 } from "os";
33346
34609
  import { join as join17 } from "path";
33347
34610
  function Shell(props) {
33348
34611
  const themeCtx = useTheme();
@@ -33423,6 +34686,23 @@ function Shell(props) {
33423
34686
  const focusedPane = focus.focused;
33424
34687
  const setFocusedPane = focus.setFocused;
33425
34688
  const renderer = useRenderer();
34689
+ let quitting = false;
34690
+ const quit = () => {
34691
+ if (quitting)
34692
+ return;
34693
+ quitting = true;
34694
+ try {
34695
+ renderer?.destroy();
34696
+ } catch (err) {
34697
+ console.error("kobe: renderer.destroy() failed during quit:", err);
34698
+ }
34699
+ const forceExit = setTimeout(() => process.exit(0), 1500);
34700
+ forceExit.unref();
34701
+ (props.onQuit?.() ?? Promise.resolve()).finally(() => {
34702
+ clearTimeout(forceExit);
34703
+ process.exit(0);
34704
+ });
34705
+ };
33426
34706
  const isFocused = (pane) => {
33427
34707
  const baseAcc = focus.is(pane);
33428
34708
  return () => baseAcc() && dialog.stack.length === 0;
@@ -33436,10 +34716,7 @@ function Shell(props) {
33436
34716
  while (true) {
33437
34717
  const choice = await DialogConfirm.show(dialog, "daemon disconnected", message, "Quit", "Restart");
33438
34718
  if (choice !== true) {
33439
- try {
33440
- renderer?.destroy();
33441
- } catch {}
33442
- process.exit(0);
34719
+ quit();
33443
34720
  }
33444
34721
  try {
33445
34722
  await orch.manualReconnect();
@@ -33553,7 +34830,8 @@ Try again or quit?`;
33553
34830
  if (focusedPane() !== "workspace")
33554
34831
  focus.cycle(-1);
33555
34832
  },
33556
- focusCycleEnabled: () => focusedPane() !== "workspace"
34833
+ focusCycleEnabled: () => focusedPane() !== "workspace",
34834
+ onQuit: quit
33557
34835
  });
33558
34836
  const {
33559
34837
  openNewTaskFlow,
@@ -33580,6 +34858,7 @@ Try again or quit?`;
33580
34858
  kv,
33581
34859
  orchestrator: props.orchestrator,
33582
34860
  renderer,
34861
+ onQuit: quit,
33583
34862
  activeTask,
33584
34863
  openActiveTaskInEditor
33585
34864
  });
@@ -33871,8 +35150,16 @@ async function startApp() {
33871
35150
  } of loadUserThemes()) {
33872
35151
  addTheme(name, theme);
33873
35152
  }
33874
- const homeDir2 = process.env.KOBE_HOME_DIR ?? homedir17();
35153
+ const homeDir2 = process.env.KOBE_HOME_DIR ?? homedir18();
33875
35154
  let orchestrator;
35155
+ let stopOwnedDaemon;
35156
+ let ownedDaemonStopped = false;
35157
+ const stopOwnedDaemonOnce = async () => {
35158
+ if (ownedDaemonStopped)
35159
+ return;
35160
+ ownedDaemonStopped = true;
35161
+ await stopOwnedDaemon?.();
35162
+ };
33876
35163
  if (process.env.KOBE_TEST_ENGINE || process.env.KOBE_NO_DAEMON === "1") {
33877
35164
  const engines = await buildEngines();
33878
35165
  const store2 = new TaskIndexStore({
@@ -33896,8 +35183,16 @@ async function startApp() {
33896
35183
  console.error("[kobe] bridge failed to start:", err);
33897
35184
  }
33898
35185
  } else {
33899
- const client = await connectOrStartDaemon();
33900
- orchestrator = new RemoteOrchestrator(client);
35186
+ const daemonMode = process.env.KOBE_DAEMON_MODE === "shared" ? "shared" : "single";
35187
+ if (daemonMode === "shared") {
35188
+ orchestrator = new RemoteOrchestrator(await connectOrStartDaemon());
35189
+ } else {
35190
+ const owned = await connectOrStartOwnedDaemon();
35191
+ stopOwnedDaemon = owned.stop;
35192
+ orchestrator = new RemoteOrchestrator(owned.client, {
35193
+ ensureReachable: () => ensureOwnedDaemonReachable(owned.socketPath, owned.pidPath)
35194
+ });
35195
+ }
33901
35196
  await orchestrator.init();
33902
35197
  }
33903
35198
  normalizeSavedRepos();
@@ -33909,10 +35204,16 @@ async function startApp() {
33909
35204
  }
33910
35205
  }
33911
35206
  await render(() => createComponent2(App, {
33912
- orchestrator
35207
+ orchestrator,
35208
+ onQuit: stopOwnedDaemonOnce
33913
35209
  }), {
33914
35210
  backgroundColor: "transparent",
35211
+ externalOutputMode: "passthrough",
33915
35212
  exitOnCtrlC: false,
35213
+ onDestroy: () => {
35214
+ stopOwnedDaemonOnce().catch(() => {});
35215
+ },
35216
+ screenMode: "alternate-screen",
33916
35217
  useKittyKeyboard: {}
33917
35218
  });
33918
35219
  }