@sma1lboy/kobe 0.7.7 → 0.7.9
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 +264 -254
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -70,7 +70,7 @@ var init_package = __esm(() => {
|
|
|
70
70
|
package_default = {
|
|
71
71
|
$schema: "https://json.schemastore.org/package.json",
|
|
72
72
|
name: "@sma1lboy/kobe",
|
|
73
|
-
version: "0.7.
|
|
73
|
+
version: "0.7.9",
|
|
74
74
|
description: "TUI orchestrator for Claude Code (codename)",
|
|
75
75
|
type: "module",
|
|
76
76
|
packageManager: "bun@1.3.13",
|
|
@@ -4997,6 +4997,29 @@ var init_auto_title_poller = __esm(() => {
|
|
|
4997
4997
|
init_chat_tab_naming();
|
|
4998
4998
|
});
|
|
4999
4999
|
|
|
5000
|
+
// src/daemon/cwd-task.ts
|
|
5001
|
+
function normalize(p) {
|
|
5002
|
+
return p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
|
|
5003
|
+
}
|
|
5004
|
+
function isAncestorOrSelf(wt, cwd) {
|
|
5005
|
+
return cwd === wt || cwd.startsWith(`${wt}/`);
|
|
5006
|
+
}
|
|
5007
|
+
function matchTaskByCwd(tasks, cwd) {
|
|
5008
|
+
const target = normalize(cwd);
|
|
5009
|
+
let bestId;
|
|
5010
|
+
let bestLen = -1;
|
|
5011
|
+
for (const t of tasks) {
|
|
5012
|
+
if (!t.worktreePath)
|
|
5013
|
+
continue;
|
|
5014
|
+
const wt = normalize(t.worktreePath);
|
|
5015
|
+
if (isAncestorOrSelf(wt, target) && wt.length > bestLen) {
|
|
5016
|
+
bestLen = wt.length;
|
|
5017
|
+
bestId = t.id;
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
return bestId;
|
|
5021
|
+
}
|
|
5022
|
+
|
|
5000
5023
|
// src/daemon/event-bus.ts
|
|
5001
5024
|
class DaemonEventBus {
|
|
5002
5025
|
last = new Map;
|
|
@@ -5317,10 +5340,14 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
5317
5340
|
return {};
|
|
5318
5341
|
}
|
|
5319
5342
|
case "engine.reportEvent": {
|
|
5320
|
-
const taskId = requireString(payload, "taskId");
|
|
5321
5343
|
const kind = requireString(payload, "kind");
|
|
5322
5344
|
if (!isEngineActivityKind(kind))
|
|
5323
5345
|
throw new Error(`unknown engine event kind: ${kind}`);
|
|
5346
|
+
const explicitId = optionalString(payload, "taskId");
|
|
5347
|
+
const cwd = optionalString(payload, "cwd");
|
|
5348
|
+
const taskId = explicitId ?? (cwd ? matchTaskByCwd(orch.listTasks(), cwd) : undefined);
|
|
5349
|
+
if (!taskId)
|
|
5350
|
+
return {};
|
|
5324
5351
|
const detail = optionalActivityDetail(payload);
|
|
5325
5352
|
reportActivity(taskId, kind, detail);
|
|
5326
5353
|
return {};
|
|
@@ -5863,172 +5890,6 @@ var init_prompt_delivery = __esm(() => {
|
|
|
5863
5890
|
init_client2();
|
|
5864
5891
|
});
|
|
5865
5892
|
|
|
5866
|
-
// src/engine/claude-code-local/hook-adapter.ts
|
|
5867
|
-
import { existsSync as existsSync2 } from "fs";
|
|
5868
|
-
import { appendFile as appendFile3, mkdir as mkdir5, readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
|
|
5869
|
-
import { dirname as dirname6, join as join4 } from "path";
|
|
5870
|
-
function isObject6(v) {
|
|
5871
|
-
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
5872
|
-
}
|
|
5873
|
-
async function readJsonObject(path6) {
|
|
5874
|
-
try {
|
|
5875
|
-
const parsed = JSON.parse(await readFile6(path6, "utf8"));
|
|
5876
|
-
return isObject6(parsed) ? parsed : {};
|
|
5877
|
-
} catch {
|
|
5878
|
-
return {};
|
|
5879
|
-
}
|
|
5880
|
-
}
|
|
5881
|
-
function isKobeWorktreeSyncGroup(group) {
|
|
5882
|
-
if (!isObject6(group) || !Array.isArray(group.hooks))
|
|
5883
|
-
return false;
|
|
5884
|
-
return group.hooks.some((h) => isObject6(h) && typeof h.command === "string" && h.command.includes(WORKTREE_SYNC_MARKER));
|
|
5885
|
-
}
|
|
5886
|
-
function mergeWorktreeSyncHook(current, command) {
|
|
5887
|
-
const { hooks: rawHooks, ...restSettings } = current;
|
|
5888
|
-
const { WorktreeCreate, ...otherHooks } = isObject6(rawHooks) ? rawHooks : {};
|
|
5889
|
-
const prior = Array.isArray(WorktreeCreate) ? WorktreeCreate : [];
|
|
5890
|
-
const kept = prior.filter((g) => !isKobeWorktreeSyncGroup(g));
|
|
5891
|
-
if (command !== null)
|
|
5892
|
-
kept.push({ hooks: [{ type: "command", command }] });
|
|
5893
|
-
const nextHooks = { ...otherHooks };
|
|
5894
|
-
if (kept.length > 0)
|
|
5895
|
-
nextHooks.WorktreeCreate = kept;
|
|
5896
|
-
return Object.keys(nextHooks).length > 0 ? { ...restSettings, hooks: nextHooks } : { ...restSettings };
|
|
5897
|
-
}
|
|
5898
|
-
function buildClaudeHooks(taskId, inv = kobeCliInvocation()) {
|
|
5899
|
-
const out = {};
|
|
5900
|
-
for (const { event, matcher, verb } of EVENT_MAP) {
|
|
5901
|
-
const command = shellQuoteArgv([...inv, "hook", verb, "--task-id", taskId]);
|
|
5902
|
-
const group = { hooks: [{ type: "command", command }] };
|
|
5903
|
-
if (matcher)
|
|
5904
|
-
group.matcher = matcher;
|
|
5905
|
-
out[event] = [group];
|
|
5906
|
-
}
|
|
5907
|
-
return out;
|
|
5908
|
-
}
|
|
5909
|
-
function mergeClaudeHooks(existing, kobeHooks) {
|
|
5910
|
-
const merged = { ...existing };
|
|
5911
|
-
for (const event of KOBE_HOOK_EVENTS)
|
|
5912
|
-
merged[event] = kobeHooks[event];
|
|
5913
|
-
return merged;
|
|
5914
|
-
}
|
|
5915
|
-
|
|
5916
|
-
class ClaudeHookAdapter {
|
|
5917
|
-
vendor = "claude";
|
|
5918
|
-
supportsHooks() {
|
|
5919
|
-
return true;
|
|
5920
|
-
}
|
|
5921
|
-
supportsWorktreeSync() {
|
|
5922
|
-
return true;
|
|
5923
|
-
}
|
|
5924
|
-
async installWorktreeSyncHook(settingsFilePath) {
|
|
5925
|
-
await this.editWorktreeSyncHook(settingsFilePath, true);
|
|
5926
|
-
}
|
|
5927
|
-
async removeWorktreeSyncHook(settingsFilePath) {
|
|
5928
|
-
await this.editWorktreeSyncHook(settingsFilePath, false);
|
|
5929
|
-
}
|
|
5930
|
-
async editWorktreeSyncHook(settingsFilePath, install) {
|
|
5931
|
-
const current = await readJsonObject(settingsFilePath);
|
|
5932
|
-
const command = install ? shellQuoteArgv([...kobeCliInvocation(), "hook", "worktree-created"]) : null;
|
|
5933
|
-
const next = mergeWorktreeSyncHook(current, command);
|
|
5934
|
-
if (JSON.stringify(next) === JSON.stringify(current))
|
|
5935
|
-
return;
|
|
5936
|
-
await mkdir5(dirname6(settingsFilePath), { recursive: true });
|
|
5937
|
-
await writeFile4(settingsFilePath, `${JSON.stringify(next, null, 2)}
|
|
5938
|
-
`);
|
|
5939
|
-
}
|
|
5940
|
-
async installTaskHooks(ctx) {
|
|
5941
|
-
try {
|
|
5942
|
-
const claudeDir = join4(ctx.worktreeDir, ".claude");
|
|
5943
|
-
const settingsPath = join4(claudeDir, "settings.local.json");
|
|
5944
|
-
await mkdir5(claudeDir, { recursive: true });
|
|
5945
|
-
let current = {};
|
|
5946
|
-
try {
|
|
5947
|
-
const raw = await readFile6(settingsPath, "utf8");
|
|
5948
|
-
const parsed = JSON.parse(raw);
|
|
5949
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
5950
|
-
current = parsed;
|
|
5951
|
-
} catch {}
|
|
5952
|
-
const existingHooks = current.hooks && typeof current.hooks === "object" && !Array.isArray(current.hooks) ? current.hooks : {};
|
|
5953
|
-
current.hooks = mergeClaudeHooks(existingHooks, buildClaudeHooks(ctx.taskId));
|
|
5954
|
-
await writeFile4(settingsPath, `${JSON.stringify(current, null, 2)}
|
|
5955
|
-
`);
|
|
5956
|
-
await hideFromGit(ctx.worktreeDir, ".claude/settings.local.json");
|
|
5957
|
-
} catch {}
|
|
5958
|
-
}
|
|
5959
|
-
}
|
|
5960
|
-
async function hideFromGit(worktreeDir, relPath) {
|
|
5961
|
-
if (hiddenWorktrees.has(worktreeDir))
|
|
5962
|
-
return;
|
|
5963
|
-
try {
|
|
5964
|
-
const proc = Bun.spawn(["git", "-C", worktreeDir, "rev-parse", "--git-common-dir"], {
|
|
5965
|
-
stdout: "pipe",
|
|
5966
|
-
stderr: "ignore"
|
|
5967
|
-
});
|
|
5968
|
-
const [out, code] = await Promise.all([new Response(proc.stdout).text(), proc.exited]);
|
|
5969
|
-
if (code !== 0)
|
|
5970
|
-
return;
|
|
5971
|
-
let commonDir = out.trim();
|
|
5972
|
-
if (!commonDir)
|
|
5973
|
-
return;
|
|
5974
|
-
if (!commonDir.startsWith("/"))
|
|
5975
|
-
commonDir = join4(worktreeDir, commonDir);
|
|
5976
|
-
const excludePath = join4(commonDir, "info", "exclude");
|
|
5977
|
-
const existing = existsSync2(excludePath) ? await readFile6(excludePath, "utf8") : "";
|
|
5978
|
-
if (existing.split(`
|
|
5979
|
-
`).some((l) => l.trim() === relPath)) {
|
|
5980
|
-
hiddenWorktrees.add(worktreeDir);
|
|
5981
|
-
return;
|
|
5982
|
-
}
|
|
5983
|
-
await mkdir5(join4(commonDir, "info"), { recursive: true });
|
|
5984
|
-
await appendFile3(excludePath, `${existing.endsWith(`
|
|
5985
|
-
`) || existing === "" ? "" : `
|
|
5986
|
-
`}${relPath}
|
|
5987
|
-
`);
|
|
5988
|
-
hiddenWorktrees.add(worktreeDir);
|
|
5989
|
-
} catch {}
|
|
5990
|
-
}
|
|
5991
|
-
var EVENT_MAP, KOBE_HOOK_EVENTS, WORKTREE_SYNC_MARKER = "worktree-created", hiddenWorktrees;
|
|
5992
|
-
var init_hook_adapter = __esm(() => {
|
|
5993
|
-
init_invocation();
|
|
5994
|
-
EVENT_MAP = [
|
|
5995
|
-
{ event: "SessionStart", verb: "session-start" },
|
|
5996
|
-
{ event: "UserPromptSubmit", verb: "turn-start" },
|
|
5997
|
-
{ event: "Stop", verb: "turn-complete" },
|
|
5998
|
-
{ event: "StopFailure", verb: "turn-failed" },
|
|
5999
|
-
{ event: "Notification", matcher: "permission_prompt", verb: "awaiting-input" },
|
|
6000
|
-
{ event: "SessionEnd", verb: "session-end" }
|
|
6001
|
-
];
|
|
6002
|
-
KOBE_HOOK_EVENTS = EVENT_MAP.map((e) => e.event);
|
|
6003
|
-
hiddenWorktrees = new Set;
|
|
6004
|
-
});
|
|
6005
|
-
|
|
6006
|
-
// src/engine/hook-adapter.ts
|
|
6007
|
-
function createEngineHookAdapter(vendor) {
|
|
6008
|
-
if (vendor === "claude")
|
|
6009
|
-
return new ClaudeHookAdapter;
|
|
6010
|
-
return new NoopHookAdapter(vendor);
|
|
6011
|
-
}
|
|
6012
|
-
|
|
6013
|
-
class NoopHookAdapter {
|
|
6014
|
-
vendor;
|
|
6015
|
-
constructor(vendor) {
|
|
6016
|
-
this.vendor = vendor;
|
|
6017
|
-
}
|
|
6018
|
-
supportsHooks() {
|
|
6019
|
-
return false;
|
|
6020
|
-
}
|
|
6021
|
-
async installTaskHooks() {}
|
|
6022
|
-
supportsWorktreeSync() {
|
|
6023
|
-
return false;
|
|
6024
|
-
}
|
|
6025
|
-
async installWorktreeSyncHook() {}
|
|
6026
|
-
async removeWorktreeSyncHook() {}
|
|
6027
|
-
}
|
|
6028
|
-
var init_hook_adapter2 = __esm(() => {
|
|
6029
|
-
init_hook_adapter();
|
|
6030
|
-
});
|
|
6031
|
-
|
|
6032
5893
|
// src/tui/panes/terminal/tmux.ts
|
|
6033
5894
|
var exports_tmux = {};
|
|
6034
5895
|
__export(exports_tmux, {
|
|
@@ -6079,12 +5940,6 @@ async function ensureSession(opts) {
|
|
|
6079
5940
|
}
|
|
6080
5941
|
}
|
|
6081
5942
|
async function ensureSessionImpl(opts) {
|
|
6082
|
-
if (opts.taskId && opts.cwd) {
|
|
6083
|
-
await createEngineHookAdapter(coerceVendorId(opts.vendor)).installTaskHooks({
|
|
6084
|
-
worktreeDir: opts.cwd,
|
|
6085
|
-
taskId: opts.taskId
|
|
6086
|
-
});
|
|
6087
|
-
}
|
|
6088
5943
|
if (await sessionExists(opts.name)) {
|
|
6089
5944
|
const sessionOptions = await getSessionOptions(opts.name, ["@kobe_worktree", "@kobe_vendor"]);
|
|
6090
5945
|
const taggedWorktree = sessionOptions["@kobe_worktree"] ?? "";
|
|
@@ -6499,7 +6354,6 @@ async function quickCreate(session) {
|
|
|
6499
6354
|
var CHAT_TAB_SWITCH_BINDINGS, CHAT_TAB_CLOSE_BINDING, CHAT_TAB_RENAME_BINDING, CHAT_TAB_ENGINE_PROMPT, CHAT_TAB_CHOOSE_ENGINE_BINDINGS, CHAT_TAB_STATE_OPTION = "@kobe_tab_state", PANE_VERSION_OPTION = "@kobe_pane_version", CHAT_TAB_STATUS_FORMAT = "#{?#{==:#{@kobe_tab_state},running},\u25CF,#{?#{==:#{@kobe_tab_state},done},\u2713,#{?#{==:#{@kobe_tab_state},error},!,#{?#{==:#{@kobe_tab_state},unknown},?,\u25CB}}}} #I:#W", CHAT_TAB_STATUS_CURRENT_FORMAT, ensureSessionLocks;
|
|
6500
6355
|
var init_tmux = __esm(() => {
|
|
6501
6356
|
init_invocation();
|
|
6502
|
-
init_hook_adapter2();
|
|
6503
6357
|
init_interactive_command();
|
|
6504
6358
|
init_env();
|
|
6505
6359
|
init_client2();
|
|
@@ -6544,14 +6398,14 @@ var exports_repo_init = {};
|
|
|
6544
6398
|
__export(exports_repo_init, {
|
|
6545
6399
|
resolveRepoInit: () => resolveRepoInit
|
|
6546
6400
|
});
|
|
6547
|
-
import { existsSync as
|
|
6548
|
-
import { join as
|
|
6401
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
6402
|
+
import { join as join4 } from "path";
|
|
6549
6403
|
function repoFileScript(worktreePath) {
|
|
6550
|
-
return
|
|
6404
|
+
return existsSync2(join4(worktreePath, INIT_SCRIPT_REL)) ? `sh ${INIT_SCRIPT_REL}` : undefined;
|
|
6551
6405
|
}
|
|
6552
6406
|
function repoFilePrompt(worktreePath) {
|
|
6553
|
-
const p =
|
|
6554
|
-
if (!
|
|
6407
|
+
const p = join4(worktreePath, INIT_PROMPT_REL);
|
|
6408
|
+
if (!existsSync2(p))
|
|
6555
6409
|
return;
|
|
6556
6410
|
try {
|
|
6557
6411
|
const text = readFileSync3(p, "utf8");
|
|
@@ -6572,8 +6426,8 @@ function resolveRepoInit(repoRoot, worktreePath) {
|
|
|
6572
6426
|
var INIT_SCRIPT_REL, INIT_PROMPT_REL;
|
|
6573
6427
|
var init_repo_init = __esm(() => {
|
|
6574
6428
|
init_repos();
|
|
6575
|
-
INIT_SCRIPT_REL =
|
|
6576
|
-
INIT_PROMPT_REL =
|
|
6429
|
+
INIT_SCRIPT_REL = join4(".kobe", "init.sh");
|
|
6430
|
+
INIT_PROMPT_REL = join4(".kobe", "init-prompt.md");
|
|
6577
6431
|
});
|
|
6578
6432
|
|
|
6579
6433
|
// src/tui/panes/sidebar/worktree-changes.ts
|
|
@@ -7585,9 +7439,9 @@ var init_schema = () => {};
|
|
|
7585
7439
|
|
|
7586
7440
|
// src/tui/context/theme/loader.ts
|
|
7587
7441
|
import { readFileSync as readFileSync4, readdirSync } from "fs";
|
|
7588
|
-
import { join as
|
|
7442
|
+
import { join as join5 } from "path";
|
|
7589
7443
|
function userThemesDir() {
|
|
7590
|
-
return
|
|
7444
|
+
return join5(kobeStateDir(), "themes");
|
|
7591
7445
|
}
|
|
7592
7446
|
function loadUserThemes() {
|
|
7593
7447
|
const dir = userThemesDir();
|
|
@@ -7601,7 +7455,7 @@ function loadUserThemes() {
|
|
|
7601
7455
|
for (const file of entries) {
|
|
7602
7456
|
if (!file.endsWith(".json"))
|
|
7603
7457
|
continue;
|
|
7604
|
-
const path6 =
|
|
7458
|
+
const path6 = join5(dir, file);
|
|
7605
7459
|
let parsed;
|
|
7606
7460
|
try {
|
|
7607
7461
|
const text = readFileSync4(path6, "utf8");
|
|
@@ -7631,8 +7485,8 @@ var exports_theme = {};
|
|
|
7631
7485
|
__export(exports_theme, {
|
|
7632
7486
|
runThemeSubcommand: () => runThemeSubcommand
|
|
7633
7487
|
});
|
|
7634
|
-
import { existsSync as
|
|
7635
|
-
import { basename as basename3, join as
|
|
7488
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync as readFileSync5, readdirSync as readdirSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
7489
|
+
import { basename as basename3, join as join6, resolve as resolve5 } from "path";
|
|
7636
7490
|
function fail2(message) {
|
|
7637
7491
|
process.stderr.write(`kobe theme: ${message}
|
|
7638
7492
|
`);
|
|
@@ -7663,7 +7517,7 @@ function listThemes() {
|
|
|
7663
7517
|
} else {
|
|
7664
7518
|
for (const f of userFiles) {
|
|
7665
7519
|
const name = f.slice(0, -".json".length);
|
|
7666
|
-
const path6 =
|
|
7520
|
+
const path6 = join6(dir, f);
|
|
7667
7521
|
const overridesBundled = BUNDLED_NAMES.includes(name) ? " (overrides built-in)" : "";
|
|
7668
7522
|
lines.push(` ${name}${overridesBundled} ${path6}`);
|
|
7669
7523
|
}
|
|
@@ -7753,8 +7607,8 @@ async function addTheme(args) {
|
|
|
7753
7607
|
}
|
|
7754
7608
|
const dir = userThemesDir();
|
|
7755
7609
|
mkdirSync3(dir, { recursive: true });
|
|
7756
|
-
const dest =
|
|
7757
|
-
if (
|
|
7610
|
+
const dest = join6(dir, `${name}.json`);
|
|
7611
|
+
if (existsSync3(dest) && !opts.force) {
|
|
7758
7612
|
fail2(`${dest} already exists (pass --force to overwrite)`);
|
|
7759
7613
|
}
|
|
7760
7614
|
writeFileSync2(dest, `${JSON.stringify(result.theme, null, 2)}
|
|
@@ -7771,8 +7625,8 @@ function removeTheme(args) {
|
|
|
7771
7625
|
if (BUNDLED_NAMES.includes(name)) {
|
|
7772
7626
|
fail2(`"${name}" is a built-in theme and cannot be removed`);
|
|
7773
7627
|
}
|
|
7774
|
-
const dest =
|
|
7775
|
-
if (!
|
|
7628
|
+
const dest = join6(userThemesDir(), `${name}.json`);
|
|
7629
|
+
if (!existsSync3(dest)) {
|
|
7776
7630
|
fail2(`no user theme named "${name}" (looked for ${dest})`);
|
|
7777
7631
|
}
|
|
7778
7632
|
unlinkSync(dest);
|
|
@@ -7955,9 +7809,9 @@ var init_daemon_cmd = __esm(() => {
|
|
|
7955
7809
|
});
|
|
7956
7810
|
|
|
7957
7811
|
// src/lib/skill-install.ts
|
|
7958
|
-
import { existsSync as
|
|
7812
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
|
|
7959
7813
|
import { homedir as homedir9 } from "os";
|
|
7960
|
-
import { join as
|
|
7814
|
+
import { join as join7 } from "path";
|
|
7961
7815
|
function npxSkillsArgv(opts = {}) {
|
|
7962
7816
|
return ["skills", "add", SKILL_SOURCE_SLUG, "--skill", "kobe", "--agent", opts.agent ?? DEFAULT_SKILL_AGENT];
|
|
7963
7817
|
}
|
|
@@ -7967,14 +7821,14 @@ function npxSkillsCommand(opts = {}) {
|
|
|
7967
7821
|
function kobeSkillPaths(opts = {}) {
|
|
7968
7822
|
const home = opts.home ?? homedir9();
|
|
7969
7823
|
const cwd = opts.cwd ?? process.cwd();
|
|
7970
|
-
return [
|
|
7824
|
+
return [join7(home, SKILL_REL_PATH), join7(cwd, SKILL_REL_PATH)];
|
|
7971
7825
|
}
|
|
7972
7826
|
function parseSkillVersion(content) {
|
|
7973
7827
|
const m = content.match(/kobe-skill-version:\s*(\d+)/);
|
|
7974
7828
|
return m ? Number.parseInt(m[1], 10) : null;
|
|
7975
7829
|
}
|
|
7976
7830
|
function kobeSkillState(opts) {
|
|
7977
|
-
const path6 = kobeSkillPaths(opts).find((p) =>
|
|
7831
|
+
const path6 = kobeSkillPaths(opts).find((p) => existsSync4(p));
|
|
7978
7832
|
if (!path6) {
|
|
7979
7833
|
return { installed: false, installedVersion: null, currentVersion: KOBE_SKILL_VERSION, stale: false };
|
|
7980
7834
|
}
|
|
@@ -8026,9 +7880,9 @@ __export(exports_maintenance, {
|
|
|
8026
7880
|
runReloadSubcommand: () => runReloadSubcommand,
|
|
8027
7881
|
runDoctorSubcommand: () => runDoctorSubcommand
|
|
8028
7882
|
});
|
|
8029
|
-
import { existsSync as
|
|
7883
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7, statSync } from "fs";
|
|
8030
7884
|
import { unlink as unlink6 } from "fs/promises";
|
|
8031
|
-
import { join as
|
|
7885
|
+
import { join as join8 } from "path";
|
|
8032
7886
|
import { createInterface } from "readline";
|
|
8033
7887
|
function isProcessAlive2(pid) {
|
|
8034
7888
|
try {
|
|
@@ -8125,7 +7979,7 @@ async function runDoctorSubcommand(argv = []) {
|
|
|
8125
7979
|
const socketPath = defaultDaemonSocketPath();
|
|
8126
7980
|
const pidPath = defaultDaemonPidPath();
|
|
8127
7981
|
const logPath = defaultDaemonLogPath();
|
|
8128
|
-
const tasksPath =
|
|
7982
|
+
const tasksPath = join8(kobeStateDir(), "tasks.json");
|
|
8129
7983
|
const statePath2 = kvStatePath();
|
|
8130
7984
|
const out = ["kobe doctor", ` home: ${homeDir()}`, ` socket: ${socketPath}`, ""];
|
|
8131
7985
|
const status = await probeDaemonStatus(socketPath);
|
|
@@ -8153,7 +8007,7 @@ async function runDoctorSubcommand(argv = []) {
|
|
|
8153
8007
|
} else {
|
|
8154
8008
|
out.push("daemon: \u2717 not running (no pidfile)");
|
|
8155
8009
|
}
|
|
8156
|
-
if (
|
|
8010
|
+
if (existsSync5(socketPath))
|
|
8157
8011
|
out.push(` orphan socket file present: ${socketPath}`);
|
|
8158
8012
|
const tail = tailFile(logPath, 8);
|
|
8159
8013
|
if (tail) {
|
|
@@ -8244,7 +8098,7 @@ async function runResetSubcommand(argv) {
|
|
|
8244
8098
|
const yes = argv.includes("--yes") || argv.includes("-y");
|
|
8245
8099
|
const socketPath = defaultDaemonSocketPath();
|
|
8246
8100
|
const pidPath = defaultDaemonPidPath();
|
|
8247
|
-
const tasksPath =
|
|
8101
|
+
const tasksPath = join8(kobeStateDir(), "tasks.json");
|
|
8248
8102
|
const statePath2 = kvStatePath();
|
|
8249
8103
|
console.log("kobe reset will:");
|
|
8250
8104
|
console.log(" \u2022 stop the kobe daemon (graceful \u2192 SIGTERM \u2192 SIGKILL)");
|
|
@@ -8448,14 +8302,153 @@ var init_skill_cmd = __esm(() => {
|
|
|
8448
8302
|
SKILL_VERBS = ["install", "status", "command"];
|
|
8449
8303
|
});
|
|
8450
8304
|
|
|
8305
|
+
// src/engine/claude-code-local/hook-adapter.ts
|
|
8306
|
+
import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
|
|
8307
|
+
import { dirname as dirname6 } from "path";
|
|
8308
|
+
function isObject6(v) {
|
|
8309
|
+
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
8310
|
+
}
|
|
8311
|
+
async function readJsonObject(path6) {
|
|
8312
|
+
try {
|
|
8313
|
+
const parsed = JSON.parse(await readFile6(path6, "utf8"));
|
|
8314
|
+
return isObject6(parsed) ? parsed : {};
|
|
8315
|
+
} catch {
|
|
8316
|
+
return {};
|
|
8317
|
+
}
|
|
8318
|
+
}
|
|
8319
|
+
function isKobeWorktreeSyncGroup(group) {
|
|
8320
|
+
if (!isObject6(group) || !Array.isArray(group.hooks))
|
|
8321
|
+
return false;
|
|
8322
|
+
return group.hooks.some((h) => isObject6(h) && typeof h.command === "string" && h.command.includes(WORKTREE_SYNC_MARKER));
|
|
8323
|
+
}
|
|
8324
|
+
function isKobeActivityGroup(group) {
|
|
8325
|
+
if (!isObject6(group) || !Array.isArray(group.hooks))
|
|
8326
|
+
return false;
|
|
8327
|
+
return group.hooks.some((h) => isObject6(h) && typeof h.command === "string" && ACTIVITY_MARKERS.some((m) => h.command.includes(m)));
|
|
8328
|
+
}
|
|
8329
|
+
function mergeWorktreeSyncHook(current, command) {
|
|
8330
|
+
const { hooks: rawHooks, ...restSettings } = current;
|
|
8331
|
+
const { WorktreeCreate, ...otherHooks } = isObject6(rawHooks) ? rawHooks : {};
|
|
8332
|
+
const prior = Array.isArray(WorktreeCreate) ? WorktreeCreate : [];
|
|
8333
|
+
const kept = prior.filter((g) => !isKobeWorktreeSyncGroup(g));
|
|
8334
|
+
if (command !== null)
|
|
8335
|
+
kept.push({ hooks: [{ type: "command", command }] });
|
|
8336
|
+
const nextHooks = { ...otherHooks };
|
|
8337
|
+
if (kept.length > 0)
|
|
8338
|
+
nextHooks.WorktreeCreate = kept;
|
|
8339
|
+
return Object.keys(nextHooks).length > 0 ? { ...restSettings, hooks: nextHooks } : { ...restSettings };
|
|
8340
|
+
}
|
|
8341
|
+
function buildClaudeHooks(inv = kobeCliInvocation()) {
|
|
8342
|
+
const out = {};
|
|
8343
|
+
for (const { event, matcher, verb } of EVENT_MAP) {
|
|
8344
|
+
const command = shellQuoteArgv([...inv, "hook", verb]);
|
|
8345
|
+
const group = { hooks: [{ type: "command", command }] };
|
|
8346
|
+
if (matcher)
|
|
8347
|
+
group.matcher = matcher;
|
|
8348
|
+
out[event] = [group];
|
|
8349
|
+
}
|
|
8350
|
+
return out;
|
|
8351
|
+
}
|
|
8352
|
+
function mergeActivityHooks(current, install, inv = kobeCliInvocation()) {
|
|
8353
|
+
const { hooks: rawHooks, ...restSettings } = current;
|
|
8354
|
+
const hooks = isObject6(rawHooks) ? { ...rawHooks } : {};
|
|
8355
|
+
const built = install ? buildClaudeHooks(inv) : {};
|
|
8356
|
+
for (const { event } of EVENT_MAP) {
|
|
8357
|
+
const prior = Array.isArray(hooks[event]) ? hooks[event] : [];
|
|
8358
|
+
const kept = prior.filter((g) => !isKobeActivityGroup(g));
|
|
8359
|
+
if (install && Array.isArray(built[event]))
|
|
8360
|
+
kept.push(...built[event]);
|
|
8361
|
+
if (kept.length > 0)
|
|
8362
|
+
hooks[event] = kept;
|
|
8363
|
+
else
|
|
8364
|
+
delete hooks[event];
|
|
8365
|
+
}
|
|
8366
|
+
return Object.keys(hooks).length > 0 ? { ...restSettings, hooks } : { ...restSettings };
|
|
8367
|
+
}
|
|
8368
|
+
|
|
8369
|
+
class ClaudeHookAdapter {
|
|
8370
|
+
vendor = "claude";
|
|
8371
|
+
supportsHooks() {
|
|
8372
|
+
return true;
|
|
8373
|
+
}
|
|
8374
|
+
supportsWorktreeSync() {
|
|
8375
|
+
return true;
|
|
8376
|
+
}
|
|
8377
|
+
async installActivityHooks(settingsFilePath) {
|
|
8378
|
+
await this.editSettings(settingsFilePath, (cur) => mergeActivityHooks(cur, true));
|
|
8379
|
+
}
|
|
8380
|
+
async removeActivityHooks(settingsFilePath) {
|
|
8381
|
+
await this.editSettings(settingsFilePath, (cur) => mergeActivityHooks(cur, false));
|
|
8382
|
+
}
|
|
8383
|
+
async installWorktreeSyncHook(settingsFilePath) {
|
|
8384
|
+
const command = shellQuoteArgv([...kobeCliInvocation(), "hook", "worktree-created"]);
|
|
8385
|
+
await this.editSettings(settingsFilePath, (cur) => mergeWorktreeSyncHook(cur, command));
|
|
8386
|
+
}
|
|
8387
|
+
async removeWorktreeSyncHook(settingsFilePath) {
|
|
8388
|
+
await this.editSettings(settingsFilePath, (cur) => mergeWorktreeSyncHook(cur, null));
|
|
8389
|
+
}
|
|
8390
|
+
async editSettings(settingsFilePath, transform) {
|
|
8391
|
+
try {
|
|
8392
|
+
const current = await readJsonObject(settingsFilePath);
|
|
8393
|
+
const next = transform(current);
|
|
8394
|
+
if (JSON.stringify(next) === JSON.stringify(current))
|
|
8395
|
+
return;
|
|
8396
|
+
await mkdir5(dirname6(settingsFilePath), { recursive: true });
|
|
8397
|
+
await writeFile4(settingsFilePath, `${JSON.stringify(next, null, 2)}
|
|
8398
|
+
`);
|
|
8399
|
+
} catch {}
|
|
8400
|
+
}
|
|
8401
|
+
}
|
|
8402
|
+
var EVENT_MAP, KOBE_HOOK_EVENTS, ACTIVITY_MARKERS, WORKTREE_SYNC_MARKER = "worktree-created";
|
|
8403
|
+
var init_hook_adapter = __esm(() => {
|
|
8404
|
+
init_invocation();
|
|
8405
|
+
EVENT_MAP = [
|
|
8406
|
+
{ event: "SessionStart", verb: "session-start" },
|
|
8407
|
+
{ event: "UserPromptSubmit", verb: "turn-start" },
|
|
8408
|
+
{ event: "Stop", verb: "turn-complete" },
|
|
8409
|
+
{ event: "StopFailure", verb: "turn-failed" },
|
|
8410
|
+
{ event: "Notification", matcher: "permission_prompt", verb: "awaiting-input" },
|
|
8411
|
+
{ event: "SessionEnd", verb: "session-end" }
|
|
8412
|
+
];
|
|
8413
|
+
KOBE_HOOK_EVENTS = EVENT_MAP.map((e) => e.event);
|
|
8414
|
+
ACTIVITY_MARKERS = EVENT_MAP.map((e) => shellQuoteArgv(["hook", e.verb]));
|
|
8415
|
+
});
|
|
8416
|
+
|
|
8417
|
+
// src/engine/hook-adapter.ts
|
|
8418
|
+
function createEngineHookAdapter(vendor) {
|
|
8419
|
+
if (vendor === "claude")
|
|
8420
|
+
return new ClaudeHookAdapter;
|
|
8421
|
+
return new NoopHookAdapter(vendor);
|
|
8422
|
+
}
|
|
8423
|
+
|
|
8424
|
+
class NoopHookAdapter {
|
|
8425
|
+
vendor;
|
|
8426
|
+
constructor(vendor) {
|
|
8427
|
+
this.vendor = vendor;
|
|
8428
|
+
}
|
|
8429
|
+
supportsHooks() {
|
|
8430
|
+
return false;
|
|
8431
|
+
}
|
|
8432
|
+
async installActivityHooks() {}
|
|
8433
|
+
async removeActivityHooks() {}
|
|
8434
|
+
supportsWorktreeSync() {
|
|
8435
|
+
return false;
|
|
8436
|
+
}
|
|
8437
|
+
async installWorktreeSyncHook() {}
|
|
8438
|
+
async removeWorktreeSyncHook() {}
|
|
8439
|
+
}
|
|
8440
|
+
var init_hook_adapter2 = __esm(() => {
|
|
8441
|
+
init_hook_adapter();
|
|
8442
|
+
});
|
|
8443
|
+
|
|
8451
8444
|
// src/cli/hook-cmd.ts
|
|
8452
8445
|
var exports_hook_cmd = {};
|
|
8453
8446
|
__export(exports_hook_cmd, {
|
|
8454
8447
|
runHookSubcommand: () => runHookSubcommand,
|
|
8455
|
-
|
|
8448
|
+
ensureGlobalKobeHooks: () => ensureGlobalKobeHooks
|
|
8456
8449
|
});
|
|
8457
8450
|
import { homedir as homedir10 } from "os";
|
|
8458
|
-
import { dirname as dirname7, join as
|
|
8451
|
+
import { dirname as dirname7, join as join9, resolve as resolve6 } from "path";
|
|
8459
8452
|
async function readStdinPayload() {
|
|
8460
8453
|
try {
|
|
8461
8454
|
const text = await Promise.race([
|
|
@@ -8501,10 +8494,9 @@ async function runHookSubcommand(argv) {
|
|
|
8501
8494
|
}
|
|
8502
8495
|
if (!verb || !isEngineActivityKind(verb))
|
|
8503
8496
|
return;
|
|
8504
|
-
const taskId = flagValue(rest, "--task-id");
|
|
8505
|
-
if (!taskId)
|
|
8506
|
-
return;
|
|
8507
8497
|
const payload = await readStdinPayload();
|
|
8498
|
+
const taskId = flagValue(rest, "--task-id");
|
|
8499
|
+
const cwd = typeof payload.cwd === "string" && payload.cwd ? payload.cwd : process.cwd();
|
|
8508
8500
|
let detail;
|
|
8509
8501
|
if (verb === "turn-failed") {
|
|
8510
8502
|
detail = { failure: failureFromErrorType(payload.error_type) };
|
|
@@ -8515,7 +8507,11 @@ async function runHookSubcommand(argv) {
|
|
|
8515
8507
|
if (!client)
|
|
8516
8508
|
return;
|
|
8517
8509
|
try {
|
|
8518
|
-
await client.request("engine.reportEvent", {
|
|
8510
|
+
await client.request("engine.reportEvent", {
|
|
8511
|
+
...taskId ? { taskId } : { cwd },
|
|
8512
|
+
kind: verb,
|
|
8513
|
+
...detail ? { detail } : {}
|
|
8514
|
+
});
|
|
8519
8515
|
} finally {
|
|
8520
8516
|
client.close();
|
|
8521
8517
|
}
|
|
@@ -8555,12 +8551,18 @@ async function deriveRepoRoot(worktreePath) {
|
|
|
8555
8551
|
}
|
|
8556
8552
|
function syncSettingsPath(scope) {
|
|
8557
8553
|
if (scope.kind === "repo")
|
|
8558
|
-
return
|
|
8559
|
-
return
|
|
8554
|
+
return join9(resolve6(scope.path), ".claude", "settings.json");
|
|
8555
|
+
return globalSettingsPath();
|
|
8560
8556
|
}
|
|
8561
8557
|
function worktreeSyncAdapters() {
|
|
8562
8558
|
return ALL_VENDORS.map((v) => createEngineHookAdapter(v)).filter((a) => a.supportsWorktreeSync());
|
|
8563
8559
|
}
|
|
8560
|
+
function activityHookAdapters() {
|
|
8561
|
+
return ALL_VENDORS.map((v) => createEngineHookAdapter(v)).filter((a) => a.supportsHooks());
|
|
8562
|
+
}
|
|
8563
|
+
function globalSettingsPath() {
|
|
8564
|
+
return join9(homedir10(), ".claude", "settings.json");
|
|
8565
|
+
}
|
|
8564
8566
|
function persistedSyncPath(stored) {
|
|
8565
8567
|
if (!stored || stored === "off")
|
|
8566
8568
|
return;
|
|
@@ -8570,16 +8572,19 @@ function persistedSyncPath(stored) {
|
|
|
8570
8572
|
return syncSettingsPath({ kind: "repo", path: stored.slice(5) });
|
|
8571
8573
|
return stored;
|
|
8572
8574
|
}
|
|
8573
|
-
async function
|
|
8575
|
+
async function ensureGlobalKobeHooks() {
|
|
8574
8576
|
try {
|
|
8577
|
+
const globalPath = globalSettingsPath();
|
|
8578
|
+
for (const a of activityHookAdapters())
|
|
8579
|
+
await a.installActivityHooks(globalPath);
|
|
8575
8580
|
const stored = getPersistedString(SYNC_SETTING_KEY);
|
|
8576
8581
|
if (stored === "off")
|
|
8577
8582
|
return;
|
|
8578
|
-
const
|
|
8579
|
-
if (
|
|
8583
|
+
const syncAdapters = worktreeSyncAdapters();
|
|
8584
|
+
if (syncAdapters.length === 0)
|
|
8580
8585
|
return;
|
|
8581
8586
|
const path6 = persistedSyncPath(stored) ?? syncSettingsPath({ kind: "global" });
|
|
8582
|
-
for (const a of
|
|
8587
|
+
for (const a of syncAdapters)
|
|
8583
8588
|
await a.installWorktreeSyncHook(path6);
|
|
8584
8589
|
if (!stored)
|
|
8585
8590
|
setPersistedString(SYNC_SETTING_KEY, path6);
|
|
@@ -13853,7 +13858,7 @@ var init_rename_task_dialog = __esm(() => {
|
|
|
13853
13858
|
|
|
13854
13859
|
// src/engine/claude-code-local/binary.ts
|
|
13855
13860
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
13856
|
-
import { existsSync as
|
|
13861
|
+
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
13857
13862
|
import { homedir as homedir12 } from "os";
|
|
13858
13863
|
import path7 from "path";
|
|
13859
13864
|
async function findClaudeBinary(deps = defaultDeps4) {
|
|
@@ -13940,7 +13945,7 @@ var init_binary = __esm(() => {
|
|
|
13940
13945
|
return;
|
|
13941
13946
|
if (first.startsWith("claude:") && first.includes("aliased to")) {
|
|
13942
13947
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
13943
|
-
return aliasTarget &&
|
|
13948
|
+
return aliasTarget && existsSync7(aliasTarget) ? aliasTarget : undefined;
|
|
13944
13949
|
}
|
|
13945
13950
|
return first;
|
|
13946
13951
|
},
|
|
@@ -13957,7 +13962,7 @@ var init_binary = __esm(() => {
|
|
|
13957
13962
|
|
|
13958
13963
|
// src/engine/codex-local/binary.ts
|
|
13959
13964
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
13960
|
-
import { existsSync as
|
|
13965
|
+
import { existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
13961
13966
|
import { homedir as homedir13 } from "os";
|
|
13962
13967
|
import path8 from "path";
|
|
13963
13968
|
async function findCodexBinary(deps = defaultDeps5) {
|
|
@@ -14028,7 +14033,7 @@ var init_binary2 = __esm(() => {
|
|
|
14028
14033
|
return;
|
|
14029
14034
|
if (first.startsWith("codex:") && first.includes("aliased to")) {
|
|
14030
14035
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
14031
|
-
return aliasTarget &&
|
|
14036
|
+
return aliasTarget && existsSync8(aliasTarget) ? aliasTarget : undefined;
|
|
14032
14037
|
}
|
|
14033
14038
|
return first;
|
|
14034
14039
|
},
|
|
@@ -14045,7 +14050,7 @@ var init_binary2 = __esm(() => {
|
|
|
14045
14050
|
|
|
14046
14051
|
// src/engine/copilot-local/binary.ts
|
|
14047
14052
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
14048
|
-
import { existsSync as
|
|
14053
|
+
import { existsSync as existsSync9, statSync as statSync5 } from "fs";
|
|
14049
14054
|
import { homedir as homedir14 } from "os";
|
|
14050
14055
|
import path9 from "path";
|
|
14051
14056
|
async function findCopilotBinary(deps = defaultDeps6) {
|
|
@@ -14140,7 +14145,7 @@ var init_binary3 = __esm(() => {
|
|
|
14140
14145
|
return;
|
|
14141
14146
|
if (first.startsWith("copilot:") && first.includes("aliased to")) {
|
|
14142
14147
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
14143
|
-
return aliasTarget &&
|
|
14148
|
+
return aliasTarget && existsSync9(aliasTarget) ? aliasTarget : undefined;
|
|
14144
14149
|
}
|
|
14145
14150
|
return first;
|
|
14146
14151
|
},
|
|
@@ -14529,7 +14534,7 @@ var init_dialog_confirm = __esm(() => {
|
|
|
14529
14534
|
|
|
14530
14535
|
// src/tui/component/settings-dialog/actions.ts
|
|
14531
14536
|
import { unlinkSync as unlinkSync2 } from "fs";
|
|
14532
|
-
import { join as
|
|
14537
|
+
import { join as join11 } from "path";
|
|
14533
14538
|
function hasRestartableDaemon(orchestrator) {
|
|
14534
14539
|
return orchestrator instanceof RemoteOrchestrator;
|
|
14535
14540
|
}
|
|
@@ -14546,7 +14551,7 @@ async function confirmResetState(dialog, kv, renderer) {
|
|
|
14546
14551
|
return;
|
|
14547
14552
|
kv.clear();
|
|
14548
14553
|
try {
|
|
14549
|
-
unlinkSync2(
|
|
14554
|
+
unlinkSync2(join11(homeDir(), ".kobe", "tasks.json"));
|
|
14550
14555
|
} catch (err) {
|
|
14551
14556
|
if (err.code !== "ENOENT") {
|
|
14552
14557
|
console.error("kobe: failed to delete tasks.json during reset:", err);
|
|
@@ -16102,8 +16107,8 @@ var init_persisted_ui_prefs = __esm(() => {
|
|
|
16102
16107
|
|
|
16103
16108
|
// src/tui/lib/worktree-opener.ts
|
|
16104
16109
|
import { spawn as spawn3 } from "child_process";
|
|
16105
|
-
import { existsSync as
|
|
16106
|
-
import { basename as basename4, delimiter, isAbsolute, join as
|
|
16110
|
+
import { existsSync as existsSync10 } from "fs";
|
|
16111
|
+
import { basename as basename4, delimiter, isAbsolute, join as join12 } from "path";
|
|
16107
16112
|
function executableOnPath(command, env, exists) {
|
|
16108
16113
|
if (isAbsolute(command))
|
|
16109
16114
|
return exists(command);
|
|
@@ -16111,7 +16116,7 @@ function executableOnPath(command, env, exists) {
|
|
|
16111
16116
|
for (const dir of pathEnv.split(delimiter)) {
|
|
16112
16117
|
if (!dir)
|
|
16113
16118
|
continue;
|
|
16114
|
-
if (exists(
|
|
16119
|
+
if (exists(join12(dir, command)))
|
|
16115
16120
|
return true;
|
|
16116
16121
|
}
|
|
16117
16122
|
return false;
|
|
@@ -16131,7 +16136,7 @@ function labelForOverride(command) {
|
|
|
16131
16136
|
function detectWorktreeOpener(deps = {}) {
|
|
16132
16137
|
const env = deps.env ?? process.env;
|
|
16133
16138
|
const platform = deps.platform ?? process.platform;
|
|
16134
|
-
const exists = deps.exists ??
|
|
16139
|
+
const exists = deps.exists ?? existsSync10;
|
|
16135
16140
|
const override = env.KOBE_OPEN_EDITOR?.trim();
|
|
16136
16141
|
if (override) {
|
|
16137
16142
|
return { id: "env", label: labelForOverride(override), command: override, args: [] };
|
|
@@ -17101,13 +17106,7 @@ var init_keys = __esm(() => {
|
|
|
17101
17106
|
init_keymap();
|
|
17102
17107
|
});
|
|
17103
17108
|
|
|
17104
|
-
// src/tui/panes/sidebar/
|
|
17105
|
-
import { TextAttributes as TextAttributes9 } from "@opentui/core";
|
|
17106
|
-
function truncateBranchLabel(branch, max = BRANCH_LABEL_MAX) {
|
|
17107
|
-
if (branch.length <= max)
|
|
17108
|
-
return branch;
|
|
17109
|
-
return `${branch.slice(0, Math.max(0, max - 1))}\u2026`;
|
|
17110
|
-
}
|
|
17109
|
+
// src/tui/panes/sidebar/labels.ts
|
|
17111
17110
|
function truncateTitle(title, max) {
|
|
17112
17111
|
if (max <= 0)
|
|
17113
17112
|
return "";
|
|
@@ -17115,6 +17114,17 @@ function truncateTitle(title, max) {
|
|
|
17115
17114
|
return title;
|
|
17116
17115
|
return `${title.slice(0, Math.max(0, max - 1))}\u2026`;
|
|
17117
17116
|
}
|
|
17117
|
+
function spacedTitle(title, max) {
|
|
17118
|
+
return ` ${truncateTitle(title, Math.max(0, max))}`;
|
|
17119
|
+
}
|
|
17120
|
+
|
|
17121
|
+
// src/tui/panes/sidebar/Sidebar.tsx
|
|
17122
|
+
import { TextAttributes as TextAttributes9 } from "@opentui/core";
|
|
17123
|
+
function truncateBranchLabel(branch, max = BRANCH_LABEL_MAX) {
|
|
17124
|
+
if (branch.length <= max)
|
|
17125
|
+
return branch;
|
|
17126
|
+
return `${branch.slice(0, Math.max(0, max - 1))}\u2026`;
|
|
17127
|
+
}
|
|
17118
17128
|
function approxCellWidth(s) {
|
|
17119
17129
|
let n = 0;
|
|
17120
17130
|
for (const ch of s)
|
|
@@ -17560,7 +17570,7 @@ function Sidebar(props) {
|
|
|
17560
17570
|
setProp(_el$32, "flexDirection", "row");
|
|
17561
17571
|
setProp(_el$32, "flexGrow", 1);
|
|
17562
17572
|
setProp(_el$32, "paddingRight", 1);
|
|
17563
|
-
setProp(_el$32, "gap",
|
|
17573
|
+
setProp(_el$32, "gap", 0);
|
|
17564
17574
|
setProp(_el$33, "wrapMode", "none");
|
|
17565
17575
|
insert(_el$33, (() => {
|
|
17566
17576
|
var _c$2 = memo2(() => !!loading());
|
|
@@ -17568,14 +17578,14 @@ function Sidebar(props) {
|
|
|
17568
17578
|
})());
|
|
17569
17579
|
setProp(_el$34, "wrapMode", "none");
|
|
17570
17580
|
setProp(_el$34, "flexGrow", 1);
|
|
17571
|
-
insert(_el$34, () =>
|
|
17581
|
+
insert(_el$34, () => spacedTitle(titleText, titleBudget()));
|
|
17572
17582
|
insert(_el$32, createComponent2(Show, {
|
|
17573
17583
|
get when() {
|
|
17574
17584
|
return loading();
|
|
17575
17585
|
},
|
|
17576
17586
|
get children() {
|
|
17577
17587
|
var _el$35 = createElement("text");
|
|
17578
|
-
insertNode(_el$35, createTextNode(`working`));
|
|
17588
|
+
insertNode(_el$35, createTextNode(` working`));
|
|
17579
17589
|
setProp(_el$35, "wrapMode", "none");
|
|
17580
17590
|
effect((_$p) => setProp(_el$35, "fg", theme.primary, _$p));
|
|
17581
17591
|
return _el$35;
|
|
@@ -17588,7 +17598,7 @@ function Sidebar(props) {
|
|
|
17588
17598
|
get children() {
|
|
17589
17599
|
var _el$37 = createElement("text");
|
|
17590
17600
|
setProp(_el$37, "wrapMode", "none");
|
|
17591
|
-
insert(_el$37, () => truncatePathTail(abbrevHome(task.repo), subtitleBudget()));
|
|
17601
|
+
insert(_el$37, () => ` ${truncatePathTail(abbrevHome(task.repo), subtitleBudget())}`);
|
|
17592
17602
|
effect((_p$) => {
|
|
17593
17603
|
var _v$15 = theme.textMuted, _v$16 = TextAttributes9.DIM;
|
|
17594
17604
|
_v$15 !== _p$.e && (_p$.e = setProp(_el$37, "fg", _v$15, _p$.e));
|
|
@@ -17635,7 +17645,7 @@ function Sidebar(props) {
|
|
|
17635
17645
|
setProp(_el$40, "flexDirection", "row");
|
|
17636
17646
|
setProp(_el$40, "flexGrow", 1);
|
|
17637
17647
|
setProp(_el$40, "paddingRight", 1);
|
|
17638
|
-
setProp(_el$40, "gap",
|
|
17648
|
+
setProp(_el$40, "gap", 0);
|
|
17639
17649
|
setProp(_el$41, "wrapMode", "none");
|
|
17640
17650
|
insert(_el$41, (() => {
|
|
17641
17651
|
var _c$3 = memo2(() => !!loading());
|
|
@@ -17643,14 +17653,14 @@ function Sidebar(props) {
|
|
|
17643
17653
|
})());
|
|
17644
17654
|
setProp(_el$42, "wrapMode", "none");
|
|
17645
17655
|
setProp(_el$42, "flexGrow", 1);
|
|
17646
|
-
insert(_el$42, () =>
|
|
17656
|
+
insert(_el$42, () => spacedTitle(titleText, titleBudget()));
|
|
17647
17657
|
insert(_el$40, createComponent2(Show, {
|
|
17648
17658
|
get when() {
|
|
17649
17659
|
return loading();
|
|
17650
17660
|
},
|
|
17651
17661
|
get children() {
|
|
17652
17662
|
var _el$43 = createElement("text");
|
|
17653
|
-
insertNode(_el$43, createTextNode(`working`));
|
|
17663
|
+
insertNode(_el$43, createTextNode(` working`));
|
|
17654
17664
|
setProp(_el$43, "wrapMode", "none");
|
|
17655
17665
|
effect((_$p) => setProp(_el$43, "fg", theme.primary, _$p));
|
|
17656
17666
|
return _el$43;
|
|
@@ -17663,7 +17673,7 @@ function Sidebar(props) {
|
|
|
17663
17673
|
children: (chip) => (() => {
|
|
17664
17674
|
var _el$55 = createElement("text");
|
|
17665
17675
|
setProp(_el$55, "wrapMode", "none");
|
|
17666
|
-
insert(_el$55, () => chip().text);
|
|
17676
|
+
insert(_el$55, () => ` ${chip().text}`);
|
|
17667
17677
|
effect((_$p) => setProp(_el$55, "fg", chip().tone === "error" ? theme.error : chip().tone === "warning" ? theme.warning : theme.primary, _$p));
|
|
17668
17678
|
return _el$55;
|
|
17669
17679
|
})()
|
|
@@ -17944,7 +17954,7 @@ var exports_host = {};
|
|
|
17944
17954
|
__export(exports_host, {
|
|
17945
17955
|
startTasksPane: () => startTasksPane
|
|
17946
17956
|
});
|
|
17947
|
-
import { existsSync as
|
|
17957
|
+
import { existsSync as existsSync11 } from "fs";
|
|
17948
17958
|
import { TextAttributes as TextAttributes10 } from "@opentui/core";
|
|
17949
17959
|
function TasksShell(props) {
|
|
17950
17960
|
const themeCtx = useTheme();
|
|
@@ -18179,7 +18189,7 @@ function TasksShell(props) {
|
|
|
18179
18189
|
async function openSelectedWorktree(id) {
|
|
18180
18190
|
const task = props.tasks().find((t) => t.id === id);
|
|
18181
18191
|
let worktree = task?.worktreePath;
|
|
18182
|
-
if (!worktree || !
|
|
18192
|
+
if (!worktree || !existsSync11(worktree)) {
|
|
18183
18193
|
if (!props.orch) {
|
|
18184
18194
|
console.error("[kobe tasks] no daemon; cannot materialise worktree");
|
|
18185
18195
|
return;
|
|
@@ -18192,7 +18202,7 @@ function TasksShell(props) {
|
|
|
18192
18202
|
}
|
|
18193
18203
|
await props.reload();
|
|
18194
18204
|
}
|
|
18195
|
-
if (!worktree || !
|
|
18205
|
+
if (!worktree || !existsSync11(worktree))
|
|
18196
18206
|
return;
|
|
18197
18207
|
const opener = detectWorktreeOpener();
|
|
18198
18208
|
if (!opener) {
|
|
@@ -18243,7 +18253,7 @@ function TasksShell(props) {
|
|
|
18243
18253
|
const exists = await sessionExists(name);
|
|
18244
18254
|
if (exists) {
|
|
18245
18255
|
const cwd2 = await getSessionOption(name, "@kobe_worktree") || task?.worktreePath || "";
|
|
18246
|
-
if (cwd2 &&
|
|
18256
|
+
if (cwd2 && existsSync11(cwd2)) {
|
|
18247
18257
|
await ensureSession({
|
|
18248
18258
|
name,
|
|
18249
18259
|
cwd: cwd2,
|
|
@@ -18257,7 +18267,7 @@ function TasksShell(props) {
|
|
|
18257
18267
|
return;
|
|
18258
18268
|
}
|
|
18259
18269
|
let cwd = task?.worktreePath;
|
|
18260
|
-
if (!cwd || !
|
|
18270
|
+
if (!cwd || !existsSync11(cwd)) {
|
|
18261
18271
|
if (!props.orch) {
|
|
18262
18272
|
console.error("[kobe tasks] no daemon; cannot materialise worktree");
|
|
18263
18273
|
return;
|
|
@@ -18270,7 +18280,7 @@ function TasksShell(props) {
|
|
|
18270
18280
|
}
|
|
18271
18281
|
await props.reload();
|
|
18272
18282
|
}
|
|
18273
|
-
if (!cwd || !
|
|
18283
|
+
if (!cwd || !existsSync11(cwd))
|
|
18274
18284
|
return;
|
|
18275
18285
|
const init2 = task?.repo ? resolveRepoInit(task.repo, cwd) : {};
|
|
18276
18286
|
const ready = await ensureSession({
|
|
@@ -19721,14 +19731,14 @@ var init_keys2 = __esm(() => {
|
|
|
19721
19731
|
|
|
19722
19732
|
// src/tui/panes/filetree/open-external.ts
|
|
19723
19733
|
import { spawn as spawn5 } from "child_process";
|
|
19724
|
-
import { existsSync as
|
|
19734
|
+
import { existsSync as existsSync12 } from "fs";
|
|
19725
19735
|
import { platform } from "os";
|
|
19726
19736
|
function openExternally(absPath) {
|
|
19727
19737
|
if (!absPath)
|
|
19728
19738
|
return;
|
|
19729
19739
|
const plat = platform();
|
|
19730
19740
|
if (plat === "linux") {
|
|
19731
|
-
if (
|
|
19741
|
+
if (existsSync12("/proc/sys/fs/binfmt_misc/WSLInterop") || process.env.WSL_DISTRO_NAME) {
|
|
19732
19742
|
spawnDetached("wslview", [absPath], () => {
|
|
19733
19743
|
const child = spawn5("wslpath", ["-w", absPath], { stdio: ["ignore", "pipe", "ignore"] });
|
|
19734
19744
|
let out = "";
|
|
@@ -21169,7 +21179,7 @@ async function ensureRepos(orchestrator) {
|
|
|
21169
21179
|
}
|
|
21170
21180
|
async function startDirectTmux() {
|
|
21171
21181
|
setClientLogContext("gui");
|
|
21172
|
-
Promise.resolve().then(() => (init_hook_cmd(), exports_hook_cmd)).then((m) => m.
|
|
21182
|
+
Promise.resolve().then(() => (init_hook_cmd(), exports_hook_cmd)).then((m) => m.ensureGlobalKobeHooks());
|
|
21173
21183
|
if (!await tmuxAvailable()) {
|
|
21174
21184
|
console.error("kobe: tmux not found on PATH \u2014 install tmux to use kobe 0.6 direct mode");
|
|
21175
21185
|
process.exitCode = 1;
|
|
@@ -21763,9 +21773,9 @@ var pulse_default = "../pulse-n3cq1btw.wav";
|
|
|
21763
21773
|
var init_pulse = () => {};
|
|
21764
21774
|
|
|
21765
21775
|
// src/tui/lib/sound.ts
|
|
21766
|
-
import { existsSync as
|
|
21776
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync5 } from "fs";
|
|
21767
21777
|
import { tmpdir as tmpdir2 } from "os";
|
|
21768
|
-
import { basename as basename6, isAbsolute as isAbsolute2, join as
|
|
21778
|
+
import { basename as basename6, isAbsolute as isAbsolute2, join as join13, resolve as resolve8 } from "path";
|
|
21769
21779
|
function args(player, file, volume) {
|
|
21770
21780
|
if (player === "ffplay")
|
|
21771
21781
|
return [player, "-autoexit", "-nodisp", "-af", `volume=${volume}`, file];
|
|
@@ -21788,13 +21798,13 @@ function pickPlayer() {
|
|
|
21788
21798
|
return cachedPlayer;
|
|
21789
21799
|
const path12 = process.env.PATH ?? "";
|
|
21790
21800
|
const segments = path12.split(":").filter(Boolean);
|
|
21791
|
-
cachedPlayer = PLAYERS.find((p) => segments.some((dir) =>
|
|
21801
|
+
cachedPlayer = PLAYERS.find((p) => segments.some((dir) => existsSync13(join13(dir, p)))) ?? null;
|
|
21792
21802
|
return cachedPlayer;
|
|
21793
21803
|
}
|
|
21794
21804
|
async function ensureAsset() {
|
|
21795
21805
|
cachedPath ??= (async () => {
|
|
21796
21806
|
mkdirSync5(DIR, { recursive: true });
|
|
21797
|
-
const dest =
|
|
21807
|
+
const dest = join13(DIR, basename6(pulseAsset));
|
|
21798
21808
|
const out = Bun.file(dest);
|
|
21799
21809
|
if (await out.exists())
|
|
21800
21810
|
return dest;
|
|
@@ -21824,7 +21834,7 @@ var pulseAsset, DIR, PLAYERS, cachedPlayer, cachedPath;
|
|
|
21824
21834
|
var init_sound = __esm(() => {
|
|
21825
21835
|
init_pulse();
|
|
21826
21836
|
pulseAsset = isAbsolute2(pulse_default) ? pulse_default : resolve8(import.meta.dir, pulse_default);
|
|
21827
|
-
DIR =
|
|
21837
|
+
DIR = join13(tmpdir2(), "kobe-sfx");
|
|
21828
21838
|
PLAYERS = [
|
|
21829
21839
|
"ffplay",
|
|
21830
21840
|
"mpv",
|
package/package.json
CHANGED