{"version":3,"file":"session-B3qJnaix.mjs","names":["cmdList","renderTable","cmdInfo","cmdTag","upsertTag","getProject","statusColor","statusColor","renderTable"],"sources":["../src/config/claude-json.ts","../src/cli/impl/project/commands.ts","../src/cli/lib/new-dir.ts","../src/cli/help.ts","../src/cli/lib/harness.ts","../src/cli/lib/health.ts","../src/cli/lib/provider-choice.ts","../src/cli/lib/names.ts","../src/cli/lib/legacy.ts","../src/session/slug-generator.ts","../src/cli/commands/session/helpers.ts","../src/cli/commands/session/commands.ts","../src/cli/commands/session.ts"],"sourcesContent":["/**\n * claude-json.ts — safe read/write for ~/.claude.json\n *\n * This file is not ours. It holds every MCP server registration plus Claude\n * Code's own per-project state — on a working machine, hundreds of kilobytes\n * that no one can reconstruct by hand. PAI only ever adds one key to it.\n *\n * The previous implementation (duplicated in mcp.ts and daemon.ts) did:\n *\n *     try { return JSON.parse(read(path)); } catch { return {}; }\n *\n * followed by a full-file write. A malformed or transiently unreadable file\n * therefore became an empty object, and the next write replaced the user's\n * entire config with just PAI's entry. No error, no backup, exit code 0.\n *\n * The precondition is unlikely, which is exactly the problem: `pai setup` is\n * advertised as idempotent and safe to re-run, so it is what people run when\n * something is already broken — the state in which the file is most likely to\n * be malformed.\n */\n\nimport { existsSync, readFileSync, writeFileSync, copyFileSync, renameSync, unlinkSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { assertTestWriteAllowed } from \"./test-isolation.js\";\n\n/** Resolved at call time so a changed HOME (tests) is honoured. */\nexport function claudeJsonPath(): string {\n  return join(homedir(), \".claude.json\");\n}\n\n\n/**\n * Read ~/.claude.json.\n *\n * A missing file is a legitimate first-run state and yields {}. Anything else\n * — malformed JSON, permissions, a half-written file — throws. Returning {}\n * for an unreadable file is what turns a read problem into data loss on the\n * next write.\n */\nexport function readClaudeJson(): Record<string, unknown> {\n  if (!existsSync(claudeJsonPath())) return {};\n\n  let raw: string;\n  try {\n    raw = readFileSync(claudeJsonPath(), \"utf8\");\n  } catch (e) {\n    throw new Error(\n      `Could not read ${claudeJsonPath()}: ${e instanceof Error ? e.message : String(e)}\\n` +\n      `Refusing to continue — writing now would replace your MCP registrations with PAI's alone.`\n    );\n  }\n\n  try {\n    return JSON.parse(raw) as Record<string, unknown>;\n  } catch (e) {\n    throw new Error(\n      `${claudeJsonPath()} is not valid JSON: ${e instanceof Error ? e.message : String(e)}\\n` +\n      `Refusing to continue — overwriting it would destroy every MCP server registration it holds.\\n` +\n      `Fix the file, or move it aside and let Claude Code recreate it, then re-run this command.`\n    );\n  }\n}\n\n/**\n * Write ~/.claude.json, keeping a backup and never leaving it half-written.\n *\n * Writes to a temp file and renames: rename is atomic within a filesystem, so\n * a crash mid-write leaves the original intact rather than truncated. The\n * previous direct writeFileSync could truncate the file and then fail.\n */\nexport function writeClaudeJson(data: Record<string, unknown>): void {\n  assertTestWriteAllowed(claudeJsonPath());\n  const serialized = JSON.stringify(data, null, 2) + \"\\n\";\n\n  if (existsSync(claudeJsonPath())) {\n    try {\n      copyFileSync(claudeJsonPath(), backupPath());\n    } catch (e) {\n      throw new Error(\n        `Could not back up ${claudeJsonPath()} to ${backupPath()}: ${e instanceof Error ? e.message : String(e)}\\n` +\n        `Refusing to write without a backup.`\n      );\n    }\n  }\n\n  const tmp = `${claudeJsonPath()}.tmp-pai-${process.pid}`;\n  try {\n    writeFileSync(tmp, serialized, \"utf8\");\n    renameSync(tmp, claudeJsonPath());\n  } catch (e) {\n    try { if (existsSync(tmp)) unlinkSync(tmp); } catch { /* best effort */ }\n    throw new Error(\n      `Failed to write ${claudeJsonPath()}: ${e instanceof Error ? e.message : String(e)}\\n` +\n      `The original is unchanged${existsSync(backupPath()) ? `; a backup is at ${backupPath()}` : \"\"}.`\n    );\n  }\n}\n\nfunction backupPath(): string {\n  return `${claudeJsonPath()}.bak-pai`;\n}\n\n/** Where the pre-write backup is kept, for messages to the user. */\nexport function claudeJsonBackupPath(): string {\n  return backupPath();\n}\n\n/**\n * Mark `absPath` as trusted in Claude Code's per-project state\n * (projects[<path>].hasTrustDialogAccepted), so launching it skips the\n * \"trust this folder\" dialog. Goes through readClaudeJson/writeClaudeJson, so\n * a malformed file throws instead of being replaced. Returns false when the\n * path was already trusted (nothing written).\n */\nexport function trustProjectPath(absPath: string): boolean {\n  const config = readClaudeJson();\n  const projects =\n    typeof config.projects === \"object\" && config.projects !== null ? (config.projects as Record<string, unknown>) : {};\n  const entry =\n    typeof projects[absPath] === \"object\" && projects[absPath] !== null ? (projects[absPath] as Record<string, unknown>) : {};\n  if (entry.hasTrustDialogAccepted === true) return false;\n  writeClaudeJson({ ...config, projects: { ...projects, [absPath]: { ...entry, hasTrustDialogAccepted: true } } });\n  return true;\n}\n","/**\n * Core project CRUD commands: add, list, info, archive, unarchive, move, tag,\n * alias, edit, detect, consolidate, go, rebind — plus private helpers levenshtein,\n * containsIgnoreCase, findProjectNotesDirs, and findMovedPath.\n */\n\nimport {\n  existsSync,\n  readdirSync,\n  statSync,\n  mkdirSync,\n  renameSync,\n} from \"node:fs\";\nimport { join, basename, resolve } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport chalk from \"chalk\";\nimport { trustProjectPath } from \"../../../config/claude-json.js\";\nimport { unregistrableReason } from \"../../../registry/registrable.js\";\nimport { getRegistryBackend } from \"../../../storage/factory.js\";\nimport type { Project } from \"../../../storage/registry-interface.js\";\nimport {\n  ok,\n  warn,\n  err,\n  dim,\n  bold,\n  header,\n  slugFromPath,\n  encodeDir,\n  resolvePath,\n  scaffoldProjectDirs,\n  renderTable,\n  shortenPath,\n  fmtDate,\n  now,\n} from \"../../lib/utils.js\";\nimport {\n  detectProject,\n  formatDetection,\n  formatDetectionJson,\n} from \"../detect.js\";\nimport { ensurePaiMarker } from \"../../../registry/pai-marker.js\";\nimport type { ProjectRow, SessionRow } from \"./types.js\";\nimport {\n  requireProject,\n  resolveIdentifier,\n  getProject,\n  getProjectTags,\n  getProjectAliases,\n  getSessionCount,\n  getLastSessionDate,\n  upsertTag,\n} from \"./helpers.js\";\nimport { loadScanConfig, resolveHome } from \"../registry/scan.js\";\n\n// ---------------------------------------------------------------------------\n// Private helpers\n// ---------------------------------------------------------------------------\n\nfunction levenshtein(a: string, b: string): number {\n  const m = a.length;\n  const n = b.length;\n  const dp: number[][] = Array.from({ length: m + 1 }, (_, i) =>\n    Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0))\n  );\n  for (let i = 1; i <= m; i++) {\n    for (let j = 1; j <= n; j++) {\n      dp[i][j] =\n        a[i - 1] === b[j - 1]\n          ? dp[i - 1][j - 1]\n          : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);\n    }\n  }\n  return dp[m][n];\n}\n\nfunction containsIgnoreCase(haystack: string, needle: string): boolean {\n  return haystack.toLowerCase().includes(needle.toLowerCase());\n}\n\nfunction findProjectNotesDirs(project: ProjectRow): {\n  encodedDir: string;\n  fullPath: string;\n  notesPath: string;\n  noteCount: number;\n}[] {\n  const claudeProjects = join(homedir(), \".claude\", \"projects\");\n  if (!existsSync(claudeProjects)) return [];\n\n  const results: {\n    encodedDir: string;\n    fullPath: string;\n    notesPath: string;\n    noteCount: number;\n  }[] = [];\n  const rootEncoded = encodeDir(project.root_path);\n\n  try {\n    for (const entry of readdirSync(claudeProjects)) {\n      const full = join(claudeProjects, entry);\n      try {\n        if (!statSync(full).isDirectory()) continue;\n      } catch {\n        continue;\n      }\n\n      if (entry !== rootEncoded && !entry.startsWith(rootEncoded)) continue;\n\n      const notesPath = join(full, \"Notes\");\n      if (!existsSync(notesPath)) continue;\n\n      let noteCount = 0;\n      try {\n        noteCount = readdirSync(notesPath).filter(\n          (f) => f.endsWith(\".md\") || f.endsWith(\".txt\")\n        ).length;\n      } catch {\n        // count stays 0\n      }\n\n      results.push({ encodedDir: entry, fullPath: full, notesPath, noteCount });\n    }\n  } catch {\n    // Unreadable — ignore\n  }\n\n  return results;\n}\n\n// ---------------------------------------------------------------------------\n// Moved-project detection\n// ---------------------------------------------------------------------------\n\n// Directories to skip during filesystem walk\nconst SKIP_DIRS = new Set([\n  \".git\", \"node_modules\", \".next\", \".nuxt\", \"dist\", \"build\", \"coverage\",\n  \".cache\", \"__pycache__\", \"vendor\", \".svn\", \".hg\", \"venv\", \".venv\",\n  \"target\",  // Rust/Java build dir\n  \"Notes\",   // PAI session notes — not project roots\n]);\n\n/**\n * Walk `dir` up to `maxDepth` levels deep, collecting all subdirectory paths\n * whose basename matches `targetBasename` (case-insensitive on macOS/case-sensitive\n * on Linux, whichever is appropriate — we use exact case matching to keep it\n * correct and fast).\n *\n * Skips hidden directories and known build/tool dirs.\n * Stops walking a branch if the deadline is exceeded (returns partial results).\n */\nfunction walkForBasename(\n  dir: string,\n  targetBasename: string,\n  maxDepth: number,\n  deadline: number,\n  results: string[]\n): void {\n  if (Date.now() > deadline) return;\n  if (maxDepth <= 0) return;\n\n  let entries: string[];\n  try {\n    entries = readdirSync(dir);\n  } catch {\n    return;\n  }\n\n  for (const entry of entries) {\n    if (Date.now() > deadline) return;\n    if (entry.startsWith(\".\")) continue;\n    if (SKIP_DIRS.has(entry)) continue;\n\n    const full = join(dir, entry);\n    let isDir = false;\n    try {\n      isDir = statSync(full).isDirectory();\n    } catch {\n      continue;\n    }\n    if (!isDir) continue;\n\n    // Case-insensitive comparison for the target basename (handles macOS APFS)\n    if (entry.toLowerCase() === targetBasename.toLowerCase()) {\n      results.push(full);\n      // Don't recurse into the match itself — we want the directory, not children\n      continue;\n    }\n\n    walkForBasename(full, targetBasename, maxDepth - 1, deadline, results);\n  }\n}\n\n/**\n * Try to find where a project has moved.\n *\n * Searches scan_dirs from config (plus a set of common fallback dirs) for a\n * directory whose basename matches the basename of the registered root_path.\n *\n * Returns:\n *   { found: string }   — exactly one match found\n *   { ambiguous: string[] }  — multiple matches found\n *   { found: undefined }     — no match found (or timed out)\n */\nexport function findMovedPath(registeredPath: string): { found?: string; ambiguous?: string[] } {\n  const targetBasename = basename(registeredPath);\n  const config = loadScanConfig();\n  const deadline = Date.now() + 5_000; // 5-second max\n\n  // Build the list of top-level directories to search\n  const home = homedir();\n  const configDirs = (config.scan_dirs ?? []).map((d) => resolveHome(d));\n\n  // Walk UP the registered path to find the deepest existing ancestor.\n  // This is the best search root when a project has moved within the same tree.\n  // e.g. ~/Cloud/Ablage/2025/Project → ~/Cloud/Ablage/2026/Project\n  //      Deepest existing ancestor: ~/Cloud/Ablage (if 2025 is gone but Ablage exists)\n  function deepestExistingAncestor(p: string): string | null {\n    let current = p;\n    while (true) {\n      const parent = join(current, \"..\");\n      if (parent === current) return null; // filesystem root\n      if (parent === home) return null;    // don't use home itself as search root\n      if (existsSync(parent)) return parent;\n      current = parent;\n    }\n  }\n\n  const ancestorRoot = deepestExistingAncestor(registeredPath);\n\n  const fallbackDirs = [\n    join(home, \"dev\"),\n    join(home, \"Desktop\"),\n    join(home, \"Projects\"),\n    join(home, \"Documents\"),\n    // Common cloud-storage root folders (Synology Drive, iCloud, etc.)\n    join(home, \"Cloud\"),\n    join(home, \"Library\", \"Mobile Documents\", \"com~apple~CloudDocs\"),  // iCloud Drive\n    // The deepest ancestor of the registered path that still exists on disk\n    ...(ancestorRoot ? [ancestorRoot] : []),\n  ];\n\n  // Deduplicate and filter to existing directories\n  const searchRoots = [...new Set([...configDirs, ...fallbackDirs])]\n    .map((d) => {\n      try { return resolve(d); } catch { return null; }\n    })\n    .filter((d): d is string => d !== null && existsSync(d));\n\n  const results: string[] = [];\n  for (const root of searchRoots) {\n    if (Date.now() > deadline) break;\n    walkForBasename(root, targetBasename, 6, deadline, results);\n  }\n\n  // Deduplicate results (different roots might overlap)\n  const unique = [...new Set(results)];\n\n  if (unique.length === 0) return {};\n  if (unique.length === 1) return { found: unique[0] };\n  return { ambiguous: unique };\n}\n\n// ---------------------------------------------------------------------------\n// Command implementations\n// ---------------------------------------------------------------------------\n\nexport async function cmdAdd(\n  rawPath: string,\n  opts: { slug?: string; type?: string; displayName?: string; trust?: boolean }\n): Promise<void> {\n  const backend = await getRegistryBackend();\n  const rootPath = resolvePath(rawPath);\n  const slug = opts.slug ?? slugFromPath(rootPath);\n  const encodedDir = encodeDir(rootPath);\n  const displayName = opts.displayName ?? slug;\n  const type = opts.type ?? \"local\";\n\n  const validTypes = [\"local\", \"central\", \"obsidian-linked\", \"external\"];\n  if (!validTypes.includes(type)) {\n    console.error(err(`Invalid type \"${type}\". Valid: ${validTypes.join(\", \")}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  // Disposable directories must not become projects. Two agent worktrees and two\n  // /private/tmp paths got in this way and between them carried 8 sessions\n  // attributed to locations with no future — and `pai <name>` will happily route\n  // someone into a worktree a cleanup can delete underneath them.\n  const ephemeral = unregistrableReason(rootPath);\n  if (ephemeral) {\n    console.error(err(`Refusing to register ${shortenPath(rootPath, 60)}`));\n    console.error(dim(`  That is ${ephemeral}.`));\n    console.error(dim(`  A project needs a durable location — move it, then register.`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const existing = (await backend.getProjectBySlug(slug)) ?? (await backend.getProjectByRootPath(rootPath));\n  if (existing) {\n    console.error(\n      err(`Project already registered (slug: ${slug} or path: ${rootPath})`)\n    );\n    process.exitCode = 1;\n    return;\n  }\n\n  const dirName = basename(rootPath).toLowerCase();\n  const active = await backend.listProjects({ status: \"active\" });\n  const similar = active.filter((p) => p.slug !== slug).map((p) => ({ slug: p.slug, root_path: p.root_path }));\n  const matches = similar.filter(\n    (s) =>\n      basename(s.root_path).toLowerCase() === dirName ||\n      s.slug.replace(/-\\d+$/, \"\") === slug.replace(/-\\d+$/, \"\")\n  );\n  if (matches.length > 0) {\n    console.log(warn(`Similar project(s) already registered:`));\n    for (const m of matches) {\n      console.log(dim(`  ${bold(m.slug)}  ${shortenPath(m.root_path, 50)}`));\n    }\n    console.log(\n      dim(\n        `  Consider: pai project alias ${matches[0].slug} <name> (to link them)`\n      )\n    );\n    console.log(\n      dim(`  Or: pai project archive ${slug} (if this is a duplicate)`)\n    );\n    console.log();\n  }\n\n  const ts = now();\n  await backend.createProject({\n    slug,\n    displayName,\n    rootPath,\n    encodedDir,\n    type: type as Project[\"type\"],\n    status: \"active\",\n    createdAt: ts,\n    updatedAt: ts,\n  });\n\n  scaffoldProjectDirs(rootPath);\n\n  try {\n    ensurePaiMarker(rootPath, slug, displayName);\n  } catch {\n    // Non-fatal — warn but don't fail the add command.\n  }\n\n  if (opts.trust !== false) {\n    try {\n      trustProjectPath(rootPath);\n    } catch (e) {\n      console.error(warn(`Could not mark ${rootPath} trusted in Claude Code: ${(e as Error).message.split(\"\\n\")[0]}`));\n    }\n  }\n\n  console.log(ok(`Project added: ${bold(slug)}`));\n  console.log(dim(`  Path:         ${rootPath}`));\n  console.log(dim(`  Encoded dir:  ${encodedDir}`));\n  console.log(dim(`  Type:         ${type}`));\n}\n\nexport async function cmdList(\n  opts: { status?: string; tag?: string; type?: string; all?: boolean }\n): Promise<void> {\n  const backend = await getRegistryBackend();\n\n  let tagId: number | undefined;\n  if (opts.tag) {\n    const tags = await backend.listAllTags();\n    tagId = tags.find((t) => t.name === opts.tag)?.id;\n    if (tagId === undefined) {\n      console.log(warn(\"No projects found.\"));\n      return;\n    }\n  }\n\n  const rows = (\n    await backend.listProjectsWithSessionStats({\n      status: opts.status ? (opts.status as Project[\"status\"]) : opts.all ? undefined : \"active\",\n      tagId,\n      orderBy: \"status_updated\",\n    })\n  ).filter((p) => !opts.type || p.type === opts.type);\n\n  if (!rows.length) {\n    console.log(warn(\"No projects found.\"));\n    return;\n  }\n\n  const tableRows = rows.map((r, i) => [\n    dim(String(i + 1)),\n    bold(r.display_name ?? r.slug),\n    dim(r.slug),\n    dim(shortenPath(r.root_path, 44)),\n    r.status === \"active\" ? chalk.green(r.status) : chalk.yellow(r.status),\n    dim(r.type),\n    String(r.session_count),\n    fmtDate(r.last_active),\n  ]);\n\n  console.log(\n    renderTable(\n      [\"#\", \"Name\", \"Slug\", \"Path\", \"Status\", \"Type\", \"Sessions\", \"Last Active\"],\n      tableRows\n    )\n  );\n  console.log();\n\n  // When showing active-only, inform the user about hidden archived projects\n  const total = await backend.countProjects();\n  const hiddenCount = total - rows.length;\n  if (!opts.all && !opts.status && hiddenCount > 0) {\n    console.log(dim(`  ${rows.length} active project(s)  (${hiddenCount} archived — use --all to show)`));\n  } else {\n    console.log(dim(`  ${rows.length} project(s)`));\n  }\n}\n\nexport async function cmdInfo(identifier: string): Promise<void> {\n  const project =\n    (await resolveIdentifier(identifier)) ?? (await requireProject(identifier));\n  const backend = await getRegistryBackend();\n  const tags = await getProjectTags(project.id);\n  const aliases = await getProjectAliases(project.id);\n  const sessionCount = await getSessionCount(project.id);\n  const lastSession = await getLastSessionDate(project.id);\n\n  const recentSessions: SessionRow[] = await backend.listSessionsForProject(project.id, {\n    orderBy: \"created_desc\",\n    limit: 5,\n  });\n\n  console.log();\n  console.log(header(`  ${project.display_name}`));\n  console.log();\n  console.log(`  ${bold(\"Slug:\")}         ${project.slug}`);\n  console.log(`  ${bold(\"Path:\")}         ${project.root_path}`);\n  console.log(`  ${bold(\"Encoded dir:\")}  ${project.encoded_dir}`);\n  console.log(`  ${bold(\"Type:\")}         ${project.type}`);\n  console.log(\n    `  ${bold(\"Status:\")}       ${\n      project.status === \"active\"\n        ? chalk.green(project.status)\n        : chalk.yellow(project.status)\n    }`\n  );\n  console.log(\n    `  ${bold(\"Tags:\")}         ${\n      tags.length ? tags.map((t) => chalk.cyan(t)).join(\", \") : dim(\"none\")\n    }`\n  );\n  console.log(\n    `  ${bold(\"Aliases:\")}      ${aliases.length ? aliases.join(\", \") : dim(\"none\")}`\n  );\n  console.log(`  ${bold(\"Sessions:\")}     ${sessionCount}`);\n  console.log(`  ${bold(\"Last active:\")}  ${fmtDate(lastSession)}`);\n  console.log(`  ${bold(\"Created:\")}      ${fmtDate(project.created_at)}`);\n  if (project.archived_at) {\n    console.log(`  ${bold(\"Archived:\")}     ${fmtDate(project.archived_at)}`);\n  }\n\n  if (recentSessions.length) {\n    console.log();\n    console.log(`  ${bold(\"Recent sessions:\")}`);\n    const sessionRows = recentSessions.map((s) => [\n      dim(`#${s.number}`),\n      s.date,\n      s.title.length > 50 ? s.title.slice(0, 47) + \"...\" : s.title,\n      s.status === \"completed\"\n        ? chalk.green(s.status)\n        : chalk.yellow(s.status),\n    ]);\n    console.log(\n      renderTable([\"#\", \"Date\", \"Title\", \"Status\"], sessionRows)\n        .split(\"\\n\")\n        .map((l) => \"  \" + l)\n        .join(\"\\n\")\n    );\n  }\n  console.log();\n}\n\nexport async function cmdArchive(slug: string): Promise<void> {\n  const project = await requireProject(slug);\n  if (project.status === \"archived\") {\n    console.log(warn(`Project ${slug} is already archived.`));\n    return;\n  }\n  const ts = now();\n  const backend = await getRegistryBackend();\n  await backend.updateProjectStatus(project.id, \"archived\", { archivedAt: ts, updatedAt: ts });\n  console.log(ok(`Archived: ${bold(slug)}`));\n}\n\nexport async function cmdUnarchive(slug: string): Promise<void> {\n  const project = await requireProject(slug);\n  if (project.status !== \"archived\") {\n    console.log(\n      warn(`Project ${slug} is not archived (status: ${project.status}).`)\n    );\n    return;\n  }\n  const ts = now();\n  const backend = await getRegistryBackend();\n  await backend.updateProjectStatus(project.id, \"active\", { archivedAt: null, updatedAt: ts });\n  console.log(ok(`Unarchived: ${bold(slug)}`));\n}\n\nexport async function cmdMove(slug: string, newPath: string): Promise<void> {\n  const project = await requireProject(slug);\n  const resolvedNew = resolvePath(newPath);\n  const newEncoded = encodeDir(resolvedNew);\n  const ts = now();\n\n  const backend = await getRegistryBackend();\n  await backend.updateProjectPath(project.id, { rootPath: resolvedNew, encodedDir: newEncoded }, ts);\n\n  console.log(ok(`Moved: ${bold(slug)}`));\n  console.log(dim(`  Old path: ${project.root_path}`));\n  console.log(dim(`  New path: ${resolvedNew}`));\n}\n\nexport async function cmdTag(\n  slug: string,\n  tags: string[]\n): Promise<void> {\n  const project = await requireProject(slug);\n  const backend = await getRegistryBackend();\n  const added: string[] = [];\n  const skipped: string[] = [];\n\n  for (const tagName of tags) {\n    const tagId = await upsertTag(tagName);\n    const exists = await backend.projectHasTag(project.id, tagId);\n    if (exists) {\n      skipped.push(tagName);\n    } else {\n      await backend.addProjectTag(project.id, tagId);\n      added.push(tagName);\n    }\n  }\n\n  if (added.length) {\n    console.log(\n      ok(\n        `Tagged ${bold(slug)}: ${added.map((t) => chalk.cyan(t)).join(\", \")}`\n      )\n    );\n  }\n  if (skipped.length) {\n    console.log(dim(`  Already present: ${skipped.join(\", \")}`));\n  }\n}\n\nexport async function cmdAlias(\n  slug: string,\n  alias: string\n): Promise<void> {\n  await requireProject(slug);\n  const backend = await getRegistryBackend();\n\n  const conflict = await backend.getProjectBySlug(alias);\n  if (conflict) {\n    console.error(\n      err(`\"${alias}\" is already a project slug — cannot use as alias.`)\n    );\n    process.exitCode = 1;\n    return;\n  }\n\n  const project = (await getProject(slug))!;\n  try {\n    await backend.addAlias(alias, project.id);\n    console.log(ok(`Alias added: ${bold(alias)} → ${slug}`));\n  } catch {\n    console.error(err(`Alias \"${alias}\" is already registered.`));\n    process.exitCode = 1;\n  }\n}\n\nexport async function cmdEdit(\n  slug: string,\n  opts: { displayName?: string; type?: string }\n): Promise<void> {\n  const project = await requireProject(slug);\n\n  if (!opts.displayName && !opts.type) {\n    console.log(warn(\"Nothing to update. Use --display-name or --type.\"));\n    return;\n  }\n\n  const validTypes = [\"local\", \"central\", \"obsidian-linked\", \"external\"];\n  if (opts.type && !validTypes.includes(opts.type)) {\n    console.error(\n      err(`Invalid type \"${opts.type}\". Valid: ${validTypes.join(\", \")}`)\n    );\n    process.exitCode = 1;\n    return;\n  }\n\n  const ts = now();\n  const backend = await getRegistryBackend();\n  if (opts.displayName) {\n    await backend.updateProjectDisplayName(project.id, opts.displayName, ts);\n    console.log(ok(`Display name updated: ${bold(opts.displayName)}`));\n  }\n  if (opts.type) {\n    await backend.updateProjectType(project.id, opts.type as Project[\"type\"], ts);\n    console.log(ok(`Type updated: ${bold(opts.type)}`));\n  }\n}\n\nexport async function cmdDetect(\n  pathArg: string | undefined,\n  opts: { json?: boolean }\n): Promise<void> {\n  const cwd = pathArg ? resolvePath(pathArg) : process.cwd();\n  const detection = await detectProject(cwd);\n\n  if (!detection) {\n    if (opts.json) {\n      console.log(JSON.stringify({ error: \"no_match\", cwd }, null, 2));\n    } else {\n      console.log(warn(`No registered project found for: ${cwd}`));\n      console.log(dim(\"  Run 'pai project add .' to register this directory.\"));\n    }\n    return;\n  }\n\n  if (opts.json) {\n    console.log(formatDetectionJson(detection));\n    return;\n  }\n\n  console.log();\n  console.log(header(\"  Project Detection Result\"));\n  console.log();\n  console.log(\n    formatDetection(detection)\n      .split(\"\\n\")\n      .map((l) => \"  \" + l)\n      .join(\"\\n\")\n  );\n  console.log();\n}\n\nexport async function cmdConsolidate(\n  identifier: string,\n  opts: { yes?: boolean; dryRun?: boolean }\n): Promise<void> {\n  const project =\n    (await resolveIdentifier(identifier)) ?? (await requireProject(identifier));\n\n  console.log();\n  console.log(header(`  Consolidate: ${project.slug}`));\n  console.log(`  Target:  ${project.root_path}`);\n  console.log();\n\n  const dirs = findProjectNotesDirs(project);\n\n  if (dirs.length === 0) {\n    console.log(warn(\"  No scattered notes directories found for this project.\"));\n    return;\n  }\n\n  const canonicalNotes = join(project.root_path, \"Notes\");\n  const toMerge = dirs.filter((d) => d.notesPath !== canonicalNotes);\n\n  if (toMerge.length === 0) {\n    console.log(ok(\"  All notes are already in the canonical location.\"));\n    console.log(dim(`  ${canonicalNotes}`));\n    return;\n  }\n\n  console.log(\n    `  Found ${toMerge.length} scattered Notes directory(ies) to consolidate:`\n  );\n  console.log();\n\n  for (const d of toMerge) {\n    console.log(`    ${bold(d.encodedDir)}`);\n    console.log(dim(`      Notes: ${d.notesPath} (${d.noteCount} file(s))`));\n  }\n\n  console.log();\n  console.log(`  Destination: ${canonicalNotes}`);\n  console.log();\n\n  if (opts.dryRun) {\n    console.log(warn(\"  Dry run — no changes made. Remove --dry-run to proceed.\"));\n    return;\n  }\n\n  if (!opts.yes) {\n    console.log(\n      warn(\n        \"  Run with --yes to perform consolidation, or --dry-run to preview changes.\"\n      )\n    );\n    return;\n  }\n\n  mkdirSync(canonicalNotes, { recursive: true });\n\n  let movedCount = 0;\n  for (const d of toMerge) {\n    try {\n      const files = readdirSync(d.notesPath);\n      for (const f of files) {\n        if (!f.endsWith(\".md\") && !f.endsWith(\".txt\")) continue;\n        const src = join(d.notesPath, f);\n        const dest = join(canonicalNotes, f);\n        if (!existsSync(dest)) {\n          renameSync(src, dest);\n          console.log(ok(`    Moved: ${f}`));\n          movedCount++;\n        } else {\n          console.log(warn(`    Skipped (exists): ${f}`));\n        }\n      }\n    } catch (e) {\n      console.error(err(`    Error reading ${d.notesPath}: ${e}`));\n    }\n  }\n\n  console.log();\n  console.log(ok(`  Consolidated ${movedCount} file(s) into ${canonicalNotes}`));\n}\n\n/**\n * Attempt moved-path recovery for a project whose registered root_path is\n * missing. Updates the DB if exactly one candidate is found.\n *\n * Returns the new path on success, or undefined if ambiguous/not found.\n * Prints all messages to stderr (safe for shell-wrapper stdout capture).\n */\nasync function tryRecoverMovedProject(project: ProjectRow): Promise<string | undefined> {\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    const backend = await getRegistryBackend();\n    await backend.updateProjectPath(project.id, { rootPath: newPath, encodedDir: newEncoded }, ts);\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    return newPath;\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    return undefined;\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  return undefined;\n}\n\nexport async function cmdGo(query: string): Promise<void> {\n  const backend = await getRegistryBackend();\n  const all: ProjectRow[] = await backend.listProjects({ status: \"active\", orderBy: \"updated_desc\" });\n\n  if (!all.length) {\n    console.error(\n      err(\"No active projects registered. Run: pai project add <path>\")\n    );\n    process.exitCode = 1;\n    return;\n  }\n\n  const q = query.trim().toLowerCase();\n\n  // 1. Exact slug or alias match\n  const exact = await getProject(query);\n  if (exact) {\n    if (!existsSync(exact.root_path)) {\n      const recovered = await tryRecoverMovedProject(exact);\n      if (!recovered) { process.exitCode = 1; return; }\n      process.stdout.write(recovered + \"\\n\");\n      return;\n    }\n    process.stdout.write(exact.root_path + \"\\n\");\n    return;\n  }\n\n  // 2. Substring match against slug, display_name, or root_path basename\n  const partial = all.filter(\n    (p) =>\n      containsIgnoreCase(p.slug, q) ||\n      containsIgnoreCase(p.display_name, q) ||\n      containsIgnoreCase(basename(p.root_path), q)\n  );\n\n  if (partial.length === 1) {\n    const p = partial[0];\n    if (!existsSync(p.root_path)) {\n      const recovered = await tryRecoverMovedProject(p);\n      if (!recovered) { process.exitCode = 1; return; }\n      process.stdout.write(recovered + \"\\n\");\n      return;\n    }\n    process.stdout.write(p.root_path + \"\\n\");\n    return;\n  }\n\n  if (partial.length > 1) {\n    console.error(\n      err(`Ambiguous: \"${query}\" matches ${partial.length} projects:\\n`)\n    );\n    partial.forEach((p, i) => {\n      console.error(\n        `  ${dim(String(i + 1).padStart(2))}  ${bold(p.slug.padEnd(30))}  ${dim(\n          shortenPath(p.root_path, 50)\n        )}`\n      );\n    });\n    console.error();\n    console.error(dim(\"  Use a more specific name or the exact slug.\"));\n    process.exitCode = 1;\n    return;\n  }\n\n  // 3. No match — Levenshtein suggestions\n  const scored = all\n    .map((p) => {\n      const distSlug = levenshtein(q, p.slug.toLowerCase());\n      const distName = levenshtein(q, p.display_name.toLowerCase());\n      return { project: p, dist: Math.min(distSlug, distName) };\n    })\n    .sort((a, b) => a.dist - b.dist);\n\n  const threshold = 4;\n  const suggestions =\n    scored.filter((s) => s.dist <= threshold).length > 0\n      ? scored.filter((s) => s.dist <= threshold).slice(0, 3)\n      : scored.slice(0, 3);\n\n  console.error(err(`Project not found: \"${query}\"\\n`));\n  if (suggestions.length) {\n    console.error(warn(\"  Did you mean?\"));\n    for (const s of suggestions) {\n      console.error(\n        `    ${bold(s.project.slug.padEnd(30))}  ${dim(\n          shortenPath(s.project.root_path, 50)\n        )}`\n      );\n    }\n    console.error();\n    console.error(dim(\"  Run: pai project list  (to see all projects)\"));\n  }\n  process.exitCode = 1;\n}\n\nexport async function cmdRebind(\n  slug: string,\n  newPath: string\n): Promise<void> {\n  const project = await requireProject(slug);\n  const resolved = resolve(newPath.startsWith(\"~/\") ? join(homedir(), newPath.slice(2)) : newPath);\n\n  if (!existsSync(resolved)) {\n    console.error(err(`Path does not exist: ${resolved}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  let isDir = false;\n  try {\n    isDir = statSync(resolved).isDirectory();\n  } catch {\n    // stat failed\n  }\n  if (!isDir) {\n    console.error(err(`Path is not a directory: ${resolved}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const newEncoded = encodeDir(resolved);\n  const backend = await getRegistryBackend();\n\n  // Check if another project already owns this path\n  const conflict = await backend.getProjectByEncodedDir(newEncoded, { excludeId: project.id });\n  if (conflict) {\n    console.error(\n      err(`Path is already registered to project: ${bold(conflict.slug)}\\n`) +\n      dim(`  ${resolved}\\n`) +\n      dim(`  Archive or move that project first, or choose a different path.`)\n    );\n    process.exitCode = 1;\n    return;\n  }\n\n  const ts = now();\n  await backend.updateProjectPath(project.id, { rootPath: resolved, encodedDir: newEncoded }, ts);\n\n  console.log(ok(`Rebound: ${bold(slug)}`));\n  console.log(dim(`  Old path: ${project.root_path}`));\n  console.log(dim(`  New path: ${resolved}`));\n  console.log(dim(`  Encoded:  ${newEncoded}`));\n}\n","/** `pai new DIR`: resolve the folder, create it when missing, register it as a project. */\n\nimport { existsSync, mkdirSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { resolve } from \"node:path\";\nimport { CliError } from \"../define.js\";\nimport { cmdAdd } from \"../impl/project/commands.js\";\nimport { getRegistryBackend } from \"../../storage/factory.js\";\n\n/** \"~\", \"~/x\" -> under the home folder; anything else relative to `cwd`. */\nexport function resolveDir(raw: string, cwd = process.cwd()): string {\n  if (raw === \"~\") return homedir();\n  if (raw.startsWith(\"~/\")) return resolve(homedir(), raw.slice(2));\n  return resolve(cwd, raw);\n}\n\n/** A bare word is a session name; ./x ../x /x ~ ~/x or an existing folder is a path. */\nexport function looksLikePath(arg: string, cwd = process.cwd()): boolean {\n  if (/^(\\.{1,2}(\\/|$)|\\/|~(\\/|$))/.test(arg)) return true;\n  try {\n    return statSync(resolve(cwd, arg)).isDirectory();\n  } catch {\n    return false;\n  }\n}\n\nexport type Register = (dir: string) => Promise<void>;\n\n/** Register through the same code as `pai project add`; an already registered folder is fine. */\nexport const registerProject: Register = async (dir) => {\n  const backend = await getRegistryBackend();\n  if (await backend.getProjectByRootPath(dir)) return;\n  const code = process.exitCode;\n  await cmdAdd(dir, {});\n  if (process.exitCode && process.exitCode !== code) {\n    process.exitCode = code; // a refused registration (disposable folder) must not fail the launch\n  }\n};\n\nexport async function prepareDir(\n  raw: string | undefined,\n  o: { dryRun: boolean; out: (s: string) => void; register?: Register }\n): Promise<string> {\n  const dir = resolveDir(raw ?? \".\");\n  if (existsSync(dir) && !statSync(dir).isDirectory()) throw new CliError(`${dir} exists and is not a folder`, \"pai new <another folder>\");\n  if (o.dryRun) {\n    o.out(`(dry run) ${existsSync(dir) ? \"would register\" : \"would create and register\"} ${dir}`);\n    return dir;\n  }\n  if (!existsSync(dir)) {\n    mkdirSync(dir, { recursive: true });\n    o.out(`Created ${dir}`);\n  }\n  try {\n    await (o.register ?? registerProject)(dir);\n  } catch (e) {\n    o.out(`Could not register ${dir} as a project: ${e instanceof Error ? e.message.split(\"\\n\")[0] : String(e)}`);\n  }\n  return dir;\n}\n","/**\n * Help rendering and \"did you mean\" — the whole help experience in one file.\n *\n * Everything shown by `pai`, `pai help <command>`, `pai <command> --help`\n * and written by `pai doc` is derived from the CommandDef objects, so the\n * text next to a command's definition is the only copy.\n *\n * Colour only when stdout is a TTY and NO_COLOR is unset (FORCE_COLOR wins);\n * piped output is plain text.\n */\n\nimport { Chalk } from \"chalk\";\nimport type { CommandDef, GroupDef, OptDef } from \"./define.js\";\n\n// ---------------------------------------------------------------------------\n// Style\n// ---------------------------------------------------------------------------\n\nexport interface Style {\n  color: boolean;\n  bold(s: string): string;\n  dim(s: string): string;\n  cyan(s: string): string;\n  green(s: string): string;\n  yellow(s: string): string;\n  red(s: string): string;\n  head(s: string): string;\n}\n\nexport function colorEnabled(env: NodeJS.ProcessEnv = process.env, isTTY = !!process.stdout.isTTY): boolean {\n  if (env.NO_COLOR !== undefined && env.NO_COLOR !== \"\") return false;\n  if (env.FORCE_COLOR !== undefined && env.FORCE_COLOR !== \"\" && env.FORCE_COLOR !== \"0\") return true;\n  return isTTY && env.TERM !== \"dumb\";\n}\n\nexport function makeStyle(color: boolean): Style {\n  const c = new Chalk({ level: color ? 1 : 0 });\n  return {\n    color,\n    bold: (s) => c.bold(s),\n    dim: (s) => c.dim(s),\n    cyan: (s) => c.cyan(s),\n    green: (s) => c.green(s),\n    yellow: (s) => c.yellow(s),\n    red: (s) => c.red(s),\n    head: (s) => c.bold.underline(s),\n  };\n}\n\n// eslint-disable-next-line no-control-regex\nconst ANSI = /\\u001b\\[[0-9;]*m/g;\nconst visible = (s: string) => s.replace(ANSI, \"\").length;\nconst padEnd = (s: string, w: number) => s + \" \".repeat(Math.max(0, w - visible(s)));\n\n/** Aligned table with a header row. Cells may carry colour; widths ignore it. */\nexport function renderTable(headers: string[], rows: string[][], st: Style, indent = \"  \"): string {\n  const widths = headers.map((h, i) => Math.max(visible(h), ...rows.map((r) => visible(r[i] ?? \"\"))));\n  const line = (cells: string[]) =>\n    indent + cells.map((c, i) => (i === cells.length - 1 ? c : padEnd(c, widths[i]))).join(\"  \").trimEnd();\n  return [\n    line(headers.map((h) => st.dim(h))),\n    indent + st.dim(widths.map((w) => \"─\".repeat(w)).join(\"  \")),\n    ...rows.map(line),\n  ].join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Did you mean\n// ---------------------------------------------------------------------------\n\nfunction distance(a: string, b: string): number {\n  const d: number[][] = Array.from({ length: a.length + 1 }, (_, i) => [i, ...Array(b.length).fill(0)]);\n  for (let j = 1; j <= b.length; j++) d[0][j] = j;\n  for (let i = 1; i <= a.length; i++) {\n    for (let j = 1; j <= b.length; j++) {\n      d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));\n      if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);\n    }\n  }\n  return d[a.length][b.length];\n}\n\n/** Closest candidate to `input`, or null when nothing is plausibly meant. */\nexport function suggest(input: string, candidates: string[]): string | null {\n  const x = input.toLowerCase();\n  let best: string | null = null;\n  let bestScore = Infinity;\n  for (const c of candidates) {\n    const lc = c.toLowerCase();\n    let d = distance(x, lc);\n    if (x.length >= 2 && (lc.startsWith(x) || x.startsWith(lc))) d = Math.min(d, 1);\n    if (d < bestScore) {\n      bestScore = d;\n      best = c;\n    }\n  }\n  const limit = Math.max(1, Math.floor(x.length / 3) + (x.length > 4 ? 1 : 0));\n  return best !== null && bestScore <= limit ? best : null;\n}\n\n// ---------------------------------------------------------------------------\n// Command help\n// ---------------------------------------------------------------------------\n\nconst flagText = (o: OptDef) =>\n  `${o.short ? `-${o.short}, ` : \"    \"}--${o.name}${o.type !== \"boolean\" ? ` ${o.value ?? o.type.toUpperCase()}` : \"\"}`;\n\nexport function usageLine(path: string[], cmd: CommandDef): string {\n  const parts = [\"pai\", ...path];\n  if (cmd.subcommands?.length && !cmd.run) parts.push(\"<command>\");\n  for (const a of cmd.args ?? []) {\n    const n = a.variadic ? `${a.name}...` : a.name;\n    parts.push(a.required ? n : `[${n}]`);\n  }\n  if (cmd.subcommands?.length && cmd.run) parts.push(\"[command]\");\n  if (cmd.options?.length) parts.push(\"[options]\");\n  return parts.join(\" \");\n}\n\nfunction defaultText(o: OptDef): string {\n  if (o.default === undefined || o.default === false) return \"—\";\n  return String(o.default);\n}\n\n/** Full help for one command (what `pai help <cmd>` and `pai <cmd> --help` print). */\nexport function renderCommandHelp(path: string[], cmd: CommandDef, st: Style): string {\n  const out: string[] = [];\n  out.push(`${st.head(\"Usage\")}  ${st.bold(usageLine(path, cmd))}`, \"\");\n  out.push(cmd.description.trim(), \"\");\n  if (cmd.aliasOf) out.push(st.dim(`Shortcut for: pai ${cmd.aliasOf}`), \"\");\n\n  if (cmd.subcommands?.length) {\n    out.push(st.head(\"Commands\"));\n    out.push(\n      renderTable(\n        [\"Command\", \"Description\"],\n        cmd.subcommands.filter((s) => !s.hidden).map((s) => [st.cyan(s.name), s.summary]),\n        st\n      )\n    );\n    out.push(\"\");\n  }\n  if (cmd.args?.length) {\n    out.push(st.head(\"Arguments\"));\n    out.push(\n      renderTable(\n        [\"Argument\", \"Required\", \"Description\"],\n        cmd.args.map((a) => [st.cyan(a.variadic ? `${a.name}...` : a.name), a.required ? \"yes\" : \"no\", a.summary]),\n        st\n      ),\n      \"\"\n    );\n  }\n  const opts: OptDef[] = [\n    ...(cmd.options ?? []),\n    { name: \"help\", short: \"h\", type: \"boolean\", summary: \"Show this help\" },\n  ];\n  out.push(st.head(\"Options\"));\n  out.push(\n    renderTable(\n      [\"Flag\", \"Type\", \"Default\", \"Description\"],\n      opts.map((o) => [st.cyan(flagText(o)), o.type === \"boolean\" ? \"flag\" : o.type, defaultText(o), o.summary]),\n      st\n    ),\n    \"\"\n  );\n  if (cmd.examples.length) {\n    out.push(st.head(\"Examples\"));\n    for (const e of cmd.examples) out.push(`  ${st.green(\"$\")} ${e}`);\n    out.push(\"\");\n  }\n  if (cmd.seeAlso?.length) out.push(`${st.head(\"See also\")}  ${cmd.seeAlso.join(\", \")}`, \"\");\n  return out.join(\"\\n\").replace(/\\n+$/, \"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Overview\n// ---------------------------------------------------------------------------\n\nconst DAILY_EXAMPLES = [\n  [\"pai\", \"pick a session (type to filter, Enter opens)\"],\n  ['pai \"20 - Webseiten\"', \"open it; shows how it will start\"],\n  [\"pai ls\", \"the sessions as a table\"],\n  [\"pai setups\", \"orchestrator + worker combinations\"],\n  ['pai setups save \"my mix\"', \"keep the current combination\"],\n  ['pai new ~/code/app --with \"anthropic + flashnext-iq3 workers\"', \"start a new folder: Anthropic plans, the local model codes\"],\n  ['pai webseiten --with \"glm only\"', \"scripting: start it that way, no questions\"],\n];\n\n/** `pai --help`: only the daily things, then a pointer to `pai more`. */\nexport function renderOverview(groups: GroupDef[], root: CommandDef, version: string, st: Style): string {\n  const daily = groups.flatMap((g) => g.commands).filter((c) => c.daily);\n  const out: string[] = [];\n  out.push(`${st.bold(\"pai\")} ${st.dim(version)} — find a session, start it, choose where it runs`, \"\");\n  out.push(`${st.head(\"Usage\")}  ${st.bold(\"pai [NAME] [options]\")}   ${st.dim(\"or\")}   ${st.bold(\"pai <command>\")}`, \"\");\n  out.push(st.head(\"Daily\"));\n  out.push(\n    renderList(\n      [\n        [st.cyan(\"pai\"), \"Pick a session: type to filter, Enter opens it\"],\n        [st.cyan(\"pai NAME\"), root.summary],\n        ...daily.map((c) => [st.cyan(`pai ${c.name}`), c.summary]),\n      ],\n      st\n    ),\n    \"\"\n  );\n  out.push(st.head(\"Examples\"));\n  for (const [cmd, why] of DAILY_EXAMPLES) out.push(`  ${st.green(\"$\")} ${cmd.padEnd(34)} ${st.dim(why)}`);\n  out.push(\"\");\n  out.push(`more commands: ${st.bold(\"pai more\")}   ${st.dim(\"·   details for one command: pai help <command>\")}`, \"\");\n  return out.join(\"\\n\");\n}\n\n/** `pai more`: every command that is not on the first screen, by group. */\nexport function renderMore(groups: GroupDef[], st: Style): string {\n  const out: string[] = [st.head(\"More commands\"), \"\"];\n  for (const g of groups) {\n    const cmds = g.commands.filter((c) => !c.daily);\n    if (!cmds.length) continue;\n    out.push(st.bold(g.title));\n    out.push(\n      renderTable(\n        [\"Command\", \"Description\"],\n        cmds.map((c) => [st.cyan(c.name), c.summary]),\n        st\n      ),\n      \"\"\n    );\n  }\n  out.push(st.dim(\"Details for one command: pai help <command>\"), \"\");\n  return out.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// Markdown reference (pai doc)\n// ---------------------------------------------------------------------------\n\nexport function mdCommand(path: string[], cmd: CommandDef, level: number): string[] {\n  const h = \"#\".repeat(level);\n  const out = [`${h} pai ${path.join(\" \")}`, \"\", cmd.summary, \"\", \"```\", usageLine(path, cmd), \"```\", \"\", cmd.description.trim(), \"\"];\n  if (cmd.aliasOf) out.push(`Shortcut for \\`pai ${cmd.aliasOf}\\`.`, \"\");\n  if (cmd.args?.length) {\n    out.push(\"| Argument | Required | Description |\", \"|---|---|---|\");\n    for (const a of cmd.args) out.push(`| \\`${a.variadic ? `${a.name}...` : a.name}\\` | ${a.required ? \"yes\" : \"no\"} | ${a.summary} |`);\n    out.push(\"\");\n  }\n  if (cmd.options?.length) {\n    out.push(\"| Flag | Type | Default | Description |\", \"|---|---|---|---|\");\n    for (const o of cmd.options) {\n      out.push(`| \\`${flagText(o).trim()}\\` | ${o.type === \"boolean\" ? \"flag\" : o.type} | ${defaultText(o)} | ${o.summary} |`);\n    }\n    out.push(\"\");\n  }\n  if (cmd.examples.length) out.push(\"```sh\", ...cmd.examples, \"```\", \"\");\n  if (cmd.seeAlso?.length) out.push(`See also: ${cmd.seeAlso.map((s) => `\\`${s}\\``).join(\", \")}`, \"\");\n  for (const s of cmd.subcommands ?? []) out.push(...mdCommand([...path, s.name], s, level + 1));\n  return out;\n}\n\nexport function renderMarkdown(groups: GroupDef[], version: string): string {\n  const out = [`# pai ${version} — command reference`, \"\", \"_Generated by `pai doc` from the command definitions. Do not edit by hand._\", \"\"];\n  for (const g of groups) {\n    out.push(`## ${g.title}`, \"\");\n    for (const c of g.commands) out.push(...mdCommand([c.name], c, 3));\n  }\n  return out.join(\"\\n\").replace(/\\n{3,}/g, \"\\n\\n\");\n}\n\n/** Two-column list without a header row — the overview and `help more` use it. */\nfunction renderList(rows: string[][], st: Style, indent = \"  \"): string {\n  const w = Math.max(...rows.map((r) => visible(r[0])));\n  return rows.map((r) => `${indent}${padEnd(r[0], w)}  ${r.slice(1).join(\"  \")}`.trimEnd()).join(\"\\n\");\n}\n","/**\n * The command line that starts the Claude Code harness on a provider.\n *\n * This is the one builder behind `pai open`, `pai new` and (later) every\n * other launcher. The env, --settings pin, --model and extra arguments come\n * from buildLaunchPlan (src/workers/launch.ts) — the same code the old\n * `pai launch` runs — so the two cannot differ. Nothing here shells out to a\n * second `pai`.\n */\n\nimport { spawnSync } from \"node:child_process\";\nimport { buildLaunchPlan, maskLaunchEnv, type LaunchPlan } from \"../../workers/launch.js\";\nimport type { WorkersConfig } from \"../../workers/config.js\";\nimport { workersLogDir, ledgerPath } from \"../../workers/paths.js\";\nimport { appendLedger } from \"../../workers/ledger.js\";\nimport { SESSION_NAME_ENV, getProfile } from \"../../workers/session-profile-store.js\";\nimport { SESSION_WORKER_PROVIDER_ENV } from \"../../workers/session-provider.js\";\nimport { printExitDir } from \"./exit-dir.js\";\n\nexport interface Harness {\n  cmd: \"claude\";\n  argv: string[];\n  env: NodeJS.ProcessEnv;\n  cwd: string;\n  provider: string;\n  model: string;\n}\n\n/** `--name N \"/Name N\"`: label the session and tab (same as launchPrompt in lib/launch.ts). `named`: the session already carries N, so no /Name is sent. */\nexport const nameArgs = (name: string, named = false): string[] => (named ? [\"--name\", name] : [\"--name\", name, `/Name ${name}`]);\n\nexport async function buildHarness(\n  workers: Pick<WorkersConfig, \"providers\" | \"nativeModels\" | \"logDir\">,\n  opts: { provider: string; model?: string; cwd: string; resume?: string; name: string; named?: boolean }\n): Promise<Harness> {\n  const extra = [...(opts.resume ? [\"--resume\", opts.resume] : []), ...nameArgs(opts.name, opts.named)];\n  const plan: LaunchPlan = await buildLaunchPlan(workers, opts.provider, opts.model, extra, workersLogDir(workers));\n  // the session's name lets worker spawns find its profile; its worker provider follows the profile\n  plan.env[SESSION_NAME_ENV] = opts.name;\n  const wp = getProfile(opts.name)?.workers?.provider;\n  if (wp) plan.env[SESSION_WORKER_PROVIDER_ENV] = wp;\n  return { cmd: \"claude\", argv: plan.argv, env: plan.env, cwd: opts.cwd, provider: plan.providerName, model: plan.model };\n}\n\nconst quote = (a: string) => (/[\\s\"'$`\\\\{}]/.test(a) ? JSON.stringify(a) : a);\n\n/** The exec line for --dry-run. The auth token is inside the --settings JSON, so it is masked here too. */\nexport function execLine(h: Harness): string {\n  const token = h.env.ANTHROPIC_AUTH_TOKEN;\n  const masked = token ? maskLaunchEnv({ ANTHROPIC_AUTH_TOKEN: token }).ANTHROPIC_AUTH_TOKEN : undefined;\n  const hide = (a: string) => (token && masked ? a.split(token).join(masked) : a);\n  return `cd ${quote(h.cwd)} && ${h.cmd} ${h.argv.map((a) => quote(hide(a))).join(\" \")}`;\n}\n\nexport function dryRunText(h: Harness): string {\n  const masked = maskLaunchEnv(h.env);\n  const env = Object.keys(masked)\n    .sort()\n    .filter((k) => /^(ANTHROPIC_|CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC|ENABLE_TOOL_SEARCH|PAI_WORKER|PAI_SESSION_)/.test(k))\n    .map((k) => `  ${k}=${masked[k]}`);\n  return [execLine(h), ...(env.length ? [\"env:\", ...env] : [])].join(\"\\n\");\n}\n\n/** Run the harness in the foreground; returns its exit code. */\nexport function execHarness(h: Harness, workers: Pick<WorkersConfig, \"logDir\">): number {\n  appendLedger(ledgerPath(workersLogDir(workers)), \"LAUNCH-START\", {\n    kind: \"launch\",\n    provider: h.provider,\n    model: h.model,\n    cwd: h.cwd,\n  });\n  const r = spawnSync(h.cmd, h.argv, { stdio: \"inherit\", env: h.env, cwd: h.cwd });\n  if (r.error) throw new Error(`could not start claude: ${r.error.message}`);\n  printExitDir(h.cwd);\n  return r.status ?? 0;\n}\n","/** Is a provider usable right now, and if not, the plain-words reason. */\n\nimport { mkdirSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { paiHomePath } from \"../../config/pai-home.js\";\nimport { ANTHROPIC_NATIVE, type WorkersConfig } from \"../../workers/config.js\";\nimport { budgetExceeded, budgetSkipReason, budgetWall, type BudgetReading } from \"../../workers/budget.js\";\n\nexport interface Health {\n  state: \"ok\" | \"limit\" | \"off\";\n  reason: string;\n}\n\nexport function providerHealth(\n  name: string,\n  cfg: Pick<WorkersConfig, \"providers\" | \"routing\">,\n  budget: Record<string, BudgetReading | undefined>,\n  now = new Date()\n): Health {\n  if (name !== ANTHROPIC_NATIVE) {\n    const p = cfg.providers[name];\n    if (!p) return { state: \"off\", reason: `${name}: not configured` };\n    if (!p.enabled) return { state: \"off\", reason: `${name}: disabled` };\n  }\n  const r = budget[name];\n  if (r && budgetExceeded(r, budgetWall(cfg.routing, name))) {\n    return { state: \"limit\", reason: `${budgetSkipReason(name, r, now).replace(\" \", \": at limit, \")}` };\n  }\n  return { state: \"ok\", reason: r?.percent != null ? `${Math.round(r.percent)}% used` : \"ok\" };\n}\n\nimport { budgetCache } from \"../../workers/budget.js\";\n\n/** Live budget readings, cached for 5 minutes by the worker engine; never waits longer than `ms`. */\nexport async function readBudget(workers: WorkersConfig, ms = 1500): Promise<Record<string, BudgetReading | undefined>> {\n  try {\n    return await Promise.race([\n      budgetCache.warm(workers),\n      new Promise<Record<string, BudgetReading>>((res) => setTimeout(() => res({}), ms).unref()),\n    ]);\n  } catch {\n    return {};\n  }\n}\n\nconst SNAPSHOT_MAX_AGE_MS = 6 * 3600_000;\n\n/**\n * Last budget readings a full lookup saved, for a first paint that must not\n * wait on provider usage endpoints. Stale-by-design: callers refresh after.\n */\nexport function readBudgetSnapshot(now = Date.now()): Record<string, BudgetReading | undefined> {\n  try {\n    const raw = JSON.parse(readFileSync(paiHomePath(\"budget-snapshot.json\"), \"utf8\")) as { at?: number; map?: Record<string, BudgetReading> };\n    if (typeof raw.at === \"number\" && now - raw.at < SNAPSHOT_MAX_AGE_MS && raw.map) return raw.map;\n  } catch {\n    /* none yet */\n  }\n  return {};\n}\n\nexport function saveBudgetSnapshot(map: Record<string, BudgetReading | undefined>, now = Date.now()): void {\n  try {\n    mkdirSync(paiHomePath(), { recursive: true });\n    const target = paiHomePath(\"budget-snapshot.json\");\n    writeFileSync(target + \".tmp\", JSON.stringify({ at: now, map }));\n    renameSync(target + \".tmp\", target);\n  } catch {\n    /* the next run just has no snapshot */\n  }\n}\n","/**\n * Which provider (and model) a session opens on. One pure function, one\n * order, written down:\n *\n *   1. --provider on the command line — always wins, never overridden\n *   2. the provider the session's transcript ran on\n *   3. the active provider from workers.yaml\n *   4. anthropic (plain Claude Code login)\n *\n * Nothing falls back silently: an explicit provider that is not available is\n * an error naming the ones that are (see assertAvailable).\n */\n\nimport { ANTHROPIC_NATIVE, type WorkerProvider } from \"../../workers/config.js\";\nimport { stripModelVariant } from \"../../utils/model-window.js\";\nimport { CliError } from \"../define.js\";\n\nexport type ChoiceSource = \"flag\" | \"session\" | \"active\" | \"default\";\n\nexport interface SessionOrigin {\n  provider: string;\n  model: string;\n}\n\nexport interface Choice {\n  provider: string;\n  /** Undefined = the provider's default model. */\n  model?: string;\n  source: ChoiceSource;\n}\n\n/** Provider a transcript's model belongs to: a configured provider whose model\n *  table names it, else anthropic for a claude-* model, else unknown. */\nexport function inferOrigin(\n  model: string | null | undefined,\n  providers: Record<string, Pick<WorkerProvider, \"enabled\" | \"native\" | \"models\">>\n): SessionOrigin | null {\n  if (!model) return null;\n  const base = stripModelVariant(model);\n  for (const [name, p] of Object.entries(providers)) {\n    if (!p.enabled || p.native) continue;\n    if (Object.values(p.models).some((m) => !!m && stripModelVariant(m) === base)) return { provider: name, model };\n  }\n  return /^claude-/.test(base) ? { provider: ANTHROPIC_NATIVE, model } : null;\n}\n\nexport function chooseProvider(input: {\n  flagProvider?: string;\n  flagModel?: string;\n  origin: SessionOrigin | null;\n  active: string | null;\n}): Choice {\n  const { flagProvider, flagModel, origin, active } = input;\n  if (flagProvider) {\n    const same = origin?.provider === flagProvider;\n    return { provider: flagProvider, model: flagModel ?? (same ? origin.model : undefined), source: \"flag\" };\n  }\n  if (origin) return { provider: origin.provider, model: flagModel ?? origin.model, source: \"session\" };\n  if (active && active !== \"auto\") return { provider: active, model: flagModel, source: \"active\" };\n  return { provider: ANTHROPIC_NATIVE, model: flagModel, source: \"default\" };\n}\n\nconst shortList = (names: string[], max = 8) =>\n  names.length <= max ? names.join(\", \") : `${names.slice(0, max).join(\", \")} … (${names.length - max} more: pai providers)`;\n\n/** Fail with the reason and the providers that do work. */\nexport function assertAvailable(\n  provider: string,\n  available: string[],\n  retry: (alternative: string) => string\n): void {\n  if (available.includes(provider)) return;\n  const alt = available.find((n) => n !== provider) ?? ANTHROPIC_NATIVE;\n  throw new CliError(\n    `provider \"${provider}\" is not available (not configured or disabled). Available: ${shortList(available)}`,\n    retry(alt)\n  );\n}\n\n/** Keep a session's recorded model only when the target provider offers it. */\nexport function modelFor(provider: Pick<WorkerProvider, \"models\">, wanted: string | undefined): string | undefined {\n  if (!wanted) return undefined;\n  const base = stripModelVariant(wanted);\n  return Object.values(provider.models).find((m) => !!m && (m === wanted || stripModelVariant(m) === base)) ?? undefined;\n}\n","/**\n * Session names live in Claude's clc registry (~/.claude/session.json):\n * { sessions: [ { name, resume|session (uuid), directory } ] }.\n * Renaming rewrites that one entry, leaving every other field alone.\n */\n\nimport { existsSync, readFileSync, renameSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport const clcRegistryPath = (home = homedir()) => join(home, \".claude\", \"session.json\");\n\ninterface Entry {\n  name?: string;\n  resume?: string;\n  session?: string;\n  directory?: string;\n  [k: string]: unknown;\n}\n\nexport function renameSession(\n  uuid: string,\n  newName: string,\n  directory: string | undefined,\n  path = clcRegistryPath()\n): { previous?: string } {\n  const data: { sessions?: Entry[]; [k: string]: unknown } = existsSync(path)\n    ? (JSON.parse(readFileSync(path, \"utf8\")) as { sessions?: Entry[] })\n    : {};\n  const sessions = (data.sessions ??= []);\n  const hit = sessions.find((e) => e.resume === uuid || e.session === uuid);\n  let previous: string | undefined;\n  if (hit) {\n    previous = hit.name;\n    hit.name = newName;\n  } else {\n    sessions.push({ name: newName, resume: uuid, ...(directory ? { directory } : {}) });\n  }\n  const tmp = `${path}.tmp-${process.pid}`;\n  writeFileSync(tmp, JSON.stringify(data, null, 2) + \"\\n\");\n  renameSync(tmp, path);\n  return { previous };\n}\n","/**\n * Exit-code bridge for old-style commands. They report failure by setting\n * process.exitCode; the entry point exits with the number a command returns.\n */\nexport async function legacy(fn: () => Promise<void> | void): Promise<number> {\n  process.exitCode = undefined;\n  await fn();\n  const code = Number(process.exitCode ?? 0);\n  process.exitCode = undefined;\n  return code;\n}\n","/**\n * Slug generator for PAI session notes.\n *\n * Extracts a 1-3 word descriptive slug from Claude Code JSONL transcripts\n * using keyword frequency analysis — no LLM required.\n *\n * JSONL format (one JSON object per line):\n *   - type \"user\":      { type: \"user\",      message: { role: \"user\",      content: string | [{ type, text }] } }\n *   - type \"assistant\": { type: \"assistant\", message: { role: \"assistant\", content: [{ type, text }] } }\n */\n\nimport { readFileSync, existsSync, readdirSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { STOP_WORDS } from \"../utils/stop-words.js\";\n\n// ---------------------------------------------------------------------------\n// Public API types\n// ---------------------------------------------------------------------------\n\nexport interface SlugOptions {\n  /** Maximum number of words in the generated slug (default: 3) */\n  maxWords?: number;\n  /** Maximum character length of the generated slug (default: 30) */\n  maxLength?: number;\n}\n\n// STOP_WORDS imported from utils/stop-words.ts\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extract plain text from a parsed JSONL message object.\n */\nfunction extractText(obj: Record<string, unknown>): string | null {\n  const msg = obj.message as Record<string, unknown> | undefined;\n  if (!msg) return null;\n\n  const content = msg.content;\n\n  // Array of content blocks (modern assistant messages)\n  if (Array.isArray(content)) {\n    const texts: string[] = [];\n    for (const block of content) {\n      const b = block as Record<string, unknown>;\n      if (b.type === \"text\" && typeof b.text === \"string\") {\n        texts.push(b.text);\n      }\n    }\n    return texts.join(\" \") || null;\n  }\n\n  // Plain string content (user messages)\n  if (typeof content === \"string\") {\n    return content || null;\n  }\n\n  return null;\n}\n\n/**\n * Tokenize a string into lowercase words, filtering stop words and short tokens.\n */\nfunction tokenize(text: string): string[] {\n  return text\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, \" \")\n    .split(/\\s+/)\n    .filter((w) => {\n      if (w.length < 3) return false;\n      if (/^\\d+$/.test(w)) return false;\n      if (STOP_WORDS.has(w)) return false;\n      return true;\n    });\n}\n\n// ---------------------------------------------------------------------------\n// Public functions\n// ---------------------------------------------------------------------------\n\n/**\n * Find the latest JSONL transcript for a project's Claude encoded directory.\n *\n * @param encodedDir  Claude-encoded project directory name,\n *                    e.g. \"-Users-alice-dev-ai-PAI\"\n * @returns  Absolute path to the most recently modified .jsonl file, or null.\n */\nexport function findLatestTranscript(encodedDir: string): string | null {\n  const sessionsDir = join(\n    homedir(),\n    \".claude\",\n    \"projects\",\n    encodedDir,\n    \"sessions\"\n  );\n\n  if (!existsSync(sessionsDir)) return null;\n\n  let entries: string[];\n  try {\n    entries = readdirSync(sessionsDir).filter((f) => f.endsWith(\".jsonl\"));\n  } catch {\n    return null;\n  }\n\n  if (!entries.length) return null;\n\n  // Sort by mtime descending, return the newest\n  const sorted = entries\n    .map((f) => {\n      const fullPath = join(sessionsDir, f);\n      try {\n        return { path: fullPath, mtime: statSync(fullPath).mtimeMs };\n      } catch {\n        return { path: fullPath, mtime: 0 };\n      }\n    })\n    .sort((a, b) => b.mtime - a.mtime);\n\n  return sorted[0].path;\n}\n\n/**\n * Read the last `count` human/assistant message pairs from a JSONL file.\n *\n * Synchronous — reads the whole file in memory.  JSONL transcripts are\n * bounded by context window size so this is safe even for large sessions.\n *\n * @param jsonlPath  Absolute path to a Claude Code .jsonl transcript file.\n * @param count      Number of conversation pairs to read (default: 15).\n * @returns  Array of plain-text message strings (up to count*2 entries).\n */\nexport function readLastMessages(\n  jsonlPath: string,\n  count: number = 15\n): string[] {\n  if (!existsSync(jsonlPath)) return [];\n\n  let raw: string;\n  try {\n    raw = readFileSync(jsonlPath, \"utf8\");\n  } catch {\n    return [];\n  }\n\n  const lines = raw.split(\"\\n\").filter((l) => l.trim().length > 0);\n  const messages: string[] = [];\n  const limit = count * 2;\n\n  // Walk from the end to collect the most recent messages first\n  for (let i = lines.length - 1; i >= 0 && messages.length < limit; i--) {\n    let obj: Record<string, unknown>;\n    try {\n      obj = JSON.parse(lines[i]) as Record<string, unknown>;\n    } catch {\n      continue;\n    }\n\n    const type = obj.type as string | undefined;\n    if (type !== \"assistant\" && type !== \"user\") continue;\n\n    const text = extractText(obj);\n    if (text && text.trim().length > 0) {\n      // Prepend to maintain chronological order\n      messages.unshift(text);\n    }\n  }\n\n  return messages;\n}\n\n/**\n * Generate a descriptive 1-3 word slug from conversation message strings.\n *\n * Algorithm:\n *  1. Tokenize all messages, remove stop words and short tokens\n *  2. Count word frequency\n *  3. Pick the top `maxWords` most frequent tokens\n *  4. Join with hyphen, lowercase\n *\n * @param messages  Array of plain-text conversation messages.\n * @param opts      Optional slug configuration.\n * @returns  A lowercase hyphen-joined slug, e.g. \"memory-engine-refactor\",\n *           or \"unnamed-session\" if no meaningful words are found.\n */\nexport function generateSlug(messages: string[], opts?: SlugOptions): string {\n  const maxWords = opts?.maxWords ?? 3;\n  const maxLength = opts?.maxLength ?? 30;\n\n  if (!messages.length) return \"unnamed-session\";\n\n  // Count word frequencies across all messages\n  const freq = new Map<string, number>();\n  for (const msg of messages) {\n    for (const token of tokenize(msg)) {\n      freq.set(token, (freq.get(token) ?? 0) + 1);\n    }\n  }\n\n  if (!freq.size) return \"unnamed-session\";\n\n  // Sort by frequency descending, take top maxWords\n  const topWords = Array.from(freq.entries())\n    .sort((a, b) => b[1] - a[1])\n    .slice(0, maxWords)\n    .map(([word]) => word);\n\n  if (!topWords.length) return \"unnamed-session\";\n\n  // Join and trim to maxLength (truncate at last hyphen boundary)\n  let slug = topWords.join(\"-\");\n  if (slug.length > maxLength) {\n    slug = slug.slice(0, maxLength).replace(/-[^-]*$/, \"\");\n  }\n\n  return slug || \"unnamed-session\";\n}\n","/**\n * Shared DB helpers, formatting, and path utilities for session sub-commands.\n */\n\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport chalk from \"chalk\";\nimport { err } from \"../../lib/utils.js\";\nimport type { RegistryBackend } from \"../../../storage/registry-interface.js\";\nimport type { SessionRow, ProjectRow } from \"./types.js\";\n\nexport async function getProject(\n  registryBackend: RegistryBackend,\n  slug: string\n): Promise<ProjectRow | undefined> {\n  const project = await registryBackend.getProjectBySlug(slug);\n  return project ?? undefined;\n}\n\nexport function statusColor(status: string): string {\n  switch (status) {\n    case \"completed\":\n      return chalk.green(status);\n    case \"compacted\":\n      return chalk.blue(status);\n    default:\n      return chalk.yellow(status);\n  }\n}\n\n/** Convert a slug to title-cased display name: \"memory-engine\" → \"Memory Engine\" */\nexport function toTitleCase(slug: string): string {\n  return slug\n    .replace(/-/g, \" \")\n    .replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\n/** Notes directory for a project: ~/.claude/projects/<encoded_dir>/Notes/ */\nexport function getNotesDir(project: ProjectRow): string {\n  return join(homedir(), \".claude\", \"projects\", project.encoded_dir, \"Notes\");\n}\n\n/** Format a session filename: number=27, date=\"2026-02-23\" → \"0027 - 2026-02-23 - Title.md\" */\nexport function formatFilename(\n  number: number,\n  date: string,\n  titleSlug: string\n): string {\n  const n = String(number).padStart(4, \"0\");\n  return `${n} - ${date} - ${titleSlug}.md`;\n}\n\n/** Resolve a session by project + number or \"latest\". Exits on failure. */\nexport async function resolveSession(\n  registryBackend: RegistryBackend,\n  project: ProjectRow,\n  numberOrLatest: string\n): Promise<SessionRow> {\n  let session: SessionRow | undefined;\n\n  if (numberOrLatest === \"latest\") {\n    session = (await registryBackend.getLatestSessionForProject(project.id)) ?? undefined;\n  } else {\n    const num = parseInt(numberOrLatest, 10);\n    if (isNaN(num)) {\n      console.error(err(`Invalid session number: ${numberOrLatest}`));\n      process.exit(1);\n    }\n    session = (await registryBackend.getSessionByNumber(project.id, num)) ?? undefined;\n  }\n\n  if (!session) {\n    console.error(\n      err(`Session ${numberOrLatest} not found in project ${project.slug}`)\n    );\n    process.exit(1);\n  }\n\n  return session;\n}\n\nexport async function upsertTag(registryBackend: RegistryBackend, tagName: string): Promise<number> {\n  return registryBackend.upsertTag(tagName);\n}\n\nexport async function getSessionTags(registryBackend: RegistryBackend, sessionId: number): Promise<string[]> {\n  return registryBackend.listTagsForSession(sessionId);\n}\n","/**\n * Session CRUD commands: list, info, rename, slug, tag, route, active, auto-route.\n */\n\nimport {\n  existsSync,\n  readdirSync,\n  renameSync,\n  readFileSync,\n  writeFileSync,\n  statSync,\n} from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport chalk from \"chalk\";\nimport {\n  ok,\n  warn,\n  err,\n  dim,\n  bold,\n  header,\n  renderTable,\n  fmtDate,\n} from \"../../lib/utils.js\";\nimport {\n  findLatestTranscript,\n  readLastMessages,\n  generateSlug,\n} from \"../../../session/slug-generator.js\";\nimport type { RegistryBackend } from \"../../../storage/registry-interface.js\";\nimport type { SessionRow, ProjectRow } from \"./types.js\";\nimport {\n  getProject,\n  statusColor,\n  toTitleCase,\n  getNotesDir,\n  formatFilename,\n  resolveSession,\n  upsertTag,\n  getSessionTags,\n} from \"./helpers.js\";\n\n// ---------------------------------------------------------------------------\n// list\n// ---------------------------------------------------------------------------\n\nexport async function cmdList(\n  projectSlug: string | undefined,\n  opts: { limit?: string; status?: string }\n): Promise<void> {\n  const { getRegistryBackend } = await import(\"../../../storage/factory.js\");\n  const registryBackend = await getRegistryBackend();\n\n  const limit = parseInt(opts.limit ?? \"20\", 10);\n\n  let project: ProjectRow | undefined;\n  if (projectSlug) {\n    project = await getProject(registryBackend, projectSlug);\n    if (!project) {\n      console.error(err(`Project not found: ${projectSlug}`));\n      process.exitCode = 1;\n      return;\n    }\n  }\n\n  const rows = await registryBackend.listSessions({\n    projectId: project?.id,\n    status: opts.status,\n    limit,\n  });\n\n  if (!rows.length) {\n    console.log(warn(\"No sessions found.\"));\n    return;\n  }\n\n  const showProject = !projectSlug;\n  const headers = showProject\n    ? [\"#\", \"Project\", \"Date\", \"Title\", \"Status\", \"Tokens\"]\n    : [\"#\", \"Date\", \"Title\", \"Status\", \"Tokens\"];\n\n  const tableRows = rows.map((r) => {\n    const title = r.title.length > 45 ? r.title.slice(0, 42) + \"...\" : r.title;\n    const tokens =\n      r.token_count != null ? dim(r.token_count.toLocaleString()) : dim(\"—\");\n    if (showProject) {\n      return [\n        dim(`#${r.number}`),\n        r.project_slug,\n        r.date,\n        title,\n        statusColor(r.status),\n        tokens,\n      ];\n    }\n    return [dim(`#${r.number}`), r.date, title, statusColor(r.status), tokens];\n  });\n\n  console.log();\n  if (project) {\n    console.log(`  ${bold(project.display_name)} sessions:`);\n    console.log();\n  }\n  console.log(renderTable(headers, tableRows));\n  console.log();\n  console.log(dim(`  ${rows.length} session(s) shown (limit: ${limit})`));\n}\n\n// ---------------------------------------------------------------------------\n// info\n// ---------------------------------------------------------------------------\n\nexport async function cmdInfo(\n  projectSlug: string,\n  sessionNumber: string\n): Promise<void> {\n  const { getRegistryBackend } = await import(\"../../../storage/factory.js\");\n  const registryBackend = await getRegistryBackend();\n\n  const project = await getProject(registryBackend, projectSlug);\n  if (!project) {\n    console.error(err(`Project not found: ${projectSlug}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const session = await resolveSession(registryBackend, project, sessionNumber);\n\n  console.log();\n  console.log(header(`  Session #${session.number}: ${session.title}`));\n  console.log();\n  console.log(\n    `  ${bold(\"Project:\")}     ${project.display_name} (${project.slug})`\n  );\n  console.log(`  ${bold(\"Date:\")}        ${session.date}`);\n  console.log(`  ${bold(\"Status:\")}      ${statusColor(session.status)}`);\n  console.log(`  ${bold(\"Filename:\")}    ${session.filename}`);\n  console.log(`  ${bold(\"Slug:\")}        ${session.slug}`);\n  if (session.claude_session_id) {\n    console.log(\n      `  ${bold(\"Claude ID:\")}   ${dim(session.claude_session_id)}`\n    );\n  }\n  if (session.token_count != null) {\n    console.log(\n      `  ${bold(\"Tokens:\")}      ${session.token_count.toLocaleString()}`\n    );\n  }\n  console.log(`  ${bold(\"Created:\")}     ${fmtDate(session.created_at)}`);\n  if (session.closed_at) {\n    console.log(`  ${bold(\"Closed:\")}      ${fmtDate(session.closed_at)}`);\n  }\n  console.log();\n}\n\n// ---------------------------------------------------------------------------\n// rename\n// ---------------------------------------------------------------------------\n\nexport async function cmdRename(\n  projectSlug: string,\n  numberOrLatest: string,\n  newSlug: string\n): Promise<void> {\n  const { getRegistryBackend } = await import(\"../../../storage/factory.js\");\n  const registryBackend = await getRegistryBackend();\n  await cmdRenameWith(registryBackend, projectSlug, numberOrLatest, newSlug);\n}\n\nasync function cmdRenameWith(\n  registryBackend: RegistryBackend,\n  projectSlug: string,\n  numberOrLatest: string,\n  newSlug: string\n): Promise<void> {\n  const project = await getProject(registryBackend, projectSlug);\n  if (!project) {\n    console.error(err(`Project not found: ${projectSlug}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const session = await resolveSession(registryBackend, project, numberOrLatest);\n  const notesDir = getNotesDir(project);\n\n  if (!existsSync(notesDir)) {\n    console.error(err(`Notes directory not found: ${notesDir}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const titleSlug = toTitleCase(newSlug);\n  const newFilename = formatFilename(session.number, session.date, titleSlug);\n  const oldPath = join(notesDir, session.filename);\n  const newPath = join(notesDir, newFilename);\n\n  if (existsSync(oldPath)) {\n    if (oldPath !== newPath) {\n      try {\n        renameSync(oldPath, newPath);\n      } catch (e) {\n        console.error(err(`Failed to rename file: ${e}`));\n        process.exitCode = 1;\n        return;\n      }\n    }\n  } else {\n    console.log(\n      warn(`  Note: file not found at expected path: ${session.filename}`)\n    );\n    console.log(warn(`  Skipping disk rename. Database will still be updated.`));\n  }\n\n  if (existsSync(newPath)) {\n    try {\n      const content = readFileSync(newPath, \"utf8\");\n      const lines = content.split(\"\\n\");\n      let h1Updated = false;\n      const updated = lines.map((line) => {\n        if (!h1Updated && line.startsWith(\"# \")) {\n          h1Updated = true;\n          return `# ${titleSlug}`;\n        }\n        return line;\n      });\n      if (!h1Updated) updated.unshift(`# ${titleSlug}`, \"\");\n      writeFileSync(newPath, updated.join(\"\\n\"), \"utf8\");\n    } catch (e) {\n      console.error(err(`Failed to update H1 in file: ${e}`));\n    }\n  }\n\n  const normalizedSlug = newSlug\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, \"-\")\n    .replace(/^-+|-+$/g, \"\");\n\n  await registryBackend.updateSessionMeta(session.id, {\n    slug: normalizedSlug,\n    title: titleSlug,\n    filename: newFilename,\n  });\n\n  console.log();\n  console.log(ok(`  Session #${session.number} renamed.`));\n  console.log(`  ${bold(\"Old:\")}   ${session.filename}`);\n  console.log(`  ${bold(\"New:\")}   ${newFilename}`);\n  console.log(`  ${bold(\"Slug:\")}  ${normalizedSlug}`);\n  console.log(`  ${bold(\"Title:\")} ${titleSlug}`);\n  console.log();\n}\n\n// ---------------------------------------------------------------------------\n// slug\n// ---------------------------------------------------------------------------\n\nexport async function cmdSlug(\n  projectSlug: string,\n  numberOrLatest: string,\n  opts: { apply?: boolean }\n): Promise<void> {\n  const { getRegistryBackend } = await import(\"../../../storage/factory.js\");\n  const registryBackend = await getRegistryBackend();\n\n  const project = await getProject(registryBackend, projectSlug);\n  if (!project) {\n    console.error(err(`Project not found: ${projectSlug}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const session = await resolveSession(registryBackend, project, numberOrLatest);\n  const transcriptPath = findLatestTranscript(project.encoded_dir);\n\n  if (!transcriptPath) {\n    console.log(warn(`  No JSONL transcripts found for project ${projectSlug}`));\n    console.log(\"unnamed-session\");\n    return;\n  }\n\n  const messages = readLastMessages(transcriptPath);\n\n  if (messages.length < 2) {\n    console.log(\n      warn(`  Too few messages found (${messages.length}) in transcript`)\n    );\n    console.log(\"unnamed-session\");\n    return;\n  }\n\n  const generatedSlug = generateSlug(messages);\n  console.log(generatedSlug);\n\n  if (opts.apply) {\n    console.log();\n    console.log(dim(`  Applying slug to session #${session.number}...`));\n    await cmdRenameWith(registryBackend, projectSlug, String(session.number), generatedSlug);\n  }\n}\n\n// ---------------------------------------------------------------------------\n// tag\n// ---------------------------------------------------------------------------\n\nexport async function cmdTag(\n  projectSlug: string,\n  sessionNumber: string,\n  rawTags: string[]\n): Promise<void> {\n  const { getRegistryBackend } = await import(\"../../../storage/factory.js\");\n  const registryBackend = await getRegistryBackend();\n\n  const project = await getProject(registryBackend, projectSlug);\n  if (!project) {\n    console.error(err(`Project not found: ${projectSlug}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const session = await resolveSession(registryBackend, project, sessionNumber);\n\n  if (rawTags.length === 0) {\n    const current = await getSessionTags(registryBackend, session.id);\n    console.log();\n    if (current.length === 0) {\n      console.log(dim(`  Session #${session.number} has no tags.`));\n    } else {\n      console.log(\n        `  ${bold(`Session #${session.number}`)} tags: ${current\n          .map((t) => chalk.cyan(t))\n          .join(\", \")}`\n      );\n    }\n    console.log();\n    return;\n  }\n\n  const tags = rawTags\n    .flatMap((t) => t.split(\",\"))\n    .map((t) => t.trim().toLowerCase())\n    .filter((t) => t.length > 0);\n\n  if (tags.length === 0) {\n    console.log(warn(\"No valid tags provided.\"));\n    return;\n  }\n\n  const added: string[] = [];\n  const skipped: string[] = [];\n\n  for (const tagName of tags) {\n    const tagId = await upsertTag(registryBackend, tagName);\n    const exists = await registryBackend.sessionHasTag(session.id, tagId);\n    if (exists) {\n      skipped.push(tagName);\n    } else {\n      await registryBackend.addSessionTag(session.id, tagId);\n      added.push(tagName);\n    }\n  }\n\n  console.log();\n  if (added.length) {\n    console.log(\n      ok(\n        `  Tagged session #${session.number}: ${added\n          .map((t) => chalk.cyan(t))\n          .join(\", \")}`\n      )\n    );\n  }\n  if (skipped.length) {\n    console.log(dim(`  Already present: ${skipped.join(\", \")}`));\n  }\n\n  const allTags = await getSessionTags(registryBackend, session.id);\n  console.log(\n    `  ${bold(\"All tags:\")} ${allTags.map((t) => chalk.cyan(t)).join(\", \")}`\n  );\n  console.log();\n}\n\n// ---------------------------------------------------------------------------\n// route\n// ---------------------------------------------------------------------------\n\nexport async function cmdRoute(\n  projectSlug: string,\n  sessionNumber: string,\n  targetProjectSlug: string,\n  opts: { type?: string }\n): Promise<void> {\n  const { getRegistryBackend } = await import(\"../../../storage/factory.js\");\n  const registryBackend = await getRegistryBackend();\n\n  const project = await getProject(registryBackend, projectSlug);\n  if (!project) {\n    console.error(err(`Project not found: ${projectSlug}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const session = await resolveSession(registryBackend, project, sessionNumber);\n\n  const targetProject = await getProject(registryBackend, targetProjectSlug);\n\n  if (!targetProject) {\n    console.error(err(`Target project not found: ${targetProjectSlug}`));\n    process.exitCode = 1;\n    return;\n  }\n\n  const validTypes = [\"related\", \"follow-up\", \"reference\"];\n  const linkType = (opts.type ?? \"related\") as \"related\" | \"follow-up\" | \"reference\";\n  if (!validTypes.includes(linkType)) {\n    console.error(\n      err(`Invalid link type \"${linkType}\". Valid: ${validTypes.join(\", \")}`)\n    );\n    process.exitCode = 1;\n    return;\n  }\n\n  if (await registryBackend.linkExists(session.id, targetProject.id)) {\n    console.log(\n      warn(\n        `  Link already exists: session #${session.number} → ${targetProjectSlug}`\n      )\n    );\n    return;\n  }\n\n  await registryBackend.addLink({\n    sessionId: session.id,\n    targetProjectId: targetProject.id,\n    linkType,\n    createdAt: Date.now(),\n  });\n\n  console.log();\n  console.log(\n    ok(\n      `  Linked session #${session.number} (${project.slug}) → ${targetProject.display_name} (${targetProjectSlug})`\n    )\n  );\n  console.log(dim(`  Link type: ${linkType}`));\n  console.log();\n}\n\n// ---------------------------------------------------------------------------\n// active\n// ---------------------------------------------------------------------------\n\nexport async function cmdActive(\n  opts: { minutes?: string; json?: boolean }\n): Promise<void> {\n  const { getRegistryBackend } = await import(\"../../../storage/factory.js\");\n  const registryBackend = await getRegistryBackend();\n\n  const minutes = parseInt(opts.minutes ?? \"60\", 10);\n  const cutoff = Date.now() - minutes * 60 * 1000;\n  const claudeProjectsDir = join(homedir(), \".claude\", \"projects\");\n\n  if (!existsSync(claudeProjectsDir)) {\n    console.log(err(\"Claude projects directory not found.\"));\n    return;\n  }\n\n  interface ActiveSession {\n    slug: string;\n    displayName: string;\n    rootPath: string;\n    encodedDir: string;\n    lastModified: Date;\n    jsonlFile: string;\n  }\n\n  const active: ActiveSession[] = [];\n  const entries = readdirSync(claudeProjectsDir);\n\n  for (const entry of entries) {\n    const projectDir = join(claudeProjectsDir, entry);\n    try {\n      if (!statSync(projectDir).isDirectory()) continue;\n    } catch {\n      continue;\n    }\n\n    let latestJsonl: string | null = null;\n    let latestMtime = 0;\n\n    try {\n      for (const file of readdirSync(projectDir)) {\n        if (!file.endsWith(\".jsonl\")) continue;\n        const filePath = join(projectDir, file);\n        try {\n          const mtime = statSync(filePath).mtimeMs;\n          if (mtime > latestMtime) {\n            latestMtime = mtime;\n            latestJsonl = filePath;\n          }\n        } catch {\n          continue;\n        }\n      }\n    } catch {\n      continue;\n    }\n\n    if (!latestJsonl || latestMtime < cutoff) continue;\n\n    const project = await registryBackend.getProjectByEncodedDir(entry);\n\n    active.push({\n      slug: project?.slug ?? entry,\n      displayName: project?.display_name ?? project?.slug ?? entry,\n      rootPath: project?.root_path ?? \"\",\n      encodedDir: entry,\n      lastModified: new Date(latestMtime),\n      jsonlFile: latestJsonl,\n    });\n  }\n\n  active.sort((a, b) => b.lastModified.getTime() - a.lastModified.getTime());\n\n  const seen = new Set<string>();\n  const deduped = active.filter((a) => {\n    const key = a.slug.replace(/-\\d+$/, \"\");\n    if (seen.has(key)) return false;\n    seen.add(key);\n    return true;\n  });\n\n  if (opts.json) {\n    console.log(\n      JSON.stringify(\n        deduped.map((a) => ({\n          slug: a.slug,\n          display_name: a.displayName,\n          root_path: a.rootPath,\n          last_modified: a.lastModified.toISOString(),\n        })),\n        null,\n        2\n      )\n    );\n    return;\n  }\n\n  if (deduped.length === 0) {\n    console.log(dim(`No active sessions in the last ${minutes} minutes.`));\n    return;\n  }\n\n  console.log(\n    header(`Currently Active Sessions`) +\n      dim(` (modified in last ${minutes}min)`)\n  );\n  console.log();\n\n  const rows = deduped.map((a) => {\n    const time = a.lastModified.toTimeString().slice(0, 5);\n    const dirName = a.rootPath\n      ? a.rootPath.replace(homedir(), \"~\").split(\"/\").pop() ?? a.slug\n      : a.slug;\n    return [chalk.cyan(dirName), dim(a.slug), chalk.green(time)];\n  });\n\n  console.log(renderTable([\"Directory\", \"Project\", \"Last Active\"], rows));\n}\n\n// ---------------------------------------------------------------------------\n// auto-route\n// ---------------------------------------------------------------------------\n\nexport async function cmdAutoRoute(opts: {\n  cwd?: string;\n  context?: string;\n  json?: boolean;\n}): Promise<void> {\n  const { autoRoute, formatAutoRouteJson } = await import(\n    \"../../../session/auto-route.js\"\n  );\n  const { getRegistryBackend, createStorageBackend } = await import(\"../../../storage/factory.js\");\n  const { loadConfig } = await import(\"../../../daemon/config.js\");\n\n  const config = loadConfig();\n  const registryBackend = await getRegistryBackend();\n  const federation = await createStorageBackend(config);\n\n  const targetCwd = opts.cwd ?? process.cwd();\n  const result = await autoRoute(\n    registryBackend,\n    federation,\n    targetCwd,\n    opts.context\n  );\n\n  if (!result) {\n    console.log();\n    console.log(warn(\"  No project match found for: \" + targetCwd));\n    console.log();\n    console.log(\n      dim(\"  Tried: path match, PAI.md marker walk\") +\n        (opts.context ? dim(\", topic detection\") : \"\")\n    );\n    console.log();\n    console.log(dim(\"  Run 'pai project add .' to register this directory.\"));\n    console.log();\n    return;\n  }\n\n  if (opts.json) {\n    console.log(formatAutoRouteJson(result));\n    return;\n  }\n\n  console.log();\n  console.log(header(\"  PAI Auto-Route\"));\n  console.log();\n  console.log(`  ${bold(\"Project:\")}     ${result.display_name}`);\n  console.log(`  ${bold(\"Slug:\")}        ${result.slug}`);\n  console.log(`  ${bold(\"Root path:\")}   ${result.root_path}`);\n  console.log(`  ${bold(\"Method:\")}      ${result.method}`);\n  console.log(\n    `  ${bold(\"Confidence:\")}  ${(result.confidence * 100).toFixed(0)}%`\n  );\n  console.log();\n  console.log(ok(\"  Routed to: \") + bold(result.slug));\n  console.log();\n}\n","/**\n * Sessions: `pai session list|open|new|rename`, plus the daily shortcuts\n * `pai ls`, `pai open`, `pai new`, `pai rename`.\n */\n\nimport { realpathSync } from \"node:fs\";\nimport { basename } from \"node:path\";\nimport { createInterface } from \"node:readline\";\nimport { readWorkersSection, type WorkersConfig } from \"../../workers/config.js\";\nimport { launchableProviderNames, LaunchError } from \"../../workers/launch.js\";\nimport { CliError, OPT, type CommandDef, type RunContext } from \"../define.js\";\nimport { renderTable, makeStyle, colorEnabled, type Style } from \"../help.js\";\nimport { fetchLiveSessions } from \"../lib/aibroker-client.js\";\nimport { dryRunText, buildHarness, execHarness, type Harness } from \"../lib/harness.js\";\nimport { probeResume, transcriptModelFor } from \"../lib/launch.js\";\nimport { providerHealth, readBudget, readBudgetSnapshot, saveBudgetSnapshot, type Health } from \"../lib/health.js\";\nimport type { BudgetReading } from \"../../workers/budget.js\";\nimport { renameSession } from \"../lib/names.js\";\nimport {\n  assertAvailable,\n  chooseProvider,\n  inferOrigin,\n  modelFor,\n  type Choice,\n  type SessionOrigin,\n} from \"../lib/provider-choice.js\";\nimport {\n  fmtAge,\n  resolveSessionByNameOrId,\n  scanSessions,\n  type ScannedSession,\n} from \"../lib/session-scan.js\";\nimport { getProfile } from \"../../workers/session-profile-store.js\";\nimport { prepareDir } from \"../lib/new-dir.js\";\nimport { legacy } from \"../lib/legacy.js\";\nimport { cmdRename } from \"./session/commands.js\";\nimport { getProviderOrNative } from \"../../workers/config.js\";\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\nfunction loadWorkers(): WorkersConfig {\n  try {\n    return readWorkersSection().workers;\n  } catch (e) {\n    throw new CliError(\n      `cannot read the provider configuration: ${e instanceof Error ? e.message : String(e)}`,\n      \"pai config path   (shows which file is read)\"\n    );\n  }\n}\n\n/** Where a session's working directory is: registry-known paths first, as the old resolver did. */\nexport function sessionDir(s: Pick<ScannedSession, \"clcDirectory\" | \"registryRootPath\" | \"decodedPath\">): string | undefined {\n  for (const c of [s.clcDirectory, s.registryRootPath, s.decodedPath]) {\n    if (!c) continue;\n    try {\n      return realpathSync(c);\n    } catch {\n      /* stale path, try the next */\n    }\n  }\n  return undefined;\n}\n\nconst projectOf = (s: ScannedSession) => basename(sessionDir(s) ?? s.decodedPath) || s.decodedPath;\nconst nameOf = (s: ScannedSession) => s.friendlyName ?? s.aiTitle ?? projectOf(s);\n\nexport interface SessionRow {\n  id: string;\n  uuid: string;\n  name: string;\n  project: string;\n  provider: string;\n  model: string;\n  lastActive: string;\n  lastActiveMs: number;\n  status: string;\n  /** Last thing the user typed, one line. */\n  message: string;\n  /** Working directory the session opens in, when it still exists. */\n  dir?: string;\n  /** Can the provider it last ran on be used right now? */\n  health: Health;\n  /** The session already carries this name (set with /Name), so starting it must not send /Name. */\n  named: boolean;\n}\n\n/** Last user text on one line, without the <tag> wrappers Claude Code adds to notifications. */\nexport function oneLine(text: string | undefined): string {\n  return (text ?? \"\").replace(/<[^>]{1,60}>/g, \" \").replace(/\\s+/g, \" \").trim();\n}\n\nfunction originOf(s: ScannedSession, workers: WorkersConfig | null): SessionOrigin | null {\n  const model = transcriptModelFor(s.uuid, s.encodedDir);\n  return inferOrigin(model, workers?.providers ?? {});\n}\n\nexport async function collectRows(opts: { project?: string; all?: boolean; workers?: boolean }): Promise<SessionRow[]> {\n  const { rows } = await collectView({ ...opts, fast: true, waitMs: LISTING_WAIT_MS });\n  return rows;\n}\n\n/** How long a printed listing waits for live status and usage before showing what it has. */\nconst LISTING_WAIT_MS = 400;\n\nexport interface SessionView {\n  rows: SessionRow[];\n  workers: WorkersConfig | null;\n  /**\n   * Fast views only: fetch what the first paint skipped (live sessions, fresh\n   * budget readings) and return the rows rebuilt with it. Resolves to the\n   * same rows when there is nothing to add.\n   */\n  refresh(): Promise<SessionRow[]>;\n}\n\nexport async function collectView(opts: {\n  project?: string;\n  all?: boolean;\n  workers?: boolean;\n  limit?: number;\n  offline?: boolean;\n  /** Build rows from the disk-cached budget and no live lookup; `refresh` fills those in. */\n  fast?: boolean;\n  /** With `fast`: wait this long for the refresh before returning the first-paint rows (listings that print once). */\n  waitMs?: number;\n  /** Beyond the newest `limit`, keep every session the operator named, so a filter finds it whatever its age. */\n  includeNamed?: boolean;\n}): Promise<SessionView> {\n  let workers: WorkersConfig | null = null;\n  try {\n    workers = readWorkersSection().workers;\n  } catch {\n    /* provider column falls back to what the model name says */\n  }\n  const limit = opts.limit ?? (opts.all ? 1000 : 25);\n  const scanLimit = opts.includeNamed ? 100000 : opts.limit ?? (opts.all ? 1000 : opts.workers ? 25 : 150);\n  const deferred = opts.fast && !opts.offline;\n  const [scanned, live0] = await Promise.all([\n    scanSessions({ limit: scanLimit, filter: opts.all ? \"all\" : \"named\", workers: opts.workers }),\n    opts.offline || deferred ? Promise.resolve([]) : fetchLiveSessions().catch(() => []),\n  ]);\n  const needle = opts.project?.toLowerCase();\n  const picked = scanned\n    .filter((s) => !needle || projectOf(s).toLowerCase().includes(needle) || s.decodedPath.toLowerCase().includes(needle))\n    .sort((a, b) => b.mtime - a.mtime)\n    .filter((s, i) => i < limit || (opts.includeNamed && !!s.persistentName));\n\n  const build = (live: Awaited<ReturnType<typeof fetchLiveSessions>>, budget: Record<string, BudgetReading | undefined>): SessionRow[] => {\n    const liveIds = new Set(live.filter((l) => l.kind === \"claude\").map((l) => l.sessionId));\n    return picked.map((s) => {\n      const origin = originOf(s, workers);\n      return {\n        id: s.shortId,\n        uuid: s.uuid,\n        name: nameOf(s),\n        project: projectOf(s),\n        provider: origin?.provider ?? \"—\",\n        model: origin?.model ?? \"—\",\n        lastActive: `${fmtAge(s.mtime)}${fmtAge(s.mtime) === \"now\" ? \"\" : \" ago\"}`,\n        lastActiveMs: s.mtime,\n        status: liveIds.has(s.uuid) ? \"live\" : s.sessionStatus,\n        message: oneLine(s.lastUserPrompt),\n        dir: sessionDir(s),\n        named: !!s.persistentName && s.persistentName === nameOf(s),\n        health: origin && workers ? providerHealth(origin.provider, workers, budget) : ({ state: \"ok\", reason: \"ok\" } as Health),\n      };\n    });\n  };\n\n  const budget0 = deferred ? readBudgetSnapshot() : workers && !opts.offline ? await readBudget(workers) : {};\n  const rows = build(live0, budget0);\n  const refresh = async (): Promise<SessionRow[]> => {\n    if (!deferred) return rows;\n    const [live, budget] = await Promise.all([\n      fetchLiveSessions().catch(() => []),\n      workers ? readBudget(workers) : Promise.resolve({}),\n    ]);\n    if (Object.keys(budget).length) saveBudgetSnapshot(budget);\n    return build(live, Object.keys(budget).length ? budget : budget0);\n  };\n  if (deferred && opts.waitMs) {\n    const settled = await Promise.race([\n      refresh().catch(() => null),\n      new Promise<null>((res) => setTimeout(() => res(null), opts.waitMs).unref()),\n    ]);\n    if (settled) return { rows: settled, workers, refresh: async () => settled };\n  }\n  return { rows, workers, refresh };\n}\n\nconst statusColor = (st: Style, s: string) =>\n  s === \"live\" || s === \"resumable\" ? st.green(s) : s === \"orphan\" ? st.dim(s) : st.yellow(s);\n\nexport function rowsTable(rows: SessionRow[], st: Style, numbered = false): string {\n  const head = [...(numbered ? [\"#\"] : []), \"ID\", \"Name\", \"Project\", \"Provider\", \"Model\", \"Last active\", \"Status\"];\n  return renderTable(\n    head,\n    rows.map((r, i) => [\n      ...(numbered ? [st.dim(String(i + 1))] : []),\n      st.cyan(r.id),\n      r.name.length > 34 ? r.name.slice(0, 33) + \"…\" : r.name,\n      r.project.length > 24 ? r.project.slice(0, 23) + \"…\" : r.project,\n      r.provider,\n      r.model,\n      r.lastActive,\n      statusColor(st, r.status),\n    ]),\n    st\n  );\n}\n\nconst out = (s: string) => process.stdout.write(s + \"\\n\");\nconst style = () => makeStyle(colorEnabled());\n\nfunction ask(q: string): Promise<string> {\n  const rl = createInterface({ input: process.stdin, output: process.stdout });\n  return new Promise((res) => rl.question(q, (a) => (rl.close(), res(a))));\n}\n\n// ---------------------------------------------------------------------------\n// ls\n// ---------------------------------------------------------------------------\n\nconst listCommand: CommandDef = {\n  name: \"list\",\n  summary: \"List sessions, newest first\",\n  description:\n    \"Shows your named sessions with the provider and model each last ran on, how long ago it was active, and whether it can be reopened.\\n\" +\n    \"Status: live = running now · resumable = can be reopened · stub / transcript-only = partial history · orphan = unnamed (--all).\",\n  options: [\n    { ...OPT.project },\n    { name: \"all\", type: \"boolean\", default: false, summary: \"Include unnamed sessions and show more than the newest 25\" },\n    { name: \"workers\", type: \"boolean\", default: false, summary: \"Also show sessions started by background workers (hidden by default)\" },\n    { ...OPT.json },\n  ],\n  examples: [\"pai ls\", \"pai ls --project api\", \"pai ls --all --json\", \"pai ls --workers\"],\n  seeAlso: [\"pai open\", \"pai rename\", \"pai providers\"],\n  async run(ctx) {\n    const rows = await collectRows({ project: ctx.opts.project as string | undefined, all: ctx.opts.all === true, workers: ctx.opts.workers === true });\n    if (ctx.opts.json) return void out(JSON.stringify(rows, null, 2));\n    const st = style();\n    if (rows.length === 0) {\n      out(\"No sessions found\" + (ctx.opts.project ? ` for project \"${ctx.opts.project}\"` : \"\") + \".\");\n      out(st.dim(\"Start one with: pai new\"));\n      return;\n    }\n    out(rowsTable(rows, st));\n    out(\"\");\n    out(st.dim(`${rows.length} session${rows.length === 1 ? \"\" : \"s\"} · reopen one with: pai open <name or id>`));\n  },\n};\n\n// ---------------------------------------------------------------------------\n// open\n// ---------------------------------------------------------------------------\n\n/** Pure planning half of `open`, exported for tests: what provider, why. */\nexport function planOpen(input: {\n  workers: Pick<WorkersConfig, \"providers\" | \"active\" | \"nativeModels\">;\n  origin: SessionOrigin | null;\n  flagProvider?: string;\n  flagModel?: string;\n  name: string;\n}): Choice {\n  const { workers, origin, flagProvider, flagModel, name } = input;\n  const choice = chooseProvider({ flagProvider, flagModel, origin, active: workers.active });\n  assertAvailable(choice.provider, launchableProviderNames(workers), (alt) => `pai open \"${name}\" --provider ${alt}`);\n  return choice;\n}\n\nconst openCommand: CommandDef = {\n  name: \"open\",\n  summary: \"Reopen a session (on its own provider unless --provider is given)\",\n  description:\n    \"Continues a session with its full history. The provider is chosen in this order, and nothing else is consulted:\\n\" +\n    \"  1. --provider, if you give it (always wins; if it is unavailable the command fails and lists the ones that are)\\n\" +\n    \"  2. the provider the session last ran on\\n\" +\n    \"  3. the active provider (pai providers)\\n\" +\n    \"Without NAME_OR_ID you pick from a numbered list.\",\n  args: [{ name: \"NAME_OR_ID\", summary: \"Session name, or the id from `pai ls` (a prefix is enough)\" }],\n  options: [\n    { ...OPT.provider, summary: \"Open on this provider, whatever the session used before\" },\n    { ...OPT.model },\n    { ...OPT.dryRun },\n  ],\n  examples: [\"pai open\", \"pai open my-session\", \"pai open 3a9f1c2e --provider kimi\", \"pai open my-session --dry-run\"],\n  seeAlso: [\"pai ls\", \"pai new\", \"pai providers\"],\n  async run(ctx: RunContext) {\n    const st = style();\n    const workers = loadWorkers();\n    const sessions = await scanSessions({ limit: 500, filter: \"named\" });\n    let query = ctx.args.NAME_OR_ID as string | undefined;\n    if (!query) {\n      if (!process.stdin.isTTY || !process.stdout.isTTY) {\n        throw new CliError(\"no session given and no terminal to pick from\", \"pai ls   then   pai open <name or id>\");\n      }\n      const rows = (await collectRows({})).slice(0, 15);\n      if (rows.length === 0) throw new CliError(\"there are no sessions to open\", \"pai new\");\n      out(rowsTable(rows, st, true));\n      const a = (await ask(\"\\nOpen which? number, name or id: \")).trim();\n      if (!a) throw new CliError(\"nothing picked\", \"pai open <name or id>\");\n      query = /^\\d+$/.test(a) ? rows[Number(a) - 1]?.uuid : a;\n      if (!query) throw new CliError(`\"${a}\" is not a number from the list`, \"pai ls\");\n    }\n\n    let session: ScannedSession;\n    let name: string | undefined;\n    try {\n      ({ session, friendlyName: name } = resolveSessionByNameOrId(sessions, query));\n    } catch (e) {\n      throw new CliError(String(e instanceof Error ? e.message : e).split(\"\\n\\n\")[0], \"pai ls   (shows names and ids)\");\n    }\n    name = name ?? nameOf(session);\n    const cwd = sessionDir(session);\n    if (!cwd) {\n      throw new CliError(\n        `the folder of session \"${name}\" no longer exists (${session.decodedPath})`,\n        `cd <an existing folder> && pai new --name \"${name}\"`\n      );\n    }\n\n    const origin = originOf(session, workers);\n    const choice = planOpen({\n      workers,\n      origin,\n      flagProvider: ctx.opts.provider as string | undefined,\n      flagModel: ctx.opts.model as string | undefined,\n      name,\n    });\n    if (!ctx.opts.provider && !ctx.opts.model) applyProfileChat(choice, name, workers);\n    const provider = getProviderOrNative(workers, choice.provider)!;\n    const model = ctx.opts.model ? (ctx.opts.model as string) : chatModel(provider, choice.model);\n\n    const probe = probeResume(session.uuid, cwd);\n    if (!probe.ok) {\n      throw new CliError(\n        `session \"${name}\" has no history that can be continued (${probe.reason ?? \"unknown reason\"})`,\n        `cd ${JSON.stringify(cwd)} && pai new --name ${JSON.stringify(name)} --provider ${choice.provider}`\n      );\n    }\n\n    let harness: Harness;\n    try {\n      harness = await buildHarness(workers, { provider: choice.provider, model, cwd, resume: session.uuid, name });\n    } catch (e) {\n      if (e instanceof LaunchError || (e as Error).name === \"WorkersConfigError\") {\n        throw new CliError(\n          (e as Error).message,\n          `pai open \"${name}\" --provider ${launchableProviderNames(workers).find((n) => n !== choice.provider) ?? \"anthropic\"}`\n        );\n      }\n      throw e;\n    }\n\n    out(`Opening \"${name}\" on ${st.bold(harness.provider)} (${harness.model})`);\n    if (origin && origin.provider !== harness.provider) {\n      out(\n        st.yellow(\n          `Note: this session last ran on ${origin.provider} (${origin.model}). It continues with its history on ${harness.provider}; ` +\n            `if ${harness.provider} rejects that history, start fresh: cd ${JSON.stringify(cwd)} && pai new --name ${JSON.stringify(name)} --provider ${harness.provider}`\n        )\n      );\n    }\n    if (ctx.dryRun) return void out(dryRunText(harness));\n    return execHarness(harness, workers);\n  },\n};\n\n/** The session's profile chat model replaces the default choice when no flag named one (and its provider is configured). */\nexport function applyProfileChat(choice: { provider: string; model?: string }, name: string, workers: WorkersConfig): void {\n  const chat = getProfile(name)?.chat;\n  if (!chat || !getProviderOrNative(workers, chat.provider)) return;\n  choice.provider = chat.provider;\n  choice.model = chat.model;\n}\n\n/** A profile's model alias (\"opus\") passes through on the native login; otherwise the provider's own table decides. */\nfunction chatModel(provider: Parameters<typeof modelFor>[0] & { native?: boolean }, wanted: string | undefined): string | undefined {\n  return provider.native && wanted === \"opus\" ? \"opus\" : modelFor(provider, wanted);\n}\n\n// ---------------------------------------------------------------------------\n// new\n// ---------------------------------------------------------------------------\n\n/** Start a session in DIR on the active provider (no --with): the old `pai new`, now for any folder. */\nasync function startNewIn(o: { dir?: string; name?: string; provider?: string; model?: string; dryRun: boolean }): Promise<number> {\n  const st = style();\n  const workers = loadWorkers();\n  const cwd = await prepareDir(o.dir, { dryRun: o.dryRun, out });\n  const name = o.name ?? (basename(cwd) || \"session\");\n  const choice = chooseProvider({ flagProvider: o.provider, flagModel: o.model, origin: null, active: workers.active });\n  if (!o.provider && !o.model) applyProfileChat(choice, name, workers);\n  assertAvailable(choice.provider, launchableProviderNames(workers), (alt) => `pai new --provider ${alt}`);\n  let harness: Harness;\n  try {\n    harness = await buildHarness(workers, { provider: choice.provider, model: choice.model, cwd, name });\n  } catch (e) {\n    if (e instanceof LaunchError || (e as Error).name === \"WorkersConfigError\") {\n      throw new CliError((e as Error).message, \"pai providers   (lists what is available)\");\n    }\n    throw e;\n  }\n  out(`Starting \"${name}\" on ${st.bold(harness.provider)} (${harness.model})`);\n  if (o.dryRun) {\n    out(dryRunText(harness));\n    return 0;\n  }\n  return execHarness(harness, workers);\n}\n\nexport const runNewDefault = (o: { dir?: string; dryRun: boolean }) => startNewIn(o);\n\nconst newCommand: CommandDef = {\n  name: \"new\",\n  summary: \"Start a new session in a new or existing folder\",\n  description:\n    \"Creates DIR when it is missing (default: the current folder), registers it as a project and starts Claude Code there. \" +\n    \"With --with the setup decides who orchestrates and which provider the workers run on, and nothing is asked. \" +\n    \"Without it the session runs on the active provider (see `pai providers`; --provider overrides). \" +\n    \"`pai ./dir` or `pai ~/dir` does the same as `pai new`.\",\n  args: [{ name: \"DIR\", summary: \"Folder to start in; created if missing (default: the current folder)\" }],\n  options: [\n    { name: \"with\", type: \"string\", value: \"SETUP\", summary: 'Start with this setup, no questions (see: pai setups), e.g. \"anthropic + flashnext-iq3 workers\"' },\n    { ...OPT.provider, summary: \"Provider to start on (default: the active provider)\" },\n    { ...OPT.model },\n    { name: \"name\", type: \"string\", value: \"NAME\", summary: \"Session name (default: the folder name)\" },\n    { ...OPT.dryRun },\n  ],\n  examples: [\n    'pai new ~/code/app --with \"anthropic + flashnext-iq3 workers\"',\n    'pai new ~/code/app --with \"anthropic only\" --name app',\n    \"pai new\",\n    \"pai new --provider glm\",\n    \"pai new ~/code/spike --provider kimi --model k3 --dry-run\",\n  ],\n  seeAlso: [\"pai setups\", \"pai open\", \"pai providers\"],\n  async run(ctx) {\n    const dir = ctx.args.DIR as string | undefined;\n    const name = ctx.opts.name as string | undefined;\n    const withSetup = ctx.opts.with as string | undefined;\n    if (withSetup) {\n      const { runNewWith } = await import(\"./root.js\");\n      return runNewWith({ dir, with: withSetup, name, dryRun: ctx.dryRun });\n    }\n    return startNewIn({ dir, name, provider: ctx.opts.provider as string | undefined, model: ctx.opts.model as string | undefined, dryRun: ctx.dryRun });\n  },\n};\n\n// ---------------------------------------------------------------------------\n// rename\n// ---------------------------------------------------------------------------\n\nconst renameCommand: CommandDef = {\n  name: \"rename\",\n  summary: \"Give a session a new name\",\n  description: \"Changes the name `pai ls` shows and `pai open` accepts. The history is untouched.\",\n  args: [\n    { name: \"ID\", required: true, summary: \"Session id from `pai ls` (a prefix is enough) or its current name\" },\n    { name: \"NAME\", required: true, summary: \"The new name\" },\n    { name: \"NEW_SLUG\", summary: \"Only for the old note form `session rename PROJECT NUMBER NEW_SLUG`: renames a session note instead\" },\n  ],\n  options: [],\n  examples: [\"pai rename 3a9f1c2e api-spike\", 'pai rename old-name \"new name\"', \"pai session rename my-project 12 fix-login-bug\"],\n  seeAlso: [\"pai ls\", \"pai open\"],\n  async run(ctx) {\n    if (ctx.args.NEW_SLUG !== undefined) {\n      return legacy(() => cmdRename(ctx.args.ID as string, ctx.args.NAME as string, ctx.args.NEW_SLUG as string));\n    }\n    const sessions = await scanSessions({ limit: 500, filter: \"all\" });\n    let session: ScannedSession;\n    try {\n      ({ session } = resolveSessionByNameOrId(sessions, ctx.args.ID as string));\n    } catch (e) {\n      throw new CliError(String(e instanceof Error ? e.message : e).split(\"\\n\\n\")[0], \"pai ls   (shows names and ids)\");\n    }\n    const name = (ctx.args.NAME as string).trim();\n    if (!name) throw new CliError(\"the new name is empty\", 'pai rename <id> \"<new name>\"');\n    if (ctx.dryRun) return void out(`would rename ${session.shortId} to \"${name}\"`);\n    const { previous } = renameSession(session.uuid, name, sessionDir(session));\n    out(`Renamed ${session.shortId}${previous ? ` \"${previous}\"` : \"\"} → \"${name}\"`);\n  },\n};\n\n// ---------------------------------------------------------------------------\n// Exports: the group and its daily shortcuts\n// ---------------------------------------------------------------------------\n\nexport const sessionCommand: CommandDef = {\n  name: \"session\",\n  summary: \"Work with sessions: list, open, new, rename\",\n  description: \"Everything about sessions lives under `pai session`; the daily verbs also exist as short top-level commands.\",\n  examples: [\"pai session list\", \"pai session open my-session\", \"pai session new --provider glm\"],\n  seeAlso: [\"pai ls\", \"pai open\", \"pai new\"],\n  subcommands: [listCommand, openCommand, newCommand, renameCommand],\n};\n\nexport const lsCommand: CommandDef = { ...listCommand, name: \"ls\", aliasOf: \"session list\", daily: true };\nexport const openTop: CommandDef = { ...openCommand, aliasOf: \"session open\" };\nexport const newTop: CommandDef = { ...newCommand, aliasOf: \"session new\", daily: true };\nexport const renameTop: CommandDef = { ...renameCommand, aliasOf: \"session rename\" };\n"],"mappings":"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"}