@sma1lboy/kobe 0.7.8 → 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 +244 -240
- 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 && opts.cwd.includes(`/${KOBE_WORKTREE_ROOT_SUBPATH}/`)) {
|
|
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,10 +6354,8 @@ 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
|
-
init_paths();
|
|
6506
6359
|
init_client2();
|
|
6507
6360
|
init_prompt_delivery();
|
|
6508
6361
|
init_vendor();
|
|
@@ -6545,14 +6398,14 @@ var exports_repo_init = {};
|
|
|
6545
6398
|
__export(exports_repo_init, {
|
|
6546
6399
|
resolveRepoInit: () => resolveRepoInit
|
|
6547
6400
|
});
|
|
6548
|
-
import { existsSync as
|
|
6549
|
-
import { join as
|
|
6401
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
6402
|
+
import { join as join4 } from "path";
|
|
6550
6403
|
function repoFileScript(worktreePath) {
|
|
6551
|
-
return
|
|
6404
|
+
return existsSync2(join4(worktreePath, INIT_SCRIPT_REL)) ? `sh ${INIT_SCRIPT_REL}` : undefined;
|
|
6552
6405
|
}
|
|
6553
6406
|
function repoFilePrompt(worktreePath) {
|
|
6554
|
-
const p =
|
|
6555
|
-
if (!
|
|
6407
|
+
const p = join4(worktreePath, INIT_PROMPT_REL);
|
|
6408
|
+
if (!existsSync2(p))
|
|
6556
6409
|
return;
|
|
6557
6410
|
try {
|
|
6558
6411
|
const text = readFileSync3(p, "utf8");
|
|
@@ -6573,8 +6426,8 @@ function resolveRepoInit(repoRoot, worktreePath) {
|
|
|
6573
6426
|
var INIT_SCRIPT_REL, INIT_PROMPT_REL;
|
|
6574
6427
|
var init_repo_init = __esm(() => {
|
|
6575
6428
|
init_repos();
|
|
6576
|
-
INIT_SCRIPT_REL =
|
|
6577
|
-
INIT_PROMPT_REL =
|
|
6429
|
+
INIT_SCRIPT_REL = join4(".kobe", "init.sh");
|
|
6430
|
+
INIT_PROMPT_REL = join4(".kobe", "init-prompt.md");
|
|
6578
6431
|
});
|
|
6579
6432
|
|
|
6580
6433
|
// src/tui/panes/sidebar/worktree-changes.ts
|
|
@@ -7586,9 +7439,9 @@ var init_schema = () => {};
|
|
|
7586
7439
|
|
|
7587
7440
|
// src/tui/context/theme/loader.ts
|
|
7588
7441
|
import { readFileSync as readFileSync4, readdirSync } from "fs";
|
|
7589
|
-
import { join as
|
|
7442
|
+
import { join as join5 } from "path";
|
|
7590
7443
|
function userThemesDir() {
|
|
7591
|
-
return
|
|
7444
|
+
return join5(kobeStateDir(), "themes");
|
|
7592
7445
|
}
|
|
7593
7446
|
function loadUserThemes() {
|
|
7594
7447
|
const dir = userThemesDir();
|
|
@@ -7602,7 +7455,7 @@ function loadUserThemes() {
|
|
|
7602
7455
|
for (const file of entries) {
|
|
7603
7456
|
if (!file.endsWith(".json"))
|
|
7604
7457
|
continue;
|
|
7605
|
-
const path6 =
|
|
7458
|
+
const path6 = join5(dir, file);
|
|
7606
7459
|
let parsed;
|
|
7607
7460
|
try {
|
|
7608
7461
|
const text = readFileSync4(path6, "utf8");
|
|
@@ -7632,8 +7485,8 @@ var exports_theme = {};
|
|
|
7632
7485
|
__export(exports_theme, {
|
|
7633
7486
|
runThemeSubcommand: () => runThemeSubcommand
|
|
7634
7487
|
});
|
|
7635
|
-
import { existsSync as
|
|
7636
|
-
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";
|
|
7637
7490
|
function fail2(message) {
|
|
7638
7491
|
process.stderr.write(`kobe theme: ${message}
|
|
7639
7492
|
`);
|
|
@@ -7664,7 +7517,7 @@ function listThemes() {
|
|
|
7664
7517
|
} else {
|
|
7665
7518
|
for (const f of userFiles) {
|
|
7666
7519
|
const name = f.slice(0, -".json".length);
|
|
7667
|
-
const path6 =
|
|
7520
|
+
const path6 = join6(dir, f);
|
|
7668
7521
|
const overridesBundled = BUNDLED_NAMES.includes(name) ? " (overrides built-in)" : "";
|
|
7669
7522
|
lines.push(` ${name}${overridesBundled} ${path6}`);
|
|
7670
7523
|
}
|
|
@@ -7754,8 +7607,8 @@ async function addTheme(args) {
|
|
|
7754
7607
|
}
|
|
7755
7608
|
const dir = userThemesDir();
|
|
7756
7609
|
mkdirSync3(dir, { recursive: true });
|
|
7757
|
-
const dest =
|
|
7758
|
-
if (
|
|
7610
|
+
const dest = join6(dir, `${name}.json`);
|
|
7611
|
+
if (existsSync3(dest) && !opts.force) {
|
|
7759
7612
|
fail2(`${dest} already exists (pass --force to overwrite)`);
|
|
7760
7613
|
}
|
|
7761
7614
|
writeFileSync2(dest, `${JSON.stringify(result.theme, null, 2)}
|
|
@@ -7772,8 +7625,8 @@ function removeTheme(args) {
|
|
|
7772
7625
|
if (BUNDLED_NAMES.includes(name)) {
|
|
7773
7626
|
fail2(`"${name}" is a built-in theme and cannot be removed`);
|
|
7774
7627
|
}
|
|
7775
|
-
const dest =
|
|
7776
|
-
if (!
|
|
7628
|
+
const dest = join6(userThemesDir(), `${name}.json`);
|
|
7629
|
+
if (!existsSync3(dest)) {
|
|
7777
7630
|
fail2(`no user theme named "${name}" (looked for ${dest})`);
|
|
7778
7631
|
}
|
|
7779
7632
|
unlinkSync(dest);
|
|
@@ -7956,9 +7809,9 @@ var init_daemon_cmd = __esm(() => {
|
|
|
7956
7809
|
});
|
|
7957
7810
|
|
|
7958
7811
|
// src/lib/skill-install.ts
|
|
7959
|
-
import { existsSync as
|
|
7812
|
+
import { existsSync as existsSync4, readFileSync as readFileSync6 } from "fs";
|
|
7960
7813
|
import { homedir as homedir9 } from "os";
|
|
7961
|
-
import { join as
|
|
7814
|
+
import { join as join7 } from "path";
|
|
7962
7815
|
function npxSkillsArgv(opts = {}) {
|
|
7963
7816
|
return ["skills", "add", SKILL_SOURCE_SLUG, "--skill", "kobe", "--agent", opts.agent ?? DEFAULT_SKILL_AGENT];
|
|
7964
7817
|
}
|
|
@@ -7968,14 +7821,14 @@ function npxSkillsCommand(opts = {}) {
|
|
|
7968
7821
|
function kobeSkillPaths(opts = {}) {
|
|
7969
7822
|
const home = opts.home ?? homedir9();
|
|
7970
7823
|
const cwd = opts.cwd ?? process.cwd();
|
|
7971
|
-
return [
|
|
7824
|
+
return [join7(home, SKILL_REL_PATH), join7(cwd, SKILL_REL_PATH)];
|
|
7972
7825
|
}
|
|
7973
7826
|
function parseSkillVersion(content) {
|
|
7974
7827
|
const m = content.match(/kobe-skill-version:\s*(\d+)/);
|
|
7975
7828
|
return m ? Number.parseInt(m[1], 10) : null;
|
|
7976
7829
|
}
|
|
7977
7830
|
function kobeSkillState(opts) {
|
|
7978
|
-
const path6 = kobeSkillPaths(opts).find((p) =>
|
|
7831
|
+
const path6 = kobeSkillPaths(opts).find((p) => existsSync4(p));
|
|
7979
7832
|
if (!path6) {
|
|
7980
7833
|
return { installed: false, installedVersion: null, currentVersion: KOBE_SKILL_VERSION, stale: false };
|
|
7981
7834
|
}
|
|
@@ -8027,9 +7880,9 @@ __export(exports_maintenance, {
|
|
|
8027
7880
|
runReloadSubcommand: () => runReloadSubcommand,
|
|
8028
7881
|
runDoctorSubcommand: () => runDoctorSubcommand
|
|
8029
7882
|
});
|
|
8030
|
-
import { existsSync as
|
|
7883
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7, statSync } from "fs";
|
|
8031
7884
|
import { unlink as unlink6 } from "fs/promises";
|
|
8032
|
-
import { join as
|
|
7885
|
+
import { join as join8 } from "path";
|
|
8033
7886
|
import { createInterface } from "readline";
|
|
8034
7887
|
function isProcessAlive2(pid) {
|
|
8035
7888
|
try {
|
|
@@ -8126,7 +7979,7 @@ async function runDoctorSubcommand(argv = []) {
|
|
|
8126
7979
|
const socketPath = defaultDaemonSocketPath();
|
|
8127
7980
|
const pidPath = defaultDaemonPidPath();
|
|
8128
7981
|
const logPath = defaultDaemonLogPath();
|
|
8129
|
-
const tasksPath =
|
|
7982
|
+
const tasksPath = join8(kobeStateDir(), "tasks.json");
|
|
8130
7983
|
const statePath2 = kvStatePath();
|
|
8131
7984
|
const out = ["kobe doctor", ` home: ${homeDir()}`, ` socket: ${socketPath}`, ""];
|
|
8132
7985
|
const status = await probeDaemonStatus(socketPath);
|
|
@@ -8154,7 +8007,7 @@ async function runDoctorSubcommand(argv = []) {
|
|
|
8154
8007
|
} else {
|
|
8155
8008
|
out.push("daemon: \u2717 not running (no pidfile)");
|
|
8156
8009
|
}
|
|
8157
|
-
if (
|
|
8010
|
+
if (existsSync5(socketPath))
|
|
8158
8011
|
out.push(` orphan socket file present: ${socketPath}`);
|
|
8159
8012
|
const tail = tailFile(logPath, 8);
|
|
8160
8013
|
if (tail) {
|
|
@@ -8245,7 +8098,7 @@ async function runResetSubcommand(argv) {
|
|
|
8245
8098
|
const yes = argv.includes("--yes") || argv.includes("-y");
|
|
8246
8099
|
const socketPath = defaultDaemonSocketPath();
|
|
8247
8100
|
const pidPath = defaultDaemonPidPath();
|
|
8248
|
-
const tasksPath =
|
|
8101
|
+
const tasksPath = join8(kobeStateDir(), "tasks.json");
|
|
8249
8102
|
const statePath2 = kvStatePath();
|
|
8250
8103
|
console.log("kobe reset will:");
|
|
8251
8104
|
console.log(" \u2022 stop the kobe daemon (graceful \u2192 SIGTERM \u2192 SIGKILL)");
|
|
@@ -8449,14 +8302,153 @@ var init_skill_cmd = __esm(() => {
|
|
|
8449
8302
|
SKILL_VERBS = ["install", "status", "command"];
|
|
8450
8303
|
});
|
|
8451
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
|
+
|
|
8452
8444
|
// src/cli/hook-cmd.ts
|
|
8453
8445
|
var exports_hook_cmd = {};
|
|
8454
8446
|
__export(exports_hook_cmd, {
|
|
8455
8447
|
runHookSubcommand: () => runHookSubcommand,
|
|
8456
|
-
|
|
8448
|
+
ensureGlobalKobeHooks: () => ensureGlobalKobeHooks
|
|
8457
8449
|
});
|
|
8458
8450
|
import { homedir as homedir10 } from "os";
|
|
8459
|
-
import { dirname as dirname7, join as
|
|
8451
|
+
import { dirname as dirname7, join as join9, resolve as resolve6 } from "path";
|
|
8460
8452
|
async function readStdinPayload() {
|
|
8461
8453
|
try {
|
|
8462
8454
|
const text = await Promise.race([
|
|
@@ -8502,10 +8494,9 @@ async function runHookSubcommand(argv) {
|
|
|
8502
8494
|
}
|
|
8503
8495
|
if (!verb || !isEngineActivityKind(verb))
|
|
8504
8496
|
return;
|
|
8505
|
-
const taskId = flagValue(rest, "--task-id");
|
|
8506
|
-
if (!taskId)
|
|
8507
|
-
return;
|
|
8508
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();
|
|
8509
8500
|
let detail;
|
|
8510
8501
|
if (verb === "turn-failed") {
|
|
8511
8502
|
detail = { failure: failureFromErrorType(payload.error_type) };
|
|
@@ -8516,7 +8507,11 @@ async function runHookSubcommand(argv) {
|
|
|
8516
8507
|
if (!client)
|
|
8517
8508
|
return;
|
|
8518
8509
|
try {
|
|
8519
|
-
await client.request("engine.reportEvent", {
|
|
8510
|
+
await client.request("engine.reportEvent", {
|
|
8511
|
+
...taskId ? { taskId } : { cwd },
|
|
8512
|
+
kind: verb,
|
|
8513
|
+
...detail ? { detail } : {}
|
|
8514
|
+
});
|
|
8520
8515
|
} finally {
|
|
8521
8516
|
client.close();
|
|
8522
8517
|
}
|
|
@@ -8556,12 +8551,18 @@ async function deriveRepoRoot(worktreePath) {
|
|
|
8556
8551
|
}
|
|
8557
8552
|
function syncSettingsPath(scope) {
|
|
8558
8553
|
if (scope.kind === "repo")
|
|
8559
|
-
return
|
|
8560
|
-
return
|
|
8554
|
+
return join9(resolve6(scope.path), ".claude", "settings.json");
|
|
8555
|
+
return globalSettingsPath();
|
|
8561
8556
|
}
|
|
8562
8557
|
function worktreeSyncAdapters() {
|
|
8563
8558
|
return ALL_VENDORS.map((v) => createEngineHookAdapter(v)).filter((a) => a.supportsWorktreeSync());
|
|
8564
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
|
+
}
|
|
8565
8566
|
function persistedSyncPath(stored) {
|
|
8566
8567
|
if (!stored || stored === "off")
|
|
8567
8568
|
return;
|
|
@@ -8571,16 +8572,19 @@ function persistedSyncPath(stored) {
|
|
|
8571
8572
|
return syncSettingsPath({ kind: "repo", path: stored.slice(5) });
|
|
8572
8573
|
return stored;
|
|
8573
8574
|
}
|
|
8574
|
-
async function
|
|
8575
|
+
async function ensureGlobalKobeHooks() {
|
|
8575
8576
|
try {
|
|
8577
|
+
const globalPath = globalSettingsPath();
|
|
8578
|
+
for (const a of activityHookAdapters())
|
|
8579
|
+
await a.installActivityHooks(globalPath);
|
|
8576
8580
|
const stored = getPersistedString(SYNC_SETTING_KEY);
|
|
8577
8581
|
if (stored === "off")
|
|
8578
8582
|
return;
|
|
8579
|
-
const
|
|
8580
|
-
if (
|
|
8583
|
+
const syncAdapters = worktreeSyncAdapters();
|
|
8584
|
+
if (syncAdapters.length === 0)
|
|
8581
8585
|
return;
|
|
8582
8586
|
const path6 = persistedSyncPath(stored) ?? syncSettingsPath({ kind: "global" });
|
|
8583
|
-
for (const a of
|
|
8587
|
+
for (const a of syncAdapters)
|
|
8584
8588
|
await a.installWorktreeSyncHook(path6);
|
|
8585
8589
|
if (!stored)
|
|
8586
8590
|
setPersistedString(SYNC_SETTING_KEY, path6);
|
|
@@ -13854,7 +13858,7 @@ var init_rename_task_dialog = __esm(() => {
|
|
|
13854
13858
|
|
|
13855
13859
|
// src/engine/claude-code-local/binary.ts
|
|
13856
13860
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
13857
|
-
import { existsSync as
|
|
13861
|
+
import { existsSync as existsSync7, statSync as statSync3 } from "fs";
|
|
13858
13862
|
import { homedir as homedir12 } from "os";
|
|
13859
13863
|
import path7 from "path";
|
|
13860
13864
|
async function findClaudeBinary(deps = defaultDeps4) {
|
|
@@ -13941,7 +13945,7 @@ var init_binary = __esm(() => {
|
|
|
13941
13945
|
return;
|
|
13942
13946
|
if (first.startsWith("claude:") && first.includes("aliased to")) {
|
|
13943
13947
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
13944
|
-
return aliasTarget &&
|
|
13948
|
+
return aliasTarget && existsSync7(aliasTarget) ? aliasTarget : undefined;
|
|
13945
13949
|
}
|
|
13946
13950
|
return first;
|
|
13947
13951
|
},
|
|
@@ -13958,7 +13962,7 @@ var init_binary = __esm(() => {
|
|
|
13958
13962
|
|
|
13959
13963
|
// src/engine/codex-local/binary.ts
|
|
13960
13964
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
13961
|
-
import { existsSync as
|
|
13965
|
+
import { existsSync as existsSync8, statSync as statSync4 } from "fs";
|
|
13962
13966
|
import { homedir as homedir13 } from "os";
|
|
13963
13967
|
import path8 from "path";
|
|
13964
13968
|
async function findCodexBinary(deps = defaultDeps5) {
|
|
@@ -14029,7 +14033,7 @@ var init_binary2 = __esm(() => {
|
|
|
14029
14033
|
return;
|
|
14030
14034
|
if (first.startsWith("codex:") && first.includes("aliased to")) {
|
|
14031
14035
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
14032
|
-
return aliasTarget &&
|
|
14036
|
+
return aliasTarget && existsSync8(aliasTarget) ? aliasTarget : undefined;
|
|
14033
14037
|
}
|
|
14034
14038
|
return first;
|
|
14035
14039
|
},
|
|
@@ -14046,7 +14050,7 @@ var init_binary2 = __esm(() => {
|
|
|
14046
14050
|
|
|
14047
14051
|
// src/engine/copilot-local/binary.ts
|
|
14048
14052
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
14049
|
-
import { existsSync as
|
|
14053
|
+
import { existsSync as existsSync9, statSync as statSync5 } from "fs";
|
|
14050
14054
|
import { homedir as homedir14 } from "os";
|
|
14051
14055
|
import path9 from "path";
|
|
14052
14056
|
async function findCopilotBinary(deps = defaultDeps6) {
|
|
@@ -14141,7 +14145,7 @@ var init_binary3 = __esm(() => {
|
|
|
14141
14145
|
return;
|
|
14142
14146
|
if (first.startsWith("copilot:") && first.includes("aliased to")) {
|
|
14143
14147
|
const aliasTarget = first.split("aliased to")[1]?.trim();
|
|
14144
|
-
return aliasTarget &&
|
|
14148
|
+
return aliasTarget && existsSync9(aliasTarget) ? aliasTarget : undefined;
|
|
14145
14149
|
}
|
|
14146
14150
|
return first;
|
|
14147
14151
|
},
|
|
@@ -14530,7 +14534,7 @@ var init_dialog_confirm = __esm(() => {
|
|
|
14530
14534
|
|
|
14531
14535
|
// src/tui/component/settings-dialog/actions.ts
|
|
14532
14536
|
import { unlinkSync as unlinkSync2 } from "fs";
|
|
14533
|
-
import { join as
|
|
14537
|
+
import { join as join11 } from "path";
|
|
14534
14538
|
function hasRestartableDaemon(orchestrator) {
|
|
14535
14539
|
return orchestrator instanceof RemoteOrchestrator;
|
|
14536
14540
|
}
|
|
@@ -14547,7 +14551,7 @@ async function confirmResetState(dialog, kv, renderer) {
|
|
|
14547
14551
|
return;
|
|
14548
14552
|
kv.clear();
|
|
14549
14553
|
try {
|
|
14550
|
-
unlinkSync2(
|
|
14554
|
+
unlinkSync2(join11(homeDir(), ".kobe", "tasks.json"));
|
|
14551
14555
|
} catch (err) {
|
|
14552
14556
|
if (err.code !== "ENOENT") {
|
|
14553
14557
|
console.error("kobe: failed to delete tasks.json during reset:", err);
|
|
@@ -16103,8 +16107,8 @@ var init_persisted_ui_prefs = __esm(() => {
|
|
|
16103
16107
|
|
|
16104
16108
|
// src/tui/lib/worktree-opener.ts
|
|
16105
16109
|
import { spawn as spawn3 } from "child_process";
|
|
16106
|
-
import { existsSync as
|
|
16107
|
-
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";
|
|
16108
16112
|
function executableOnPath(command, env, exists) {
|
|
16109
16113
|
if (isAbsolute(command))
|
|
16110
16114
|
return exists(command);
|
|
@@ -16112,7 +16116,7 @@ function executableOnPath(command, env, exists) {
|
|
|
16112
16116
|
for (const dir of pathEnv.split(delimiter)) {
|
|
16113
16117
|
if (!dir)
|
|
16114
16118
|
continue;
|
|
16115
|
-
if (exists(
|
|
16119
|
+
if (exists(join12(dir, command)))
|
|
16116
16120
|
return true;
|
|
16117
16121
|
}
|
|
16118
16122
|
return false;
|
|
@@ -16132,7 +16136,7 @@ function labelForOverride(command) {
|
|
|
16132
16136
|
function detectWorktreeOpener(deps = {}) {
|
|
16133
16137
|
const env = deps.env ?? process.env;
|
|
16134
16138
|
const platform = deps.platform ?? process.platform;
|
|
16135
|
-
const exists = deps.exists ??
|
|
16139
|
+
const exists = deps.exists ?? existsSync10;
|
|
16136
16140
|
const override = env.KOBE_OPEN_EDITOR?.trim();
|
|
16137
16141
|
if (override) {
|
|
16138
16142
|
return { id: "env", label: labelForOverride(override), command: override, args: [] };
|
|
@@ -17950,7 +17954,7 @@ var exports_host = {};
|
|
|
17950
17954
|
__export(exports_host, {
|
|
17951
17955
|
startTasksPane: () => startTasksPane
|
|
17952
17956
|
});
|
|
17953
|
-
import { existsSync as
|
|
17957
|
+
import { existsSync as existsSync11 } from "fs";
|
|
17954
17958
|
import { TextAttributes as TextAttributes10 } from "@opentui/core";
|
|
17955
17959
|
function TasksShell(props) {
|
|
17956
17960
|
const themeCtx = useTheme();
|
|
@@ -18185,7 +18189,7 @@ function TasksShell(props) {
|
|
|
18185
18189
|
async function openSelectedWorktree(id) {
|
|
18186
18190
|
const task = props.tasks().find((t) => t.id === id);
|
|
18187
18191
|
let worktree = task?.worktreePath;
|
|
18188
|
-
if (!worktree || !
|
|
18192
|
+
if (!worktree || !existsSync11(worktree)) {
|
|
18189
18193
|
if (!props.orch) {
|
|
18190
18194
|
console.error("[kobe tasks] no daemon; cannot materialise worktree");
|
|
18191
18195
|
return;
|
|
@@ -18198,7 +18202,7 @@ function TasksShell(props) {
|
|
|
18198
18202
|
}
|
|
18199
18203
|
await props.reload();
|
|
18200
18204
|
}
|
|
18201
|
-
if (!worktree || !
|
|
18205
|
+
if (!worktree || !existsSync11(worktree))
|
|
18202
18206
|
return;
|
|
18203
18207
|
const opener = detectWorktreeOpener();
|
|
18204
18208
|
if (!opener) {
|
|
@@ -18249,7 +18253,7 @@ function TasksShell(props) {
|
|
|
18249
18253
|
const exists = await sessionExists(name);
|
|
18250
18254
|
if (exists) {
|
|
18251
18255
|
const cwd2 = await getSessionOption(name, "@kobe_worktree") || task?.worktreePath || "";
|
|
18252
|
-
if (cwd2 &&
|
|
18256
|
+
if (cwd2 && existsSync11(cwd2)) {
|
|
18253
18257
|
await ensureSession({
|
|
18254
18258
|
name,
|
|
18255
18259
|
cwd: cwd2,
|
|
@@ -18263,7 +18267,7 @@ function TasksShell(props) {
|
|
|
18263
18267
|
return;
|
|
18264
18268
|
}
|
|
18265
18269
|
let cwd = task?.worktreePath;
|
|
18266
|
-
if (!cwd || !
|
|
18270
|
+
if (!cwd || !existsSync11(cwd)) {
|
|
18267
18271
|
if (!props.orch) {
|
|
18268
18272
|
console.error("[kobe tasks] no daemon; cannot materialise worktree");
|
|
18269
18273
|
return;
|
|
@@ -18276,7 +18280,7 @@ function TasksShell(props) {
|
|
|
18276
18280
|
}
|
|
18277
18281
|
await props.reload();
|
|
18278
18282
|
}
|
|
18279
|
-
if (!cwd || !
|
|
18283
|
+
if (!cwd || !existsSync11(cwd))
|
|
18280
18284
|
return;
|
|
18281
18285
|
const init2 = task?.repo ? resolveRepoInit(task.repo, cwd) : {};
|
|
18282
18286
|
const ready = await ensureSession({
|
|
@@ -19727,14 +19731,14 @@ var init_keys2 = __esm(() => {
|
|
|
19727
19731
|
|
|
19728
19732
|
// src/tui/panes/filetree/open-external.ts
|
|
19729
19733
|
import { spawn as spawn5 } from "child_process";
|
|
19730
|
-
import { existsSync as
|
|
19734
|
+
import { existsSync as existsSync12 } from "fs";
|
|
19731
19735
|
import { platform } from "os";
|
|
19732
19736
|
function openExternally(absPath) {
|
|
19733
19737
|
if (!absPath)
|
|
19734
19738
|
return;
|
|
19735
19739
|
const plat = platform();
|
|
19736
19740
|
if (plat === "linux") {
|
|
19737
|
-
if (
|
|
19741
|
+
if (existsSync12("/proc/sys/fs/binfmt_misc/WSLInterop") || process.env.WSL_DISTRO_NAME) {
|
|
19738
19742
|
spawnDetached("wslview", [absPath], () => {
|
|
19739
19743
|
const child = spawn5("wslpath", ["-w", absPath], { stdio: ["ignore", "pipe", "ignore"] });
|
|
19740
19744
|
let out = "";
|
|
@@ -21175,7 +21179,7 @@ async function ensureRepos(orchestrator) {
|
|
|
21175
21179
|
}
|
|
21176
21180
|
async function startDirectTmux() {
|
|
21177
21181
|
setClientLogContext("gui");
|
|
21178
|
-
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());
|
|
21179
21183
|
if (!await tmuxAvailable()) {
|
|
21180
21184
|
console.error("kobe: tmux not found on PATH \u2014 install tmux to use kobe 0.6 direct mode");
|
|
21181
21185
|
process.exitCode = 1;
|
|
@@ -21769,9 +21773,9 @@ var pulse_default = "../pulse-n3cq1btw.wav";
|
|
|
21769
21773
|
var init_pulse = () => {};
|
|
21770
21774
|
|
|
21771
21775
|
// src/tui/lib/sound.ts
|
|
21772
|
-
import { existsSync as
|
|
21776
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync5 } from "fs";
|
|
21773
21777
|
import { tmpdir as tmpdir2 } from "os";
|
|
21774
|
-
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";
|
|
21775
21779
|
function args(player, file, volume) {
|
|
21776
21780
|
if (player === "ffplay")
|
|
21777
21781
|
return [player, "-autoexit", "-nodisp", "-af", `volume=${volume}`, file];
|
|
@@ -21794,13 +21798,13 @@ function pickPlayer() {
|
|
|
21794
21798
|
return cachedPlayer;
|
|
21795
21799
|
const path12 = process.env.PATH ?? "";
|
|
21796
21800
|
const segments = path12.split(":").filter(Boolean);
|
|
21797
|
-
cachedPlayer = PLAYERS.find((p) => segments.some((dir) =>
|
|
21801
|
+
cachedPlayer = PLAYERS.find((p) => segments.some((dir) => existsSync13(join13(dir, p)))) ?? null;
|
|
21798
21802
|
return cachedPlayer;
|
|
21799
21803
|
}
|
|
21800
21804
|
async function ensureAsset() {
|
|
21801
21805
|
cachedPath ??= (async () => {
|
|
21802
21806
|
mkdirSync5(DIR, { recursive: true });
|
|
21803
|
-
const dest =
|
|
21807
|
+
const dest = join13(DIR, basename6(pulseAsset));
|
|
21804
21808
|
const out = Bun.file(dest);
|
|
21805
21809
|
if (await out.exists())
|
|
21806
21810
|
return dest;
|
|
@@ -21830,7 +21834,7 @@ var pulseAsset, DIR, PLAYERS, cachedPlayer, cachedPath;
|
|
|
21830
21834
|
var init_sound = __esm(() => {
|
|
21831
21835
|
init_pulse();
|
|
21832
21836
|
pulseAsset = isAbsolute2(pulse_default) ? pulse_default : resolve8(import.meta.dir, pulse_default);
|
|
21833
|
-
DIR =
|
|
21837
|
+
DIR = join13(tmpdir2(), "kobe-sfx");
|
|
21834
21838
|
PLAYERS = [
|
|
21835
21839
|
"ffplay",
|
|
21836
21840
|
"mpv",
|
package/package.json
CHANGED