@sma1lboy/kobe 0.5.10 → 0.5.11

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/README.md CHANGED
@@ -68,6 +68,7 @@ Once you're in, the keys you'll use most:
68
68
  | `ctrl+1` / `2` / `3` / `4` | Jump straight to a pane (sidebar, workspace, files, terminal) |
69
69
  | `tab` | Cycle focus to the next pane |
70
70
  | `ctrl+q` | Detach back to the sidebar (your task keeps streaming) |
71
+ | `ctrl+o` | Open the active task's worktree in your editor |
71
72
  | `?` | Show the full keybinding help dialog |
72
73
  | `,` or `ctrl+,` | Open Settings (theme, transparent background, dev reset) |
73
74
  | `q` | Quit (with confirm) |
@@ -87,6 +88,29 @@ Inside the chat composer:
87
88
  A given task can host **multiple chat tabs** on the same worktree — useful when
88
89
  you want a parallel sub-conversation without losing the main thread.
89
90
 
91
+ ## Opening tasks in your editor
92
+
93
+ The top bar shows an `[Open] <editor>` chip when kobe can find an editor for the
94
+ active task. Click it, use `ctrl+o`, or run **Open task in editor** from the
95
+ command palette to open the task's worktree.
96
+
97
+ Detection order is:
98
+
99
+ 1. `KOBE_OPEN_EDITOR`
100
+ 2. `code` (VS Code)
101
+ 3. `cursor`
102
+ 4. `windsurf`
103
+ 5. `zed`
104
+ 6. platform fallback (`open` on macOS, `xdg-open` on Linux)
105
+
106
+ Set `KOBE_OPEN_EDITOR` globally if you want to force a specific tool:
107
+
108
+ ```bash
109
+ export KOBE_OPEN_EDITOR=cursor
110
+ export KOBE_OPEN_EDITOR=code
111
+ export KOBE_OPEN_EDITOR=/Applications/Cursor.app/Contents/Resources/app/bin/cursor
112
+ ```
113
+
90
114
  For the full feature manifest, see [`CHANGELOG.md`](./CHANGELOG.md).
91
115
 
92
116
  ## Custom themes
@@ -152,8 +176,8 @@ If you want to hack on kobe itself rather than just use it:
152
176
  ```bash
153
177
  bun install
154
178
  bun run dev # boots the 5-pane TUI under KOBE_DEV=1 (no update chip, etc.)
155
- bun run test # unit + type tests
156
- bun run test:behavior # PTY-driven; spawns kobe as a real binary
179
+ bun run test # normal suite: fast tests + serial socket tests
180
+ bun run test:behavior # slow PTY suite; only run for user-visible TUI behavior
157
181
  bun run typecheck # strict tsc
158
182
  bun run build # produces ./dist/index.js for `npm publish`
159
183
  ```
package/dist/bin/kobed.js CHANGED
@@ -1208,18 +1208,29 @@ var init_server = () => {};
1208
1208
  // src/orchestrator/bridge/index.ts
1209
1209
  var exports_bridge = {};
1210
1210
  __export(exports_bridge, {
1211
- startBridge: () => startBridge
1211
+ startBridge: () => startBridge,
1212
+ bridgeSocketPathForHome: () => bridgeSocketPathForHome
1212
1213
  });
