{"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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"}