@sma1lboy/kobe 0.7.10 → 0.7.11
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 +123 -3
- 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.11",
|
|
74
74
|
description: "TUI orchestrator for Claude Code (codename)",
|
|
75
75
|
type: "module",
|
|
76
76
|
packageManager: "bun@1.3.13",
|
|
@@ -5019,6 +5019,21 @@ function matchTaskByCwd(tasks, cwd) {
|
|
|
5019
5019
|
}
|
|
5020
5020
|
return bestId;
|
|
5021
5021
|
}
|
|
5022
|
+
function matchRepoByCwd(tasks, cwd) {
|
|
5023
|
+
const target = normalize(cwd);
|
|
5024
|
+
let best;
|
|
5025
|
+
let bestLen = -1;
|
|
5026
|
+
for (const t of tasks) {
|
|
5027
|
+
if (!t.repo)
|
|
5028
|
+
continue;
|
|
5029
|
+
const repo = normalize(t.repo);
|
|
5030
|
+
if (isAncestorOrSelf(repo, target) && repo.length > bestLen) {
|
|
5031
|
+
bestLen = repo.length;
|
|
5032
|
+
best = repo;
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
return best;
|
|
5036
|
+
}
|
|
5022
5037
|
function findAdoptableWorktree(tasks, cwd) {
|
|
5023
5038
|
const target = normalize(cwd);
|
|
5024
5039
|
const repos = new Set;
|
|
@@ -5364,6 +5379,20 @@ async function startDaemonServer(orch, options = {}) {
|
|
|
5364
5379
|
});
|
|
5365
5380
|
return { task: serializeTask(task) };
|
|
5366
5381
|
}
|
|
5382
|
+
case "worktree.reconcile": {
|
|
5383
|
+
const cwd = requireString(payload, "cwd");
|
|
5384
|
+
const worktreePath = requireString(payload, "worktreePath");
|
|
5385
|
+
const repo = matchRepoByCwd(orch.listTasks(), cwd) ?? matchRepoByCwd(orch.listTasks(), worktreePath);
|
|
5386
|
+
if (!repo)
|
|
5387
|
+
return { adopted: false };
|
|
5388
|
+
try {
|
|
5389
|
+
const task = await orch.adoptWorktree({ repo, worktreePath, ifExists: "return" });
|
|
5390
|
+
return { adopted: true, taskId: task.id };
|
|
5391
|
+
} catch (err) {
|
|
5392
|
+
logDaemonError("worktree-created", err);
|
|
5393
|
+
return { adopted: false };
|
|
5394
|
+
}
|
|
5395
|
+
}
|
|
5367
5396
|
case "task.setActive": {
|
|
5368
5397
|
bus.publish("active-task", { taskId: optionalString(payload, "taskId") ?? null });
|
|
5369
5398
|
return {};
|
|
@@ -8405,6 +8434,29 @@ function mergeActivityHooks(current, install, inv = kobeCliInvocation()) {
|
|
|
8405
8434
|
}
|
|
8406
8435
|
return Object.keys(hooks).length > 0 ? { ...restSettings, hooks } : { ...restSettings };
|
|
8407
8436
|
}
|
|
8437
|
+
function buildWorktreeWatchHook(inv = kobeCliInvocation()) {
|
|
8438
|
+
const command = shellQuoteArgv([...inv, "hook", WORKTREE_SYNC_MARKER]);
|
|
8439
|
+
return { PostToolUse: [{ matcher: "Bash", hooks: [{ type: "command", command }] }] };
|
|
8440
|
+
}
|
|
8441
|
+
function isKobeWorktreeWatchGroup(group) {
|
|
8442
|
+
if (!isObject6(group) || !Array.isArray(group.hooks))
|
|
8443
|
+
return false;
|
|
8444
|
+
return group.hooks.some((h) => isObject6(h) && typeof h.command === "string" && h.command.includes(WORKTREE_SYNC_MARKER));
|
|
8445
|
+
}
|
|
8446
|
+
function mergeWorktreeWatchHook(current, install, inv = kobeCliInvocation()) {
|
|
8447
|
+
const { hooks: rawHooks, ...restSettings } = current;
|
|
8448
|
+
const hooks = isObject6(rawHooks) ? { ...rawHooks } : {};
|
|
8449
|
+
const key = "PostToolUse";
|
|
8450
|
+
const prior = Array.isArray(hooks[key]) ? hooks[key] : [];
|
|
8451
|
+
const kept = prior.filter((g) => !isKobeWorktreeWatchGroup(g));
|
|
8452
|
+
if (install)
|
|
8453
|
+
kept.push(...buildWorktreeWatchHook(inv)[key]);
|
|
8454
|
+
if (kept.length > 0)
|
|
8455
|
+
hooks[key] = kept;
|
|
8456
|
+
else
|
|
8457
|
+
delete hooks[key];
|
|
8458
|
+
return Object.keys(hooks).length > 0 ? { ...restSettings, hooks } : { ...restSettings };
|
|
8459
|
+
}
|
|
8408
8460
|
|
|
8409
8461
|
class ClaudeHookAdapter {
|
|
8410
8462
|
vendor = "claude";
|
|
@@ -8423,6 +8475,12 @@ class ClaudeHookAdapter {
|
|
|
8423
8475
|
async removeWorktreeSyncHook(settingsFilePath) {
|
|
8424
8476
|
await this.editSettings(settingsFilePath, (cur) => mergeWorktreeSyncHook(cur, null));
|
|
8425
8477
|
}
|
|
8478
|
+
async installWorktreeWatchHook(settingsFilePath) {
|
|
8479
|
+
await this.editSettings(settingsFilePath, (cur) => mergeWorktreeWatchHook(cur, true));
|
|
8480
|
+
}
|
|
8481
|
+
async removeWorktreeWatchHook(settingsFilePath) {
|
|
8482
|
+
await this.editSettings(settingsFilePath, (cur) => mergeWorktreeWatchHook(cur, false));
|
|
8483
|
+
}
|
|
8426
8484
|
async editSettings(settingsFilePath, transform) {
|
|
8427
8485
|
try {
|
|
8428
8486
|
const current = await readJsonObject(settingsFilePath);
|
|
@@ -8471,6 +8529,8 @@ class NoopHookAdapter {
|
|
|
8471
8529
|
return false;
|
|
8472
8530
|
}
|
|
8473
8531
|
async removeWorktreeSyncHook() {}
|
|
8532
|
+
async installWorktreeWatchHook() {}
|
|
8533
|
+
async removeWorktreeWatchHook() {}
|
|
8474
8534
|
}
|
|
8475
8535
|
var init_hook_adapter2 = __esm(() => {
|
|
8476
8536
|
init_hook_adapter();
|
|
@@ -8480,6 +8540,7 @@ var init_hook_adapter2 = __esm(() => {
|
|
|
8480
8540
|
var exports_hook_cmd = {};
|
|
8481
8541
|
__export(exports_hook_cmd, {
|
|
8482
8542
|
runHookSubcommand: () => runHookSubcommand,
|
|
8543
|
+
parseWorktreeAddPath: () => parseWorktreeAddPath,
|
|
8483
8544
|
ensureGlobalKobeHooks: () => ensureGlobalKobeHooks
|
|
8484
8545
|
});
|
|
8485
8546
|
import { homedir as homedir10 } from "os";
|
|
@@ -8516,12 +8577,69 @@ function flagValue(argv, name) {
|
|
|
8516
8577
|
}
|
|
8517
8578
|
return;
|
|
8518
8579
|
}
|
|
8580
|
+
function isPlainObject2(v) {
|
|
8581
|
+
return !!v && typeof v === "object" && !Array.isArray(v);
|
|
8582
|
+
}
|
|
8583
|
+
function tokenizeCommand(command) {
|
|
8584
|
+
const out = [];
|
|
8585
|
+
const re = /"([^"]*)"|'([^']*)'|(\S+)/g;
|
|
8586
|
+
let m;
|
|
8587
|
+
while ((m = re.exec(command)) !== null)
|
|
8588
|
+
out.push(m[1] ?? m[2] ?? m[3] ?? "");
|
|
8589
|
+
return out;
|
|
8590
|
+
}
|
|
8591
|
+
function parseWorktreeAddPath(command) {
|
|
8592
|
+
const tokens = tokenizeCommand(command);
|
|
8593
|
+
const valueFlags = new Set(["-b", "-B", "--reason"]);
|
|
8594
|
+
for (let i = 0;i + 1 < tokens.length; i++) {
|
|
8595
|
+
if (tokens[i] !== "worktree" || tokens[i + 1] !== "add")
|
|
8596
|
+
continue;
|
|
8597
|
+
let j = i + 2;
|
|
8598
|
+
while (j < tokens.length) {
|
|
8599
|
+
const t = tokens[j];
|
|
8600
|
+
if (t === "&&" || t === "||" || t === ";" || t === "|" || t === ">" || t === ">>")
|
|
8601
|
+
break;
|
|
8602
|
+
if (t.startsWith("-")) {
|
|
8603
|
+
j += valueFlags.has(t) ? 2 : 1;
|
|
8604
|
+
continue;
|
|
8605
|
+
}
|
|
8606
|
+
return t;
|
|
8607
|
+
}
|
|
8608
|
+
}
|
|
8609
|
+
return;
|
|
8610
|
+
}
|
|
8611
|
+
async function runWorktreeCreatedHook() {
|
|
8612
|
+
const payload = await readStdinPayload();
|
|
8613
|
+
const toolInput = isPlainObject2(payload.tool_input) ? payload.tool_input : {};
|
|
8614
|
+
const command = typeof toolInput.command === "string" ? toolInput.command : "";
|
|
8615
|
+
if (!command.includes("worktree"))
|
|
8616
|
+
return;
|
|
8617
|
+
const rawPath = parseWorktreeAddPath(command);
|
|
8618
|
+
if (!rawPath)
|
|
8619
|
+
return;
|
|
8620
|
+
const cwd = typeof payload.cwd === "string" && payload.cwd ? payload.cwd : process.cwd();
|
|
8621
|
+
const worktreePath = resolve6(cwd, rawPath);
|
|
8622
|
+
const client = await connectIfRunning();
|
|
8623
|
+
if (!client)
|
|
8624
|
+
return;
|
|
8625
|
+
try {
|
|
8626
|
+
await client.request("worktree.reconcile", { cwd, worktreePath });
|
|
8627
|
+
} finally {
|
|
8628
|
+
client.close();
|
|
8629
|
+
}
|
|
8630
|
+
}
|
|
8519
8631
|
async function runHookSubcommand(argv) {
|
|
8520
8632
|
const [verb, ...rest] = argv;
|
|
8521
8633
|
if (verb === "setup") {
|
|
8522
8634
|
await runHookSetup(rest);
|
|
8523
8635
|
return;
|
|
8524
8636
|
}
|
|
8637
|
+
if (verb === WORKTREE_CREATED_VERB) {
|
|
8638
|
+
try {
|
|
8639
|
+
await runWorktreeCreatedHook();
|
|
8640
|
+
} catch {}
|
|
8641
|
+
return;
|
|
8642
|
+
}
|
|
8525
8643
|
try {
|
|
8526
8644
|
if (!verb || !isEngineActivityKind(verb))
|
|
8527
8645
|
return;
|
|
@@ -8569,8 +8687,10 @@ function persistedSyncPath(stored) {
|
|
|
8569
8687
|
async function ensureGlobalKobeHooks() {
|
|
8570
8688
|
try {
|
|
8571
8689
|
const globalPath = globalSettingsPath();
|
|
8572
|
-
for (const a of activityHookAdapters())
|
|
8690
|
+
for (const a of activityHookAdapters()) {
|
|
8573
8691
|
await a.installActivityHooks(globalPath);
|
|
8692
|
+
await a.installWorktreeWatchHook(globalPath);
|
|
8693
|
+
}
|
|
8574
8694
|
await cleanupWorktreeSyncHook();
|
|
8575
8695
|
} catch {}
|
|
8576
8696
|
}
|
|
@@ -8605,7 +8725,7 @@ async function runHookSetup(_argv) {
|
|
|
8605
8725
|
].join(`
|
|
8606
8726
|
`));
|
|
8607
8727
|
}
|
|
8608
|
-
var SYNC_SETTING_KEY = "externalWorktreeSync";
|
|
8728
|
+
var WORKTREE_CREATED_VERB = "worktree-created", SYNC_SETTING_KEY = "externalWorktreeSync";
|
|
8609
8729
|
var init_hook_cmd = __esm(() => {
|
|
8610
8730
|
init_daemon_process();
|
|
8611
8731
|
init_hook_adapter2();
|
package/package.json
CHANGED