@tekmidian/pai 0.26.0 → 0.27.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.
@@ -7,13 +7,13 @@ import "../helpers-crDEr6S2.mjs";
7
7
  import "../sync--BoxBBok.mjs";
8
8
  import "../embeddings-Bn86ssxR.mjs";
9
9
  import "../search-CpTv1I24.mjs";
10
- import "../pick-FrfZ_iY7.mjs";
10
+ import "../pick-sZo7IQi5.mjs";
11
11
  import "../checkpoint-block-D75rhsPY.mjs";
12
12
  import "../indexer-AEcT8wHf.mjs";
13
13
  import "../ipc-client-aVKVERjJ.mjs";
14
14
  import "../config-CcdkNSWa.mjs";
15
15
  import "../factory-CAy0N1xR.mjs";
16
- import "../main-resolver-BozXCqpl.mjs";
16
+ import "../main-resolver-Bzloyzi0.mjs";
17
17
  import { buildProgram } from "./program.mjs";
18
18
 
19
19
  //#region src/cli/index.ts
@@ -6,13 +6,13 @@ import "../helpers-crDEr6S2.mjs";
6
6
  import "../sync--BoxBBok.mjs";
7
7
  import "../embeddings-Bn86ssxR.mjs";
8
8
  import "../search-CpTv1I24.mjs";
9
- import { A as registerProjectsCommands, C as registerRestoreCommands, D as registerIdentityCommands, E as registerMcpCommands, M as resolveIdentifier, O as registerMemoryCommands, S as registerSetupCommand, T as registerDaemonCommands, _ as registerUpdateCommand, a as cmdEnd, b as registerZettelCommands, c as cmdGoto, d as registerHelpCommand, f as registerDbCommands, g as registerNotifyCommands, h as registerTaskCommands, i as cmdPauseAll, j as findMovedPath, k as registerRegistryCommands, l as cmdPause, m as registerTopicCommands, n as cmdFind, o as registerSessionCleanupCommand, p as registerKgCommands, r as cmdClearNames, s as registerSessionCommands, t as cmdPick, u as cmdList, v as registerSkillCommands, w as registerBackupCommands, x as registerObsidianCommands, y as registerObservationCommands } from "../pick-FrfZ_iY7.mjs";
9
+ import { A as registerProjectsCommands, C as registerRestoreCommands, D as registerIdentityCommands, E as registerMcpCommands, M as resolveIdentifier, O as registerMemoryCommands, S as registerSetupCommand, T as registerDaemonCommands, _ as registerUpdateCommand, a as cmdEnd, b as registerZettelCommands, c as cmdGoto, d as registerHelpCommand, f as registerDbCommands, g as registerNotifyCommands, h as registerTaskCommands, i as cmdPauseAll, j as findMovedPath, k as registerRegistryCommands, l as cmdPause, m as registerTopicCommands, n as cmdFind, o as registerSessionCleanupCommand, p as registerKgCommands, r as cmdClearNames, s as registerSessionCommands, t as cmdPick, u as cmdList, v as registerSkillCommands, w as registerBackupCommands, x as registerObsidianCommands, y as registerObservationCommands } from "../pick-sZo7IQi5.mjs";
10
10
  import "../checkpoint-block-D75rhsPY.mjs";
11
11
  import "../indexer-AEcT8wHf.mjs";
12
12
  import "../ipc-client-aVKVERjJ.mjs";
13
13
  import "../config-CcdkNSWa.mjs";
14
14
  import "../factory-CAy0N1xR.mjs";
15
- import { t as cmdMain } from "../main-resolver-BozXCqpl.mjs";
15
+ import { t as cmdMain } from "../main-resolver-Bzloyzi0.mjs";
16
16
  import { existsSync, readFileSync } from "node:fs";
17
17
  import { basename, dirname, join } from "node:path";
18
18
  import { Command } from "commander";
@@ -101,10 +101,11 @@ Examples:
101
101
  registerObservationCommands(program.command("observation").description("Observation capture: list, search, and stats"));
102
102
  registerSkillCommands(program.command("skill").description("Skill telemetry and (future) discovery for the self-educating skill system"));
103
103
  registerHelpCommand(program);
