@sma1lboy/kobe 0.6.3 → 0.6.4

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
@@ -78,28 +78,20 @@ Once you're in, the keys you'll use most:
78
78
 
79
79
  | Key | What it does |
80
80
  | ------------------ | -------------------------------------------------------------- |
81
- | `ctrl+h` / `ctrl+j` / `ctrl+k` / `ctrl+l` | Jump straight to a pane (sidebar, workspace, files, terminal) |
82
- | `tab` | Cycle focus to the next pane |
83
- | `ctrl+q` | Detach back to the sidebar (your task keeps streaming) |
84
- | `ctrl+o` | Open the active task's worktree in your editor |
85
- | `F1` | Show the full keybinding help dialog |
86
- | `ctrl+,` | Open Settings (theme, transparent background, dev reset) |
87
- | `q` | Quit (with confirm) |
88
-
89
- Inside the sidebar, with a task highlighted: `n` creates a task, `j/k` moves,
90
- `enter` opens, `r` renames, `a` archives, `d` deletes, `s` opens Settings, and
91
- `[` / `]` switches between the working session and the archives view.
92
-
93
- Inside the chat composer:
94
-
95
- - `enter` to send, `shift+enter` for a newline.
96
- - `shift+tab` toggles the per-task tool-permission mode between `default` and `plan`. `default` is the trusted-bypass mode — kobe forwards it to `claude` as `--permission-mode bypassPermissions` because `claude -p` has no interactive permission protocol, so the only meaningful choice is "auto-deny outside cwd" or "auto-approve everything." `plan` forwards unchanged.
97
- - Click the model label in the footer to pick the model for this task (opus / sonnet / haiku).
98
- - Type `/` to open the slash-command dropdown. Bundled `claude-code` commands and your own `.claude/{commands,skills}/*.md` are merged in.
99
- - A `Create PR` chip on the chat header injects a PR-instructions prompt into the active task and routes the resulting PR through the orchestrator.
100
-
101
- A given task can host **multiple chat tabs** on the same worktree — useful when
102
- you want a parallel sub-conversation without losing the main thread.
81
+ | `ctrl+h` / `ctrl+j` / `ctrl+k` / `ctrl+l` | Move between tmux panes (Tasks, engine, Ops files, shell) |
82
+ | `ctrl+q` | Detach back to your launching shell; the task tmux session keeps running |
83
+ | `ctrl+t` | Open a same-engine ChatTab window on the current task/worktree |
84
+ | `ctrl+shift+t` or tmux `prefix T` | Pick an engine, then open a new ChatTab window |
85
+ | `ctrl+[` / `ctrl+]` | Switch to previous / next ChatTab window |
86
+ | `ctrl+w` | Close the current ChatTab window; the final window is protected |
87
+ | `F2` | Rename the current ChatTab window |
88
+ | tmux `prefix f` | Open the Tasks pane's new-task dialog from anywhere in the session |
89
+
90
+ Inside the Tasks pane, with a task highlighted: `n` creates a task, `j/k` moves, `enter` opens, `r` renames, `b` renames the branch, `v` cycles the engine, `o` opens the worktree in your editor, `a` archives/unarchives, `d` deletes, `s` opens Settings, and `[` / `]` switches between Working session and Archives. Archive/delete also kill the task's cached tmux session when one exists.
91
+
92
+ Inside the Ops files pane: `[` / `]` switches All / Changes, `enter` opens the preview, `a` injects an `@file` mention into the engine pane, `p` injects the create-PR prompt, `r` refreshes, and `o` opens a file externally when that makes sense.
93
+
94
+ A given task can host **multiple ChatTab tmux windows** on the same worktree — useful when you want a parallel sub-conversation without losing the main thread.
103
95
 
104
96
  ## Opening tasks in your editor
105
97
 