1213
- import { writeFile as writeFile2 } from "fs/promises";
1214
- import { homedir as homedir5 } from "os";
1214
+ import { mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
1215
+ import { homedir as homedir5, tmpdir as tmpdir2 } from "os";
1215
1216
  import { join as join3 } from "path";
1216
1217
  import { fileURLToPath as fileURLToPath2 } from "url";
1218
+ function bridgeSocketPathForHome(home, pid = process.pid) {
1219
+ const runDir = join3(home, ".kobe", "run");
1220
+ const preferred = join3(runDir, `bridge-${pid}.sock`);
1221
+ const macTempSocket = process.platform === "darwin" && preferred.startsWith(tmpdir2());
1222
+ if (preferred.length <= UNIX_SOCKET_PATH_LIMIT && !macTempSocket)
1223
+ return preferred;
1224
+ const shortTmp = process.platform === "darwin" ? "/tmp" : tmpdir2();
1225
+ return join3(shortTmp, `kobe-bridge-${pid}.sock`);
1226
+ }
1217
1227
  async function startBridge(orch, opts = {}) {
1218
1228
  const home = opts.homeDir ?? process.env.KOBE_HOME_DIR ?? homedir5();
1219
1229
  const runDir = join3(home, ".kobe", "run");
1220
- const socketPath = join3(runDir, `bridge-${process.pid}.sock`);
1230
+ const socketPath = bridgeSocketPathForHome(home);
1221
1231
  const mcpConfigPath = join3(runDir, `mcp-${process.pid}.json`);
1222
1232
  const server = await startBridgeServer(orch, socketPath);
1233
+ await mkdir3(runDir, { recursive: true });
1223
1234
  const moduleExt = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
1224
1235
  const entry = fileURLToPath2(new URL(`../../cli/index${moduleExt}`, import.meta.url));
1225
1236
  const mcpConfig = {
@@ -1240,6 +1251,7 @@ async function startBridge(orch, opts = {}) {
1240
1251
  }
1241
1252
  };
1242
1253
  }
1254
+ var UNIX_SOCKET_PATH_LIMIT = 103;
1243
1255
  var init_bridge = __esm(() => {
1244
1256
  init_server();
1245
1257
  });
@@ -3994,7 +4006,7 @@ var init_core = __esm(() => {
3994
4006
  });
3995
4007
 
3996
4008
  // src/orchestrator/index/store.ts
3997
- import { mkdir as mkdir3, open, readFile as readFile3, rename, unlink as unlink3 } from "fs/promises";
4009
+ import { mkdir as mkdir4, open, readFile as readFile3, rename, unlink as unlink3 } from "fs/promises";
3998
4010
  import { homedir as homedir8 } from "os";
3999
4011
  import { dirname as dirname4, join as join6 } from "path";
4000
4012
 
@@ -4068,7 +4080,7 @@ class TaskIndexStore {
4068
4080
  return next;
4069
4081
  }
4070
4082
  async doSave() {
4071
- await mkdir3(dirname4(this.path), { recursive: true });
4083
+ await mkdir4(dirname4(this.path), { recursive: true });
4072
4084
  const payload = this.snapshot();
4073
4085
  const json = `${JSON.stringify(payload, null, 2)}
4074
4086
  `;
@@ -4619,7 +4631,7 @@ init_paths();
4619
4631
  // src/daemon/server.ts
4620
4632
  init_repos();
4621
4633
  init_paths();
4622
- import { mkdir as mkdir4, readFile as readFile5, unlink as unlink4, writeFile as writeFile4 } from "fs/promises";
4634
+ import { mkdir as mkdir5, readFile as readFile5, unlink as unlink4, writeFile as writeFile4 } from "fs/promises";
4623
4635
  import { createServer as createServer2 } from "net";
4624
4636
  import { dirname as dirname5 } from "path";
4625
4637
 
@@ -4959,8 +4971,8 @@ async function startDaemonServer(orch, options = {}) {
4959
4971
  const startedAt = options.startedAt ?? new Date;
4960
4972
  const clients = new Set;
4961
4973
  let nextClientId = 1;
4962
- await mkdir4(dirname5(socketPath), { recursive: true });
4963
- await mkdir4(dirname5(pidPath), { recursive: true });
4974
+ await mkdir5(dirname5(socketPath), { recursive: true });
4975
+ await mkdir5(dirname5(pidPath), { recursive: true });
4964
4976
  await unlink4(socketPath).catch(() => {});
4965
4977
  const server = createServer2((socket) => {
4966
4978
  const client = {
package/dist/cli/index.js CHANGED
@@ -5271,6 +5271,13 @@ var init_keybindings = __esm(() => {
5271
5271
  description: "New task",
5272
5272
  hint: { keys: "n", label: "new" }
5273
5273
  },
5274
+ {
5275
+ id: "task.openEditor",
5276
+ scope: "global",
5277
+ keys: ["ctrl+o"],
5278
+ category: "Global",
5279
+ description: "Open active task worktree in editor"
5280
+ },
5274
5281
  {
5275
5282
  id: "settings.open",
5276
5283
  scope: "global",
@@ -8857,7 +8864,7 @@ var init_package = __esm(() => {
8857
8864
  package_default = {
8858
8865
  $schema: "https://json.schemastore.org/package.json",
8859
8866
  name: "@sma1lboy/kobe",
8860
- version: "0.5.10",
8867
+ version: "0.5.11",
8861
8868
  description: "TUI orchestrator for Claude Code (codename)",
8862
8869
  type: "module",
8863
8870
  packageManager: "bun@1.3.13",
@@ -8887,8 +8894,10 @@ var init_package = __esm(() => {
8887
8894
  build: "bun run scripts/build.ts",
8888
8895
  compile: "bun run scripts/compile.ts",
8889
8896
  typecheck: "tsc --noEmit",
8890
- test: "vitest run --passWithNoTests",
8891
- "test:behavior": "vitest run test/behavior --passWithNoTests",
8897
+ test: "bun run test:fast && bun run test:socket",
8898
+ "test:fast": "vitest run --passWithNoTests",
8899
+ "test:socket": "KOBE_INCLUDE_SOCKET=1 vitest run test/daemon test/orchestrator/bridge.test.ts --pool forks --minWorkers=1 --maxWorkers=1 --passWithNoTests",
8900
+ "test:behavior": "KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --passWithNoTests",
8892
8901
  lint: "biome check .",
8893
8902
  prepublishOnly: "bun run typecheck && bun run build"
8894
8903
  },
@@ -12950,6 +12959,7 @@ function useAppKeymap(deps) {
12950
12959
  useBindings(() => ({
12951
12960
  enabled: dialog.stack.length === 0,
12952
12961
  bindings: bindByIds({
12962
+ "task.openEditor": deps.openActiveTaskInEditor,
12953
12963
  "settings.open": () => {
12954
12964
  SettingsDialog.show(dialog, deps.kv, deps.orchestrator);
12955
12965
  }
@@ -14653,6 +14663,173 @@ var init_create_pr_button = __esm(() => {
14653
14663
  init_theme();
14654
14664
  });
14655
14665
 
14666
+ // src/tui/lib/worktree-opener.ts
14667
+ import { spawn as spawn4 } from "child_process";
14668
+ import { existsSync as existsSync6 } from "fs";
14669
+ import { basename as basename5, delimiter, isAbsolute as isAbsolute2, join as join13 } from "path";
14670
+ function executableOnPath(command, env, exists) {
14671
+ if (isAbsolute2(command))
14672
+ return exists(command);
14673
+ const pathEnv = env.PATH ?? "";
14674
+ for (const dir of pathEnv.split(delimiter)) {
14675
+ if (!dir)
14676
+ continue;
14677
+ if (exists(join13(dir, command)))
14678
+ return true;
14679
+ }
14680
+ return false;
14681
+ }
14682
+ function labelForOverride(command) {
14683
+ const name = basename5(command);
14684
+ if (name === "code")
14685
+ return "VS Code";
14686
+ if (name === "cursor")
14687
+ return "Cursor";
14688
+ if (name === "windsurf")
14689
+ return "Windsurf";
14690
+ if (name === "zed")
14691
+ return "Zed";
14692
+ return name || command;
14693
+ }
14694
+ function detectWorktreeOpener(deps = {}) {
14695
+ const env = deps.env ?? process.env;
14696
+ const platform = deps.platform ?? process.platform;
14697
+ const exists = deps.exists ?? existsSync6;
14698
+ const override = env.KOBE_OPEN_EDITOR?.trim();
14699
+ if (override) {
14700
+ return { id: "env", label: labelForOverride(override), command: override, args: [] };
14701
+ }
14702
+ for (const c of CLI_CANDIDATES) {
14703
+ if (executableOnPath(c.command, env, exists)) {
14704
+ return { id: c.id, label: c.label, command: c.command, args: [] };
14705
+ }
14706
+ }
14707
+ if (platform === "darwin" && executableOnPath("open", env, exists)) {
14708
+ for (const app of MAC_APP_CANDIDATES) {
14709
+ if (app.paths.some((path6) => exists(path6))) {
14710
+ return { id: app.id, label: app.label, command: "open", args: ["-a", app.appName] };
14711
+ }
14712
+ }
14713
+ return { id: "mac-open", label: "Finder", command: "open", args: [] };
14714
+ }
14715
+ if (platform === "linux" && executableOnPath("xdg-open", env, exists)) {
14716
+ return { id: "xdg-open", label: "Open", command: "xdg-open", args: [] };
14717
+ }
14718
+ return null;
14719
+ }
14720
+ function buildOpenWorktreeCommand(worktreePath, opener) {
14721
+ return [opener.command, [...opener.args, worktreePath]];
14722
+ }
14723
+ function openWorktree(worktreePath, opener, deps = {}) {
14724
+ if (!worktreePath)
14725
+ return false;
14726
+ const spawnFn = deps.spawn ?? spawn4;
14727
+ const [command, args2] = buildOpenWorktreeCommand(worktreePath, opener);
14728
+ try {
14729
+ const child = spawnFn(command, args2, { detached: true, stdio: "ignore" });
14730
+ if (child.pid === undefined)
14731
+ return false;
14732
+ child.unref();
14733
+ return true;
14734
+ } catch {
14735
+ return false;
14736
+ }
14737
+ }
14738
+ var CLI_CANDIDATES, MAC_APP_CANDIDATES;
14739
+ var init_worktree_opener = __esm(() => {
14740
+ CLI_CANDIDATES = [
14741
+ { id: "code", label: "VS Code", command: "code" },
14742
+ { id: "cursor", label: "Cursor", command: "cursor" },
14743
+ { id: "windsurf", label: "Windsurf", command: "windsurf" },
14744
+ { id: "zed", label: "Zed", command: "zed" }
14745
+ ];
14746
+ MAC_APP_CANDIDATES = [
14747
+ {
14748
+ id: "vscode.app",
14749
+ label: "VS Code",
14750
+ appName: "Visual Studio Code",
14751
+ paths: ["/Applications/Visual Studio Code.app"]
14752
+ },
14753
+ {
14754
+ id: "cursor.app",
14755
+ label: "Cursor",
14756
+ appName: "Cursor",
14757
+ paths: ["/Applications/Cursor.app", "/System/Applications/Cursor.app"]
14758
+ },
14759
+ {
14760
+ id: "windsurf.app",
14761
+ label: "Windsurf",
14762
+ appName: "Windsurf",
14763
+ paths: ["/Applications/Windsurf.app"]
14764
+ },
14765
+ {
14766
+ id: "zed.app",
14767
+ label: "Zed",
14768
+ appName: "Zed",
14769
+ paths: ["/Applications/Zed.app"]
14770
+ }
14771
+ ];
14772
+ });
14773
+
14774
+ // src/tui/component/open-worktree-button.tsx
14775
+ import { TextAttributes as TextAttributes16 } from "@opentui/core";
14776
+ function canOpen(task, opener) {
14777
+ return Boolean(task?.worktreePath && opener);
14778
+ }
14779
+ function OpenWorktreeButton(props) {
14780
+ const {
14781
+ theme
14782
+ } = useTheme();
14783
+ const enabled = () => canOpen(props.activeTask(), props.opener());
14784
+ const label = () => props.opener()?.label ?? "Editor";
14785
+ const color = () => enabled() ? theme.accent : theme.textMuted;
14786
+ function onClick() {
14787
+ const task = props.activeTask();
14788
+ const opener = props.opener();
14789
+ if (!task?.worktreePath || !opener)
14790
+ return;
14791
+ if (!openWorktree(task.worktreePath, opener)) {
14792
+ console.error("[kobe] failed to open worktree:", task.worktreePath);
14793
+ }
14794
+ }
14795
+ return (() => {
14796
+ var _el$ = createElement("box"), _el$2 = createElement("text"), _el$4 = createElement("text");
14797
+ insertNode(_el$, _el$2);
14798
+ insertNode(_el$, _el$4);
14799
+ setProp(_el$, "flexDirection", "row");
14800
+ setProp(_el$, "gap", 1);
14801
+ setProp(_el$, "flexShrink", 0);
14802
+ insertNode(_el$2, createTextNode(`[Open]`));
14803
+ setProp(_el$2, "wrapMode", "none");
14804
+ setProp(_el$4, "wrapMode", "none");
14805
+ insert(_el$4, label);
14806
+ effect((_p$) => {
14807
+ var _v$ = enabled() ? onClick : undefined, _v$2 = color(), _v$3 = TextAttributes16.BOLD, _v$4 = theme.textMuted;
14808
+ _v$ !== _p$.e && (_p$.e = setProp(_el$, "onMouseUp", _v$, _p$.e));
14809
+ _v$2 !== _p$.t && (_p$.t = setProp(_el$2, "fg", _v$2, _p$.t));
14810
+ _v$3 !== _p$.a && (_p$.a = setProp(_el$2, "attributes", _v$3, _p$.a));
14811
+ _v$4 !== _p$.o && (_p$.o = setProp(_el$4, "fg", _v$4, _p$.o));
14812
+ return _p$;
14813
+ }, {
14814
+ e: undefined,
14815
+ t: undefined,
14816
+ a: undefined,
14817
+ o: undefined
14818
+ });
14819
+ return _el$;
14820
+ })();
14821
+ }
14822
+ var init_open_worktree_button = __esm(() => {
14823
+ init_solid();
14824
+ init_solid();
14825
+ init_solid();
14826
+ init_solid();
14827
+ init_solid();
14828
+ init_solid();
14829
+ init_theme();
14830
+ init_worktree_opener();
14831
+ });
14832
+
14656
14833
  // src/tui/panes/chat/markdown-parser.ts
14657
14834
  function splitTableRow(line) {
14658
14835
  const trimmed = line.trim().replace(/^\||\|$/g, "");
@@ -14919,7 +15096,7 @@ var init_markdown_parser = __esm(() => {
14919
15096
  });
14920
15097
 
14921
15098
  // src/tui/panes/chat/Markdown.tsx
14922
- import { TextAttributes as TextAttributes16 } from "@opentui/core";
15099
+ import { TextAttributes as TextAttributes17 } from "@opentui/core";
14923
15100
  function InlineSpans(props) {
14924
15101
  const {
14925
15102
  theme
@@ -14949,7 +15126,7 @@ function InlineSpans(props) {
14949
15126
  insert(_el$3, () => t.text, _el$5);
14950
15127
  effect((_$p) => setProp(_el$3, "style", {
14951
15128
  fg: theme.accent,
14952
- attributes: TextAttributes16.DIM
15129
+ attributes: TextAttributes17.DIM
14953
15130
  }, _$p));
14954
15131
  return _el$3;
14955
15132
  })();
@@ -14961,7 +15138,7 @@ function InlineSpans(props) {
14961
15138
  insert(_el$6, () => showUrl ? t.text : t.href);
14962
15139
  effect((_$p) => setProp(_el$6, "style", {
14963
15140
  fg: theme.accent,
14964
- attributes: TextAttributes16.UNDERLINE
15141
+ attributes: TextAttributes17.UNDERLINE
14965
15142
  }, _$p));
14966
15143
  return _el$6;
14967
15144
  })(), createComponent2(Show, {
@@ -14973,7 +15150,7 @@ function InlineSpans(props) {
14973
15150
  insert(_el$7, () => t.href, _el$9);
14974
15151
  effect((_$p) => setProp(_el$7, "style", {
14975
15152
  fg: theme.textMuted,
14976
- attributes: TextAttributes16.DIM
15153
+ attributes: TextAttributes17.DIM
14977
15154
  }, _$p));
14978
15155
  return _el$7;
14979
15156
  }
@@ -15150,7 +15327,7 @@ function VerticalTable(props) {
15150
15327
  var _el$20 = createElement("text");
15151
15328
  insertNode(_el$20, createTextNode(`\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`));
15152
15329
  effect((_p$) => {
15153
- var _v$4 = theme.textMuted, _v$5 = TextAttributes16.DIM;
15330
+ var _v$4 = theme.textMuted, _v$5 = TextAttributes17.DIM;
15154
15331
  _v$4 !== _p$.e && (_p$.e = setProp(_el$20, "fg", _v$4, _p$.e));
15155
15332
  _v$5 !== _p$.t && (_p$.t = setProp(_el$20, "attributes", _v$5, _p$.t));
15156
15333
  return _p$;
@@ -15241,7 +15418,7 @@ function BlockNode(props) {
15241
15418
  })();
15242
15419
  }
15243
15420
  if (b.kind === "heading") {
15244
- const attrs = b.level === 1 ? TextAttributes16.BOLD | TextAttributes16.UNDERLINE : TextAttributes16.BOLD;
15421
+ const attrs = b.level === 1 ? TextAttributes17.BOLD | TextAttributes17.UNDERLINE : TextAttributes17.BOLD;
15245
15422
  const fg = b.level <= 2 ? theme.accent : theme.text;
15246
15423
  const tokens = parseInline(b.text);
15247
15424
  return (() => {
@@ -15267,7 +15444,7 @@ function BlockNode(props) {
15267
15444
  const checkbox = item.checked ? "[x] " : "[ ] ";
15268
15445
  const bullet = b.ordered ? `${b.start + idx()}. ` : "\u2022 ";
15269
15446
  const prefix = isTask ? checkbox : bullet;
15270
- const labelAttrs = isTask && item.checked ? TextAttributes16.DIM : 0;
15447
+ const labelAttrs = isTask && item.checked ? TextAttributes17.DIM : 0;
15271
15448
  return (() => {
15272
15449
  var _el$30 = createElement("text"), _el$31 = createElement("span");
15273
15450
  insertNode(_el$30, _el$31);
@@ -15314,9 +15491,9 @@ function BlockNode(props) {
15314
15491
  }
15315
15492
  }), null);
15316
15493
  effect((_p$) => {
15317
- var _v$10 = theme.textMuted, _v$11 = TextAttributes16.ITALIC, _v$12 = {
15494
+ var _v$10 = theme.textMuted, _v$11 = TextAttributes17.ITALIC, _v$12 = {
15318
15495
  fg: theme.textMuted,
15319
- attributes: TextAttributes16.DIM
15496
+ attributes: TextAttributes17.DIM
15320
15497
  };
15321
15498
  _v$10 !== _p$.e && (_p$.e = setProp(_el$33, "fg", _v$10, _p$.e));
15322
15499
  _v$11 !== _p$.t && (_p$.t = setProp(_el$33, "attributes", _v$11, _p$.t));
@@ -15358,7 +15535,7 @@ function BlockNode(props) {
15358
15535
  var _el$37 = createElement("text");
15359
15536
  insert(_el$37, () => b.lang);
15360
15537
  effect((_p$) => {
15361
- var _v$13 = theme.textMuted, _v$14 = TextAttributes16.DIM;
15538
+ var _v$13 = theme.textMuted, _v$14 = TextAttributes17.DIM;
15362
15539
  _v$13 !== _p$.e && (_p$.e = setProp(_el$37, "fg", _v$13, _p$.e));
15363
15540
  _v$14 !== _p$.t && (_p$.t = setProp(_el$37, "attributes", _v$14, _p$.t));
15364
15541
  return _p$;
@@ -15418,7 +15595,7 @@ var init_Markdown = __esm(() => {
15418
15595
  });
15419
15596
 
15420
15597
  // src/tui/component/update-dialog.tsx
15421
- import { TextAttributes as TextAttributes17 } from "@opentui/core";
15598
+ import { TextAttributes as TextAttributes18 } from "@opentui/core";
15422
15599
  function UpdateDialog(props) {
15423
15600
  const dialog = useDialog();
15424
15601
  const {
@@ -15538,7 +15715,7 @@ function UpdateDialog(props) {
15538
15715
  }
15539
15716
  }));
15540
15717
  effect((_p$) => {
15541
- var _v$ = TextAttributes17.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted, _v$5 = theme.textMuted, _v$6 = theme.warning, _v$7 = TextAttributes17.BOLD, _v$8 = theme.textMuted, _v$9 = theme.accent, _v$0 = TextAttributes17.BOLD, _v$1 = theme.textMuted, _v$10 = theme.textMuted;
15718
+ var _v$ = TextAttributes18.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted, _v$5 = theme.textMuted, _v$6 = theme.warning, _v$7 = TextAttributes18.BOLD, _v$8 = theme.textMuted, _v$9 = theme.accent, _v$0 = TextAttributes18.BOLD, _v$1 = theme.textMuted, _v$10 = theme.textMuted;
15542
15719
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
15543
15720
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
15544
15721
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -15591,7 +15768,7 @@ var init_update_dialog = __esm(() => {
15591
15768
  });
15592
15769
 
15593
15770
  // src/tui/component/top-bar.tsx
15594
- import { TextAttributes as TextAttributes18 } from "@opentui/core";
15771
+ import { TextAttributes as TextAttributes19 } from "@opentui/core";
15595
15772
  function TopBar(props) {
15596
15773
  const {
15597
15774
  theme
@@ -15601,10 +15778,10 @@ function TopBar(props) {
15601
15778
  const rcBridge = props.orchestrator.rcBridgeSignal();
15602
15779
  const isBridgeOn = () => rcBridge().state === "running" || rcBridge().state === "starting";
15603
15780
  return (() => {
15604
- var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$6 = createTextNode(`v`), _el$10 = createElement("box"), _el$12 = createElement("box");
15781
+ var _el$ = createElement("box"), _el$2 = createElement("box"), _el$3 = createElement("text"), _el$5 = createElement("text"), _el$6 = createTextNode(`v`), _el$11 = createElement("box"), _el$13 = createElement("box");
15605
15782
  insertNode(_el$, _el$2);
15606
- insertNode(_el$, _el$10);
15607
- insertNode(_el$, _el$12);
15783
+ insertNode(_el$, _el$11);
15784
+ insertNode(_el$, _el$13);
15608
15785
  setProp(_el$, "flexDirection", "row");
15609
15786
  setProp(_el$, "paddingLeft", 2);
15610
15787
  setProp(_el$, "paddingRight", 2);
@@ -15635,7 +15812,7 @@ function TopBar(props) {
15635
15812
  });
15636
15813
  insert(_el$7, () => props.updateInfo()?.latest, _el$9);
15637
15814
  effect((_p$) => {
15638
- var _v$ = theme.warning, _v$2 = TextAttributes18.BOLD;
15815
+ var _v$ = theme.warning, _v$2 = TextAttributes19.BOLD;
15639
15816
  _v$ !== _p$.e && (_p$.e = setProp(_el$7, "fg", _v$, _p$.e));
15640
15817
  _v$2 !== _p$.t && (_p$.t = setProp(_el$7, "attributes", _v$2, _p$.t));
15641
15818
  return _p$;
@@ -15663,7 +15840,7 @@ function TopBar(props) {
15663
15840
  return () => _c$() ? rcBridge().bound?.taskTitle ?? rcBridge().envId ?? "RC" : "RC connecting\u2026";
15664
15841
  })(), null);
15665
15842
  effect((_p$) => {
15666
- var _v$3 = theme.accent, _v$4 = TextAttributes18.BOLD;
15843
+ var _v$3 = theme.accent, _v$4 = TextAttributes19.BOLD;
15667
15844
  _v$3 !== _p$.e && (_p$.e = setProp(_el$0, "fg", _v$3, _p$.e));
15668
15845
  _v$4 !== _p$.t && (_p$.t = setProp(_el$0, "attributes", _v$4, _p$.t));
15669
15846
  return _p$;
@@ -15674,47 +15851,56 @@ function TopBar(props) {
15674
15851
  return _el$0;
15675
15852
  }
15676
15853
  }), null);
15677
- setProp(_el$10, "flexDirection", "row");
15678
- setProp(_el$10, "flexGrow", 1);
15679
- setProp(_el$10, "flexShrink", 1);
15680
- setProp(_el$10, "flexBasis", 0);
15681
- setProp(_el$10, "gap", 1);
15682
- setProp(_el$10, "justifyContent", "center");
15683
- insert(_el$10, createComponent2(Show, {
15854
+ setProp(_el$11, "flexDirection", "row");
15855
+ setProp(_el$11, "flexGrow", 1);
15856
+ setProp(_el$11, "flexShrink", 1);
15857
+ setProp(_el$11, "flexBasis", 0);
15858
+ setProp(_el$11, "gap", 1);
15859
+ setProp(_el$11, "justifyContent", "center");
15860
+ insert(_el$11, createComponent2(Show, {
15684
15861
  get when() {
15685
15862
  return props.activeTask() !== undefined;
15686
15863
  },
15687
15864
  get children() {
15688
- var _el$11 = createElement("text");
15689
- setProp(_el$11, "wrapMode", "none");
15690
- insert(_el$11, () => props.activeTask()?.branch);
15865
+ var _el$12 = createElement("text");
15866
+ setProp(_el$12, "wrapMode", "none");
15867
+ insert(_el$12, () => props.activeTask()?.branch);
15691
15868
  effect((_p$) => {
15692
- var _v$5 = theme.text, _v$6 = TextAttributes18.BOLD;
15693
- _v$5 !== _p$.e && (_p$.e = setProp(_el$11, "fg", _v$5, _p$.e));
15694
- _v$6 !== _p$.t && (_p$.t = setProp(_el$11, "attributes", _v$6, _p$.t));
15869
+ var _v$5 = theme.text, _v$6 = TextAttributes19.BOLD;
15870
+ _v$5 !== _p$.e && (_p$.e = setProp(_el$12, "fg", _v$5, _p$.e));
15871
+ _v$6 !== _p$.t && (_p$.t = setProp(_el$12, "attributes", _v$6, _p$.t));
15695
15872
  return _p$;
15696
15873
  }, {
15697
15874
  e: undefined,
15698
15875
  t: undefined
15699
15876
  });
15700
- return _el$11;
15877
+ return _el$12;
15701
15878
  }
15702
15879
  }));
15703
- setProp(_el$12, "flexDirection", "row");
15704
- setProp(_el$12, "flexGrow", 1);
15705
- setProp(_el$12, "flexShrink", 1);
15706
- setProp(_el$12, "flexBasis", 0);
15707
- setProp(_el$12, "justifyContent", "flex-end");
15708
- insert(_el$12, createComponent2(CreatePRButton, {
15880
+ setProp(_el$13, "flexDirection", "row");
15881
+ setProp(_el$13, "flexGrow", 1);
15882
+ setProp(_el$13, "flexShrink", 1);
15883
+ setProp(_el$13, "flexBasis", 0);
15884
+ setProp(_el$13, "gap", 2);
15885
+ setProp(_el$13, "justifyContent", "flex-end");
15886
+ insert(_el$13, createComponent2(OpenWorktreeButton, {
15887
+ get activeTask() {
15888
+ return props.activeTask;
15889
+ },
15890
+ get opener() {
15891
+ return props.worktreeOpener;
15892
+ }
15893
+ }), null);
15894
+ insert(_el$13, createComponent2(CreatePRButton, {
15709
15895
  get orchestrator() {
15710
15896
  return props.orchestrator;
15711
15897
  },
15712
15898
  get activeTask() {
15713
15899
  return props.activeTask;
15714
15900
  }
15715
- }));
15901
+ }), null);
15716
15902
  effect((_p$) => {
15717
- var _v$7 = theme.primary, _v$8 = TextAttributes18.BOLD, _v$9 = theme.textMuted;
15903
+ var _v$7 = theme.primary, _v$8 = TextAttributes19.BOLD, _v$9 = theme.textMuted;
15718
15904
  _v$7 !== _p$.e && (_p$.e = setProp(_el$3, "fg", _v$7, _p$.e));
15719
15905
  _v$8 !== _p$.t && (_p$.t = setProp(_el$3, "attributes", _v$8, _p$.t));
15720
15906
  _v$9 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$9, _p$.a));
@@ -15742,6 +15928,7 @@ var init_top_bar = __esm(() => {
15742
15928
  init_theme();
15743
15929
  init_dialog();
15744
15930
  init_create_pr_button();
15931
+ init_open_worktree_button();
15745
15932
  init_rc_bridge_dialog();
15746
15933
  init_update_dialog();
15747
15934
  });
@@ -16141,10 +16328,10 @@ var init_sessions = __esm(() => {
16141
16328
  });
16142
16329
 
16143
16330
  // src/engine/claude-code-local/spawn.ts
16144
- import { spawn as spawn4 } from "child_process";
16331
+ import { spawn as spawn5 } from "child_process";
16145
16332
  function spawnClaudeProcess(opts) {
16146
16333
  const args2 = buildArgs(opts);
16147
- const proc = spawn4(opts.binaryPath, args2, {
16334
+ const proc = spawn5(opts.binaryPath, args2, {
16148
16335
  cwd: opts.cwd,
16149
16336
  env: { ...process.env, ...opts.env ?? {} },
16150
16337
  stdio: ["pipe", "pipe", "pipe"]
@@ -17218,7 +17405,7 @@ var DEFAULT_BASE_REF = "main", PICKER_MAX_VISIBLE = 8;
17218
17405
  var init_state2 = () => {};
17219
17406
 
17220
17407
  // src/tui/component/new-task-dialog/dialog.tsx
17221
- import { TextAttributes as TextAttributes19 } from "@opentui/core";
17408
+ import { TextAttributes as TextAttributes20 } from "@opentui/core";
17222
17409
  function NewTaskDialogView(props) {
17223
17410
  const dialog = useDialog();
17224
17411
  const {
@@ -17446,7 +17633,7 @@ function NewTaskDialogView(props) {
17446
17633
  insert(_el$35, suffix, null);
17447
17634
  insert(_el$35, tag, null);
17448
17635
  effect((_p$) => {
17449
- var _v$12 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$13 = isCursor() ? TextAttributes19.BOLD : undefined;
17636
+ var _v$12 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$13 = isCursor() ? TextAttributes20.BOLD : undefined;
17450
17637
  _v$12 !== _p$.e && (_p$.e = setProp(_el$35, "fg", _v$12, _p$.e));
17451
17638
  _v$13 !== _p$.t && (_p$.t = setProp(_el$35, "attributes", _v$13, _p$.t));
17452
17639
  return _p$;
@@ -17560,7 +17747,7 @@ function NewTaskDialogView(props) {
17560
17747
  insert(_el$36, () => isCursor() ? "\u25B8 " : " ", null);
17561
17748
  insert(_el$36, name, null);
17562
17749
  effect((_p$) => {
17563
- var _v$14 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$15 = isCursor() ? TextAttributes19.BOLD : undefined;
17750
+ var _v$14 = isCursor() ? theme.primary : isSelected() ? theme.accent : theme.textMuted, _v$15 = isCursor() ? TextAttributes20.BOLD : undefined;
17564
17751
  _v$14 !== _p$.e && (_p$.e = setProp(_el$36, "fg", _v$14, _p$.e));
17565
17752
  _v$15 !== _p$.t && (_p$.t = setProp(_el$36, "attributes", _v$15, _p$.t));
17566
17753
  return _p$;
@@ -17598,7 +17785,7 @@ function NewTaskDialogView(props) {
17598
17785
  setProp(_el$34, "onMouseUp", () => commit());
17599
17786
  insert(_el$34, () => field() === "confirm" ? "\u25B8 [ Create ]" : " [ Create ]");
17600
17787
  effect((_p$) => {
17601
- var _v$ = TextAttributes19.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = field() === "repo" ? theme.accent : theme.textMuted, _v$5 = repo(), _v$6 = props.defaultRepo, _v$7 = field() === "repo", _v$8 = field() === "baseRef" ? theme.accent : theme.textMuted, _v$9 = baseRef(), _v$0 = field() === "baseRef", _v$1 = theme.textMuted, _v$10 = field() === "confirm" ? theme.primary : theme.text, _v$11 = field() === "confirm" ? TextAttributes19.BOLD : undefined;
17788
+ var _v$ = TextAttributes20.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = field() === "repo" ? theme.accent : theme.textMuted, _v$5 = repo(), _v$6 = props.defaultRepo, _v$7 = field() === "repo", _v$8 = field() === "baseRef" ? theme.accent : theme.textMuted, _v$9 = baseRef(), _v$0 = field() === "baseRef", _v$1 = theme.textMuted, _v$10 = field() === "confirm" ? theme.primary : theme.text, _v$11 = field() === "confirm" ? TextAttributes20.BOLD : undefined;
17602
17789
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
17603
17790
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
17604
17791
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -17670,7 +17857,7 @@ var init_new_task_dialog = __esm(() => {
17670
17857
  });
17671
17858
 
17672
17859
  // src/tui/component/rename-task-dialog/dialog.tsx
17673
- import { TextAttributes as TextAttributes20 } from "@opentui/core";
17860
+ import { TextAttributes as TextAttributes21 } from "@opentui/core";
17674
17861
  function RenameTaskDialogView(props) {
17675
17862
  const dialog = useDialog();
17676
17863
  const {
@@ -17710,7 +17897,7 @@ function RenameTaskDialogView(props) {
17710
17897
  setProp(_el$0, "paddingBottom", 1);
17711
17898
  insertNode(_el$1, createTextNode(`enter rename \xB7 esc cancel`));
17712
17899
  effect((_p$) => {
17713
- var _v$ = TextAttributes20.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.accent, _v$5 = title(), _v$6 = props.currentTitle, _v$7 = theme.textMuted;
17900
+ var _v$ = TextAttributes21.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.accent, _v$5 = title(), _v$6 = props.currentTitle, _v$7 = theme.textMuted;
17714
17901
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
17715
17902
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
17716
17903
  _v$3 !== _p$.a && (_p$.a = setProp(_el$4, "fg", _v$3, _p$.a));
@@ -18039,7 +18226,7 @@ var init_use_workspace_tabs = __esm(() => {
18039
18226
  });
18040
18227
 
18041
18228
  // src/tui/component/resume-dialog.tsx
18042
- import { TextAttributes as TextAttributes21 } from "@opentui/core";
18229
+ import { TextAttributes as TextAttributes22 } from "@opentui/core";
18043
18230
  function ResumeDialog(props) {
18044
18231
  const dialog = useDialog();
18045
18232
  const {
@@ -18186,7 +18373,7 @@ function ResumeDialog(props) {
18186
18373
  setProp(_el$9, "paddingBottom", 1);
18187
18374
  insertNode(_el$0, createTextNode(`j/k or \u2191\u2193 navigate \u2022 enter resume \u2022 esc dismiss`));
18188
18375
  effect((_p$) => {
18189
- var _v$ = TextAttributes21.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
18376
+ var _v$ = TextAttributes22.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
18190
18377
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
18191
18378
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
18192
18379
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -18326,9 +18513,9 @@ var init_history2 = __esm(() => {
18326
18513
  // src/tui/panes/chat/composer/image-paste.ts
18327
18514
  import { randomUUID as randomUUID2 } from "crypto";
18328
18515
  import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "fs";
18329
- import { join as join13 } from "path";
18516
+ import { join as join14 } from "path";
18330
18517
  function pastedImagesDir() {
18331
- return join13(kobeStateDir(), "pasted-images");
18518
+ return join14(kobeStateDir(), "pasted-images");
18332
18519
  }
18333
18520
 
18334
18521
  class ImagePasteRegistry {
@@ -18408,7 +18595,7 @@ function mimeTypeToExt(mimeType) {
18408
18595
  return ".png";
18409
18596
  }
18410
18597
  function mintPath(ext) {
18411
- return join13(pastedImagesDir(), `${randomUUID2()}${ext}`);
18598
+ return join14(pastedImagesDir(), `${randomUUID2()}${ext}`);
18412
18599
  }
18413
18600
  var IMAGE_TOKEN_RE;
18414
18601
  var init_image_paste = __esm(() => {
@@ -18511,7 +18698,7 @@ var init_mention = __esm(() => {
18511
18698
  });
18512
18699
 
18513
18700
  // src/tui/panes/chat/Composer.tsx
18514
- import { TextAttributes as TextAttributes22 } from "@opentui/core";
18701
+ import { TextAttributes as TextAttributes23 } from "@opentui/core";
18515
18702
  function resolvePlaceholder(opts) {
18516
18703
  if (!opts.hasTask)
18517
18704
  return opts.noTaskMessage ?? "(no task \u2014 press n to create)";
@@ -19079,7 +19266,7 @@ function Composer(props) {
19079
19266
  }
19080
19267
  }), null);
19081
19268
  effect((_p$) => {
19082
- var _v$23 = active() ? theme.primary : theme.text, _v$24 = active() ? TextAttributes22.BOLD : undefined;
19269
+ var _v$23 = active() ? theme.primary : theme.text, _v$24 = active() ? TextAttributes23.BOLD : undefined;
19083
19270
  _v$23 !== _p$.e && (_p$.e = setProp(_el$33, "fg", _v$23, _p$.e));
19084
19271
  _v$24 !== _p$.t && (_p$.t = setProp(_el$33, "attributes", _v$24, _p$.t));
19085
19272
  return _p$;
@@ -19186,7 +19373,7 @@ function Composer(props) {
19186
19373
  }
19187
19374
  }), null);
19188
19375
  effect((_p$) => {
19189
- var _v$25 = active() ? theme.primary : theme.text, _v$26 = active() ? TextAttributes22.BOLD : undefined;
19376
+ var _v$25 = active() ? theme.primary : theme.text, _v$26 = active() ? TextAttributes23.BOLD : undefined;
19190
19377
  _v$25 !== _p$.e && (_p$.e = setProp(_el$36, "fg", _v$25, _p$.e));
19191
19378
  _v$26 !== _p$.t && (_p$.t = setProp(_el$36, "attributes", _v$26, _p$.t));
19192
19379
  return _p$;
@@ -19270,7 +19457,7 @@ function Composer(props) {
19270
19457
  insertNode(_el$50, createTextNode(`[x]`));
19271
19458
  setProp(_el$50, "onMouseUp", () => props.onCancelQueued?.(entry.id));
19272
19459
  effect((_p$) => {
19273
- var _v$27 = theme.textMuted, _v$28 = TextAttributes22.BOLD, _v$29 = theme.textMuted, _v$30 = theme.text, _v$31 = theme.primary, _v$32 = TextAttributes22.BOLD, _v$33 = theme.error, _v$34 = TextAttributes22.BOLD;
19460
+ var _v$27 = theme.textMuted, _v$28 = TextAttributes23.BOLD, _v$29 = theme.textMuted, _v$30 = theme.text, _v$31 = theme.primary, _v$32 = TextAttributes23.BOLD, _v$33 = theme.error, _v$34 = TextAttributes23.BOLD;
19274
19461
  _v$27 !== _p$.e && (_p$.e = setProp(_el$41, "fg", _v$27, _p$.e));
19275
19462
  _v$28 !== _p$.t && (_p$.t = setProp(_el$41, "attributes", _v$28, _p$.t));
19276
19463
  _v$29 !== _p$.a && (_p$.a = setProp(_el$43, "fg", _v$29, _p$.a));
@@ -19307,7 +19494,7 @@ function Composer(props) {
19307
19494
  insertNode(_el$18, createTextNode(`+`));
19308
19495
  insert(_el$20, () => `\u2026 ${(props.queue?.() ?? []).length - QUEUE_VISIBLE_CAP} more queued`);
19309
19496
  effect((_p$) => {
19310
- var _v$7 = theme.textMuted, _v$8 = TextAttributes22.BOLD, _v$9 = theme.textMuted;
19497
+ var _v$7 = theme.textMuted, _v$8 = TextAttributes23.BOLD, _v$9 = theme.textMuted;
19311
19498
  _v$7 !== _p$.e && (_p$.e = setProp(_el$18, "fg", _v$7, _p$.e));
19312
19499
  _v$8 !== _p$.t && (_p$.t = setProp(_el$18, "attributes", _v$8, _p$.t));
19313
19500
  _v$9 !== _p$.a && (_p$.a = setProp(_el$20, "fg", _v$9, _p$.a));
@@ -20109,7 +20296,7 @@ function summarizeGlob(input, output, done) {
20109
20296
  }
20110
20297
 
20111
20298
  // src/tui/panes/chat/MessageList.tsx
20112
- import { TextAttributes as TextAttributes23 } from "@opentui/core";
20299
+ import { TextAttributes as TextAttributes24 } from "@opentui/core";
20113
20300
  function previewToolInput(input) {
20114
20301
  if (input == null)
20115
20302
  return "";
@@ -20205,7 +20392,7 @@ function UserRow(props) {
20205
20392
  })() : null;
20206
20393
  })(), null);
20207
20394
  effect((_p$) => {
20208
- var _v$ = theme.accent, _v$2 = TextAttributes23.BOLD, _v$3 = theme.primary, _v$4 = TextAttributes23.BOLD;
20395
+ var _v$ = theme.accent, _v$2 = TextAttributes24.BOLD, _v$3 = theme.primary, _v$4 = TextAttributes24.BOLD;
20209
20396
  _v$ !== _p$.e && (_p$.e = setProp(_el$2, "fg", _v$, _p$.e));
20210
20397
  _v$2 !== _p$.t && (_p$.t = setProp(_el$2, "attributes", _v$2, _p$.t));
20211
20398
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -20285,7 +20472,7 @@ function UserRow(props) {
20285
20472
  setProp(_el$21, "flexGrow", 1);
20286
20473
  insert(_el$22, () => view.text);
20287
20474
  effect((_p$) => {
20288
- var _v$9 = theme.accent, _v$0 = TextAttributes23.BOLD, _v$1 = theme.text;
20475
+ var _v$9 = theme.accent, _v$0 = TextAttributes24.BOLD, _v$1 = theme.text;
20289
20476
  _v$9 !== _p$.e && (_p$.e = setProp(_el$19, "fg", _v$9, _p$.e));
20290
20477
  _v$0 !== _p$.t && (_p$.t = setProp(_el$19, "attributes", _v$0, _p$.t));
20291
20478
  _v$1 !== _p$.a && (_p$.a = setProp(_el$22, "fg", _v$1, _p$.a));
@@ -20321,7 +20508,7 @@ function AssistantRow(props) {
20321
20508
  }
20322
20509
  }));
20323
20510
  effect((_p$) => {
20324
- var _v$10 = theme.accent, _v$11 = TextAttributes23.BOLD;
20511
+ var _v$10 = theme.accent, _v$11 = TextAttributes24.BOLD;
20325
20512
  _v$10 !== _p$.e && (_p$.e = setProp(_el$25, "fg", _v$10, _p$.e));
20326
20513
  _v$11 !== _p$.t && (_p$.t = setProp(_el$25, "attributes", _v$11, _p$.t));
20327
20514
  return _p$;
@@ -20396,7 +20583,7 @@ function ToolRow(props) {
20396
20583
  }), null);
20397
20584
  effect((_p$) => {
20398
20585
  var _v$18 = theme.text, _v$19 = {
20399
- attributes: TextAttributes23.BOLD
20586
+ attributes: TextAttributes24.BOLD
20400
20587
  };
20401
20588
  _v$18 !== _p$.e && (_p$.e = setProp(_el$45, "fg", _v$18, _p$.e));
20402
20589
  _v$19 !== _p$.t && (_p$.t = setProp(_el$46, "style", _v$19, _p$.t));
@@ -20564,7 +20751,7 @@ function ToolRow(props) {
20564
20751
  }
20565
20752
  }), null);
20566
20753
  effect((_p$) => {
20567
- var _v$16 = prefixColor(), _v$17 = TextAttributes23.BOLD;
20754
+ var _v$16 = prefixColor(), _v$17 = TextAttributes24.BOLD;
20568
20755
  _v$16 !== _p$.e && (_p$.e = setProp(_el$29, "fg", _v$16, _p$.e));
20569
20756
  _v$17 !== _p$.t && (_p$.t = setProp(_el$29, "attributes", _v$17, _p$.t));
20570
20757
  return _p$;
@@ -20803,7 +20990,7 @@ function BashBanner(props) {
20803
20990
  }
20804
20991
  }), null);
20805
20992
  effect((_p$) => {
20806
- var _v$28 = theme.accent, _v$29 = TextAttributes23.BOLD, _v$30 = theme.text;
20993
+ var _v$28 = theme.accent, _v$29 = TextAttributes24.BOLD, _v$30 = theme.text;
20807
20994
  _v$28 !== _p$.e && (_p$.e = setProp(_el$73, "fg", _v$28, _p$.e));
20808
20995
  _v$29 !== _p$.t && (_p$.t = setProp(_el$73, "attributes", _v$29, _p$.t));
20809
20996
  _v$30 !== _p$.a && (_p$.a = setProp(_el$76, "fg", _v$30, _p$.a));
@@ -20891,7 +21078,7 @@ function ReadGrepGlobBanner(props) {
20891
21078
  }), null);
20892
21079
  effect((_p$) => {
20893
21080
  var _v$31 = theme.text, _v$32 = {
20894
- attributes: TextAttributes23.BOLD
21081
+ attributes: TextAttributes24.BOLD
20895
21082
  };
20896
21083
  _v$31 !== _p$.e && (_p$.e = setProp(_el$81, "fg", _v$31, _p$.e));
20897
21084
  _v$32 !== _p$.t && (_p$.t = setProp(_el$82, "style", _v$32, _p$.t));
@@ -20920,7 +21107,7 @@ function SystemRow(props) {
20920
21107
  setProp(_el$87, "flexGrow", 1);
20921
21108
  insert(_el$88, () => props.text);
20922
21109
  effect((_p$) => {
20923
- var _v$33 = theme.textMuted, _v$34 = TextAttributes23.DIM, _v$35 = isError() ? theme.error : theme.textMuted;
21110
+ var _v$33 = theme.textMuted, _v$34 = TextAttributes24.DIM, _v$35 = isError() ? theme.error : theme.textMuted;
20924
21111
  _v$33 !== _p$.e && (_p$.e = setProp(_el$85, "fg", _v$33, _p$.e));
20925
21112
  _v$34 !== _p$.t && (_p$.t = setProp(_el$85, "attributes", _v$34, _p$.t));
20926
21113
  _v$35 !== _p$.a && (_p$.a = setProp(_el$88, "fg", _v$35, _p$.a));
@@ -21010,7 +21197,7 @@ function ApprovalRow(props) {
21010
21197
  insertNode(_el$103, _el$105);
21011
21198
  insert(_el$103, () => r().status, _el$105);
21012
21199
  effect((_p$) => {
21013
- var _v$44 = r().status === "approved" ? theme.success : theme.error, _v$45 = TextAttributes23.BOLD;
21200
+ var _v$44 = r().status === "approved" ? theme.success : theme.error, _v$45 = TextAttributes24.BOLD;
21014
21201
  _v$44 !== _p$.e && (_p$.e = setProp(_el$103, "fg", _v$44, _p$.e));
21015
21202
  _v$45 !== _p$.t && (_p$.t = setProp(_el$103, "attributes", _v$45, _p$.t));
21016
21203
  return _p$;
@@ -21027,7 +21214,7 @@ function ApprovalRow(props) {
21027
21214
  insertNode(_el$99, createTextNode(`[ Approve ]`));
21028
21215
  setProp(_el$99, "onMouseUp", () => props.onApprove(true));
21029
21216
  effect((_p$) => {
21030
- var _v$36 = theme.success, _v$37 = TextAttributes23.BOLD;
21217
+ var _v$36 = theme.success, _v$37 = TextAttributes24.BOLD;
21031
21218
  _v$36 !== _p$.e && (_p$.e = setProp(_el$99, "fg", _v$36, _p$.e));
21032
21219
  _v$37 !== _p$.t && (_p$.t = setProp(_el$99, "attributes", _v$37, _p$.t));
21033
21220
  return _p$;
@@ -21041,7 +21228,7 @@ function ApprovalRow(props) {
21041
21228
  insertNode(_el$101, createTextNode(`[ Reject ]`));
21042
21229
  setProp(_el$101, "onMouseUp", () => props.onApprove(false));
21043
21230
  effect((_p$) => {
21044
- var _v$38 = theme.error, _v$39 = TextAttributes23.BOLD;
21231
+ var _v$38 = theme.error, _v$39 = TextAttributes24.BOLD;
21045
21232
  _v$38 !== _p$.e && (_p$.e = setProp(_el$101, "fg", _v$38, _p$.e));
21046
21233
  _v$39 !== _p$.t && (_p$.t = setProp(_el$101, "attributes", _v$39, _p$.t));
21047
21234
  return _p$;
@@ -21054,7 +21241,7 @@ function ApprovalRow(props) {
21054
21241
  }
21055
21242
  }));
21056
21243
  effect((_p$) => {
21057
- var _v$40 = headerColor(), _v$41 = TextAttributes23.BOLD, _v$42 = headerColor(), _v$43 = TextAttributes23.BOLD;
21244
+ var _v$40 = headerColor(), _v$41 = TextAttributes24.BOLD, _v$42 = headerColor(), _v$43 = TextAttributes24.BOLD;
21058
21245
  _v$40 !== _p$.e && (_p$.e = setProp(_el$91, "fg", _v$40, _p$.e));
21059
21246
  _v$41 !== _p$.t && (_p$.t = setProp(_el$91, "attributes", _v$41, _p$.t));
21060
21247
  _v$42 !== _p$.a && (_p$.a = setProp(_el$92, "fg", _v$42, _p$.a));
@@ -21276,7 +21463,7 @@ function QuestionRow(props) {
21276
21463
  insertNode(_el$116, _el$118);
21277
21464
  insert(_el$116, () => q.header, _el$118);
21278
21465
  effect((_p$) => {
21279
- var _v$52 = theme.accent, _v$53 = TextAttributes23.BOLD;
21466
+ var _v$52 = theme.accent, _v$53 = TextAttributes24.BOLD;
21280
21467
  _v$52 !== _p$.e && (_p$.e = setProp(_el$116, "fg", _v$52, _p$.e));
21281
21468
  _v$53 !== _p$.t && (_p$.t = setProp(_el$116, "attributes", _v$53, _p$.t));
21282
21469
  return _p$;
@@ -21390,7 +21577,7 @@ function QuestionRow(props) {
21390
21577
  }
21391
21578
  }), null);
21392
21579
  effect((_p$) => {
21393
- 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;
21580
+ var _v$58 = isHl() ? theme.accent : theme.textMuted, _v$59 = TextAttributes24.BOLD, _v$60 = theme.textMuted, _v$61 = isPicked() ? theme.accent : theme.textMuted, _v$62 = TextAttributes24.BOLD, _v$63 = theme.text;
21394
21581
  _v$58 !== _p$.e && (_p$.e = setProp(_el$136, "fg", _v$58, _p$.e));
21395
21582
  _v$59 !== _p$.t && (_p$.t = setProp(_el$136, "attributes", _v$59, _p$.t));
21396
21583
  _v$60 !== _p$.a && (_p$.a = setProp(_el$137, "fg", _v$60, _p$.a));
@@ -21435,7 +21622,7 @@ function QuestionRow(props) {
21435
21622
  insertNode(_el$147, createTextNode(`Other`));
21436
21623
  insertNode(_el$149, createTextNode(`Type your own answer`));
21437
21624
  effect((_p$) => {
21438
- 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;
21625
+ var _v$64 = isOtherHl() ? theme.accent : theme.textMuted, _v$65 = TextAttributes24.BOLD, _v$66 = theme.textMuted, _v$67 = otherPicked() ? theme.accent : theme.textMuted, _v$68 = TextAttributes24.BOLD, _v$69 = theme.text, _v$70 = theme.textMuted;
21439
21626
  _v$64 !== _p$.e && (_p$.e = setProp(_el$143, "fg", _v$64, _p$.e));
21440
21627
  _v$65 !== _p$.t && (_p$.t = setProp(_el$143, "attributes", _v$65, _p$.t));
21441
21628
  _v$66 !== _p$.a && (_p$.a = setProp(_el$144, "fg", _v$66, _p$.a));
@@ -21491,7 +21678,7 @@ function QuestionRow(props) {
21491
21678
  }
21492
21679
  }), null);
21493
21680
  effect((_p$) => {
21494
- var _v$54 = isQuestionComplete(index()) ? theme.success : theme.textMuted, _v$55 = TextAttributes23.BOLD;
21681
+ var _v$54 = isQuestionComplete(index()) ? theme.success : theme.textMuted, _v$55 = TextAttributes24.BOLD;
21495
21682
  _v$54 !== _p$.e && (_p$.e = setProp(_el$132, "fg", _v$54, _p$.e));
21496
21683
  _v$55 !== _p$.t && (_p$.t = setProp(_el$132, "attributes", _v$55, _p$.t));
21497
21684
  return _p$;
@@ -21527,7 +21714,7 @@ function QuestionRow(props) {
21527
21714
  setProp(_el$111, "paddingTop", 1);
21528
21715
  insertNode(_el$112, createTextNode(`[submitted]`));
21529
21716
  effect((_p$) => {
21530
- var _v$46 = theme.success, _v$47 = TextAttributes23.BOLD;
21717
+ var _v$46 = theme.success, _v$47 = TextAttributes24.BOLD;
21531
21718
  _v$46 !== _p$.e && (_p$.e = setProp(_el$112, "fg", _v$46, _p$.e));
21532
21719
  _v$47 !== _p$.t && (_p$.t = setProp(_el$112, "attributes", _v$47, _p$.t));
21533
21720
  return _p$;
@@ -21539,7 +21726,7 @@ function QuestionRow(props) {
21539
21726
  }
21540
21727
  }), null);
21541
21728
  effect((_p$) => {
21542
- var _v$48 = theme.warning, _v$49 = TextAttributes23.BOLD, _v$50 = theme.warning, _v$51 = TextAttributes23.BOLD;
21729
+ var _v$48 = theme.warning, _v$49 = TextAttributes24.BOLD, _v$50 = theme.warning, _v$51 = TextAttributes24.BOLD;
21543
21730
  _v$48 !== _p$.e && (_p$.e = setProp(_el$108, "fg", _v$48, _p$.e));
21544
21731
  _v$49 !== _p$.t && (_p$.t = setProp(_el$108, "attributes", _v$49, _p$.t));
21545
21732
  _v$50 !== _p$.a && (_p$.a = setProp(_el$110, "fg", _v$50, _p$.a));
@@ -21659,7 +21846,7 @@ function MessageList(props) {
21659
21846
  insertNode(_el$160, _el$161);
21660
21847
  insert(_el$160, () => props.error, null);
21661
21848
  effect((_p$) => {
21662
- var _v$71 = theme.error, _v$72 = TextAttributes23.BOLD, _v$73 = theme.error;
21849
+ var _v$71 = theme.error, _v$72 = TextAttributes24.BOLD, _v$73 = theme.error;
21663
21850
  _v$71 !== _p$.e && (_p$.e = setProp(_el$158, "fg", _v$71, _p$.e));
21664
21851
  _v$72 !== _p$.t && (_p$.t = setProp(_el$158, "attributes", _v$72, _p$.t));
21665
21852
  _v$73 !== _p$.a && (_p$.a = setProp(_el$160, "fg", _v$73, _p$.a));
@@ -21815,7 +22002,7 @@ function ToolFoldRow(props) {
21815
22002
  setProp(_el$164, "flexGrow", 1);
21816
22003
  insert(_el$165, () => props.summary);
21817
22004
  effect((_p$) => {
21818
- var _v$74 = fg(), _v$75 = TextAttributes23.DIM, _v$76 = theme.textMuted;
22005
+ var _v$74 = fg(), _v$75 = TextAttributes24.DIM, _v$76 = theme.textMuted;
21819
22006
  _v$74 !== _p$.e && (_p$.e = setProp(_el$163, "fg", _v$74, _p$.e));
21820
22007
  _v$75 !== _p$.t && (_p$.t = setProp(_el$163, "attributes", _v$75, _p$.t));
21821
22008
  _v$76 !== _p$.a && (_p$.a = setProp(_el$165, "fg", _v$76, _p$.a));
@@ -21880,7 +22067,7 @@ var init_models = __esm(() => {
21880
22067
  });
21881
22068
 
21882
22069
  // src/tui/panes/chat/composer/ModelPicker.tsx
21883
- import { TextAttributes as TextAttributes24 } from "@opentui/core";
22070
+ import { TextAttributes as TextAttributes25 } from "@opentui/core";
21884
22071
  function ModelPicker(props) {
21885
22072
  const dialog = useDialog();
21886
22073
  const {
@@ -21960,7 +22147,7 @@ function ModelPicker(props) {
21960
22147
  })() : null;
21961
22148
  })(), null);
21962
22149
  effect((_p$) => {
21963
- var _v$5 = active() ? theme.primary : undefined, _v$6 = active() ? theme.selectedListItemText : theme.text, _v$7 = active() ? TextAttributes24.BOLD : undefined;
22150
+ var _v$5 = active() ? theme.primary : undefined, _v$6 = active() ? theme.selectedListItemText : theme.text, _v$7 = active() ? TextAttributes25.BOLD : undefined;
21964
22151
  _v$5 !== _p$.e && (_p$.e = setProp(_el$1, "backgroundColor", _v$5, _p$.e));
21965
22152
  _v$6 !== _p$.t && (_p$.t = setProp(_el$10, "fg", _v$6, _p$.t));
21966
22153
  _v$7 !== _p$.a && (_p$.a = setProp(_el$10, "attributes", _v$7, _p$.a));
@@ -21978,7 +22165,7 @@ function ModelPicker(props) {
21978
22165
  setProp(_el$8, "paddingBottom", 1);
21979
22166
  insertNode(_el$9, createTextNode(`\u2191\u2193 pick \xB7 enter select \xB7 esc cancel`));
21980
22167
  effect((_p$) => {
21981
- var _v$ = TextAttributes24.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
22168
+ var _v$ = TextAttributes25.BOLD, _v$2 = theme.text, _v$3 = theme.textMuted, _v$4 = theme.textMuted;
21982
22169
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "attributes", _v$, _p$.e));
21983
22170
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
21984
22171
  _v$3 !== _p$.a && (_p$.a = setProp(_el$5, "fg", _v$3, _p$.a));
@@ -22021,7 +22208,7 @@ var init_ModelPicker = __esm(() => {
22021
22208
  // src/tui/panes/chat/composer/user-slashes.ts
22022
22209
  import { readFile as readFile6, readdir as readdir3, stat as stat3 } from "fs/promises";
22023
22210
  import { homedir as homedir11 } from "os";
22024
- import { join as join14 } from "path";
22211
+ import { join as join15 } from "path";
22025
22212
  function resolveHome() {
22026
22213
  return process.env.HOME ?? homedir11();
22027
22214
  }
@@ -22127,7 +22314,7 @@ async function scanCommandsDir(dir) {
22127
22314
  for (const entry of entries) {
22128
22315
  if (!entry.endsWith(".md"))
22129
22316
  continue;
22130
- const full = join14(dir, entry);
22317
+ const full = join15(dir, entry);
22131
22318
  if (!await isFile(full))
22132
22319
  continue;
22133
22320
  const name = entry.slice(0, -3);
@@ -22140,10 +22327,10 @@ async function scanSkillsDir(dir) {
22140
22327
  const entries = await safeReaddir(dir);
22141
22328
  const out = [];
22142
22329
  for (const entry of entries) {
22143
- const sub = join14(dir, entry);
22330
+ const sub = join15(dir, entry);
22144
22331
  if (!await isDir(sub))
22145
22332
  continue;
22146
- const skillMd = join14(sub, "SKILL.md");
22333
+ const skillMd = join15(sub, "SKILL.md");
22147
22334
  if (!await isFile(skillMd))
22148
22335
  continue;
22149
22336
  const description = await tryReadDescription(skillMd) ?? "";
@@ -22153,8 +22340,8 @@ async function scanSkillsDir(dir) {
22153
22340
  }
22154
22341
  async function scanBasePath(claudeDir) {
22155
22342
  const [skills, commands] = await Promise.all([
22156
- scanSkillsDir(join14(claudeDir, "skills")),
22157
- scanCommandsDir(join14(claudeDir, "commands"))
22343
+ scanSkillsDir(join15(claudeDir, "skills")),
22344
+ scanCommandsDir(join15(claudeDir, "commands"))
22158
22345
  ]);
22159
22346
  const map = new Map;
22160
22347
  for (const e of skills)
@@ -22164,8 +22351,8 @@ async function scanBasePath(claudeDir) {
22164
22351
  return [...map.values()];
22165
22352
  }
22166
22353
  async function loadUserSlashes(worktreePath) {
22167
- const projectScan = worktreePath ? scanBasePath(join14(worktreePath, ".claude")) : Promise.resolve([]);
22168
- const globalScan = scanBasePath(join14(resolveHome(), ".claude"));
22354
+ const projectScan = worktreePath ? scanBasePath(join15(worktreePath, ".claude")) : Promise.resolve([]);
22355
+ const globalScan = scanBasePath(join15(resolveHome(), ".claude"));
22169
22356
  const [project, global] = await Promise.all([projectScan, globalScan]);
22170
22357
  const map = new Map;
22171
22358
  for (const e of global)
@@ -23403,7 +23590,7 @@ var init_Chat = __esm(() => {
23403
23590
  });
23404
23591
 
23405
23592
  // src/tui/component/sidebar.tsx
23406
- import { TextAttributes as TextAttributes25 } from "@opentui/core";
23593
+ import { TextAttributes as TextAttributes26 } from "@opentui/core";
23407
23594
  function Sidebar(props) {
23408
23595
  const {
23409
23596
  theme
@@ -23429,7 +23616,7 @@ function Sidebar(props) {
23429
23616
  setProp(_el$2, "paddingBottom", 1);
23430
23617
  insert(_el$3, () => props.title);
23431
23618
  effect((_p$) => {
23432
- var _v$ = theme.text, _v$2 = TextAttributes25.BOLD;
23619
+ var _v$ = theme.text, _v$2 = TextAttributes26.BOLD;
23433
23620
  _v$ !== _p$.e && (_p$.e = setProp(_el$3, "fg", _v$, _p$.e));
23434
23621
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "attributes", _v$2, _p$.t));
23435
23622
  return _p$;
@@ -23688,7 +23875,7 @@ var init_keys4 = __esm(() => {
23688
23875
  });
23689
23876
 
23690
23877
  // src/tui/panes/sidebar/Sidebar.tsx
23691
- import { TextAttributes as TextAttributes26 } from "@opentui/core";
23878
+ import { TextAttributes as TextAttributes27 } from "@opentui/core";
23692
23879
  function Sidebar2(props) {
23693
23880
  const {
23694
23881
  theme
@@ -23780,7 +23967,7 @@ function Sidebar2(props) {
23780
23967
  return () => _c$() ? `[ ${tab.label} ]` : tab.label;
23781
23968
  })());
23782
23969
  effect((_p$) => {
23783
- var _v$7 = active() ? theme.primary : theme.textMuted, _v$8 = active() ? TextAttributes26.BOLD : undefined;
23970
+ var _v$7 = active() ? theme.primary : theme.textMuted, _v$8 = active() ? TextAttributes27.BOLD : undefined;
23784
23971
  _v$7 !== _p$.e && (_p$.e = setProp(_el$13, "fg", _v$7, _p$.e));
23785
23972
  _v$8 !== _p$.t && (_p$.t = setProp(_el$13, "attributes", _v$8, _p$.t));
23786
23973
  return _p$;
@@ -23875,7 +24062,7 @@ function Sidebar2(props) {
23875
24062
  }
23876
24063
  }), null);
23877
24064
  effect((_p$) => {
23878
- var _v$9 = isCursor() ? theme.primary : isSelected() ? theme.backgroundElement : undefined, _v$0 = isCursor() ? theme.selectedListItemText : badgeColor(), _v$1 = isCursor() ? theme.selectedListItemText : theme.text, _v$10 = (isMain || isSelected() && !isCursor()) && !isCursor() ? TextAttributes26.BOLD : undefined;
24065
+ var _v$9 = isCursor() ? theme.primary : isSelected() ? theme.backgroundElement : undefined, _v$0 = isCursor() ? theme.selectedListItemText : badgeColor(), _v$1 = isCursor() ? theme.selectedListItemText : theme.text, _v$10 = (isMain || isSelected() && !isCursor()) && !isCursor() ? TextAttributes27.BOLD : undefined;
23879
24066
  _v$9 !== _p$.e && (_p$.e = setProp(_el$14, "backgroundColor", _v$9, _p$.e));
23880
24067
  _v$0 !== _p$.t && (_p$.t = setProp(_el$15, "fg", _v$0, _p$.t));
23881
24068
  _v$1 !== _p$.a && (_p$.a = setProp(_el$16, "fg", _v$1, _p$.a));
@@ -23913,7 +24100,7 @@ function Sidebar2(props) {
23913
24100
  setProp(_el$11, "wrapMode", "none");
23914
24101
  setProp(_el$11, "onMouseUp", () => props.onAddTask?.());
23915
24102
  effect((_p$) => {
23916
- var _v$ = props.width ? props.width() : SIDEBAR_WIDTH, _v$2 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$3 = TextAttributes26.BOLD, _v$4 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$5 = TextAttributes26.BOLD, _v$6 = theme.textMuted;
24103
+ var _v$ = props.width ? props.width() : SIDEBAR_WIDTH, _v$2 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$3 = TextAttributes27.BOLD, _v$4 = focusedAccessor() ? theme.focusAccent : theme.textMuted, _v$5 = TextAttributes27.BOLD, _v$6 = theme.textMuted;
23917
24104
  _v$ !== _p$.e && (_p$.e = setProp(_el$, "width", _v$, _p$.e));
23918
24105
  _v$2 !== _p$.t && (_p$.t = setProp(_el$3, "fg", _v$2, _p$.t));
23919
24106
  _v$3 !== _p$.a && (_p$.a = setProp(_el$3, "attributes", _v$3, _p$.a));
@@ -24118,18 +24305,29 @@ var init_server = () => {};
24118
24305
  // src/orchestrator/bridge/index.ts
24119
24306
  var exports_bridge = {};
24120
24307
  __export(exports_bridge, {
24121
- startBridge: () => startBridge
24308
+ startBridge: () => startBridge,
24309
+ bridgeSocketPathForHome: () => bridgeSocketPathForHome
24122
24310
  });
24123
- import { writeFile as writeFile4 } from "fs/promises";
24124
- import { homedir as homedir12 } from "os";
24125
- import { join as join15 } from "path";
24311
+ import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
24312
+ import { homedir as homedir12, tmpdir as tmpdir3 } from "os";
24313
+ import { join as join16 } from "path";
24126
24314
  import { fileURLToPath as fileURLToPath2 } from "url";
24315
+ function bridgeSocketPathForHome(home, pid = process.pid) {
24316
+ const runDir = join16(home, ".kobe", "run");
24317
+ const preferred = join16(runDir, `bridge-${pid}.sock`);
24318
+ const macTempSocket = process.platform === "darwin" && preferred.startsWith(tmpdir3());
24319
+ if (preferred.length <= UNIX_SOCKET_PATH_LIMIT && !macTempSocket)
24320
+ return preferred;
24321
+ const shortTmp = process.platform === "darwin" ? "/tmp" : tmpdir3();
24322
+ return join16(shortTmp, `kobe-bridge-${pid}.sock`);
24323
+ }
24127
24324
  async function startBridge(orch, opts = {}) {
24128
24325
  const home = opts.homeDir ?? process.env.KOBE_HOME_DIR ?? homedir12();
24129
- const runDir = join15(home, ".kobe", "run");
24130
- const socketPath = join15(runDir, `bridge-${process.pid}.sock`);
24131
- const mcpConfigPath = join15(runDir, `mcp-${process.pid}.json`);
24326
+ const runDir = join16(home, ".kobe", "run");
24327
+ const socketPath = bridgeSocketPathForHome(home);
24328
+ const mcpConfigPath = join16(runDir, `mcp-${process.pid}.json`);
24132
24329
  const server = await startBridgeServer(orch, socketPath);
24330
+ await mkdir5(runDir, { recursive: true });
24133
24331
  const moduleExt = import.meta.url.endsWith(".ts") ? ".ts" : ".js";
24134
24332
  const entry = fileURLToPath2(new URL(`../../cli/index${moduleExt}`, import.meta.url));
24135
24333
  const mcpConfig = {
@@ -24150,13 +24348,14 @@ async function startBridge(orch, opts = {}) {
24150
24348
  }
24151
24349
  };
24152
24350
  }
24351
+ var UNIX_SOCKET_PATH_LIMIT = 103;
24153
24352
  var init_bridge = __esm(() => {
24154
24353
  init_server();
24155
24354
  });
24156
24355
 
24157
24356
  // src/tui/app.tsx
24158
24357
  import { homedir as homedir13 } from "os";
24159
- import { join as join16 } from "path";
24358
+ import { join as join17 } from "path";
24160
24359
  function Shell(props) {
24161
24360
  const themeCtx = useTheme();
24162
24361
  const {
@@ -24188,6 +24387,16 @@ function Shell(props) {
24188
24387
  return;
24189
24388
  return tasksAcc().find((t) => t.id === id);
24190
24389
  });
24390
+ const worktreeOpener = createMemo(() => detectWorktreeOpener());
24391
+ function openActiveTaskInEditor() {
24392
+ const task = activeTask();
24393
+ const opener = worktreeOpener();
24394
+ if (!task?.worktreePath || !opener)
24395
+ return;
24396
+ if (!openWorktree(task.worktreePath, opener)) {
24397
+ console.error("[kobe] failed to open worktree:", task.worktreePath);
24398
+ }
24399
+ }
24191
24400
  const taskIdAcc = createMemo(() => selectedId() ?? undefined);
24192
24401
  createEffect(on(taskIdAcc, () => {
24193
24402
  setWorkspaceContextAside(null);
@@ -24279,6 +24488,15 @@ function Shell(props) {
24279
24488
  });
24280
24489
  onCleanup(unregister);
24281
24490
  });
24491
+ onMount(() => {
24492
+ const unregister = palette.addCommand({
24493
+ name: "task.openEditor",
24494
+ title: "Open task in editor",
24495
+ desc: "Open the active task worktree in Cursor, VS Code, or the detected system editor.",
24496
+ run: openActiveTaskInEditor
24497
+ });
24498
+ onCleanup(unregister);
24499
+ });
24282
24500
  let pendingPersistedId = persistedSelectedId ?? null;
24283
24501
  createEffect(() => {
24284
24502
  const tasks = tasksAcc();
@@ -24335,7 +24553,8 @@ function Shell(props) {
24335
24553
  kv,
24336
24554
  orchestrator: props.orchestrator,
24337
24555
  renderer,
24338
- activeTask
24556
+ activeTask,
24557
+ openActiveTaskInEditor
24339
24558
  });
24340
24559
  const visibleTabKey = createMemo(() => {
24341
24560
  const taskId = selectedId();
@@ -24376,7 +24595,8 @@ function Shell(props) {
24376
24595
  },
24377
24596
  activeTask,
24378
24597
  activeChatTabId: activeChatTabIdAcc,
24379
- updateInfo
24598
+ updateInfo,
24599
+ worktreeOpener
24380
24600
  }), _el$2);
24381
24601
  insertNode(_el$2, _el$3);
24382
24602
  insertNode(_el$2, _el$4);
@@ -24710,6 +24930,7 @@ var init_app = __esm(() => {
24710
24930
  init_use_task_actions();
24711
24931
  init_use_theme_persistence();
24712
24932
  init_use_workspace_tabs();
24933
+ init_worktree_opener();
24713
24934
  init_Chat();
24714
24935
  init_filetree();
24715
24936
  init_preview();
@@ -24723,7 +24944,7 @@ var exports_tui = {};
24723
24944
  __export(exports_tui, {
24724
24945
  startTui: () => startTui
24725
24946
  });
24726
- import { TextAttributes as TextAttributes27 } from "@opentui/core";
24947
+ import { TextAttributes as TextAttributes28 } from "@opentui/core";
24727
24948
  function HelpHint() {
24728
24949
  const {
24729
24950
  theme
@@ -24797,7 +25018,7 @@ function Banner() {
24797
25018
  insert(_el$20, selected);
24798
25019
  insert(_el$12, createComponent2(HelpHint, {}), null);
24799
25020
  effect((_p$) => {
24800
- var _v$7 = theme.primary, _v$8 = TextAttributes27.BOLD, _v$9 = theme.borderActive, _v$0 = theme.text, _v$1 = theme.textMuted, _v$10 = {
25021
+ var _v$7 = theme.primary, _v$8 = TextAttributes28.BOLD, _v$9 = theme.borderActive, _v$0 = theme.text, _v$1 = theme.textMuted, _v$10 = {
24801
25022
  fg: theme.accent
24802
25023
  };
24803
25024
  _v$7 !== _p$.e && (_p$.e = setProp(_el$13, "fg", _v$7, _p$.e));
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@sma1lboy/kobe",
4
- "version": "0.5.10",
4
+ "version": "0.5.11",
5
5
  "description": "TUI orchestrator for Claude Code (codename)",
6
6
  "type": "module",
7
7
  "packageManager": "bun@1.3.13",
@@ -31,8 +31,10 @@
31
31
  "build": "bun run scripts/build.ts",
32
32
  "compile": "bun run scripts/compile.ts",
33
33
  "typecheck": "tsc --noEmit",
34
- "test": "vitest run --passWithNoTests",
35
- "test:behavior": "vitest run test/behavior --passWithNoTests",
34
+ "test": "bun run test:fast && bun run test:socket",
35
+ "test:fast": "vitest run --passWithNoTests",
36
+ "test:socket": "KOBE_INCLUDE_SOCKET=1 vitest run test/daemon test/orchestrator/bridge.test.ts --pool forks --minWorkers=1 --maxWorkers=1 --passWithNoTests",
37
+ "test:behavior": "KOBE_INCLUDE_BEHAVIOR=1 vitest run test/behavior --pool forks --minWorkers=1 --maxWorkers=1 --passWithNoTests",
36
38
  "lint": "biome check .",
37
39
  "prepublishOnly": "bun run typecheck && bun run build"
38
40
  },