104
- program.command("pause [target]").description("Save state and display safe-exit instructions for the current session.\nWrites a ## Continue checkpoint to the project's TODO.md.\nUse `pai pause all` to pause every live session via AIBroker.").option("--dry-run", "Preview changes without writing them").option("--body-file <path>", "File holding the checkpoint markdown to persist ('-' reads stdin). Required unless --no-body.").option("--session-id <uuid>", "Claude Code session UUID — recorded as the `claude --resume` handle").option("--no-body", "Deliberately write a metadata-only checkpoint (no content)").option("--exit", "(pause all only) Also send /exit to each session after pausing").option("--wait <ms>", "(pause all only) Max milliseconds to wait for a session to finish its\ncheckpoint before /exit. Not a fixed delay — sessions are exited as soon\nas they return to the prompt, and any still busy at the deadline are left\nopen rather than killed mid-write. (default: 180000)", "180000").action(async (target, opts) => {
104
+ program.command("pause [target]").description("Save state and display safe-exit instructions for the current session.\nWrites a ## Continue checkpoint to the project's TODO.md.\nUse `pai pause all` to pause every live session via AIBroker.").option("--dry-run", "Preview changes without writing them").option("--body-file <path>", "File holding the checkpoint markdown to persist ('-' reads stdin). Required unless --no-body.").option("--session-id <uuid>", "Claude Code session UUID — recorded as the `claude --resume` handle").option("--no-body", "Deliberately write a metadata-only checkpoint (no content)").option("--exit", "(pause all only) Also send /exit to each session after pausing").option("--only <name>", "(pause all only) Pause just the sessions whose name or id contains <name>.\nFor rehearsing the real thing against one session before trusting it with\nevery open tab — a dry run exercises enumeration but never sends anything,\nwhich is exactly how a broken send survived until it was needed.").option("--wait <ms>", "(pause all only) Max milliseconds to wait for a session to finish its\ncheckpoint before /exit. Not a fixed delay — sessions are exited as soon\nas they return to the prompt, and any still busy at the deadline are left\nopen rather than killed mid-write. (default: 180000)", "180000").action(async (target, opts) => {
105
105
  if (target === "all") await cmdPauseAll({
106
106
  exit: opts.exit,
107
107
  dryRun: opts.dryRun,
108
+ only: opts.only,
108
109
  wait: opts.wait !== void 0 ? parseInt(opts.wait, 10) : void 0
109
110
  });
110
111
  else {
@@ -1 +1 @@
1
- {"version":3,"file":"program.mjs","names":[],"sources":["../../src/cli/program.ts"],"sourcesContent":["/**\n * PAI CLI — Commander program builder.\n *\n * Constructs the full `pai` command tree WITHOUT parsing argv. This separation\n * lets the documentation generator (scripts/build-docs.mjs) import and introspect\n * the live program object — the single source of truth for `--help`, the\n * generated man pages, and `pai help <area>`.\n *\n * The thin entry point (cli/index.ts) imports buildProgram() and calls parse().\n */\n\nimport { Command } from \"commander\";\nimport { readFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { openRegistry } from \"../registry/db.js\";\nimport type { Database } from \"better-sqlite3\";\nimport { registerProjectsCommands } from \"./commands/project/projects-index.js\";\nimport { findMovedPath } from \"./commands/project/commands.js\";\nimport { existsSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport { registerRegistryCommands } from \"./commands/registry.js\";\nimport { registerMemoryCommands } from \"./commands/memory.js\";\nimport { registerIdentityCommands } from \"./commands/identity.js\";\nimport { registerMcpCommands } from \"./commands/mcp.js\";\nimport { registerDaemonCommands } from \"./commands/daemon.js\";\nimport { registerBackupCommands } from \"./commands/backup.js\";\nimport { registerRestoreCommands } from \"./commands/restore.js\";\nimport { registerSetupCommand } from \"./commands/setup.js\";\nimport { registerObsidianCommands } from \"./commands/obsidian.js\";\nimport { registerZettelCommands } from \"./commands/zettel.js\";\nimport { registerObservationCommands } from \"./commands/observation.js\";\nimport { registerSkillCommands } from \"./commands/skill.js\";\nimport { registerUpdateCommand } from \"./commands/update.js\";\nimport { registerNotifyCommands } from \"./commands/notify.js\";\nimport { registerTaskCommands } from \"./commands/task.js\";\nimport { registerTopicCommands } from \"./commands/topic.js\";\nimport { registerKgCommands } from \"./commands/kg.js\";\nimport { registerDbCommands } from \"./commands/db.js\";\nimport { registerHelpCommand } from \"./commands/help.js\";\nimport { registerSessionCommands } from \"./commands/session/index.js\";\nimport { registerSessionCleanupCommand } from \"./commands/session-cleanup/index.js\";\nimport { err, warn, ok, dim, shortenPath, encodeDir, now } from \"./utils.js\";\nimport { cmdPause } from \"./commands/session/pause.js\";\nimport { cmdEnd } from \"./commands/session/end.js\";\nimport { cmdGoto } from \"./commands/session/goto.js\";\nimport { cmdPauseAll } from \"./commands/session/pause-all.js\";\nimport { cmdClearNames } from \"./commands/session/clear-names.js\";\nimport { cmdList as cmdNotesList } from \"./commands/session/commands.js\";\nimport { resolveIdentifier } from \"./commands/project/helpers.js\";\nimport { cmdFind } from \"./commands/find.js\";\nimport { cmdMain } from \"./commands/main-resolver.js\";\nimport { cmdPick } from \"./commands/pick.js\";\n\n// ---------------------------------------------------------------------------\n// Version resolution\n// ---------------------------------------------------------------------------\n\nfunction getVersion(): string {\n try {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(__dirname, \"../../package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as { version?: string };\n return pkg.version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Lazy database singleton\n// ---------------------------------------------------------------------------\n\nlet _db: Database | null = null;\n\nfunction getDb(): Database {\n if (!_db) {\n try {\n _db = openRegistry();\n } catch (e) {\n console.error(err(`Failed to open PAI registry: ${e}`));\n process.exit(1);\n }\n }\n return _db;\n}\n\n// ---------------------------------------------------------------------------\n// Program builder\n// ---------------------------------------------------------------------------\n\n/**\n * Build and return the fully configured `pai` Commander program.\n * Does NOT call parse — the caller (cli/index.ts) does that.\n */\nexport function buildProgram(): Command {\n const program = new Command();\n\n program\n .name(\"pai\")\n .description(\"PAI Knowledge OS — Personal AI Infrastructure CLI\")\n .version(getVersion(), \"-V, --version\", \"Print version and exit\")\n .addHelpText(\n \"after\",\n `\nDaily commands:\n pai Show your work: live tabs + recent sessions + recent projects\n pai <name> Switch / resume / fresh — universal\n pai pause [all] Pause current (or all live) sessions\n pai end Finalize current session\n\nSubcommands (rarely needed):\n pai projects ... Project registry management (cd, rebind, info, ...)\n pai registry ... Registry maintenance (scan, ...)\n pai memory ... Memory engine (index, search, ...)\n pai shell-init Shell integration (eval \"$(pai shell-init)\")\n\nRecovery:\n pai clear-names Wipe corrupt iTerm tab-name store\n\nExamples:\n pai aibroker Switch to the live AIBroker tab in iTerm\n pai mdf Find sessions where you worked on MDF\n pai 81c5c3dc Resume session by UUID prefix\n pai --all Show everything including cold and zero-session projects`\n );\n\n // -------------------------------------------------------------------------\n // pai projects (canonical plural namespace)\n // -------------------------------------------------------------------------\n\n const projectsCmd = program\n .command(\"projects\")\n .description(\"Manage registered projects (list, cd, add, info, ...)\");\n\n registerProjectsCommands(projectsCmd, getDb);\n\n // Singular alias: `pai project` → `pai projects`\n const projectCmd = program\n .command(\"project\")\n .description(\"Alias for `pai projects`\");\n\n registerProjectsCommands(projectCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai sessions (alias for the unified `pai` listing)\n // -------------------------------------------------------------------------\n\n // -------------------------------------------------------------------------\n // pai session <subcommand>\n //\n // These were written, exported and never wired: neither\n // registerSessionCommands nor registerSessionCleanupCommand was called from\n // anywhere, so every `pai session <x>` fell through to the default `query`\n // resolver and was interpreted as a prompt-history search.\n //\n // That is why session-stop.sh has been a near no-op — all four of its calls\n // (`session cleanup --execute`, `session checkpoint`, `session slug --apply`,\n // `session handover`) failed silently behind `2>/dev/null || true`.\n // -------------------------------------------------------------------------\n\n const sessionCmd = program\n .command(\"session\")\n .description(\n \"Session management: list, info, checkpoint, handover, cleanup, slug, tag, route.\\n\" +\n \"Short forms: `pai pause`, `pai end`, `pai resume <name>`.\"\n );\n\n registerSessionCommands(sessionCmd, getDb);\n registerSessionCleanupCommand(sessionCmd, getDb);\n\n program\n .command(\"sessions\")\n .description(\"Alias for `pai` — show the unified deduped listing.\")\n .option(\"--all\", \"Show all entries including cold / zero-session / archived projects\")\n .option(\"-n, --n <count>\", \"Max candidates for history search\", \"20\")\n .action(async (opts: { all?: boolean; n?: string }) => {\n await cmdMain(getDb(), undefined, undefined, opts);\n });\n\n // -------------------------------------------------------------------------\n // pai registry\n // -------------------------------------------------------------------------\n\n const registryCmd = program\n .command(\"registry\")\n .description(\"Registry maintenance: scan, migrate, stats, rebuild\");\n\n registerRegistryCommands(registryCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai memory\n // -------------------------------------------------------------------------\n\n const memoryCmd = program\n .command(\"memory\")\n .description(\"Memory engine: index, search, and status\");\n\n registerMemoryCommands(memoryCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai identity\n // -------------------------------------------------------------------------\n\n const identityCmd = program\n .command(\"identity\")\n .description(\"Declare who you are: self addresses and where mail is delivered\");\n\n registerIdentityCommands(identityCmd);\n\n // -------------------------------------------------------------------------\n // pai mcp\n // -------------------------------------------------------------------------\n\n const mcpCmd = program\n .command(\"mcp\")\n .description(\"MCP server management: install and status\");\n\n registerMcpCommands(mcpCmd);\n\n // -------------------------------------------------------------------------\n // pai daemon\n // -------------------------------------------------------------------------\n\n const daemonCmd = program\n .command(\"daemon\")\n .description(\"PAI daemon management: serve, status, restart, install, uninstall, logs\");\n\n registerDaemonCommands(daemonCmd);\n\n // -------------------------------------------------------------------------\n // pai backup / pai restore\n // -------------------------------------------------------------------------\n\n registerBackupCommands(program);\n registerRestoreCommands(program);\n\n // -------------------------------------------------------------------------\n // pai setup / pai update\n // -------------------------------------------------------------------------\n\n registerSetupCommand(program);\n registerUpdateCommand(program);\n\n // -------------------------------------------------------------------------\n // pai notify\n // -------------------------------------------------------------------------\n\n const notifyCmd = program\n .command(\"notify\")\n .description(\"Notification config: status, get, set, test, send\");\n\n registerNotifyCommands(notifyCmd);\n\n // -------------------------------------------------------------------------\n // pai task\n // -------------------------------------------------------------------------\n\n const taskCmd = program\n .command(\"task\")\n .alias(\"tasks\")\n .description(\"Task bus: list, add, dispatch, and complete cross-session work\");\n\n registerTaskCommands(taskCmd);\n\n // -------------------------------------------------------------------------\n // pai topic\n // -------------------------------------------------------------------------\n\n const topicCmd = program\n .command(\"topic\")\n .description(\"Topic shift detection: check whether context has drifted to a different project\");\n\n registerTopicCommands(topicCmd);\n\n // -------------------------------------------------------------------------\n // pai kg\n // -------------------------------------------------------------------------\n\n const kgCmd = program\n .command(\"kg\")\n .description(\"Temporal knowledge graph: backfill, query, list, stats\");\n\n registerKgCommands(kgCmd);\n\n // -------------------------------------------------------------------------\n // pai db\n // -------------------------------------------------------------------------\n\n const dbCmd = program\n .command(\"db\")\n .description(\"Database inspection: query, tables, schema (sqlite or postgres)\");\n\n registerDbCommands(dbCmd);\n\n // -------------------------------------------------------------------------\n // pai obsidian\n // -------------------------------------------------------------------------\n\n const obsidianCmd = program\n .command(\"obsidian\")\n .description(\"Obsidian vault: sync project notes, view status, open in Obsidian\");\n\n registerObsidianCommands(obsidianCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai zettel\n // -------------------------------------------------------------------------\n\n const zettelCmd = program\n .command(\"zettel\")\n .description(\"Zettelkasten intelligence: explore, surprise, converse, themes, health, suggest\");\n\n registerZettelCommands(zettelCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai observation\n // -------------------------------------------------------------------------\n\n const observationCmd = program\n .command(\"observation\")\n .description(\"Observation capture: list, search, and stats\");\n\n registerObservationCommands(observationCmd);\n\n // -------------------------------------------------------------------------\n // pai skill\n // -------------------------------------------------------------------------\n\n const skillCmd = program\n .command(\"skill\")\n .description(\"Skill telemetry and (future) discovery for the self-educating skill system\");\n\n registerSkillCommands(skillCmd);\n\n // -------------------------------------------------------------------------\n // pai help [area] — rich man-page viewer for the generated docs\n // -------------------------------------------------------------------------\n\n registerHelpCommand(program);\n\n // -------------------------------------------------------------------------\n // DAILY VERBS — top-level\n // -------------------------------------------------------------------------\n\n // pai pause [all] [--dry-run] [--exit] [--wait <ms>]\n program\n .command(\"pause [target]\")\n .description(\n \"Save state and display safe-exit instructions for the current session.\\n\" +\n \"Writes a ## Continue checkpoint to the project's TODO.md.\\n\" +\n \"Use `pai pause all` to pause every live session via AIBroker.\"\n )\n .option(\"--dry-run\", \"Preview changes without writing them\")\n .option(\n \"--body-file <path>\",\n \"File holding the checkpoint markdown to persist ('-' reads stdin). Required unless --no-body.\"\n )\n .option(\n \"--session-id <uuid>\",\n \"Claude Code session UUID — recorded as the `claude --resume` handle\"\n )\n .option(\n \"--no-body\",\n \"Deliberately write a metadata-only checkpoint (no content)\"\n )\n .option(\"--exit\", \"(pause all only) Also send /exit to each session after pausing\")\n .option(\n \"--wait <ms>\",\n \"(pause all only) Max milliseconds to wait for a session to finish its\\n\" +\n \"checkpoint before /exit. Not a fixed delay — sessions are exited as soon\\n\" +\n \"as they return to the prompt, and any still busy at the deadline are left\\n\" +\n \"open rather than killed mid-write. (default: 180000)\",\n \"180000\"\n )\n .action(async (target: string | undefined, opts: { dryRun?: boolean; exit?: boolean; wait?: string; bodyFile?: string; sessionId?: string; body?: boolean }) => {\n if (target === \"all\") {\n await cmdPauseAll({\n exit: opts.exit,\n dryRun: opts.dryRun,\n wait: opts.wait !== undefined ? parseInt(opts.wait, 10) : undefined,\n });\n } else {\n if (target !== undefined) {\n console.error(err(`Unknown target: ${target}. Did you mean 'pai pause all'?`));\n process.exitCode = 1;\n return;\n }\n // Commander maps `--no-body` to opts.body === false.\n cmdPause(getDb(), {\n dryRun: opts.dryRun,\n bodyFile: opts.bodyFile,\n sessionId: opts.sessionId,\n noBody: opts.body === false,\n });\n }\n });\n\n // pai end [--body-file <path>] [--session-id <uuid>] [--no-body] [--dry-run]\n program\n .command(\"end\")\n .description(\n \"Finalize a session: save state, mark note Completed, display safe-exit instructions.\"\n )\n .option(\"--dry-run\", \"Preview all changes without writing them\")\n .option(\n \"--body-file <path>\",\n \"File holding the checkpoint markdown to persist ('-' reads stdin). Required unless --no-body.\"\n )\n .option(\n \"--session-id <uuid>\",\n \"Claude Code session UUID — recorded as the `claude --resume` handle\"\n )\n .option(\n \"--no-body\",\n \"Deliberately write a metadata-only checkpoint (no content)\"\n )\n .action((opts: { dryRun?: boolean; bodyFile?: string; sessionId?: string; body?: boolean }) => {\n cmdEnd(getDb(), {\n dryRun: opts.dryRun,\n bodyFile: opts.bodyFile,\n sessionId: opts.sessionId,\n noBody: opts.body === false,\n });\n });\n\n // pai clear-names [--dry-run] — recovery: wipe corrupt iTerm/JSON name store\n program\n .command(\"clear-names\")\n .description(\n \"Recovery: wipe corrupted iTerm2 session name state.\\n\" +\n \"Clears ~/.aibroker/session-names.json AND user.paiName from all live iTerm2 sessions.\\n\" +\n \"After running this, use /Name to re-label each tab.\"\n )\n .option(\"--dry-run\", \"Preview what would be cleared without making changes\")\n .action(async (opts: { dryRun?: boolean }) => {\n await cmdClearNames(opts);\n });\n\n // -------------------------------------------------------------------------\n // HIDDEN COMPAT ALIASES\n // -------------------------------------------------------------------------\n\n // pai resume <name> [--dry-run] — hidden; prefer `pai <name>`\n program\n .command(\"resume <name>\", { hidden: true })\n .description(\"Go to a session by name or UUID (prefer: pai <name>)\")\n .option(\"--dry-run\", \"Print the exact argv and cwd, then exit without launching\")\n .action((name: string, opts: { dryRun?: boolean }) => {\n cmdGoto(getDb(), name, { dryRun: opts.dryRun });\n });\n\n // pai cd <identifier> — hidden; shell wrapper uses this\n program\n .command(\"cd <identifier>\", { hidden: true })\n .description(\"cd to a project directory (shell wrapper handles the actual cd)\")\n .action((identifier: string) => {\n const db = getDb();\n const project = resolveIdentifier(db, identifier);\n if (!project) {\n console.error(`Project not found: ${identifier}`);\n process.exit(1);\n return;\n }\n\n if (existsSync(project.root_path)) {\n process.stdout.write(project.root_path + \"\\n\");\n return;\n }\n\n process.stderr.write(\n warn(`Path not found: ${project.root_path}\\n`) +\n dim(\" Searching for moved location...\\n\")\n );\n\n const result = findMovedPath(project.root_path);\n\n if (result.found) {\n const newPath = result.found;\n const newEncoded = encodeDir(newPath);\n const ts = now();\n db.prepare(\n \"UPDATE projects SET root_path = ?, encoded_dir = ?, updated_at = ? WHERE id = ?\"\n ).run(newPath, newEncoded, ts, project.id);\n process.stderr.write(\n ok(`Project moved: ${shortenPath(project.root_path, 50)}\\n`) +\n dim(` → ${newPath}\\n`) +\n ok(\"Registry updated.\\n\")\n );\n process.stdout.write(newPath + \"\\n\");\n return;\n }\n\n if (result.ambiguous) {\n process.stderr.write(\n warn(`Multiple directories named \"${basename(project.root_path)}\" found:\\n`)\n );\n for (const candidate of result.ambiguous!) {\n process.stderr.write(dim(` ${candidate}\\n`));\n }\n process.stderr.write(\n dim(`\\n Disambiguate with: pai projects rebind ${project.slug} <path>\\n`)\n );\n process.exitCode = 1;\n return;\n }\n\n process.stderr.write(\n err(\n `Project \"${project.slug}\" root_path \"${project.root_path}\" does not exist on disk\\n` +\n ` and no folder named \"${basename(project.root_path)}\" was found in scan dirs.\\n`\n ) +\n dim(` Fix with: pai projects rebind ${project.slug} <new-path>\\n`)\n );\n process.exitCode = 1;\n });\n\n // -------------------------------------------------------------------------\n // pai notes — hidden power-user alias; accessible but not in main help\n // -------------------------------------------------------------------------\n\n const notesCmd = program\n .command(\"notes [project-slug]\", { hidden: true })\n .description(\"Markdown session notes — list notes, optionally filtered to a project.\")\n .option(\"--limit <n>\", \"Maximum number of notes to show\", \"20\")\n .option(\"--status <status>\", \"Filter by status: open | completed | compacted\")\n .action(\n (projectSlug: string | undefined, opts: { limit?: string; status?: string }) => {\n cmdNotesList(getDb(), projectSlug, opts);\n }\n );\n\n notesCmd\n .command(\"list [project-slug]\")\n .description(\"List markdown session notes (same as: pai notes)\")\n .option(\"--limit <n>\", \"Maximum number of notes to show\", \"20\")\n .option(\"--status <status>\", \"Filter by status: open | completed | compacted\")\n .action(\n (projectSlug: string | undefined, opts: { limit?: string; status?: string }) => {\n cmdNotesList(getDb(), projectSlug, opts);\n }\n );\n\n // -------------------------------------------------------------------------\n // pai find <query> — hidden power-user alias for history search\n // -------------------------------------------------------------------------\n\n program\n .command(\"find <query>\", { hidden: true })\n .description(\"Search prompt history for matching sessions.\")\n .option(\"-n, --n <count>\", \"Maximum number of sessions to show\", \"20\")\n .option(\"--json\", \"Output as JSON array\")\n .action(async (query: string, opts: { n?: string; json?: boolean }) => {\n await cmdFind(query, opts);\n });\n\n // -------------------------------------------------------------------------\n // pai shell-init — emit shell function for eval \"$(pai shell-init)\"\n // -------------------------------------------------------------------------\n\n program\n .command(\"shell-init\")\n .description('Emit shell integration code. Add to ~/.zshrc: eval \"$(pai shell-init)\"')\n .action(() => {\n process.stdout.write(\n `# PAI shell integration — generated by: pai shell-init\npai() {\n if [[ \"$1\" == \"cd\" ]]; then\n local dir=$(command pai cd \"$2\" 2>/dev/null)\n if [[ -n \"$dir\" && -d \"$dir\" ]]; then\n builtin cd \"$dir\"\n echo \"-> $dir\"\n else\n echo \"Project not found: $2\" >&2\n return 1\n fi\n elif [[ \"$1\" == \"projects\" && \"$2\" == \"cd\" ]]; then\n local dir=$(command pai projects cd \"$3\" 2>/dev/null)\n if [[ -n \"$dir\" && -d \"$dir\" ]]; then\n builtin cd \"$dir\"\n echo \"-> $dir\"\n else\n echo \"Project not found: $3\" >&2\n return 1\n fi\n elif [[ $# -eq 0 ]]; then\n # Bare \\`pai\\` → interactive picker. fzf draws on /dev/tty; the picker writes\n # a chosen directory to PAI_PICK_OUT when you press Ctrl-G (cd only), which we\n # then cd into here (a child process can't change this shell's cwd itself).\n local __pai_f\n __pai_f=$(mktemp -t pai-pick 2>/dev/null) || { command pai; return $?; }\n PAI_PICK_OUT=\"$__pai_f\" command pai\n local __pai_rc=$?\n local __pai_dir=\"\"\n [[ -s \"$__pai_f\" ]] && __pai_dir=$(cat \"$__pai_f\")\n command rm -f \"$__pai_f\"\n if [[ -n \"$__pai_dir\" && -d \"$__pai_dir\" ]]; then\n builtin cd \"$__pai_dir\"\n echo \"-> $__pai_dir\"\n fi\n return $__pai_rc\n else\n command pai \"$@\"\n fi\n}\n\n# Print the working directory after an interactive Claude Code session exits.\n# A SessionEnd hook can't do this reliably: Claude Code does not fire SessionEnd\n# on /exit (anthropics/claude-code#17885) and may reap the hook mid-run (#41577).\n# Running it from the shell, after \\`claude\\` returns, sidesteps both.\nclaude() {\n local __pai_skip=0 __pai_arg\n for __pai_arg in \"$@\"; do\n case \"$__pai_arg\" in\n -p|--print) __pai_skip=1 ;;\n esac\n done\n command claude \"$@\"\n local __pai_rc=$?\n if [[ -t 1 && $__pai_skip -eq 0 ]]; then\n printf '\\\\n\\\\033[2m📂 Working directory:\\\\033[0m %s\\\\n\\\\033[2m cd \"%s\"\\\\033[0m\\\\n' \"$PWD\" \"$PWD\"\n fi\n return $__pai_rc\n}\n`\n );\n });\n\n // -------------------------------------------------------------------------\n // pai [query] [pick] — DEFAULT COMMAND (must be registered LAST)\n // -------------------------------------------------------------------------\n\n program\n .command(\"query [query] [pick]\", { isDefault: true, hidden: true })\n .description(\n \"Find and launch a session by topic, name, or UUID.\\n\" +\n \"No arg → deduped session listing\\n\" +\n \"Name → switch live tab, or resume, or start fresh\\n\" +\n \"UUID → direct resume via filesystem scan\\n\" +\n \"Topic → history search → candidate list → pick #\"\n )\n .option(\"-y, --auto\", \"Auto-pick #1 without prompting\")\n .option(\"--dry-run\", \"Print what would happen without launching\")\n .option(\"-n, --n <count>\", \"Max candidates for history search\", \"20\")\n .option(\"--all\", \"Show all entries including cold / zero-session / archived projects\")\n .option(\"--list\", \"Skip the interactive picker; print the static session listing\")\n .action(async (query: string | undefined, pick: string | undefined, opts: { auto?: boolean; dryRun?: boolean; n?: string; all?: boolean; list?: boolean }) => {\n // No query → interactive fzf picker (projects + sessions, go where you pick).\n // `--list` (or a non-TTY pipe, handled inside cmdPick) falls back to the\n // static listing. Any query still goes through the name/UUID/topic resolver.\n if (query === undefined && !opts.list) {\n await cmdPick(getDb(), { all: opts.all, dryRun: opts.dryRun });\n return;\n }\n const pickN = pick !== undefined ? parseInt(pick, 10) : undefined;\n await cmdMain(getDb(), query, pickN, opts);\n });\n\n // -------------------------------------------------------------------------\n // Error handling\n // -------------------------------------------------------------------------\n\n program.configureOutput({\n writeErr: (str) => process.stderr.write(err(str)),\n });\n\n program.exitOverride((error) => {\n if (error.code === \"commander.helpDisplayed\" || error.code === \"commander.version\") {\n process.exit(0);\n }\n if (\n error.code === \"commander.missingArgument\" ||\n error.code === \"commander.unknownOption\" ||\n error.code === \"commander.unknownCommand\"\n ) {\n process.exit(1);\n }\n console.error(err(error.message));\n process.exit(1);\n });\n\n return program;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"program.mjs","names":[],"sources":["../../src/cli/program.ts"],"sourcesContent":["/**\n * PAI CLI — Commander program builder.\n *\n * Constructs the full `pai` command tree WITHOUT parsing argv. This separation\n * lets the documentation generator (scripts/build-docs.mjs) import and introspect\n * the live program object — the single source of truth for `--help`, the\n * generated man pages, and `pai help <area>`.\n *\n * The thin entry point (cli/index.ts) imports buildProgram() and calls parse().\n */\n\nimport { Command } from \"commander\";\nimport { readFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { openRegistry } from \"../registry/db.js\";\nimport type { Database } from \"better-sqlite3\";\nimport { registerProjectsCommands } from \"./commands/project/projects-index.js\";\nimport { findMovedPath } from \"./commands/project/commands.js\";\nimport { existsSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport { registerRegistryCommands } from \"./commands/registry.js\";\nimport { registerMemoryCommands } from \"./commands/memory.js\";\nimport { registerIdentityCommands } from \"./commands/identity.js\";\nimport { registerMcpCommands } from \"./commands/mcp.js\";\nimport { registerDaemonCommands } from \"./commands/daemon.js\";\nimport { registerBackupCommands } from \"./commands/backup.js\";\nimport { registerRestoreCommands } from \"./commands/restore.js\";\nimport { registerSetupCommand } from \"./commands/setup.js\";\nimport { registerObsidianCommands } from \"./commands/obsidian.js\";\nimport { registerZettelCommands } from \"./commands/zettel.js\";\nimport { registerObservationCommands } from \"./commands/observation.js\";\nimport { registerSkillCommands } from \"./commands/skill.js\";\nimport { registerUpdateCommand } from \"./commands/update.js\";\nimport { registerNotifyCommands } from \"./commands/notify.js\";\nimport { registerTaskCommands } from \"./commands/task.js\";\nimport { registerTopicCommands } from \"./commands/topic.js\";\nimport { registerKgCommands } from \"./commands/kg.js\";\nimport { registerDbCommands } from \"./commands/db.js\";\nimport { registerHelpCommand } from \"./commands/help.js\";\nimport { registerSessionCommands } from \"./commands/session/index.js\";\nimport { registerSessionCleanupCommand } from \"./commands/session-cleanup/index.js\";\nimport { err, warn, ok, dim, shortenPath, encodeDir, now } from \"./utils.js\";\nimport { cmdPause } from \"./commands/session/pause.js\";\nimport { cmdEnd } from \"./commands/session/end.js\";\nimport { cmdGoto } from \"./commands/session/goto.js\";\nimport { cmdPauseAll } from \"./commands/session/pause-all.js\";\nimport { cmdClearNames } from \"./commands/session/clear-names.js\";\nimport { cmdList as cmdNotesList } from \"./commands/session/commands.js\";\nimport { resolveIdentifier } from \"./commands/project/helpers.js\";\nimport { cmdFind } from \"./commands/find.js\";\nimport { cmdMain } from \"./commands/main-resolver.js\";\nimport { cmdPick } from \"./commands/pick.js\";\n\n// ---------------------------------------------------------------------------\n// Version resolution\n// ---------------------------------------------------------------------------\n\nfunction getVersion(): string {\n try {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pkgPath = join(__dirname, \"../../package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as { version?: string };\n return pkg.version ?? \"0.0.0\";\n } catch {\n return \"0.0.0\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Lazy database singleton\n// ---------------------------------------------------------------------------\n\nlet _db: Database | null = null;\n\nfunction getDb(): Database {\n if (!_db) {\n try {\n _db = openRegistry();\n } catch (e) {\n console.error(err(`Failed to open PAI registry: ${e}`));\n process.exit(1);\n }\n }\n return _db;\n}\n\n// ---------------------------------------------------------------------------\n// Program builder\n// ---------------------------------------------------------------------------\n\n/**\n * Build and return the fully configured `pai` Commander program.\n * Does NOT call parse — the caller (cli/index.ts) does that.\n */\nexport function buildProgram(): Command {\n const program = new Command();\n\n program\n .name(\"pai\")\n .description(\"PAI Knowledge OS — Personal AI Infrastructure CLI\")\n .version(getVersion(), \"-V, --version\", \"Print version and exit\")\n .addHelpText(\n \"after\",\n `\nDaily commands:\n pai Show your work: live tabs + recent sessions + recent projects\n pai <name> Switch / resume / fresh — universal\n pai pause [all] Pause current (or all live) sessions\n pai end Finalize current session\n\nSubcommands (rarely needed):\n pai projects ... Project registry management (cd, rebind, info, ...)\n pai registry ... Registry maintenance (scan, ...)\n pai memory ... Memory engine (index, search, ...)\n pai shell-init Shell integration (eval \"$(pai shell-init)\")\n\nRecovery:\n pai clear-names Wipe corrupt iTerm tab-name store\n\nExamples:\n pai aibroker Switch to the live AIBroker tab in iTerm\n pai mdf Find sessions where you worked on MDF\n pai 81c5c3dc Resume session by UUID prefix\n pai --all Show everything including cold and zero-session projects`\n );\n\n // -------------------------------------------------------------------------\n // pai projects (canonical plural namespace)\n // -------------------------------------------------------------------------\n\n const projectsCmd = program\n .command(\"projects\")\n .description(\"Manage registered projects (list, cd, add, info, ...)\");\n\n registerProjectsCommands(projectsCmd, getDb);\n\n // Singular alias: `pai project` → `pai projects`\n const projectCmd = program\n .command(\"project\")\n .description(\"Alias for `pai projects`\");\n\n registerProjectsCommands(projectCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai sessions (alias for the unified `pai` listing)\n // -------------------------------------------------------------------------\n\n // -------------------------------------------------------------------------\n // pai session <subcommand>\n //\n // These were written, exported and never wired: neither\n // registerSessionCommands nor registerSessionCleanupCommand was called from\n // anywhere, so every `pai session <x>` fell through to the default `query`\n // resolver and was interpreted as a prompt-history search.\n //\n // That is why session-stop.sh has been a near no-op — all four of its calls\n // (`session cleanup --execute`, `session checkpoint`, `session slug --apply`,\n // `session handover`) failed silently behind `2>/dev/null || true`.\n // -------------------------------------------------------------------------\n\n const sessionCmd = program\n .command(\"session\")\n .description(\n \"Session management: list, info, checkpoint, handover, cleanup, slug, tag, route.\\n\" +\n \"Short forms: `pai pause`, `pai end`, `pai resume <name>`.\"\n );\n\n registerSessionCommands(sessionCmd, getDb);\n registerSessionCleanupCommand(sessionCmd, getDb);\n\n program\n .command(\"sessions\")\n .description(\"Alias for `pai` — show the unified deduped listing.\")\n .option(\"--all\", \"Show all entries including cold / zero-session / archived projects\")\n .option(\"-n, --n <count>\", \"Max candidates for history search\", \"20\")\n .action(async (opts: { all?: boolean; n?: string }) => {\n await cmdMain(getDb(), undefined, undefined, opts);\n });\n\n // -------------------------------------------------------------------------\n // pai registry\n // -------------------------------------------------------------------------\n\n const registryCmd = program\n .command(\"registry\")\n .description(\"Registry maintenance: scan, migrate, stats, rebuild\");\n\n registerRegistryCommands(registryCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai memory\n // -------------------------------------------------------------------------\n\n const memoryCmd = program\n .command(\"memory\")\n .description(\"Memory engine: index, search, and status\");\n\n registerMemoryCommands(memoryCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai identity\n // -------------------------------------------------------------------------\n\n const identityCmd = program\n .command(\"identity\")\n .description(\"Declare who you are: self addresses and where mail is delivered\");\n\n registerIdentityCommands(identityCmd);\n\n // -------------------------------------------------------------------------\n // pai mcp\n // -------------------------------------------------------------------------\n\n const mcpCmd = program\n .command(\"mcp\")\n .description(\"MCP server management: install and status\");\n\n registerMcpCommands(mcpCmd);\n\n // -------------------------------------------------------------------------\n // pai daemon\n // -------------------------------------------------------------------------\n\n const daemonCmd = program\n .command(\"daemon\")\n .description(\"PAI daemon management: serve, status, restart, install, uninstall, logs\");\n\n registerDaemonCommands(daemonCmd);\n\n // -------------------------------------------------------------------------\n // pai backup / pai restore\n // -------------------------------------------------------------------------\n\n registerBackupCommands(program);\n registerRestoreCommands(program);\n\n // -------------------------------------------------------------------------\n // pai setup / pai update\n // -------------------------------------------------------------------------\n\n registerSetupCommand(program);\n registerUpdateCommand(program);\n\n // -------------------------------------------------------------------------\n // pai notify\n // -------------------------------------------------------------------------\n\n const notifyCmd = program\n .command(\"notify\")\n .description(\"Notification config: status, get, set, test, send\");\n\n registerNotifyCommands(notifyCmd);\n\n // -------------------------------------------------------------------------\n // pai task\n // -------------------------------------------------------------------------\n\n const taskCmd = program\n .command(\"task\")\n .alias(\"tasks\")\n .description(\"Task bus: list, add, dispatch, and complete cross-session work\");\n\n registerTaskCommands(taskCmd);\n\n // -------------------------------------------------------------------------\n // pai topic\n // -------------------------------------------------------------------------\n\n const topicCmd = program\n .command(\"topic\")\n .description(\"Topic shift detection: check whether context has drifted to a different project\");\n\n registerTopicCommands(topicCmd);\n\n // -------------------------------------------------------------------------\n // pai kg\n // -------------------------------------------------------------------------\n\n const kgCmd = program\n .command(\"kg\")\n .description(\"Temporal knowledge graph: backfill, query, list, stats\");\n\n registerKgCommands(kgCmd);\n\n // -------------------------------------------------------------------------\n // pai db\n // -------------------------------------------------------------------------\n\n const dbCmd = program\n .command(\"db\")\n .description(\"Database inspection: query, tables, schema (sqlite or postgres)\");\n\n registerDbCommands(dbCmd);\n\n // -------------------------------------------------------------------------\n // pai obsidian\n // -------------------------------------------------------------------------\n\n const obsidianCmd = program\n .command(\"obsidian\")\n .description(\"Obsidian vault: sync project notes, view status, open in Obsidian\");\n\n registerObsidianCommands(obsidianCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai zettel\n // -------------------------------------------------------------------------\n\n const zettelCmd = program\n .command(\"zettel\")\n .description(\"Zettelkasten intelligence: explore, surprise, converse, themes, health, suggest\");\n\n registerZettelCommands(zettelCmd, getDb);\n\n // -------------------------------------------------------------------------\n // pai observation\n // -------------------------------------------------------------------------\n\n const observationCmd = program\n .command(\"observation\")\n .description(\"Observation capture: list, search, and stats\");\n\n registerObservationCommands(observationCmd);\n\n // -------------------------------------------------------------------------\n // pai skill\n // -------------------------------------------------------------------------\n\n const skillCmd = program\n .command(\"skill\")\n .description(\"Skill telemetry and (future) discovery for the self-educating skill system\");\n\n registerSkillCommands(skillCmd);\n\n // -------------------------------------------------------------------------\n // pai help [area] — rich man-page viewer for the generated docs\n // -------------------------------------------------------------------------\n\n registerHelpCommand(program);\n\n // -------------------------------------------------------------------------\n // DAILY VERBS — top-level\n // -------------------------------------------------------------------------\n\n // pai pause [all] [--dry-run] [--exit] [--wait <ms>]\n program\n .command(\"pause [target]\")\n .description(\n \"Save state and display safe-exit instructions for the current session.\\n\" +\n \"Writes a ## Continue checkpoint to the project's TODO.md.\\n\" +\n \"Use `pai pause all` to pause every live session via AIBroker.\"\n )\n .option(\"--dry-run\", \"Preview changes without writing them\")\n .option(\n \"--body-file <path>\",\n \"File holding the checkpoint markdown to persist ('-' reads stdin). Required unless --no-body.\"\n )\n .option(\n \"--session-id <uuid>\",\n \"Claude Code session UUID — recorded as the `claude --resume` handle\"\n )\n .option(\n \"--no-body\",\n \"Deliberately write a metadata-only checkpoint (no content)\"\n )\n .option(\"--exit\", \"(pause all only) Also send /exit to each session after pausing\")\n .option(\n \"--only <name>\",\n \"(pause all only) Pause just the sessions whose name or id contains <name>.\\n\" +\n \"For rehearsing the real thing against one session before trusting it with\\n\" +\n \"every open tab — a dry run exercises enumeration but never sends anything,\\n\" +\n \"which is exactly how a broken send survived until it was needed.\"\n )\n .option(\n \"--wait <ms>\",\n \"(pause all only) Max milliseconds to wait for a session to finish its\\n\" +\n \"checkpoint before /exit. Not a fixed delay — sessions are exited as soon\\n\" +\n \"as they return to the prompt, and any still busy at the deadline are left\\n\" +\n \"open rather than killed mid-write. (default: 180000)\",\n \"180000\"\n )\n .action(async (target: string | undefined, opts: { dryRun?: boolean; exit?: boolean; wait?: string; only?: string; bodyFile?: string; sessionId?: string; body?: boolean }) => {\n if (target === \"all\") {\n await cmdPauseAll({\n exit: opts.exit,\n dryRun: opts.dryRun,\n only: opts.only,\n wait: opts.wait !== undefined ? parseInt(opts.wait, 10) : undefined,\n });\n } else {\n if (target !== undefined) {\n console.error(err(`Unknown target: ${target}. Did you mean 'pai pause all'?`));\n process.exitCode = 1;\n return;\n }\n // Commander maps `--no-body` to opts.body === false.\n cmdPause(getDb(), {\n dryRun: opts.dryRun,\n bodyFile: opts.bodyFile,\n sessionId: opts.sessionId,\n noBody: opts.body === false,\n });\n }\n });\n\n // pai end [--body-file <path>] [--session-id <uuid>] [--no-body] [--dry-run]\n program\n .command(\"end\")\n .description(\n \"Finalize a session: save state, mark note Completed, display safe-exit instructions.\"\n )\n .option(\"--dry-run\", \"Preview all changes without writing them\")\n .option(\n \"--body-file <path>\",\n \"File holding the checkpoint markdown to persist ('-' reads stdin). Required unless --no-body.\"\n )\n .option(\n \"--session-id <uuid>\",\n \"Claude Code session UUID — recorded as the `claude --resume` handle\"\n )\n .option(\n \"--no-body\",\n \"Deliberately write a metadata-only checkpoint (no content)\"\n )\n .action((opts: { dryRun?: boolean; bodyFile?: string; sessionId?: string; body?: boolean }) => {\n cmdEnd(getDb(), {\n dryRun: opts.dryRun,\n bodyFile: opts.bodyFile,\n sessionId: opts.sessionId,\n noBody: opts.body === false,\n });\n });\n\n // pai clear-names [--dry-run] — recovery: wipe corrupt iTerm/JSON name store\n program\n .command(\"clear-names\")\n .description(\n \"Recovery: wipe corrupted iTerm2 session name state.\\n\" +\n \"Clears ~/.aibroker/session-names.json AND user.paiName from all live iTerm2 sessions.\\n\" +\n \"After running this, use /Name to re-label each tab.\"\n )\n .option(\"--dry-run\", \"Preview what would be cleared without making changes\")\n .action(async (opts: { dryRun?: boolean }) => {\n await cmdClearNames(opts);\n });\n\n // -------------------------------------------------------------------------\n // HIDDEN COMPAT ALIASES\n // -------------------------------------------------------------------------\n\n // pai resume <name> [--dry-run] — hidden; prefer `pai <name>`\n program\n .command(\"resume <name>\", { hidden: true })\n .description(\"Go to a session by name or UUID (prefer: pai <name>)\")\n .option(\"--dry-run\", \"Print the exact argv and cwd, then exit without launching\")\n .action((name: string, opts: { dryRun?: boolean }) => {\n cmdGoto(getDb(), name, { dryRun: opts.dryRun });\n });\n\n // pai cd <identifier> — hidden; shell wrapper uses this\n program\n .command(\"cd <identifier>\", { hidden: true })\n .description(\"cd to a project directory (shell wrapper handles the actual cd)\")\n .action((identifier: string) => {\n const db = getDb();\n const project = resolveIdentifier(db, identifier);\n if (!project) {\n console.error(`Project not found: ${identifier}`);\n process.exit(1);\n return;\n }\n\n if (existsSync(project.root_path)) {\n process.stdout.write(project.root_path + \"\\n\");\n return;\n }\n\n process.stderr.write(\n warn(`Path not found: ${project.root_path}\\n`) +\n dim(\" Searching for moved location...\\n\")\n );\n\n const result = findMovedPath(project.root_path);\n\n if (result.found) {\n const newPath = result.found;\n const newEncoded = encodeDir(newPath);\n const ts = now();\n db.prepare(\n \"UPDATE projects SET root_path = ?, encoded_dir = ?, updated_at = ? WHERE id = ?\"\n ).run(newPath, newEncoded, ts, project.id);\n process.stderr.write(\n ok(`Project moved: ${shortenPath(project.root_path, 50)}\\n`) +\n dim(` → ${newPath}\\n`) +\n ok(\"Registry updated.\\n\")\n );\n process.stdout.write(newPath + \"\\n\");\n return;\n }\n\n if (result.ambiguous) {\n process.stderr.write(\n warn(`Multiple directories named \"${basename(project.root_path)}\" found:\\n`)\n );\n for (const candidate of result.ambiguous!) {\n process.stderr.write(dim(` ${candidate}\\n`));\n }\n process.stderr.write(\n dim(`\\n Disambiguate with: pai projects rebind ${project.slug} <path>\\n`)\n );\n process.exitCode = 1;\n return;\n }\n\n process.stderr.write(\n err(\n `Project \"${project.slug}\" root_path \"${project.root_path}\" does not exist on disk\\n` +\n ` and no folder named \"${basename(project.root_path)}\" was found in scan dirs.\\n`\n ) +\n dim(` Fix with: pai projects rebind ${project.slug} <new-path>\\n`)\n );\n process.exitCode = 1;\n });\n\n // -------------------------------------------------------------------------\n // pai notes — hidden power-user alias; accessible but not in main help\n // -------------------------------------------------------------------------\n\n const notesCmd = program\n .command(\"notes [project-slug]\", { hidden: true })\n .description(\"Markdown session notes — list notes, optionally filtered to a project.\")\n .option(\"--limit <n>\", \"Maximum number of notes to show\", \"20\")\n .option(\"--status <status>\", \"Filter by status: open | completed | compacted\")\n .action(\n (projectSlug: string | undefined, opts: { limit?: string; status?: string }) => {\n cmdNotesList(getDb(), projectSlug, opts);\n }\n );\n\n notesCmd\n .command(\"list [project-slug]\")\n .description(\"List markdown session notes (same as: pai notes)\")\n .option(\"--limit <n>\", \"Maximum number of notes to show\", \"20\")\n .option(\"--status <status>\", \"Filter by status: open | completed | compacted\")\n .action(\n (projectSlug: string | undefined, opts: { limit?: string; status?: string }) => {\n cmdNotesList(getDb(), projectSlug, opts);\n }\n );\n\n // -------------------------------------------------------------------------\n // pai find <query> — hidden power-user alias for history search\n // -------------------------------------------------------------------------\n\n program\n .command(\"find <query>\", { hidden: true })\n .description(\"Search prompt history for matching sessions.\")\n .option(\"-n, --n <count>\", \"Maximum number of sessions to show\", \"20\")\n .option(\"--json\", \"Output as JSON array\")\n .action(async (query: string, opts: { n?: string; json?: boolean }) => {\n await cmdFind(query, opts);\n });\n\n // -------------------------------------------------------------------------\n // pai shell-init — emit shell function for eval \"$(pai shell-init)\"\n // -------------------------------------------------------------------------\n\n program\n .command(\"shell-init\")\n .description('Emit shell integration code. Add to ~/.zshrc: eval \"$(pai shell-init)\"')\n .action(() => {\n process.stdout.write(\n `# PAI shell integration — generated by: pai shell-init\npai() {\n if [[ \"$1\" == \"cd\" ]]; then\n local dir=$(command pai cd \"$2\" 2>/dev/null)\n if [[ -n \"$dir\" && -d \"$dir\" ]]; then\n builtin cd \"$dir\"\n echo \"-> $dir\"\n else\n echo \"Project not found: $2\" >&2\n return 1\n fi\n elif [[ \"$1\" == \"projects\" && \"$2\" == \"cd\" ]]; then\n local dir=$(command pai projects cd \"$3\" 2>/dev/null)\n if [[ -n \"$dir\" && -d \"$dir\" ]]; then\n builtin cd \"$dir\"\n echo \"-> $dir\"\n else\n echo \"Project not found: $3\" >&2\n return 1\n fi\n elif [[ $# -eq 0 ]]; then\n # Bare \\`pai\\` → interactive picker. fzf draws on /dev/tty; the picker writes\n # a chosen directory to PAI_PICK_OUT when you press Ctrl-G (cd only), which we\n # then cd into here (a child process can't change this shell's cwd itself).\n local __pai_f\n __pai_f=$(mktemp -t pai-pick 2>/dev/null) || { command pai; return $?; }\n PAI_PICK_OUT=\"$__pai_f\" command pai\n local __pai_rc=$?\n local __pai_dir=\"\"\n [[ -s \"$__pai_f\" ]] && __pai_dir=$(cat \"$__pai_f\")\n command rm -f \"$__pai_f\"\n if [[ -n \"$__pai_dir\" && -d \"$__pai_dir\" ]]; then\n builtin cd \"$__pai_dir\"\n echo \"-> $__pai_dir\"\n fi\n return $__pai_rc\n else\n command pai \"$@\"\n fi\n}\n\n# Print the working directory after an interactive Claude Code session exits.\n# A SessionEnd hook can't do this reliably: Claude Code does not fire SessionEnd\n# on /exit (anthropics/claude-code#17885) and may reap the hook mid-run (#41577).\n# Running it from the shell, after \\`claude\\` returns, sidesteps both.\nclaude() {\n local __pai_skip=0 __pai_arg\n for __pai_arg in \"$@\"; do\n case \"$__pai_arg\" in\n -p|--print) __pai_skip=1 ;;\n esac\n done\n command claude \"$@\"\n local __pai_rc=$?\n if [[ -t 1 && $__pai_skip -eq 0 ]]; then\n printf '\\\\n\\\\033[2m📂 Working directory:\\\\033[0m %s\\\\n\\\\033[2m cd \"%s\"\\\\033[0m\\\\n' \"$PWD\" \"$PWD\"\n fi\n return $__pai_rc\n}\n`\n );\n });\n\n // -------------------------------------------------------------------------\n // pai [query] [pick] — DEFAULT COMMAND (must be registered LAST)\n // -------------------------------------------------------------------------\n\n program\n .command(\"query [query] [pick]\", { isDefault: true, hidden: true })\n .description(\n \"Find and launch a session by topic, name, or UUID.\\n\" +\n \"No arg → deduped session listing\\n\" +\n \"Name → switch live tab, or resume, or start fresh\\n\" +\n \"UUID → direct resume via filesystem scan\\n\" +\n \"Topic → history search → candidate list → pick #\"\n )\n .option(\"-y, --auto\", \"Auto-pick #1 without prompting\")\n .option(\"--dry-run\", \"Print what would happen without launching\")\n .option(\"-n, --n <count>\", \"Max candidates for history search\", \"20\")\n .option(\"--all\", \"Show all entries including cold / zero-session / archived projects\")\n .option(\"--list\", \"Skip the interactive picker; print the static session listing\")\n .action(async (query: string | undefined, pick: string | undefined, opts: { auto?: boolean; dryRun?: boolean; n?: string; all?: boolean; list?: boolean }) => {\n // No query → interactive fzf picker (projects + sessions, go where you pick).\n // `--list` (or a non-TTY pipe, handled inside cmdPick) falls back to the\n // static listing. Any query still goes through the name/UUID/topic resolver.\n if (query === undefined && !opts.list) {\n await cmdPick(getDb(), { all: opts.all, dryRun: opts.dryRun });\n return;\n }\n const pickN = pick !== undefined ? parseInt(pick, 10) : undefined;\n await cmdMain(getDb(), query, pickN, opts);\n });\n\n // -------------------------------------------------------------------------\n // Error handling\n // -------------------------------------------------------------------------\n\n program.configureOutput({\n writeErr: (str) => process.stderr.write(err(str)),\n });\n\n program.exitOverride((error) => {\n if (error.code === \"commander.helpDisplayed\" || error.code === \"commander.version\") {\n process.exit(0);\n }\n if (\n error.code === \"commander.missingArgument\" ||\n error.code === \"commander.unknownOption\" ||\n error.code === \"commander.unknownCommand\"\n ) {\n process.exit(1);\n }\n console.error(err(error.message));\n process.exit(1);\n });\n\n return program;\n}\n"],"mappings":"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"}