package/dist/cli/index.js CHANGED
@@ -576,7 +576,7 @@ var init_package = __esm(() => {
576
576
  package_default = {
577
577
  $schema: "https://json.schemastore.org/package.json",
578
578
  name: "@sma1lboy/kobe",
579
- version: "0.6.3",
579
+ version: "0.6.4",
580
580
  description: "TUI orchestrator for Claude Code (codename)",
581
581
  type: "module",
582
582
  packageManager: "bun@1.3.13",
@@ -4786,6 +4786,7 @@ __export(exports_tmux, {
4786
4786
  killSession: () => killSession,
4787
4787
  ensureSession: () => ensureSession,
4788
4788
  attachArgv: () => attachArgv,
4789
+ PANE_VERSION_OPTION: () => PANE_VERSION_OPTION,
4789
4790
  CHAT_TAB_SWITCH_BINDINGS: () => CHAT_TAB_SWITCH_BINDINGS,
4790
4791
  CHAT_TAB_STATUS_FORMAT: () => CHAT_TAB_STATUS_FORMAT,
4791
4792
  CHAT_TAB_STATUS_CURRENT_FORMAT: () => CHAT_TAB_STATUS_CURRENT_FORMAT,
@@ -4826,6 +4827,7 @@ async function ensureSessionImpl(opts) {
4826
4827
  const claudeAlive = await claudePaneIdStrict(opts.name) !== "";
4827
4828
  if (claudeAlive && worktreeOk && vendorOk) {
4828
4829
  await healTaskPaneWidths(opts.name);
4830
+ await healKobePaneVersions(opts.name, opts.cwd, opts.taskId, opts.vendor);
4829
4831
  return true;
4830
4832
  }
4831
4833
  if (worktreeOk && !vendorOk && opts.command.length > 0) {
@@ -4833,11 +4835,13 @@ async function ensureSessionImpl(opts) {
4833
4835
  if (opts.vendor)
4834
4836
  await setSessionOption(opts.name, "@kobe_vendor", opts.vendor);
4835
4837
  await healTaskPaneWidths(opts.name);
4838
+ await healKobePaneVersions(opts.name, opts.cwd, opts.taskId, opts.vendor);
4836
4839
  return true;
4837
4840
  }
4838
4841
  }
4839
4842
  if (worktreeOk && vendorOk && await windowCount(opts.name) > 1) {
4840
4843
  await healTaskPaneWidths(opts.name);
4844
+ await healKobePaneVersions(opts.name, opts.cwd, opts.taskId, opts.vendor);
4841
4845
  return true;
4842
4846
  }
4843
4847
  await runTmux(["kill-session", "-t", `=${opts.name}`]);
@@ -4936,6 +4940,68 @@ async function healTaskPaneWidths(session) {
4936
4940
  `).map((line) => line.split("\t")).filter(([, role]) => role?.trim() === "tasks").map(([id]) => id?.trim()).filter((id) => !!id);
4937
4941
  await runTmuxSequence(taskPanes.map((pane) => ["resize-pane", "-t", pane, "-x", `${TASKS_PANE_WIDTH}`]));
4938
4942
  }
4943
+ function parseKobePaneRows(stdout) {
4944
+ const rows = [];
4945
+ for (const raw of stdout.split(`
4946
+ `)) {
4947
+ const line = raw.trim();
4948
+ if (!line)
4949
+ continue;
4950
+ const [windowId, paneId, role, version] = line.split("\t");
4951
+ if (!windowId || !paneId || !role)
4952
+ continue;
4953
+ rows.push({ windowId: windowId.trim(), paneId: paneId.trim(), role: role.trim(), version: version?.trim() ?? "" });
4954
+ }
4955
+ return rows;
4956
+ }
4957
+ async function healKobePaneVersions(session, cwd, taskId, vendor) {
4958
+ const inv = kobeCliInvocation();
4959
+ const envPrefix = inheritedEnvPrefix();
4960
+ const { code, stdout } = await runTmuxCapturing([
4961
+ "list-panes",
4962
+ "-s",
4963
+ "-t",
4964
+ `=${session}`,
4965
+ "-F",
4966
+ `#{window_id} #{pane_id} #{@kobe_role} #{${PANE_VERSION_OPTION}}`
4967
+ ]);
4968
+ if (code !== 0)
4969
+ return;
4970
+ const byWindow = new Map;
4971
+ for (const row of parseKobePaneRows(stdout)) {
4972
+ const panes = byWindow.get(row.windowId) ?? [];
4973
+ panes.push(row);
4974
+ byWindow.set(row.windowId, panes);
4975
+ }
4976
+ const commands = [];
4977
+ for (const panes of byWindow.values()) {
4978
+ const claudePane = panes.find((pane) => pane.role === "claude")?.paneId;
4979
+ const tasksPane = panes.find((pane) => pane.role === "tasks");
4980
+ const opsPane = panes.find((pane) => pane.role === "ops");
4981
+ if (tasksPane && tasksPane.version !== CURRENT_VERSION) {
4982
+ commands.push(["respawn-pane", "-k", "-t", tasksPane.paneId, "-c", cwd, keepAlive(envPrefix + tasksPaneCommand(inv))], ["set-option", "-p", "-t", tasksPane.paneId, "@kobe_role", "tasks"], ["set-option", "-p", "-t", tasksPane.paneId, PANE_VERSION_OPTION, CURRENT_VERSION]);
4983
+ }
4984
+ if (opsPane && claudePane && opsPane.version !== CURRENT_VERSION) {
4985
+ commands.push([
4986
+ "respawn-pane",
4987
+ "-k",
4988
+ "-t",
4989
+ opsPane.paneId,
4990
+ "-c",
4991
+ cwd,
4992
+ keepAlive(envPrefix + opsPaneCommand({
4993
+ cwd,
4994
+ taskId,
4995
+ claudePaneId: claudePane,
4996
+ cliInvocation: inv,
4997
+ vendor
4998
+ }))
4999
+ ], ["set-option", "-p", "-t", opsPane.paneId, "@kobe_role", "ops"], ["set-option", "-p", "-t", opsPane.paneId, PANE_VERSION_OPTION, CURRENT_VERSION]);
5000
+ }
5001
+ }
5002
+ if (commands.length > 0)
5003
+ await runTmuxSequence(commands);
5004
+ }
4939
5005
  function inheritedEnvPrefix() {
4940
5006
  const parts = [];
4941
5007
  for (const key of ["KOBE_HOME_DIR", "KOBE_DAEMON_SOCKET_PATH", "KOBE_TMUX_SOCKET"]) {
@@ -4993,7 +5059,9 @@ async function buildPanesAround(claudePane, args) {
4993
5059
  `).map((line) => line.trim()).filter(Boolean).map((line) => line.split("=", 2)));
4994
5060
  await runTmuxSequence([
4995
5061
  ...ids.tasks ? [["set-option", "-p", "-t", ids.tasks, "@kobe_role", "tasks"]] : [],
4996
- ...ids.ops ? [["set-option", "-p", "-t", ids.ops, "@kobe_role", "ops"]] : []
5062
+ ...ids.tasks ? [["set-option", "-p", "-t", ids.tasks, PANE_VERSION_OPTION, CURRENT_VERSION]] : [],
5063
+ ...ids.ops ? [["set-option", "-p", "-t", ids.ops, "@kobe_role", "ops"]] : [],
5064
+ ...ids.ops ? [["set-option", "-p", "-t", ids.ops, PANE_VERSION_OPTION, CURRENT_VERSION]] : []
4997
5065
  ]);
4998
5066
  }
4999
5067
  async function newChatTab(session, vendorOverride) {
@@ -5048,12 +5116,13 @@ async function quickCreate(session) {
5048
5116
  await runTmux(["select-pane", "-t", tasksPane]);
5049
5117
  await sendKeys(tasksPane, "n");
5050
5118
  }
5051
- var CHAT_TAB_SWITCH_BINDINGS, CHAT_TAB_CLOSE_BINDING, CHAT_TAB_RENAME_BINDING, CHAT_TAB_ENGINE_PROMPT, CHAT_TAB_CHOOSE_ENGINE_BINDINGS, CHAT_TAB_STATE_OPTION = "@kobe_tab_state", CHAT_TAB_STATUS_FORMAT = "#{?#{==:#{@kobe_tab_state},running},\u25CF,#{?#{==:#{@kobe_tab_state},done},\u2713,#{?#{==:#{@kobe_tab_state},error},!,#{?#{==:#{@kobe_tab_state},unknown},?,\u25CB}}}} #I:#W", CHAT_TAB_STATUS_CURRENT_FORMAT, ensureSessionLocks;
5119
+ var CHAT_TAB_SWITCH_BINDINGS, CHAT_TAB_CLOSE_BINDING, CHAT_TAB_RENAME_BINDING, CHAT_TAB_ENGINE_PROMPT, CHAT_TAB_CHOOSE_ENGINE_BINDINGS, CHAT_TAB_STATE_OPTION = "@kobe_tab_state", PANE_VERSION_OPTION = "@kobe_pane_version", CHAT_TAB_STATUS_FORMAT = "#{?#{==:#{@kobe_tab_state},running},\u25CF,#{?#{==:#{@kobe_tab_state},done},\u2713,#{?#{==:#{@kobe_tab_state},error},!,#{?#{==:#{@kobe_tab_state},unknown},?,\u25CB}}}} #I:#W", CHAT_TAB_STATUS_CURRENT_FORMAT, ensureSessionLocks;
5052
5120
  var init_tmux = __esm(() => {
5053
5121
  init_invocation();
5054
5122
  init_interactive_command();
5055
5123
  init_client2();
5056
5124
  init_vendor();
5125
+ init_version();
5057
5126
  init_client2();
5058
5127
  CHAT_TAB_SWITCH_BINDINGS = [
5059
5128
  ["bind-key", "-n", "C-[", "previous-window"],
@@ -14005,6 +14074,9 @@ function ShortcutHints(props) {
14005
14074
  }, {
14006
14075
  k: "O",
14007
14076
  label: "open wt"
14077
+ }, {
14078
+ k: "[/]",
14079
+ label: "views"
14008
14080
  }, {
14009
14081
  k: "A/D",
14010
14082
  label: "archive/delete"
@@ -14023,6 +14095,15 @@ function ShortcutHints(props) {
14023
14095
  }, {
14024
14096
  k: "\u2303\u21E7T",
14025
14097
  label: "engine tab"
14098
+ }, {
14099
+ k: "Prefix T",
14100
+ label: "engine tab"
14101
+ }, {
14102
+ k: "Prefix F",
14103
+ label: "new task"
14104
+ }, {
14105
+ k: "F2",
14106
+ label: "rename tab"
14026
14107
  }, {
14027
14108
  k: "\u2303W",
14028
14109
  label: "close tab"
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.6.3",
4
+ "version": "0.6.4",
5
5
  "description": "TUI orchestrator for Claude Code (codename)",
6
6
  "type": "module",
7
7
  "packageManager": "bun@1.3.13",