@sma1lboy/kobe 0.7.21 → 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 +442 -227
- 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(),
|
|
@@ -18193,6 +18329,35 @@ var init_quick_task_composer = __esm(() => {
|
|
|
18193
18329
|
};
|
|
18194
18330
|
});
|
|
18195
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
|
+
|
|
18196
18361
|
// src/tui/context/focus.tsx
|
|
18197
18362
|
function FocusProvider(props) {
|
|
18198
18363
|
const [focused, setFocusedSignal] = createSignal(props.initial ?? "sidebar");
|
|
@@ -19195,20 +19360,12 @@ function UiPrefsSync(props) {
|
|
|
19195
19360
|
let disposed = false;
|
|
19196
19361
|
onMount(() => {
|
|
19197
19362
|
(async () => {
|
|
19198
|
-
|
|
19199
|
-
|
|
19200
|
-
|
|
19201
|
-
|
|
19202
|
-
|
|
19203
|
-
return;
|
|
19204
|
-
}
|
|
19205
|
-
remote = new RemoteOrchestrator(client);
|
|
19206
|
-
await remote.init();
|
|
19207
|
-
} catch (err) {
|
|
19208
|
-
logClientError("ui-prefs", err);
|
|
19209
|
-
remote?.dispose();
|
|
19363
|
+
const remote = await connectPaneOrchestrator({
|
|
19364
|
+
logTag: "ui-prefs",
|
|
19365
|
+
channels: ["ui-prefs", "keybindings"]
|
|
19366
|
+
});
|
|
19367
|
+
if (!remote)
|
|
19210
19368
|
return;
|
|
19211
|
-
}
|
|
19212
19369
|
if (disposed) {
|
|
19213
19370
|
remote.dispose();
|
|
19214
19371
|
return;
|
|
@@ -19266,9 +19423,8 @@ var init_host_boot = __esm(() => {
|
|
|
19266
19423
|
init_solid();
|
|
19267
19424
|
init_solid();
|
|
19268
19425
|
init_client_log();
|
|
19269
|
-
init_daemon_process();
|
|
19270
19426
|
init_dev();
|
|
19271
|
-
|
|
19427
|
+
init_connect_pane_orchestrator();
|
|
19272
19428
|
init_focus();
|
|
19273
19429
|
init_keybindings_user();
|
|
19274
19430
|
init_kv();
|
|
@@ -23860,7 +24016,9 @@ var init_Sidebar = __esm(() => {
|
|
|
23860
24016
|
// src/tui/tasks-pane/host.tsx
|
|
23861
24017
|
var exports_host3 = {};
|
|
23862
24018
|
__export(exports_host3, {
|
|
23863
|
-
startTasksPane: () => startTasksPane
|
|
24019
|
+
startTasksPane: () => startTasksPane,
|
|
24020
|
+
legendRowCap: () => legendRowCap,
|
|
24021
|
+
legendCap: () => legendCap
|
|
23864
24022
|
});
|
|
23865
24023
|
import { existsSync as existsSync16 } from "fs";
|
|
23866
24024
|
import { stat as stat5 } from "fs/promises";
|
|
@@ -24002,7 +24160,7 @@ function TasksShell(props) {
|
|
|
24002
24160
|
async function archiveTask(id) {
|
|
24003
24161
|
await archiveTaskFlow(taskActions, id);
|
|
24004
24162
|
}
|
|
24005
|
-
async function
|
|
24163
|
+
async function deleteTask2(id) {
|
|
24006
24164
|
await deleteTaskFlow(taskActions, id);
|
|
24007
24165
|
}
|
|
24008
24166
|
async function renameTask(id) {
|
|
@@ -24117,13 +24275,16 @@ function TasksShell(props) {
|
|
|
24117
24275
|
if (exists) {
|
|
24118
24276
|
const cwd2 = await getSessionOption(name, "@kobe_worktree") || task?.worktreePath || "";
|
|
24119
24277
|
if (worktreeCwdUsable(cwd2)) {
|
|
24278
|
+
const init3 = task?.repo ? resolveRepoInit(task.repo, cwd2) : {};
|
|
24120
24279
|
await ensureSession({
|
|
24121
24280
|
name,
|
|
24122
24281
|
cwd: cwd2,
|
|
24123
24282
|
command: interactiveEngineCommand(task?.vendor),
|
|
24124
24283
|
taskId: id,
|
|
24125
24284
|
vendor: task?.vendor,
|
|
24126
|
-
repo: task?.repo
|
|
24285
|
+
repo: task?.repo,
|
|
24286
|
+
initScript: init3.initScript,
|
|
24287
|
+
initPrompt: init3.initPrompt
|
|
24127
24288
|
});
|
|
24128
24289
|
}
|
|
24129
24290
|
await runTmux(["switch-client", "-t", `=${name}`]);
|
|
@@ -24222,7 +24383,7 @@ function TasksShell(props) {
|
|
|
24222
24383
|
} : undefined;
|
|
24223
24384
|
},
|
|
24224
24385
|
onRenameRequest: (id) => void renameTask(id),
|
|
24225
|
-
onDeleteRequest: (id) => void
|
|
24386
|
+
onDeleteRequest: (id) => void deleteTask2(id),
|
|
24226
24387
|
onArchiveRequest: (id) => void archiveTask(id),
|
|
24227
24388
|
onLocalMergeRequest: (id) => {
|
|
24228
24389
|
const task = props.tasks().find((t) => t.id === id);
|
|
@@ -24253,6 +24414,17 @@ function TasksShell(props) {
|
|
|
24253
24414
|
return _el$;
|
|
24254
24415
|
})();
|
|
24255
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
|
+
}
|
|
24256
24428
|
function ShortcutHints(props) {
|
|
24257
24429
|
const {
|
|
24258
24430
|
theme
|
|
@@ -24340,55 +24512,70 @@ function ShortcutHints(props) {
|
|
|
24340
24512
|
});
|
|
24341
24513
|
return out;
|
|
24342
24514
|
};
|
|
24343
|
-
const defaultHints = () =>
|
|
24344
|
-
|
|
24345
|
-
|
|
24346
|
-
|
|
24347
|
-
|
|
24348
|
-
|
|
24349
|
-
|
|
24350
|
-
|
|
24351
|
-
|
|
24352
|
-
|
|
24353
|
-
|
|
24354
|
-
|
|
24355
|
-
|
|
24356
|
-
|
|
24357
|
-
|
|
24358
|
-
|
|
24359
|
-
|
|
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
|
-
|
|
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
|
+
};
|
|
24392
24579
|
const MOVE_HINTS = [{
|
|
24393
24580
|
k: "j/k",
|
|
24394
24581
|
label: "reorder"
|
|
@@ -24658,10 +24845,14 @@ async function startSettingsHost() {
|
|
|
24658
24845
|
setup: async () => {
|
|
24659
24846
|
let orch = null;
|
|
24660
24847
|
try {
|
|
24661
|
-
const client = await
|
|
24662
|
-
|
|
24663
|
-
|
|
24664
|
-
|
|
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
|
+
}
|
|
24665
24856
|
} catch (err) {
|
|
24666
24857
|
console.error("[kobe settings] daemon unavailable; Restart backend disabled:", err);
|
|
24667
24858
|
}
|
|
@@ -26476,10 +26667,16 @@ var init_pr_prompt = __esm(() => {
|
|
|
26476
26667
|
var exports_host7 = {};
|
|
26477
26668
|
__export(exports_host7, {
|
|
26478
26669
|
startOpsPreview: () => startOpsPreview,
|
|
26479
|
-
startOpsHost: () => startOpsHost
|
|
26670
|
+
startOpsHost: () => startOpsHost,
|
|
26671
|
+
nextActivityPollDelay: () => nextActivityPollDelay
|
|
26480
26672
|
});
|
|
26481
26673
|
import { createHash as createHash5 } from "crypto";
|
|
26482
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
|
+
}
|
|
26483
26680
|
function OpsShell(props) {
|
|
26484
26681
|
const {
|
|
26485
26682
|
theme
|
|
@@ -26489,6 +26686,10 @@ function OpsShell(props) {
|
|
|
26489
26686
|
let primed = false;
|
|
26490
26687
|
onMount(() => {
|
|
26491
26688
|
let disposed = false;
|
|
26689
|
+
let timer;
|
|
26690
|
+
let delayMs = ACTIVITY_POLL_MIN_MS;
|
|
26691
|
+
let idleStreak = 0;
|
|
26692
|
+
let lastSeenMtime = 0;
|
|
26492
26693
|
async function poll() {
|
|
26493
26694
|
try {
|
|
26494
26695
|
const mtime = await latestTranscriptMtime(props.vendor, props.worktree);
|
|
@@ -26497,15 +26698,29 @@ function OpsShell(props) {
|
|
|
26497
26698
|
if (!primed) {
|
|
26498
26699
|
primed = true;
|
|
26499
26700
|
setBaseline(mtime);
|
|
26701
|
+
lastSeenMtime = mtime;
|
|
26702
|
+
}
|
|
26703
|
+
if (mtime > lastSeenMtime) {
|
|
26704
|
+
lastSeenMtime = mtime;
|
|
26705
|
+
idleStreak = 0;
|
|
26706
|
+
} else {
|
|
26707
|
+
idleStreak++;
|
|
26500
26708
|
}
|
|
26501
26709
|
setLatest(mtime);
|
|
26502
|
-
} catch {
|
|
26710
|
+
} catch {
|
|
26711
|
+
idleStreak++;
|
|
26712
|
+
} finally {
|
|
26713
|
+
if (!disposed) {
|
|
26714
|
+
delayMs = nextActivityPollDelay(delayMs, idleStreak);
|
|
26715
|
+
timer = setTimeout(() => void poll(), delayMs);
|
|
26716
|
+
}
|
|
26717
|
+
}
|
|
26503
26718
|
}
|
|
26504
26719
|
poll();
|
|
26505
|
-
const timer = setInterval(() => void poll(), ACTIVITY_POLL_MS);
|
|
26506
26720
|
onCleanup(() => {
|
|
26507
26721
|
disposed = true;
|
|
26508
|
-
|
|
26722
|
+
if (timer)
|
|
26723
|
+
clearTimeout(timer);
|
|
26509
26724
|
});
|
|
26510
26725
|
});
|
|
26511
26726
|
const hasNewActivity = () => primed && latest() > baseline();
|
|
@@ -26867,7 +27082,7 @@ async function startOpsPreview(args2) {
|
|
|
26867
27082
|
})
|
|
26868
27083
|
});
|
|
26869
27084
|
}
|
|
26870
|
-
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";
|
|
26871
27086
|
var init_host7 = __esm(() => {
|
|
26872
27087
|
init_solid();
|
|
26873
27088
|
init_solid();
|