@sma1lboy/kobe 0.7.20 → 0.7.22
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 +461 -262
- package/dist/web-ui/assets/{index-DHNbtmKS.js → index-B_AO4Tl6.js} +2 -2
- package/dist/web-ui/assets/{index-Bz2DJrhb.css → index-ClDlEZ7A.css} +1 -1
- package/dist/web-ui/assets/{routes-CObX3u9V.js → routes-BY2-JOW5.js} +3 -3
- package/dist/web-ui/index.html +2 -2
- package/dist/web-ui/pty-server.mjs +8 -3
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -90,7 +90,7 @@ var init_package = __esm(() => {
|
|
|
90
90
|
package_default = {
|
|
91
91
|
$schema: "https://json.schemastore.org/package.json",
|
|
92
92
|
name: "@sma1lboy/kobe",
|
|
93
|
-
version: "0.7.
|
|
93
|
+
version: "0.7.22",
|
|
94
94
|
description: "TUI orchestrator for Claude Code (codename)",
|
|
95
95
|
type: "module",
|
|
96
96
|
packageManager: "bun@1.3.13",
|
|
@@ -3891,6 +3891,18 @@ function isDaemonVersionStale(daemonVersion, clientVersion) {
|
|
|
3891
3891
|
return false;
|
|
3892
3892
|
return daemonVersion !== clientVersion;
|
|
3893
3893
|
}
|
|
3894
|
+
function isChannelName(value) {
|
|
3895
|
+
return typeof value === "string" && CHANNEL_NAME_SET.has(value);
|
|
3896
|
+
}
|
|
3897
|
+
function normalizeChannelFilter(value) {
|
|
3898
|
+
if (!Array.isArray(value))
|
|
3899
|
+
return null;
|
|
3900
|
+
const set = new Set;
|
|
3901
|
+
for (const name of value)
|
|
3902
|
+
if (isChannelName(name))
|
|
3903
|
+
set.add(name);
|
|
3904
|
+
return set.size > 0 ? set : null;
|
|
3905
|
+
}
|
|
3894
3906
|
function serializeTask(task) {
|
|
3895
3907
|
return {
|
|
3896
3908
|
id: task.id,
|
|
@@ -3912,7 +3924,7 @@ function frameToLine(frame) {
|
|
|
3912
3924
|
return `${JSON.stringify(frame)}
|
|
3913
3925
|
`;
|
|
3914
3926
|
}
|
|
3915
|
-
var DAEMON_PROTOCOL_VERSION = 3, MIN_COMPATIBLE_PROTOCOL_VERSION = 2, CHANNEL_NAMES;
|
|
3927
|
+
var DAEMON_PROTOCOL_VERSION = 3, MIN_COMPATIBLE_PROTOCOL_VERSION = 2, CHANNEL_NAMES, CHANNEL_NAME_SET;
|
|
3916
3928
|
var init_protocol = __esm(() => {
|
|
3917
3929
|
CHANNEL_NAMES = [
|
|
3918
3930
|
"task.snapshot",
|
|
@@ -3924,6 +3936,7 @@ var init_protocol = __esm(() => {
|
|
|
3924
3936
|
"task.jobs",
|
|
3925
3937
|
"worktree.changes"
|
|
3926
3938
|
];
|
|
3939
|
+
CHANNEL_NAME_SET = new Set(CHANNEL_NAMES);
|
|
3927
3940
|
});
|
|
3928
3941
|
|
|
3929
3942
|
// ../kobe-daemon/src/daemon/paths.ts
|
|
@@ -4685,7 +4698,7 @@ async function probeBinary(probe2) {
|
|
|
4685
4698
|
return { found: false, error: err instanceof Error ? err.message : String(err) };
|
|
4686
4699
|
}
|
|
4687
4700
|
}
|
|
4688
|
-
async function
|
|
4701
|
+
async function probeAvailableVendors(deps) {
|
|
4689
4702
|
const probes = [
|
|
4690
4703
|
["claude", () => deps.findClaudeBinary()],
|
|
4691
4704
|
["codex", () => deps.findCodexBinary()],
|
|
@@ -4694,6 +4707,18 @@ async function detectAvailableVendors(deps = defaultDeps5) {
|
|
|
4694
4707
|
const detected = await Promise.all(probes.map(async ([vendor, probe2]) => (await probeBinary(probe2)).found ? vendor : null));
|
|
4695
4708
|
return detected.filter((v) => v !== null);
|
|
4696
4709
|
}
|
|
4710
|
+
function detectAvailableVendors(deps = defaultDeps5) {
|
|
4711
|
+
if (deps !== defaultDeps5)
|
|
4712
|
+
return probeAvailableVendors(deps);
|
|
4713
|
+
if (cachedDefaultVendors)
|
|
4714
|
+
return cachedDefaultVendors;
|
|
4715
|
+
const pending = probeAvailableVendors(deps).catch((err) => {
|
|
4716
|
+
cachedDefaultVendors = null;
|
|
4717
|
+
throw err;
|
|
4718
|
+
});
|
|
4719
|
+
cachedDefaultVendors = pending;
|
|
4720
|
+
return pending;
|
|
4721
|
+
}
|
|
4697
4722
|
async function availableEngineIds(deps = defaultDeps5) {
|
|
4698
4723
|
const builtins = await detectAvailableVendors(deps);
|
|
4699
4724
|
return [...builtins, ...getCustomEngineIds()];
|
|
@@ -4850,7 +4875,7 @@ function hasStringDeep(value, interestingKeys, depth = 0) {
|
|
|
4850
4875
|
}
|
|
4851
4876
|
return false;
|
|
4852
4877
|
}
|
|
4853
|
-
var defaultDeps5;
|
|
4878
|
+
var defaultDeps5, cachedDefaultVendors = null;
|
|
4854
4879
|
var init_account_detect = __esm(() => {
|
|
4855
4880
|
init_repos();
|
|
4856
4881
|
init_binary();
|
|
@@ -6291,6 +6316,28 @@ var init_auto_title = __esm(() => {
|
|
|
6291
6316
|
init_registry();
|
|
6292
6317
|
});
|
|
6293
6318
|
|
|
6319
|
+
// src/tui/panes/terminal/launch.ts
|
|
6320
|
+
function wrapEngineLaunch(engineCmd, remoteKey, remoteCwd) {
|
|
6321
|
+
if (!remoteKey)
|
|
6322
|
+
return engineCmd;
|
|
6323
|
+
const host = execHostForRepo(remoteKey);
|
|
6324
|
+
host.ensureReady();
|
|
6325
|
+
return host.wrapCommand(engineCmd, { tty: true, cwd: remoteCwd });
|
|
6326
|
+
}
|
|
6327
|
+
function inheritedEnvPrefix() {
|
|
6328
|
+
const parts = [];
|
|
6329
|
+
for (const key of ["KOBE_HOME_DIR", "KOBE_DAEMON_SOCKET_PATH", "KOBE_TMUX_SOCKET"]) {
|
|
6330
|
+
const value = process.env[key];
|
|
6331
|
+
if (value && value.length > 0)
|
|
6332
|
+
parts.push(`${key}=${shellQuote(value)}`);
|
|
6333
|
+
}
|
|
6334
|
+
return parts.length > 0 ? `${parts.join(" ")} ` : "";
|
|
6335
|
+
}
|
|
6336
|
+
var REMOTE_KEY_OPTION = "@kobe_remote";
|
|
6337
|
+
var init_launch = __esm(() => {
|
|
6338
|
+
init_resolve();
|
|
6339
|
+
});
|
|
6340
|
+
|
|
6294
6341
|
// src/tmux/client.ts
|
|
6295
6342
|
var exports_client = {};
|
|
6296
6343
|
__export(exports_client, {
|
|
@@ -6590,7 +6637,7 @@ async function ensureFallbackSession() {
|
|
|
6590
6637
|
"-P",
|
|
6591
6638
|
"-F",
|
|
6592
6639
|
"#{pane_id}",
|
|
6593
|
-
keepAlive(tasksPaneCommand(kobeCliInvocation()))
|
|
6640
|
+
keepAlive(inheritedEnvPrefix() + tasksPaneCommand(kobeCliInvocation()))
|
|
6594
6641
|
]);
|
|
6595
6642
|
const tasksPane = r1.stdout.trim();
|
|
6596
6643
|
if (tasksPane) {
|
|
@@ -6617,6 +6664,7 @@ async function switchClientBeforeKill(killedName, nextSessionName) {
|
|
|
6617
6664
|
var KOBE_TMUX_SOCKET, SAFE_SPAWN_CWD, PANE_ROLE_OPTION = "@kobe_role", CLAUDE_ROLE_OPTION, CLAUDE_ROLE_VALUE = "claude", CHAT_TAB_SESSION_ID_OPTION = "@kobe_session_id", KOBE_HOME_SESSION = "kobe-home", HOME_KIND_OPTION = "@kobe_home";
|
|
6618
6665
|
var init_client2 = __esm(() => {
|
|
6619
6666
|
init_invocation();
|
|
6667
|
+
init_launch();
|
|
6620
6668
|
KOBE_TMUX_SOCKET = process.env.KOBE_TMUX_SOCKET?.trim() || "kobe";
|
|
6621
6669
|
SAFE_SPAWN_CWD = homedir11() || "/";
|
|
6622
6670
|
CLAUDE_ROLE_OPTION = PANE_ROLE_OPTION;
|
|
@@ -6770,11 +6818,13 @@ async function runAutoTitlePass(orch, derive = deriveTitleFromSession) {
|
|
|
6770
6818
|
}
|
|
6771
6819
|
return renamed;
|
|
6772
6820
|
}
|
|
6773
|
-
function startAutoTitlePoller(orch, intervalMs = DEFAULT_AUTO_TITLE_POLL_MS) {
|
|
6821
|
+
function startAutoTitlePoller(orch, intervalMs = DEFAULT_AUTO_TITLE_POLL_MS, hasSubscribers) {
|
|
6774
6822
|
if (intervalMs <= 0)
|
|
6775
6823
|
return () => {};
|
|
6776
6824
|
let running = false;
|
|
6777
6825
|
const tick = () => {
|
|
6826
|
+
if (hasSubscribers && !hasSubscribers())
|
|
6827
|
+
return;
|
|
6778
6828
|
if (running)
|
|
6779
6829
|
return;
|
|
6780
6830
|
running = true;
|
|
@@ -7517,6 +7567,8 @@ class WorktreeChangesCollector {
|
|
|
7517
7567
|
tick() {
|
|
7518
7568
|
if (this.stopped)
|
|
7519
7569
|
return;
|
|
7570
|
+
if (this.options.hasSubscribers && !this.options.hasSubscribers())
|
|
7571
|
+
return;
|
|
7520
7572
|
try {
|
|
7521
7573
|
const tracked = trackedWorktreePaths(this.orch.listTasks());
|
|
7522
7574
|
let pruned = false;
|
|
@@ -7571,10 +7623,10 @@ class WorktreeChangesCollector {
|
|
|
7571
7623
|
this.bus.publish("worktree.changes", { changes });
|
|
7572
7624
|
}
|
|
7573
7625
|
}
|
|
7574
|
-
function startWorktreeChangesCollector(orch, bus, tickMs = DEFAULT_WORKTREE_CHANGES_TICK_MS) {
|
|
7626
|
+
function startWorktreeChangesCollector(orch, bus, tickMs = DEFAULT_WORKTREE_CHANGES_TICK_MS, hasSubscribers) {
|
|
7575
7627
|
if (tickMs <= 0)
|
|
7576
7628
|
return () => {};
|
|
7577
|
-
const collector = new WorktreeChangesCollector(orch, bus);
|
|
7629
|
+
const collector = new WorktreeChangesCollector(orch, bus, { hasSubscribers });
|
|
7578
7630
|
collector.tick();
|
|
7579
7631
|
const timer = setInterval(() => collector.tick(), tickMs);
|
|
7580
7632
|
timer.unref?.();
|
|
@@ -7617,6 +7669,12 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
7617
7669
|
n++;
|
|
7618
7670
|
return n;
|
|
7619
7671
|
}
|
|
7672
|
+
function hasSubscribers() {
|
|
7673
|
+
for (const c of clients)
|
|
7674
|
+
if (c.subscribed)
|
|
7675
|
+
return true;
|
|
7676
|
+
return false;
|
|
7677
|
+
}
|
|
7620
7678
|
function cancelIdleTimer() {
|
|
7621
7679
|
if (idleTimer) {
|
|
7622
7680
|
clearTimeout(idleTimer);
|
|
@@ -7652,7 +7710,8 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
7652
7710
|
socket,
|
|
7653
7711
|
buffer: "",
|
|
7654
7712
|
subscribed: false,
|
|
7655
|
-
holdsLifetime: false
|
|
7713
|
+
holdsLifetime: false,
|
|
7714
|
+
channels: null
|
|
7656
7715
|
};
|
|
7657
7716
|
clients.add(client);
|
|
7658
7717
|
socket.on("data", (chunk) => {
|
|
@@ -7684,7 +7743,7 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
7684
7743
|
updateTimer.unref?.();
|
|
7685
7744
|
}
|
|
7686
7745
|
const autoTitlePollMs = options.autoTitlePollMs ?? DEFAULT_AUTO_TITLE_POLL_MS;
|
|
7687
|
-
const stopAutoTitlePoller = startAutoTitlePoller(orch, autoTitlePollMs);
|
|
7746
|
+
const stopAutoTitlePoller = startAutoTitlePoller(orch, autoTitlePollMs, hasSubscribers);
|
|
7688
7747
|
const stopUiPrefsWatcher = startUiPrefsWatcher(bus, {
|
|
7689
7748
|
statePath: defaultUiPrefsStatePath(options.homeDir),
|
|
7690
7749
|
debounceMs: options.uiPrefsDebounceMs ?? DEFAULT_UI_PREFS_DEBOUNCE_MS
|
|
@@ -7693,7 +7752,7 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
7693
7752
|
path: defaultKeybindingsPath(options.homeDir),
|
|
7694
7753
|
debounceMs: options.keybindingsDebounceMs ?? DEFAULT_KEYBINDINGS_DEBOUNCE_MS
|
|
7695
7754
|
});
|
|
7696
|
-
const stopWorktreeChangesCollector = startWorktreeChangesCollector(orch, bus, options.worktreeChangesTickMs ?? DEFAULT_WORKTREE_CHANGES_TICK_MS);
|
|
7755
|
+
const stopWorktreeChangesCollector = startWorktreeChangesCollector(orch, bus, options.worktreeChangesTickMs ?? DEFAULT_WORKTREE_CHANGES_TICK_MS, hasSubscribers);
|
|
7697
7756
|
const serverApi = {
|
|
7698
7757
|
socketPath,
|
|
7699
7758
|
pidPath,
|
|
@@ -7743,21 +7802,28 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
7743
7802
|
async function dispatch(req, client) {
|
|
7744
7803
|
if (req.name === "subscribe") {
|
|
7745
7804
|
const payload = objectPayload(req.payload);
|
|
7805
|
+
const wasSubscribed = client.subscribed;
|
|
7746
7806
|
client.subscribed = true;
|
|
7747
7807
|
const role = payload.role === "gui" ? "gui" : "pane";
|
|
7748
7808
|
client.holdsLifetime = role === "gui";
|
|
7809
|
+
client.channels = normalizeChannelFilter(payload.channels);
|
|
7810
|
+
const firstSubscriber = !wasSubscribed;
|
|
7749
7811
|
if (client.holdsLifetime)
|
|
7750
7812
|
cancelIdleTimer();
|
|
7751
|
-
logDaemonInfo("conn", `client #${client.id} subscribed as ${role} \u2014 ${clients.size} client(s), ${guiCount()} gui`);
|
|
7813
|
+
logDaemonInfo("conn", `client #${client.id} subscribed as ${role}${client.channels ? ` [${[...client.channels].join(",")}]` : ""} \u2014 ${clients.size} client(s), ${guiCount()} gui${firstSubscriber ? " (collectors resume)" : ""}`);
|
|
7752
7814
|
for (const event of bus.snapshot()) {
|
|
7815
|
+
if (client.channels && !client.channels.has(event.channel))
|
|
7816
|
+
continue;
|
|
7753
7817
|
writeFrame(client, { type: "event", name: event.channel, payload: event.payload });
|
|
7754
7818
|
}
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
|
|
7758
|
-
|
|
7759
|
-
|
|
7760
|
-
|
|
7819
|
+
if (!client.channels || client.channels.has("engine-state")) {
|
|
7820
|
+
for (const payload2 of activity.currentNonIdle()) {
|
|
7821
|
+
writeFrame(client, {
|
|
7822
|
+
type: "event",
|
|
7823
|
+
name: "engine-state",
|
|
7824
|
+
payload: payload2
|
|
7825
|
+
});
|
|
7826
|
+
}
|
|
7761
7827
|
}
|
|
7762
7828
|
return {};
|
|
7763
7829
|
}
|
|
@@ -7816,10 +7882,13 @@ function writeFrame(client, frame) {
|
|
|
7816
7882
|
client.socket.write(frameToLine(frame));
|
|
7817
7883
|
}
|
|
7818
7884
|
function broadcast(clients, frame) {
|
|
7885
|
+
const channel = frame.type === "event" && frame.name !== "daemon.stopping" ? frame.name : null;
|
|
7819
7886
|
let line = null;
|
|
7820
7887
|
for (const client of clients) {
|
|
7821
7888
|
if (!client.subscribed && frame.type === "event")
|
|
7822
7889
|
continue;
|
|
7890
|
+
if (channel && client.channels && !client.channels.has(channel))
|
|
7891
|
+
continue;
|
|
7823
7892
|
line ??= frameToLine(frame);
|
|
7824
7893
|
client.socket.write(line);
|
|
7825
7894
|
}
|
|
@@ -10436,28 +10505,6 @@ var init_tmux_border_theme = __esm(() => {
|
|
|
10436
10505
|
FOCUS_ACCENT_SLOT_NAMES2 = ["primary", "success", "info"];
|
|
10437
10506
|
});
|
|
10438
10507
|
|
|
10439
|
-
// src/tui/panes/terminal/launch.ts
|
|
10440
|
-
function wrapEngineLaunch(engineCmd, remoteKey, remoteCwd) {
|
|
10441
|
-
if (!remoteKey)
|
|
10442
|
-
return engineCmd;
|
|
10443
|
-
const host = execHostForRepo(remoteKey);
|
|
10444
|
-
host.ensureReady();
|
|
10445
|
-
return host.wrapCommand(engineCmd, { tty: true, cwd: remoteCwd });
|
|
10446
|
-
}
|
|
10447
|
-
function inheritedEnvPrefix() {
|
|
10448
|
-
const parts = [];
|
|
10449
|
-
for (const key of ["KOBE_HOME_DIR", "KOBE_DAEMON_SOCKET_PATH", "KOBE_TMUX_SOCKET"]) {
|
|
10450
|
-
const value = process.env[key];
|
|
10451
|
-
if (value && value.length > 0)
|
|
10452
|
-
parts.push(`${key}=${shellQuote(value)}`);
|
|
10453
|
-
}
|
|
10454
|
-
return parts.length > 0 ? `${parts.join(" ")} ` : "";
|
|
10455
|
-
}
|
|
10456
|
-
var REMOTE_KEY_OPTION = "@kobe_remote";
|
|
10457
|
-
var init_launch = __esm(() => {
|
|
10458
|
-
init_resolve();
|
|
10459
|
-
});
|
|
10460
|
-
|
|
10461
10508
|
// src/tui/panes/terminal/pane-heal.ts
|
|
10462
10509
|
function parseKobePaneRows(stdout) {
|
|
10463
10510
|
const rows = [];
|
|
@@ -10480,9 +10527,6 @@ function parseKobePaneRows(stdout) {
|
|
|
10480
10527
|
}
|
|
10481
10528
|
return rows;
|
|
10482
10529
|
}
|
|
10483
|
-
function paneIdsByRole(rows, role) {
|
|
10484
|
-
return rows.filter((row) => row.role === role).map((row) => row.paneId);
|
|
10485
|
-
}
|
|
10486
10530
|
function planPaneHeals(rows, opts) {
|
|
10487
10531
|
const byWindow = new Map;
|
|
10488
10532
|
for (const row of rows) {
|
|
@@ -10498,7 +10542,8 @@ function planPaneHeals(rows, opts) {
|
|
|
10498
10542
|
if (tasksPane && (opts.force || tasksPane.version !== opts.currentVersion)) {
|
|
10499
10543
|
targets.push({ role: "tasks", paneId: tasksPane.paneId });
|
|
10500
10544
|
}
|
|
10501
|
-
|
|
10545
|
+
const opsNeedsRespawn = opts.force ? true : claudePane && (opts.vendorChanged || opsPane?.version !== opts.currentVersion);
|
|
10546
|
+
if (opsPane && opsNeedsRespawn) {
|
|
10502
10547
|
targets.push({ role: "ops", paneId: opsPane.paneId, claudePaneId: claudePane ?? null });
|
|
10503
10548
|
}
|
|
10504
10549
|
}
|
|
@@ -10533,15 +10578,22 @@ function respawnCommandsFor(targets, args) {
|
|
|
10533
10578
|
}
|
|
10534
10579
|
return commands;
|
|
10535
10580
|
}
|
|
10536
|
-
async function relaunchEngineInAllWindows(session, cwd, command, remoteKey) {
|
|
10581
|
+
async function relaunchEngineInAllWindows(session, cwd, command, remoteKey, vendor) {
|
|
10537
10582
|
const rows = await listKobePanes(session);
|
|
10538
10583
|
if (!rows)
|
|
10539
10584
|
return false;
|
|
10540
|
-
const enginePanes =
|
|
10585
|
+
const enginePanes = rows.filter((r) => r.role === "claude");
|
|
10541
10586
|
if (enginePanes.length === 0)
|
|
10542
10587
|
return false;
|
|
10543
|
-
const
|
|
10544
|
-
|
|
10588
|
+
const localCwd = localSpawnCwd(cwd);
|
|
10589
|
+
const commands = [];
|
|
10590
|
+
for (const pane of enginePanes) {
|
|
10591
|
+
const launch = withClaudeSessionId(command, vendor);
|
|
10592
|
+
const cmd = keepAlive(wrapEngineLaunch(shellQuoteArgv(launch.argv), remoteKey, cwd));
|
|
10593
|
+
commands.push(["respawn-pane", "-k", "-c", localCwd, "-t", pane.paneId, cmd]);
|
|
10594
|
+
commands.push(launch.sessionId ? ["set-window-option", "-t", pane.paneId, CHAT_TAB_SESSION_ID_OPTION, launch.sessionId] : ["set-window-option", "-u", "-t", pane.paneId, CHAT_TAB_SESSION_ID_OPTION]);
|
|
10595
|
+
}
|
|
10596
|
+
await runTmuxSequence(commands);
|
|
10545
10597
|
return true;
|
|
10546
10598
|
}
|
|
10547
10599
|
async function globalLayoutPrefs() {
|
|
@@ -10583,7 +10635,11 @@ async function healWorkspaceLayout(session, versions) {
|
|
|
10583
10635
|
}
|
|
10584
10636
|
}
|
|
10585
10637
|
if (versions) {
|
|
10586
|
-
commands.push(...respawnCommandsFor(planPaneHeals(rows, {
|
|
10638
|
+
commands.push(...respawnCommandsFor(planPaneHeals(rows, {
|
|
10639
|
+
currentVersion: CURRENT_VERSION,
|
|
10640
|
+
force: false,
|
|
10641
|
+
vendorChanged: versions.vendorChanged
|
|
10642
|
+
}), versions));
|
|
10587
10643
|
}
|
|
10588
10644
|
if (commands.length > 0)
|
|
10589
10645
|
await runTmuxSequence(commands);
|
|
@@ -10650,6 +10706,7 @@ async function refreshKobeWorkspacePanes(session) {
|
|
|
10650
10706
|
var PANE_VERSION_OPTION = "@kobe_pane_version", KOBE_PANE_LIST_FORMAT;
|
|
10651
10707
|
var init_pane_heal = __esm(() => {
|
|
10652
10708
|
init_invocation();
|
|
10709
|
+
init_interactive_command();
|
|
10653
10710
|
init_resolve();
|
|
10654
10711
|
init_client2();
|
|
10655
10712
|
init_tmux_border_theme();
|
|
@@ -10988,10 +11045,15 @@ async function ensureSessionImpl(opts) {
|
|
|
10988
11045
|
return true;
|
|
10989
11046
|
}
|
|
10990
11047
|
if (action.kind === "respawn-engine") {
|
|
10991
|
-
if (await relaunchEngineInAllWindows(opts.name, opts.cwd, opts.command, remoteKey)) {
|
|
11048
|
+
if (await relaunchEngineInAllWindows(opts.name, opts.cwd, opts.command, remoteKey, opts.vendor)) {
|
|
10992
11049
|
if (opts.vendor)
|
|
10993
11050
|
await setSessionOption(opts.name, "@kobe_vendor", opts.vendor);
|
|
10994
|
-
await healWorkspaceLayout(opts.name, {
|
|
11051
|
+
await healWorkspaceLayout(opts.name, {
|
|
11052
|
+
cwd: opts.cwd,
|
|
11053
|
+
taskId: opts.taskId,
|
|
11054
|
+
vendor: opts.vendor,
|
|
11055
|
+
vendorChanged: true
|
|
11056
|
+
});
|
|
10995
11057
|
return true;
|
|
10996
11058
|
}
|
|
10997
11059
|
}
|
|
@@ -11643,6 +11705,23 @@ async function setActive(ctx) {
|
|
|
11643
11705
|
await daemon.request("task.setActive", { taskId });
|
|
11644
11706
|
return { ok: true, activeTaskId: taskId };
|
|
11645
11707
|
}
|
|
11708
|
+
async function archive(ctx) {
|
|
11709
|
+
const daemon = daemonOf(ctx);
|
|
11710
|
+
const taskId = ctx.args.require("task-id");
|
|
11711
|
+
const archived = ctx.args.bool("archived") ?? true;
|
|
11712
|
+
const res = await daemon.request("task.archive", { taskId, archived });
|
|
11713
|
+
if (archived)
|
|
11714
|
+
await ctx.runtime.tearDownSession(taskId);
|
|
11715
|
+
return res;
|
|
11716
|
+
}
|
|
11717
|
+
async function deleteTask(ctx) {
|
|
11718
|
+
const daemon = daemonOf(ctx);
|
|
11719
|
+
const taskId = ctx.args.require("task-id");
|
|
11720
|
+
const force = ctx.args.bool("force") ?? false;
|
|
11721
|
+
const res = await daemon.request("task.delete", { taskId, force });
|
|
11722
|
+
await ctx.runtime.tearDownSession(taskId);
|
|
11723
|
+
return res;
|
|
11724
|
+
}
|
|
11646
11725
|
async function adopt(ctx) {
|
|
11647
11726
|
const daemon = daemonOf(ctx);
|
|
11648
11727
|
const { args } = ctx;
|
|
@@ -12006,10 +12085,7 @@ var init_api_cmd = __esm(() => {
|
|
|
12006
12085
|
F.taskId(),
|
|
12007
12086
|
{ name: "archived", type: "bool", default: "true", description: "true to archive, false to unarchive." }
|
|
12008
12087
|
],
|
|
12009
|
-
handler:
|
|
12010
|
-
taskId: ctx.args.require("task-id"),
|
|
12011
|
-
archived: ctx.args.bool("archived") ?? true
|
|
12012
|
-
})
|
|
12088
|
+
handler: archive
|
|
12013
12089
|
},
|
|
12014
12090
|
{
|
|
12015
12091
|
name: "pin",
|
|
@@ -12039,10 +12115,7 @@ var init_api_cmd = __esm(() => {
|
|
|
12039
12115
|
name: "delete",
|
|
12040
12116
|
summary: "Permanently remove a task (and its worktree). DESTRUCTIVE \u2014 prefer `archive`. Needs --force on a dirty worktree.",
|
|
12041
12117
|
flags: [F.taskId(), { name: "force", type: "bool", description: "Delete even with uncommitted changes." }],
|
|
12042
|
-
handler:
|
|
12043
|
-
taskId: ctx.args.require("task-id"),
|
|
12044
|
-
force: ctx.args.bool("force") ?? false
|
|
12045
|
-
})
|
|
12118
|
+
handler: deleteTask
|
|
12046
12119
|
},
|
|
12047
12120
|
{
|
|
12048
12121
|
name: "discover-adoptable",
|
|
@@ -12086,7 +12159,12 @@ var init_api_cmd = __esm(() => {
|
|
|
12086
12159
|
isTaskRunning: (taskId) => sessionExists(tmuxSessionName(taskId)),
|
|
12087
12160
|
deliverPrompt: (client, target, prompt) => deliverPrompt(client, target, prompt),
|
|
12088
12161
|
resolveRepoRoot: async (absPath) => (await Promise.resolve().then(() => (init_repos(), exports_repos))).resolveRepoRoot(absPath),
|
|
12089
|
-
readWorktreeChanges: async (worktreePath) => (await Promise.resolve().then(() => (init_worktree_changes(), exports_worktree_changes))).readWorktreeChanges(worktreePath)
|
|
12162
|
+
readWorktreeChanges: async (worktreePath) => (await Promise.resolve().then(() => (init_worktree_changes(), exports_worktree_changes))).readWorktreeChanges(worktreePath),
|
|
12163
|
+
tearDownSession: async (taskId) => {
|
|
12164
|
+
const session = tmuxSessionName(taskId);
|
|
12165
|
+
await switchClientBeforeKill(session).catch(() => {});
|
|
12166
|
+
await killSession(session).catch(() => {});
|
|
12167
|
+
}
|
|
12090
12168
|
};
|
|
12091
12169
|
});
|
|
12092
12170
|
|
|
@@ -13071,6 +13149,19 @@ function unquoteGitPath(p) {
|
|
|
13071
13149
|
return inner.replace(/\\([\\"nt])/g, (_m, c) => c === "n" ? `
|
|
13072
13150
|
` : c === "t" ? "\t" : c);
|
|
13073
13151
|
}
|
|
13152
|
+
async function mapPool(items, limit, fn) {
|
|
13153
|
+
const results = new Array(items.length);
|
|
13154
|
+
const width = Math.max(1, Math.min(limit, items.length));
|
|
13155
|
+
let next = 0;
|
|
13156
|
+
async function worker() {
|
|
13157
|
+
while (next < items.length) {
|
|
13158
|
+
const index = next++;
|
|
13159
|
+
results[index] = await fn(items[index], index);
|
|
13160
|
+
}
|
|
13161
|
+
}
|
|
13162
|
+
await Promise.all(Array.from({ length: width }, () => worker()));
|
|
13163
|
+
return results;
|
|
13164
|
+
}
|
|
13074
13165
|
async function untrackedPatch(cwd, relPath) {
|
|
13075
13166
|
const res = await runGit(cwd, ["diff", "--no-color", "--no-index", "--", "/dev/null", relPath]);
|
|
13076
13167
|
if (res.stdout.trim())
|
|
@@ -13120,6 +13211,7 @@ async function handleDiffRequest(req, url) {
|
|
|
13120
13211
|
const stagedByFile = splitDiffByFile(staged.stdout);
|
|
13121
13212
|
const records = statusRes.stdout.split("\x00");
|
|
13122
13213
|
const files = [];
|
|
13214
|
+
const untrackedJobs = [];
|
|
13123
13215
|
for (let i = 0;i < records.length; i++) {
|
|
13124
13216
|
const rec = records[i];
|
|
13125
13217
|
if (!rec)
|
|
@@ -13136,7 +13228,7 @@ async function handleDiffRequest(req, url) {
|
|
|
13136
13228
|
const staged2 = x !== " " && x !== "?";
|
|
13137
13229
|
let patch = "";
|
|
13138
13230
|
if (untracked) {
|
|
13139
|
-
|
|
13231
|
+
untrackedJobs.push({ fileIndex: files.length, path: path11 });
|
|
13140
13232
|
} else {
|
|
13141
13233
|
patch = stagedByFile.get(path11) ?? unstagedByFile.get(path11) ?? "";
|
|
13142
13234
|
if (stagedByFile.has(path11) && unstagedByFile.has(path11)) {
|
|
@@ -13150,13 +13242,19 @@ async function handleDiffRequest(req, url) {
|
|
|
13150
13242
|
patch
|
|
13151
13243
|
});
|
|
13152
13244
|
}
|
|
13245
|
+
if (untrackedJobs.length > 0) {
|
|
13246
|
+
const patches = await mapPool(untrackedJobs, UNTRACKED_DIFF_CONCURRENCY, (job) => untrackedPatch(worktreePath, job.path));
|
|
13247
|
+
for (let j = 0;j < untrackedJobs.length; j++) {
|
|
13248
|
+
files[untrackedJobs[j].fileIndex].patch = patches[j];
|
|
13249
|
+
}
|
|
13250
|
+
}
|
|
13153
13251
|
files.sort((a, b) => a.path.localeCompare(b.path));
|
|
13154
13252
|
const raw = [staged.stdout, unstaged.stdout].filter(Boolean).join(`
|
|
13155
13253
|
`);
|
|
13156
13254
|
const result = { files, raw };
|
|
13157
13255
|
return Response.json(result);
|
|
13158
13256
|
}
|
|
13159
|
-
var GIT_TIMEOUT_MS = 15000;
|
|
13257
|
+
var GIT_TIMEOUT_MS = 15000, UNTRACKED_DIFF_CONCURRENCY = 8;
|
|
13160
13258
|
|
|
13161
13259
|
// src/web/notes.ts
|
|
13162
13260
|
import { mkdir as mkdir7, readFile as readFile8, writeFile as writeFile5 } from "fs/promises";
|
|
@@ -13223,6 +13321,18 @@ var init_notes = __esm(() => {
|
|
|
13223
13321
|
init_env();
|
|
13224
13322
|
});
|
|
13225
13323
|
|
|
13324
|
+
// ../kobe-web/server/spa-channels.ts
|
|
13325
|
+
var SPA_CHANNELS, SPA_CHANNEL_SET;
|
|
13326
|
+
var init_spa_channels = __esm(() => {
|
|
13327
|
+
SPA_CHANNELS = [
|
|
13328
|
+
"task.snapshot",
|
|
13329
|
+
"active-task",
|
|
13330
|
+
"engine-state",
|
|
13331
|
+
"update"
|
|
13332
|
+
];
|
|
13333
|
+
SPA_CHANNEL_SET = new Set(SPA_CHANNELS);
|
|
13334
|
+
});
|
|
13335
|
+
|
|
13226
13336
|
// ../kobe-web/server/daemon-link.ts
|
|
13227
13337
|
function sleep2(ms) {
|
|
13228
13338
|
return new Promise((resolve6) => setTimeout(resolve6, ms));
|
|
@@ -13291,7 +13401,7 @@ class DaemonLink {
|
|
|
13291
13401
|
this.engineStates = {};
|
|
13292
13402
|
client.on("*", (frame) => this.onFrame(frame.name, frame.payload));
|
|
13293
13403
|
client.onLifecycle("close", () => this.onDrop(client));
|
|
13294
|
-
await client.subscribe({ role: "gui" });
|
|
13404
|
+
await client.subscribe({ role: "gui", channels: SPA_CHANNELS });
|
|
13295
13405
|
} catch (err) {
|
|
13296
13406
|
client.close();
|
|
13297
13407
|
throw err;
|
|
@@ -13341,6 +13451,8 @@ class DaemonLink {
|
|
|
13341
13451
|
default:
|
|
13342
13452
|
break;
|
|
13343
13453
|
}
|
|
13454
|
+
if (!SPA_CHANNEL_SET.has(name))
|
|
13455
|
+
return;
|
|
13344
13456
|
const event = { channel: name, payload };
|
|
13345
13457
|
for (const sink of this.eventSinks)
|
|
13346
13458
|
sink(event);
|
|
@@ -13359,6 +13471,7 @@ var init_daemon_link = __esm(() => {
|
|
|
13359
13471
|
init_daemon_process();
|
|
13360
13472
|
init_paths2();
|
|
13361
13473
|
init_protocol();
|
|
13474
|
+
init_spa_channels();
|
|
13362
13475
|
});
|
|
13363
13476
|
|
|
13364
13477
|
// ../kobe-web/server/session.ts
|
|
@@ -13890,17 +14003,29 @@ var init_skill_cmd = __esm(() => {
|
|
|
13890
14003
|
var exports_hook_cmd = {};
|
|
13891
14004
|
__export(exports_hook_cmd, {
|
|
13892
14005
|
runHookSubcommand: () => runHookSubcommand,
|
|
14006
|
+
readTextWithTimeout: () => readTextWithTimeout,
|
|
13893
14007
|
parseWorktreeAddPath: () => parseWorktreeAddPath,
|
|
13894
14008
|
ensureGlobalKobeHooks: () => ensureGlobalKobeHooks
|
|
13895
14009
|
});
|
|
13896
14010
|
import { homedir as homedir17 } from "os";
|
|
13897
14011
|
import { join as join13, resolve as resolve7 } from "path";
|
|
13898
|
-
async function
|
|
14012
|
+
async function readTextWithTimeout(read, timeoutMs = STDIN_READ_TIMEOUT_MS) {
|
|
14013
|
+
let raceTimer;
|
|
13899
14014
|
try {
|
|
13900
|
-
|
|
13901
|
-
|
|
13902
|
-
new Promise((resolve8) =>
|
|
14015
|
+
return await Promise.race([
|
|
14016
|
+
read(),
|
|
14017
|
+
new Promise((resolve8) => {
|
|
14018
|
+
raceTimer = setTimeout(() => resolve8(""), timeoutMs);
|
|
14019
|
+
})
|
|
13903
14020
|
]);
|
|
14021
|
+
} finally {
|
|
14022
|
+
if (raceTimer !== undefined)
|
|
14023
|
+
clearTimeout(raceTimer);
|
|
14024
|
+
}
|
|
14025
|
+
}
|
|
14026
|
+
async function readStdinPayload() {
|
|
14027
|
+
try {
|
|
14028
|
+
const text = await readTextWithTimeout(() => Bun.stdin.text());
|
|
13904
14029
|
if (!text.trim())
|
|
13905
14030
|
return {};
|
|
13906
14031
|
const parsed = JSON.parse(text);
|
|
@@ -14066,7 +14191,7 @@ async function runHookSetup(_argv) {
|
|
|
14066
14191
|
].join(`
|
|
14067
14192
|
`));
|
|
14068
14193
|
}
|
|
14069
|
-
var WORKTREE_CREATED_VERB = "worktree-created", SYNC_SETTING_KEY = "externalWorktreeSync";
|
|
14194
|
+
var STDIN_READ_TIMEOUT_MS = 500, WORKTREE_CREATED_VERB = "worktree-created", SYNC_SETTING_KEY = "externalWorktreeSync";
|
|
14070
14195
|
var init_hook_cmd = __esm(() => {
|
|
14071
14196
|
init_daemon_process();
|
|
14072
14197
|
init_hook_adapter2();
|
|
@@ -15400,6 +15525,8 @@ class RemoteOrchestrator {
|
|
|
15400
15525
|
setConnectionState;
|
|
15401
15526
|
ensureReachable;
|
|
15402
15527
|
role;
|
|
15528
|
+
channels;
|
|
15529
|
+
subscribesTasks;
|
|
15403
15530
|
reconnecting = false;
|
|
15404
15531
|
constructor(client, options = {}) {
|
|
15405
15532
|
this.client = client;
|
|
@@ -15435,6 +15562,8 @@ class RemoteOrchestrator {
|
|
|
15435
15562
|
this.setConnectionState = (next) => setConnectionState(() => next);
|
|
15436
15563
|
this.ensureReachable = options.ensureReachable ?? ensureDaemonReachable;
|
|
15437
15564
|
this.role = options.role ?? "pane";
|
|
15565
|
+
this.channels = options.channels;
|
|
15566
|
+
this.subscribesTasks = !options.channels || options.channels.includes("task.snapshot");
|
|
15438
15567
|
this.client.on("*", (frame) => this.handleEvent(frame.name, frame.payload));
|
|
15439
15568
|
this.client.onLifecycle("close", () => {
|
|
15440
15569
|
this.setConnectionState("disconnected");
|
|
@@ -15484,9 +15613,9 @@ class RemoteOrchestrator {
|
|
|
15484
15613
|
throw new Error(`kobe daemon is protocol v${daemonVersion} (min v${daemonMin}); this client is v${DAEMON_PROTOCOL_VERSION} (min v${MIN_COMPATIBLE_PROTOCOL_VERSION}). Restart the daemon (\`kobe daemon restart\`) or upgrade kobe.`);
|
|
15485
15614
|
}
|
|
15486
15615
|
this.setDaemonVersionSig(typeof hello.kobeVersion === "string" ? hello.kobeVersion : null);
|
|
15487
|
-
if (hello.tasks)
|
|
15616
|
+
if (hello.tasks && this.subscribesTasks)
|
|
15488
15617
|
this.setTasks(hello.tasks.map(deserializeTask));
|
|
15489
|
-
await this.client.subscribe({ role: this.role });
|
|
15618
|
+
await this.client.subscribe({ role: this.role, channels: this.channels });
|
|
15490
15619
|
if (hello.capabilities?.includes("worktree.changes")) {
|
|
15491
15620
|
if (this.worktreeChangesAcc() === null)
|
|
15492
15621
|
this.setWorktreeChangesSig(new Map);
|
|
@@ -17190,97 +17319,104 @@ function NewTaskDialogView(props) {
|
|
|
17190
17319
|
setCloneParent(joinDrill(cloneParent(), split.base, picked));
|
|
17191
17320
|
setCloneParentCursor(absoluteIndex);
|
|
17192
17321
|
}
|
|
17322
|
+
const adoptSelectAll = () => {
|
|
17323
|
+
const list2 = adoptList();
|
|
17324
|
+
if (list2.length === 0)
|
|
17325
|
+
return;
|
|
17326
|
+
const allSelected = list2.every((w) => adoptSelected().has(w.path));
|
|
17327
|
+
setAdoptSelected(allSelected ? new Set : new Set(list2.map((w) => w.path)));
|
|
17328
|
+
};
|
|
17193
17329
|
useBindings(() => ({
|
|
17194
|
-
bindings: [
|
|
17195
|
-
|
|
17196
|
-
|
|
17197
|
-
|
|
17198
|
-
|
|
17199
|
-
|
|
17200
|
-
|
|
17201
|
-
|
|
17202
|
-
|
|
17203
|
-
|
|
17204
|
-
|
|
17205
|
-
|
|
17206
|
-
|
|
17207
|
-
|
|
17208
|
-
|
|
17209
|
-
|
|
17210
|
-
|
|
17211
|
-
|
|
17212
|
-
|
|
17213
|
-
|
|
17330
|
+
bindings: [
|
|
17331
|
+
{
|
|
17332
|
+
key: "tab",
|
|
17333
|
+
cmd: () => setField((f) => nextField(f, tab()))
|
|
17334
|
+
},
|
|
17335
|
+
{
|
|
17336
|
+
key: "ctrl+]",
|
|
17337
|
+
cmd: () => switchToTab(nextDialogTab(tab()))
|
|
17338
|
+
},
|
|
17339
|
+
{
|
|
17340
|
+
key: "ctrl+[",
|
|
17341
|
+
cmd: () => switchToTab(nextDialogTab(tab()))
|
|
17342
|
+
},
|
|
17343
|
+
{
|
|
17344
|
+
key: "ctrl+e",
|
|
17345
|
+
cmd: () => setVendor((v) => nextVendorWithin(availableVendors(), v))
|
|
17346
|
+
},
|
|
17347
|
+
{
|
|
17348
|
+
key: "up",
|
|
17349
|
+
cmd: () => {
|
|
17350
|
+
if (cloneInFlight())
|
|
17214
17351
|
return;
|
|
17215
|
-
|
|
17216
|
-
|
|
17217
|
-
|
|
17218
|
-
|
|
17219
|
-
|
|
17220
|
-
if (list2.length === 0)
|
|
17352
|
+
if (tab() === "existing" && field() === "repo") {
|
|
17353
|
+
const list2 = activeList();
|
|
17354
|
+
if (list2.length === 0)
|
|
17355
|
+
return;
|
|
17356
|
+
setRepoCursor(clampCursor(repoCursor() - 1, list2.length));
|
|
17221
17357
|
return;
|
|
17222
|
-
|
|
17223
|
-
|
|
17224
|
-
|
|
17225
|
-
|
|
17226
|
-
|
|
17227
|
-
|
|
17358
|
+
}
|
|
17359
|
+
if (tab() === "existing" && field() === "baseRef") {
|
|
17360
|
+
const list2 = branchFiltered();
|
|
17361
|
+
if (list2.length === 0)
|
|
17362
|
+
return;
|
|
17363
|
+
setBranchCursor(clampCursor(branchCursor() - 1, list2.length));
|
|
17228
17364
|
return;
|
|
17229
|
-
|
|
17230
|
-
|
|
17231
|
-
|
|
17232
|
-
|
|
17233
|
-
|
|
17234
|
-
|
|
17365
|
+
}
|
|
17366
|
+
if (tab() === "clone" && field() === "cloneParent") {
|
|
17367
|
+
const list2 = cloneParentFiltered();
|
|
17368
|
+
if (list2.length === 0)
|
|
17369
|
+
return;
|
|
17370
|
+
setCloneParentCursor(clampCursor(cloneParentCursor() - 1, list2.length));
|
|
17235
17371
|
return;
|
|
17236
|
-
|
|
17372
|
+
}
|
|
17373
|
+
if (tab() === "adopt") {
|
|
17374
|
+
const list2 = adoptList();
|
|
17375
|
+
if (list2.length === 0)
|
|
17376
|
+
return;
|
|
17377
|
+
setAdoptCursor(clampCursor(adoptCursor() - 1, list2.length));
|
|
17378
|
+
}
|
|
17237
17379
|
}
|
|
17238
|
-
}
|
|
17239
|
-
|
|
17240
|
-
|
|
17241
|
-
|
|
17242
|
-
|
|
17243
|
-
return;
|
|
17244
|
-
if (tab() === "existing" && field() === "repo") {
|
|
17245
|
-
const list2 = activeList();
|
|
17246
|
-
if (list2.length === 0)
|
|
17380
|
+
},
|
|
17381
|
+
{
|
|
17382
|
+
key: "down",
|
|
17383
|
+
cmd: () => {
|
|
17384
|
+
if (cloneInFlight())
|
|
17247
17385
|
return;
|
|
17248
|
-
|
|
17249
|
-
|
|
17250
|
-
|
|
17251
|
-
|
|
17252
|
-
|
|
17253
|
-
if (list2.length === 0)
|
|
17386
|
+
if (tab() === "existing" && field() === "repo") {
|
|
17387
|
+
const list2 = activeList();
|
|
17388
|
+
if (list2.length === 0)
|
|
17389
|
+
return;
|
|
17390
|
+
setRepoCursor(clampCursor(repoCursor() + 1, list2.length));
|
|
17254
17391
|
return;
|
|
17255
|
-
|
|
17256
|
-
|
|
17257
|
-
|
|
17258
|
-
|
|
17259
|
-
|
|
17260
|
-
|
|
17392
|
+
}
|
|
17393
|
+
if (tab() === "existing" && field() === "baseRef") {
|
|
17394
|
+
const list2 = branchFiltered();
|
|
17395
|
+
if (list2.length === 0)
|
|
17396
|
+
return;
|
|
17397
|
+
setBranchCursor(clampCursor(branchCursor() + 1, list2.length));
|
|
17261
17398
|
return;
|
|
17262
|
-
|
|
17263
|
-
|
|
17264
|
-
|
|
17265
|
-
|
|
17266
|
-
|
|
17267
|
-
|
|
17399
|
+
}
|
|
17400
|
+
if (tab() === "clone" && field() === "cloneParent") {
|
|
17401
|
+
const list2 = cloneParentFiltered();
|
|
17402
|
+
if (list2.length === 0)
|
|
17403
|
+
return;
|
|
17404
|
+
setCloneParentCursor(clampCursor(cloneParentCursor() + 1, list2.length));
|
|
17268
17405
|
return;
|
|
17269
|
-
|
|
17406
|
+
}
|
|
17407
|
+
if (tab() === "adopt") {
|
|
17408
|
+
const list2 = adoptList();
|
|
17409
|
+
if (list2.length === 0)
|
|
17410
|
+
return;
|
|
17411
|
+
setAdoptCursor(clampCursor(adoptCursor() + 1, list2.length));
|
|
17412
|
+
}
|
|
17270
17413
|
}
|
|
17271
|
-
}
|
|
17272
|
-
|
|
17273
|
-
|
|
17274
|
-
|
|
17275
|
-
|
|
17276
|
-
|
|
17277
|
-
const list2 = adoptList();
|
|
17278
|
-
if (list2.length === 0)
|
|
17279
|
-
return;
|
|
17280
|
-
const allSelected = list2.every((w) => adoptSelected().has(w.path));
|
|
17281
|
-
setAdoptSelected(allSelected ? new Set : new Set(list2.map((w) => w.path)));
|
|
17282
|
-
}
|
|
17283
|
-
}]
|
|
17414
|
+
},
|
|
17415
|
+
...tab() === "adopt" ? [{
|
|
17416
|
+
key: "ctrl+a",
|
|
17417
|
+
cmd: adoptSelectAll
|
|
17418
|
+
}] : []
|
|
17419
|
+
]
|
|
17284
17420
|
}));
|
|
17285
17421
|
useBindings(() => ({
|
|
17286
17422
|
enabled: field() === "confirm" && !cloneInFlight(),
|
|
@@ -18008,6 +18144,20 @@ var init_new_task_dialog = __esm(() => {
|
|
|
18008
18144
|
};
|
|
18009
18145
|
});
|
|
18010
18146
|
|
|
18147
|
+
// src/tui/component/quick-task-bindings.ts
|
|
18148
|
+
function quickTaskBindings(field, h) {
|
|
18149
|
+
return [
|
|
18150
|
+
{ key: "tab", cmd: () => h.cycleField(1) },
|
|
18151
|
+
{ key: "shift+tab", cmd: () => h.cycleField(-1) },
|
|
18152
|
+
{ key: "ctrl+e", cmd: () => h.stepEngine(1) },
|
|
18153
|
+
...field === "engine" ? [
|
|
18154
|
+
{ key: "left", cmd: () => h.stepEngine(-1) },
|
|
18155
|
+
{ key: "right", cmd: () => h.stepEngine(1) },
|
|
18156
|
+
{ key: "return", cmd: () => h.commit() }
|
|
18157
|
+
] : []
|
|
18158
|
+
];
|
|
18159
|
+
}
|
|
18160
|
+
|
|
18011
18161
|
// src/tui/component/quick-task-composer.tsx
|
|
18012
18162
|
import { TextAttributes as TextAttributes3 } from "@opentui/core";
|
|
18013
18163
|
function QuickTaskComposerView(props) {
|
|
@@ -18049,41 +18199,11 @@ function QuickTaskComposerView(props) {
|
|
|
18049
18199
|
}
|
|
18050
18200
|
useBindings(() => ({
|
|
18051
18201
|
enabled: true,
|
|
18052
|
-
bindings:
|
|
18053
|
-
|
|
18054
|
-
|
|
18055
|
-
|
|
18056
|
-
|
|
18057
|
-
{
|
|
18058
|
-
key: "shift+tab",
|
|
18059
|
-
cmd: () => cycleField(-1)
|
|
18060
|
-
},
|
|
18061
|
-
{
|
|
18062
|
-
key: "ctrl+e",
|
|
18063
|
-
cmd: () => stepEngine(1)
|
|
18064
|
-
},
|
|
18065
|
-
{
|
|
18066
|
-
key: "left",
|
|
18067
|
-
cmd: () => {
|
|
18068
|
-
if (field() === "engine")
|
|
18069
|
-
stepEngine(-1);
|
|
18070
|
-
}
|
|
18071
|
-
},
|
|
18072
|
-
{
|
|
18073
|
-
key: "right",
|
|
18074
|
-
cmd: () => {
|
|
18075
|
-
if (field() === "engine")
|
|
18076
|
-
stepEngine(1);
|
|
18077
|
-
}
|
|
18078
|
-
},
|
|
18079
|
-
{
|
|
18080
|
-
key: "return",
|
|
18081
|
-
cmd: () => {
|
|
18082
|
-
if (field() === "engine")
|
|
18083
|
-
commit();
|
|
18084
|
-
}
|
|
18085
|
-
}
|
|
18086
|
-
]
|
|
18202
|
+
bindings: quickTaskBindings(field(), {
|
|
18203
|
+
cycleField,
|
|
18204
|
+
stepEngine,
|
|
18205
|
+
commit
|
|
18206
|
+
})
|
|
18087
18207
|
}));
|
|
18088
18208
|
const fieldColor = (f) => field() === f ? theme.accent : theme.textMuted;
|
|
18089
18209
|
return (() => {
|
|
@@ -18209,6 +18329,35 @@ var init_quick_task_composer = __esm(() => {
|
|
|
18209
18329
|
};
|
|
18210
18330
|
});
|
|
18211
18331
|
|
|
18332
|
+
// src/client/connect-pane-orchestrator.ts
|
|
18333
|
+
async function connectPaneOrchestrator(options = {}) {
|
|
18334
|
+
const tag = options.logTag ?? "orch-connect";
|
|
18335
|
+
const connect2 = options.connect ?? connectIfRunning;
|
|
18336
|
+
let remote = null;
|
|
18337
|
+
try {
|
|
18338
|
+
const client = await connect2();
|
|
18339
|
+
if (!client) {
|
|
18340
|
+
logClient(tag, "no daemon running \u2014 caller degrades");
|
|
18341
|
+
return null;
|
|
18342
|
+
}
|
|
18343
|
+
remote = new RemoteOrchestrator(client, {
|
|
18344
|
+
...options.orchestratorOptions,
|
|
18345
|
+
channels: options.channels
|
|
18346
|
+
});
|
|
18347
|
+
await remote.init();
|
|
18348
|
+
return remote;
|
|
18349
|
+
} catch (err) {
|
|
18350
|
+
logClientError(tag, err);
|
|
18351
|
+
remote?.dispose();
|
|
18352
|
+
return null;
|
|
18353
|
+
}
|
|
18354
|
+
}
|
|
18355
|
+
var init_connect_pane_orchestrator = __esm(() => {
|
|
18356
|
+
init_client_log();
|
|
18357
|
+
init_daemon_process();
|
|
18358
|
+
init_remote_orchestrator();
|
|
18359
|
+
});
|
|
18360
|
+
|
|
18212
18361
|
// src/tui/context/focus.tsx
|
|
18213
18362
|
function FocusProvider(props) {
|
|
18214
18363
|
const [focused, setFocusedSignal] = createSignal(props.initial ?? "sidebar");
|
|
@@ -19211,20 +19360,12 @@ function UiPrefsSync(props) {
|
|
|
19211
19360
|
let disposed = false;
|
|
19212
19361
|
onMount(() => {
|
|
19213
19362
|
(async () => {
|
|
19214
|
-
|
|
19215
|
-
|
|
19216
|
-
|
|
19217
|
-
|
|
19218
|
-
|
|
19219
|
-
return;
|
|
19220
|
-
}
|
|
19221
|
-
remote = new RemoteOrchestrator(client);
|
|
19222
|
-
await remote.init();
|
|
19223
|
-
} catch (err) {
|
|
19224
|
-
logClientError("ui-prefs", err);
|
|
19225
|
-
remote?.dispose();
|
|
19363
|
+
const remote = await connectPaneOrchestrator({
|
|
19364
|
+
logTag: "ui-prefs",
|
|
19365
|
+
channels: ["ui-prefs", "keybindings"]
|
|
19366
|
+
});
|
|
19367
|
+
if (!remote)
|
|
19226
19368
|
return;
|
|
19227
|
-
}
|
|
19228
19369
|
if (disposed) {
|
|
19229
19370
|
remote.dispose();
|
|
19230
19371
|
return;
|
|
@@ -19282,9 +19423,8 @@ var init_host_boot = __esm(() => {
|
|
|
19282
19423
|
init_solid();
|
|
19283
19424
|
init_solid();
|
|
19284
19425
|
init_client_log();
|
|
19285
|
-
init_daemon_process();
|
|
19286
19426
|
init_dev();
|
|
19287
|
-
|
|
19427
|
+
init_connect_pane_orchestrator();
|
|
19288
19428
|
init_focus();
|
|
19289
19429
|
init_keybindings_user();
|
|
19290
19430
|
init_kv();
|
|
@@ -23876,7 +24016,9 @@ var init_Sidebar = __esm(() => {
|
|
|
23876
24016
|
// src/tui/tasks-pane/host.tsx
|
|
23877
24017
|
var exports_host3 = {};
|
|
23878
24018
|
__export(exports_host3, {
|
|
23879
|
-
startTasksPane: () => startTasksPane
|
|
24019
|
+
startTasksPane: () => startTasksPane,
|
|
24020
|
+
legendRowCap: () => legendRowCap,
|
|
24021
|
+
legendCap: () => legendCap
|
|
23880
24022
|
});
|
|
23881
24023
|
import { existsSync as existsSync16 } from "fs";
|
|
23882
24024
|
import { stat as stat5 } from "fs/promises";
|
|
@@ -24018,7 +24160,7 @@ function TasksShell(props) {
|
|
|
24018
24160
|
async function archiveTask(id) {
|
|
24019
24161
|
await archiveTaskFlow(taskActions, id);
|
|
24020
24162
|
}
|
|
24021
|
-
async function
|
|
24163
|
+
async function deleteTask2(id) {
|
|
24022
24164
|
await deleteTaskFlow(taskActions, id);
|
|
24023
24165
|
}
|
|
24024
24166
|
async function renameTask(id) {
|
|
@@ -24133,13 +24275,16 @@ function TasksShell(props) {
|
|
|
24133
24275
|
if (exists) {
|
|
24134
24276
|
const cwd2 = await getSessionOption(name, "@kobe_worktree") || task?.worktreePath || "";
|
|
24135
24277
|
if (worktreeCwdUsable(cwd2)) {
|
|
24278
|
+
const init3 = task?.repo ? resolveRepoInit(task.repo, cwd2) : {};
|
|
24136
24279
|
await ensureSession({
|
|
24137
24280
|
name,
|
|
24138
24281
|
cwd: cwd2,
|
|
24139
24282
|
command: interactiveEngineCommand(task?.vendor),
|
|
24140
24283
|
taskId: id,
|
|
24141
24284
|
vendor: task?.vendor,
|
|
24142
|
-
repo: task?.repo
|
|
24285
|
+
repo: task?.repo,
|
|
24286
|
+
initScript: init3.initScript,
|
|
24287
|
+
initPrompt: init3.initPrompt
|
|
24143
24288
|
});
|
|
24144
24289
|
}
|
|
24145
24290
|
await runTmux(["switch-client", "-t", `=${name}`]);
|
|
@@ -24238,7 +24383,7 @@ function TasksShell(props) {
|
|
|
24238
24383
|
} : undefined;
|
|
24239
24384
|
},
|
|
24240
24385
|
onRenameRequest: (id) => void renameTask(id),
|
|
24241
|
-
onDeleteRequest: (id) => void
|
|
24386
|
+
onDeleteRequest: (id) => void deleteTask2(id),
|
|
24242
24387
|
onArchiveRequest: (id) => void archiveTask(id),
|
|
24243
24388
|
onLocalMergeRequest: (id) => {
|
|
24244
24389
|
const task = props.tasks().find((t) => t.id === id);
|
|
@@ -24269,6 +24414,17 @@ function TasksShell(props) {
|
|
|
24269
24414
|
return _el$;
|
|
24270
24415
|
})();
|
|
24271
24416
|
}
|
|
24417
|
+
function legendCap(id) {
|
|
24418
|
+
const row = findBinding(id);
|
|
24419
|
+
if (!row)
|
|
24420
|
+
return null;
|
|
24421
|
+
const cap = row.hint?.keys ?? row.keys[0];
|
|
24422
|
+
return cap && cap.length > 0 ? cap : null;
|
|
24423
|
+
}
|
|
24424
|
+
function legendRowCap(ids) {
|
|
24425
|
+
const caps = ids.map(legendCap).filter((c) => c !== null);
|
|
24426
|
+
return caps.length > 0 ? caps.join("/") : null;
|
|
24427
|
+
}
|
|
24272
24428
|
function ShortcutHints(props) {
|
|
24273
24429
|
const {
|
|
24274
24430
|
theme
|
|
@@ -24356,55 +24512,70 @@ function ShortcutHints(props) {
|
|
|
24356
24512
|
});
|
|
24357
24513
|
return out;
|
|
24358
24514
|
};
|
|
24359
|
-
const defaultHints = () =>
|
|
24360
|
-
|
|
24361
|
-
|
|
24362
|
-
|
|
24363
|
-
|
|
24364
|
-
|
|
24365
|
-
|
|
24366
|
-
|
|
24367
|
-
|
|
24368
|
-
|
|
24369
|
-
|
|
24370
|
-
|
|
24371
|
-
|
|
24372
|
-
|
|
24373
|
-
|
|
24374
|
-
|
|
24375
|
-
|
|
24376
|
-
|
|
24377
|
-
|
|
24378
|
-
|
|
24379
|
-
|
|
24380
|
-
|
|
24381
|
-
|
|
24382
|
-
|
|
24383
|
-
|
|
24384
|
-
|
|
24385
|
-
|
|
24386
|
-
|
|
24387
|
-
|
|
24388
|
-
|
|
24389
|
-
|
|
24390
|
-
|
|
24391
|
-
|
|
24392
|
-
|
|
24393
|
-
|
|
24394
|
-
|
|
24395
|
-
|
|
24396
|
-
|
|
24397
|
-
|
|
24398
|
-
|
|
24399
|
-
|
|
24400
|
-
|
|
24401
|
-
|
|
24402
|
-
|
|
24403
|
-
|
|
24404
|
-
|
|
24405
|
-
|
|
24406
|
-
|
|
24407
|
-
|
|
24515
|
+
const defaultHints = () => {
|
|
24516
|
+
keymapVersion();
|
|
24517
|
+
const rows = [
|
|
24518
|
+
{
|
|
24519
|
+
ids: ["sidebar.select"],
|
|
24520
|
+
label: "open"
|
|
24521
|
+
},
|
|
24522
|
+
{
|
|
24523
|
+
ids: ["tasks.focusEngine"],
|
|
24524
|
+
label: "focus engine"
|
|
24525
|
+
},
|
|
24526
|
+
{
|
|
24527
|
+
ids: ["task.new"],
|
|
24528
|
+
label: "new task"
|
|
24529
|
+
},
|
|
24530
|
+
{
|
|
24531
|
+
ids: ["settings.open.sidebar"],
|
|
24532
|
+
label: "settings"
|
|
24533
|
+
},
|
|
24534
|
+
{
|
|
24535
|
+
ids: ["tasks.openWorktree"],
|
|
24536
|
+
label: "open wt"
|
|
24537
|
+
},
|
|
24538
|
+
{
|
|
24539
|
+
ids: ["sidebar.view"],
|
|
24540
|
+
label: "views"
|
|
24541
|
+
},
|
|
24542
|
+
{
|
|
24543
|
+
ids: ["sidebar.sort"],
|
|
24544
|
+
label: "sort"
|
|
24545
|
+
},
|
|
24546
|
+
{
|
|
24547
|
+
ids: ["sidebar.localMerge"],
|
|
24548
|
+
label: "move task",
|
|
24549
|
+
dimWhenMain: true
|
|
24550
|
+
},
|
|
24551
|
+
{
|
|
24552
|
+
ids: ["sidebar.archive", "sidebar.delete"],
|
|
24553
|
+
label: "un/archive\xB7delete"
|
|
24554
|
+
},
|
|
24555
|
+
{
|
|
24556
|
+
ids: ["sidebar.rename", "tasks.renameBranch", "tasks.cycleEngine"],
|
|
24557
|
+
label: "name/branch/engine",
|
|
24558
|
+
dimWhenMain: true
|
|
24559
|
+
},
|
|
24560
|
+
{
|
|
24561
|
+
ids: ["help.open"],
|
|
24562
|
+
label: "help"
|
|
24563
|
+
}
|
|
24564
|
+
];
|
|
24565
|
+
const out = [];
|
|
24566
|
+
for (const row of rows) {
|
|
24567
|
+
const k = legendRowCap(row.ids);
|
|
24568
|
+
if (k === null)
|
|
24569
|
+
continue;
|
|
24570
|
+
out.push({
|
|
24571
|
+
k,
|
|
24572
|
+
label: row.label,
|
|
24573
|
+
dimWhenMain: row.dimWhenMain
|
|
24574
|
+
});
|
|
24575
|
+
}
|
|
24576
|
+
out.push(...tmuxHints());
|
|
24577
|
+
return out;
|
|
24578
|
+
};
|
|
24408
24579
|
const MOVE_HINTS = [{
|
|
24409
24580
|
k: "j/k",
|
|
24410
24581
|
label: "reorder"
|
|
@@ -24674,10 +24845,14 @@ async function startSettingsHost() {
|
|
|
24674
24845
|
setup: async () => {
|
|
24675
24846
|
let orch = null;
|
|
24676
24847
|
try {
|
|
24677
|
-
const client = await
|
|
24678
|
-
|
|
24679
|
-
|
|
24680
|
-
|
|
24848
|
+
const client = await connectIfRunning();
|
|
24849
|
+
if (client) {
|
|
24850
|
+
const remote = new RemoteOrchestrator(client);
|
|
24851
|
+
await remote.init();
|
|
24852
|
+
orch = remote;
|
|
24853
|
+
} else {
|
|
24854
|
+
console.error("[kobe settings] no daemon running; Restart backend disabled");
|
|
24855
|
+
}
|
|
24681
24856
|
} catch (err) {
|
|
24682
24857
|
console.error("[kobe settings] daemon unavailable; Restart backend disabled:", err);
|
|
24683
24858
|
}
|
|
@@ -26492,10 +26667,16 @@ var init_pr_prompt = __esm(() => {
|
|
|
26492
26667
|
var exports_host7 = {};
|
|
26493
26668
|
__export(exports_host7, {
|
|
26494
26669
|
startOpsPreview: () => startOpsPreview,
|
|
26495
|
-
startOpsHost: () => startOpsHost
|
|
26670
|
+
startOpsHost: () => startOpsHost,
|
|
26671
|
+
nextActivityPollDelay: () => nextActivityPollDelay
|
|
26496
26672
|
});
|
|
26497
26673
|
import { createHash as createHash5 } from "crypto";
|
|
26498
26674
|
import { SyntaxStyle } from "@opentui/core";
|
|
26675
|
+
function nextActivityPollDelay(currentMs, idleStreak) {
|
|
26676
|
+
if (idleStreak < ACTIVITY_IDLE_RAMP_POLLS)
|
|
26677
|
+
return ACTIVITY_POLL_MIN_MS;
|
|
26678
|
+
return Math.min(currentMs * 2, ACTIVITY_POLL_MAX_MS);
|
|
26679
|
+
}
|
|
26499
26680
|
function OpsShell(props) {
|
|
26500
26681
|
const {
|
|
26501
26682
|
theme
|
|
@@ -26505,6 +26686,10 @@ function OpsShell(props) {
|
|
|
26505
26686
|
let primed = false;
|
|
26506
26687
|
onMount(() => {
|
|
26507
26688
|
let disposed = false;
|
|
26689
|
+
let timer;
|
|
26690
|
+
let delayMs = ACTIVITY_POLL_MIN_MS;
|
|
26691
|
+
let idleStreak = 0;
|
|
26692
|
+
let lastSeenMtime = 0;
|
|
26508
26693
|
async function poll() {
|
|
26509
26694
|
try {
|
|
26510
26695
|
const mtime = await latestTranscriptMtime(props.vendor, props.worktree);
|
|
@@ -26513,15 +26698,29 @@ function OpsShell(props) {
|
|
|
26513
26698
|
if (!primed) {
|
|
26514
26699
|
primed = true;
|
|
26515
26700
|
setBaseline(mtime);
|
|
26701
|
+
lastSeenMtime = mtime;
|
|
26702
|
+
}
|
|
26703
|
+
if (mtime > lastSeenMtime) {
|
|
26704
|
+
lastSeenMtime = mtime;
|
|
26705
|
+
idleStreak = 0;
|
|
26706
|
+
} else {
|
|
26707
|
+
idleStreak++;
|
|
26516
26708
|
}
|
|
26517
26709
|
setLatest(mtime);
|
|
26518
|
-
} catch {
|
|
26710
|
+
} catch {
|
|
26711
|
+
idleStreak++;
|
|
26712
|
+
} finally {
|
|
26713
|
+
if (!disposed) {
|
|
26714
|
+
delayMs = nextActivityPollDelay(delayMs, idleStreak);
|
|
26715
|
+
timer = setTimeout(() => void poll(), delayMs);
|
|
26716
|
+
}
|
|
26717
|
+
}
|
|
26519
26718
|
}
|
|
26520
26719
|
poll();
|
|
26521
|
-
const timer = setInterval(() => void poll(), ACTIVITY_POLL_MS);
|
|
26522
26720
|
onCleanup(() => {
|
|
26523
26721
|
disposed = true;
|
|
26524
|
-
|
|
26722
|
+
if (timer)
|
|
26723
|
+
clearTimeout(timer);
|
|
26525
26724
|
});
|
|
26526
26725
|
});
|
|
26527
26726
|
const hasNewActivity = () => primed && latest() > baseline();
|
|
@@ -26883,7 +27082,7 @@ async function startOpsPreview(args2) {
|
|
|
26883
27082
|
})
|
|
26884
27083
|
});
|
|
26885
27084
|
}
|
|
26886
|
-
var
|
|
27085
|
+
var ACTIVITY_POLL_MIN_MS = 2500, ACTIVITY_POLL_MAX_MS = 20000, ACTIVITY_IDLE_RAMP_POLLS = 3, TURN_STATUS_POLL_MS = 1500, STABLE_POLLS_FOR_DONE = 2, CHAT_TAB_STATE_OPTION2 = "@kobe_tab_state";
|
|
26887
27086
|
var init_host7 = __esm(() => {
|
|
26888
27087
|
init_solid();
|
|
26889
27088
|
init_solid();
|