@tekmidian/pai 0.12.2 → 0.13.0

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 (45) hide show
  1. package/dist/cli/index.mjs +2 -2
  2. package/dist/cli/program.d.mts.map +1 -1
  3. package/dist/cli/program.mjs +3 -2
  4. package/dist/cli/program.mjs.map +1 -1
  5. package/dist/{config-BuhHWyOK.mjs → config-C8m-tPhP.mjs} +22 -2
  6. package/dist/config-C8m-tPhP.mjs.map +1 -0
  7. package/dist/daemon/index.mjs +2 -2
  8. package/dist/{daemon-Ca7YXHUW.mjs → daemon-D2aKb4mJ.mjs} +2 -2
  9. package/dist/{daemon-Ca7YXHUW.mjs.map → daemon-D2aKb4mJ.mjs.map} +1 -1
  10. package/dist/daemon-mcp/index.mjs +581 -2
  11. package/dist/daemon-mcp/index.mjs.map +1 -1
  12. package/dist/{pick-C5sUQ5g_.mjs → pick-CS_TmOqX.mjs} +1082 -445
  13. package/dist/pick-CS_TmOqX.mjs.map +1 -0
  14. package/dist/skills/Tasks/SKILL.md +101 -0
  15. package/docs/commands/README.md +6 -0
  16. package/docs/commands/backup.md +1 -1
  17. package/docs/commands/clear-names.md +1 -1
  18. package/docs/commands/daemon.md +1 -1
  19. package/docs/commands/db.md +1 -1
  20. package/docs/commands/end.md +1 -1
  21. package/docs/commands/help.md +1 -1
  22. package/docs/commands/kg.md +1 -1
  23. package/docs/commands/mcp.md +1 -1
  24. package/docs/commands/memory.md +1 -1
  25. package/docs/commands/notify.md +1 -1
  26. package/docs/commands/observation.md +1 -1
  27. package/docs/commands/obsidian.md +1 -1
  28. package/docs/commands/pause.md +1 -1
  29. package/docs/commands/project.md +1 -1
  30. package/docs/commands/projects.md +1 -1
  31. package/docs/commands/registry.md +1 -1
  32. package/docs/commands/restore.md +1 -1
  33. package/docs/commands/sessions.md +1 -1
  34. package/docs/commands/setup.md +1 -1
  35. package/docs/commands/shell-init.md +1 -1
  36. package/docs/commands/skill.md +1 -1
  37. package/docs/commands/task.md +90 -0
  38. package/docs/commands/topic.md +1 -1
  39. package/docs/commands/update.md +1 -1
  40. package/docs/commands/zettel.md +1 -1
  41. package/package.json +1 -1
  42. package/plugins/productivity/plugin.json +2 -2
  43. package/plugins/productivity/skills/Tasks/SKILL.md +126 -0
  44. package/dist/config-BuhHWyOK.mjs.map +0 -1
  45. package/dist/pick-C5sUQ5g_.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { a as openRegistry, i as indexProject, n as indexAll, t as embedChunks } from "./sync-uPR4g438.mjs";
2
- import { _ as warn, a as fmtDate, c as ok, d as scaffoldProjectDirs, f as shortenPath, i as err, l as renderTable, m as slugify, n as dim, o as header, p as slugFromPath, r as encodeDir, s as now, t as bold, u as resolvePath } from "./utils-CqqgB0dH.mjs";
2
+ import { _ as warn, a as fmtDate, c as ok, d as scaffoldProjectDirs, f as shortenPath, i as err, l as renderTable, m as slugify, n as dim$1, o as header, p as slugFromPath, r as encodeDir, s as now, t as bold$1, u as resolvePath } from "./utils-CqqgB0dH.mjs";
3
3
  import { a as slugify$1, i as parseSessionFilename } from "./migrate-B02wDDgS.mjs";
4
4
  import { n as ensurePaiMarker } from "./pai-marker-HVBwwBW-.mjs";
5
5
  import { n as openFederation } from "./db-CmYbAVCD.mjs";
@@ -8,7 +8,7 @@ import { n as formatDetection, r as formatDetectionJson, t as detectProject } fr
8
8
  import { a as resolveHome, c as upsertSession, n as cmdScan, o as saveScanConfig, r as loadScanConfig, s as upsertProject, t as extractAndStoreTriples } from "./kg-extraction-C8DEUHTS.mjs";
9
9
  import { t as createStorageBackend } from "./factory-Q88X1bAN.mjs";
10
10
  import { t as PaiClient } from "./ipc-client-CoyUHPod.mjs";
11
- import { a as expandHome, i as ensureConfigDir, n as CONFIG_FILE$2, o as loadConfig, t as CONFIG_DIR } from "./config-BuhHWyOK.mjs";
11
+ import { a as expandHome, c as UNROUTED, i as ensureConfigDir, n as CONFIG_FILE$2, o as loadConfig, s as OWNER_LABEL_PREFIX, t as CONFIG_DIR } from "./config-C8m-tPhP.mjs";
12
12
  import { s as kgQuery } from "./kg-entity-LXblD7LZ.mjs";
13
13
  import { a as renderDedupedSessions, c as revealItermSession, d as fmtAge, f as resolveSessionByNameOrId, i as normalizeName, l as sendToSession, o as callAiBroker, p as scanSessions, r as buildDeduped, s as fetchLiveSessions, u as printExitDir } from "./main-resolver-uFxNiDy7.mjs";
