@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.
Files changed (2) hide show
  1. package/dist/cli/index.js +123 -3
  2. 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.10",
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@sma1lboy/kobe",
4
- "version": "0.7.10",
4
+ "version": "0.7.11",
5
5
  "description": "TUI orchestrator for Claude Code (codename)",
6
6
  "type": "module",
7
7
  "packageManager": "bun@1.3.13",