@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 +14 -22
- package/dist/cli/index.js +84 -3
- package/package.json +1 -1
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` |
|
|
82
|
-
| `
|
|
83
|
-
| `ctrl+
|
|
84
|
-
| `ctrl+
|
|
85
|
-
| `
|
|
86
|
-
| `ctrl
|
|
87
|
-
| `
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
`enter` opens, `r` renames, `a` archives, `d` deletes, `s` opens Settings, and
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
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.
|
|
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.
|
|
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