14
14
  import { appendFileSync, chmodSync, copyFileSync, createReadStream, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, renameSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
@@ -16,7 +16,7 @@ import { homedir, platform } from "node:os";
16
16
  import { basename, dirname, join, relative, resolve } from "node:path";
17
17
  import chalk from "chalk";
18
18
  import { fileURLToPath } from "node:url";
19
- import { execSync, spawn, spawnSync } from "node:child_process";
19
+ import { execFile, execSync, spawn, spawnSync } from "node:child_process";
20
20
  import { createInterface } from "node:readline";
21
21
  import { createConnection } from "net";
22
22
 
@@ -105,17 +105,17 @@ function cmdPromote(db, opts) {
105
105
  const sourceTodoPath = join(sourceProjectRoot, "Notes", "TODO.md");
106
106
  if (existsSync(sourceTodoPath)) {
107
107
  appendFileSync(sourceTodoPath, `\n- Promoted to project: [${slug}](${targetPath})\n`, "utf-8");
108
- console.log(dim(` Backlink added to: ${sourceTodoPath}`));
108
+ console.log(dim$1(` Backlink added to: ${sourceTodoPath}`));
109
109
  }
110
110
  console.log();
111
- console.log(ok(`Project promoted: ${bold(slug)}`));
112
- console.log(dim(` Display name: ${displayName}`));
113
- console.log(dim(` Path: ${targetPath}`));
114
- console.log(dim(` Slug: ${slug}`));
115
- console.log(dim(` Session note: ${destNoteName}`));
116
- console.log(dim(` Memory: Notes/MEMORY.md created`));
111
+ console.log(ok(`Project promoted: ${bold$1(slug)}`));
112
+ console.log(dim$1(` Display name: ${displayName}`));
113
+ console.log(dim$1(` Path: ${targetPath}`));
114
+ console.log(dim$1(` Slug: ${slug}`));
115
+ console.log(dim$1(` Session note: ${destNoteName}`));
116
+ console.log(dim$1(` Memory: Notes/MEMORY.md created`));
117
117
  console.log();
118
- console.log(dim(` Next: cd ${targetPath} && pai session list ${slug}`));
118
+ console.log(dim$1(` Next: cd ${targetPath} && pai session list ${slug}`));
119
119
  }
120
120
 
121
121
  //#endregion
@@ -345,9 +345,9 @@ function cmdAdd(db, rawPath, opts) {
345
345
  const matches = db.prepare(`SELECT slug, root_path FROM projects WHERE status = 'active' AND slug != ?`).all(slug).filter((s) => basename(s.root_path).toLowerCase() === dirName || s.slug.replace(/-\d+$/, "") === slug.replace(/-\d+$/, ""));
346
346
  if (matches.length > 0) {
347
347
  console.log(warn(`Similar project(s) already registered:`));
348
- for (const m of matches) console.log(dim(` ${bold(m.slug)} ${shortenPath(m.root_path, 50)}`));
349
- console.log(dim(` Consider: pai project alias ${matches[0].slug} <name> (to link them)`));
350
- console.log(dim(` Or: pai project archive ${slug} (if this is a duplicate)`));
348
+ for (const m of matches) console.log(dim$1(` ${bold$1(m.slug)} ${shortenPath(m.root_path, 50)}`));
349
+ console.log(dim$1(` Consider: pai project alias ${matches[0].slug} <name> (to link them)`));
350
+ console.log(dim$1(` Or: pai project archive ${slug} (if this is a duplicate)`));
351
351
  console.log();
352
352
  }
353
353
  const ts = now();
@@ -358,10 +358,10 @@ function cmdAdd(db, rawPath, opts) {
358
358
  try {
359
359
  ensurePaiMarker(rootPath, slug, displayName);
360
360
  } catch {}
361
- console.log(ok(`Project added: ${bold(slug)}`));
362
- console.log(dim(` Path: ${rootPath}`));
363
- console.log(dim(` Encoded dir: ${encodedDir}`));
364
- console.log(dim(` Type: ${type}`));
361
+ console.log(ok(`Project added: ${bold$1(slug)}`));
362
+ console.log(dim$1(` Path: ${rootPath}`));
363
+ console.log(dim$1(` Encoded dir: ${encodedDir}`));
364
+ console.log(dim$1(` Type: ${type}`));
365
365
  }
366
366
  function cmdList$3(db, opts) {
367
367
  let query = `
@@ -395,12 +395,12 @@ function cmdList$3(db, opts) {
395
395
  return;
396
396
  }
397
397
  const tableRows = rows.map((r, i) => [
398
- dim(String(i + 1)),
399
- bold(r.display_name ?? r.slug),
400
- dim(r.slug),
401
- dim(shortenPath(r.root_path, 44)),
398
+ dim$1(String(i + 1)),
399
+ bold$1(r.display_name ?? r.slug),
400
+ dim$1(r.slug),
401
+ dim$1(shortenPath(r.root_path, 44)),
402
402
  r.status === "active" ? chalk.green(r.status) : chalk.yellow(r.status),
403
- dim(r.type),
403
+ dim$1(r.type),
404
404
  String(r.session_count),
405
405
  fmtDate(r.last_active)
406
406
  ]);
@@ -416,8 +416,8 @@ function cmdList$3(db, opts) {
416
416
  ], tableRows));
417
417
  console.log();
418
418
  const hiddenCount = db.prepare("SELECT COUNT(*) AS cnt FROM projects").get().cnt - rows.length;
419
- if (!opts.all && !opts.status && hiddenCount > 0) console.log(dim(` ${rows.length} active project(s) (${hiddenCount} archived — use --all to show)`));
420
- else console.log(dim(` ${rows.length} project(s)`));
419
+ if (!opts.all && !opts.status && hiddenCount > 0) console.log(dim$1(` ${rows.length} active project(s) (${hiddenCount} archived — use --all to show)`));
420
+ else console.log(dim$1(` ${rows.length} project(s)`));
421
421
  }
422
422
  function cmdInfo(db, identifier) {
423
423
  const project = resolveIdentifier(db, identifier) ?? requireProject(db, identifier);
@@ -430,22 +430,22 @@ function cmdInfo(db, identifier) {
430
430
  console.log();
431
431
  console.log(header(` ${project.display_name}`));
432
432
  console.log();
433
- console.log(` ${bold("Slug:")} ${project.slug}`);
434
- console.log(` ${bold("Path:")} ${project.root_path}`);
435
- console.log(` ${bold("Encoded dir:")} ${project.encoded_dir}`);
436
- console.log(` ${bold("Type:")} ${project.type}`);
437
- console.log(` ${bold("Status:")} ${project.status === "active" ? chalk.green(project.status) : chalk.yellow(project.status)}`);
438
- console.log(` ${bold("Tags:")} ${tags.length ? tags.map((t) => chalk.cyan(t)).join(", ") : dim("none")}`);
439
- console.log(` ${bold("Aliases:")} ${aliases.length ? aliases.join(", ") : dim("none")}`);
440
- console.log(` ${bold("Sessions:")} ${sessionCount}`);
441
- console.log(` ${bold("Last active:")} ${fmtDate(lastSession)}`);
442
- console.log(` ${bold("Created:")} ${fmtDate(project.created_at)}`);
443
- if (project.archived_at) console.log(` ${bold("Archived:")} ${fmtDate(project.archived_at)}`);
433
+ console.log(` ${bold$1("Slug:")} ${project.slug}`);
434
+ console.log(` ${bold$1("Path:")} ${project.root_path}`);
435
+ console.log(` ${bold$1("Encoded dir:")} ${project.encoded_dir}`);
436
+ console.log(` ${bold$1("Type:")} ${project.type}`);
437
+ console.log(` ${bold$1("Status:")} ${project.status === "active" ? chalk.green(project.status) : chalk.yellow(project.status)}`);
438
+ console.log(` ${bold$1("Tags:")} ${tags.length ? tags.map((t) => chalk.cyan(t)).join(", ") : dim$1("none")}`);
439
+ console.log(` ${bold$1("Aliases:")} ${aliases.length ? aliases.join(", ") : dim$1("none")}`);
440
+ console.log(` ${bold$1("Sessions:")} ${sessionCount}`);
441
+ console.log(` ${bold$1("Last active:")} ${fmtDate(lastSession)}`);
442
+ console.log(` ${bold$1("Created:")} ${fmtDate(project.created_at)}`);
443
+ if (project.archived_at) console.log(` ${bold$1("Archived:")} ${fmtDate(project.archived_at)}`);
444
444
  if (recentSessions.length) {
445
445
  console.log();
446
- console.log(` ${bold("Recent sessions:")}`);
446
+ console.log(` ${bold$1("Recent sessions:")}`);
447
447
  const sessionRows = recentSessions.map((s) => [
448
- dim(`#${s.number}`),
448
+ dim$1(`#${s.number}`),
449
449
  s.date,
450
450
  s.title.length > 50 ? s.title.slice(0, 47) + "..." : s.title,
451
451
  s.status === "completed" ? chalk.green(s.status) : chalk.yellow(s.status)
@@ -467,7 +467,7 @@ function cmdArchive(db, slug) {
467
467
  }
468
468
  const ts = now();
469
469
  db.prepare("UPDATE projects SET status = 'archived', archived_at = ?, updated_at = ? WHERE id = ?").run(ts, ts, project.id);
470
- console.log(ok(`Archived: ${bold(slug)}`));
470
+ console.log(ok(`Archived: ${bold$1(slug)}`));
471
471
  }
472
472
  function cmdUnarchive(db, slug) {
473
473
  const project = requireProject(db, slug);
@@ -477,7 +477,7 @@ function cmdUnarchive(db, slug) {
477
477
  }
478
478
  const ts = now();
479
479
  db.prepare("UPDATE projects SET status = 'active', archived_at = NULL, updated_at = ? WHERE id = ?").run(ts, project.id);
480
- console.log(ok(`Unarchived: ${bold(slug)}`));
480
+ console.log(ok(`Unarchived: ${bold$1(slug)}`));
481
481
  }
482
482
  function cmdMove(db, slug, newPath) {
483
483
  const project = requireProject(db, slug);
@@ -485,9 +485,9 @@ function cmdMove(db, slug, newPath) {
485
485
  const newEncoded = encodeDir(resolvedNew);
486
486
  const ts = now();
487
487
  db.prepare("UPDATE projects SET root_path = ?, encoded_dir = ?, updated_at = ? WHERE id = ?").run(resolvedNew, newEncoded, ts, project.id);
488
- console.log(ok(`Moved: ${bold(slug)}`));
489
- console.log(dim(` Old path: ${project.root_path}`));
490
- console.log(dim(` New path: ${resolvedNew}`));
488
+ console.log(ok(`Moved: ${bold$1(slug)}`));
489
+ console.log(dim$1(` Old path: ${project.root_path}`));
490
+ console.log(dim$1(` New path: ${resolvedNew}`));
491
491
  }
492
492
  function cmdTag(db, slug, tags) {
493
493
  const project = requireProject(db, slug);
@@ -501,8 +501,8 @@ function cmdTag(db, slug, tags) {
501
501
  added.push(tagName);
502
502
  }
503
503
  }
504
- if (added.length) console.log(ok(`Tagged ${bold(slug)}: ${added.map((t) => chalk.cyan(t)).join(", ")}`));
505
- if (skipped.length) console.log(dim(` Already present: ${skipped.join(", ")}`));
504
+ if (added.length) console.log(ok(`Tagged ${bold$1(slug)}: ${added.map((t) => chalk.cyan(t)).join(", ")}`));
505
+ if (skipped.length) console.log(dim$1(` Already present: ${skipped.join(", ")}`));
506
506
  }
507
507
  function cmdAlias(db, slug, alias) {
508
508
  requireProject(db, slug);
@@ -513,7 +513,7 @@ function cmdAlias(db, slug, alias) {
513
513
  const project = getProject$1(db, slug);
514
514
  try {
515
515
  db.prepare("INSERT INTO aliases (alias, project_id) VALUES (?, ?)").run(alias, project.id);
516
- console.log(ok(`Alias added: ${bold(alias)} → ${slug}`));
516
+ console.log(ok(`Alias added: ${bold$1(alias)} → ${slug}`));
517
517
  } catch {
518
518
  console.error(err(`Alias "${alias}" is already registered.`));
519
519
  process.exit(1);
@@ -538,11 +538,11 @@ function cmdEdit(db, slug, opts) {
538
538
  const ts = now();
539
539
  if (opts.displayName) {
540
540
  db.prepare("UPDATE projects SET display_name = ?, updated_at = ? WHERE id = ?").run(opts.displayName, ts, project.id);
541
- console.log(ok(`Display name updated: ${bold(opts.displayName)}`));
541
+ console.log(ok(`Display name updated: ${bold$1(opts.displayName)}`));
542
542
  }
543
543
  if (opts.type) {
544
544
  db.prepare("UPDATE projects SET type = ?, updated_at = ? WHERE id = ?").run(opts.type, ts, project.id);
545
- console.log(ok(`Type updated: ${bold(opts.type)}`));
545
+ console.log(ok(`Type updated: ${bold$1(opts.type)}`));
546
546
  }
547
547
  }
548
548
  function cmdDetect(db, pathArg, opts) {
@@ -555,7 +555,7 @@ function cmdDetect(db, pathArg, opts) {
555
555
  }, null, 2));
556
556
  else {
557
557
  console.log(warn(`No registered project found for: ${cwd}`));
558
- console.log(dim(" Run 'pai project add .' to register this directory."));
558
+ console.log(dim$1(" Run 'pai project add .' to register this directory."));
559
559
  }
560
560
  process.exit(0);
561
561
  return;
@@ -585,14 +585,14 @@ function cmdConsolidate(db, identifier, opts) {
585
585
  const toMerge = dirs.filter((d) => d.notesPath !== canonicalNotes);
586
586
  if (toMerge.length === 0) {
587
587
  console.log(ok(" All notes are already in the canonical location."));
588
- console.log(dim(` ${canonicalNotes}`));
588
+ console.log(dim$1(` ${canonicalNotes}`));
589
589
  return;
590
590
  }
591
591
  console.log(` Found ${toMerge.length} scattered Notes directory(ies) to consolidate:`);
592
592
  console.log();
593
593
  for (const d of toMerge) {
594
- console.log(` ${bold(d.encodedDir)}`);
595
- console.log(dim(` Notes: ${d.notesPath} (${d.noteCount} file(s))`));
594
+ console.log(` ${bold$1(d.encodedDir)}`);
595
+ console.log(dim$1(` Notes: ${d.notesPath} (${d.noteCount} file(s))`));
596
596
  }
597
597
  console.log();
598
598
  console.log(` Destination: ${canonicalNotes}`);
@@ -633,23 +633,23 @@ function cmdConsolidate(db, identifier, opts) {
633
633
  * Prints all messages to stderr (safe for shell-wrapper stdout capture).
634
634
  */
635
635
  function tryRecoverMovedProject(db, project) {
636
- process.stderr.write(warn(`Path not found: ${project.root_path}\n`) + dim(" Searching for moved location...\n"));
636
+ process.stderr.write(warn(`Path not found: ${project.root_path}\n`) + dim$1(" Searching for moved location...\n"));
637
637
  const result = findMovedPath(project.root_path);
638
638
  if (result.found) {
639
639
  const newPath = result.found;
640
640
  const newEncoded = encodeDir(newPath);
641
641
  const ts = now();
642
642
  db.prepare("UPDATE projects SET root_path = ?, encoded_dir = ?, updated_at = ? WHERE id = ?").run(newPath, newEncoded, ts, project.id);
643
- process.stderr.write(ok(`Project moved: ${shortenPath(project.root_path, 50)}\n`) + dim(` → ${newPath}\n`) + ok("Registry updated.\n"));
643
+ process.stderr.write(ok(`Project moved: ${shortenPath(project.root_path, 50)}\n`) + dim$1(` → ${newPath}\n`) + ok("Registry updated.\n"));
644
644
  return newPath;
645
645
  }
646
646
  if (result.ambiguous) {
647
647
  process.stderr.write(warn(`Multiple directories named "${basename(project.root_path)}" found:\n`));
648
- for (const candidate of result.ambiguous) process.stderr.write(dim(` ${candidate}\n`));
649
- process.stderr.write(dim(`\n Disambiguate with: pai projects rebind ${project.slug} <path>\n`));
648
+ for (const candidate of result.ambiguous) process.stderr.write(dim$1(` ${candidate}\n`));
649
+ process.stderr.write(dim$1(`\n Disambiguate with: pai projects rebind ${project.slug} <path>\n`));
650
650
  return;
651
651
  }
652
- process.stderr.write(err(`Project "${project.slug}" root_path "${project.root_path}" does not exist on disk\n and no folder named "${basename(project.root_path)}" was found in scan dirs.\n`) + dim(` Fix with: pai projects rebind ${project.slug} <new-path>\n`));
652
+ process.stderr.write(err(`Project "${project.slug}" root_path "${project.root_path}" does not exist on disk\n and no folder named "${basename(project.root_path)}" was found in scan dirs.\n`) + dim$1(` Fix with: pai projects rebind ${project.slug} <new-path>\n`));
653
653
  }
654
654
  function cmdGo(db, query) {
655
655
  const all = db.prepare("SELECT * FROM projects WHERE status = 'active' ORDER BY updated_at DESC").all();
@@ -690,10 +690,10 @@ function cmdGo(db, query) {
690
690
  if (partial.length > 1) {
691
691
  console.error(err(`Ambiguous: "${query}" matches ${partial.length} projects:\n`));
692
692
  partial.forEach((p, i) => {
693
- console.error(` ${dim(String(i + 1).padStart(2))} ${bold(p.slug.padEnd(30))} ${dim(shortenPath(p.root_path, 50))}`);
693
+ console.error(` ${dim$1(String(i + 1).padStart(2))} ${bold$1(p.slug.padEnd(30))} ${dim$1(shortenPath(p.root_path, 50))}`);
694
694
  });
695
695
  console.error();
696
- console.error(dim(" Use a more specific name or the exact slug."));
696
+ console.error(dim$1(" Use a more specific name or the exact slug."));
697
697
  process.exit(1);
698
698
  }
699
699
  const scored = all.map((p) => {
@@ -709,9 +709,9 @@ function cmdGo(db, query) {
709
709
  console.error(err(`Project not found: "${query}"\n`));
710
710
  if (suggestions.length) {
711
711
  console.error(warn(" Did you mean?"));
712
- for (const s of suggestions) console.error(` ${bold(s.project.slug.padEnd(30))} ${dim(shortenPath(s.project.root_path, 50))}`);
712
+ for (const s of suggestions) console.error(` ${bold$1(s.project.slug.padEnd(30))} ${dim$1(shortenPath(s.project.root_path, 50))}`);
713
713
  console.error();
714
- console.error(dim(" Run: pai project list (to see all projects)"));
714
+ console.error(dim$1(" Run: pai project list (to see all projects)"));
715
715
  }
716
716
  process.exit(1);
717
717
  }
@@ -733,15 +733,15 @@ function cmdRebind(db, slug, newPath) {
733
733
  const newEncoded = encodeDir(resolved);
734
734
  const conflict = db.prepare("SELECT slug FROM projects WHERE encoded_dir = ? AND id != ?").get(newEncoded, project.id);
735
735
  if (conflict) {
736
- console.error(err(`Path is already registered to project: ${bold(conflict.slug)}\n`) + dim(` ${resolved}\n`) + dim(` Archive or move that project first, or choose a different path.`));
736
+ console.error(err(`Path is already registered to project: ${bold$1(conflict.slug)}\n`) + dim$1(` ${resolved}\n`) + dim$1(` Archive or move that project first, or choose a different path.`));
737
737
  process.exit(1);
738
738
  }
739
739
  const ts = now();
740
740
  db.prepare("UPDATE projects SET root_path = ?, encoded_dir = ?, updated_at = ? WHERE id = ?").run(resolved, newEncoded, ts, project.id);
741
- console.log(ok(`Rebound: ${bold(slug)}`));
742
- console.log(dim(` Old path: ${project.root_path}`));
743
- console.log(dim(` New path: ${resolved}`));
744
- console.log(dim(` Encoded: ${newEncoded}`));
741
+ console.log(ok(`Rebound: ${bold$1(slug)}`));
742
+ console.log(dim$1(` Old path: ${project.root_path}`));
743
+ console.log(dim$1(` New path: ${resolved}`));
744
+ console.log(dim$1(` Encoded: ${newEncoded}`));
745
745
  }
746
746
 
747
747
  //#endregion
@@ -884,8 +884,8 @@ function cmdName(db, identifier, shortname, opts) {
884
884
  const config = applyPreset(getSessionConfig(project), opts.permission);
885
885
  db.prepare("UPDATE projects SET session_config = ?, updated_at = ? WHERE id = ?").run(JSON.stringify(config), now(), project.id);
886
886
  }
887
- console.log(ok(`Named: ${bold(shortname)} → ${project.slug} (${shortenPath(project.root_path, 50)})`));
888
- if (opts.permission) console.log(dim(` Permission: ${opts.permission}`));
887
+ console.log(ok(`Named: ${bold$1(shortname)} → ${project.slug} (${shortenPath(project.root_path, 50)})`));
888
+ if (opts.permission) console.log(dim$1(` Permission: ${opts.permission}`));
889
889
  }
890
890
  function cmdUnname(db, shortname) {
891
891
  const alias = db.prepare("SELECT project_id FROM aliases WHERE alias = ?").get(shortname);
@@ -895,8 +895,8 @@ function cmdUnname(db, shortname) {
895
895
  }
896
896
  db.prepare("DELETE FROM aliases WHERE alias = ?").run(shortname);
897
897
  const remaining = db.prepare("SELECT COUNT(*) AS cnt FROM aliases WHERE project_id = ?").get(alias.project_id);
898
- console.log(ok(`Removed name: ${bold(shortname)}`));
899
- if (remaining.cnt === 0) console.log(dim(" Project has no remaining names."));
898
+ console.log(ok(`Removed name: ${bold$1(shortname)}`));
899
+ if (remaining.cnt === 0) console.log(dim$1(" Project has no remaining names."));
900
900
  }
901
901
  function cmdNames(db, opts) {
902
902
  const rows = db.prepare(`
@@ -934,12 +934,12 @@ function cmdNames(db, opts) {
934
934
  if (seen.has(row.id)) continue;
935
935
  seen.add(row.id);
936
936
  const allNames = rows.filter((r) => r.id === row.id).map((r) => r.name).filter(Boolean);
937
- const perm = (row.session_config ? JSON.parse(row.session_config) : null)?.permission ?? dim("default");
937
+ const perm = (row.session_config ? JSON.parse(row.session_config) : null)?.permission ?? dim$1("default");
938
938
  tableRows.push([
939
- bold(allNames.length ? allNames.join(", ") : row.slug),
939
+ bold$1(allNames.length ? allNames.join(", ") : row.slug),
940
940
  row.slug,
941
- dim(shortenPath(row.root_path, 40)),
942
- typeof perm === "string" ? perm : dim("default"),
941
+ dim$1(shortenPath(row.root_path, 40)),
942
+ typeof perm === "string" ? perm : dim$1("default"),
943
943
  String(row.session_count),
944
944
  fmtDate(row.last_active)
945
945
  ]);
@@ -956,7 +956,7 @@ function cmdNames(db, opts) {
956
956
  "Last Active"
957
957
  ], tableRows));
958
958
  console.log();
959
- console.log(dim(` ${tableRows.length} named project(s)`));
959
+ console.log(dim$1(` ${tableRows.length} named project(s)`));
960
960
  }
961
961
  function cmdConfig(db, identifier, opts) {
962
962
  if (opts.options) {
@@ -973,14 +973,14 @@ function cmdConfig(db, identifier, opts) {
973
973
  console.log();
974
974
  console.log(header(" Session Config Options"));
975
975
  console.log();
976
- console.log(bold(" Available keys:"));
976
+ console.log(bold$1(" Available keys:"));
977
977
  console.log();
978
978
  for (const opt of CONFIG_OPTIONS) {
979
- console.log(` ${bold(opt.key.padEnd(14))} ${dim(`(${opt.type})`)} ${opt.description}`);
980
- console.log(` ${" ".repeat(14)} ${dim("e.g.")} ${opt.examples.map((e) => chalk.cyan(e)).join(", ")}`);
979
+ console.log(` ${bold$1(opt.key.padEnd(14))} ${dim$1(`(${opt.type})`)} ${opt.description}`);
980
+ console.log(` ${" ".repeat(14)} ${dim$1("e.g.")} ${opt.examples.map((e) => chalk.cyan(e)).join(", ")}`);
981
981
  }
982
982
  console.log();
983
- console.log(bold(" Permission presets:"));
983
+ console.log(bold$1(" Permission presets:"));
984
984
  console.log();
985
985
  for (const [name, config] of Object.entries(PERMISSION_PRESETS)) {
986
986
  const parts = [];
@@ -988,7 +988,7 @@ function cmdConfig(db, identifier, opts) {
988
988
  if (config.env && Object.keys(config.env).length) parts.push(`env: ${Object.entries(config.env).map(([k, v]) => `${k}=${v}`).join(" ")}`);
989
989
  if (config.autoStart) parts.push("autoStart");
990
990
  if (config.prompt) parts.push(`prompt: "${config.prompt}"`);
991
- console.log(` ${bold(name.padEnd(10))} ${dim(parts.join(", ") || "(vanilla)")}`);
991
+ console.log(` ${bold$1(name.padEnd(10))} ${dim$1(parts.join(", ") || "(vanilla)")}`);
992
992
  }
993
993
  console.log();
994
994
  return;
@@ -1003,7 +1003,7 @@ function cmdConfig(db, identifier, opts) {
1003
1003
  if (opts.preset) {
1004
1004
  defaults = applyPreset(defaults, opts.preset);
1005
1005
  saveGlobalDefaults(defaults);
1006
- console.log(ok(`Global defaults set to preset: ${bold(opts.preset)}`));
1006
+ console.log(ok(`Global defaults set to preset: ${bold$1(opts.preset)}`));
1007
1007
  return;
1008
1008
  }
1009
1009
  if (opts.set?.length) {
@@ -1042,11 +1042,11 @@ function cmdConfig(db, identifier, opts) {
1042
1042
  console.log(header(" Global Session Defaults"));
1043
1043
  console.log();
1044
1044
  if (Object.keys(defaults).length === 0) {
1045
- console.log(dim(" No defaults set. New sessions use vanilla Claude."));
1046
- console.log(dim(" Set with: pai project config --defaults --preset full"));
1045
+ console.log(dim$1(" No defaults set. New sessions use vanilla Claude."));
1046
+ console.log(dim$1(" Set with: pai project config --defaults --preset full"));
1047
1047
  } else for (const [key, value] of Object.entries(defaults)) {
1048
1048
  const display = typeof value === "object" ? JSON.stringify(value) : String(value);
1049
- console.log(` ${bold(key.padEnd(14))} ${display}`);
1049
+ console.log(` ${bold$1(key.padEnd(14))} ${display}`);
1050
1050
  }
1051
1051
  console.log();
1052
1052
  }
@@ -1054,20 +1054,20 @@ function cmdConfig(db, identifier, opts) {
1054
1054
  }
1055
1055
  if (!identifier) {
1056
1056
  console.error(err("Specify a project: pai project config <name-or-slug>"));
1057
- console.error(dim(" Or use --defaults for global defaults, --options for available keys."));
1057
+ console.error(dim$1(" Or use --defaults for global defaults, --options for available keys."));
1058
1058
  process.exit(1);
1059
1059
  }
1060
1060
  const project = resolveIdentifier(db, identifier) ?? requireProject(db, identifier);
1061
1061
  let config = getSessionConfig(project);
1062
1062
  if (opts.reset) {
1063
1063
  db.prepare("UPDATE projects SET session_config = NULL, updated_at = ? WHERE id = ?").run(now(), project.id);
1064
- console.log(ok(`Config reset for ${bold(project.slug)}. Will use global defaults.`));
1064
+ console.log(ok(`Config reset for ${bold$1(project.slug)}. Will use global defaults.`));
1065
1065
  return;
1066
1066
  }
1067
1067
  if (opts.preset) {
1068
1068
  config = applyPreset(config, opts.preset);
1069
1069
  db.prepare("UPDATE projects SET session_config = ?, updated_at = ? WHERE id = ?").run(JSON.stringify(config), now(), project.id);
1070
- console.log(ok(`Applied preset ${bold(opts.preset)} to ${bold(project.slug)}`));
1070
+ console.log(ok(`Applied preset ${bold$1(opts.preset)} to ${bold$1(project.slug)}`));
1071
1071
  }
1072
1072
  if (opts.set?.length) {
1073
1073
  for (const pair of opts.set) {
@@ -1089,7 +1089,7 @@ function cmdConfig(db, identifier, opts) {
1089
1089
  else config[key] = parseConfigValue(key, value);
1090
1090
  }
1091
1091
  db.prepare("UPDATE projects SET session_config = ?, updated_at = ? WHERE id = ?").run(JSON.stringify(config), now(), project.id);
1092
- console.log(ok(`Config updated for ${bold(project.slug)}`));
1092
+ console.log(ok(`Config updated for ${bold$1(project.slug)}`));
1093
1093
  }
1094
1094
  if (opts.unset?.length) {
1095
1095
  for (const key of opts.unset) if (key.startsWith("env.")) {
@@ -1097,7 +1097,7 @@ function cmdConfig(db, identifier, opts) {
1097
1097
  if (config.env) delete config.env[envKey];
1098
1098
  } else delete config[key];
1099
1099
  db.prepare("UPDATE projects SET session_config = ?, updated_at = ? WHERE id = ?").run(JSON.stringify(config), now(), project.id);
1100
- console.log(ok(`Config updated for ${bold(project.slug)}`));
1100
+ console.log(ok(`Config updated for ${bold$1(project.slug)}`));
1101
1101
  }
1102
1102
  const effective = {
1103
1103
  ...getGlobalDefaults(),
@@ -1117,32 +1117,32 @@ function cmdConfig(db, identifier, opts) {
1117
1117
  }
1118
1118
  console.log();
1119
1119
  console.log(header(` Config: ${project.slug}`));
1120
- if (aliases.length) console.log(dim(` Names: ${aliases.join(", ")}`));
1121
- console.log(dim(` Path: ${project.root_path}`));
1120
+ if (aliases.length) console.log(dim$1(` Names: ${aliases.join(", ")}`));
1121
+ console.log(dim$1(` Path: ${project.root_path}`));
1122
1122
  console.log();
1123
- if (Object.keys(config).length === 0) console.log(dim(" No project-specific config. Using global defaults."));
1123
+ if (Object.keys(config).length === 0) console.log(dim$1(" No project-specific config. Using global defaults."));
1124
1124
  else {
1125
- console.log(bold(" Project config:"));
1125
+ console.log(bold$1(" Project config:"));
1126
1126
  for (const [key, value] of Object.entries(config)) {
1127
1127
  const display = typeof value === "object" ? JSON.stringify(value) : String(value);
1128
- console.log(` ${bold(key.padEnd(14))} ${display}`);
1128
+ console.log(` ${bold$1(key.padEnd(14))} ${display}`);
1129
1129
  }
1130
1130
  }
1131
1131
  const globalDefaults = getGlobalDefaults();
1132
1132
  if (Object.keys(globalDefaults).length > 0) {
1133
1133
  console.log();
1134
- console.log(dim(" Global defaults (overridden by project config):"));
1134
+ console.log(dim$1(" Global defaults (overridden by project config):"));
1135
1135
  for (const [key, value] of Object.entries(globalDefaults)) {
1136
1136
  const overridden = key in config;
1137
1137
  const display = typeof value === "object" ? JSON.stringify(value) : String(value);
1138
- console.log(` ${dim(key.padEnd(14))} ${overridden ? chalk.strikethrough(display) + " " + dim("(overridden)") : display}`);
1138
+ console.log(` ${dim$1(key.padEnd(14))} ${overridden ? chalk.strikethrough(display) + " " + dim$1("(overridden)") : display}`);
1139
1139
  }
1140
1140
  }
1141
1141
  console.log();
1142
- console.log(bold(" Effective (what AIBroker uses):"));
1142
+ console.log(bold$1(" Effective (what AIBroker uses):"));
1143
1143
  for (const [key, value] of Object.entries(effective)) {
1144
1144
  const display = typeof value === "object" ? JSON.stringify(value) : String(value);
1145
- console.log(` ${bold(key.padEnd(14))} ${display}`);
1145
+ console.log(` ${bold$1(key.padEnd(14))} ${display}`);
1146
1146
  }
1147
1147
  console.log();
1148
1148
  }
@@ -1226,12 +1226,12 @@ function cmdHealth$1(db, opts) {
1226
1226
  console.log(` ${chalk.green("Active:")} ${active.length} ${chalk.yellow("Stale (moved?):")} ${stale.length} ${chalk.red("Dead (missing):")} ${dead.length}`);
1227
1227
  console.log();
1228
1228
  if (active.length) {
1229
- console.log(bold(" Active projects (path exists):"));
1229
+ console.log(bold$1(" Active projects (path exists):"));
1230
1230
  const tableRows = active.map((r) => [
1231
- bold(r.project.slug),
1232
- dim(shortenPath(r.project.root_path, 50)),
1231
+ bold$1(r.project.slug),
1232
+ dim$1(shortenPath(r.project.root_path, 50)),
1233
1233
  String(r.project.session_count),
1234
- r.claudeNotesExists ? chalk.green("yes") : dim("no")
1234
+ r.claudeNotesExists ? chalk.green("yes") : dim$1("no")
1235
1235
  ]);
1236
1236
  console.log(renderTable([
1237
1237
  "Slug",
@@ -1244,8 +1244,8 @@ function cmdHealth$1(db, opts) {
1244
1244
  if (stale.length) {
1245
1245
  console.log(warn(" Stale projects (path missing, possible new location found):"));
1246
1246
  for (const r of stale) {
1247
- console.log(` ${bold(r.project.slug)}`);
1248
- console.log(dim(` Old path: ${r.project.root_path}`));
1247
+ console.log(` ${bold$1(r.project.slug)}`);
1248
+ console.log(dim$1(` Old path: ${r.project.root_path}`));
1249
1249
  console.log(chalk.cyan(` Found at: ${r.suggestedPath}`));
1250
1250
  if (r.claudeNotesExists) console.log(chalk.green(` Notes: ${r.orphanedNotesDirs.join(", ")}`));
1251
1251
  if (opts.fix && r.suggestedPath) {
@@ -1253,23 +1253,23 @@ function cmdHealth$1(db, opts) {
1253
1253
  const newEncoded = encodeDir(r.suggestedPath);
1254
1254
  db.prepare("UPDATE projects SET root_path = ?, encoded_dir = ?, updated_at = ? WHERE id = ?").run(r.suggestedPath, newEncoded, ts, r.project.id);
1255
1255
  console.log(ok(` Auto-fixed: updated path to ${r.suggestedPath}`));
1256
- } else if (r.suggestedPath) console.log(dim(` Fix: pai project move ${r.project.slug} ${r.suggestedPath}`));
1256
+ } else if (r.suggestedPath) console.log(dim$1(` Fix: pai project move ${r.project.slug} ${r.suggestedPath}`));
1257
1257
  }
1258
1258
  console.log();
1259
1259
  }
1260
1260
  if (dead.length) {
1261
1261
  console.log(err(" Dead projects (path missing, no match found):"));
1262
1262
  for (const r of dead) {
1263
- console.log(` ${bold(r.project.slug)} ${dim(r.project.root_path)}`);
1263
+ console.log(` ${bold$1(r.project.slug)} ${dim$1(r.project.root_path)}`);
1264
1264
  if (r.claudeNotesExists) console.log(chalk.yellow(` Notes: ${r.orphanedNotesDirs.join(", ")}`));
1265
1265
  if (r.project.session_count === 0 && opts.fix) {
1266
1266
  db.prepare("UPDATE projects SET status = 'archived', archived_at = ?, updated_at = ? WHERE id = ?").run(now(), now(), r.project.id);
1267
1267
  console.log(ok(" Auto-fixed: archived (0 sessions, path gone)"));
1268
- } else console.log(dim(` Fix: pai project archive ${r.project.slug} (or pai project move ...)`));
1268
+ } else console.log(dim$1(` Fix: pai project archive ${r.project.slug} (or pai project move ...)`));
1269
1269
  }
1270
1270
  console.log();
1271
1271
  }
1272
- console.log(dim(` ${rows.length} total: ${active.length} active, ${stale.length} stale, ${dead.length} dead`));
1272
+ console.log(dim$1(` ${rows.length} total: ${active.length} active, ${stale.length} stale, ${dead.length} dead`));
1273
1273
  if (!opts.fix && (stale.length > 0 || dead.length > 0)) {
1274
1274
  console.log();
1275
1275
  console.log(warn(" Run with --fix to auto-remediate where possible."));
@@ -1298,25 +1298,25 @@ function registerProjectsCommands(projectsCmd, getDb) {
1298
1298
  process.stdout.write(project.root_path + "\n");
1299
1299
  return;
1300
1300
  }
1301
- process.stderr.write(warn(`Path not found: ${project.root_path}\n`) + dim(" Searching for moved location...\n"));
1301
+ process.stderr.write(warn(`Path not found: ${project.root_path}\n`) + dim$1(" Searching for moved location...\n"));
1302
1302
  const result = findMovedPath(project.root_path);
1303
1303
  if (result.found) {
1304
1304
  const newPath = result.found;
1305
1305
  const newEncoded = encodeDir(newPath);
1306
1306
  const ts = now();
1307
1307
  db.prepare("UPDATE projects SET root_path = ?, encoded_dir = ?, updated_at = ? WHERE id = ?").run(newPath, newEncoded, ts, project.id);
1308
- process.stderr.write(ok(`Project moved: ${shortenPath(project.root_path, 50)}\n`) + dim(` → ${newPath}\n`) + ok("Registry updated.\n"));
1308
+ process.stderr.write(ok(`Project moved: ${shortenPath(project.root_path, 50)}\n`) + dim$1(` → ${newPath}\n`) + ok("Registry updated.\n"));
1309
1309
  process.stdout.write(newPath + "\n");
1310
1310
  return;
1311
1311
  }
1312
1312
  if (result.ambiguous) {
1313
1313
  process.stderr.write(warn(`Multiple directories named "${basename(project.root_path)}" found:\n`));
1314
- for (const candidate of result.ambiguous) process.stderr.write(dim(` ${candidate}\n`));
1315
- process.stderr.write(dim(`\n Disambiguate with: pai projects rebind ${project.slug} <path>\n`));
1314
+ for (const candidate of result.ambiguous) process.stderr.write(dim$1(` ${candidate}\n`));
1315
+ process.stderr.write(dim$1(`\n Disambiguate with: pai projects rebind ${project.slug} <path>\n`));
1316
1316
  process.exitCode = 1;
1317
1317
  return;
1318
1318
  }
1319
- process.stderr.write(err(`Project "${project.slug}" root_path "${project.root_path}" does not exist on disk\n and no folder named "${basename(project.root_path)}" was found in scan dirs.\n`) + dim(` Fix with: pai projects rebind ${project.slug} <new-path>\n`));
1319
+ process.stderr.write(err(`Project "${project.slug}" root_path "${project.root_path}" does not exist on disk\n and no folder named "${basename(project.root_path)}" was found in scan dirs.\n`) + dim$1(` Fix with: pai projects rebind ${project.slug} <new-path>\n`));
1320
1320
  process.exitCode = 1;
1321
1321
  });
1322
1322
  projectsCmd.command("add <path>").description("Register a project directory in the PAI registry").option("--slug <slug>", "Override auto-generated slug").option("--type <type>", "Project type: local | central | obsidian-linked | external", "local").option("--display-name <name>", "Human-readable display name").action((rawPath, opts) => {
@@ -1397,7 +1397,7 @@ function cmdMigrate$1(db) {
1397
1397
  console.log(warn("No projects found in session-registry.json."));
1398
1398
  return;
1399
1399
  }
1400
- console.log(dim(`Migrating ${projects.length} project(s) from session-registry.json ...`));
1400
+ console.log(dim$1(`Migrating ${projects.length} project(s) from session-registry.json ...`));
1401
1401
  let projectsNew = 0;
1402
1402
  let projectsSkipped = 0;
1403
1403
  let sessionsNew = 0;
@@ -1425,13 +1425,13 @@ function cmdMigrate$1(db) {
1425
1425
  }
1426
1426
  }
1427
1427
  console.log(ok("Migration complete."));
1428
- console.log(dim(` Projects: ${projectsNew} new, ${projectsSkipped} already existed`));
1429
- console.log(dim(` Sessions: ${sessionsNew} new`));
1428
+ console.log(dim$1(` Projects: ${projectsNew} new, ${projectsSkipped} already existed`));
1429
+ console.log(dim$1(` Sessions: ${sessionsNew} new`));
1430
1430
  if (errors.length) {
1431
1431
  console.log();
1432
1432
  console.log(warn(` ${errors.length} error(s) during migration:`));
1433
- for (const e of errors.slice(0, 5)) console.log(dim(` ${e}`));
1434
- if (errors.length > 5) console.log(dim(` ... and ${errors.length - 5} more`));
1433
+ for (const e of errors.slice(0, 5)) console.log(dim$1(` ${e}`));
1434
+ if (errors.length > 5) console.log(dim$1(` ... and ${errors.length - 5} more`));
1435
1435
  }
1436
1436
  }
1437
1437
 
@@ -1446,20 +1446,20 @@ function cmdStats$2(db) {
1446
1446
  const lastProject = db.prepare("SELECT updated_at FROM projects ORDER BY updated_at DESC LIMIT 1").get();
1447
1447
  const lastSession = db.prepare("SELECT created_at FROM sessions ORDER BY created_at DESC LIMIT 1").get();
1448
1448
  console.log();
1449
- console.log(bold(" PAI Registry Stats"));
1449
+ console.log(bold$1(" PAI Registry Stats"));
1450
1450
  console.log();
1451
- console.log(` ${bold("Projects:")} ${totalProjects}`);
1452
- console.log(` ${bold(" Active:")} ${activeProjects}`);
1453
- console.log(` ${bold(" Archived:")} ${archivedProjects}`);
1454
- console.log(` ${bold("Sessions:")} ${totalSessions}`);
1455
- console.log(` ${bold("Tags:")} ${totalTags}`);
1456
- if (lastProject) console.log(` ${bold("Last updated:")} ${fmtDate(lastProject.updated_at)}`);
1457
- if (lastSession) console.log(` ${bold("Last session:")} ${fmtDate(lastSession.created_at)}`);
1451
+ console.log(` ${bold$1("Projects:")} ${totalProjects}`);
1452
+ console.log(` ${bold$1(" Active:")} ${activeProjects}`);
1453
+ console.log(` ${bold$1(" Archived:")} ${archivedProjects}`);
1454
+ console.log(` ${bold$1("Sessions:")} ${totalSessions}`);
1455
+ console.log(` ${bold$1("Tags:")} ${totalTags}`);
1456
+ if (lastProject) console.log(` ${bold$1("Last updated:")} ${fmtDate(lastProject.updated_at)}`);
1457
+ if (lastSession) console.log(` ${bold$1("Last session:")} ${fmtDate(lastSession.created_at)}`);
1458
1458
  console.log();
1459
1459
  }
1460
1460
  function cmdRebuild(db) {
1461
1461
  console.log(warn("Rebuilding registry — all existing data will be erased."));
1462
- console.log(dim("Clearing all tables ..."));
1462
+ console.log(dim$1("Clearing all tables ..."));
1463
1463
  db.exec(`
1464
1464
  DELETE FROM compaction_log;
1465
1465
  DELETE FROM session_tags;
@@ -1470,7 +1470,7 @@ function cmdRebuild(db) {
1470
1470
  DELETE FROM tags;
1471
1471
  DELETE FROM schema_version;
1472
1472
  `);
1473
- console.log(dim("Registry cleared. Re-scanning ..."));
1473
+ console.log(dim$1("Registry cleared. Re-scanning ..."));
1474
1474
  cmdScan(db);
1475
1475
  }
1476
1476
  function cmdLookup(db, fsPath) {
@@ -1484,10 +1484,10 @@ function registerRegistryCommands(registryCmd, getDb) {
1484
1484
  if (opts.showDirs) {
1485
1485
  const config = loadScanConfig();
1486
1486
  if (!config.scan_dirs.length) {
1487
- console.log(dim(" No extra scan directories configured."));
1488
- console.log(dim(" Use --add-dir <path> to add one."));
1487
+ console.log(dim$1(" No extra scan directories configured."));
1488
+ console.log(dim$1(" Use --add-dir <path> to add one."));
1489
1489
  } else {
1490
- console.log(bold(" Configured scan directories:"));
1490
+ console.log(bold$1(" Configured scan directories:"));
1491
1491
  for (const d of config.scan_dirs) console.log(` ${d}`);
1492
1492
  }
1493
1493
  return;
@@ -1504,7 +1504,7 @@ function registerRegistryCommands(registryCmd, getDb) {
1504
1504
  else {
1505
1505
  config.scan_dirs.push(display);
1506
1506
  saveScanConfig(config);
1507
- console.log(ok(`Added scan directory: ${bold(display)}`));
1507
+ console.log(ok(`Added scan directory: ${bold$1(display)}`));
1508
1508
  }
1509
1509
  }
1510
1510
  if (opts.removeDir) {
@@ -1515,7 +1515,7 @@ function registerRegistryCommands(registryCmd, getDb) {
1515
1515
  config.scan_dirs = config.scan_dirs.filter((d) => resolveHome(d) !== resolved);
1516
1516
  if (config.scan_dirs.length < before) {
1517
1517
  saveScanConfig(config);
1518
- console.log(ok(`Removed scan directory: ${bold(display)}`));
1518
+ console.log(ok(`Removed scan directory: ${bold$1(display)}`));
1519
1519
  } else console.log(warn(`Not found in config: ${display}`));
1520
1520
  }
1521
1521
  if (!opts.addDir && !opts.removeDir) cmdScan(getDb(), { quick: opts.quick });
@@ -1538,12 +1538,12 @@ function registerRegistryCommands(registryCmd, getDb) {
1538
1538
  //#region src/cli/commands/memory/embed.ts
1539
1539
  async function runEmbed(federation, projectId, projectSlug, batchSize = 50) {
1540
1540
  const label = projectSlug ? `project ${projectSlug}` : "all projects";
1541
- console.log(dim(`Generating embeddings for ${label} (this may take a while on first run)...`));
1541
+ console.log(dim$1(`Generating embeddings for ${label} (this may take a while on first run)...`));
1542
1542
  const { chunksEmbedded } = await embedChunks(federation, projectId, batchSize, (done, total) => {
1543
1543
  process.stdout.write(`\r ${done} / ${total} chunks embedded...`);
1544
1544
  });
1545
1545
  process.stdout.write("\r");
1546
- console.log(ok(`Done.`) + ` ${bold(String(chunksEmbedded))} chunks embedded`);
1546
+ console.log(ok(`Done.`) + ` ${bold$1(String(chunksEmbedded))} chunks embedded`);
1547
1547
  }
1548
1548
  function registerEmbedCommand(memoryCmd, getDb) {
1549
1549
  memoryCmd.command("embed [project-slug]").description("Generate embeddings for un-embedded chunks (Phase 2.5)").option("--batch-size <n>", "Chunks to embed per batch", "50").action(async (projectSlug, opts) => {
@@ -1573,11 +1573,11 @@ function registerIndexCommand(memoryCmd, getDb) {
1573
1573
  const registryDb = getDb();
1574
1574
  if (!opts.direct && !projectSlug) try {
1575
1575
  await new PaiClient(loadConfig().socketPath).triggerIndex();
1576
- console.log(ok("Index triggered in daemon.") + dim(" Check daemon logs for progress."));
1577
- console.log(dim(" Run `pai daemon logs` to watch progress."));
1576
+ console.log(ok("Index triggered in daemon.") + dim$1(" Check daemon logs for progress."));
1577
+ console.log(dim$1(" Run `pai daemon logs` to watch progress."));
1578
1578
  return;
1579
1579
  } catch {
1580
- console.log(dim("Daemon not running. Running direct index..."));
1580
+ console.log(dim$1("Daemon not running. Running direct index..."));
1581
1581
  }
1582
1582
  let federation;
1583
1583
  try {
@@ -1592,14 +1592,14 @@ function registerIndexCommand(memoryCmd, getDb) {
1592
1592
  console.error(err(`Project not found or not active: ${projectSlug}`));
1593
1593
  process.exit(1);
1594
1594
  }
1595
- console.log(dim(`Indexing ${project.display_name} (${project.slug})...`));
1595
+ console.log(dim$1(`Indexing ${project.display_name} (${project.slug})...`));
1596
1596
  const result = await indexProject(federation, project.id, project.root_path);
1597
- console.log(ok(`Done.`) + ` ${bold(String(result.filesProcessed))} files indexed, ${bold(String(result.chunksCreated))} chunks created, ${dim(String(result.filesSkipped) + " skipped (unchanged)")}`);
1597
+ console.log(ok(`Done.`) + ` ${bold$1(String(result.filesProcessed))} files indexed, ${bold$1(String(result.chunksCreated))} chunks created, ${dim$1(String(result.filesSkipped) + " skipped (unchanged)")}`);
1598
1598
  if (opts.embed) await runEmbed(federation, project.id, project.slug);
1599
1599
  } else if (opts.all || !projectSlug) {
1600
- console.log(dim("Indexing all active projects..."));
1600
+ console.log(dim$1("Indexing all active projects..."));
1601
1601
  const { projects, result } = await indexAll(federation, registryDb);
1602
- console.log(ok(`Done.`) + ` ${bold(String(projects))} projects, ${bold(String(result.filesProcessed))} files indexed, ${bold(String(result.chunksCreated))} chunks created, ${dim(String(result.filesSkipped) + " skipped (unchanged)")}`);
1602
+ console.log(ok(`Done.`) + ` ${bold$1(String(projects))} projects, ${bold$1(String(result.filesProcessed))} files indexed, ${bold$1(String(result.chunksCreated))} chunks created, ${dim$1(String(result.filesSkipped) + " skipped (unchanged)")}`);
1603
1603
  if (opts.embed) await runEmbed(federation);
1604
1604
  }
1605
1605
  });
@@ -1656,7 +1656,7 @@ function registerSearchCommand(memoryCmd, getDb) {
1656
1656
  const backend = await createStorageBackend(config);
1657
1657
  try {
1658
1658
  const { generateEmbedding } = await import("./embeddings-BJPOcbik.mjs").then((n) => n.i);
1659
- console.log(dim("Generating query embedding..."));
1659
+ console.log(dim$1("Generating query embedding..."));
1660
1660
  const queryEmbedding = await generateEmbedding(query, true);
1661
1661
  if (mode === "semantic") results = await backend.searchSemantic(queryEmbedding, searchOpts);
1662
1662
  else {
@@ -1700,29 +1700,29 @@ function registerSearchCommand(memoryCmd, getDb) {
1700
1700
  }
1701
1701
  } else results = [];
1702
1702
  if (!results || results.length === 0) {
1703
- console.log(dim(`No results found for: "${query}" (mode: ${mode})`));
1703
+ console.log(dim$1(`No results found for: "${query}" (mode: ${mode})`));
1704
1704
  return;
1705
1705
  }
1706
1706
  if (opts.rerank !== false) {
1707
1707
  const { rerankResults } = await import("./reranker-C08R99zn.mjs").then((n) => n.r);
1708
- console.log(dim("Reranking with cross-encoder..."));
1708
+ console.log(dim$1("Reranking with cross-encoder..."));
1709
1709
  results = await rerankResults(query, results, { topK: maxResults });
1710
1710
  }
1711
1711
  const recencyDays = parseInt(opts.recency ?? String(searchConfig.recencyBoostDays), 10);
1712
1712
  if (recencyDays > 0) {
1713
1713
  const { applyRecencyBoost } = await import("./search-HcdKtMla.mjs").then((n) => n.o);
1714
- console.log(dim(`Applying recency boost (half-life: ${recencyDays} days)...`));
1714
+ console.log(dim$1(`Applying recency boost (half-life: ${recencyDays} days)...`));
1715
1715
  results = applyRecencyBoost(results, recencyDays);
1716
1716
  }
1717
1717
  const withSlugs = populateSlugs(results, registryDb);
1718
1718
  const rerankLabel = opts.rerank !== false ? " +rerank" : "";
1719
1719
  const modeLabel = mode !== "keyword" ? ` [${mode}${rerankLabel}]` : opts.rerank !== false ? ` [rerank]` : "";
1720
- console.log(`\n ${bold(`Search results for: "${query}"`)}${modeLabel} ${dim(`(${withSlugs.length} found)`)}\n`);
1720
+ console.log(`\n ${bold$1(`Search results for: "${query}"`)}${modeLabel} ${dim$1(`(${withSlugs.length} found)`)}\n`);
1721
1721
  for (const result of withSlugs) {
1722
1722
  const projectLabel = result.projectSlug ? chalk.cyan(result.projectSlug) : chalk.cyan(String(result.projectId));
1723
1723
  const tierLabel = tierColor$1(result.tier);
1724
- const scoreLabel = dim(`score: ${result.score.toFixed(4)}`);
1725
- const locationLabel = dim(`${result.path}:${result.startLine}-${result.endLine}`);
1724
+ const scoreLabel = dim$1(`score: ${result.score.toFixed(4)}`);
1725
+ const locationLabel = dim$1(`${result.path}:${result.startLine}-${result.endLine}`);
1726
1726
  console.log(` ${projectLabel} ${tierLabel} ${locationLabel} ${scoreLabel}`);
1727
1727
  const snippetLines = result.snippet.split("\n").slice(0, 3).map((l) => ` ${l}`);
1728
1728
  console.log(snippetLines.join("\n"));
@@ -1762,12 +1762,12 @@ function registerStatsCommands(memoryCmd, getDb) {
1762
1762
  const chunkStats = federation.prepare("SELECT COUNT(*) as chunks FROM memory_chunks WHERE project_id = ?").get(project.id);
1763
1763
  const lastUpdate = federation.prepare("SELECT MAX(updated_at) as last_at FROM memory_chunks WHERE project_id = ?").get(project.id);
1764
1764
  const tierBreakdown = federation.prepare("SELECT tier, COUNT(*) as n FROM memory_chunks WHERE project_id = ? GROUP BY tier ORDER BY n DESC").all(project.id);
1765
- console.log(`\n ${bold(project.display_name)} ${dim(`(${project.slug})`)}\n`);
1766
- console.log(` ${bold("Files indexed:")} ${fileStats.files}`);
1767
- console.log(` ${bold("Chunks:")} ${chunkStats.chunks}`);
1768
- console.log(` ${bold("Last indexed:")} ${lastUpdate.last_at ? fmtDate(lastUpdate.last_at) : dim("never")}`);
1765
+ console.log(`\n ${bold$1(project.display_name)} ${dim$1(`(${project.slug})`)}\n`);
1766
+ console.log(` ${bold$1("Files indexed:")} ${fileStats.files}`);
1767
+ console.log(` ${bold$1("Chunks:")} ${chunkStats.chunks}`);
1768
+ console.log(` ${bold$1("Last indexed:")} ${lastUpdate.last_at ? fmtDate(lastUpdate.last_at) : dim$1("never")}`);
1769
1769
  if (tierBreakdown.length > 0) {
1770
- console.log(`\n ${bold("By tier:")}`);
1770
+ console.log(`\n ${bold$1("By tier:")}`);
1771
1771
  for (const row of tierBreakdown) console.log(` ${tierColor(row.tier).padEnd(20)} ${row.n} chunks`);
1772
1772
  }
1773
1773
  console.log();
@@ -1791,16 +1791,16 @@ function registerStatsCommands(memoryCmd, getDb) {
1791
1791
  const slugRows = registryDb.prepare(`SELECT id, slug, display_name FROM projects WHERE id IN (${placeholders})`).all(...projectIds);
1792
1792
  for (const row of slugRows) slugMap.set(row.id, row.slug);
1793
1793
  }
1794
- console.log(`\n ${bold("PAI Memory Index — Global Status")}\n`);
1795
- console.log(` ${bold("Total files:")} ${globalFiles.n} ${bold("Total chunks:")} ${globalChunks.n}`);
1796
- console.log(` ${bold("Last indexed:")} ${lastUpdate.last_at ? fmtDate(lastUpdate.last_at) : dim("never")}`);
1794
+ console.log(`\n ${bold$1("PAI Memory Index — Global Status")}\n`);
1795
+ console.log(` ${bold$1("Total files:")} ${globalFiles.n} ${bold$1("Total chunks:")} ${globalChunks.n}`);
1796
+ console.log(` ${bold$1("Last indexed:")} ${lastUpdate.last_at ? fmtDate(lastUpdate.last_at) : dim$1("never")}`);
1797
1797
  if (projectStats.length > 0) {
1798
1798
  console.log();
1799
1799
  const rows = projectStats.map((p) => [
1800
1800
  chalk.cyan(slugMap.get(p.project_id) ?? String(p.project_id)),
1801
1801
  String(p.files),
1802
1802
  String(p.chunks),
1803
- p.last_at ? fmtDate(p.last_at) : dim("never")
1803
+ p.last_at ? fmtDate(p.last_at) : dim$1("never")
1804
1804
  ]);
1805
1805
  console.log(renderTable([
1806
1806
  "Project",
@@ -1808,22 +1808,22 @@ function registerStatsCommands(memoryCmd, getDb) {
1808
1808
  "Chunks",
1809
1809
  "Last Indexed"
1810
1810
  ], rows));
1811
- } else console.log(dim("\n No projects indexed yet. Run `pai memory index --all` to start."));
1811
+ } else console.log(dim$1("\n No projects indexed yet. Run `pai memory index --all` to start."));
1812
1812
  console.log();
1813
1813
  }
1814
1814
  });
1815
1815
  memoryCmd.command("settings [key] [value]").description("View or modify search settings in ~/.config/pai/config.json").action((key, value) => {
1816
1816
  const search = loadConfig().search;
1817
1817
  if (!key) {
1818
- console.log(`\n ${bold("PAI Memory — Search Settings")}\n`);
1819
- console.log(` ${bold("mode:")} ${search.mode}`);
1820
- console.log(` ${bold("rerank:")} ${search.rerank}`);
1821
- console.log(` ${bold("recencyBoostDays:")} ${search.recencyBoostDays}`);
1822
- console.log(` ${bold("defaultLimit:")} ${search.defaultLimit}`);
1823
- console.log(` ${bold("snippetLength:")} ${search.snippetLength}`);
1818
+ console.log(`\n ${bold$1("PAI Memory — Search Settings")}\n`);
1819
+ console.log(` ${bold$1("mode:")} ${search.mode}`);
1820
+ console.log(` ${bold$1("rerank:")} ${search.rerank}`);
1821
+ console.log(` ${bold$1("recencyBoostDays:")} ${search.recencyBoostDays}`);
1822
+ console.log(` ${bold$1("defaultLimit:")} ${search.defaultLimit}`);
1823
+ console.log(` ${bold$1("snippetLength:")} ${search.snippetLength}`);
1824
1824
  console.log();
1825
- console.log(dim(` Config file: ${CONFIG_FILE$2}`));
1826
- console.log(dim(` Edit directly or use: pai memory settings <key> <value>`));
1825
+ console.log(dim$1(` Config file: ${CONFIG_FILE$2}`));
1826
+ console.log(dim$1(` Edit directly or use: pai memory settings <key> <value>`));
1827
1827
  console.log();
1828
1828
  return;
1829
1829
  }
@@ -1831,7 +1831,7 @@ function registerStatsCommands(memoryCmd, getDb) {
1831
1831
  const val = search[key];
1832
1832
  if (val === void 0) {
1833
1833
  console.error(err(`Unknown setting: ${key}`));
1834
- console.log(dim(` Valid keys: mode, rerank, recencyBoostDays, defaultLimit, snippetLength`));
1834
+ console.log(dim$1(` Valid keys: mode, rerank, recencyBoostDays, defaultLimit, snippetLength`));
1835
1835
  process.exit(1);
1836
1836
  }
1837
1837
  console.log(String(val));
@@ -1846,7 +1846,7 @@ function registerStatsCommands(memoryCmd, getDb) {
1846
1846
  ]);
1847
1847
  if (!validKeys.has(key)) {
1848
1848
  console.error(err(`Unknown setting: ${key}`));
1849
- console.log(dim(` Valid keys: ${[...validKeys].join(", ")}`));
1849
+ console.log(dim$1(` Valid keys: ${[...validKeys].join(", ")}`));
1850
1850
  process.exit(1);
1851
1851
  }
1852
1852
  let fileConfig = {};
@@ -1881,7 +1881,7 @@ function registerStatsCommands(memoryCmd, getDb) {
1881
1881
  ensureConfigDir();
1882
1882
  writeFileSync(CONFIG_FILE$2, JSON.stringify(fileConfig, null, 2) + "\n", "utf-8");
1883
1883
  console.log(ok(`Set search.${key} = ${parsed}`));
1884
- console.log(dim(` Restart daemon to apply: pai daemon restart`));
1884
+ console.log(dim$1(` Restart daemon to apply: pai daemon restart`));
1885
1885
  } catch (e) {
1886
1886
  console.error(err(`Could not write config: ${e}`));
1887
1887
  process.exit(1);
@@ -1930,8 +1930,8 @@ function cmdInstall$1() {
1930
1930
  const servers = config.mcpServers;
1931
1931
  if ("pai" in servers) {
1932
1932
  console.log(warn("PAI MCP server is already registered in ~/.claude.json."));
1933
- console.log(dim(` Entry: ${JSON.stringify(servers["pai"])}`));
1934
- console.log(dim(" Use `pai mcp status` to verify the configuration."));
1933
+ console.log(dim$1(` Entry: ${JSON.stringify(servers["pai"])}`));
1934
+ console.log(dim$1(" Use `pai mcp status` to verify the configuration."));
1935
1935
  return;
1936
1936
  }
1937
1937
  servers["pai"] = {
@@ -1945,15 +1945,15 @@ function cmdInstall$1() {
1945
1945
  process.exit(1);
1946
1946
  }
1947
1947
  console.log(ok("PAI MCP server registered in ~/.claude.json."));
1948
- console.log(dim(` Binary: ${mcpBin}`));
1949
- console.log(dim(""));
1950
- console.log(dim(" Restart Claude Code to activate the PAI MCP tools:"));
1951
- console.log(dim(" memory_search, memory_get, project_info,"));
1952
- console.log(dim(" project_list, session_list, registry_search"));
1948
+ console.log(dim$1(` Binary: ${mcpBin}`));
1949
+ console.log(dim$1(""));
1950
+ console.log(dim$1(" Restart Claude Code to activate the PAI MCP tools:"));
1951
+ console.log(dim$1(" memory_search, memory_get, project_info,"));
1952
+ console.log(dim$1(" project_list, session_list, registry_search"));
1953
1953
  if (!existsSync(mcpBin)) {
1954
1954
  console.log();
1955
1955
  console.log(warn(` Note: MCP binary not found at ${mcpBin}`));
1956
- console.log(dim(" Run `bun run build` to compile it first."));
1956
+ console.log(dim$1(" Run `bun run build` to compile it first."));
1957
1957
  }
1958
1958
  }
1959
1959
  function cmdStatus$3() {
@@ -1963,26 +1963,26 @@ function cmdStatus$3() {
1963
1963
  const registered = "pai" in servers;
1964
1964
  const binExists = existsSync(mcpBin);
1965
1965
  console.log();
1966
- console.log(bold(" PAI MCP Server Status"));
1966
+ console.log(bold$1(" PAI MCP Server Status"));
1967
1967
  console.log();
1968
1968
  if (registered) {
1969
1969
  const entry = servers["pai"];
1970
1970
  console.log(ok(` Registered in ~/.claude.json`));
1971
- console.log(dim(` Config: ${JSON.stringify(entry)}`));
1971
+ console.log(dim$1(` Config: ${JSON.stringify(entry)}`));
1972
1972
  } else {
1973
1973
  console.log(warn(` NOT registered in ~/.claude.json`));
1974
- console.log(dim(` Run: pai mcp install`));
1974
+ console.log(dim$1(` Run: pai mcp install`));
1975
1975
  }
1976
1976
  console.log();
1977
1977
  if (binExists) console.log(ok(` MCP binary found: ${mcpBin}`));
1978
1978
  else {
1979
1979
  console.log(warn(` MCP binary NOT found: ${mcpBin}`));
1980
- console.log(dim(" Run: bun run build"));
1980
+ console.log(dim$1(" Run: bun run build"));
1981
1981
  }
1982
1982
  console.log();
1983
- if (registered && binExists) console.log(dim(" Status: READY — restart Claude Code to use PAI tools"));
1983
+ if (registered && binExists) console.log(dim$1(" Status: READY — restart Claude Code to use PAI tools"));
1984
1984
  else if (registered && !binExists) console.log(warn(" Status: NEEDS BUILD — run `bun run build`"));
1985
- else console.log(dim(" Status: NOT INSTALLED — run `pai mcp install`"));
1985
+ else console.log(dim$1(" Status: NOT INSTALLED — run `pai mcp install`"));
1986
1986
  console.log();
1987
1987
  }
1988
1988
  function registerMcpCommands(mcpCmd) {
@@ -2073,16 +2073,16 @@ async function cmdStatus$2() {
2073
2073
  try {
2074
2074
  const s = await client.status();
2075
2075
  console.log();
2076
- console.log(bold(" PAI Daemon Status"));
2076
+ console.log(bold$1(" PAI Daemon Status"));
2077
2077
  console.log();
2078
2078
  console.log(ok(` Daemon running`));
2079
- console.log(dim(` Uptime: ${s["uptime"]}s`));
2080
- console.log(dim(` Socket: ${s["socketPath"]}`));
2081
- console.log(dim(` Index: ${s["indexInProgress"] ? "in progress" : "idle"} (interval: ${s["indexIntervalSecs"]}s)`));
2082
- if (s["lastIndexTime"]) console.log(dim(` Last index: ${s["lastIndexTime"]}`));
2079
+ console.log(dim$1(` Uptime: ${s["uptime"]}s`));
2080
+ console.log(dim$1(` Socket: ${s["socketPath"]}`));
2081
+ console.log(dim$1(` Index: ${s["indexInProgress"] ? "in progress" : "idle"} (interval: ${s["indexIntervalSecs"]}s)`));
2082
+ if (s["lastIndexTime"]) console.log(dim$1(` Last index: ${s["lastIndexTime"]}`));
2083
2083
  if (s["db"]) {
2084
2084
  const db = s["db"];
2085
- console.log(dim(` DB: ${db["projects"]} projects, ${db["files"]} files, ${db["chunks"]} chunks`));
2085
+ console.log(dim$1(` DB: ${db["projects"]} projects, ${db["files"]} files, ${db["chunks"]} chunks`));
2086
2086
  }
2087
2087
  console.log();
2088
2088
  } catch (e) {
@@ -2091,8 +2091,8 @@ async function cmdStatus$2() {
2091
2091
  console.log(warn(" PAI Daemon Status"));
2092
2092
  console.log();
2093
2093
  console.log(warn(` Daemon not running: ${msg}`));
2094
- console.log(dim(" Start with: pai daemon serve"));
2095
- console.log(dim(" Or install as service: pai daemon install"));
2094
+ console.log(dim$1(" Start with: pai daemon serve"));
2095
+ console.log(dim$1(" Or install as service: pai daemon install"));
2096
2096
  console.log();
2097
2097
  process.exit(1);
2098
2098
  }
@@ -2107,7 +2107,7 @@ function cmdRestart() {
2107
2107
  "-k",
2108
2108
  `gui/${process.getuid?.() ?? 501}/${PLIST_LABEL}`
2109
2109
  ], { encoding: "utf8" }).status === 0) console.log(ok("Sent kickstart to launchd."));
2110
- else console.log(dim("Not managed by launchd either. Run: pai daemon serve"));
2110
+ else console.log(dim$1("Not managed by launchd either. Run: pai daemon serve"));
2111
2111
  return;
2112
2112
  }
2113
2113
  const pids = result.stdout.trim().split("\n").map((p) => p.trim());
@@ -2117,7 +2117,7 @@ function cmdRestart() {
2117
2117
  } catch {
2118
2118
  console.log(warn(`Could not signal pid ${pid}.`));
2119
2119
  }
2120
- console.log(dim("launchd will restart the daemon automatically."));
2120
+ console.log(dim$1("launchd will restart the daemon automatically."));
2121
2121
  } catch (e) {
2122
2122
  const msg = e instanceof Error ? e.message : String(e);
2123
2123
  console.error(err(`restart error: ${msg}`));
@@ -2128,7 +2128,7 @@ function cmdInstall() {
2128
2128
  const daemonBin = getDaemonBinPath();
2129
2129
  const shimBin = getShimBinPath();
2130
2130
  console.log();
2131
- console.log(bold(" PAI Daemon Install"));
2131
+ console.log(bold$1(" PAI Daemon Install"));
2132
2132
  console.log();
2133
2133
  if (!existsSync(LAUNCH_AGENTS_DIR)) mkdirSync(LAUNCH_AGENTS_DIR, { recursive: true });
2134
2134
  const plistContent = generatePlist(daemonBin);
@@ -2146,7 +2146,7 @@ function cmdInstall() {
2146
2146
  else console.log(warn(` launchctl load: ${loadResult.stderr?.trim() ?? "unknown error"}`));
2147
2147
  } catch {
2148
2148
  console.log(warn(" Could not run launchctl. Load manually:"));
2149
- console.log(dim(` launchctl load ${PLIST_PATH}`));
2149
+ console.log(dim$1(` launchctl load ${PLIST_PATH}`));
2150
2150
  }
2151
2151
  const config = readClaudeJson();
2152
2152
  if (typeof config.mcpServers !== "object" || config.mcpServers === null) config.mcpServers = {};
@@ -2156,7 +2156,7 @@ function cmdInstall() {
2156
2156
  else {
2157
2157
  if (existing) {
2158
2158
  servers["pai-legacy"] = existing;
2159
- console.log(dim(" Backed up existing 'pai' entry as 'pai-legacy'."));
2159
+ console.log(dim$1(" Backed up existing 'pai' entry as 'pai-legacy'."));
2160
2160
  }
2161
2161
  servers["pai"] = {
2162
2162
  command: "node",
@@ -2173,19 +2173,19 @@ function cmdInstall() {
2173
2173
  console.log();
2174
2174
  if (!existsSync(daemonBin)) {
2175
2175
  console.log(warn(` Daemon binary not found: ${daemonBin}`));
2176
- console.log(dim(" Run: bun run build"));
2176
+ console.log(dim$1(" Run: bun run build"));
2177
2177
  } else console.log(ok(` Daemon binary: ${daemonBin}`));
2178
2178
  if (!existsSync(shimBin)) {
2179
2179
  console.log(warn(` Shim binary not found: ${shimBin}`));
2180
- console.log(dim(" Run: bun run build"));
2180
+ console.log(dim$1(" Run: bun run build"));
2181
2181
  } else console.log(ok(` Shim binary: ${shimBin}`));
2182
2182
  console.log();
2183
- console.log(dim(" Restart Claude Code to activate the daemon-backed PAI tools."));
2183
+ console.log(dim$1(" Restart Claude Code to activate the daemon-backed PAI tools."));
2184
2184
  console.log();
2185
2185
  }
2186
2186
  function cmdUninstall() {
2187
2187
  console.log();
2188
- console.log(bold(" PAI Daemon Uninstall"));
2188
+ console.log(bold$1(" PAI Daemon Uninstall"));
2189
2189
  console.log();
2190
2190
  if (existsSync(PLIST_PATH)) {
2191
2191
  try {
@@ -2200,7 +2200,7 @@ function cmdUninstall() {
2200
2200
  } catch (e) {
2201
2201
  console.log(warn(` Could not remove plist: ${e}`));
2202
2202
  }
2203
- } else console.log(dim(" No launchd plist found."));
2203
+ } else console.log(dim$1(" No launchd plist found."));
2204
2204
  const config = readClaudeJson();
2205
2205
  const servers = typeof config.mcpServers === "object" && config.mcpServers !== null ? config.mcpServers : {};
2206
2206
  const legacy = servers["pai-legacy"];
@@ -2213,16 +2213,16 @@ function cmdUninstall() {
2213
2213
  } catch (e) {
2214
2214
  console.log(warn(` Could not update ~/.claude.json: ${e}`));
2215
2215
  }
2216
- } else console.log(dim(" No legacy PAI entry found in ~/.claude.json."));
2216
+ } else console.log(dim$1(" No legacy PAI entry found in ~/.claude.json."));
2217
2217
  console.log();
2218
- console.log(dim(" Restart Claude Code to deactivate daemon-backed tools."));
2218
+ console.log(dim$1(" Restart Claude Code to deactivate daemon-backed tools."));
2219
2219
  console.log();
2220
2220
  }
2221
2221
  async function cmdMigrate(connectionString) {
2222
2222
  console.log();
2223
- console.log(bold(" PAI Daemon Migrate"));
2223
+ console.log(bold$1(" PAI Daemon Migrate"));
2224
2224
  console.log();
2225
- console.log(dim(" Running SQLite → PostgreSQL migration..."));
2225
+ console.log(dim$1(" Running SQLite → PostgreSQL migration..."));
2226
2226
  console.log();
2227
2227
  const { fileURLToPath } = await import("node:url");
2228
2228
  const { dirname: pathDirname, join: pathJoin } = await import("node:path");
@@ -2243,7 +2243,7 @@ function cmdLogs(opts) {
2243
2243
  const lines = opts.lines ?? "50";
2244
2244
  if (!existsSync(DAEMON_LOG)) {
2245
2245
  console.log(warn(`No daemon log found at ${DAEMON_LOG}.`));
2246
- console.log(dim("The daemon may not have run yet."));
2246
+ console.log(dim$1("The daemon may not have run yet."));
2247
2247
  return;
2248
2248
  }
2249
2249
  if (opts.follow) try {
@@ -2259,8 +2259,8 @@ function cmdLogs(opts) {
2259
2259
  }
2260
2260
  function registerDaemonCommands(daemonCmd) {
2261
2261
  daemonCmd.command("serve").description("Start the PAI daemon in the foreground").action(async () => {
2262
- const { serve } = await import("./daemon-Ca7YXHUW.mjs").then((n) => n.t);
2263
- const { loadConfig: lc, ensureConfigDir } = await import("./config-BuhHWyOK.mjs").then((n) => n.r);
2262
+ const { serve } = await import("./daemon-D2aKb4mJ.mjs").then((n) => n.t);
2263
+ const { loadConfig: lc, ensureConfigDir } = await import("./config-C8m-tPhP.mjs").then((n) => n.r);
2264
2264
  ensureConfigDir();
2265
2265
  await serve(lc());
2266
2266
  });
@@ -2312,7 +2312,7 @@ function fileSize(path) {
2312
2312
  function registerBackupCommands(program) {
2313
2313
  program.command("backup").description("Backup registry, config, and Postgres database to ~/.pai/backups/").option("--no-postgres", "Skip the Postgres pg_dump (faster, registry+config only)").action(async (opts) => {
2314
2314
  const backupDir = join(BACKUPS_DIR$1, timestamp());
2315
- console.log(dim(`Creating backup: ${backupDir}`));
2315
+ console.log(dim$1(`Creating backup: ${backupDir}`));
2316
2316
  mkdirSync(backupDir, { recursive: true });
2317
2317
  const results = [];
2318
2318
  if (existsSync(REGISTRY_DB$1)) {
@@ -2385,7 +2385,7 @@ function registerBackupCommands(program) {
2385
2385
  }
2386
2386
  if (opts.postgres) {
2387
2387
  const sqlDest = join(backupDir, "postgres-pai.sql");
2388
- console.log(dim(` Running pg_dump on ${DOCKER_CONTAINER$1} (this may take a moment)...`));
2388
+ console.log(dim$1(` Running pg_dump on ${DOCKER_CONTAINER$1} (this may take a moment)...`));
2389
2389
  try {
2390
2390
  execSync(`docker inspect ${DOCKER_CONTAINER$1} --format='{{.State.Status}}'`, { stdio: "pipe" });
2391
2391
  execSync(`docker exec ${DOCKER_CONTAINER$1} pg_dump -U ${PG_USER$1} ${PG_DATABASE$1} > "${sqlDest}"`, {
@@ -2416,16 +2416,16 @@ function registerBackupCommands(program) {
2416
2416
  label: "Postgres DB",
2417
2417
  path: "-",
2418
2418
  size: "-",
2419
- status: dim("skipped (--no-postgres)")
2419
+ status: dim$1("skipped (--no-postgres)")
2420
2420
  });
2421
- console.log(`\n${bold("Backup complete:")} ${backupDir}\n`);
2421
+ console.log(`\n${bold$1("Backup complete:")} ${backupDir}\n`);
2422
2422
  const labelWidth = Math.max(...results.map((r) => r.label.length)) + 2;
2423
2423
  for (const r of results) {
2424
2424
  const label = r.label.padEnd(labelWidth);
2425
- console.log(` ${bold(label)} ${r.status} ${dim(r.size)}`);
2425
+ console.log(` ${bold$1(label)} ${r.status} ${dim$1(r.size)}`);
2426
2426
  }
2427
- console.log(`\n ${dim("Path:")} ${backupDir}`);
2428
- console.log(` ${dim("To restore:")} pai restore ${backupDir}\n`);
2427
+ console.log(`\n ${dim$1("Path:")} ${backupDir}`);
2428
+ console.log(` ${dim$1("To restore:")} pai restore ${backupDir}\n`);
2429
2429
  });
2430
2430
  }
2431
2431
 
@@ -2481,35 +2481,35 @@ function registerRestoreCommands(program) {
2481
2481
  const backups = listBackups();
2482
2482
  if (backups.length === 0) {
2483
2483
  console.error(err(`No backups found in ${BACKUPS_DIR}`));
2484
- console.log(dim(" Run 'pai backup' to create one."));
2484
+ console.log(dim$1(" Run 'pai backup' to create one."));
2485
2485
  process.exit(1);
2486
2486
  }
2487
- console.log(`\n${bold("Available backups")} (newest first):\n`);
2487
+ console.log(`\n${bold$1("Available backups")} (newest first):\n`);
2488
2488
  backups.forEach((name, i) => {
2489
2489
  const dir = join(BACKUPS_DIR, name);
2490
2490
  const contents = backupContents(dir).join(", ");
2491
2491
  const marker = i === 0 ? ok(" ← latest") : "";
2492
- console.log(` ${bold(String(i + 1).padStart(2))}. ${formatBackupDate(name)}${marker}`);
2493
- console.log(` ${dim(dir)}`);
2494
- console.log(` ${dim("Contents:")} ${contents}`);
2492
+ console.log(` ${bold$1(String(i + 1).padStart(2))}. ${formatBackupDate(name)}${marker}`);
2493
+ console.log(` ${dim$1(dir)}`);
2494
+ console.log(` ${dim$1("Contents:")} ${contents}`);
2495
2495
  });
2496
2496
  console.log();
2497
2497
  resolvedDir = join(BACKUPS_DIR, backups[0]);
2498
- console.log(dim(`Using latest backup: ${resolvedDir}\n`));
2498
+ console.log(dim$1(`Using latest backup: ${resolvedDir}\n`));
2499
2499
  }
2500
2500
  const hasRegistry = existsSync(join(resolvedDir, "registry.db"));
2501
2501
  const hasConfig = existsSync(join(resolvedDir, "config.json"));
2502
2502
  const hasSql = existsSync(join(resolvedDir, "postgres-pai.sql"));
2503
2503
  const hasFed = existsSync(join(resolvedDir, "federation.db"));
2504
- console.log(`${bold("Backup contents:")}`);
2504
+ console.log(`${bold$1("Backup contents:")}`);
2505
2505
  console.log(` registry.db ${hasRegistry ? ok("present") : warn("missing")}`);
2506
2506
  console.log(` config.json ${hasConfig ? ok("present") : warn("missing")}`);
2507
2507
  console.log(` postgres-pai.sql ${hasSql && opts.postgres ? ok("present") : hasSql ? warn("present (skipped via --no-postgres)") : warn("missing")}`);
2508
- if (hasFed) console.log(` federation.db ${ok("present")} ${dim("(legacy)")}`);
2508
+ if (hasFed) console.log(` federation.db ${ok("present")} ${dim$1("(legacy)")}`);
2509
2509
  console.log(`\n${warn("WARNING:")} This will OVERWRITE your current PAI data.`);
2510
2510
  if (hasSql && opts.postgres) console.log(warn(" Postgres database will be dropped and recreated from the backup."));
2511
2511
  if (!(opts.yes || await confirm("Proceed with restore?"))) {
2512
- console.log(dim("Restore cancelled."));
2512
+ console.log(dim$1("Restore cancelled."));
2513
2513
  process.exit(0);
2514
2514
  }
2515
2515
  console.log();
@@ -2561,7 +2561,7 @@ function registerRestoreCommands(program) {
2561
2561
  });
2562
2562
  }
2563
2563
  if (hasSql && opts.postgres) {
2564
- console.log(dim(" Restoring Postgres database (this may take a while)..."));
2564
+ console.log(dim$1(" Restoring Postgres database (this may take a while)..."));
2565
2565
  try {
2566
2566
  execSync(`docker inspect ${DOCKER_CONTAINER} --format='{{.State.Status}}'`, { stdio: "pipe" });
2567
2567
  execSync(`docker exec ${DOCKER_CONTAINER} psql -U ${PG_USER} -c "DROP DATABASE IF EXISTS ${PG_DATABASE}; CREATE DATABASE ${PG_DATABASE} OWNER ${PG_USER};"`, {
@@ -2608,15 +2608,15 @@ function registerRestoreCommands(program) {
2608
2608
  const reason = !hasSql ? "no SQL dump in backup" : "--no-postgres";
2609
2609
  results.push({
2610
2610
  label: "Postgres DB",
2611
- status: dim(`skipped (${reason})`)
2611
+ status: dim$1(`skipped (${reason})`)
2612
2612
  });
2613
2613
  }
2614
- console.log(`\n${bold("Restore complete:")}\n`);
2614
+ console.log(`\n${bold$1("Restore complete:")}\n`);
2615
2615
  const labelWidth = Math.max(...results.map((r) => r.label.length)) + 2;
2616
- for (const r of results) console.log(` ${bold(r.label.padEnd(labelWidth))} ${r.status}`);
2616
+ for (const r of results) console.log(` ${bold$1(r.label.padEnd(labelWidth))} ${r.status}`);
2617
2617
  if (!results.some((r) => r.status.includes("\x1B[31m"))) {
2618
2618
  console.log(`\n ${ok("All done.")} You may need to restart the PAI daemon.\n`);
2619
- console.log(` ${dim("Restart:")} pai daemon restart\n`);
2619
+ console.log(` ${dim$1("Restart:")} pai daemon restart\n`);
2620
2620
  } else {
2621
2621
  console.log(`\n ${warn("Some items failed — check output above.")}\n`);
2622
2622
  process.exit(1);
@@ -3951,6 +3951,355 @@ function stepSummary(configUpdates, claudeMdGenerated, paiSkillInstalled, aiStee
3951
3951
  line$1();
3952
3952
  }
3953
3953
 
3954
+ //#endregion
3955
+ //#region src/tasks/resolver.ts
3956
+ /**
3957
+ * Fold a tracker-supplied string onto its comparable form.
3958
+ *
3959
+ * Container names are written for humans and carry decoration the registry
3960
+ * never sees: "Reading List 📚", "AcmeAPI", "Client Work". Strip the decoration
3961
+ * rather than demanding the user keep two naming schemes in sync.
3962
+ *
3963
+ * Emoji and pictographs are removed, separators collapse to a single hyphen,
3964
+ * and the result is lowercased — so "Client Work" and "client-work" agree.
3965
+ */
3966
+ function normalize$1(raw) {
3967
+ return raw.normalize("NFKD").replace(/[\u{1F000}-\u{1FAFF}\u{2600}-\u{27BF}\u{FE0F}\u{200D}]/gu, "").replace(/[^\p{L}\p{N}]+/gu, "-").replace(/^-+|-+$/g, "").toLowerCase();
3968
+ }
3969
+ /**
3970
+ * Load every alias registered in the PAI registry.
3971
+ *
3972
+ * Reads the curated shortlist only — the `aliases` table — deliberately. The
3973
+ * full registry commonly carries hundreds of projects with no aliases and
3974
+ * genuine ambiguity — separate entries routinely share a display name at
3975
+ * different paths — so widening this query resolves tasks to the wrong
3976
+ * directory. That failure is silent, which makes it worse than no match. Bus
3977
+ * participation is opt-in via `pai project name <identifier> <shortname>`.
3978
+ */
3979
+ function loadAliasMap(db) {
3980
+ const rows = db.prepare(`SELECT a.alias AS alias,
3981
+ p.slug AS slug,
3982
+ p.root_path AS rootPath
3983
+ FROM aliases a
3984
+ JOIN projects p ON p.id = a.project_id
3985
+ WHERE p.status != 'archived'`).all();
3986
+ const map = /* @__PURE__ */ new Map();
3987
+ for (const row of rows) {
3988
+ const target = {
3989
+ alias: row.alias,
3990
+ slug: row.slug,
3991
+ rootPath: row.rootPath
3992
+ };
3993
+ map.set(normalize$1(row.alias), target);
3994
+ const slugKey = normalize$1(row.slug);
3995
+ if (!map.has(slugKey)) map.set(slugKey, target);
3996
+ }
3997
+ return map;
3998
+ }
3999
+ /** Extract the project named by a `pai:<project>` label, if any. */
4000
+ function ownerLabel(labels) {
4001
+ for (const label of labels) {
4002
+ const trimmed = label.trim();
4003
+ if (trimmed.toLowerCase().startsWith(OWNER_LABEL_PREFIX)) {
4004
+ const value = trimmed.slice(OWNER_LABEL_PREFIX.length).trim();
4005
+ if (value) return value;
4006
+ }
4007
+ }
4008
+ return null;
4009
+ }
4010
+ /**
4011
+ * Resolve a task's owner.
4012
+ *
4013
+ * An unresolvable task is never an error: it returns UNROUTED with `rawHint`
4014
+ * set to whatever was tried, so a routine can say *why* it could not route it
4015
+ * rather than dropping it silently. A container like "Reading List 📚" maps to
4016
+ * no PAI project — that is expected, not a fault.
4017
+ */
4018
+ function resolveOwner(input, aliases) {
4019
+ const label = ownerLabel(input.labels);
4020
+ if (label) {
4021
+ const hit = aliases.get(normalize$1(label));
4022
+ if (hit) return {
4023
+ project: hit.alias,
4024
+ rootPath: hit.rootPath,
4025
+ source: "label"
4026
+ };
4027
+ return {
4028
+ ...UNROUTED,
4029
+ rawHint: label
4030
+ };
4031
+ }
4032
+ if (input.container) {
4033
+ const hit = aliases.get(normalize$1(input.container));
4034
+ if (hit) return {
4035
+ project: hit.alias,
4036
+ rootPath: hit.rootPath,
4037
+ source: "container"
4038
+ };
4039
+ return {
4040
+ ...UNROUTED,
4041
+ rawHint: input.container
4042
+ };
4043
+ }
4044
+ return { ...UNROUTED };
4045
+ }
4046
+
4047
+ //#endregion
4048
+ //#region src/tasks/providers/todoist.ts
4049
+ /**
4050
+ * Unified API v1. The older `/rest/v2` endpoints now return 410 Gone — they
4051
+ * were sunset, so anything still targeting them fails outright rather than
4052
+ * degrading.
4053
+ */
4054
+ const API = "https://api.todoist.com/api/v1";
4055
+ async function call(token, path, init) {
4056
+ const res = await fetch(`${API}${path}`, {
4057
+ method: init?.method ?? "GET",
4058
+ headers: {
4059
+ Authorization: `Bearer ${token}`,
4060
+ ...init?.body ? { "Content-Type": "application/json" } : {}
4061
+ },
4062
+ body: init?.body ? JSON.stringify(init.body) : void 0
4063
+ });
4064
+ if (!res.ok) {
4065
+ const hint = res.status === 401 ? " (token rejected — check it was copied in full)" : "";
4066
+ throw new Error(`Todoist ${res.status} ${res.statusText}${hint}`);
4067
+ }
4068
+ if (res.status === 204) return void 0;
4069
+ return await res.json();
4070
+ }
4071
+ /**
4072
+ * Drain a paginated collection.
4073
+ *
4074
+ * Every v1 list endpoint pages. Stopping at the first page would silently
4075
+ * truncate — the account here already exceeds one page of tasks — so follow the
4076
+ * cursor to exhaustion. The guard is a safety stop against a server that keeps
4077
+ * handing back the same cursor, not an intentional cap.
4078
+ */
4079
+ async function collect(token, path) {
4080
+ const out = [];
4081
+ let cursor;
4082
+ let guard = 0;
4083
+ do {
4084
+ const sep = path.includes("?") ? "&" : "?";
4085
+ const page = await call(token, cursor ? `${path}${sep}cursor=${encodeURIComponent(cursor)}` : path);
4086
+ out.push(...page.results ?? []);
4087
+ cursor = page.next_cursor;
4088
+ } while (cursor && ++guard < 100);
4089
+ return out;
4090
+ }
4091
+ /**
4092
+ * List every live project on the account.
4093
+ *
4094
+ * Exported because setup uses it both to let the user pick the bus root and to
4095
+ * validate the token — a bad token fails here, at install time, rather than
4096
+ * silently returning nothing during a routine.
4097
+ */
4098
+ async function listProjects(token) {
4099
+ return (await collect(token, "/projects")).filter((p) => !p.is_archived && !p.is_deleted).map((p) => ({
4100
+ id: p.id,
4101
+ name: p.name
4102
+ }));
4103
+ }
4104
+ /** Todoist priority is inverted: 4 is urgent, 1 is lowest. */
4105
+ function toPriority(wire) {
4106
+ switch (wire) {
4107
+ case 4: return "p1";
4108
+ case 3: return "p2";
4109
+ case 2: return "p3";
4110
+ default: return "p4";
4111
+ }
4112
+ }
4113
+ function fromPriority(p) {
4114
+ switch (p) {
4115
+ case "p1": return 4;
4116
+ case "p2": return 3;
4117
+ case "p3": return 2;
4118
+ default: return 1;
4119
+ }
4120
+ }
4121
+ var TodoistProvider = class {
4122
+ providerId = "todoist";
4123
+ constructor(config, aliases) {
4124
+ this.config = config;
4125
+ this.aliases = aliases;
4126
+ }
4127
+ /**
4128
+ * Resolution order is config → env → unconfigured. A missing token disables
4129
+ * the provider rather than throwing: a user without a tracker still gets a
4130
+ * fully working PAI.
4131
+ */
4132
+ token() {
4133
+ return this.config.apiKey?.trim() || process.env.TODOIST_API_KEY?.trim() || null;
4134
+ }
4135
+ isConfigured() {
4136
+ return Boolean(this.config.enabled && this.token() && this.config.rootProjectId);
4137
+ }
4138
+ async listOpen(opts = {}) {
4139
+ const token = this.token();
4140
+ if (!token || !this.config.rootProjectId) return [];
4141
+ const projects = await collect(token, "/projects");
4142
+ const root = this.config.rootProjectId;
4143
+ const inBus = /* @__PURE__ */ new Map();
4144
+ for (const p of projects) {
4145
+ if (p.is_archived || p.is_deleted) continue;
4146
+ if (p.id === root || p.parent_id === root) inBus.set(p.id, p);
4147
+ }
4148
+ if (inBus.size === 0) return [];
4149
+ const wire = [];
4150
+ for (const id of inBus.keys()) wire.push(...await collect(token, `/tasks?project_id=${encodeURIComponent(id)}`));
4151
+ const out = [];
4152
+ for (const w of wire) {
4153
+ if (w.checked || w.is_deleted) continue;
4154
+ const container = inBus.get(w.project_id);
4155
+ if (!container) continue;
4156
+ const containerName = container.id === root ? null : container.name;
4157
+ const owner = resolveOwner({
4158
+ labels: w.labels ?? [],
4159
+ container: containerName
4160
+ }, this.aliases);
4161
+ if (opts.owner && owner.project !== opts.owner) continue;
4162
+ if (opts.includeUnrouted === false && owner.project === null) continue;
4163
+ const due = w.due?.datetime ?? w.due?.date ?? null;
4164
+ if (opts.dueBefore) {
4165
+ if (!due || due.slice(0, 10) > opts.dueBefore) continue;
4166
+ }
4167
+ out.push({
4168
+ id: w.id,
4169
+ title: w.content,
4170
+ body: w.description ?? "",
4171
+ owner,
4172
+ due,
4173
+ priority: toPriority(w.priority),
4174
+ labels: w.labels ?? [],
4175
+ sourceUrl: `https://app.todoist.com/app/task/${w.id}`
4176
+ });
4177
+ if (opts.limit && out.length >= opts.limit) break;
4178
+ }
4179
+ return out;
4180
+ }
4181
+ async add(task) {
4182
+ const token = this.token();
4183
+ if (!token || !this.config.rootProjectId) throw new Error("Todoist provider is not configured — run `pai setup`.");
4184
+ const labels = [...task.labels ?? []];
4185
+ if (task.owner && !labels.some((l) => l.toLowerCase() === `pai:${task.owner.toLowerCase()}`)) labels.push(`pai:${task.owner}`);
4186
+ const sectionId = task.owner ? void 0 : this.config.findingsSectionId;
4187
+ const created = await call(token, "/tasks", {
4188
+ method: "POST",
4189
+ body: {
4190
+ content: task.title,
4191
+ description: task.body,
4192
+ project_id: this.config.rootProjectId,
4193
+ ...sectionId ? { section_id: sectionId } : {},
4194
+ labels,
4195
+ priority: fromPriority(task.priority),
4196
+ ...task.due ? { due_date: task.due } : {}
4197
+ }
4198
+ });
4199
+ return {
4200
+ id: created.id,
4201
+ title: created.content,
4202
+ body: created.description ?? "",
4203
+ owner: task.owner ? resolveOwner({
4204
+ labels,
4205
+ container: null
4206
+ }, this.aliases) : { ...UNROUTED },
4207
+ due: created.due?.datetime ?? created.due?.date ?? null,
4208
+ priority: toPriority(created.priority),
4209
+ labels: created.labels ?? [],
4210
+ sourceUrl: `https://app.todoist.com/app/task/${created.id}`
4211
+ };
4212
+ }
4213
+ async complete(id) {
4214
+ const token = this.token();
4215
+ if (!token) throw new Error("Todoist provider is not configured — run `pai setup`.");
4216
+ await call(token, `/tasks/${id}/close`, { method: "POST" });
4217
+ }
4218
+ };
4219
+
4220
+ //#endregion
4221
+ //#region src/cli/commands/setup/steps/16-task-bus.ts
4222
+ /** Step 16: Task bus — optional external tracker for cross-session work. */
4223
+ async function stepTaskBus(rl) {
4224
+ section("Step 16: Task Bus (Optional)");
4225
+ const current = readConfigRaw().tasks ?? {};
4226
+ const todoist = current.providers?.todoist;
4227
+ if (todoist?.apiKey && todoist?.rootProjectId) {
4228
+ console.log(c.ok("Task bus already configured. Skipping."));
4229
+ return { tasks: current };
4230
+ }
4231
+ line$1();
4232
+ line$1(" The task bus lets any PAI session file work into a shared tracker, so a");
4233
+ line$1(" routine can pick it up later and hand it to the session that owns it.");
4234
+ line$1();
4235
+ line$1(" PAI works fully without this. Skip it unless you want cross-session tasks.");
4236
+ line$1();
4237
+ if (!await promptYesNo(rl, "Enable the task bus (requires a Todoist account)?", false)) {
4238
+ line$1();
4239
+ console.log(c.ok("Skipping the task bus."));
4240
+ console.log(c.dim(" Add later by re-running `pai setup`."));
4241
+ return { tasks: { enabled: false } };
4242
+ }
4243
+ line$1();
4244
+ line$1(" Get your API token from Todoist:");
4245
+ line$1(c.dim(" Settings -> Integrations -> Developer"));
4246
+ line$1(c.dim(" https://app.todoist.com/app/settings/integrations/developer"));
4247
+ line$1();
4248
+ line$1(" It grants full read/write access to your Todoist. Treat it like a password.");
4249
+ line$1();
4250
+ const envToken = process.env.TODOIST_API_KEY?.trim();
4251
+ let apiKey = todoist?.apiKey ?? "";
4252
+ if (!apiKey && envToken) {
4253
+ if (await promptYesNo(rl, "Found TODOIST_API_KEY in the environment. Use it?", true)) apiKey = envToken;
4254
+ }
4255
+ while (!apiKey) {
4256
+ apiKey = (await prompt(rl, " Paste your Todoist API token: ")).trim();
4257
+ if (!apiKey) console.log(c.warn(" A token is required, or answer no to skip the task bus."));
4258
+ }
4259
+ line$1();
4260
+ line$1(" Fetching your Todoist projects...");
4261
+ let projects;
4262
+ try {
4263
+ projects = await listProjects(apiKey);
4264
+ } catch (e) {
4265
+ line$1();
4266
+ console.log(c.warn(`Could not reach Todoist: ${e instanceof Error ? e.message : String(e)}`));
4267
+ console.log(c.dim(" The token may be wrong, or the network is unavailable."));
4268
+ console.log(c.dim(" Saved nothing. Re-run `pai setup` to try again."));
4269
+ return { tasks: { enabled: false } };
4270
+ }
4271
+ if (projects.length === 0) {
4272
+ console.log(c.warn(" No projects found. Create one in Todoist first, then re-run setup."));
4273
+ return { tasks: { enabled: false } };
4274
+ }
4275
+ line$1();
4276
+ line$1(" Which project should hold the bus? Create a dedicated one if unsure.");
4277
+ line$1();
4278
+ projects.forEach((p, i) => line$1(` ${String(i + 1).padStart(2)}. ${p.name}`));
4279
+ line$1();
4280
+ let rootProjectId = "";
4281
+ while (!rootProjectId) {
4282
+ const answer = (await prompt(rl, ` Project number [1-${projects.length}]: `)).trim();
4283
+ const idx = Number.parseInt(answer, 10) - 1;
4284
+ if (Number.isInteger(idx) && idx >= 0 && idx < projects.length) rootProjectId = projects[idx].id;
4285
+ else console.log(c.warn(` Enter a number between 1 and ${projects.length}.`));
4286
+ }
4287
+ const chosen = projects.find((p) => p.id === rootProjectId);
4288
+ line$1();
4289
+ console.log(c.ok(`Task bus enabled on "${chosen.name}" (id ${rootProjectId}).`));
4290
+ console.log(c.dim(" Label a task `pai:<project>` to assign it to a PAI project."));
4291
+ console.log(c.dim(" Only projects with an alias can be dispatched to — see `pai project name`."));
4292
+ return { tasks: {
4293
+ enabled: true,
4294
+ autoDispatch: await promptYesNo(rl, "Automatically hand tasks to the owning session (needs AIBroker)?", false),
4295
+ providers: { todoist: {
4296
+ enabled: true,
4297
+ apiKey,
4298
+ rootProjectId
4299
+ } }
4300
+ } };
4301
+ }
4302
+
3954
4303
  //#endregion
3955
4304
  //#region src/cli/commands/setup/index.ts
3956
4305
  async function runSetup() {
@@ -3986,9 +4335,11 @@ async function runSetup() {
3986
4335
  const daemonInstalled = await stepDaemon(rl);
3987
4336
  const mcpRegistered = await stepMcp(rl);
3988
4337
  await stepDirectories(rl);
4338
+ const taskConfig = await stepTaskBus(rl);
3989
4339
  const allUpdates = {
3990
4340
  ...storageConfig,
3991
- ...embeddingConfig
4341
+ ...embeddingConfig,
4342
+ ...taskConfig
3992
4343
  };
3993
4344
  mergeConfig(allUpdates);
3994
4345
  line$1();
@@ -4763,7 +5114,7 @@ function cmdSync(db, opts) {
4763
5114
  if (!q) {
4764
5115
  console.log();
4765
5116
  console.log(header(" PAI Obsidian Sync"));
4766
- console.log(dim(` Vault: ${vaultPath}`));
5117
+ console.log(dim$1(` Vault: ${vaultPath}`));
4767
5118
  console.log();
4768
5119
  }
4769
5120
  if (!q) process.stdout.write(" Syncing symlinks...");
@@ -4799,7 +5150,7 @@ function cmdStatus$1(db, opts) {
4799
5150
  const report = checkHealth(vaultPath, db);
4800
5151
  console.log();
4801
5152
  console.log(header(" PAI Obsidian Vault Status"));
4802
- console.log(dim(` Vault: ${vaultPath}`));
5153
+ console.log(dim$1(` Vault: ${vaultPath}`));
4803
5154
  console.log();
4804
5155
  if (!existsSync(vaultPath)) {
4805
5156
  console.log(warn(" Vault directory does not exist. Run: pai obsidian sync"));
@@ -4813,27 +5164,27 @@ function cmdStatus$1(db, opts) {
4813
5164
  console.log(` ${chalk.green("Healthy:")} ${healthyCount} ${chalk.red("Broken:")} ${brokenCount} ${chalk.yellow("Orphaned:")} ${orphanedCount} ${chalk.cyan("Missing:")} ${missingCount}`);
4814
5165
  console.log();
4815
5166
  if (report.healthy.length && report.healthy.length <= 10) {
4816
- console.log(bold(" Healthy symlinks:"));
4817
- for (const h of report.healthy) console.log(` ${chalk.green("✓")} ${bold(h.slug)} ${dim("→ " + (h.target ?? ""))}`);
5167
+ console.log(bold$1(" Healthy symlinks:"));
5168
+ for (const h of report.healthy) console.log(` ${chalk.green("✓")} ${bold$1(h.slug)} ${dim$1("→ " + (h.target ?? ""))}`);
4818
5169
  console.log();
4819
5170
  } else if (report.healthy.length > 10) {
4820
- console.log(bold(` ${report.healthy.length} healthy symlinks (all good)`));
5171
+ console.log(bold$1(` ${report.healthy.length} healthy symlinks (all good)`));
4821
5172
  console.log();
4822
5173
  }
4823
5174
  if (report.broken.length) {
4824
5175
  console.log(err(" Broken symlinks (target missing):"));
4825
- for (const b of report.broken) console.log(` ${chalk.red("✗")} ${bold(b.slug)} ${dim(b.notes)}`);
4826
- console.log(dim(" Fix: pai obsidian sync"));
5176
+ for (const b of report.broken) console.log(` ${chalk.red("✗")} ${bold$1(b.slug)} ${dim$1(b.notes)}`);
5177
+ console.log(dim$1(" Fix: pai obsidian sync"));
4827
5178
  console.log();
4828
5179
  }
4829
5180
  if (report.orphaned.length) {
4830
5181
  console.log(warn(" Orphaned symlinks (no registry project):"));
4831
- for (const o of report.orphaned) console.log(` ${chalk.yellow("?")} ${bold(o.slug)} ${dim(o.notes)}`);
5182
+ for (const o of report.orphaned) console.log(` ${chalk.yellow("?")} ${bold$1(o.slug)} ${dim$1(o.notes)}`);
4832
5183
  console.log();
4833
5184
  }
4834
5185
  if (report.missing.length) {
4835
5186
  console.log(warn(" Projects with Notes/ but no vault symlink:"));
4836
- for (const m of report.missing) console.log(` ${chalk.cyan("→")} ${bold(m.slug)} ${dim(m.notes)}`);
5187
+ for (const m of report.missing) console.log(` ${chalk.cyan("→")} ${bold$1(m.slug)} ${dim$1(m.notes)}`);
4837
5188
  console.log();
4838
5189
  }
4839
5190
  if (brokenCount === 0 && orphanedCount === 0 && missingCount === 0) {
@@ -4847,17 +5198,17 @@ function cmdOpen(opts) {
4847
5198
  const vaultName = parts[parts.length - 1] ?? "obsidian-vault";
4848
5199
  if (!existsSync(vaultPath)) {
4849
5200
  console.error(err(`Vault not found at: ${vaultPath}`));
4850
- console.error(dim(" Run: pai obsidian sync"));
5201
+ console.error(dim$1(" Run: pai obsidian sync"));
4851
5202
  process.exit(1);
4852
5203
  }
4853
5204
  const url = `obsidian://open?vault=${encodeURIComponent(vaultName)}`;
4854
- console.log(dim(` Opening: ${url}`));
5205
+ console.log(dim$1(` Opening: ${url}`));
4855
5206
  try {
4856
5207
  execSync(`open "${url}"`, { stdio: "ignore" });
4857
5208
  console.log(ok(` Opened vault "${vaultName}" in Obsidian.`));
4858
5209
  } catch (e) {
4859
5210
  console.error(err(` Failed to open Obsidian: ${e}`));
4860
- console.error(dim(" Ensure Obsidian is installed and the vault is registered in Obsidian."));
5211
+ console.error(dim$1(" Ensure Obsidian is installed and the vault is registered in Obsidian."));
4861
5212
  process.exit(1);
4862
5213
  }
4863
5214
  }
@@ -4906,15 +5257,15 @@ async function cmdExplore(note, opts) {
4906
5257
  });
4907
5258
  console.log();
4908
5259
  console.log(header(" PAI Zettel Explore"));
4909
- console.log(dim(` Starting note: ${note}`));
4910
- console.log(dim(` Depth: ${depth} Direction: ${direction} Mode: ${mode}`));
5260
+ console.log(dim$1(` Starting note: ${note}`));
5261
+ console.log(dim$1(` Depth: ${depth} Direction: ${direction} Mode: ${mode}`));
4911
5262
  console.log();
4912
5263
  if (result.nodes.length === 0) {
4913
5264
  console.log(warn(" No connected notes found. Check that the note path exists in the vault index."));
4914
5265
  console.log();
4915
5266
  return;
4916
5267
  }
4917
- console.log(` ${chalk.cyan("●")} ${bold(shortPath(result.root))} ${dim("(root)")}`);
5268
+ console.log(` ${chalk.cyan("●")} ${bold$1(shortPath(result.root))} ${dim$1("(root)")}`);
4918
5269
  const byDepth = /* @__PURE__ */ new Map();
4919
5270
  for (const node of result.nodes) {
4920
5271
  const list = byDepth.get(node.depth) ?? [];
@@ -4925,20 +5276,20 @@ async function cmdExplore(note, opts) {
4925
5276
  const nodes = byDepth.get(d) ?? [];
4926
5277
  if (nodes.length === 0) continue;
4927
5278
  console.log();
4928
- console.log(dim(` ${" ".repeat(d - 1)}Depth ${d}:`));
5279
+ console.log(dim$1(` ${" ".repeat(d - 1)}Depth ${d}:`));
4929
5280
  for (const node of nodes) {
4930
5281
  const indent = " ".repeat(d);
4931
5282
  const isBranching = result.branchingPoints.includes(node.path);
4932
5283
  const typeColor = node.linkType === "sequential" ? chalk.blue : chalk.magenta;
4933
5284
  const branchMark = isBranching ? chalk.yellow(" ⑂ branching") : "";
4934
5285
  const title = node.title ?? shortPath(node.path);
4935
- const stats = dim(`in:${node.inbound} out:${node.outbound}`);
4936
- console.log(` ${indent}${typeColor("→")} ${bold(title)}${branchMark} ${stats} ${dim(typeColor(node.linkType))}`);
5286
+ const stats = dim$1(`in:${node.inbound} out:${node.outbound}`);
5287
+ console.log(` ${indent}${typeColor("→")} ${bold$1(title)}${branchMark} ${stats} ${dim$1(typeColor(node.linkType))}`);
4937
5288
  }
4938
5289
  }
4939
5290
  console.log();
4940
5291
  const edgeSummary = `${result.edges.length} edges (${result.edges.filter((e) => e.type === "sequential").length} sequential, ${result.edges.filter((e) => e.type === "associative").length} associative)`;
4941
- console.log(dim(` ${edgeSummary}`));
5292
+ console.log(dim$1(` ${edgeSummary}`));
4942
5293
  if (result.branchingPoints.length > 0) console.log(ok(` ${result.branchingPoints.length} branching point(s) found`));
4943
5294
  if (result.maxDepthReached) console.log(warn(" Max depth reached — use --depth to explore further"));
4944
5295
  console.log();
@@ -4970,31 +5321,31 @@ async function cmdHealth(opts) {
4970
5321
  });
4971
5322
  console.log();
4972
5323
  console.log(header(" PAI Zettel Health"));
4973
- console.log(dim(` Scope: ${scope}${scope === "project" ? ` Path: ${projectPath ?? "(none)"}` : ""}${scope === "recent" ? ` Days: ${recentDays}` : ""}`));
5324
+ console.log(dim$1(` Scope: ${scope}${scope === "project" ? ` Path: ${projectPath ?? "(none)"}` : ""}${scope === "recent" ? ` Days: ${recentDays}` : ""}`));
4974
5325
  console.log();
4975
5326
  const score = result.healthScore;
4976
5327
  const scoreColor = score >= 80 ? chalk.green : score >= 60 ? chalk.yellow : chalk.red;
4977
5328
  const barWidth = 30;
4978
5329
  const filled = Math.round(score / 100 * barWidth);
4979
- const bar = scoreColor("█".repeat(filled)) + dim("░".repeat(barWidth - filled));
4980
- console.log(` Health Score: ${scoreColor(bold(String(score)))}% [${bar}]`);
5330
+ const bar = scoreColor("█".repeat(filled)) + dim$1("░".repeat(barWidth - filled));
5331
+ console.log(` Health Score: ${scoreColor(bold$1(String(score)))}% [${bar}]`);
4981
5332
  console.log();
4982
- console.log(dim(` Files: ${result.totalFiles} Links: ${result.totalLinks}`));
5333
+ console.log(dim$1(` Files: ${result.totalFiles} Links: ${result.totalLinks}`));
4983
5334
  console.log();
4984
5335
  if (result.deadLinks.length === 0) console.log(ok(" Dead links: none"));
4985
5336
  else {
4986
5337
  console.log(warn(` Dead links: ${result.deadLinks.length}`));
4987
5338
  const preview = result.deadLinks.slice(0, 10);
4988
- for (const dl of preview) console.log(` ${chalk.red("✗")} ${dim(shortPath(dl.sourcePath))} → ${bold(dl.targetRaw)} ${dim(`(line ${dl.lineNumber})`)}`);
4989
- if (result.deadLinks.length > 10) console.log(dim(` ... and ${result.deadLinks.length - 10} more`));
5339
+ for (const dl of preview) console.log(` ${chalk.red("✗")} ${dim$1(shortPath(dl.sourcePath))} → ${bold$1(dl.targetRaw)} ${dim$1(`(line ${dl.lineNumber})`)}`);
5340
+ if (result.deadLinks.length > 10) console.log(dim$1(` ... and ${result.deadLinks.length - 10} more`));
4990
5341
  console.log();
4991
5342
  }
4992
5343
  if (result.orphans.length === 0) console.log(ok(" Orphan notes: none"));
4993
5344
  else {
4994
5345
  console.log(warn(` Orphan notes: ${result.orphans.length}`));
4995
5346
  const preview = result.orphans.slice(0, 10);
4996
- for (const o of preview) console.log(` ${chalk.yellow("○")} ${dim(shortPath(o))}`);
4997
- if (result.orphans.length > 10) console.log(dim(` ... and ${result.orphans.length - 10} more`));
5347
+ for (const o of preview) console.log(` ${chalk.yellow("○")} ${dim$1(shortPath(o))}`);
5348
+ if (result.orphans.length > 10) console.log(dim$1(` ... and ${result.orphans.length - 10} more`));
4998
5349
  console.log();
4999
5350
  }
5000
5351
  if (result.disconnectedClusters <= 1) console.log(ok(" Disconnected clusters: 1 (fully connected)"));
@@ -5003,8 +5354,8 @@ async function cmdHealth(opts) {
5003
5354
  else {
5004
5355
  console.log(warn(` Low-connectivity: ${result.lowConnectivity.length} note(s) with ≤1 link`));
5005
5356
  const preview = result.lowConnectivity.slice(0, 5);
5006
- for (const lc of preview) console.log(` ${chalk.dim("—")} ${dim(shortPath(lc))}`);
5007
- if (result.lowConnectivity.length > 5) console.log(dim(` ... and ${result.lowConnectivity.length - 5} more`));
5357
+ for (const lc of preview) console.log(` ${chalk.dim("—")} ${dim$1(shortPath(lc))}`);
5358
+ if (result.lowConnectivity.length > 5) console.log(dim$1(` ... and ${result.lowConnectivity.length - 5} more`));
5008
5359
  }
5009
5360
  console.log();
5010
5361
  }
@@ -5034,8 +5385,8 @@ async function cmdSurprise(note, opts) {
5034
5385
  const db = getFedDb();
5035
5386
  console.log();
5036
5387
  console.log(header(" PAI Zettel Surprise"));
5037
- console.log(dim(` Reference note: ${note}`));
5038
- process.stdout.write(dim(" Searching for surprising connections...\n"));
5388
+ console.log(dim$1(` Reference note: ${note}`));
5389
+ process.stdout.write(dim$1(" Searching for surprising connections...\n"));
5039
5390
  const results = await zettelSurprise(db, {
5040
5391
  referencePath: note,
5041
5392
  vaultProjectId,
@@ -5049,16 +5400,16 @@ async function cmdSurprise(note, opts) {
5049
5400
  return;
5050
5401
  }
5051
5402
  console.log();
5052
- console.log(bold(` Found ${results.length} surprising connection(s):`));
5403
+ console.log(bold$1(` Found ${results.length} surprising connection(s):`));
5053
5404
  console.log();
5054
5405
  for (let i = 0; i < results.length; i++) {
5055
5406
  const r = results[i];
5056
5407
  const title = r.title ?? shortPath(r.path);
5057
5408
  const surpriseBar = Math.round(r.surpriseScore * 10);
5058
- console.log(` ${chalk.cyan(String(i + 1).padStart(2, " "))}. ${bold(title)}`);
5059
- console.log(` ${dim("Surprise:")} ${chalk.magenta(r.surpriseScore.toFixed(3))} ${"■".repeat(surpriseBar)}${"□".repeat(10 - surpriseBar)}`);
5060
- console.log(` ${dim("Cosine:")} ${r.cosineSimilarity.toFixed(3)} ${dim("Graph distance:")} ${r.graphDistance}`);
5061
- if (r.sharedSnippet) console.log(` ${dim("Context:")} ${r.sharedSnippet.slice(0, 120)}`);
5409
+ console.log(` ${chalk.cyan(String(i + 1).padStart(2, " "))}. ${bold$1(title)}`);
5410
+ console.log(` ${dim$1("Surprise:")} ${chalk.magenta(r.surpriseScore.toFixed(3))} ${"■".repeat(surpriseBar)}${"□".repeat(10 - surpriseBar)}`);
5411
+ console.log(` ${dim$1("Cosine:")} ${r.cosineSimilarity.toFixed(3)} ${dim$1("Graph distance:")} ${r.graphDistance}`);
5412
+ if (r.sharedSnippet) console.log(` ${dim$1("Context:")} ${r.sharedSnippet.slice(0, 120)}`);
5062
5413
  console.log();
5063
5414
  }
5064
5415
  }
@@ -5087,8 +5438,8 @@ async function cmdSuggest(note, opts) {
5087
5438
  const db = getFedDb();
5088
5439
  console.log();
5089
5440
  console.log(header(" PAI Zettel Suggest"));
5090
- console.log(dim(` Note: ${note}`));
5091
- process.stdout.write(dim(" Computing suggestions...\n"));
5441
+ console.log(dim$1(` Note: ${note}`));
5442
+ process.stdout.write(dim$1(" Computing suggestions...\n"));
5092
5443
  const suggestions = await zettelSuggest(db, {
5093
5444
  notePath: note,
5094
5445
  vaultProjectId,
@@ -5101,15 +5452,15 @@ async function cmdSuggest(note, opts) {
5101
5452
  return;
5102
5453
  }
5103
5454
  console.log();
5104
- console.log(bold(` ${suggestions.length} suggested connection(s):`));
5455
+ console.log(bold$1(` ${suggestions.length} suggested connection(s):`));
5105
5456
  console.log();
5106
5457
  for (let i = 0; i < suggestions.length; i++) {
5107
5458
  const s = suggestions[i];
5108
5459
  const title = s.title ?? shortPath(s.path);
5109
- console.log(` ${chalk.green(String(i + 1).padStart(2, " "))}. ${bold(title)}`);
5110
- console.log(` ${dim("Score:")} ${chalk.green(s.score.toFixed(3))} ${dim("Semantic:")} ${s.semanticScore.toFixed(2)} ${dim("Tag:")} ${s.tagScore.toFixed(2)} ${dim("Neighbor:")} ${s.neighborScore.toFixed(2)}`);
5111
- console.log(` ${dim("Reason:")} ${s.reason}`);
5112
- console.log(` ${dim("Wikilink:")} ${chalk.cyan(s.suggestedWikilink)}`);
5460
+ console.log(` ${chalk.green(String(i + 1).padStart(2, " "))}. ${bold$1(title)}`);
5461
+ console.log(` ${dim$1("Score:")} ${chalk.green(s.score.toFixed(3))} ${dim$1("Semantic:")} ${s.semanticScore.toFixed(2)} ${dim$1("Tag:")} ${s.tagScore.toFixed(2)} ${dim$1("Neighbor:")} ${s.neighborScore.toFixed(2)}`);
5462
+ console.log(` ${dim$1("Reason:")} ${s.reason}`);
5463
+ console.log(` ${dim$1("Wikilink:")} ${chalk.cyan(s.suggestedWikilink)}`);
5113
5464
  console.log();
5114
5465
  }
5115
5466
  }
@@ -5138,8 +5489,8 @@ async function cmdConverse(question, opts) {
5138
5489
  const db = getFedDb();
5139
5490
  console.log();
5140
5491
  console.log(header(" PAI Zettel Converse"));
5141
- console.log(dim(` Question: "${question}"`));
5142
- process.stdout.write(dim(" Searching vault for relevant notes...\n"));
5492
+ console.log(dim$1(` Question: "${question}"`));
5493
+ process.stdout.write(dim$1(" Searching vault for relevant notes...\n"));
5143
5494
  const result = await zettelConverse(db, {
5144
5495
  question,
5145
5496
  vaultProjectId,
@@ -5152,24 +5503,24 @@ async function cmdConverse(question, opts) {
5152
5503
  return;
5153
5504
  }
5154
5505
  console.log();
5155
- console.log(bold(` ${result.relevantNotes.length} relevant note(s) from ${result.domains.length} domain(s):`));
5156
- console.log(dim(` Domains: ${result.domains.join(", ")}`));
5506
+ console.log(bold$1(` ${result.relevantNotes.length} relevant note(s) from ${result.domains.length} domain(s):`));
5507
+ console.log(dim$1(` Domains: ${result.domains.join(", ")}`));
5157
5508
  console.log();
5158
5509
  for (const note of result.relevantNotes) {
5159
5510
  const title = note.title ?? shortPath(note.path);
5160
- console.log(` ${chalk.cyan("◆")} ${bold(title)} ${dim(`[${note.domain}] score: ${note.score.toFixed(3)}`)}`);
5161
- if (note.snippet) console.log(` ${dim(note.snippet.slice(0, 200))}`);
5511
+ console.log(` ${chalk.cyan("◆")} ${bold$1(title)} ${dim$1(`[${note.domain}] score: ${note.score.toFixed(3)}`)}`);
5512
+ if (note.snippet) console.log(` ${dim$1(note.snippet.slice(0, 200))}`);
5162
5513
  console.log();
5163
5514
  }
5164
5515
  if (result.connections.length > 0) {
5165
- console.log(bold(" Cross-domain connections:"));
5166
- for (const conn of result.connections.slice(0, 10)) console.log(` ${chalk.magenta("⟷")} ${dim(conn.fromDomain)} ${chalk.dim("→")} ${dim(conn.toDomain)} ${dim(shortPath(conn.fromPath))} → ${dim(shortPath(conn.toPath))} ${dim(`strength: ${conn.strength}`)}`);
5516
+ console.log(bold$1(" Cross-domain connections:"));
5517
+ for (const conn of result.connections.slice(0, 10)) console.log(` ${chalk.magenta("⟷")} ${dim$1(conn.fromDomain)} ${chalk.dim("→")} ${dim$1(conn.toDomain)} ${dim$1(shortPath(conn.fromPath))} → ${dim$1(shortPath(conn.toPath))} ${dim$1(`strength: ${conn.strength}`)}`);
5167
5518
  console.log();
5168
5519
  }
5169
- console.log(bold(" Synthesis prompt (paste into your AI):"));
5520
+ console.log(bold$1(" Synthesis prompt (paste into your AI):"));
5170
5521
  console.log();
5171
5522
  const promptLines = result.synthesisPrompt.split("\n");
5172
- for (const line of promptLines) console.log(` ${dim(line)}`);
5523
+ for (const line of promptLines) console.log(` ${dim$1(line)}`);
5173
5524
  console.log();
5174
5525
  }
5175
5526
  function registerConverseCommand(parent) {
@@ -5199,8 +5550,8 @@ async function cmdThemes(opts) {
5199
5550
  const db = getFedDb();
5200
5551
  console.log();
5201
5552
  console.log(header(" PAI Zettel Themes"));
5202
- console.log(dim(` Lookback: ${lookbackDays}d Min cluster: ${minClusterSize} Threshold: ${similarityThreshold}`));
5203
- process.stdout.write(dim(" Detecting emerging themes...\n"));
5553
+ console.log(dim$1(` Lookback: ${lookbackDays}d Min cluster: ${minClusterSize} Threshold: ${similarityThreshold}`));
5554
+ process.stdout.write(dim$1(" Detecting emerging themes...\n"));
5204
5555
  const result = await zettelThemes(db, {
5205
5556
  vaultProjectId,
5206
5557
  lookbackDays,
@@ -5216,20 +5567,20 @@ async function cmdThemes(opts) {
5216
5567
  const fromDate = new Date(result.timeWindow.from).toISOString().slice(0, 10);
5217
5568
  const toDate = new Date(result.timeWindow.to).toISOString().slice(0, 10);
5218
5569
  console.log();
5219
- console.log(bold(` ${result.themes.length} theme(s) from ${result.totalNotesAnalyzed} notes [${fromDate} → ${toDate}]:`));
5570
+ console.log(bold$1(` ${result.themes.length} theme(s) from ${result.totalNotesAnalyzed} notes [${fromDate} → ${toDate}]:`));
5220
5571
  console.log();
5221
5572
  for (let i = 0; i < result.themes.length; i++) {
5222
5573
  const cluster = result.themes[i];
5223
5574
  const diversityBar = Math.round(cluster.folderDiversity * 10);
5224
5575
  const indexSuggestion = cluster.suggestIndexNote ? chalk.yellow(" ⚑ suggest index note") : "";
5225
- console.log(` ${chalk.cyan(String(i + 1).padStart(2, " "))}. ${bold(cluster.label)}${indexSuggestion}`);
5226
- console.log(` ${dim("Notes:")} ${cluster.size} ${dim("Diversity:")} ${"█".repeat(diversityBar)}${"░".repeat(10 - diversityBar)} ${cluster.folderDiversity.toFixed(2)} ${dim("Linked:")} ${Math.round(cluster.linkedRatio * 100)}%`);
5576
+ console.log(` ${chalk.cyan(String(i + 1).padStart(2, " "))}. ${bold$1(cluster.label)}${indexSuggestion}`);
5577
+ console.log(` ${dim$1("Notes:")} ${cluster.size} ${dim$1("Diversity:")} ${"█".repeat(diversityBar)}${"░".repeat(10 - diversityBar)} ${cluster.folderDiversity.toFixed(2)} ${dim$1("Linked:")} ${Math.round(cluster.linkedRatio * 100)}%`);
5227
5578
  const preview = cluster.notes.slice(0, 5);
5228
5579
  for (const note of preview) {
5229
5580
  const title = note.title ?? shortPath(note.path);
5230
- console.log(` ${dim("•")} ${title}`);
5581
+ console.log(` ${dim$1("•")} ${title}`);
5231
5582
  }
5232
- if (cluster.notes.length > 5) console.log(dim(` ... and ${cluster.notes.length - 5} more`));
5583
+ if (cluster.notes.length > 5) console.log(dim$1(` ... and ${cluster.notes.length - 5} more`));
5233
5584
  console.log();
5234
5585
  }
5235
5586
  }
@@ -5311,12 +5662,12 @@ function typeColor(type) {
5311
5662
  }
5312
5663
  }
5313
5664
  function fmtTs$2(ts) {
5314
- if (!ts) return dim("—");
5665
+ if (!ts) return dim$1("—");
5315
5666
  try {
5316
5667
  const d = new Date(ts);
5317
5668
  return `${d.toISOString().slice(0, 10)} ${d.toISOString().slice(11, 16)}`;
5318
5669
  } catch {
5319
- return dim("—");
5670
+ return dim$1("—");
5320
5671
  }
5321
5672
  }
5322
5673
  function trunc$1(s, maxLen) {
@@ -5335,7 +5686,7 @@ async function cmdList$2(opts) {
5335
5686
  observations = await ipcCall$1("observation_list", params);
5336
5687
  } catch (e) {
5337
5688
  console.error(err(` Failed to reach PAI daemon: ${e}`));
5338
- console.error(dim(" Is the daemon running? Try: pai daemon status"));
5689
+ console.error(dim$1(" Is the daemon running? Try: pai daemon status"));
5339
5690
  process.exit(1);
5340
5691
  }
5341
5692
  console.log();
@@ -5345,7 +5696,7 @@ async function cmdList$2(opts) {
5345
5696
  if (opts.type) filterParts.push(`type: ${opts.type}`);
5346
5697
  if (opts.session) filterParts.push(`session: ${opts.session}`);
5347
5698
  filterParts.push(`limit: ${limit}`);
5348
- console.log(dim(` ${filterParts.join(" | ")}`));
5699
+ console.log(dim$1(` ${filterParts.join(" | ")}`));
5349
5700
  console.log();
5350
5701
  if (!observations || observations.length === 0) {
5351
5702
  console.log(warn(" No observations found."));
@@ -5357,18 +5708,18 @@ async function cmdList$2(opts) {
5357
5708
  const TITLE_W = 42;
5358
5709
  const PROJ_W = 14;
5359
5710
  const TS_W = 16;
5360
- console.log(" " + bold("id".padEnd(ID_W)) + " " + bold("type".padEnd(TYPE_W)) + " " + bold("title".padEnd(TITLE_W)) + " " + bold("project".padEnd(PROJ_W)) + " " + bold("created_at"));
5361
- console.log(dim(" " + "-".repeat(ID_W) + " " + "-".repeat(TYPE_W) + " " + "-".repeat(TITLE_W) + " " + "-".repeat(PROJ_W) + " " + "-".repeat(TS_W)));
5711
+ console.log(" " + bold$1("id".padEnd(ID_W)) + " " + bold$1("type".padEnd(TYPE_W)) + " " + bold$1("title".padEnd(TITLE_W)) + " " + bold$1("project".padEnd(PROJ_W)) + " " + bold$1("created_at"));
5712
+ console.log(dim$1(" " + "-".repeat(ID_W) + " " + "-".repeat(TYPE_W) + " " + "-".repeat(TITLE_W) + " " + "-".repeat(PROJ_W) + " " + "-".repeat(TS_W)));
5362
5713
  for (const obs of observations) {
5363
5714
  const idStr = String(obs.id).padStart(ID_W, " ");
5364
5715
  const typeStr = typeColor(obs.type ?? "").padEnd(TYPE_W + (typeColor(obs.type ?? "").length - (obs.type ?? "").length));
5365
5716
  const titleStr = trunc$1(obs.title ?? "", TITLE_W).padEnd(TITLE_W);
5366
5717
  const projStr = trunc$1(obs.project_slug ?? "—", PROJ_W).padEnd(PROJ_W);
5367
5718
  const tsStr = fmtTs$2(obs.created_at);
5368
- console.log(` ${idStr} ${typeStr} ${titleStr} ${projStr} ${dim(tsStr)}`);
5719
+ console.log(` ${idStr} ${typeStr} ${titleStr} ${projStr} ${dim$1(tsStr)}`);
5369
5720
  }
5370
5721
  console.log();
5371
- console.log(dim(` ${observations.length} observation(s)`));
5722
+ console.log(dim$1(` ${observations.length} observation(s)`));
5372
5723
  console.log();
5373
5724
  }
5374
5725
  async function cmdSearch(query, opts) {
@@ -5388,14 +5739,14 @@ async function cmdSearch(query, opts) {
5388
5739
  });
5389
5740
  } catch (e) {
5390
5741
  console.error(err(` Failed to reach PAI daemon: ${e}`));
5391
- console.error(dim(" Is the daemon running? Try: pai daemon status"));
5742
+ console.error(dim$1(" Is the daemon running? Try: pai daemon status"));
5392
5743
  process.exit(1);
5393
5744
  }
5394
5745
  const q = query.toLowerCase();
5395
5746
  const observations = allObservations.filter((o) => (o.title ?? "").toLowerCase().includes(q) || (o.narrative ?? "").toLowerCase().includes(q) || (o.tool_input_summary ?? "").toLowerCase().includes(q)).slice(0, limit);
5396
5747
  console.log();
5397
5748
  console.log(header(" PAI Observation Search"));
5398
- console.log(dim(` Query: "${query}"${opts.project ? ` project: ${opts.project}` : ""}${opts.type ? ` type: ${opts.type}` : ""} limit: ${limit}`));
5749
+ console.log(dim$1(` Query: "${query}"${opts.project ? ` project: ${opts.project}` : ""}${opts.type ? ` type: ${opts.type}` : ""} limit: ${limit}`));
5399
5750
  console.log();
5400
5751
  if (!observations || observations.length === 0) {
5401
5752
  console.log(warn(` No observations matching "${query}".`));
@@ -5406,19 +5757,19 @@ async function cmdSearch(query, opts) {
5406
5757
  const obs = observations[i];
5407
5758
  const idx = chalk.dim(String(i + 1).padStart(3, " "));
5408
5759
  const type = typeColor(obs.type ?? "");
5409
- const title = bold(obs.title ?? "(untitled)");
5410
- const proj = obs.project_slug ? dim(`[${obs.project_slug}]`) : dim("[—]");
5411
- const ts = dim(fmtTs$2(obs.created_at));
5412
- const id = dim(`#${obs.id}`);
5760
+ const title = bold$1(obs.title ?? "(untitled)");
5761
+ const proj = obs.project_slug ? dim$1(`[${obs.project_slug}]`) : dim$1("[—]");
5762
+ const ts = dim$1(fmtTs$2(obs.created_at));
5763
+ const id = dim$1(`#${obs.id}`);
5413
5764
  console.log(` ${idx} ${type.padEnd(12)} ${title}`);
5414
5765
  console.log(` ${proj} ${ts} ${id}`);
5415
5766
  if (obs.narrative) {
5416
5767
  const snippet = trunc$1(obs.narrative.replace(/\n/g, " "), 160);
5417
- console.log(` ${dim(snippet)}`);
5768
+ console.log(` ${dim$1(snippet)}`);
5418
5769
  }
5419
5770
  console.log();
5420
5771
  }
5421
- console.log(dim(` ${observations.length} result(s)`));
5772
+ console.log(dim$1(` ${observations.length} result(s)`));
5422
5773
  console.log();
5423
5774
  }
5424
5775
  async function cmdStats$1() {
@@ -5427,39 +5778,39 @@ async function cmdStats$1() {
5427
5778
  stats = await ipcCall$1("observation_stats", {});
5428
5779
  } catch (e) {
5429
5780
  console.error(err(` Failed to reach PAI daemon: ${e}`));
5430
- console.error(dim(" Is the daemon running? Try: pai daemon status"));
5781
+ console.error(dim$1(" Is the daemon running? Try: pai daemon status"));
5431
5782
  process.exit(1);
5432
5783
  }
5433
5784
  console.log();
5434
5785
  console.log(header(" PAI Observation Statistics"));
5435
5786
  console.log();
5436
- console.log(` ${bold("Total observations:")} ${chalk.cyan(String(stats.total ?? 0))}`);
5437
- if (stats.most_recent) console.log(` ${bold("Most recent:")} ${dim(fmtTs$2(stats.most_recent))}`);
5787
+ console.log(` ${bold$1("Total observations:")} ${chalk.cyan(String(stats.total ?? 0))}`);
5788
+ if (stats.most_recent) console.log(` ${bold$1("Most recent:")} ${dim$1(fmtTs$2(stats.most_recent))}`);
5438
5789
  console.log();
5439
5790
  if (stats.by_type && stats.by_type.length > 0) {
5440
- console.log(bold(" By type:"));
5791
+ console.log(bold$1(" By type:"));
5441
5792
  const maxCount = Math.max(...stats.by_type.map((r) => r.count));
5442
5793
  for (const row of stats.by_type) {
5443
5794
  const barWidth = 20;
5444
5795
  const filled = Math.round(row.count / maxCount * barWidth);
5445
- const bar = chalk.cyan("█".repeat(filled)) + dim("░".repeat(barWidth - filled));
5796
+ const bar = chalk.cyan("█".repeat(filled)) + dim$1("░".repeat(barWidth - filled));
5446
5797
  const label = typeColor(row.type).padEnd(12 + (typeColor(row.type).length - row.type.length));
5447
5798
  console.log(` ${label} ${bar} ${String(row.count).padStart(5)}`);
5448
5799
  }
5449
5800
  console.log();
5450
5801
  }
5451
5802
  if (stats.by_project && stats.by_project.length > 0) {
5452
- console.log(bold(" By project:"));
5803
+ console.log(bold$1(" By project:"));
5453
5804
  const maxCount = Math.max(...stats.by_project.map((r) => r.count));
5454
5805
  const show = stats.by_project.slice(0, 15);
5455
5806
  for (const row of show) {
5456
5807
  const barWidth = 20;
5457
5808
  const filled = Math.round(row.count / maxCount * barWidth);
5458
- const bar = chalk.green("█".repeat(filled)) + dim("░".repeat(barWidth - filled));
5809
+ const bar = chalk.green("█".repeat(filled)) + dim$1("░".repeat(barWidth - filled));
5459
5810
  const label = (row.project_slug ?? "—").padEnd(20);
5460
- console.log(` ${dim(label)} ${bar} ${String(row.count).padStart(5)}`);
5811
+ console.log(` ${dim$1(label)} ${bar} ${String(row.count).padStart(5)}`);
5461
5812
  }
5462
- if (stats.by_project.length > 15) console.log(dim(` ... and ${stats.by_project.length - 15} more project(s)`));
5813
+ if (stats.by_project.length > 15) console.log(dim$1(` ... and ${stats.by_project.length - 15} more project(s)`));
5463
5814
  console.log();
5464
5815
  }
5465
5816
  if ((!stats.by_type || stats.by_type.length === 0) && (!stats.by_project || stats.by_project.length === 0)) {
@@ -5539,12 +5890,12 @@ function ipcCall(method, params) {
5539
5890
  });
5540
5891
  }
5541
5892
  function fmtTs$1(ts) {
5542
- if (!ts) return dim("—");
5893
+ if (!ts) return dim$1("—");
5543
5894
  try {
5544
5895
  const d = new Date(ts);
5545
5896
  return `${d.toISOString().slice(0, 10)} ${d.toISOString().slice(11, 16)}`;
5546
5897
  } catch {
5547
- return dim("—");
5898
+ return dim$1("—");
5548
5899
  }
5549
5900
  }
5550
5901
  function statusColor$1(status) {
@@ -5570,7 +5921,7 @@ async function cmdTelemetry(opts) {
5570
5921
  rows = await ipcCall("skill_telemetry_query", params);
5571
5922
  } catch (e) {
5572
5923
  console.error(err(` Failed to reach PAI daemon: ${e}`));
5573
- console.error(dim(" Is the daemon running? Try: pai daemon status"));
5924
+ console.error(dim$1(" Is the daemon running? Try: pai daemon status"));
5574
5925
  process.exit(1);
5575
5926
  }
5576
5927
  if (opts.json) {
@@ -5579,11 +5930,11 @@ async function cmdTelemetry(opts) {
5579
5930
  }
5580
5931
  console.log();
5581
5932
  console.log(header(" Skill Telemetry"));
5582
- console.log(dim(` scope: ${params.scope}${opts.status ? ` | status: ${opts.status}` : ""}`));
5933
+ console.log(dim$1(` scope: ${params.scope}${opts.status ? ` | status: ${opts.status}` : ""}`));
5583
5934
  console.log();
5584
5935
  if (!rows || rows.length === 0) {
5585
5936
  console.log(warn(" No skill telemetry yet."));
5586
- console.log(dim(" Invoke a skill (e.g. /name) and it will be recorded."));
5937
+ console.log(dim$1(" Invoke a skill (e.g. /name) and it will be recorded."));
5587
5938
  console.log();
5588
5939
  return;
5589
5940
  }
@@ -5592,8 +5943,8 @@ async function cmdTelemetry(opts) {
5592
5943
  const STAT_W = 9;
5593
5944
  const TRIG_W = 8;
5594
5945
  const SEEN_W = 16;
5595
- console.log(" " + bold("skill".padEnd(NAME_W)) + " " + bold("source".padEnd(SRC_W)) + " " + bold("status".padEnd(STAT_W)) + " " + bold("triggers".padStart(TRIG_W)) + " " + bold("last used".padEnd(SEEN_W)) + " " + bold("projects"));
5596
- console.log(dim(" " + "-".repeat(NAME_W + SRC_W + STAT_W + TRIG_W + SEEN_W + 18)));
5946
+ console.log(" " + bold$1("skill".padEnd(NAME_W)) + " " + bold$1("source".padEnd(SRC_W)) + " " + bold$1("status".padEnd(STAT_W)) + " " + bold$1("triggers".padStart(TRIG_W)) + " " + bold$1("last used".padEnd(SEEN_W)) + " " + bold$1("projects"));
5947
+ console.log(dim$1(" " + "-".repeat(NAME_W + SRC_W + STAT_W + TRIG_W + SEEN_W + 18)));
5597
5948
  for (const r of rows) {
5598
5949
  const name = trunc(r.skill_name ?? "", NAME_W).padEnd(NAME_W);
5599
5950
  const src = trunc(r.source ?? "", SRC_W).padEnd(SRC_W);
@@ -5602,10 +5953,10 @@ async function cmdTelemetry(opts) {
5602
5953
  const trig = String(r.trigger_count ?? 0).padStart(TRIG_W);
5603
5954
  const seen = fmtTs$1(r.last_triggered).padEnd(SEEN_W);
5604
5955
  const projs = Array.isArray(r.context_projects) ? r.context_projects.join(", ") : "";
5605
- console.log(` ${chalk.white(name)} ${dim(src)} ${statPad} ${chalk.cyan(trig)} ${dim(seen)} ${dim(trunc(projs, 30))}`);
5956
+ console.log(` ${chalk.white(name)} ${dim$1(src)} ${statPad} ${chalk.cyan(trig)} ${dim$1(seen)} ${dim$1(trunc(projs, 30))}`);
5606
5957
  }
5607
5958
  console.log();
5608
- console.log(dim(` ${rows.length} skill(s)`));
5959
+ console.log(dim$1(` ${rows.length} skill(s)`));
5609
5960
  console.log();
5610
5961
  }
5611
5962
  function registerSkillCommands(parent) {
@@ -5628,7 +5979,7 @@ function step(msg) {
5628
5979
  console.log(chalk.bold.cyan(`\n ${msg}`));
5629
5980
  }
5630
5981
  function info(msg) {
5631
- console.log(dim(` ${msg}`));
5982
+ console.log(dim$1(` ${msg}`));
5632
5983
  }
5633
5984
  function success(msg) {
5634
5985
  console.log(ok(` ${msg}`));
@@ -5643,7 +5994,7 @@ function error(msg) {
5643
5994
  * Run a shell command, streaming output to stdout.
5644
5995
  * Returns true on success, false on failure.
5645
5996
  */
5646
- function run(cmd, cwd) {
5997
+ function run$1(cmd, cwd) {
5647
5998
  try {
5648
5999
  execSync(cmd, {
5649
6000
  stdio: "inherit",
@@ -5744,7 +6095,7 @@ function stepStash(repoDir) {
5744
6095
  function stepPull(repoDir) {
5745
6096
  step("Pulling latest from origin/main...");
5746
6097
  const headBefore = capture("git rev-parse HEAD", repoDir);
5747
- if (!run("git pull origin main", repoDir)) {
6098
+ if (!run$1("git pull origin main", repoDir)) {
5748
6099
  warning("git pull failed. There may be merge conflicts with your stash.");
5749
6100
  return null;
5750
6101
  }
@@ -5792,12 +6143,12 @@ function stepPopStash(repoDir) {
5792
6143
  function stepBuild(repoDir) {
5793
6144
  step("Rebuilding PAI (bun install && bun run build)...");
5794
6145
  info("Installing dependencies...");
5795
- if (!run("bun install", repoDir)) {
6146
+ if (!run$1("bun install", repoDir)) {
5796
6147
  error("bun install failed.");
5797
6148
  return false;
5798
6149
  }
5799
6150
  info("Building...");
5800
- if (!run("bun run build", repoDir)) {
6151
+ if (!run$1("bun run build", repoDir)) {
5801
6152
  error("bun run build failed.");
5802
6153
  return false;
5803
6154
  }
@@ -5911,7 +6262,7 @@ async function runUpdate() {
5911
6262
  console.log(chalk.bold.cyan(" ─────────────────────────────────────"));
5912
6263
  if (newCommitsLog) success("PAI updated successfully!");
5913
6264
  else success("PAI is up to date and rebuilt successfully!");
5914
- console.log(dim(" Version: ") + chalk.cyan(capture("pai --version", repoDir) ?? "unknown"));
6265
+ console.log(dim$1(" Version: ") + chalk.cyan(capture("pai --version", repoDir) ?? "unknown"));
5915
6266
  line();
5916
6267
  }
5917
6268
  function registerUpdateCommand(program) {
@@ -5928,7 +6279,7 @@ function makeClient$1() {
5928
6279
  function modeColor(mode) {
5929
6280
  switch (mode) {
5930
6281
  case "off": return warn(mode);
5931
- case "voice": return bold(ok(mode));
6282
+ case "voice": return bold$1(ok(mode));
5932
6283
  case "auto": return ok(mode);
5933
6284
  default: return ok(mode);
5934
6285
  }
@@ -5937,23 +6288,23 @@ function printConfig(config, activeChannels) {
5937
6288
  console.log();
5938
6289
  console.log(header(" PAI Notification Config"));
5939
6290
  console.log();
5940
- console.log(` ${bold("Mode:")} ${modeColor(config.mode)}`);
6291
+ console.log(` ${bold$1("Mode:")} ${modeColor(config.mode)}`);
5941
6292
  console.log();
5942
- console.log(` ${bold("Channels:")}`);
6293
+ console.log(` ${bold$1("Channels:")}`);
5943
6294
  for (const [ch, cfg] of Object.entries(config.channels)) {
5944
6295
  const c = cfg;
5945
- const status = c.enabled ? ok("enabled") : dim("disabled");
6296
+ const status = c.enabled ? ok("enabled") : dim$1("disabled");
5946
6297
  let extra = "";
5947
- if (ch === "ntfy" && c.url) extra = dim(` ${c.url}`);
5948
- if (ch === "voice" && c.voiceName) extra = dim(` voice: ${c.voiceName}`);
5949
- console.log(` ${bold(ch.padEnd(12))}${status}${extra}`);
6298
+ if (ch === "ntfy" && c.url) extra = dim$1(` ${c.url}`);
6299
+ if (ch === "voice" && c.voiceName) extra = dim$1(` voice: ${c.voiceName}`);
6300
+ console.log(` ${bold$1(ch.padEnd(12))}${status}${extra}`);
5950
6301
  }
5951
6302
  console.log();
5952
- console.log(` ${bold("Active:")} ${activeChannels.length > 0 ? activeChannels.join(", ") : dim("(none)")}`);
6303
+ console.log(` ${bold$1("Active:")} ${activeChannels.length > 0 ? activeChannels.join(", ") : dim$1("(none)")}`);
5953
6304
  console.log();
5954
- console.log(` ${bold("Routing:")} ${dim("(auto mode only)")}`);
6305
+ console.log(` ${bold$1("Routing:")} ${dim$1("(auto mode only)")}`);
5955
6306
  for (const [event, channels] of Object.entries(config.routing)) {
5956
- const ch = channels.join(", ") || dim("(none)");
6307
+ const ch = channels.join(", ") || dim$1("(none)");
5957
6308
  console.log(` ${event.padEnd(12)}→ ${ch}`);
5958
6309
  }
5959
6310
  console.log();
@@ -5967,8 +6318,8 @@ async function cmdStatus() {
5967
6318
  const msg = e instanceof Error ? e.message : String(e);
5968
6319
  console.log();
5969
6320
  console.log(warn(" Cannot reach PAI daemon."));
5970
- console.log(dim(` ${msg}`));
5971
- console.log(dim(" Start it with: pai daemon serve"));
6321
+ console.log(dim$1(` ${msg}`));
6322
+ console.log(dim$1(" Start it with: pai daemon serve"));
5972
6323
  console.log();
5973
6324
  process.exit(1);
5974
6325
  }
@@ -6010,15 +6361,15 @@ async function cmdSet(opts) {
6010
6361
  if (Object.keys(channels).length > 0) patch.channels = channels;
6011
6362
  if (!patch.mode && !patch.channels) {
6012
6363
  console.error(err("No changes specified. Use --mode, --enable, --disable, etc."));
6013
- console.log(dim(" Example: pai notify set --mode voice"));
6014
- console.log(dim(" Example: pai notify set --mode auto --enable macos --disable ntfy"));
6364
+ console.log(dim$1(" Example: pai notify set --mode voice"));
6365
+ console.log(dim$1(" Example: pai notify set --mode auto --enable macos --disable ntfy"));
6015
6366
  process.exit(1);
6016
6367
  }
6017
6368
  try {
6018
6369
  const { config } = await client.setNotificationConfig(patch);
6019
6370
  console.log();
6020
6371
  console.log(ok(" Notification config updated."));
6021
- console.log(` ${bold("Mode:")} ${modeColor(config.mode)}`);
6372
+ console.log(` ${bold$1("Mode:")} ${modeColor(config.mode)}`);
6022
6373
  console.log();
6023
6374
  } catch (e) {
6024
6375
  const msg = e instanceof Error ? e.message : String(e);
@@ -6030,7 +6381,7 @@ async function cmdTest(opts) {
6030
6381
  const client = makeClient$1();
6031
6382
  const event = opts.event ?? "info";
6032
6383
  console.log();
6033
- console.log(dim(` Sending test ${event} notification...`));
6384
+ console.log(dim$1(` Sending test ${event} notification...`));
6034
6385
  try {
6035
6386
  const result = await client.sendNotification({
6036
6387
  event,
@@ -6041,7 +6392,7 @@ async function cmdTest(opts) {
6041
6392
  else if (result.channelsAttempted.length === 0) console.log(warn(" No channels active for this event. Check mode and channel config."));
6042
6393
  else console.log(ok(` Sent to: ${result.channelsSucceeded.join(", ")}`));
6043
6394
  if (result.channelsFailed.length > 0) console.log(warn(` Failed: ${result.channelsFailed.join(", ")}`));
6044
- console.log(dim(` Mode: ${result.mode}`));
6395
+ console.log(dim$1(` Mode: ${result.mode}`));
6045
6396
  console.log();
6046
6397
  } catch (e) {
6047
6398
  const msg = e instanceof Error ? e.message : String(e);
@@ -6102,6 +6453,292 @@ function registerNotifyCommands(notifyCmd) {
6102
6453
  });
6103
6454
  }
6104
6455
 
6456
+ //#endregion
6457
+ //#region src/tasks/dispatch.ts
6458
+ /**
6459
+ * Render a task as a session-to-session message.
6460
+ *
6461
+ * The body is included in full and deliberately not summarised: the whole point
6462
+ * of the description convention is that a task is actionable months later
6463
+ * without re-deriving anything, and truncating it here would undo that.
6464
+ */
6465
+ function renderTask(task) {
6466
+ const parts = [`Task from the bus: ${task.title}`];
6467
+ if (task.due) parts.push(`Due: ${task.due}`);
6468
+ if (task.priority !== "p4") parts.push(`Priority: ${task.priority}`);
6469
+ if (task.body.trim()) parts.push("", task.body.trim());
6470
+ if (task.sourceUrl) parts.push("", `Source: ${task.sourceUrl}`);
6471
+ parts.push("", `Tracker id: ${task.id}`, `When done, run \`pai task done ${task.id}\` so it is not dispatched again.`, "No reply is expected — the process that sent this has already exited.", "If you are blocked, file it back to the tracker with `pai task add` rather than replying.");
6472
+ return parts.join("\n");
6473
+ }
6474
+ async function dispatchTask(task, opts) {
6475
+ if (task.owner.project === null) return {
6476
+ task,
6477
+ outcome: "unrouted",
6478
+ reason: task.owner.rawHint ? `"${task.owner.rawHint}" matches no PAI project` : "no owner label or container"
6479
+ };
6480
+ const project = task.owner.project;
6481
+ if (!opts.autoDispatch || !opts.transport) return {
6482
+ task,
6483
+ outcome: "skipped",
6484
+ session: project,
6485
+ reason: opts.transport ? "autoDispatch is off" : "no transport available — run `pai <project>` to pick this up"
6486
+ };
6487
+ let result;
6488
+ try {
6489
+ result = await opts.transport.dispatch(project, renderTask(task), { spawnIfAbsent: opts.spawnIfAbsent !== false });
6490
+ } catch (e) {
6491
+ return {
6492
+ task,
6493
+ outcome: "unlaunchable",
6494
+ session: project,
6495
+ reason: e instanceof Error ? e.message : String(e)
6496
+ };
6497
+ }
6498
+ if (result.outcome === "unlaunchable" && !result.reason?.includes("pai project name")) return {
6499
+ task,
6500
+ outcome: "unlaunchable",
6501
+ session: result.session ?? project,
6502
+ reason: `${result.reason ?? "no session could be launched"} — give it an alias with \`pai project name <identifier> ${project}\``
6503
+ };
6504
+ return {
6505
+ task,
6506
+ outcome: result.outcome,
6507
+ session: result.session ?? project,
6508
+ reason: result.reason
6509
+ };
6510
+ }
6511
+ /**
6512
+ * Dispatch a batch, sequentially.
6513
+ *
6514
+ * Deliberately not parallel: dispatching spawns terminal tabs and types into
6515
+ * them. Racing that would interleave input across sessions.
6516
+ */
6517
+ async function dispatchAll(tasks, opts) {
6518
+ const results = [];
6519
+ for (const task of tasks) results.push(await dispatchTask(task, opts));
6520
+ return results;
6521
+ }
6522
+
6523
+ //#endregion
6524
+ //#region src/tasks/transport/aibroker.ts
6525
+ /**
6526
+ * aibroker.ts — AIBroker transport for the task bus
6527
+ *
6528
+ * Shells out to the `aibroker` CLI. PAI's CLI cannot call MCP tools, so the
6529
+ * MCP-only dispatch primitives are unreachable from a shell — this is the
6530
+ * bridge.
6531
+ *
6532
+ * Optional by design: when AIBroker is not installed, `detect()` returns null
6533
+ * and the bus reports ownership instead of delivering. PAI must stay useful on
6534
+ * machines that do not run iTerm2.
6535
+ *
6536
+ * See Notes/docs/task-bus.md.
6537
+ */
6538
+ /** Long enough to cover launching a terminal tab and waiting for it to settle. */
6539
+ const DISPATCH_TIMEOUT_MS = 6e4;
6540
+ const VALID_OUTCOMES = new Set([
6541
+ "delivered",
6542
+ "spawned",
6543
+ "unlaunchable",
6544
+ "unreachable",
6545
+ "skipped"
6546
+ ]);
6547
+ /**
6548
+ * Run `aibroker dispatch`, feeding the message over stdin.
6549
+ *
6550
+ * stdin rather than argv is deliberate: task bodies carry the full procedure
6551
+ * and reasoning, so they are long, multi-line, and full of quotes and
6552
+ * backticks. argv would mangle them or hit length limits.
6553
+ */
6554
+ function run(bin, args, stdin) {
6555
+ return new Promise((resolve, reject) => {
6556
+ execFile(bin, args, {
6557
+ timeout: DISPATCH_TIMEOUT_MS,
6558
+ maxBuffer: 1024 * 1024
6559
+ }, (error, stdout, stderr) => {
6560
+ if (error && !stdout.trim().startsWith("{")) {
6561
+ reject(new Error(stderr.trim() || error.message));
6562
+ return;
6563
+ }
6564
+ resolve(stdout);
6565
+ }).stdin?.end(stdin);
6566
+ });
6567
+ }
6568
+ var AiBrokerTransport = class {
6569
+ constructor(bin = "aibroker") {
6570
+ this.bin = bin;
6571
+ }
6572
+ async dispatch(project, message, opts) {
6573
+ const args = [
6574
+ "dispatch",
6575
+ project,
6576
+ "--stdin",
6577
+ "--json"
6578
+ ];
6579
+ if (!opts.spawnIfAbsent) args.push("--no-spawn");
6580
+ const stdout = await run(this.bin, args, message);
6581
+ const start = stdout.lastIndexOf("{");
6582
+ if (start === -1) throw new Error(`aibroker returned no JSON: ${stdout.trim().slice(0, 200)}`);
6583
+ let wire;
6584
+ try {
6585
+ wire = JSON.parse(stdout.slice(start));
6586
+ } catch {
6587
+ throw new Error(`aibroker returned malformed JSON: ${stdout.trim().slice(0, 200)}`);
6588
+ }
6589
+ if (!wire.outcome || !VALID_OUTCOMES.has(wire.outcome)) return {
6590
+ outcome: "unlaunchable",
6591
+ session: wire.session ?? project,
6592
+ reason: `unexpected outcome from aibroker: ${String(wire.outcome)}`
6593
+ };
6594
+ return {
6595
+ outcome: wire.outcome,
6596
+ session: wire.session ?? wire.project ?? project,
6597
+ reason: wire.reason
6598
+ };
6599
+ }
6600
+ };
6601
+ /**
6602
+ * Return a transport if the `aibroker` CLI is present and supports dispatch.
6603
+ *
6604
+ * Probing for the subcommand rather than just the binary matters: AIBroker
6605
+ * shipped for a long time without `dispatch`, and an older install would
6606
+ * otherwise fail once per task instead of degrading cleanly up front.
6607
+ */
6608
+ async function detectAiBroker(bin = "aibroker") {
6609
+ try {
6610
+ return (await new Promise((resolve, reject) => {
6611
+ execFile(bin, ["help"], { timeout: 1e4 }, (error, stdout, stderr) => {
6612
+ if (error && !stdout) reject(error);
6613
+ else resolve(stdout + stderr);
6614
+ });
6615
+ })).includes("dispatch") ? new AiBrokerTransport(bin) : null;
6616
+ } catch {
6617
+ return null;
6618
+ }
6619
+ }
6620
+
6621
+ //#endregion
6622
+ //#region src/cli/commands/task.ts
6623
+ const dim = chalk.dim;
6624
+ const bold = chalk.bold;
6625
+ function buildProvider() {
6626
+ const tasks = loadConfig().tasks;
6627
+ if (!tasks?.enabled) return null;
6628
+ const aliases = loadAliasMap(openRegistry());
6629
+ const provider = new TodoistProvider(tasks.providers.todoist, aliases);
6630
+ return provider.isConfigured() ? provider : null;
6631
+ }
6632
+ /** Print the one message that actually helps when nothing is configured. */
6633
+ function reportUnconfigured() {
6634
+ console.error(chalk.yellow(" Task bus is not configured."));
6635
+ console.error(dim(" Run `pai setup` and complete the Task Bus step."));
6636
+ }
6637
+ function todayIso() {
6638
+ return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
6639
+ }
6640
+ function renderOwner(task) {
6641
+ if (task.owner.project) {
6642
+ const via = task.owner.source === "label" ? "label" : "container";
6643
+ return chalk.cyan(task.owner.project) + dim(` (${via})`);
6644
+ }
6645
+ return task.owner.rawHint ? chalk.yellow("unrouted") + dim(` (${task.owner.rawHint} matches no project)`) : chalk.yellow("unrouted");
6646
+ }
6647
+ function printTasks(tasks) {
6648
+ if (tasks.length === 0) {
6649
+ console.log(dim(" Nothing open."));
6650
+ return;
6651
+ }
6652
+ console.log();
6653
+ for (const t of tasks) {
6654
+ const due = t.due ? dim(` due ${t.due.slice(0, 10)}`) : "";
6655
+ const prio = t.priority !== "p4" ? dim(` ${t.priority}`) : "";
6656
+ console.log(` ${bold(t.title)}${prio}${due}`);
6657
+ console.log(` ${renderOwner(t)} ${dim("· " + t.id)}`);
6658
+ }
6659
+ console.log();
6660
+ }
6661
+ function printResults(results) {
6662
+ const symbol = {
6663
+ delivered: chalk.green("→"),
6664
+ spawned: chalk.green("+"),
6665
+ unrouted: chalk.yellow("?"),
6666
+ unlaunchable: chalk.red("!"),
6667
+ unreachable: chalk.red("✗"),
6668
+ skipped: dim("·")
6669
+ };
6670
+ console.log();
6671
+ for (const r of results) {
6672
+ console.log(` ${symbol[r.outcome]} ${r.task.title}`);
6673
+ const detail = [r.session, r.reason].filter(Boolean).join(" — ");
6674
+ if (detail) console.log(` ${dim(detail)}`);
6675
+ }
6676
+ console.log();
6677
+ const counts = results.reduce((acc, r) => {
6678
+ acc[r.outcome] = (acc[r.outcome] ?? 0) + 1;
6679
+ return acc;
6680
+ }, {});
6681
+ console.log(dim(" " + Object.entries(counts).map(([k, v]) => `${v} ${k}`).join(", ")));
6682
+ console.log();
6683
+ }
6684
+ function registerTaskCommands(taskCmd) {
6685
+ taskCmd.command("list").description("List open tasks on the bus").option("--owner <project>", "Only tasks owned by this PAI project").option("--due <date>", "Only tasks due on or before this ISO date").option("--today", "Shorthand for --due <today>").option("--routed", "Hide tasks with no resolved owner").option("--limit <n>", "Maximum tasks to show", (v) => Number.parseInt(v, 10)).action(async (opts) => {
6686
+ const provider = buildProvider();
6687
+ if (!provider) return reportUnconfigured();
6688
+ printTasks(await provider.listOpen({
6689
+ owner: opts.owner,
6690
+ dueBefore: opts.today ? todayIso() : opts.due,
6691
+ includeUnrouted: !opts.routed,
6692
+ limit: opts.limit
6693
+ }));
6694
+ });
6695
+ taskCmd.command("add <title>").description("File a task onto the bus").option("--owner <project>", "PAI project that owns this (adds a pai: label)").option("--body <text>", "Full procedure and reasoning — not just a restatement of the title").option("--due <date>", "Due date (ISO or natural language)").option("--priority <p>", "p1 (highest) … p4 (default)").option("--url <url>", "Reference — prefer a hook:// URL over a file path").action(async (title, opts) => {
6696
+ const provider = buildProvider();
6697
+ if (!provider) return reportUnconfigured();
6698
+ if (!opts.body) {
6699
+ console.log(dim(" No --body given. Add the procedure and reasoning so this"));
6700
+ console.log(dim(" is still actionable months from now, by you alone."));
6701
+ }
6702
+ const created = await provider.add({
6703
+ title,
6704
+ body: opts.body ?? "",
6705
+ owner: opts.owner ?? null,
6706
+ due: opts.due,
6707
+ priority: opts.priority,
6708
+ sourceUrl: opts.url
6709
+ });
6710
+ console.log(chalk.green(` Filed: ${created.title}`));
6711
+ console.log(` ${renderOwner(created)} ${dim("· " + created.id)}`);
6712
+ });
6713
+ taskCmd.command("dispatch").description("Hand open tasks to the PAI sessions that own them").option("--owner <project>", "Only dispatch tasks for this project").option("--today", "Only tasks due today or overdue").option("--dry-run", "Report what would happen without contacting any session").option("--no-spawn", "Never launch a session; skip owners that are not running").action(async (opts) => {
6714
+ const provider = buildProvider();
6715
+ if (!provider) return reportUnconfigured();
6716
+ const config = loadConfig();
6717
+ const tasks = await provider.listOpen({
6718
+ owner: opts.owner,
6719
+ dueBefore: opts.today ? todayIso() : void 0,
6720
+ includeUnrouted: true
6721
+ });
6722
+ if (tasks.length === 0) {
6723
+ console.log(dim(" Nothing to dispatch."));
6724
+ return;
6725
+ }
6726
+ const transport = opts.dryRun ? null : await detectAiBroker();
6727
+ if (!opts.dryRun && !transport) console.log(dim(" No aibroker CLI with `dispatch` found — reporting ownership only."));
6728
+ printResults(await dispatchAll(tasks, {
6729
+ transport,
6730
+ autoDispatch: opts.dryRun ? false : config.tasks?.autoDispatch ?? false,
6731
+ spawnIfAbsent: opts.spawn !== false
6732
+ }));
6733
+ });
6734
+ taskCmd.command("done <id>").description("Mark a task complete on the tracker").action(async (id) => {
6735
+ const provider = buildProvider();
6736
+ if (!provider) return reportUnconfigured();
6737
+ await provider.complete(id);
6738
+ console.log(chalk.green(` Completed ${id}.`));
6739
+ });
6740
+ }
6741
+
6105
6742
  //#endregion
6106
6743
  //#region src/cli/commands/topic.ts
6107
6744
  function makeClient() {
@@ -6116,32 +6753,32 @@ function printTopicResult(result) {
6116
6753
  console.log();
6117
6754
  console.log(header(" PAI Topic Check"));
6118
6755
  console.log();
6119
- console.log(` ${bold("Current project:")} ${result.currentProject ?? dim("(none)")}`);
6120
- console.log(` ${bold("Suggested project:")} ${result.suggestedProject ?? dim("(none)")}`);
6121
- console.log(` ${bold("Confidence:")} ${confidenceBar(result.confidence)} ${(result.confidence * 100).toFixed(1)}%`);
6122
- console.log(` ${bold("Chunks scored:")} ${result.chunkCount}`);
6756
+ console.log(` ${bold$1("Current project:")} ${result.currentProject ?? dim$1("(none)")}`);
6757
+ console.log(` ${bold$1("Suggested project:")} ${result.suggestedProject ?? dim$1("(none)")}`);
6758
+ console.log(` ${bold$1("Confidence:")} ${confidenceBar(result.confidence)} ${(result.confidence * 100).toFixed(1)}%`);
6759
+ console.log(` ${bold$1("Chunks scored:")} ${result.chunkCount}`);
6123
6760
  if (result.topProjects.length > 0) {
6124
6761
  console.log();
6125
- console.log(` ${bold("Top matches:")}`);
6762
+ console.log(` ${bold$1("Top matches:")}`);
6126
6763
  for (const p of result.topProjects) {
6127
6764
  const bar = confidenceBar(p.score, 15);
6128
- const marker = p.slug === result.currentProject ? dim(" (current)") : "";
6765
+ const marker = p.slug === result.currentProject ? dim$1(" (current)") : "";
6129
6766
  console.log(` ${p.slug.padEnd(30)} ${bar} ${(p.score * 100).toFixed(1)}%${marker}`);
6130
6767
  }
6131
6768
  }
6132
6769
  console.log();
6133
6770
  if (result.shifted) {
6134
- console.log(warn(" TOPIC SHIFT DETECTED") + dim(` — conversation appears to be about "${result.suggestedProject}", not "${result.currentProject}"`));
6771
+ console.log(warn(" TOPIC SHIFT DETECTED") + dim$1(` — conversation appears to be about "${result.suggestedProject}", not "${result.currentProject}"`));
6135
6772
  console.log();
6136
6773
  } else if (result.suggestedProject && result.suggestedProject === result.currentProject) {
6137
- console.log(ok(" No shift detected") + dim(" — context matches current project"));
6774
+ console.log(ok(" No shift detected") + dim$1(" — context matches current project"));
6138
6775
  console.log();
6139
6776
  } else if (!result.currentProject) {
6140
- if (result.suggestedProject) console.log(ok(" Best matching project: ") + bold(result.suggestedProject) + dim(` (confidence: ${(result.confidence * 100).toFixed(0)}%)`));
6141
- else console.log(dim(" No matching project found in memory index."));
6777
+ if (result.suggestedProject) console.log(ok(" Best matching project: ") + bold$1(result.suggestedProject) + dim$1(` (confidence: ${(result.confidence * 100).toFixed(0)}%)`));
6778
+ else console.log(dim$1(" No matching project found in memory index."));
6142
6779
  console.log();
6143
6780
  } else {
6144
- console.log(dim(` No shift detected (top match "${result.suggestedProject}" has confidence ${(result.confidence * 100).toFixed(0)}% — below threshold)`));
6781
+ console.log(dim$1(` No shift detected (top match "${result.suggestedProject}" has confidence ${(result.confidence * 100).toFixed(0)}% — below threshold)`));
6145
6782
  console.log();
6146
6783
  }
6147
6784
  }
@@ -6168,8 +6805,8 @@ async function cmdCheck(context, opts) {
6168
6805
  const msg = e instanceof Error ? e.message : String(e);
6169
6806
  console.log();
6170
6807
  console.log(warn(" Cannot reach PAI daemon."));
6171
- console.log(dim(` ${msg}`));
6172
- console.log(dim(" Start it with: pai daemon serve"));
6808
+ console.log(dim$1(` ${msg}`));
6809
+ console.log(dim$1(" Start it with: pai daemon serve"));
6173
6810
  console.log();
6174
6811
  process.exit(1);
6175
6812
  }
@@ -6342,7 +6979,7 @@ async function getPool$1() {
6342
6979
  const config = loadConfig();
6343
6980
  if (config.storageBackend !== "postgres") {
6344
6981
  console.error(err(" KG commands require Postgres backend."));
6345
- console.error(dim(" Set \"storageBackend\": \"postgres\" in ~/.config/pai/config.json"));
6982
+ console.error(dim$1(" Set \"storageBackend\": \"postgres\" in ~/.config/pai/config.json"));
6346
6983
  process.exit(1);
6347
6984
  }
6348
6985
  const backend = await createStorageBackend(config);
@@ -6367,9 +7004,9 @@ async function cmdBackfill(opts) {
6367
7004
  console.log();
6368
7005
  console.log(header(" PAI KG Backfill"));
6369
7006
  console.log();
6370
- if (opts.project) console.log(` ${bold("Project:")} ${opts.project}`);
6371
- if (limit) console.log(` ${bold("Limit:")} ${limit}`);
6372
- if (opts.dryRun) console.log(` ${bold("Mode:")} ${warn("dry-run")}`);
7007
+ if (opts.project) console.log(` ${bold$1("Project:")} ${opts.project}`);
7008
+ if (limit) console.log(` ${bold$1("Limit:")} ${limit}`);
7009
+ if (opts.dryRun) console.log(` ${bold$1("Mode:")} ${warn("dry-run")}`);
6373
7010
  console.log();
6374
7011
  try {
6375
7012
  const result = await backfillKgFromNotes({
@@ -6378,15 +7015,15 @@ async function cmdBackfill(opts) {
6378
7015
  dryRun: opts.dryRun,
6379
7016
  onProgress: (current, total, note) => {
6380
7017
  const short = shorten$1(note.replace(process.env.HOME ?? "", "~"), 70);
6381
- process.stdout.write(` [${current}/${total}] ${dim(short)}\n`);
7018
+ process.stdout.write(` [${current}/${total}] ${dim$1(short)}\n`);
6382
7019
  }
6383
7020
  });
6384
7021
  console.log();
6385
7022
  console.log(ok(" Backfill complete"));
6386
- console.log(` Notes processed: ${bold(String(result.notes_processed))}`);
6387
- console.log(` Triples extracted: ${bold(String(result.triples_extracted))}`);
6388
- console.log(` Triples added: ${bold(String(result.triples_added))}`);
6389
- console.log(` Triples superseded: ${bold(String(result.triples_superseded))}`);
7023
+ console.log(` Notes processed: ${bold$1(String(result.notes_processed))}`);
7024
+ console.log(` Triples extracted: ${bold$1(String(result.triples_extracted))}`);
7025
+ console.log(` Triples added: ${bold$1(String(result.triples_added))}`);
7026
+ console.log(` Triples superseded: ${bold$1(String(result.triples_superseded))}`);
6390
7027
  if (result.errors > 0) console.log(` ${warn("Errors:")} ${result.errors}`);
6391
7028
  console.log();
6392
7029
  } catch (e) {
@@ -6424,8 +7061,8 @@ async function cmdQuery$1(opts) {
6424
7061
  console.log(header(` ${triples.length} triple(s)`));
6425
7062
  console.log();
6426
7063
  for (const t of triples) {
6427
- const validity = t.valid_to ? dim(`(invalidated ${t.valid_to.toISOString().slice(0, 10)})`) : dim(`(valid since ${t.valid_from.toISOString().slice(0, 10)})`);
6428
- console.log(` ${bold(t.subject)} ${dim("·")} ${t.predicate} ${dim("·")} ${t.object} ${validity}`);
7064
+ const validity = t.valid_to ? dim$1(`(invalidated ${t.valid_to.toISOString().slice(0, 10)})`) : dim$1(`(valid since ${t.valid_from.toISOString().slice(0, 10)})`);
7065
+ console.log(` ${bold$1(t.subject)} ${dim$1("·")} ${t.predicate} ${dim$1("·")} ${t.object} ${validity}`);
6429
7066
  }
6430
7067
  console.log();
6431
7068
  } finally {
@@ -6446,10 +7083,10 @@ async function cmdList$1(opts) {
6446
7083
  console.log();
6447
7084
  console.log(header(` ${slice.length} of ${triples.length} currently-valid triple(s)`));
6448
7085
  console.log();
6449
- for (const t of slice) console.log(` ${bold(t.subject)} ${dim("·")} ${t.predicate} ${dim("·")} ${t.object}`);
7086
+ for (const t of slice) console.log(` ${bold$1(t.subject)} ${dim$1("·")} ${t.predicate} ${dim$1("·")} ${t.object}`);
6450
7087
  if (triples.length > slice.length) {
6451
7088
  console.log();
6452
- console.log(dim(` (${triples.length - slice.length} more — increase --limit)`));
7089
+ console.log(dim$1(` (${triples.length - slice.length} more — increase --limit)`));
6453
7090
  }
6454
7091
  console.log();
6455
7092
  } finally {
@@ -6477,12 +7114,12 @@ async function cmdStats() {
6477
7114
  console.log();
6478
7115
  console.log(header(" PAI KG Stats"));
6479
7116
  console.log();
6480
- console.log(` ${bold("Total triples:")} ${row.total ?? "0"}`);
6481
- console.log(` ${bold("Currently valid:")} ${row.valid ?? "0"}`);
6482
- console.log(` ${bold("Invalidated:")} ${row.invalidated ?? "0"}`);
6483
- console.log(` ${bold("Distinct subjects:")} ${row.subjects ?? "0"}`);
6484
- console.log(` ${bold("Distinct predicates:")} ${row.predicates ?? "0"}`);
6485
- console.log(` ${bold("Contradictions:")} ${contradictions.rows[0]?.count ?? "0"}`);
7117
+ console.log(` ${bold$1("Total triples:")} ${row.total ?? "0"}`);
7118
+ console.log(` ${bold$1("Currently valid:")} ${row.valid ?? "0"}`);
7119
+ console.log(` ${bold$1("Invalidated:")} ${row.invalidated ?? "0"}`);
7120
+ console.log(` ${bold$1("Distinct subjects:")} ${row.subjects ?? "0"}`);
7121
+ console.log(` ${bold$1("Distinct predicates:")} ${row.predicates ?? "0"}`);
7122
+ console.log(` ${bold$1("Contradictions:")} ${contradictions.rows[0]?.count ?? "0"}`);
6486
7123
  console.log();
6487
7124
  } finally {
6488
7125
  await close();
@@ -6642,25 +7279,25 @@ function printResult(result, json) {
6642
7279
  }
6643
7280
  if (result.rows.length === 0) {
6644
7281
  console.log();
6645
- console.log(dim(" (no rows)"));
7282
+ console.log(dim$1(" (no rows)"));
6646
7283
  console.log();
6647
7284
  return;
6648
7285
  }
6649
7286
  const stringRows = result.rows.map((row) => row.map((cell) => {
6650
- if (cell === null || cell === void 0) return dim("NULL");
7287
+ if (cell === null || cell === void 0) return dim$1("NULL");
6651
7288
  if (typeof cell === "object") return JSON.stringify(cell);
6652
7289
  return String(cell);
6653
7290
  }));
6654
7291
  console.log();
6655
7292
  console.log(renderTable(result.columns, stringRows));
6656
7293
  console.log();
6657
- console.log(dim(` ${result.rows.length} row(s)`));
7294
+ console.log(dim$1(` ${result.rows.length} row(s)`));
6658
7295
  console.log();
6659
7296
  }
6660
7297
  async function cmdQuery(sql, opts) {
6661
7298
  const target = opts.db ?? "sqlite";
6662
7299
  console.log();
6663
- console.log(header(` Query [${target}]`) + dim(` ${sql.slice(0, 80)}${sql.length > 80 ? "…" : ""}`));
7300
+ console.log(header(` Query [${target}]`) + dim$1(` ${sql.slice(0, 80)}${sql.length > 80 ? "…" : ""}`));
6664
7301
  try {
6665
7302
  let result;
6666
7303
  if (target === "postgres") result = await postgresQuery(sql);
@@ -6685,10 +7322,10 @@ async function cmdTables(opts) {
6685
7322
  console.log(JSON.stringify(tables, null, 2));
6686
7323
  return;
6687
7324
  }
6688
- if (tables.length === 0) console.log(dim(" (no tables found)"));
6689
- else for (const t of tables) console.log(` ${bold(t)}`);
7325
+ if (tables.length === 0) console.log(dim$1(" (no tables found)"));
7326
+ else for (const t of tables) console.log(` ${bold$1(t)}`);
6690
7327
  console.log();
6691
- console.log(dim(` ${tables.length} table(s)`));
7328
+ console.log(dim$1(` ${tables.length} table(s)`));
6692
7329
  console.log();
6693
7330
  } catch (e) {
6694
7331
  const msg = e instanceof Error ? e.message : String(e);
@@ -6780,11 +7417,11 @@ function renderMarkdown(md) {
6780
7417
  continue;
6781
7418
  }
6782
7419
  if (/^>\s?/.test(line)) {
6783
- out.push(dim(line.replace(/^>\s?/, "")));
7420
+ out.push(dim$1(line.replace(/^>\s?/, "")));
6784
7421
  continue;
6785
7422
  }
6786
7423
  if (/^\|?\s*[-:]+\s*(\|\s*[-:]+\s*)+\|?$/.test(line)) {
6787
- out.push(dim(line));
7424
+ out.push(dim$1(line));
6788
7425
  continue;
6789
7426
  }
6790
7427
  out.push(inlineBold(line));
@@ -6800,7 +7437,7 @@ function registerHelpCommand(program) {
6800
7437
  const docsDir = findDocsDir();
6801
7438
  if (!docsDir) {
6802
7439
  console.error(err(" Command docs not found."));
6803
- console.error(dim(" Run `bun run build` to generate them, or use `pai <area> --help`."));
7440
+ console.error(dim$1(" Run `bun run build` to generate them, or use `pai <area> --help`."));
6804
7441
  process.exitCode = 1;
6805
7442
  return;
6806
7443
  }
@@ -6812,7 +7449,7 @@ function registerHelpCommand(program) {
6812
7449
  } else {
6813
7450
  console.log(chalk.bold("\nPAI command areas\n"));
6814
7451
  for (const a of listAreas(docsDir)) console.log(` ${a}`);
6815
- console.log(dim("\n pai help <area> show the man page for an area"));
7452
+ console.log(dim$1("\n pai help <area> show the man page for an area"));
6816
7453
  }
6817
7454
  return;
6818
7455
  }
@@ -6825,9 +7462,9 @@ function registerHelpCommand(program) {
6825
7462
  console.error(err(` No man page for "${area}".`));
6826
7463
  const areas = listAreas(docsDir);
6827
7464
  const near = areas.filter((a) => a.includes(area) || area.includes(a));
6828
- if (near.length > 0) console.error(dim(` Did you mean: ${near.join(", ")}?`));
6829
- else console.error(dim(` Available: ${areas.join(", ")}`));
6830
- console.error(dim(` Or try: pai ${area} --help`));
7465
+ if (near.length > 0) console.error(dim$1(` Did you mean: ${near.join(", ")}?`));
7466
+ else console.error(dim$1(` Available: ${areas.join(", ")}`));
7467
+ console.error(dim$1(` Or try: pai ${area} --help`));
6831
7468
  process.exitCode = 1;
6832
7469
  });
6833
7470
  }
@@ -7269,7 +7906,7 @@ async function cmdPauseAll(opts) {
7269
7906
  liveSessions = await fetchLiveSessions();
7270
7907
  } catch (e) {
7271
7908
  console.error(err("AIBroker is not running. Cannot list live sessions."));
7272
- console.error(dim(" Start AIBroker or run `pai pause` from each session manually."));
7909
+ console.error(dim$1(" Start AIBroker or run `pai pause` from each session manually."));
7273
7910
  process.exitCode = 1;
7274
7911
  return;
7275
7912
  }
@@ -7284,13 +7921,13 @@ async function cmdPauseAll(opts) {
7284
7921
  console.log("\n" + header("Dry Run — Would Pause These Sessions") + "\n");
7285
7922
  for (const s of claudeSessions) {
7286
7923
  console.log(" " + sessionLabel(s));
7287
- console.log(dim(" → send: \"pause session\""));
7288
- if (opts.exit) console.log(dim(` → wait ${waitMs}ms then send: "/exit"`));
7924
+ console.log(dim$1(" → send: \"pause session\""));
7925
+ if (opts.exit) console.log(dim$1(` → wait ${waitMs}ms then send: "/exit"`));
7289
7926
  }
7290
7927
  console.log();
7291
7928
  return;
7292
7929
  }
7293
- console.log("\n" + header("Pausing All Live Sessions") + "\n" + dim(` ${claudeSessions.length} Claude session(s) via AIBroker`) + "\n");
7930
+ console.log("\n" + header("Pausing All Live Sessions") + "\n" + dim$1(` ${claudeSessions.length} Claude session(s) via AIBroker`) + "\n");
7294
7931
  const results = [];
7295
7932
  for (const s of claudeSessions) {
7296
7933
  process.stdout.write(" " + sessionLabel(s) + " … ");
@@ -7313,7 +7950,7 @@ async function cmdPauseAll(opts) {
7313
7950
  if (opts.exit) {
7314
7951
  const pausedSessions = results.filter((r) => r.pauseOk).map((r) => r.session);
7315
7952
  if (pausedSessions.length > 0) {
7316
- console.log("\n" + dim(` Waiting ${waitMs / 1e3}s for sessions to save state…`));
7953
+ console.log("\n" + dim$1(` Waiting ${waitMs / 1e3}s for sessions to save state…`));
7317
7954
  await sleep(waitMs);
7318
7955
  console.log();
7319
7956
  for (const s of pausedSessions) {
@@ -7340,7 +7977,7 @@ async function cmdPauseAll(opts) {
7340
7977
  }
7341
7978
  if (opts.exit) {
7342
7979
  const exitOk = results.filter((r) => r.exitOk).length;
7343
- console.log(dim(` /exit sent to ${exitOk} session(s).`));
7980
+ console.log(dim$1(` /exit sent to ${exitOk} session(s).`));
7344
7981
  }
7345
7982
  console.log();
7346
7983
  }
@@ -7361,9 +7998,9 @@ async function cmdPauseAll(opts) {
7361
7998
  */
7362
7999
  async function cmdClearNames(opts) {
7363
8000
  if (opts.dryRun) {
7364
- console.log(dim("Dry run — would:"));
7365
- console.log(dim(" 1. Call AIBroker clear_session_names (wipe session-names.json)"));
7366
- console.log(dim(" 2. Call AIBroker clear_pai_names (wipe user.paiName from all iTerm sessions)"));
8001
+ console.log(dim$1("Dry run — would:"));
8002
+ console.log(dim$1(" 1. Call AIBroker clear_session_names (wipe session-names.json)"));
8003
+ console.log(dim$1(" 2. Call AIBroker clear_pai_names (wipe user.paiName from all iTerm sessions)"));
7367
8004
  return;
7368
8005
  }
7369
8006
  let anyFailed = false;
@@ -7463,9 +8100,9 @@ function cmdList(db, projectSlug, opts) {
7463
8100
  ];
7464
8101
  const tableRows = rows.map((r) => {
7465
8102
  const title = r.title.length > 45 ? r.title.slice(0, 42) + "..." : r.title;
7466
- const tokens = r.token_count != null ? dim(r.token_count.toLocaleString()) : dim("—");
8103
+ const tokens = r.token_count != null ? dim$1(r.token_count.toLocaleString()) : dim$1("—");
7467
8104
  if (showProject) return [
7468
- dim(`#${r.number}`),
8105
+ dim$1(`#${r.number}`),
7469
8106
  r.project_slug,
7470
8107
  r.date,
7471
8108
  title,
@@ -7473,7 +8110,7 @@ function cmdList(db, projectSlug, opts) {
7473
8110
  tokens
7474
8111
  ];
7475
8112
  return [
7476
- dim(`#${r.number}`),
8113
+ dim$1(`#${r.number}`),
7477
8114
  r.date,
7478
8115
  title,
7479
8116
  statusColor(r.status),
@@ -7483,12 +8120,12 @@ function cmdList(db, projectSlug, opts) {
7483
8120
  console.log();
7484
8121
  if (projectSlug) {
7485
8122
  const project = getProject(db, projectSlug);
7486
- console.log(` ${bold(project.display_name)} sessions:`);
8123
+ console.log(` ${bold$1(project.display_name)} sessions:`);
7487
8124
  console.log();
7488
8125
  }
7489
8126
  console.log(renderTable(headers, tableRows));
7490
8127
  console.log();
7491
- console.log(dim(` ${rows.length} session(s) shown (limit: ${limit})`));
8128
+ console.log(dim$1(` ${rows.length} session(s) shown (limit: ${limit})`));
7492
8129
  }
7493
8130
 
7494
8131
  //#endregion
@@ -7589,11 +8226,11 @@ async function cmdFind(query, opts) {
7589
8226
  }
7590
8227
  if (matches.length === 0) {
7591
8228
  console.log(warn(`No sessions found matching "${query}" in ~/.claude/history.jsonl.`));
7592
- console.log(dim(` Try a shorter or different search term.`));
8229
+ console.log(dim$1(` Try a shorter or different search term.`));
7593
8230
  return;
7594
8231
  }
7595
8232
  console.log("\n" + header("Session Search Results") + "\n");
7596
- console.log(dim(` Query: "${query}" (${matches.length} session(s) with matching prompts)\n`));
8233
+ console.log(dim$1(` Query: "${query}" (${matches.length} session(s) with matching prompts)\n`));
7597
8234
  const headers = [
7598
8235
  "#",
7599
8236
  "id",
@@ -7603,21 +8240,21 @@ async function cmdFind(query, opts) {
7603
8240
  ];
7604
8241
  const rows = matches.map((m, idx) => {
7605
8242
  const shortId = (m.sessionId ?? "no-session").slice(0, 8);
7606
- const when = m.lastMatchTs > 0 ? fmtTs(m.lastMatchTs) : dim("—");
7607
- const project = shortenProject(m.project || dim("—"));
8243
+ const when = m.lastMatchTs > 0 ? fmtTs(m.lastMatchTs) : dim$1("—");
8244
+ const project = shortenProject(m.project || dim$1("—"));
7608
8245
  const snippet = m.lastMatchDisplay.replace(/\n+/g, " ").trim().slice(0, 48);
7609
8246
  const display = snippet.length < m.lastMatchDisplay.replace(/\n+/g, " ").trim().length ? `"${snippet}…"` : `"${snippet}"`;
7610
8247
  return [
7611
- dim(String(idx + 1)),
8248
+ dim$1(String(idx + 1)),
7612
8249
  chalk.cyan(shortId),
7613
8250
  when,
7614
- dim(project),
8251
+ dim$1(project),
7615
8252
  chalk.dim(display)
7616
8253
  ];
7617
8254
  });
7618
8255
  console.log(renderTable(headers, rows));
7619
8256
  console.log();
7620
- console.log(dim(" Resume: ") + chalk.white("pai resume <id>"));
8257
+ console.log(dim$1(" Resume: ") + chalk.white("pai resume <id>"));
7621
8258
  console.log();
7622
8259
  }
7623
8260
 
@@ -7902,9 +8539,9 @@ function buildFeedFrom(allSessions, projects, liveSessions, allProjects) {
7902
8539
  const kw = dir ? noteKeywords(dir) : "";
7903
8540
  const tag = tagFor(e.status);
7904
8541
  const name = chalk.white(pad(e.name, 22));
7905
- const where = dir ? dim(shorten(dir, 40)) : chalk.green("(running in another tab)");
7906
- const age = e.status === "live" ? chalk.green("now") : e.lastActivity > 0 ? dim(fmtAge(e.lastActivity)) : dim("—");
7907
- const kwDisp = kw ? dim(" " + kw) : "";
8542
+ const where = dir ? dim$1(shorten(dir, 40)) : chalk.green("(running in another tab)");
8543
+ const age = e.status === "live" ? chalk.green("now") : e.lastActivity > 0 ? dim$1(fmtAge(e.lastActivity)) : dim$1("—");
8544
+ const kwDisp = kw ? dim$1(" " + kw) : "";
7908
8545
  const display = `${tag} ${name} ${pad(age, 5)} ${where}${kwDisp}`;
7909
8546
  const search = `${e.name} ${dir ?? ""} ${kw}`.toLowerCase();
7910
8547
  lines.push({
@@ -7962,15 +8599,15 @@ function filterLines(lines, query) {
7962
8599
  /** Cached per-directory context (recent notes) for the detail panel. */
7963
8600
  const ctxCache = /* @__PURE__ */ new Map();
7964
8601
  function contextFor(rec) {
7965
- if (!rec.dir) return rec.live ? [chalk.green("live — running in another tab")] : [dim("no directory on record")];
8602
+ if (!rec.dir) return rec.live ? [chalk.green("live — running in another tab")] : [dim$1("no directory on record")];
7966
8603
  const cached = ctxCache.get(rec.dir);
7967
8604
  if (cached) return cached;
7968
8605
  const lines = [];
7969
8606
  const notes = recentMarkdown(rec.dir, 4);
7970
8607
  if (notes.length) {
7971
- lines.push(dim("recent notes:"));
7972
- for (const n of notes) lines.push(" " + dim(n.rel.slice(0, 60)) + " " + dim(fmtAge(n.mtime)));
7973
- } else lines.push(dim("(no notes here yet)"));
8608
+ lines.push(dim$1("recent notes:"));
8609
+ for (const n of notes) lines.push(" " + dim$1(n.rel.slice(0, 60)) + " " + dim$1(fmtAge(n.mtime)));
8610
+ } else lines.push(dim$1("(no notes here yet)"));
7974
8611
  ctxCache.set(rec.dir, lines);
7975
8612
  return lines;
7976
8613
  }
@@ -8011,43 +8648,43 @@ async function runSelector(lines, onRemove) {
8011
8648
  const rows = out.rows && out.rows > 8 ? out.rows : 24;
8012
8649
  const cols = out.columns && out.columns > 20 ? out.columns : 100;
8013
8650
  const frame = [];
8014
- const title = chalk.bold(" pai") + dim(" — find a project or session");
8651
+ const title = chalk.bold(" pai") + dim$1(" — find a project or session");
8015
8652
  frame.push(title);
8016
8653
  if (mode === "search") frame.push(" " + chalk.cyan("search > ") + query + chalk.inverse(" "));
8017
- else frame.push(" " + dim(`${filtered.length}/${lines.length}`) + (query ? dim(` filter: ${query}`) : ""));
8018
- frame.push(dim(" " + "─".repeat(Math.min(cols - 4, 80))));
8654
+ else frame.push(" " + dim$1(`${filtered.length}/${lines.length}`) + (query ? dim$1(` filter: ${query}`) : ""));
8655
+ frame.push(dim$1(" " + "─".repeat(Math.min(cols - 4, 80))));
8019
8656
  const ctxHeight = 6;
8020
8657
  const listHeight = Math.max(3, rows - 4 - ctxHeight - 2);
8021
8658
  let start = 0;
8022
8659
  if (cursor >= listHeight) start = cursor - listHeight + 1;
8023
8660
  const end = Math.min(filtered.length, start + listHeight);
8024
- if (filtered.length === 0) frame.push(" " + dim("no matches — press s to change the search, esc to quit"));
8661
+ if (filtered.length === 0) frame.push(" " + dim$1("no matches — press s to change the search, esc to quit"));
8025
8662
  for (let i = start; i < end; i++) {
8026
8663
  const row = filtered[i];
8027
8664
  if (i === cursor) frame.push(chalk.inverse(" " + stripAnsi(row.display).slice(0, cols - 2).padEnd(cols - 2)));
8028
8665
  else frame.push(" " + row.display);
8029
8666
  }
8030
- frame.push(dim(" " + "─".repeat(Math.min(cols - 4, 80))));
8667
+ frame.push(dim$1(" " + "─".repeat(Math.min(cols - 4, 80))));
8031
8668
  const cur = filtered[cursor];
8032
8669
  if (cur) {
8033
- frame.push(" " + chalk.bold.white(cur.record.name) + (cur.record.dir ? dim(" " + shorten(cur.record.dir, cols - 30)) : ""));
8670
+ frame.push(" " + chalk.bold.white(cur.record.name) + (cur.record.dir ? dim$1(" " + shorten(cur.record.dir, cols - 30)) : ""));
8034
8671
  for (const l of contextFor(cur.record).slice(0, ctxHeight - 2)) frame.push(l);
8035
8672
  }
8036
- frame.push(dim(" " + "─".repeat(Math.min(cols - 4, 80))));
8037
- if (confirm) frame.push(" " + chalk.yellow(`Remove "${confirm.record.name}" from PAI's list?`) + dim(" files stay on disk ") + chalk.cyan("y") + dim("/") + chalk.cyan("N"));
8038
- else if (mode === "search") frame.push(" " + dim("type to filter · ") + chalk.cyan("Enter") + dim(" done · ") + chalk.cyan("esc") + dim(" cancel"));
8673
+ frame.push(dim$1(" " + "─".repeat(Math.min(cols - 4, 80))));
8674
+ if (confirm) frame.push(" " + chalk.yellow(`Remove "${confirm.record.name}" from PAI's list?`) + dim$1(" files stay on disk ") + chalk.cyan("y") + dim$1("/") + chalk.cyan("N"));
8675
+ else if (mode === "search") frame.push(" " + dim$1("type to filter · ") + chalk.cyan("Enter") + dim$1(" done · ") + chalk.cyan("esc") + dim$1(" cancel"));
8039
8676
  else {
8040
8677
  const parts = [];
8041
- if (cur?.record.live) parts.push(chalk.cyan("g") + dim(" go to tab"));
8042
- if (cur?.record.dir) parts.push(chalk.cyan("n") + dim(" new"));
8043
- if (cur?.record.dir) parts.push(chalk.cyan("c") + dim(" cd"));
8044
- if (cur?.record.dir) parts.push(chalk.cyan("f") + dim(" finder"));
8045
- if (cur?.record.slug) parts.push(chalk.cyan("d") + dim(" remove"));
8046
- parts.push(chalk.cyan("s") + dim(" search"));
8047
- parts.push(chalk.cyan("↑↓") + dim(" move"));
8048
- parts.push(chalk.cyan("q") + dim(" quit"));
8049
- frame.push(" " + parts.join(dim(" · ")));
8050
- if (flash) frame.push(" " + dim(flash));
8678
+ if (cur?.record.live) parts.push(chalk.cyan("g") + dim$1(" go to tab"));
8679
+ if (cur?.record.dir) parts.push(chalk.cyan("n") + dim$1(" new"));
8680
+ if (cur?.record.dir) parts.push(chalk.cyan("c") + dim$1(" cd"));
8681
+ if (cur?.record.dir) parts.push(chalk.cyan("f") + dim$1(" finder"));
8682
+ if (cur?.record.slug) parts.push(chalk.cyan("d") + dim$1(" remove"));
8683
+ parts.push(chalk.cyan("s") + dim$1(" search"));
8684
+ parts.push(chalk.cyan("↑↓") + dim$1(" move"));
8685
+ parts.push(chalk.cyan("q") + dim$1(" quit"));
8686
+ frame.push(" " + parts.join(dim$1(" · ")));
8687
+ if (flash) frame.push(" " + dim$1(flash));
8051
8688
  }
8052
8689
  const painted = frame.map((l) => truncVisible(l, cols)).join("\x1B[K\n");
8053
8690
  out.write("\x1B[H" + painted + "\x1B[K\x1B[J");
@@ -8220,7 +8857,7 @@ async function cmdPick(db, opts = {}) {
8220
8857
  const allProjects = getProjects(db, true);
8221
8858
  const lines = buildFeedFrom(allSessions, projects, live, allProjects);
8222
8859
  if (lines.length === 0) {
8223
- process.stderr.write(dim(" No projects or sessions found.\n"));
8860
+ process.stderr.write(dim$1(" No projects or sessions found.\n"));
8224
8861
  return;
8225
8862
  }
8226
8863
  const onRemove = (rec) => {
@@ -8243,7 +8880,7 @@ async function cmdPick(db, opts = {}) {
8243
8880
  return;
8244
8881
  }
8245
8882
  if (!record.dir) {
8246
- process.stderr.write(dim(` No directory on record for "${record.name}".\n`));
8883
+ process.stderr.write(dim$1(` No directory on record for "${record.name}".\n`));
8247
8884
  return;
8248
8885
  }
8249
8886
  if (action === "cd") {
@@ -8262,5 +8899,5 @@ async function cmdPick(db, opts = {}) {
8262
8899
  }
8263
8900
 
8264
8901
  //#endregion
8265
- export { registerMcpCommands as C, findMovedPath as D, registerProjectsCommands as E, resolveIdentifier as O, registerDaemonCommands as S, registerRegistryCommands as T, registerZettelCommands as _, cmdPauseAll as a, registerRestoreCommands as b, cmdPause as c, registerKgCommands as d, registerTopicCommands as f, registerObservationCommands as g, registerSkillCommands as h, cmdClearNames as i, registerHelpCommand as l, registerUpdateCommand as m, cmdFind as n, cmdGoto as o, registerNotifyCommands as p, cmdList as r, cmdEnd as s, cmdPick as t, registerDbCommands as u, registerObsidianCommands as v, registerMemoryCommands as w, registerBackupCommands as x, registerSetupCommand as y };
8266
- //# sourceMappingURL=pick-C5sUQ5g_.mjs.map
8902
+ export { registerDaemonCommands as C, registerProjectsCommands as D, registerRegistryCommands as E, findMovedPath as O, registerBackupCommands as S, registerMemoryCommands as T, registerObservationCommands as _, cmdPauseAll as a, registerSetupCommand as b, cmdPause as c, registerKgCommands as d, registerTopicCommands as f, registerSkillCommands as g, registerUpdateCommand as h, cmdClearNames as i, resolveIdentifier as k, registerHelpCommand as l, registerNotifyCommands as m, cmdFind as n, cmdGoto as o, registerTaskCommands as p, cmdList as r, cmdEnd as s, cmdPick as t, registerDbCommands as u, registerZettelCommands as v, registerMcpCommands as w, registerRestoreCommands as x, registerObsidianCommands as y };
8903
+ //# sourceMappingURL=pick-CS_TmOqX.mjs.map