{"version":3,"file":"cli.mjs","names":["BUILD_VERSION","parseYaml","stringifyYaml","parsePath","parseYaml","ulid","stringifyYaml","normalizePath","ulid","ulid","addCommand","removeCommand","parseYaml","stringifyYaml","parseYaml","ulid","lines","worktreeExists","remoteBranchExists","homedir","content","parseYaml"],"sources":["../src/cli/lib/version.ts","../src/cli/lib/context.ts","../src/cli/lib/output.ts","../src/lib/paths.ts","../src/lib/tbd-format.ts","../src/file/config.ts","../src/cli/lib/errors.ts","../src/cli/lib/base-command.ts","../src/utils/file-utils.ts","../src/utils/gitignore-utils.ts","../src/utils/time-utils.ts","../src/file/git.ts","../src/cli/commands/init.ts","../src/lib/ids.ts","../src/file/storage.ts","../src/lib/sort.ts","../src/file/id-mapping.ts","../src/lib/priority.ts","../src/lib/project-paths.ts","../src/cli/commands/create.ts","../src/cli/lib/data-context.ts","../src/lib/status.ts","../src/lib/truncate.ts","../src/cli/lib/issue-format.ts","../src/cli/lib/tree-view.ts","../src/lib/spec-matching.ts","../src/cli/commands/list.ts","../src/cli/commands/show.ts","../src/cli/commands/update.ts","../src/cli/commands/close.ts","../src/cli/commands/reopen.ts","../src/cli/commands/ready.ts","../src/cli/commands/blocked.ts","../src/cli/commands/stale.ts","../src/cli/commands/label.ts","../src/cli/commands/dep.ts","../src/lib/sync-summary.ts","../src/cli/commands/sync.ts","../src/cli/commands/search.ts","../src/cli/commands/status.ts","../src/cli/commands/stats.ts","../src/cli/lib/diagnostics.ts","../src/cli/commands/doctor.ts","../src/cli/commands/config.ts","../src/cli/commands/attic.ts","../src/cli/commands/import.ts","../src/file/doc-sync.ts","../src/cli/commands/docs.ts","../src/cli/commands/closing.ts","../src/cli/commands/design.ts","../src/cli/commands/readme.ts","../src/cli/commands/uninstall.ts","../src/utils/markdown-utils.ts","../src/file/doc-cache.ts","../src/cli/commands/prime.ts","../src/cli/commands/skill.ts","../src/cli/lib/doc-prompts.ts","../src/cli/commands/shortcut.ts","../src/cli/lib/doc-command-handler.ts","../src/cli/commands/guidelines.ts","../src/cli/commands/template.ts","../src/cli/lib/prefix-detection.ts","../src/cli/commands/setup.ts","../src/cli/cli.ts"],"sourcesContent":["/**\n * CLI version detection\n *\n * Priority:\n * 1. Build-time injected __TBD_VERSION__ (production builds)\n * 2. TBD_DEV_VERSION env var (dev mode, set by pnpm tbd script)\n * 3. package.json version (fallback)\n *\n * No git dependency at runtime - git version is computed at build time\n * or by the dev script wrapper.\n */\n\nimport { createRequire } from 'node:module';\n\nimport { VERSION as BUILD_VERSION } from '../../index.js';\n\n/**\n * Get the CLI version.\n */\nfunction getVersion(): string {\n  // 1. Build-time injected version (production)\n  if (BUILD_VERSION !== 'development') {\n    return BUILD_VERSION;\n  }\n\n  // 2. Dev mode env var (set by pnpm tbd script)\n  if (process.env.TBD_DEV_VERSION) {\n    return process.env.TBD_DEV_VERSION;\n  }\n\n  // 3. Fallback to package.json version\n  const require = createRequire(import.meta.url);\n  const pkg = require('../../../package.json') as { version: string };\n  return pkg.version;\n}\n\n/**\n * CLI version - use this instead of importing VERSION directly from index.ts\n */\nexport const VERSION = getVersion();\n","/**\n * Command context and global options management.\n *\n * See: research-modern-typescript-cli-patterns.md#9-global-options\n */\n\nimport type { Command } from 'commander';\n\n/**\n * Output format options.\n */\nexport type OutputFormat = 'text' | 'json';\n\n/**\n * Color output options.\n */\nexport type ColorOption = 'auto' | 'always' | 'never';\n\n/**\n * Global command context extracted from Commander options.\n */\nexport interface CommandContext {\n  dryRun: boolean;\n  verbose: boolean;\n  quiet: boolean;\n  json: boolean;\n  color: ColorOption;\n  nonInteractive: boolean;\n  yes: boolean;\n  sync: boolean;\n  /** Debug mode: shows internal IDs alongside public IDs */\n  debug: boolean;\n}\n\n/**\n * Extract command context from a Commander command.\n * Handles inheritance of global options through the command hierarchy.\n */\nexport function getCommandContext(command: Command): CommandContext {\n  const opts = command.optsWithGlobals();\n  const isCI = Boolean(process.env.CI);\n\n  return {\n    dryRun: opts.dryRun ?? false,\n    verbose: opts.verbose ?? false,\n    quiet: opts.quiet ?? false,\n    json: opts.json ?? false,\n    color: (opts.color as ColorOption) ?? 'auto',\n    nonInteractive: opts.nonInteractive ?? (!process.stdin.isTTY || isCI),\n    yes: opts.yes ?? false,\n    sync: opts.sync !== false, // --no-sync sets this to false\n    debug: opts.debug ?? false,\n  };\n}\n\n/**\n * Determine if output should be colorized based on options and environment.\n */\nexport function shouldColorize(colorOption: ColorOption): boolean {\n  // NO_COLOR takes precedence (unless --color=always explicitly set)\n  if (process.env.NO_COLOR && colorOption !== 'always') {\n    return false;\n  }\n  if (colorOption === 'always') {\n    return true;\n  }\n  if (colorOption === 'never') {\n    return false;\n  }\n  return process.stdout.isTTY ?? false;\n}\n\n/**\n * Check if running in interactive mode.\n */\nexport function isInteractive(ctx: CommandContext): boolean {\n  return !ctx.nonInteractive && process.stdin.isTTY === true && !process.env.CI;\n}\n","/**\n * OutputManager for dual-mode output (text + JSON).\n *\n * See: research-modern-typescript-cli-patterns.md#4-dual-output-mode-text--json\n */\n\nimport pc from 'picocolors';\nimport type { Command } from 'commander';\nimport { marked } from 'marked';\nimport { markedTerminal } from 'marked-terminal';\n\nimport type { CommandContext, ColorOption } from './context.js';\nimport { shouldColorize } from './context.js';\n\n/**\n * Standard icons for CLI output. Use these constants instead of hardcoded characters.\n *\n * Message icons (prefix messages with these):\n * - SUCCESS_ICON: ✓ for completed operations\n * - ERROR_ICON: ✗ for failures\n * - WARN_ICON: ⚠ for warnings\n * - NOTICE_ICON: • for notices/bullets\n *\n * Status icons (show issue status):\n * - OPEN_ICON: ○ for open issues\n * - IN_PROGRESS_ICON: ◐ for in-progress issues\n * - BLOCKED_ICON: ● for blocked issues\n * - CLOSED_ICON: ✓ for closed issues (same as SUCCESS_ICON)\n */\n\n/**\n * Format a section heading - ALL CAPS for consistent CLI output.\n * Per arch-cli-interface-design-system.md, section headings should be\n * ALL CAPS, bold, followed by blank line before content.\n *\n * @param text - The heading text to format\n * @returns Uppercase heading string\n */\nexport function formatHeading(text: string): string {\n  return text.toUpperCase();\n}\n\nexport const ICONS = {\n  // Message icons\n  SUCCESS: '✓', // U+2713\n  ERROR: '✗', // U+2717\n  WARN: '⚠', // U+26A0\n  NOTICE: '•', // U+2022\n\n  // Status icons\n  OPEN: '○', // U+25CB\n  IN_PROGRESS: '◐', // U+25D0\n  BLOCKED: '●', // U+25CF\n  CLOSED: '✓', // U+2713 (same as SUCCESS)\n  DEFERRED: '○', // U+25CB (same as OPEN)\n} as const;\n\n/**\n * Pre-parse argv to determine color setting before Commander parses options.\n * This is needed because help output happens before full option parsing.\n */\nexport function getColorOptionFromArgv(): ColorOption {\n  const colorArg = process.argv.find((arg) => arg.startsWith('--color='));\n  if (colorArg) {\n    const value = colorArg.split('=')[1];\n    if (value === 'always' || value === 'never' || value === 'auto') {\n      return value;\n    }\n  }\n  // Check for --color followed by value\n  const colorIdx = process.argv.indexOf('--color');\n  if (colorIdx !== -1 && process.argv[colorIdx + 1]) {\n    const value = process.argv[colorIdx + 1];\n    if (value === 'always' || value === 'never' || value === 'auto') {\n      return value;\n    }\n  }\n  return 'auto';\n}\n\n/**\n * Maximum width for help text and formatted output. We cap at 88 characters\n * for readability, but use narrower if the terminal is smaller.\n */\nexport const MAX_HELP_WIDTH = 88;\n\n/**\n * Get terminal width capped at MAX_HELP_WIDTH.\n * Use this for all formatted CLI output to ensure consistent width handling.\n */\nexport function getTerminalWidth(): number {\n  return Math.min(MAX_HELP_WIDTH, process.stdout.columns ?? 80);\n}\n\n/**\n * Create colored help configuration for Commander.js.\n * Uses Commander's built-in configureHelp() style functions (requires v14+).\n *\n * @param colorOption - Color option to determine if colors should be enabled\n * @returns Help configuration object for program.configureHelp()\n */\nexport function createColoredHelpConfig(colorOption: ColorOption = 'auto') {\n  const colors = pc.createColors(shouldColorize(colorOption));\n\n  return {\n    helpWidth: getTerminalWidth(),\n    styleTitle: (str: string) => colors.bold(colors.cyan(str)),\n    styleCommandText: (str: string) => colors.green(str),\n    styleOptionText: (str: string) => colors.yellow(str),\n    showGlobalOptions: true,\n  };\n}\n\n/**\n * Create the help epilog text with color.\n * Includes \"Getting Started\" section per spec.\n *\n * @param colorOption - Color option to determine if colors should be enabled\n * @returns Colored epilog string\n */\nexport function createHelpEpilog(colorOption: ColorOption = 'auto'): string {\n  const colors = pc.createColors(shouldColorize(colorOption));\n  const lines = [\n    colors.bold('Getting Started:'),\n    `  ${colors.green('npm install -g tbd-git@latest && tbd setup --auto --prefix=<name>')}`,\n    '',\n    '  This initializes tbd and configures your coding agents automatically.',\n    `  For interactive setup: ${colors.dim('tbd setup --interactive')}`,\n    `  For manual control: ${colors.dim('tbd init --help')}`,\n    '',\n    colors.bold('Orientation:'),\n    `  For workflow guidance, run: ${colors.green('tbd prime')}`,\n    '',\n    colors.blue('For more on tbd, see: https://github.com/jlevy/tbd'),\n  ];\n  return lines.join('\\n');\n}\n\n/**\n * Configure Commander.js with colored help text.\n * Call this on the program before adding commands.\n */\nexport function configureColoredHelp(program: Command): Command {\n  const colorOption = getColorOptionFromArgv();\n  return program.configureHelp(createColoredHelpConfig(colorOption));\n}\n\n/**\n * Color utilities with conditional colorization.\n *\n * Uses picocolors' createColors() for manual color support control,\n * which is the recommended approach per picocolors documentation.\n * This allows --color=always to work even when stdout is not a TTY.\n */\nexport function createColors(colorOption: ColorOption) {\n  const enabled = shouldColorize(colorOption);\n\n  // Use picocolors' createColors() for proper manual control\n  // This overrides picocolors' automatic TTY detection\n  const colors = pc.createColors(enabled);\n\n  return {\n    // Status colors\n    success: colors.green,\n    error: colors.red,\n    warn: colors.yellow,\n    info: colors.blue,\n\n    // Text formatting\n    bold: colors.bold,\n    dim: colors.dim,\n    italic: colors.italic,\n    underline: colors.underline,\n\n    // Semantic colors\n    id: colors.cyan,\n    label: colors.magenta,\n    path: colors.blue,\n  };\n}\n\n/**\n * Render Markdown to colorized terminal output.\n *\n * Uses marked-terminal for colorized output when colors are enabled,\n * falls back to plain Markdown when colors are disabled or piped.\n * Respects the --color option and TTY detection.\n *\n * @param content - Markdown string to render\n * @param colorOption - Color option to determine if colors should be enabled\n * @returns Rendered string (colorized or plain)\n */\nexport function renderMarkdown(content: string, colorOption: ColorOption = 'auto'): string {\n  const useColors = shouldColorize(colorOption);\n\n  if (!useColors) {\n    // Return plain markdown when colors are disabled\n    return content;\n  }\n\n  // Configure marked with terminal renderer for this parse\n  // Note: @types/marked-terminal is outdated; markedTerminal returns MarkedExtension in v7+\n  // but types still claim it returns TerminalRenderer. Cast to work around this.\n  marked.use(\n    markedTerminal({\n      width: getTerminalWidth(),\n      reflowText: true,\n    }) as unknown as Parameters<typeof marked.use>[0],\n  );\n\n  // marked.parse returns string with sync renderer\n  return marked.parse(content) as string;\n}\n\n/**\n * Spinner interface for progress indication.\n */\nexport interface Spinner {\n  message(msg: string): void;\n  stop(msg?: string): void;\n}\n\n/**\n * No-op spinner for non-TTY or quiet mode.\n */\nconst noopSpinner: Spinner = {\n  message: () => {},\n  stop: () => {},\n};\n\n/**\n * OutputManager handles all CLI output with format switching.\n */\nexport class OutputManager {\n  private ctx: CommandContext;\n  private colors: ReturnType<typeof createColors>;\n\n  constructor(ctx: CommandContext) {\n    this.ctx = ctx;\n    this.colors = createColors(ctx.color);\n  }\n\n  /**\n   * Output structured data - always goes to stdout.\n   * In JSON mode, outputs JSON. In text mode, calls the formatter.\n   */\n  data<T>(data: T, textFormatter?: (data: T) => void): void {\n    if (this.ctx.json) {\n      console.log(JSON.stringify(data, null, 2));\n    } else if (textFormatter) {\n      textFormatter(data);\n    }\n  }\n\n  /**\n   * Output success message - text mode only, stdout.\n   * Suppressed by --quiet and --json.\n   */\n  success(message: string): void {\n    if (!this.ctx.json && !this.ctx.quiet) {\n      console.log(this.colors.success(`${ICONS.SUCCESS} ${message}`));\n    }\n  }\n\n  /**\n   * Output notice message - noteworthy events during normal operation.\n   * Blue bullet, shown at default level. Suppressed by --quiet and --json.\n   */\n  notice(message: string): void {\n    if (!this.ctx.json && !this.ctx.quiet) {\n      console.log(this.colors.info(`${ICONS.NOTICE} ${message}`));\n    }\n  }\n\n  /**\n   * Output info message - operational progress.\n   * Requires --verbose or --debug. Suppressed by --json.\n   */\n  info(message: string): void {\n    if (!this.ctx.json && (this.ctx.verbose || this.ctx.debug)) {\n      console.error(this.colors.dim(message));\n    }\n  }\n\n  /**\n   * Output warning - issues that didn't stop operation.\n   * Yellow warning icon, stderr. Suppressed by --quiet.\n   */\n  warn(message: string): void {\n    if (this.ctx.json) {\n      console.error(JSON.stringify({ warning: message }));\n    } else if (!this.ctx.quiet) {\n      console.error(this.colors.warn(`${ICONS.WARN} ${message}`));\n    }\n  }\n\n  /**\n   * Output error - failures that stop operation.\n   * Red X icon, always shown (even in --quiet), stderr.\n   */\n  error(message: string, err?: Error): void {\n    if (this.ctx.json) {\n      console.error(JSON.stringify({ error: message, details: err?.message }));\n    } else {\n      console.error(this.colors.error(`${ICONS.ERROR} ${message}`));\n      if (this.ctx.verbose && err?.stack) {\n        console.error(this.colors.dim(err.stack));\n      }\n    }\n  }\n\n  /**\n   * Output command being executed - shows external commands.\n   * Requires --verbose or --debug. Suppressed by --json.\n   */\n  command(cmd: string, args?: string[]): void {\n    if (!this.ctx.json && (this.ctx.verbose || this.ctx.debug)) {\n      const fullCmd = args ? `${cmd} ${args.join(' ')}` : cmd;\n      console.error(this.colors.dim(`> ${fullCmd}`));\n    }\n  }\n\n  /**\n   * Output debug message - internal state for troubleshooting.\n   * Requires --debug only (not --verbose). Suppressed by --json.\n   */\n  debug(message: string): void {\n    if (this.ctx.debug && !this.ctx.json) {\n      console.error(this.colors.dim(`[debug] ${message}`));\n    }\n  }\n\n  /**\n   * Output dry-run indication.\n   */\n  dryRun(message: string, details?: object): void {\n    if (this.ctx.json) {\n      console.log(JSON.stringify({ dryRun: true, action: message, ...details }));\n    } else {\n      console.log(this.colors.warn(`[DRY-RUN] ${message}`));\n      if (details && (this.ctx.verbose || this.ctx.debug)) {\n        console.log(this.colors.dim(JSON.stringify(details, null, 2)));\n      }\n    }\n  }\n\n  /**\n   * Output a table with headers and rows.\n   * Headers are dimmed. Rows are formatted with consistent column widths.\n   * Suppressed in JSON mode.\n   *\n   * @param headers - Array of column headers with widths\n   * @param rows - Array of row data arrays (each row = array of strings)\n   */\n  table(\n    headers: { label: string; width: number }[],\n    rows: (string | { value: string; color?: (s: string) => string })[][],\n  ): void {\n    if (this.ctx.json) return;\n\n    // Output header row\n    const headerLine = headers.map((h) => h.label.padEnd(h.width)).join('');\n    console.log(this.colors.dim(headerLine));\n\n    // Output data rows\n    for (const row of rows) {\n      const cells = row.map((cell, i) => {\n        const width = headers[i]?.width ?? 0;\n        if (typeof cell === 'string') {\n          return cell.padEnd(width);\n        }\n        // Cell with custom color\n        const paddedValue = cell.value.padEnd(width);\n        return cell.color ? cell.color(paddedValue) : paddedValue;\n      });\n      console.log(cells.join(''));\n    }\n  }\n\n  /**\n   * Output a bulleted list.\n   * Uses NOTICE icon (•) as bullet. Suppressed in JSON mode.\n   *\n   * @param items - Array of items to list\n   * @param options - Optional indent level (default 0)\n   */\n  list(items: string[], options?: { indent?: number }): void {\n    if (this.ctx.json) return;\n\n    const indent = '  '.repeat(options?.indent ?? 0);\n    for (const item of items) {\n      console.log(`${indent}${ICONS.NOTICE} ${item}`);\n    }\n  }\n\n  /**\n   * Output a count summary in standard format.\n   * Format: \"N item(s)\" with dim color. Suppressed in JSON mode.\n   *\n   * @param count - The count to display\n   * @param singular - Singular form of the item (e.g., \"issue\")\n   * @param plural - Optional plural form (defaults to singular + \"s\")\n   */\n  count(count: number, singular: string, plural?: string): void {\n    if (this.ctx.json) return;\n\n    const pluralForm = plural ?? `${singular}s`;\n    const label = count === 1 ? singular : pluralForm;\n    console.log(this.colors.dim(`${count} ${label}`));\n  }\n\n  /**\n   * Create a spinner for progress indication.\n   * Returns no-op in JSON/quiet mode or non-TTY.\n   */\n  spinner(message: string): Spinner {\n    // Never show spinners in JSON mode, quiet mode, or non-TTY\n    if (this.ctx.json || this.ctx.quiet || !process.stderr.isTTY) {\n      return noopSpinner;\n    }\n\n    // Simple inline spinner (no external dependency for now)\n    let frame = 0;\n    const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];\n    let currentMessage = message;\n\n    const spinnerColor = this.colors.info;\n    const write = () => {\n      process.stderr.write(`\\r${spinnerColor(frames[frame] ?? '⠋')} ${currentMessage}`);\n      frame = (frame + 1) % frames.length;\n    };\n\n    write();\n    const interval = setInterval(write, 80);\n\n    return {\n      message: (msg: string) => {\n        currentMessage = msg;\n      },\n      stop: (msg?: string) => {\n        clearInterval(interval);\n        process.stderr.write('\\r' + ' '.repeat(currentMessage.length + 3) + '\\r');\n        if (msg) {\n          console.error(msg);\n        }\n      },\n    };\n  }\n\n  /**\n   * Get colors instance for direct use.\n   */\n  getColors() {\n    return this.colors;\n  }\n\n  /**\n   * Check if quiet mode is enabled.\n   */\n  isQuiet(): boolean {\n    return this.ctx.quiet;\n  }\n}\n","/**\n * Centralized path constants for tbd.\n *\n * Directory structure (per spec):\n *\n * On main/dev branches:\n *   .tbd/\n *     config.yml              - Project configuration (tracked)\n *     state.yml               - Local state (gitignored)\n *     .gitignore              - Ignores docs/, data-sync-worktree/, data-sync/\n *     docs/                   - Installed documentation (gitignored, regenerated on setup)\n *     data-sync-worktree/     - Hidden worktree checkout of tbd-sync branch\n *       .tbd/\n *         data-sync/\n *           issues/\n *           mappings/\n *           attic/\n *           meta.yml\n *\n * On tbd-sync branch:\n *   .tbd/\n *     data-sync/\n *       issues/\n *       mappings/\n *       attic/\n *       meta.yml\n */\n\nimport { join } from 'node:path';\n\n/** The tbd configuration directory on main branch */\nexport const TBD_DIR = '.tbd';\n\n/** The config file path */\nexport const CONFIG_FILE = join(TBD_DIR, 'config.yml');\n\n/** The local state file (gitignored) */\nexport const STATE_FILE = join(TBD_DIR, 'state.yml');\n\n/** The worktree directory name */\nexport const WORKTREE_DIR_NAME = 'data-sync-worktree';\n\n/** The worktree path (gitignored) */\nexport const WORKTREE_DIR = join(TBD_DIR, WORKTREE_DIR_NAME);\n\n/** The data directory name on the sync branch */\nexport const DATA_SYNC_DIR_NAME = 'data-sync';\n\n/**\n * The base directory for synced data.\n *\n * NOTE: This is currently pointing directly to .tbd/data-sync/ which is WRONG\n * per the spec. The correct path should be via the worktree:\n *   .tbd/data-sync-worktree/.tbd/data-sync/\n *\n * TODO(tbd-208): Update this to use the worktree path once worktree\n * management is implemented.\n */\nexport const DATA_SYNC_DIR = join(TBD_DIR, DATA_SYNC_DIR_NAME);\n\n/**\n * The correct path for synced data via worktree (per spec).\n * Use this once worktree management is implemented.\n */\nexport const DATA_SYNC_DIR_VIA_WORKTREE = join(WORKTREE_DIR, TBD_DIR, DATA_SYNC_DIR_NAME);\n\n/** Issues directory */\nexport const ISSUES_DIR = join(DATA_SYNC_DIR, 'issues');\n\n/** Mappings directory */\nexport const MAPPINGS_DIR = join(DATA_SYNC_DIR, 'mappings');\n\n/** Attic directory for conflict resolution */\nexport const ATTIC_DIR = join(DATA_SYNC_DIR, 'attic');\n\n/** Meta file for schema version */\nexport const META_FILE = join(DATA_SYNC_DIR, 'meta.yml');\n\n/** The sync branch name */\nexport const SYNC_BRANCH = 'tbd-sync';\n\n// =============================================================================\n// Documentation/Shortcuts Paths\n// =============================================================================\n\n/** Docs directory name within .tbd/ */\nexport const DOCS_DIR = 'docs';\n\n/** Shortcuts directory name within docs/ */\nexport const SHORTCUTS_DIR = 'shortcuts';\n\n/** System shortcuts directory name (core docs like skill.md) */\nexport const SYSTEM_DIR = 'system';\n\n/** Standard shortcuts directory name (workflow shortcuts) */\nexport const STANDARD_DIR = 'standard';\n\n/** Guidelines directory name (coding rules and best practices) */\nexport const GUIDELINES_DIR = 'guidelines';\n\n/** Templates directory name (document templates) */\nexport const TEMPLATES_DIR = 'templates';\n\n/** Full path to docs directory: .tbd/docs/ */\nexport const TBD_DOCS_DIR = join(TBD_DIR, DOCS_DIR);\n\n/** Full path to shortcuts directory: .tbd/docs/shortcuts/ */\nexport const TBD_SHORTCUTS_DIR = join(TBD_DOCS_DIR, SHORTCUTS_DIR);\n\n/** Full path to system shortcuts: .tbd/docs/shortcuts/system/ */\nexport const TBD_SHORTCUTS_SYSTEM = join(TBD_SHORTCUTS_DIR, SYSTEM_DIR);\n\n/** Full path to standard shortcuts: .tbd/docs/shortcuts/standard/ */\nexport const TBD_SHORTCUTS_STANDARD = join(TBD_SHORTCUTS_DIR, STANDARD_DIR);\n\n/** Full path to guidelines: .tbd/docs/guidelines/ (top-level, not under shortcuts) */\nexport const TBD_GUIDELINES_DIR = join(TBD_DOCS_DIR, GUIDELINES_DIR);\n\n/** Full path to templates: .tbd/docs/templates/ (top-level, not under shortcuts) */\nexport const TBD_TEMPLATES_DIR = join(TBD_DOCS_DIR, TEMPLATES_DIR);\n\n/** @deprecated Use TBD_GUIDELINES_DIR instead */\nexport const TBD_SHORTCUTS_GUIDELINES = TBD_GUIDELINES_DIR;\n\n/** @deprecated Use TBD_TEMPLATES_DIR instead */\nexport const TBD_SHORTCUTS_TEMPLATES = TBD_TEMPLATES_DIR;\n\n/** Built-in docs source paths (relative to package docs/) */\nexport const BUILTIN_SHORTCUTS_SYSTEM = join(SHORTCUTS_DIR, SYSTEM_DIR);\nexport const BUILTIN_SHORTCUTS_STANDARD = join(SHORTCUTS_DIR, STANDARD_DIR);\n\n/** Built-in guidelines source path (relative to package docs/) */\nexport const BUILTIN_GUIDELINES_DIR = GUIDELINES_DIR;\n\n/** Built-in templates source path (relative to package docs/) */\nexport const BUILTIN_TEMPLATES_DIR = TEMPLATES_DIR;\n\n/** Install directory name (header files for tool-specific installation) */\nexport const INSTALL_DIR = 'install';\n\n/** Built-in install source path (relative to package docs/) */\nexport const BUILTIN_INSTALL_DIR = INSTALL_DIR;\n\n/**\n * Default shortcut lookup paths (searched in order, relative to tbd root).\n * Earlier paths take precedence over later paths.\n * Note: Guidelines and templates are now separate top-level directories.\n */\nexport const DEFAULT_SHORTCUT_PATHS = [\n  TBD_SHORTCUTS_SYSTEM, // .tbd/docs/shortcuts/system/\n  TBD_SHORTCUTS_STANDARD, // .tbd/docs/shortcuts/standard/\n];\n\n/**\n * Default guidelines lookup paths (relative to tbd root).\n */\nexport const DEFAULT_GUIDELINES_PATHS = [\n  TBD_GUIDELINES_DIR, // .tbd/docs/guidelines/\n];\n\n/**\n * Default template lookup paths (relative to tbd root).\n */\nexport const DEFAULT_TEMPLATE_PATHS = [\n  TBD_TEMPLATES_DIR, // .tbd/docs/templates/\n];\n\n/**\n * @deprecated Use DEFAULT_SHORTCUT_PATHS instead.\n * Legacy alias that includes all doc types for backward compatibility.\n */\nexport const DEFAULT_DOC_PATHS = [\n  ...DEFAULT_SHORTCUT_PATHS,\n  ...DEFAULT_GUIDELINES_PATHS,\n  ...DEFAULT_TEMPLATE_PATHS,\n];\n\n/**\n * Get the full path to an issue file.\n */\nexport function getIssuePath(issueId: string): string {\n  return join(ISSUES_DIR, `${issueId}.md`);\n}\n\n/**\n * Get the full path to a mapping file.\n */\nexport function getMappingPath(name: string): string {\n  return join(MAPPINGS_DIR, `${name}.yml`);\n}\n\n/**\n * Get the full path to an attic entry.\n */\nexport function getAtticPath(issueId: string, filename: string): string {\n  return join(ATTIC_DIR, 'conflicts', issueId, filename);\n}\n\n// =============================================================================\n// Dynamic Path Resolution\n// =============================================================================\n\nimport { access } from 'node:fs/promises';\n\n/**\n * Cache for resolved data sync directory.\n * Reset when baseDir changes.\n */\nlet _resolvedDataSyncDir: string | null = null;\nlet _resolvedBaseDir: string | null = null;\n\n/**\n * Resolve the actual data sync directory path.\n *\n * This function detects whether we're running with a git worktree\n * (production) or in a test environment without worktree.\n *\n * Order of preference:\n * 1. Worktree path if worktree exists: .tbd/data-sync-worktree/.tbd/data-sync/\n * 2. Direct path as fallback: .tbd/data-sync/\n *\n * @param baseDir - The base directory of the repository (default: process.cwd())\n * @returns Resolved data sync directory path\n */\nexport async function resolveDataSyncDir(baseDir: string = process.cwd()): Promise<string> {\n  // Return cached result if baseDir hasn't changed\n  if (_resolvedDataSyncDir && _resolvedBaseDir === baseDir) {\n    return _resolvedDataSyncDir;\n  }\n\n  const worktreePath = join(baseDir, DATA_SYNC_DIR_VIA_WORKTREE);\n  const directPath = join(baseDir, DATA_SYNC_DIR);\n\n  // Check if worktree path exists\n  try {\n    await access(worktreePath);\n    _resolvedDataSyncDir = worktreePath;\n    _resolvedBaseDir = baseDir;\n    return worktreePath;\n  } catch {\n    // Worktree doesn't exist, use direct path\n    _resolvedDataSyncDir = directPath;\n    _resolvedBaseDir = baseDir;\n    return directPath;\n  }\n}\n\n/**\n * Resolve issues directory path.\n */\nexport async function resolveIssuesDir(baseDir: string = process.cwd()): Promise<string> {\n  const dataSyncDir = await resolveDataSyncDir(baseDir);\n  return join(dataSyncDir, 'issues');\n}\n\n/**\n * Resolve mappings directory path.\n */\nexport async function resolveMappingsDir(baseDir: string = process.cwd()): Promise<string> {\n  const dataSyncDir = await resolveDataSyncDir(baseDir);\n  return join(dataSyncDir, 'mappings');\n}\n\n/**\n * Resolve attic directory path.\n */\nexport async function resolveAtticDir(baseDir: string = process.cwd()): Promise<string> {\n  const dataSyncDir = await resolveDataSyncDir(baseDir);\n  return join(dataSyncDir, 'attic');\n}\n\n/**\n * Clear the resolved path cache.\n * Call this when the repository state changes (e.g., after init).\n */\nexport function clearPathCache(): void {\n  _resolvedDataSyncDir = null;\n  _resolvedBaseDir = null;\n}\n\n// =============================================================================\n// Doc Path Resolution\n// =============================================================================\n\nimport { isAbsolute } from 'node:path';\nimport { homedir } from 'node:os';\n\n/**\n * Resolve a doc path for consistent handling across the codebase.\n *\n * Path resolution rules:\n * - Absolute paths (starting with /): used as-is\n * - Home directory paths (starting with ~/): expanded to user home directory\n * - Relative paths: resolved from tbd root (baseDir)\n *\n * @param docPath - The path to resolve\n * @param baseDir - The tbd root directory (parent of .tbd/), defaults to cwd\n * @returns Resolved absolute path\n *\n * @example\n * // Absolute path - returned as-is\n * resolveDocPath('/usr/local/docs/file.md') // => '/usr/local/docs/file.md'\n *\n * // Home path - expanded\n * resolveDocPath('~/docs/file.md') // => '/Users/username/docs/file.md'\n *\n * // Relative path - resolved from baseDir\n * resolveDocPath('docs/file.md', '/project') // => '/project/docs/file.md'\n */\nexport function resolveDocPath(docPath: string, baseDir: string = process.cwd()): string {\n  // Handle home directory expansion\n  if (docPath.startsWith('~/')) {\n    return join(homedir(), docPath.slice(2));\n  }\n\n  // Absolute paths used as-is\n  if (isAbsolute(docPath)) {\n    return docPath;\n  }\n\n  // Relative paths resolved from baseDir (tbd root)\n  return join(baseDir, docPath);\n}\n","/**\n * tbd Directory Format Versioning\n * ================================\n *\n * This file is the SINGLE SOURCE OF TRUTH for .tbd/ directory format versions.\n *\n * WHEN TO BUMP THE FORMAT VERSION:\n * - Bump when changes REQUIRE migration (deleting files, changing formats, moving files)\n * - Do NOT bump for additive changes (new optional config fields, new directories)\n *\n * HOW TO ADD A NEW FORMAT VERSION:\n * 1. Add entry to FORMAT_HISTORY with detailed description\n * 2. Implement migrate_fXX_to_fYY() function\n * 3. Add case to migrateToLatest()\n * 4. Update CURRENT_FORMAT\n * 5. Add tests for the migration path\n */\n\n// =============================================================================\n// Format Constants\n// =============================================================================\n\n/**\n * Current format version.\n * Bump this ONLY for breaking changes that require migration.\n */\nexport const CURRENT_FORMAT = 'f03';\n\n/**\n * Initial format version for configs that don't have tbd_format field.\n */\nexport const INITIAL_FORMAT = 'f01';\n\n// =============================================================================\n// Format History\n// =============================================================================\n\n/**\n * Complete history of format versions with their changes.\n * This serves as documentation and enables version detection.\n */\nexport const FORMAT_HISTORY = {\n  f01: {\n    introduced: '0.1.0',\n    description: 'Initial format',\n    structure: {\n      'config.yml': 'Project configuration',\n      'state.yml': 'Local state (gitignored)',\n      'docs/': 'Documentation cache (gitignored)',\n      'issues/': 'Issue YAML files',\n    },\n  },\n  f02: {\n    introduced: '0.1.5',\n    description: 'Adds configurable doc_cache',\n    changes: [\n      'Added doc_cache: key to config.yml for configurable doc sources',\n      'Added settings.doc_auto_sync_hours for automatic doc refresh',\n      'Added last_doc_sync_at to state.yml for tracking sync time',\n    ],\n    migration: 'Populates default doc_cache config from bundled docs',\n  },\n  f03: {\n    introduced: '0.1.6',\n    description: 'Consolidates docs_cache config structure',\n    changes: [\n      'Consolidated doc_cache: and docs: into single docs_cache: key',\n      'Moved doc_cache: -> docs_cache.files:',\n      'Moved docs.paths: -> docs_cache.lookup_path:',\n      'Removed separate docs: key',\n    ],\n    migration: 'Migrates old config keys to new docs_cache structure',\n  },\n} as const;\n\nexport type FormatVersion = keyof typeof FORMAT_HISTORY;\n\n// =============================================================================\n// Migration Types\n// =============================================================================\n\n/**\n * Raw config data before parsing/validation.\n * Used during migration when we need to work with potentially old formats.\n */\nexport interface RawConfig {\n  tbd_format?: string;\n  tbd_version?: string;\n  sync?: {\n    branch?: string;\n    remote?: string;\n  };\n  display?: {\n    id_prefix?: string;\n  };\n  settings?: {\n    auto_sync?: boolean;\n    doc_auto_sync_hours?: number;\n  };\n  // Old format (f02 and earlier)\n  docs?: {\n    paths?: string[];\n  };\n  doc_cache?: Record<string, string>;\n  // New format (f03+)\n  docs_cache?: {\n    files?: Record<string, string>;\n    lookup_path?: string[];\n  };\n}\n\n/**\n * Result of a migration operation.\n */\nexport interface MigrationResult {\n  /** The migrated config */\n  config: RawConfig;\n  /** Format version before migration */\n  fromFormat: FormatVersion;\n  /** Format version after migration */\n  toFormat: FormatVersion;\n  /** Whether any changes were made */\n  changed: boolean;\n  /** Description of changes made */\n  changes: string[];\n}\n\n// =============================================================================\n// Migration Functions\n// =============================================================================\n\n/**\n * Migrate from f01 to f02.\n * - Adds tbd_format field\n * - Adds doc_auto_sync_hours setting (default: 24)\n * - doc_cache will be populated separately during setup (requires file system access)\n */\nfunction migrate_f01_to_f02(config: RawConfig): MigrationResult {\n  const changes: string[] = [];\n  const migrated = { ...config };\n\n  // Add format version\n  migrated.tbd_format = 'f02';\n  changes.push('Added tbd_format: f02');\n\n  // Ensure settings exists and add doc_auto_sync_hours\n  migrated.settings ??= {};\n  if (migrated.settings.doc_auto_sync_hours === undefined) {\n    migrated.settings.doc_auto_sync_hours = 24;\n    changes.push('Added settings.doc_auto_sync_hours: 24');\n  }\n\n  // Note: doc_cache is intentionally NOT added here.\n  // It will be populated during setup when we have access to the file system\n  // and can enumerate the bundled docs.\n\n  return {\n    config: migrated,\n    fromFormat: 'f01',\n    toFormat: 'f02',\n    changed: changes.length > 0,\n    changes,\n  };\n}\n\n/**\n * Migrate from f02 to f03.\n * - Consolidates doc_cache: and docs: into docs_cache:\n * - Moves doc_cache: -> docs_cache.files:\n * - Moves docs.paths: -> docs_cache.lookup_path:\n * - Removes separate docs: and doc_cache: keys\n */\nfunction migrate_f02_to_f03(config: RawConfig): MigrationResult {\n  const changes: string[] = [];\n  const migrated = { ...config };\n\n  // Update format version\n  migrated.tbd_format = 'f03';\n  changes.push('Updated tbd_format: f03');\n\n  // Initialize docs_cache if it doesn't exist\n  migrated.docs_cache ??= {};\n\n  // Migrate doc_cache -> docs_cache.files\n  if (migrated.doc_cache && Object.keys(migrated.doc_cache).length > 0) {\n    migrated.docs_cache.files = { ...migrated.doc_cache };\n    changes.push('Moved doc_cache: -> docs_cache.files:');\n    delete migrated.doc_cache;\n  }\n\n  // Migrate docs.paths -> docs_cache.lookup_path\n  if (migrated.docs?.paths && migrated.docs.paths.length > 0) {\n    migrated.docs_cache.lookup_path = [...migrated.docs.paths];\n    changes.push('Moved docs.paths: -> docs_cache.lookup_path:');\n  }\n\n  // Remove old docs: key\n  if (migrated.docs) {\n    delete migrated.docs;\n    changes.push('Removed docs: key');\n  }\n\n  return {\n    config: migrated,\n    fromFormat: 'f02',\n    toFormat: 'f03',\n    changed: changes.length > 0,\n    changes,\n  };\n}\n\n// =============================================================================\n// Public API\n// =============================================================================\n\n/**\n * Detect the format version of a config.\n * Returns INITIAL_FORMAT ('f01') if no tbd_format field is present.\n */\nexport function detectFormat(config: RawConfig): FormatVersion {\n  const format = config.tbd_format;\n  if (!format) {\n    return INITIAL_FORMAT;\n  }\n  if (format in FORMAT_HISTORY) {\n    return format as FormatVersion;\n  }\n  // Unknown format - treat as latest (will fail validation if incompatible)\n  return CURRENT_FORMAT;\n}\n\n/**\n * Check if a config needs migration.\n */\nexport function needsMigration(config: RawConfig): boolean {\n  const currentFormat = detectFormat(config);\n  return currentFormat !== CURRENT_FORMAT;\n}\n\n/**\n * Migrate a config to the latest format version.\n *\n * This function applies all necessary migrations in sequence.\n * It does NOT populate doc_cache - that requires file system access\n * and should be done separately during setup.\n *\n * @param config - The raw config to migrate\n * @returns Migration result with the migrated config and change log\n */\nexport function migrateToLatest(config: RawConfig): MigrationResult {\n  const fromFormat = detectFormat(config);\n\n  if (fromFormat === CURRENT_FORMAT) {\n    return {\n      config,\n      fromFormat,\n      toFormat: CURRENT_FORMAT,\n      changed: false,\n      changes: [],\n    };\n  }\n\n  let current = config;\n  let currentFormat: FormatVersion = fromFormat;\n  const allChanges: string[] = [];\n\n  // Apply migrations in sequence\n  if (currentFormat === 'f01') {\n    const result = migrate_f01_to_f02(current);\n    current = result.config;\n    currentFormat = 'f02' as FormatVersion;\n    allChanges.push(...result.changes);\n  }\n\n  if (currentFormat === 'f02') {\n    const result = migrate_f02_to_f03(current);\n    current = result.config;\n    currentFormat = 'f03' as FormatVersion;\n    allChanges.push(...result.changes);\n  }\n\n  // Add more migrations here as new format versions are added\n\n  return {\n    config: current,\n    fromFormat,\n    toFormat: currentFormat,\n    changed: allChanges.length > 0,\n    changes: allChanges,\n  };\n}\n\n/**\n * Check if a format version is compatible with the current tbd version.\n * Future format versions are considered incompatible (would need tbd upgrade).\n */\nexport function isCompatibleFormat(format: string): boolean {\n  const formatVersions = Object.keys(FORMAT_HISTORY);\n  const currentIndex = formatVersions.indexOf(CURRENT_FORMAT);\n  const checkIndex = formatVersions.indexOf(format);\n\n  if (checkIndex === -1) {\n    // Unknown format - might be from a newer tbd version\n    return false;\n  }\n\n  // Compatible if same or older format (we can migrate up)\n  return checkIndex <= currentIndex;\n}\n\n/**\n * Get a human-readable description of what migrations will be applied.\n */\nexport function describeMigration(fromFormat: FormatVersion): string[] {\n  const descriptions: string[] = [];\n  let current = fromFormat;\n\n  if (current === 'f01') {\n    descriptions.push('f01 → f02: Add doc_cache configuration support');\n    current = 'f02';\n  }\n\n  if (current === 'f02') {\n    descriptions.push('f02 → f03: Consolidate doc_cache and docs into docs_cache');\n    current = 'f03';\n  }\n\n  // Add more migration descriptions here\n\n  return descriptions;\n}\n","/**\n * Config file operations.\n *\n * Config is stored at .tbd/config.yml and contains project-level settings.\n *\n * ⚠️ FORMAT VERSIONING: See tbd-format.ts for version history and migration rules.\n *\n * See: tbd-design.md §2.2.2 Config File\n */\n\nimport { readFile, mkdir, access } from 'node:fs/promises';\nimport { join, dirname, parse as parsePath } from 'node:path';\nimport { writeFile } from 'atomically';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\n\nimport type { Config, LocalState } from '../lib/types.js';\nimport { ConfigSchema, LocalStateSchema } from '../lib/schemas.js';\nimport { CONFIG_FILE, STATE_FILE, SYNC_BRANCH } from '../lib/paths.js';\nimport {\n  CURRENT_FORMAT,\n  needsMigration,\n  migrateToLatest,\n  type RawConfig,\n} from '../lib/tbd-format.js';\n\n/**\n * Path to config file relative to project root.\n * Re-exported from paths.ts for backwards compatibility.\n */\nexport const CONFIG_FILE_PATH = CONFIG_FILE;\n\n/**\n * Create default config for a new project.\n * @param prefix - Required: the project prefix for display IDs (e.g., \"proj\", \"myapp\")\n */\nfunction createDefaultConfig(version: string, prefix: string): Config {\n  return ConfigSchema.parse({\n    tbd_format: CURRENT_FORMAT,\n    tbd_version: version,\n    sync: {\n      branch: SYNC_BRANCH,\n      remote: 'origin',\n    },\n    display: {\n      id_prefix: prefix,\n    },\n    settings: {\n      auto_sync: false,\n      doc_auto_sync_hours: 24,\n    },\n  });\n}\n\n/**\n * Initialize a new config file with default settings.\n * Creates .tbd directory if it doesn't exist.\n * @param prefix - Required: the project prefix for display IDs (e.g., \"proj\", \"myapp\")\n */\nexport async function initConfig(\n  baseDir: string,\n  version: string,\n  prefix: string,\n): Promise<Config> {\n  const tbdDir = join(baseDir, '.tbd');\n  await mkdir(tbdDir, { recursive: true });\n\n  const config = createDefaultConfig(version, prefix);\n  await writeConfig(baseDir, config);\n\n  return config;\n}\n\n/**\n * Read config from file with automatic migration if needed.\n *\n * ⚠️ FORMAT VERSIONING: See tbd-format.ts for version history and migration rules.\n *\n * @throws If config file doesn't exist or is invalid.\n */\nexport async function readConfig(baseDir: string): Promise<Config> {\n  const configPath = join(baseDir, CONFIG_FILE_PATH);\n  const content = await readFile(configPath, 'utf-8');\n  const data = parseYaml(content) as RawConfig;\n\n  // Check if migration is needed\n  if (needsMigration(data)) {\n    const result = migrateToLatest(data);\n    // Note: We don't automatically write the migrated config here.\n    // Migration writes should be explicit via writeConfig() after setup.\n    return ConfigSchema.parse(result.config);\n  }\n\n  return ConfigSchema.parse(data);\n}\n\n/**\n * Read config from file, returning migration info if a migration was applied.\n * Use this when you need to know if the config was migrated.\n */\nexport async function readConfigWithMigration(\n  baseDir: string,\n): Promise<{ config: Config; migrated: boolean; changes: string[] }> {\n  const configPath = join(baseDir, CONFIG_FILE_PATH);\n  const content = await readFile(configPath, 'utf-8');\n  const data = parseYaml(content) as RawConfig;\n\n  if (needsMigration(data)) {\n    const result = migrateToLatest(data);\n    return {\n      config: ConfigSchema.parse(result.config),\n      migrated: result.changed,\n      changes: result.changes,\n    };\n  }\n\n  return {\n    config: ConfigSchema.parse(data),\n    migrated: false,\n    changes: [],\n  };\n}\n\n/**\n * Write config to file with explanatory comments.\n */\nexport async function writeConfig(baseDir: string, config: Config): Promise<void> {\n  const configPath = join(baseDir, CONFIG_FILE_PATH);\n\n  const yaml = stringifyYaml(config, {\n    sortMapEntries: true,\n    lineWidth: 0,\n  });\n\n  // Add explanatory comments for docs_cache section\n  let content = yaml;\n  if (config.docs_cache && Object.keys(config.docs_cache).length > 0) {\n    const docsCacheComment = `# Documentation cache configuration.\n# files: Maps destination paths (relative to .tbd/docs/) to source locations.\n#   Sources can be:\n#   - internal: prefix for bundled docs (e.g., \"internal:shortcuts/standard/commit-code.md\")\n#   - Full URL for external docs (e.g., \"https://raw.githubusercontent.com/org/repo/main/file.md\")\n# lookup_path: Search paths for doc lookup (like shell $PATH). Earlier paths take precedence.\n#\n# To sync docs: tbd docs --refresh\n# To check status: tbd docs --status\n#\n# Auto-sync: Docs are automatically synced when stale (default: every 24 hours).\n# Configure with settings.doc_auto_sync_hours (0 = disabled).\n`;\n    content = content.replace('docs_cache:', docsCacheComment + 'docs_cache:');\n  }\n\n  await writeFile(configPath, content);\n}\n\n/**\n * Check if tbd is initialized in the given directory (immediate check only).\n * Returns true if .tbd/ directory exists directly in baseDir.\n */\nasync function hasTbdDir(dir: string): Promise<boolean> {\n  const tbdDir = join(dir, '.tbd');\n  try {\n    await access(tbdDir);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Find the tbd repository root by walking up the directory tree.\n * Similar to how git finds .git/ directories.\n *\n * @param startDir - Directory to start searching from\n * @returns The tbd root directory path, or null if not found\n */\nexport async function findTbdRoot(startDir: string): Promise<string | null> {\n  let currentDir = startDir;\n  const { root } = parsePath(startDir);\n\n  while (currentDir !== root) {\n    if (await hasTbdDir(currentDir)) {\n      return currentDir;\n    }\n    currentDir = dirname(currentDir);\n  }\n\n  // Check root directory as well\n  if (await hasTbdDir(root)) {\n    return root;\n  }\n\n  return null;\n}\n\n/**\n * Check if tbd is initialized in the given directory or any parent directory.\n * Walks up the directory tree looking for .tbd/.\n */\nexport async function isInitialized(baseDir: string): Promise<boolean> {\n  const root = await findTbdRoot(baseDir);\n  return root !== null;\n}\n\n// =============================================================================\n// Local State Operations\n// =============================================================================\n\n/**\n * Read local state from .tbd/state.yml\n * Returns empty state if file doesn't exist.\n */\nexport async function readLocalState(baseDir: string): Promise<LocalState> {\n  const statePath = join(baseDir, STATE_FILE);\n  try {\n    const content = await readFile(statePath, 'utf-8');\n    const data: unknown = parseYaml(content);\n    return LocalStateSchema.parse(data ?? {});\n  } catch {\n    // File doesn't exist or is invalid - return empty state\n    return {};\n  }\n}\n\n/**\n * Write local state to .tbd/state.yml\n */\nexport async function writeLocalState(baseDir: string, state: LocalState): Promise<void> {\n  const statePath = join(baseDir, STATE_FILE);\n\n  // Ensure .tbd directory exists\n  await mkdir(join(baseDir, '.tbd'), { recursive: true });\n\n  const yaml = stringifyYaml(state, {\n    sortMapEntries: true,\n    lineWidth: 0,\n  });\n\n  await writeFile(statePath, yaml);\n}\n\n/**\n * Update specific fields in local state (merge with existing).\n */\nexport async function updateLocalState(\n  baseDir: string,\n  updates: Partial<LocalState>,\n): Promise<LocalState> {\n  const current = await readLocalState(baseDir);\n  const updated = { ...current, ...updates };\n  await writeLocalState(baseDir, updated);\n  return updated;\n}\n\n// =============================================================================\n// Welcome State Operations\n// =============================================================================\n\n/**\n * Check if the user has seen the welcome message.\n */\nexport async function hasSeenWelcome(baseDir: string): Promise<boolean> {\n  const state = await readLocalState(baseDir);\n  return state.welcome_seen === true;\n}\n\n/**\n * Mark the welcome message as seen.\n */\nexport async function markWelcomeSeen(baseDir: string): Promise<void> {\n  await updateLocalState(baseDir, { welcome_seen: true });\n}\n","/**\n * CLI error types and helpers for structured error handling.\n *\n * See: research-modern-typescript-cli-patterns.md#3-base-command-pattern\n */\n\nimport { findTbdRoot } from '../../file/config.js';\n\n/**\n * Find and return the tbd repository root, starting from the given directory.\n * Walks up the directory tree to find .tbd/.\n *\n * @param cwd - Working directory to start from (defaults to process.cwd())\n * @returns The tbd repository root path\n * @throws NotInitializedError if tbd is not initialized in any parent directory\n */\nexport async function requireInit(cwd: string = process.cwd()): Promise<string> {\n  const tbdRoot = await findTbdRoot(cwd);\n  if (!tbdRoot) {\n    throw new NotInitializedError();\n  }\n  return tbdRoot;\n}\n\n/**\n * Base CLI error. Thrown for operational errors that should exit\n * with a specific code but don't need stack traces.\n */\nexport class CLIError extends Error {\n  constructor(\n    message: string,\n    public exitCode = 1,\n  ) {\n    super(message);\n    this.name = 'CLIError';\n  }\n}\n\n/**\n * Validation error for usage/argument issues.\n * Exit code 2 follows Unix convention.\n */\nexport class ValidationError extends CLIError {\n  constructor(message: string) {\n    super(message, 2);\n    this.name = 'ValidationError';\n  }\n}\n\n/**\n * Not initialized error - tbd repository not found.\n * Uses the stable error message defined in design spec §5.6.\n */\nexport class NotInitializedError extends CLIError {\n  constructor(message = \"Not a tbd repository (run 'tbd setup --auto --prefix=<name>' first)\") {\n    super(message, 1);\n    this.name = 'NotInitializedError';\n  }\n}\n\n/**\n * Entity not found error (issue, config, etc.).\n */\nexport class NotFoundError extends CLIError {\n  constructor(entityType: string, id: string) {\n    super(`${entityType} not found: ${id}`, 1);\n    this.name = 'NotFoundError';\n  }\n}\n\n/**\n * Sync/conflict error.\n */\nexport class SyncError extends CLIError {\n  constructor(message: string) {\n    super(message, 1);\n    this.name = 'SyncError';\n  }\n}\n","/**\n * Base command class for CLI handlers.\n *\n * See: research-modern-typescript-cli-patterns.md#3-base-command-pattern\n */\n\nimport type { Command } from 'commander';\n\nimport type { CommandContext, OutputFormat } from './context.js';\nimport { getCommandContext } from './context.js';\nimport { OutputManager } from './output.js';\nimport { CLIError } from './errors.js';\n\n/**\n * Base class for all CLI command handlers.\n * Provides common functionality for context, output, and error handling.\n */\nexport abstract class BaseCommand {\n  protected ctx: CommandContext;\n  protected output: OutputManager;\n\n  constructor(command: Command) {\n    this.ctx = getCommandContext(command);\n    this.output = new OutputManager(this.ctx);\n  }\n\n  /**\n   * Execute an async action with error handling.\n   * Catches errors and formats them consistently.\n   */\n  protected async execute<T>(action: () => Promise<T>, errorMessage: string): Promise<T> {\n    try {\n      return await action();\n    } catch (error) {\n      if (error instanceof CLIError) {\n        this.output.error(error.message);\n        throw error;\n      }\n      this.output.error(errorMessage, error instanceof Error ? error : undefined);\n      throw new CLIError(errorMessage);\n    }\n  }\n\n  /**\n   * Check if dry-run mode is enabled and log the action.\n   * Returns true if in dry-run mode (caller should skip the actual action).\n   */\n  protected checkDryRun(message: string, details?: object): boolean {\n    if (this.ctx.dryRun) {\n      this.output.dryRun(message, details);\n      return true;\n    }\n    return false;\n  }\n\n  /**\n   * Abstract method that subclasses must implement.\n   * Signature varies by command (positional args + options object).\n   */\n  abstract run(...args: unknown[]): Promise<void>;\n}\n\n/**\n * Helper to get output format from context.\n */\nexport function getOutputFormat(ctx: CommandContext): OutputFormat {\n  return ctx.json ? 'json' : 'text';\n}\n","/**\n * File system utility functions.\n */\n\nimport { access } from 'node:fs/promises';\n\n/**\n * Check if a path exists on the filesystem.\n */\nexport async function pathExists(path: string): Promise<boolean> {\n  try {\n    await access(path);\n    return true;\n  } catch {\n    return false;\n  }\n}\n","/**\n * Gitignore file utilities for idempotent pattern management.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { writeFile } from 'atomically';\nimport { pathExists } from './file-utils.js';\n\n/**\n * Check if a pattern exists in gitignore content.\n * Matches exact lines, normalizing trailing slashes for directories.\n */\nexport function hasGitignorePattern(content: string, pattern: string): boolean {\n  const normalizedPattern = pattern.replace(/\\/+$/, '');\n  const lines = content.split('\\n');\n\n  for (const line of lines) {\n    const trimmed = line.trim();\n    // Skip comments and empty lines\n    if (trimmed === '' || trimmed.startsWith('#')) continue;\n\n    const normalizedLine = trimmed.replace(/\\/+$/, '');\n    if (normalizedLine === normalizedPattern) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Ensure patterns exist in a .gitignore file.\n * Creates file if missing. Appends only missing patterns.\n * Always uses atomic write.\n *\n * @param gitignorePath - Path to .gitignore file\n * @param patterns - Patterns to ensure exist (can include comments)\n * @param header - Optional header comment for new patterns section\n */\nexport async function ensureGitignorePatterns(\n  gitignorePath: string,\n  patterns: string[],\n  header?: string,\n): Promise<{ added: string[]; skipped: string[]; created: boolean }> {\n  // Read existing content or empty string\n  let content = '';\n  let created = false;\n\n  if (await pathExists(gitignorePath)) {\n    content = await readFile(gitignorePath, 'utf-8');\n  } else {\n    created = true;\n  }\n\n  // Determine which patterns need to be added\n  const added: string[] = [];\n  const skipped: string[] = [];\n\n  for (const pattern of patterns) {\n    const trimmed = pattern.trim();\n    // Always add comments and blank lines (for formatting)\n    if (trimmed === '' || trimmed.startsWith('#')) {\n      added.push(pattern);\n    } else if (hasGitignorePattern(content, trimmed)) {\n      skipped.push(trimmed);\n    } else {\n      added.push(pattern);\n    }\n  }\n\n  // Filter out comments/blanks to check if we have actual patterns to add\n  const actualPatternsToAdd = added.filter((p) => p.trim() && !p.trim().startsWith('#'));\n\n  // If nothing new to add (all skipped), return early\n  if (actualPatternsToAdd.length === 0) {\n    return { added: [], skipped, created: false };\n  }\n\n  // Build new content\n  let newContent = content;\n\n  // Ensure content ends with newline before appending\n  if (newContent && !newContent.endsWith('\\n')) {\n    newContent += '\\n';\n  }\n\n  // Add blank line separator if file has existing content\n  if (newContent && !newContent.endsWith('\\n\\n')) {\n    newContent += '\\n';\n  }\n\n  // Add header if provided\n  if (header) {\n    newContent += header + '\\n';\n  }\n\n  // Add patterns\n  newContent += added.join('\\n') + '\\n';\n\n  // Atomic write\n  await writeFile(gitignorePath, newContent);\n\n  return { added: actualPatternsToAdd, skipped, created };\n}\n","/**\n * Time utilities for tbd.\n *\n * All timestamps should be ISO 8601 UTC format with Z suffix.\n * Use these functions instead of raw Date calls for consistency.\n */\n\n/**\n * Get current time as ISO 8601 UTC string.\n * Use this when recording timestamps for new/updated issues.\n */\nexport function now(): string {\n  return new Date().toISOString();\n}\n\n/**\n * Get current time as Date object.\n * Use this when you need date arithmetic or comparisons.\n */\nexport function nowDate(): Date {\n  return new Date();\n}\n\n/**\n * Parse a timestamp string to Date object.\n * Returns null if the timestamp is invalid.\n */\nexport function parseDate(timestamp: string | undefined | null): Date | null {\n  if (!timestamp) return null;\n  try {\n    const date = new Date(timestamp);\n    if (isNaN(date.getTime())) return null;\n    return date;\n  } catch {\n    return null;\n  }\n}\n\n/**\n * Normalize any timestamp to ISO 8601 UTC format with Z suffix.\n * Handles various formats including timezone offsets like -08:00.\n * Returns null if the timestamp is invalid or missing.\n */\nexport function normalizeTimestamp(timestamp: string | undefined | null): string | null {\n  const date = parseDate(timestamp);\n  return date?.toISOString() ?? null;\n}\n\n/**\n * Check if a timestamp string is valid.\n */\nexport function isValidTimestamp(timestamp: string | undefined | null): boolean {\n  return parseDate(timestamp) !== null;\n}\n\n/**\n * Get current time as a filename-safe timestamp.\n * Replaces colons with dashes and removes milliseconds for filesystem compatibility.\n */\nexport function nowFilenameTimestamp(): string {\n  return new Date()\n    .toISOString()\n    .replace(/:/g, '-')\n    .replace(/\\.\\d+Z$/, 'Z');\n}\n","/**\n * Git utilities for sync operations.\n *\n * Provides:\n * - Isolated index operations (protect user's staging area)\n * - Field-level merge algorithm\n * - Push retry with exponential backoff\n *\n * See: tbd-design.md §3.3 Sync Operations\n */\n\nimport { execFile } from 'node:child_process';\nimport { mkdir } from 'node:fs/promises';\nimport { promisify } from 'node:util';\nimport { join } from 'node:path';\n\nimport { writeFile } from 'atomically';\n\nimport type { Issue } from '../lib/types.js';\nimport { now, nowFilenameTimestamp } from '../utils/time-utils.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Execute a git command and return stdout.\n * Uses execFile for security - prevents shell injection attacks.\n */\nexport async function git(...args: string[]): Promise<string> {\n  const { stdout } = await execFileAsync('git', args);\n  return stdout.trim();\n}\n\n// =============================================================================\n// Git Version Detection\n// See: plan spec §3.4 Git Integration Architecture\n// =============================================================================\n\n/**\n * Minimum Git version required.\n * Git 2.42 (August 2023) introduced `git worktree add --orphan` which tbd requires.\n */\nexport const MIN_GIT_VERSION = '2.42.0';\n\n/**\n * Parsed Git version information.\n */\n/**\n * Check if the current directory is inside a git repository.\n */\nexport async function isInGitRepo(cwd?: string): Promise<boolean> {\n  try {\n    const args = ['rev-parse', '--is-inside-work-tree'];\n    if (cwd) {\n      args.unshift('-C', cwd);\n    }\n    const result = await git(...args);\n    return result === 'true';\n  } catch {\n    return false;\n  }\n}\n\nexport interface GitVersion {\n  major: number;\n  minor: number;\n  patch: number;\n  raw: string;\n}\n\n/**\n * Get the installed Git version.\n *\n * @returns Parsed version information\n * @throws Error if git is not installed or version cannot be parsed\n */\nexport async function getGitVersion(): Promise<GitVersion> {\n  const versionOutput = await git('--version');\n  // Output format: \"git version 2.42.0\" or \"git version 2.42.0.windows.1\"\n  const versionRegex = /git version (\\d+)\\.(\\d+)\\.(\\d+)/;\n  const match = versionRegex.exec(versionOutput);\n\n  const major = match?.[1];\n  const minor = match?.[2];\n  const patch = match?.[3];\n\n  if (!major || !minor || !patch) {\n    throw new Error(`Unable to parse git version from: ${versionOutput}`);\n  }\n\n  return {\n    major: parseInt(major, 10),\n    minor: parseInt(minor, 10),\n    patch: parseInt(patch, 10),\n    raw: versionOutput,\n  };\n}\n\n/**\n * Compare two version strings.\n *\n * @returns -1 if a < b, 0 if a === b, 1 if a > b\n */\nexport function compareVersions(a: GitVersion, b: string): number {\n  const parts = b.split('.');\n  const bMajor = parseInt(parts[0] ?? '0', 10);\n  const bMinor = parseInt(parts[1] ?? '0', 10);\n  const bPatch = parseInt(parts[2] ?? '0', 10);\n\n  if (a.major !== bMajor) return a.major < bMajor ? -1 : 1;\n  if (a.minor !== bMinor) return a.minor < bMinor ? -1 : 1;\n  if (a.patch !== bPatch) return a.patch < bPatch ? -1 : 1;\n  return 0;\n}\n\n/**\n * Check if the installed Git version meets minimum requirements.\n *\n * @returns Object with version info and whether it meets requirements\n * @throws Error with upgrade instructions if Git version is too old\n */\nexport async function checkGitVersion(): Promise<{\n  version: GitVersion;\n  supported: boolean;\n}> {\n  const version = await getGitVersion();\n  const supported = compareVersions(version, MIN_GIT_VERSION) >= 0;\n  return { version, supported };\n}\n\n/**\n * Require minimum Git version, throwing an error if not met.\n */\nexport async function requireGitVersion(): Promise<GitVersion> {\n  const { version, supported } = await checkGitVersion();\n  if (!supported) {\n    throw new Error(getUpgradeInstructions(version));\n  }\n  return version;\n}\n\n/**\n * Get platform-specific upgrade instructions.\n * Points to official documentation rather than detailed commands for easier maintenance.\n */\nfunction getUpgradeInstructions(currentVersion: GitVersion): string {\n  const platform = process.platform;\n  const versionStr = `${currentVersion.major}.${currentVersion.minor}.${currentVersion.patch}`;\n\n  let upgradeUrl: string;\n  switch (platform) {\n    case 'darwin':\n      upgradeUrl = 'https://git-scm.com/download/mac';\n      break;\n    case 'linux':\n      upgradeUrl = 'https://git-scm.com/download/linux';\n      break;\n    case 'win32':\n      upgradeUrl = 'https://git-scm.com/download/win';\n      break;\n    default:\n      upgradeUrl = 'https://git-scm.com/downloads';\n  }\n\n  return `Git ${versionStr} detected. Git ${MIN_GIT_VERSION}+ required for tbd.\\nUpgrade: ${upgradeUrl}`;\n}\n\n/**\n * Execute a git command with isolated index.\n * This protects the user's staging area during sync operations.\n *\n * See: tbd-design.md §3.3.2 Writing to Sync Branch\n */\nexport async function withIsolatedIndex<T>(fn: () => Promise<T>): Promise<T> {\n  const gitDir = await git('rev-parse', '--git-dir');\n  const isolatedIndex = join(gitDir, 'tbd-index');\n  const originalIndex = process.env.GIT_INDEX_FILE;\n\n  try {\n    process.env.GIT_INDEX_FILE = isolatedIndex;\n    return await fn();\n  } finally {\n    if (originalIndex) {\n      process.env.GIT_INDEX_FILE = originalIndex;\n    } else {\n      delete process.env.GIT_INDEX_FILE;\n    }\n  }\n}\n\n/**\n * Commit changes to sync branch using isolated index.\n */\nexport async function commitToSyncBranch(\n  syncBranch: string,\n  message: string,\n  files: string[],\n): Promise<string> {\n  return withIsolatedIndex(async () => {\n    // Try to read existing tree from sync branch\n    try {\n      await git('read-tree', syncBranch);\n    } catch {\n      // Branch doesn't exist - start fresh\n    }\n\n    // Add changed files to index\n    for (const file of files) {\n      await git('add', file);\n    }\n\n    // Write tree object\n    const tree = await git('write-tree');\n\n    // Get parent commit if exists\n    let parent: string | null = null;\n    try {\n      parent = await git('rev-parse', syncBranch);\n    } catch {\n      // No parent - orphan commit\n    }\n\n    // Create commit\n    // Note: With execFile, we pass the message directly without shell quoting\n    const commitArgs = ['commit-tree', tree, '-m', message];\n    if (parent) {\n      commitArgs.push('-p', parent);\n    }\n\n    const commit = await git(...commitArgs);\n\n    // Update branch ref\n    await git('update-ref', `refs/heads/${syncBranch}`, commit);\n\n    return commit;\n  });\n}\n\n/**\n * Field-level merge strategy types.\n */\ntype MergeStrategy = 'lww' | 'union' | 'max' | 'immutable';\n\n/**\n * Field-level merge strategies for Issue fields.\n * See: tbd-design.md §3.5 Merge Rules\n */\nconst FIELD_STRATEGIES: Record<keyof Issue, MergeStrategy> = {\n  // Immutable - never change after creation\n  type: 'immutable',\n  id: 'immutable',\n  created_at: 'immutable',\n  created_by: 'immutable',\n\n  // LWW (Last-Write-Wins) - compare updated_at\n  version: 'max',\n  kind: 'lww',\n  title: 'lww',\n  description: 'lww',\n  notes: 'lww',\n  status: 'lww',\n  priority: 'lww',\n  assignee: 'lww',\n  parent_id: 'lww',\n  updated_at: 'max',\n  closed_at: 'lww',\n  close_reason: 'lww',\n  due_date: 'lww',\n  deferred_until: 'lww',\n  spec_path: 'lww',\n\n  // Union - combine arrays, deduplicate\n  labels: 'union',\n  dependencies: 'union',\n\n  // Extensions - LWW for whole object\n  extensions: 'lww',\n};\n\n/**\n * Conflict entry for attic storage.\n */\nexport interface ConflictEntry {\n  issue_id: string;\n  field: string;\n  timestamp: string;\n  lost_value: unknown;\n  winner_value: unknown;\n  local_version: number;\n  remote_version: number;\n  resolution: 'lww' | 'union' | 'manual';\n}\n\n/**\n * Merge result with merged issue and any conflicts.\n */\nexport interface MergeResult {\n  merged: Issue;\n  conflicts: ConflictEntry[];\n}\n\n/**\n * Deep equality check for values.\n */\nfunction deepEqual(a: unknown, b: unknown): boolean {\n  if (a === b) return true;\n  if (a === null || b === null) return a === b;\n  if (typeof a !== typeof b) return false;\n\n  if (Array.isArray(a) && Array.isArray(b)) {\n    if (a.length !== b.length) return false;\n    return a.every((item, i) => deepEqual(item, b[i]));\n  }\n\n  if (typeof a === 'object' && typeof b === 'object') {\n    const aKeys = Object.keys(a);\n    const bKeys = Object.keys(b);\n    if (aKeys.length !== bKeys.length) return false;\n    return aKeys.every((key) =>\n      deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n    );\n  }\n\n  return false;\n}\n\n/**\n * Union arrays with deduplication.\n */\nfunction unionArrays<T>(a: T[], b: T[]): T[] {\n  const result = [...a];\n  for (const item of b) {\n    if (!result.some((existing) => deepEqual(existing, item))) {\n      result.push(item);\n    }\n  }\n  return result;\n}\n\n/**\n * Create an attic entry for a conflict.\n */\nfunction createConflictEntry(\n  issueId: string,\n  field: string,\n  lostValue: unknown,\n  winnerValue: unknown,\n  localVersion: number,\n  remoteVersion: number,\n  resolution: 'lww' | 'union' | 'manual',\n): ConflictEntry {\n  const timestamp = nowFilenameTimestamp();\n\n  return {\n    issue_id: issueId,\n    field,\n    timestamp,\n    lost_value: lostValue,\n    winner_value: winnerValue,\n    local_version: localVersion,\n    remote_version: remoteVersion,\n    resolution,\n  };\n}\n\n/**\n * Three-way merge algorithm for issues.\n * See: tbd-design.md §3.4 Conflict Detection and Resolution\n *\n * @param base - Common ancestor (null if new issue)\n * @param local - Local version\n * @param remote - Remote version\n */\nexport function mergeIssues(base: Issue | null, local: Issue, remote: Issue): MergeResult {\n  const conflicts: ConflictEntry[] = [];\n\n  // If no base, one was created independently - LWW based on created_at\n  if (!base) {\n    const localTime = new Date(local.created_at).getTime();\n    const remoteTime = new Date(remote.created_at).getTime();\n\n    if (localTime <= remoteTime) {\n      // Local was created first - it wins\n      if (!deepEqual(local, remote)) {\n        conflicts.push(\n          createConflictEntry(\n            remote.id,\n            'whole_issue',\n            remote,\n            local,\n            remote.version,\n            local.version,\n            'lww',\n          ),\n        );\n      }\n      return { merged: local, conflicts };\n    } else {\n      // Remote was created first - it wins\n      if (!deepEqual(local, remote)) {\n        conflicts.push(\n          createConflictEntry(\n            local.id,\n            'whole_issue',\n            local,\n            remote,\n            local.version,\n            remote.version,\n            'lww',\n          ),\n        );\n      }\n      return { merged: remote, conflicts };\n    }\n  }\n\n  // Field-by-field merge\n  const merged = { ...base } as Issue;\n\n  for (const [field, strategy] of Object.entries(FIELD_STRATEGIES)) {\n    const key = field as keyof Issue;\n    const localVal = local[key];\n    const remoteVal = remote[key];\n    const baseVal = base[key];\n\n    // Skip if both unchanged from base\n    if (deepEqual(localVal, baseVal) && deepEqual(remoteVal, baseVal)) {\n      continue;\n    }\n\n    // Only one changed - take changed value\n    if (deepEqual(localVal, baseVal)) {\n      (merged as Record<string, unknown>)[key] = remoteVal;\n      continue;\n    }\n    if (deepEqual(remoteVal, baseVal)) {\n      (merged as Record<string, unknown>)[key] = localVal;\n      continue;\n    }\n\n    // Both changed - apply strategy\n    switch (strategy) {\n      case 'immutable':\n        // Keep base value (shouldn't change)\n        break;\n\n      case 'lww': {\n        // Compare updated_at timestamps\n        const localTime = new Date(local.updated_at).getTime();\n        const remoteTime = new Date(remote.updated_at).getTime();\n\n        if (localTime >= remoteTime) {\n          (merged as Record<string, unknown>)[key] = localVal;\n          conflicts.push(\n            createConflictEntry(\n              local.id,\n              field,\n              remoteVal,\n              localVal,\n              local.version,\n              remote.version,\n              'lww',\n            ),\n          );\n        } else {\n          (merged as Record<string, unknown>)[key] = remoteVal;\n          conflicts.push(\n            createConflictEntry(\n              local.id,\n              field,\n              localVal,\n              remoteVal,\n              local.version,\n              remote.version,\n              'lww',\n            ),\n          );\n        }\n        break;\n      }\n\n      case 'union':\n        // Combine arrays and deduplicate\n        (merged as Record<string, unknown>)[key] = unionArrays(\n          localVal as unknown[],\n          remoteVal as unknown[],\n        );\n        break;\n\n      case 'max':\n        // Take maximum value\n        (merged as Record<string, unknown>)[key] = Math.max(\n          localVal as number,\n          remoteVal as number,\n        );\n        break;\n    }\n  }\n\n  // Always increment version after merge\n  merged.version = Math.max(local.version, remote.version) + 1;\n  merged.updated_at = now();\n\n  return { merged, conflicts };\n}\n\n/**\n * Maximum retry attempts for push operations.\n */\nconst MAX_PUSH_RETRIES = 3;\n\n/**\n * Check if error is a non-fast-forward rejection.\n */\nfunction isNonFastForward(error: unknown): boolean {\n  const msg = error instanceof Error ? error.message : String(error);\n  return (\n    msg.includes('non-fast-forward') || msg.includes('fetch first') || msg.includes('rejected')\n  );\n}\n\n/**\n * Push result with retry information.\n */\nexport interface PushResult {\n  success: boolean;\n  attempt: number;\n  conflicts?: ConflictEntry[];\n  error?: string;\n}\n\n/**\n * Push with retry and merge on conflict.\n * See: tbd-design.md §3.3.3 Sync Algorithm\n *\n * @param syncBranch - The sync branch name\n * @param remote - The remote name\n * @param onMergeNeeded - Callback to merge remote changes\n */\nexport async function pushWithRetry(\n  syncBranch: string,\n  remote: string,\n  onMergeNeeded: () => Promise<ConflictEntry[]>,\n): Promise<PushResult> {\n  for (let attempt = 1; attempt <= MAX_PUSH_RETRIES; attempt++) {\n    try {\n      // Try to push\n      await git('push', remote, syncBranch);\n      return { success: true, attempt };\n    } catch (error) {\n      if (!isNonFastForward(error)) {\n        // Unrecoverable error\n        return {\n          success: false,\n          attempt,\n          error: error instanceof Error ? error.message : String(error),\n        };\n      }\n\n      if (attempt === MAX_PUSH_RETRIES) {\n        return {\n          success: false,\n          attempt,\n          error: `Push failed after ${MAX_PUSH_RETRIES} attempts. Remote has conflicting changes.`,\n        };\n      }\n\n      // Fetch and merge remote changes\n      await git('fetch', remote, syncBranch);\n      const conflicts = await onMergeNeeded();\n\n      if (conflicts.length > 0) {\n        // Return conflicts but continue trying\n        return { success: false, attempt, conflicts };\n      }\n\n      // Loop to retry push\n    }\n  }\n\n  return { success: false, attempt: MAX_PUSH_RETRIES, error: 'Unexpected error in push retry' };\n}\n\n/**\n * Get the current branch name.\n */\nexport async function getCurrentBranch(): Promise<string> {\n  return git('rev-parse', '--abbrev-ref', 'HEAD');\n}\n\n/**\n * Check if a branch exists locally.\n */\nexport async function branchExists(branch: string): Promise<boolean> {\n  try {\n    await git('rev-parse', '--verify', `refs/heads/${branch}`);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Check if a remote branch exists.\n */\nexport async function remoteBranchExists(remote: string, branch: string): Promise<boolean> {\n  try {\n    await git('ls-remote', '--exit-code', remote, `refs/heads/${branch}`);\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Get the remote URL.\n */\nexport async function getRemoteUrl(remote: string): Promise<string | null> {\n  try {\n    return await git('remote', 'get-url', remote);\n  } catch {\n    return null;\n  }\n}\n\n// =============================================================================\n// Worktree Management\n// See: tbd-design.md §2.3 Hidden Worktree Model\n// =============================================================================\n\nimport { access, rm } from 'node:fs/promises';\nimport { WORKTREE_DIR, TBD_DIR, DATA_SYNC_DIR_NAME, SYNC_BRANCH } from '../lib/paths.js';\n\n/**\n * Check if the hidden worktree exists and is valid.\n */\nexport async function worktreeExists(baseDir: string): Promise<boolean> {\n  const worktreePath = join(baseDir, WORKTREE_DIR);\n  try {\n    await access(worktreePath);\n    // Also verify it's a valid git worktree by checking for .git file\n    await access(join(worktreePath, '.git'));\n    return true;\n  } catch {\n    return false;\n  }\n}\n\n/**\n * Worktree health status.\n */\nexport interface WorktreeHealth {\n  exists: boolean;\n  valid: boolean;\n  branch: string | null;\n  commit: string | null;\n  error?: string;\n}\n\n/**\n * Check worktree health and return status.\n * See: tbd-design.md §2.3 Worktree Lifecycle\n */\nexport async function checkWorktreeHealth(baseDir: string): Promise<WorktreeHealth> {\n  const worktreePath = join(baseDir, WORKTREE_DIR);\n\n  // Check if worktree directory exists\n  try {\n    await access(worktreePath);\n  } catch {\n    return { exists: false, valid: false, branch: null, commit: null };\n  }\n\n  // Check if it's a valid git worktree\n  try {\n    await access(join(worktreePath, '.git'));\n  } catch {\n    return {\n      exists: true,\n      valid: false,\n      branch: null,\n      commit: null,\n      error: 'Worktree directory exists but is not a valid git worktree',\n    };\n  }\n\n  // Get current commit and branch info\n  try {\n    const commit = await git('-C', worktreePath, 'rev-parse', 'HEAD');\n    let branch: string | null = null;\n\n    try {\n      // Check if we're on detached HEAD pointing to tbd-sync\n      const refName = await git('-C', worktreePath, 'symbolic-ref', '-q', 'HEAD');\n      branch = refName.replace('refs/heads/', '');\n    } catch {\n      // Detached HEAD - expected state\n      branch = null;\n    }\n\n    return { exists: true, valid: true, branch, commit };\n  } catch (error) {\n    return {\n      exists: true,\n      valid: false,\n      branch: null,\n      commit: null,\n      error: error instanceof Error ? error.message : String(error),\n    };\n  }\n}\n\n/**\n * Initialize the hidden worktree for the tbd-sync branch.\n * Follows the decision tree from tbd-design.md §2.3.\n *\n * @param baseDir - The base directory of the repository\n * @param remote - The remote name (default: 'origin')\n * @param syncBranch - The sync branch name (default: 'tbd-sync')\n * @returns Path to the worktree or error message\n */\nexport async function initWorktree(\n  baseDir: string,\n  remote = 'origin',\n  syncBranch: string = SYNC_BRANCH,\n): Promise<{ success: boolean; path?: string; created?: boolean; error?: string }> {\n  const worktreePath = join(baseDir, WORKTREE_DIR);\n\n  // Check if worktree already exists and is valid\n  if (await worktreeExists(baseDir)) {\n    return { success: true, path: worktreePath, created: false };\n  }\n\n  // Remove any stale worktree directory\n  try {\n    await rm(worktreePath, { recursive: true, force: true });\n  } catch {\n    // Ignore errors - directory might not exist\n  }\n\n  try {\n    // Check if local branch exists\n    const localExists = await branchExists(syncBranch);\n    if (localExists) {\n      // Create worktree from local branch with detached HEAD\n      await git('-C', baseDir, 'worktree', 'add', worktreePath, syncBranch, '--detach');\n      return { success: true, path: worktreePath, created: true };\n    }\n\n    // Check if remote branch exists\n    const remoteExists = await remoteBranchExists(remote, syncBranch);\n    if (remoteExists) {\n      // Fetch and create worktree from remote branch\n      await git('-C', baseDir, 'fetch', remote, syncBranch);\n      await git(\n        '-C',\n        baseDir,\n        'worktree',\n        'add',\n        worktreePath,\n        `${remote}/${syncBranch}`,\n        '--detach',\n      );\n      return { success: true, path: worktreePath, created: true };\n    }\n\n    // No branch exists - create orphan worktree (requires Git 2.42+)\n    // Syntax: git worktree add --orphan -b <branch> <path>\n    await requireGitVersion();\n    await git('-C', baseDir, 'worktree', 'add', '--orphan', '-b', syncBranch, worktreePath);\n\n    // Initialize the data-sync directory structure in the worktree\n    const dataSyncPath = join(worktreePath, TBD_DIR, DATA_SYNC_DIR_NAME);\n    await mkdir(join(dataSyncPath, 'issues'), { recursive: true });\n    await mkdir(join(dataSyncPath, 'mappings'), { recursive: true });\n    await mkdir(join(dataSyncPath, 'attic', 'conflicts'), { recursive: true });\n\n    // Create initial commit in worktree\n    await writeFile(join(dataSyncPath, 'meta.yml'), 'schema_version: 1\\n');\n    await writeFile(join(dataSyncPath, 'issues', '.gitkeep'), '');\n    await writeFile(join(dataSyncPath, 'mappings', '.gitkeep'), '');\n\n    // Stage and commit the initial structure\n    await git('-C', worktreePath, 'add', '.');\n    await git('-C', worktreePath, 'commit', '-m', 'Initialize tbd-sync branch');\n\n    return { success: true, path: worktreePath, created: true };\n  } catch (error) {\n    return {\n      success: false,\n      error: error instanceof Error ? error.message : String(error),\n    };\n  }\n}\n\n/**\n * Update the hidden worktree to latest sync branch state.\n * Called after sync operations to ensure worktree reflects current state.\n *\n * @param baseDir - The base directory of the repository\n * @param remote - The remote name (default: 'origin')\n * @param syncBranch - The sync branch name (default: 'tbd-sync')\n */\nexport async function updateWorktree(\n  baseDir: string,\n  remote = 'origin',\n  syncBranch: string = SYNC_BRANCH,\n): Promise<{ success: boolean; error?: string }> {\n  const worktreePath = join(baseDir, WORKTREE_DIR);\n\n  // Ensure worktree exists\n  if (!(await worktreeExists(baseDir))) {\n    const initResult = await initWorktree(baseDir, remote, syncBranch);\n    if (!initResult.success) {\n      return { success: false, error: initResult.error };\n    }\n  }\n\n  try {\n    // Fetch latest from remote\n    try {\n      await git('-C', baseDir, 'fetch', remote, syncBranch);\n    } catch {\n      // Remote fetch may fail if offline - that's ok\n    }\n\n    // Get the latest commit on the sync branch\n    let targetCommit: string;\n    try {\n      // Try local branch first\n      targetCommit = await git('-C', baseDir, 'rev-parse', `refs/heads/${syncBranch}`);\n    } catch {\n      try {\n        // Fall back to remote tracking branch\n        targetCommit = await git(\n          '-C',\n          baseDir,\n          'rev-parse',\n          `refs/remotes/${remote}/${syncBranch}`,\n        );\n      } catch {\n        // No remote either - worktree is already at latest\n        return { success: true };\n      }\n    }\n\n    // Update worktree to that commit (detached HEAD)\n    await git('-C', worktreePath, 'checkout', '--detach', targetCommit);\n\n    return { success: true };\n  } catch (error) {\n    return {\n      success: false,\n      error: error instanceof Error ? error.message : String(error),\n    };\n  }\n}\n\n/**\n * Remove the hidden worktree.\n * Used by doctor --fix when worktree is corrupted.\n */\nexport async function removeWorktree(\n  baseDir: string,\n): Promise<{ success: boolean; error?: string }> {\n  const worktreePath = join(baseDir, WORKTREE_DIR);\n\n  try {\n    // First try to properly remove via git\n    try {\n      await git('-C', baseDir, 'worktree', 'remove', worktreePath, '--force');\n    } catch {\n      // If git worktree remove fails, just delete the directory\n      await rm(worktreePath, { recursive: true, force: true });\n    }\n\n    // Prune stale worktree references\n    await git('-C', baseDir, 'worktree', 'prune');\n\n    return { success: true };\n  } catch (error) {\n    return {\n      success: false,\n      error: error instanceof Error ? error.message : String(error),\n    };\n  }\n}\n","/**\n * `tbd init` - Initialize tbd in a repository.\n *\n * See: tbd-design.md §4.3 Initialization\n */\n\nimport { Command } from 'commander';\nimport { mkdir, stat } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { ensureGitignorePatterns } from '../../utils/gitignore-utils.js';\nimport { CLIError, ValidationError } from '../lib/errors.js';\nimport { VERSION } from '../lib/version.js';\nimport { initConfig } from '../../file/config.js';\nimport {\n  TBD_DIR,\n  WORKTREE_DIR_NAME,\n  DATA_SYNC_DIR_NAME,\n  SYNC_BRANCH,\n  TBD_SHORTCUTS_SYSTEM,\n  TBD_SHORTCUTS_STANDARD,\n  TBD_GUIDELINES_DIR,\n  TBD_TEMPLATES_DIR,\n  TBD_DOCS_DIR,\n} from '../../lib/paths.js';\nimport { initWorktree, checkGitVersion, MIN_GIT_VERSION } from '../../file/git.js';\n\ninterface InitOptions {\n  prefix?: string;\n  syncBranch?: string;\n  remote?: string;\n}\n\nclass InitHandler extends BaseCommand {\n  async run(options: InitOptions): Promise<void> {\n    const cwd = process.cwd();\n\n    // Check if already initialized\n    try {\n      await stat(join(cwd, TBD_DIR));\n      throw new CLIError('tbd is already initialized in this directory');\n    } catch (error) {\n      // Not initialized - continue (unless it's our CLIError)\n      if (error instanceof CLIError) throw error;\n    }\n\n    // Validate prefix is provided\n    if (!options.prefix) {\n      throw new ValidationError(\n        'The --prefix option is required\\n\\n' +\n          'Usage: tbd init --prefix=<name>\\n\\n' +\n          'The prefix is used for display IDs (e.g., proj-a7k2, myapp-b3m9)\\n' +\n          'Choose a short 2-4 letter prefix for your project (e.g., tbd, myp).\\n\\n' +\n          'For full setup with integrations: tbd setup --auto --prefix=<name>',\n      );\n    }\n\n    if (this.checkDryRun('Would initialize tbd repository', options)) {\n      return;\n    }\n\n    await this.execute(async () => {\n      // 1. Create .tbd/ directory with config.yml\n      // Note: options.prefix is validated to be non-null above\n      await initConfig(cwd, VERSION, options.prefix!);\n      this.output.debug(`Created ${TBD_DIR}/config.yml with prefix '${options.prefix}'`);\n\n      // 2. Create .tbd/.gitignore (idempotent)\n      // Per spec: Must ignore docs/, data-sync-worktree/, and data-sync/\n      await ensureGitignorePatterns(join(cwd, TBD_DIR, '.gitignore'), [\n        '# Installed documentation (regenerated on setup)',\n        'docs/',\n        '',\n        '# Hidden worktree for tbd-sync branch',\n        `${WORKTREE_DIR_NAME}/`,\n        '',\n        '# Data sync directory (only exists in worktree)',\n        `${DATA_SYNC_DIR_NAME}/`,\n        '',\n        '# Local state',\n        'state.yml',\n        '',\n        '# Temporary files',\n        '*.tmp',\n        '*.temp',\n      ]);\n      this.output.debug(`Created ${TBD_DIR}/.gitignore`);\n\n      // 3. Create docs directories for shortcuts, guidelines, and templates\n      await mkdir(join(cwd, TBD_SHORTCUTS_SYSTEM), { recursive: true });\n      await mkdir(join(cwd, TBD_SHORTCUTS_STANDARD), { recursive: true });\n      await mkdir(join(cwd, TBD_GUIDELINES_DIR), { recursive: true });\n      await mkdir(join(cwd, TBD_TEMPLATES_DIR), { recursive: true });\n      this.output.debug(`Created ${TBD_DOCS_DIR}/ directories`);\n\n      // 4. Initialize the hidden worktree for tbd-sync branch\n      // This creates .tbd/data-sync-worktree/ with the sync branch checkout\n      const remote = options.remote ?? 'origin';\n      const syncBranch = options.syncBranch ?? SYNC_BRANCH;\n\n      // Check Git version before attempting worktree creation\n      // Git 2.42+ is required for --orphan worktree support\n      try {\n        const { version, supported } = await checkGitVersion();\n        if (!supported) {\n          const versionStr = `${version.major}.${version.minor}.${version.patch}`;\n          throw new CLIError(\n            `Git ${versionStr} detected. Git ${MIN_GIT_VERSION}+ is required for tbd.\\n\\n` +\n              `tbd requires Git 2.42+ for orphan worktree support.\\n` +\n              `Please upgrade Git: https://git-scm.com/downloads`,\n          );\n        }\n        this.output.debug(`Git version ${version.major}.${version.minor}.${version.patch} OK`);\n      } catch (error) {\n        // If git is not installed at all, let worktree init handle it\n        if (error instanceof CLIError) throw error;\n        this.output.debug(`Git version check skipped: ${(error as Error).message}`);\n      }\n\n      const worktreeResult = await initWorktree(cwd, remote, syncBranch);\n\n      if (worktreeResult.success) {\n        if (worktreeResult.created) {\n          this.output.debug(`Created hidden worktree at ${TBD_DIR}/${WORKTREE_DIR_NAME}/`);\n        } else {\n          this.output.debug(`Worktree already exists at ${TBD_DIR}/${WORKTREE_DIR_NAME}/`);\n        }\n      } else {\n        // Worktree creation failed - this is ok if not in a git repo\n        // Log warning but don't fail init (supports non-git usage)\n        this.output.debug(`Note: Worktree not created (${worktreeResult.error})`);\n      }\n    }, 'Failed to initialize tbd');\n\n    this.output.data({ initialized: true, version: VERSION, prefix: options.prefix }, () => {\n      this.output.success(`Initialized tbd repository (prefix: ${options.prefix})`);\n      // Only show next steps if not in quiet mode\n      if (!this.output.isQuiet()) {\n        console.log('');\n        console.log('Next steps:');\n        console.log('  git add .tbd/ && git commit -m \"Initialize tbd\"');\n        console.log('  tbd setup --auto   # Optional: configure agent integrations');\n      }\n    });\n  }\n}\n\nexport const initCommand = new Command('init')\n  .description('Initialize tbd in a git repository')\n  .option('--prefix <name>', 'Project prefix for display IDs (e.g., \"proj\", \"myapp\")')\n  .option('--sync-branch <name>', 'Sync branch name (default: tbd-sync)')\n  .option('--remote <name>', 'Remote name (default: origin)')\n  .action(async (options, command) => {\n    const handler = new InitHandler(command);\n    await handler.run(options);\n  });\n","/**\n * ID generation and validation utilities.\n *\n * The system uses dual IDs for usability:\n * - Internal ID: is-{ulid} - ULID-based (26 lowercase chars), stored in files\n * - External ID: {prefix}-{short} - 4-5 base36 chars for CLI display/input\n *\n * For Beads compatibility, bd- prefix is accepted on input for external IDs.\n *\n * See: tbd-design.md §2.5 ID Generation\n */\n\nimport { ulid } from 'ulid';\nimport { randomBytes } from 'node:crypto';\n\n/**\n * Prefix for internal IDs (ULID-based).\n * All internal IDs are formatted as: {INTERNAL_ID_PREFIX}-{ulid}\n */\nexport const INTERNAL_ID_PREFIX = 'is';\n\n/**\n * Length of internal ID prefix including the hyphen (e.g., \"is-\" = 3).\n */\nexport const INTERNAL_ID_PREFIX_LENGTH = INTERNAL_ID_PREFIX.length + 1;\n\n/**\n * Construct an internal ID from a ULID.\n *\n * @param ulidValue - The ULID (26 chars)\n * @returns Internal ID in format {prefix}-{ulid}\n */\nexport function makeInternalId(ulidValue: string): string {\n  return `${INTERNAL_ID_PREFIX}-${ulidValue.toLowerCase()}`;\n}\n\n/**\n * Generate a unique internal ID using ULID.\n * Format: is-{ulid} (26 lowercase alphanumeric chars)\n * Example: is-01hx5zzkbkactav9wevgemmvrz\n *\n * ULID provides:\n * - Time-ordered sorting (48-bit timestamp)\n * - 80-bit randomness (no collisions)\n * - Lexicographic sort = chronological order\n */\nexport function generateInternalId(): string {\n  return makeInternalId(ulid());\n}\n\n/**\n * Generate a short ID for external display.\n * Format: base36 characters (a-z, 0-9)\n * Example: a7k2\n *\n * @param length - Number of characters (default 4)\n */\nexport function generateShortId(length = 4): string {\n  const chars = '0123456789abcdefghijklmnopqrstuvwxyz';\n  let result = '';\n  const bytes = randomBytes(length);\n  for (let i = 0; i < length; i++) {\n    result += chars[bytes[i]! % 36];\n  }\n  return result;\n}\n\n// Regex pattern for validating internal IDs - built from prefix constant\nconst INTERNAL_ID_PATTERN = new RegExp(`^${INTERNAL_ID_PREFIX}-[0-9a-z]{26}$`);\n\n// Expected length of a full internal ID (prefix + hyphen + 26-char ULID)\nconst INTERNAL_ID_LENGTH = INTERNAL_ID_PREFIX_LENGTH + 26;\n\n/**\n * Validate an internal issue ID matches the ULID format.\n * Format: {prefix}-{26 lowercase alphanumeric chars}\n */\nexport function validateIssueId(id: string): boolean {\n  return INTERNAL_ID_PATTERN.test(id);\n}\n\n/**\n * Validate a short/external ID format.\n * Format: 1+ base36 characters (typically 4 for new IDs, but imports may preserve longer IDs).\n */\nexport function validateShortId(id: string): boolean {\n  return /^[0-9a-z]+$/.test(id);\n}\n\n/**\n * Check if an input looks like an internal ID (ULID-based).\n */\nexport function isInternalId(input: string): boolean {\n  const lower = input.toLowerCase();\n  // Check if it starts with the internal prefix and has correct length\n  const prefixWithHyphen = `${INTERNAL_ID_PREFIX}-`;\n  if (lower.startsWith(prefixWithHyphen) && lower.length === INTERNAL_ID_LENGTH) {\n    return INTERNAL_ID_PATTERN.test(lower);\n  }\n  return false;\n}\n\n/**\n * Check if an input looks like a short/external ID.\n * Returns true for IDs like \"a7k2\", \"bd-a7k2\", \"100\", \"tbd-100\".\n * Short IDs are 16 characters or less (ULIDs are 26 characters).\n */\nexport function isShortId(input: string): boolean {\n  const lower = input.toLowerCase();\n  // Strip prefix if present\n  const stripped = lower.replace(/^[a-z]+-/, '');\n  // Must be 1-16 alphanumeric chars (short IDs, not ULIDs which are 26 chars)\n  return /^[0-9a-z]+$/.test(stripped) && stripped.length >= 1 && stripped.length <= 16;\n}\n\n/**\n * Extract the short ID portion from an external ID.\n * Examples:\n *   \"tbd-100\" -> \"100\"\n *   \"bd-a7k2\" -> \"a7k2\"\n *   \"a7k2\" -> \"a7k2\"\n *   \"100\" -> \"100\"\n */\nexport function extractShortId(externalId: string): string {\n  return externalId.toLowerCase().replace(/^[a-z]+-/, '');\n}\n\n/**\n * Extract the prefix portion from an external ID.\n * Returns the prefix (letters before the hyphen) or null if no prefix found.\n * Examples:\n *   \"tbd-100\" -> \"tbd\"\n *   \"bd-a7k2\" -> \"bd\"\n *   \"TBD-100\" -> \"tbd\" (normalized to lowercase)\n *   \"a7k2\" -> null (no prefix)\n *   \"100\" -> null (no prefix)\n */\nexport function extractPrefix(externalId: string): string | null {\n  const match = /^([a-zA-Z]+)-/.exec(externalId);\n  return match?.[1]?.toLowerCase() ?? null;\n}\n\n/**\n * Extract the ULID portion from an internal ID.\n *\n * Internal IDs have the format: {prefix}-{ulid}\n * This function strips any prefix to return just the ULID.\n *\n * Examples:\n *   \"is-01hx5zzkbkactav9wevgemmvrz\" -> \"01hx5zzkbkactav9wevgemmvrz\"\n *   \"01hx5zzkbkactav9wevgemmvrz\" -> \"01hx5zzkbkactav9wevgemmvrz\" (no prefix)\n *\n * @param internalId - The internal ID (with or without prefix)\n * @returns The ULID portion without any prefix\n */\nexport function extractUlidFromInternalId(internalId: string): string {\n  // Strip any prefix in format {letters}- (e.g., \"is-\", \"bd-\")\n  return internalId.toLowerCase().replace(/^[a-z]+-/, '');\n}\n\n/** Prefix used in Beads for compatibility */\nconst BEADS_COMPAT_PREFIX = 'bd';\n\n/**\n * Normalize an internal issue ID.\n *\n * This function expects a full internal ID ({prefix}-{ulid}).\n * If given a short ID, it won't be able to resolve it without\n * access to the ID mapping.\n *\n * Handles:\n * - Uppercase (converts to lowercase)\n * - Ensures internal ID prefix\n * - Beads compatibility (bd- prefix)\n */\nexport function normalizeIssueId(input: string): string {\n  const lower = input.toLowerCase();\n  const internalPrefixWithHyphen = `${INTERNAL_ID_PREFIX}-`;\n  const beadsPrefixWithHyphen = `${BEADS_COMPAT_PREFIX}-`;\n\n  // If already a valid internal ID, return as-is\n  if (validateIssueId(lower)) {\n    return lower;\n  }\n\n  // If it starts with internal prefix but wrong length, might be corrupted\n  if (lower.startsWith(internalPrefixWithHyphen)) {\n    return lower; // Return as-is, let validation fail later\n  }\n\n  // If it starts with bd- (Beads compat), convert prefix\n  if (lower.startsWith(beadsPrefixWithHyphen)) {\n    const rest = lower.slice(beadsPrefixWithHyphen.length);\n    if (rest.length === 26) {\n      return makeInternalId(rest);\n    }\n    // Short ID - can't resolve without mapping\n    return lower;\n  }\n\n  // Bare ID without prefix\n  if (lower.length === 26 && /^[0-9a-z]{26}$/.test(lower)) {\n    return makeInternalId(lower);\n  }\n\n  // Can't normalize - return as-is\n  return lower;\n}\n\nimport type { IdMapping } from '../file/id-mapping.js';\n\n/**\n * Format an internal ID for display with the configured prefix.\n *\n * Uses the short ID (4 chars) from the mapping.\n * Throws an error if the mapping is missing or doesn't contain the ID.\n *\n * IMPORTANT: All user-facing output MUST use short IDs, never internal ULIDs.\n * If you see a ULID in user output, it's a bug.\n *\n * @param internalId - The internal ID (is-{ulid})\n * @param mapping - ID mapping for short ID lookup (required)\n * @param prefix - Display prefix (should come from config.display.id_prefix; defaults to 'tbd' as fallback)\n * @throws Error if mapping is missing or ID not found in mapping\n */\nexport function formatDisplayId(internalId: string, mapping: IdMapping, prefix = 'tbd'): string {\n  // Extract the ULID portion\n  const ulidPart = extractUlidFromInternalId(internalId);\n\n  // Get short ID from mapping\n  const shortId = mapping.ulidToShort.get(ulidPart);\n  if (!shortId) {\n    throw new Error(\n      `No short ID mapping found for internal ID: ${internalId}. ` +\n        `This is a bug - all issues must have a short ID mapping.`,\n    );\n  }\n\n  return `${prefix}-${shortId}`;\n}\n\n/**\n * Format an ID for debug output, showing both public and internal IDs.\n *\n * @param internalId - The internal ID (is-{ulid})\n * @param mapping - ID mapping for short ID lookup\n * @param prefix - Display prefix (should come from config.display.id_prefix; defaults to 'tbd' as fallback)\n */\nexport function formatDebugId(internalId: string, mapping: IdMapping, prefix = 'tbd'): string {\n  const displayId = formatDisplayId(internalId, mapping, prefix);\n  return `${displayId} (${internalId})`;\n}\n","/**\n * Storage layer for issue files.\n *\n * Provides atomic file operations and issue CRUD operations.\n * All operations work on the hidden worktree at .tbd/data-sync/issues/.\n *\n * See: tbd-design.md §3.2 Storage Layer\n */\n\nimport { readFile, unlink, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { writeFile } from 'atomically';\n\nimport type { Issue } from '../lib/types.js';\nimport { parseIssue, serializeIssue } from './parser.js';\n\n/**\n * Get the path to an issue file.\n */\nfunction getIssuePath(baseDir: string, id: string): string {\n  return join(baseDir, 'issues', `${id}.md`);\n}\n\n/**\n * Read an issue from the worktree.\n * @throws If the issue file doesn't exist or is invalid.\n */\nexport async function readIssue(baseDir: string, id: string): Promise<Issue> {\n  const filePath = getIssuePath(baseDir, id);\n  const content = await readFile(filePath, 'utf-8');\n  return parseIssue(content);\n}\n\n/**\n * Write an issue to the worktree.\n * Uses atomic write to prevent corruption.\n */\nexport async function writeIssue(baseDir: string, issue: Issue): Promise<void> {\n  const filePath = getIssuePath(baseDir, issue.id);\n  const content = serializeIssue(issue);\n  await writeFile(filePath, content);\n}\n\n/**\n * List all issues in the worktree.\n * Returns empty array if issues directory doesn't exist.\n *\n * Uses parallel file reading for better performance with many issues.\n */\nexport async function listIssues(baseDir: string): Promise<Issue[]> {\n  const issuesDir = join(baseDir, 'issues');\n\n  let files: string[];\n  try {\n    files = await readdir(issuesDir);\n  } catch {\n    // Directory doesn't exist - return empty\n    return [];\n  }\n\n  // Filter to only .md files\n  const mdFiles = files.filter((f) => f.endsWith('.md'));\n\n  // Read all files in parallel for better I/O performance\n  const fileContents = await Promise.all(\n    mdFiles.map(async (file) => {\n      const filePath = join(issuesDir, file);\n      try {\n        const content = await readFile(filePath, 'utf-8');\n        return { file, content };\n      } catch {\n        return { file, content: null };\n      }\n    }),\n  );\n\n  // Parse issues (filter out failed reads)\n  const issues: Issue[] = [];\n  for (const { file, content } of fileContents) {\n    if (content === null) continue;\n    try {\n      const issue = parseIssue(content);\n      issues.push(issue);\n    } catch (error) {\n      // Skip invalid files with a warning\n      console.warn(`Skipping invalid issue file: ${file}`, error);\n    }\n  }\n\n  return issues;\n}\n\n/**\n * Delete an issue from the worktree.\n * Does not throw if issue doesn't exist.\n */\nexport async function deleteIssue(baseDir: string, id: string): Promise<void> {\n  const filePath = getIssuePath(baseDir, id);\n  try {\n    await unlink(filePath);\n  } catch (error) {\n    // Ignore ENOENT (file doesn't exist)\n    if ((error as NodeJS.ErrnoException).code !== 'ENOENT') {\n      throw error;\n    }\n  }\n}\n","/**\n * Natural sort utilities.\n *\n * Provides alphanumeric sorting where numeric portions are sorted numerically.\n * Similar to `sort -V` (version sort) or `sort -n` for numbers.\n *\n * Examples:\n *   [\"1\", \"2\", \"9\", \"10\", \"11\"] instead of [\"1\", \"10\", \"11\", \"2\", \"9\"]\n *   [\"a1\", \"a2\", \"a10\"] instead of [\"a1\", \"a10\", \"a2\"]\n *   [\"file1.txt\", \"file2.txt\", \"file10.txt\"] instead of [\"file1.txt\", \"file10.txt\", \"file2.txt\"]\n */\n\n/**\n * Split a string into alternating runs of digits and non-digits.\n * @param str - The string to split\n * @returns Array of [isNumeric, value] tuples\n */\nfunction splitIntoChunks(str: string): [boolean, string][] {\n  const chunks: [boolean, string][] = [];\n  let current = '';\n  let currentIsNumeric: boolean | null = null;\n\n  for (const char of str) {\n    const isDigit = char >= '0' && char <= '9';\n\n    if (currentIsNumeric === null) {\n      // First character\n      currentIsNumeric = isDigit;\n      current = char;\n    } else if (isDigit === currentIsNumeric) {\n      // Same type, continue accumulating\n      current += char;\n    } else {\n      // Type changed, push current chunk and start new one\n      chunks.push([currentIsNumeric, current]);\n      currentIsNumeric = isDigit;\n      current = char;\n    }\n  }\n\n  // Push final chunk\n  if (current) {\n    chunks.push([currentIsNumeric!, current]);\n  }\n\n  return chunks;\n}\n\n/**\n * Compare two strings using natural (alphanumeric) ordering.\n *\n * Numeric portions are compared numerically, non-numeric portions are\n * compared lexicographically (case-insensitive). Numbers sort before letters\n * when they appear at the same position in mixed comparisons, matching\n * the behavior of `sort -V` (version sort).\n *\n * @param a - First string\n * @param b - Second string\n * @returns Negative if a < b, positive if a > b, zero if equal\n */\nexport function naturalCompare(a: string, b: string): number {\n  // Handle empty strings\n  if (!a && !b) return 0;\n  if (!a) return -1;\n  if (!b) return 1;\n\n  const chunksA = splitIntoChunks(a);\n  const chunksB = splitIntoChunks(b);\n\n  const minLen = Math.min(chunksA.length, chunksB.length);\n\n  for (let i = 0; i < minLen; i++) {\n    const [isNumericA, valueA] = chunksA[i]!;\n    const [isNumericB, valueB] = chunksB[i]!;\n\n    if (isNumericA && isNumericB) {\n      // Both are numeric - compare as numbers\n      const numA = parseInt(valueA, 10);\n      const numB = parseInt(valueB, 10);\n      if (numA !== numB) {\n        return numA - numB;\n      }\n      // If numerically equal but different strings (e.g., \"01\" vs \"1\"),\n      // prefer shorter (fewer leading zeros)\n      if (valueA.length !== valueB.length) {\n        return valueA.length - valueB.length;\n      }\n    } else if (!isNumericA && !isNumericB) {\n      // Both are non-numeric - compare lexicographically (case-insensitive)\n      const lowerA = valueA.toLowerCase();\n      const lowerB = valueB.toLowerCase();\n      if (lowerA !== lowerB) {\n        return lowerA.localeCompare(lowerB);\n      }\n      // Same when lowercased - they're equal for sorting purposes\n    } else {\n      // Mixed: numeric comes before non-numeric\n      // (so \"1\" comes before \"a\" at the same position)\n      // This matches `sort -V` behavior\n      return isNumericA ? -1 : 1;\n    }\n  }\n\n  // All compared chunks are equal, shorter string comes first\n  return chunksA.length - chunksB.length;\n}\n\n/**\n * Sort an array of strings using natural (alphanumeric) ordering.\n *\n * @param arr - Array to sort\n * @returns New sorted array (does not mutate original)\n */\nexport function naturalSort(arr: readonly string[]): string[] {\n  return [...arr].sort(naturalCompare);\n}\n\n/**\n * Sort an array of objects by a string key using natural ordering.\n *\n * @param arr - Array to sort\n * @param keyFn - Function to extract the sort key from each element\n * @returns New sorted array (does not mutate original)\n */\nexport function naturalSortBy<T>(arr: readonly T[], keyFn: (item: T) => string): T[] {\n  return [...arr].sort((a, b) => naturalCompare(keyFn(a), keyFn(b)));\n}\n","/**\n * ID mapping management for short public IDs.\n *\n * Maps 4-char base36 short IDs to 26-char ULIDs.\n * Stored in .tbd/data-sync/mappings/ids.yml\n *\n * See: tbd-design.md §2.5 ID Generation\n */\n\nimport { readFile, mkdir } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { writeFile } from 'atomically';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\n\nimport {\n  generateShortId,\n  extractUlidFromInternalId,\n  makeInternalId,\n  isInternalId,\n  extractShortId,\n} from '../lib/ids.js';\nimport { naturalSort } from '../lib/sort.js';\n\n/**\n * ID mapping from short ID to ULID.\n * Format in ids.yml:\n *   a7k2: 01hx5zzkbkactav9wevgemmvrz\n *   b3m9: 01hx5zzkbkbctav9wevgemmvrz\n */\nexport interface IdMapping {\n  shortToUlid: Map<string, string>;\n  ulidToShort: Map<string, string>;\n}\n\n/**\n * Get the path to the ids.yml mapping file.\n */\nfunction getMappingPath(baseDir: string): string {\n  return join(baseDir, 'mappings', 'ids.yml');\n}\n\n/**\n * Load the ID mapping from disk.\n * Returns empty mapping if file doesn't exist.\n */\nexport async function loadIdMapping(baseDir: string): Promise<IdMapping> {\n  const filePath = getMappingPath(baseDir);\n\n  let content: string;\n  try {\n    content = await readFile(filePath, 'utf-8');\n  } catch {\n    // File doesn't exist - return empty mapping\n    return {\n      shortToUlid: new Map(),\n      ulidToShort: new Map(),\n    };\n  }\n\n  const data = (parseYaml(content) as Record<string, string>) || {};\n\n  const shortToUlid = new Map<string, string>();\n  const ulidToShort = new Map<string, string>();\n\n  for (const [shortId, ulid] of Object.entries(data)) {\n    shortToUlid.set(shortId, ulid);\n    ulidToShort.set(ulid, shortId);\n  }\n\n  return { shortToUlid, ulidToShort };\n}\n\n/**\n * Save the ID mapping to disk.\n */\nexport async function saveIdMapping(baseDir: string, mapping: IdMapping): Promise<void> {\n  const filePath = getMappingPath(baseDir);\n\n  // Ensure directory exists\n  await mkdir(dirname(filePath), { recursive: true });\n\n  // Convert Map to sorted object for deterministic output\n  // Use natural sort so \"1\", \"2\", \"10\" sorts correctly (not \"1\", \"10\", \"2\")\n  const data: Record<string, string> = {};\n  const sortedKeys = naturalSort(Array.from(mapping.shortToUlid.keys()));\n  for (const key of sortedKeys) {\n    data[key] = mapping.shortToUlid.get(key)!;\n  }\n\n  const content = stringifyYaml(data);\n  await writeFile(filePath, content);\n}\n\n/**\n * Calculate the optimal short ID length based on existing ID count.\n *\n * At 50K issues, switches from 4-char to 5-char IDs to keep\n * collision probability low (~3% per attempt with 4 chars at 50K).\n *\n * With 10 retries per length, actual failure probability is astronomically low.\n */\nexport function calculateOptimalLength(existingCount: number): number {\n  return existingCount < 50_000 ? 4 : 5;\n}\n\n/**\n * Generate a unique short ID that doesn't collide with existing ones.\n *\n * Calculates optimal length (4 or 5 chars) based on existing ID count,\n * then retries with the next length if collisions occur.\n *\n * @returns The new short ID\n * @throws If unable to generate a unique ID after max attempts\n */\nexport function generateUniqueShortId(mapping: IdMapping): string {\n  const ATTEMPTS_PER_LENGTH = 10;\n  const existingCount = mapping.shortToUlid.size;\n  const optimalLength = calculateOptimalLength(existingCount);\n\n  // Try optimal length first, then fall back to longer if needed\n  for (const length of [optimalLength, optimalLength + 1]) {\n    for (let attempt = 0; attempt < ATTEMPTS_PER_LENGTH; attempt++) {\n      const shortId = generateShortId(length);\n      if (!mapping.shortToUlid.has(shortId)) {\n        return shortId;\n      }\n    }\n  }\n\n  throw new Error(\n    `Failed to generate unique short ID after 20 attempts with ${existingCount} existing IDs. ` +\n      `This should be extremely rare - please report if you see this error.`,\n  );\n}\n\n/**\n * Register a new ID mapping.\n * @param ulid - The ULID (without is- prefix)\n * @param shortId - The short ID (4 chars)\n */\nexport function addIdMapping(mapping: IdMapping, ulid: string, shortId: string): void {\n  mapping.shortToUlid.set(shortId, ulid);\n  mapping.ulidToShort.set(ulid, shortId);\n}\n\n/**\n * Get the short ID for a ULID.\n * @param ulid - The ULID (without is- prefix)\n * @returns The short ID, or undefined if not found\n */\nexport function getShortId(mapping: IdMapping, ulid: string): string | undefined {\n  return mapping.ulidToShort.get(ulid);\n}\n\n/**\n * Get the ULID for a short ID.\n * @param shortId - The short ID\n * @returns The ULID (without is- prefix), or undefined if not found\n */\nexport function getUlid(mapping: IdMapping, shortId: string): string | undefined {\n  return mapping.shortToUlid.get(shortId);\n}\n\n/**\n * Check if a short ID exists in the mapping.\n */\nexport function hasShortId(mapping: IdMapping, shortId: string): boolean {\n  return mapping.shortToUlid.has(shortId);\n}\n\n/**\n * Create a short ID mapping for a new internal ID.\n * Generates a unique short ID and registers it in the mapping.\n *\n * @param internalId - The internal ID (is-{ulid})\n * @param mapping - The ID mapping to update\n * @returns The generated short ID\n */\nexport function createShortIdMapping(internalId: string, mapping: IdMapping): string {\n  // Extract ULID from internal ID (remove prefix)\n  const ulid = extractUlidFromInternalId(internalId);\n\n  // Check if already mapped\n  const existing = mapping.ulidToShort.get(ulid);\n  if (existing) {\n    return existing;\n  }\n\n  // Generate unique short ID\n  const shortId = generateUniqueShortId(mapping);\n\n  // Register mapping\n  addIdMapping(mapping, ulid, shortId);\n\n  return shortId;\n}\n\n/**\n * Resolve any ID input to an internal ID ({prefix}-{ulid}).\n *\n * Handles:\n * - Internal IDs: {prefix}-{ulid} -> {prefix}-{ulid}\n * - Short IDs: a7k2 -> {prefix}-{ulid from mapping}\n * - Prefixed short IDs: bd-a7k2 -> {prefix}-{ulid from mapping}\n *\n * @param input - The ID input (short ID, prefixed short ID, or internal ID)\n * @param mapping - The ID mapping for short ID resolution\n * @returns The internal ID ({prefix}-{ulid})\n * @throws If the short ID is not found in the mapping\n */\nexport function resolveToInternalId(input: string, mapping: IdMapping): string {\n  const lower = input.toLowerCase();\n\n  // If it's already an internal ID, return it\n  if (isInternalId(lower)) {\n    return lower;\n  }\n\n  // Extract the short ID portion (strips any prefix like \"bd-\" or \"is-\")\n  const shortId = extractShortId(lower);\n\n  // If it's a full ULID (26 chars), it might be a bare internal ID\n  if (shortId.length === 26 && /^[0-9a-z]{26}$/.test(shortId)) {\n    return makeInternalId(shortId);\n  }\n\n  // Must be a short ID - look it up in the mapping\n  const ulid = mapping.shortToUlid.get(shortId);\n  if (!ulid) {\n    throw new Error(`Unknown issue ID: ${input}. ` + `Short ID \"${shortId}\" not found in mapping.`);\n  }\n\n  return makeInternalId(ulid);\n}\n","/**\n * Priority formatting and parsing utilities.\n *\n * Priority values range from 0 (critical) to 4 (backlog).\n * Display format uses \"P\" prefix: P0, P1, P2, P3, P4.\n */\n\nimport type { createColors } from '../cli/lib/output.js';\n\n/**\n * Valid priority values.\n */\nexport const MIN_PRIORITY = 0;\nexport const MAX_PRIORITY = 4;\n\n/**\n * Format a priority number for display.\n * Always uses \"P\" prefix format.\n *\n * @example formatPriority(0) → \"P0\"\n * @example formatPriority(2) → \"P2\"\n */\nexport function formatPriority(priority: number): string {\n  return `P${priority}`;\n}\n\n/**\n * Parse a priority string to a number.\n * Accepts both numeric (\"1\") and prefixed (\"P1\") formats.\n * Case-insensitive for prefixed format.\n *\n * @example parsePriority(\"P1\") → 1\n * @example parsePriority(\"p0\") → 0\n * @example parsePriority(\"2\") → 2\n * @example parsePriority(\"invalid\") → undefined\n *\n * @returns The priority number, or undefined if invalid.\n */\nexport function parsePriority(input: string): number | undefined {\n  const trimmed = input.trim().toUpperCase();\n  if (!trimmed) return undefined;\n\n  let numStr: string;\n  if (trimmed.startsWith('P')) {\n    // Prefixed format: P0, P1, etc.\n    if (trimmed.length !== 2) return undefined;\n    numStr = trimmed.slice(1);\n  } else {\n    // Numeric format: 0, 1, etc.\n    numStr = trimmed;\n  }\n\n  const num = parseInt(numStr, 10);\n  if (isNaN(num) || num < MIN_PRIORITY || num > MAX_PRIORITY) {\n    return undefined;\n  }\n\n  return num;\n}\n\n/**\n * Get the color function for a priority value.\n *\n * - P0 (critical): red\n * - P1 (high): yellow\n * - P2-P4: no color (identity function)\n *\n * @param priority - The priority number (0-4)\n * @param colors - The colors object from createColors()\n * @returns A function that applies the appropriate color\n */\nexport function getPriorityColor(\n  priority: number,\n  colors: ReturnType<typeof createColors>,\n): (s: string) => string {\n  switch (priority) {\n    case 0:\n      return colors.error;\n    case 1:\n      return colors.warn;\n    default:\n      return (s) => s;\n  }\n}\n","/**\n * Generic project path utilities for handling user-provided paths.\n *\n * This module provides reusable functions for resolving, validating, and\n * normalizing paths relative to a project root. It is designed to be\n * general-purpose and not tied to any specific use case (e.g., specs).\n *\n * Key features:\n * - Resolves absolute, relative, and subdirectory paths to project-relative paths\n * - Validates that paths stay within project boundaries\n * - Normalizes paths (removes ./, converts backslashes, etc.)\n * - Validates file existence\n */\n\nimport { resolve, relative, isAbsolute, normalize, sep } from 'node:path';\nimport { access, stat } from 'node:fs/promises';\n\n/**\n * Result of resolving a path relative to the project root.\n */\nexport interface ResolvedProjectPath {\n  /** Path relative to project root (always uses forward slashes) */\n  relativePath: string;\n  /** Absolute path to the file */\n  absolutePath: string;\n}\n\n/**\n * Error thrown when a path operation fails.\n * The message is user-friendly and can be displayed directly.\n */\nexport class ProjectPathError extends Error {\n  constructor(\n    message: string,\n    public readonly code: 'OUTSIDE_PROJECT' | 'NOT_FOUND' | 'NOT_A_FILE',\n  ) {\n    super(message);\n    this.name = 'ProjectPathError';\n  }\n}\n\n/**\n * Converts a ProjectPathError to a user-friendly error message for CLI display.\n * Returns the error message if it's a ProjectPathError, otherwise re-throws.\n */\nexport function getPathErrorMessage(error: unknown): string {\n  if (error instanceof ProjectPathError) {\n    return error.message;\n  }\n  throw error;\n}\n\n/**\n * Normalizes a path by:\n * - Removing leading ./\n * - Converting backslashes to forward slashes (Windows compatibility)\n * - Removing redundant slashes\n * - Resolving . and .. components\n *\n * @param inputPath - The path to normalize\n * @returns Normalized path string\n */\nexport function normalizePath(inputPath: string): string {\n  if (!inputPath) {\n    return '';\n  }\n\n  // First, convert all backslashes to forward slashes (Windows compatibility)\n  // This must happen BEFORE normalize() since backslashes aren't path separators on Linux\n  let normalized = inputPath.replace(/\\\\/g, '/');\n\n  // Use Node's normalize to handle . and .. components\n  // (normalize on Linux won't touch forward slashes)\n  normalized = normalize(normalized);\n\n  // Ensure we still have forward slashes after normalize (in case of mixed separators)\n  normalized = normalized.split(sep).join('/');\n\n  // Remove leading ./\n  while (normalized.startsWith('./')) {\n    normalized = normalized.slice(2);\n  }\n\n  // Remove trailing slash (unless it's just \"/\")\n  if (normalized.length > 1 && normalized.endsWith('/')) {\n    normalized = normalized.slice(0, -1);\n  }\n\n  // Handle edge case where normalize returns '.'\n  if (normalized === '.') {\n    return '';\n  }\n\n  return normalized;\n}\n\n/**\n * Checks if an absolute path is within the project root.\n *\n * @param absolutePath - The absolute path to check\n * @param projectRoot - The project root directory\n * @returns true if the path is within or at the project root\n */\nexport function isPathWithinProject(absolutePath: string, projectRoot: string): boolean {\n  // Normalize both paths for consistent comparison\n  const normalizedPath = resolve(absolutePath);\n  const normalizedRoot = resolve(projectRoot);\n\n  // The path is within the project if it starts with the project root\n  // We need to handle the case where the path IS the project root\n  // or is a subdirectory of it\n  if (normalizedPath === normalizedRoot) {\n    return true;\n  }\n\n  // Check if path starts with root + separator\n  // This prevents false positives like /project-backup matching /project\n  return normalizedPath.startsWith(normalizedRoot + sep);\n}\n\n/**\n * Resolves any path (absolute, relative, or from subdirectory) to a project-relative path.\n *\n * Resolution rules:\n * 1. Absolute paths within project → convert to relative\n * 2. Absolute paths outside project → error\n * 3. Relative paths from subdirectory → resolve to project root\n * 4. Already project-relative → pass through with normalization\n * 5. Path escaping project (../../) → error\n *\n * @param inputPath - The path provided by the user (can be absolute or relative)\n * @param projectRoot - The project root directory (parent of .tbd/)\n * @param cwd - Current working directory (where command was run)\n * @returns Resolved paths object with both relative and absolute paths\n * @throws ProjectPathError if path is outside project\n */\nexport function resolveProjectPath(\n  inputPath: string,\n  projectRoot: string,\n  cwd: string,\n): ResolvedProjectPath {\n  // Normalize inputs\n  const normalizedProjectRoot = resolve(projectRoot);\n  const normalizedCwd = resolve(cwd);\n\n  let absolutePath: string;\n\n  if (isAbsolute(inputPath)) {\n    // Input is already absolute\n    absolutePath = resolve(inputPath);\n  } else {\n    // Input is relative - resolve from current working directory\n    absolutePath = resolve(normalizedCwd, inputPath);\n  }\n\n  // Check if path is within project\n  if (!isPathWithinProject(absolutePath, normalizedProjectRoot)) {\n    throw new ProjectPathError(`Path is outside project root: ${inputPath}`, 'OUTSIDE_PROJECT');\n  }\n\n  // Calculate relative path from project root\n  const relativePath = relative(normalizedProjectRoot, absolutePath);\n\n  // Normalize the relative path (remove ./, convert separators, etc.)\n  const normalizedRelative = normalizePath(relativePath);\n\n  return {\n    relativePath: normalizedRelative,\n    absolutePath,\n  };\n}\n\n/**\n * Validates that a file exists at the resolved path.\n *\n * @param resolvedPath - Path already resolved via resolveProjectPath\n * @returns true if file exists\n * @throws ProjectPathError if file does not exist or is not a file\n */\nexport async function validateFileExists(resolvedPath: ResolvedProjectPath): Promise<boolean> {\n  try {\n    await access(resolvedPath.absolutePath);\n  } catch {\n    throw new ProjectPathError(`File not found: ${resolvedPath.relativePath}`, 'NOT_FOUND');\n  }\n\n  // Also verify it's a file, not a directory\n  try {\n    const stats = await stat(resolvedPath.absolutePath);\n    if (!stats.isFile()) {\n      throw new ProjectPathError(`Path is not a file: ${resolvedPath.relativePath}`, 'NOT_A_FILE');\n    }\n  } catch (error) {\n    if (error instanceof ProjectPathError) {\n      throw error;\n    }\n    throw new ProjectPathError(`File not found: ${resolvedPath.relativePath}`, 'NOT_FOUND');\n  }\n\n  return true;\n}\n\n/**\n * Convenience function that resolves and validates a path in one call.\n *\n * @param inputPath - The path provided by the user\n * @param projectRoot - The project root directory\n * @param cwd - Current working directory\n * @returns Resolved and validated path\n * @throws ProjectPathError if path is outside project or file doesn't exist\n */\nexport async function resolveAndValidatePath(\n  inputPath: string,\n  projectRoot: string,\n  cwd: string,\n): Promise<ResolvedProjectPath> {\n  const resolved = resolveProjectPath(inputPath, projectRoot, cwd);\n  await validateFileExists(resolved);\n  return resolved;\n}\n","/**\n * `tbd create` - Create a new issue.\n *\n * See: tbd-design.md §4.4 Create\n */\n\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, ValidationError, CLIError } from '../lib/errors.js';\nimport type { Issue, IssueKindType, PriorityType } from '../../lib/types.js';\nimport { generateInternalId, extractUlidFromInternalId } from '../../lib/ids.js';\nimport { readIssue, writeIssue } from '../../file/storage.js';\nimport {\n  loadIdMapping,\n  saveIdMapping,\n  generateUniqueShortId,\n  addIdMapping,\n  resolveToInternalId,\n} from '../../file/id-mapping.js';\nimport { IssueKind } from '../../lib/schemas.js';\nimport { parsePriority } from '../../lib/priority.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { now } from '../../utils/time-utils.js';\nimport { readConfig } from '../../file/config.js';\nimport { resolveAndValidatePath, getPathErrorMessage } from '../../lib/project-paths.js';\n\ninterface CreateOptions {\n  fromFile?: string;\n  type?: string;\n  priority?: string;\n  description?: string;\n  file?: string;\n  assignee?: string;\n  due?: string;\n  defer?: string;\n  parent?: string;\n  label?: string[];\n  spec?: string;\n}\n\nclass CreateHandler extends BaseCommand {\n  async run(title: string | undefined, options: CreateOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    // Validate title is provided (unless --from-file)\n    if (!title && !options.fromFile) {\n      throw new ValidationError('Title is required. Use: tbd create \"Issue title\"');\n    }\n\n    // Parse and validate options\n    const kind = this.parseKind(options.type ?? 'task');\n    const priority = this.validatePriority(options.priority ?? '2');\n\n    // Read description from file if specified\n    let description = options.description;\n    if (options.file) {\n      try {\n        description = await readFile(options.file, 'utf-8');\n      } catch {\n        throw new CLIError(`Failed to read description from file: ${options.file}`);\n      }\n    }\n\n    // Validate and normalize spec path if provided\n    let specPath: string | undefined;\n    if (options.spec) {\n      try {\n        const resolved = await resolveAndValidatePath(options.spec, tbdRoot, process.cwd());\n        specPath = resolved.relativePath;\n      } catch (error) {\n        throw new ValidationError(getPathErrorMessage(error));\n      }\n    }\n\n    if (\n      this.checkDryRun('Would create issue', { title, kind, priority, spec: specPath, ...options })\n    ) {\n      return;\n    }\n\n    const timestamp = now();\n    const id = generateInternalId();\n    const ulid = extractUlidFromInternalId(id);\n\n    let shortId: string;\n    let prefix: string;\n    let issue: Issue;\n    await this.execute(async () => {\n      const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n      // Read config for display prefix\n      const config = await readConfig(tbdRoot);\n      prefix = config.display.id_prefix;\n\n      // Load mapping, generate unique short ID, and save\n      const mapping = await loadIdMapping(dataSyncDir);\n      shortId = generateUniqueShortId(mapping);\n      addIdMapping(mapping, ulid, shortId);\n\n      // Resolve parent ID if provided (convert display ID to internal ID)\n      let parentId: string | undefined;\n      if (options.parent) {\n        try {\n          parentId = resolveToInternalId(options.parent, mapping);\n        } catch {\n          throw new ValidationError(`Invalid parent ID: ${options.parent}`);\n        }\n      }\n\n      // Inherit spec_path from parent if not explicitly provided\n      if (!specPath && parentId) {\n        const parentIssue = await readIssue(dataSyncDir, parentId);\n        if (parentIssue.spec_path) {\n          specPath = parentIssue.spec_path;\n        }\n      }\n\n      issue = {\n        type: 'is',\n        id,\n        version: 1,\n        title: title!,\n        kind,\n        status: 'open',\n        priority,\n        labels: options.label ?? [],\n        dependencies: [],\n        created_at: timestamp,\n        updated_at: timestamp,\n        description: description ?? undefined,\n        assignee: options.assignee ?? undefined,\n        due_date: options.due ?? undefined,\n        deferred_until: options.defer ?? undefined,\n        parent_id: parentId,\n        spec_path: specPath,\n      };\n\n      // Write both the issue and the mapping\n      await writeIssue(dataSyncDir, issue);\n      await saveIdMapping(dataSyncDir, mapping);\n    }, 'Failed to create issue');\n\n    // Output with display ID (prefix + short ID)\n    const displayId = `${prefix!}-${shortId!}`;\n    this.output.data({ id: displayId, internalId: id, title }, () => {\n      this.output.success(`Created ${displayId}: ${title}`);\n    });\n  }\n\n  private parseKind(value: string): IssueKindType {\n    const result = IssueKind.safeParse(value);\n    if (!result.success) {\n      throw new ValidationError(`Invalid type: ${value}. Must be: bug, feature, task, epic, chore`);\n    }\n    return result.data;\n  }\n\n  private validatePriority(value: string): PriorityType {\n    // Use shared parsePriority which accepts both \"P1\" and \"1\" formats\n    const num = parsePriority(value);\n    if (num === undefined) {\n      throw new ValidationError(`Invalid priority: ${value}. Use P0-P4 or 0-4.`);\n    }\n    return num;\n  }\n}\n\nexport const createCommand = new Command('create')\n  .description('Create a new issue')\n  .argument('[title]', 'Issue title')\n  .option('--from-file <path>', 'Create from YAML+Markdown file')\n  .option('-t, --type <type>', 'Issue type: bug, feature, task, epic, chore', 'task')\n  .option('-p, --priority <0-4>', 'Priority (0=critical, 4=lowest)', '2')\n  .option('-d, --description <text>', 'Description')\n  .option('-f, --file <path>', 'Read description from file')\n  .option('--assignee <name>', 'Assignee')\n  .option('--due <date>', 'Due date (ISO8601)')\n  .option('--defer <date>', 'Defer until date (ISO8601)')\n  .option('--parent <id>', 'Parent issue ID')\n  .option('--spec <path>', 'Link to spec document (relative path)')\n  .option('-l, --label <label>', 'Add label (repeatable)', (val, prev: string[] = []) => [\n    ...prev,\n    val,\n  ])\n  .action(async (title, options, command) => {\n    const handler = new CreateHandler(command);\n    await handler.run(title, options);\n  });\n","/**\n * Shared data context for tbd commands.\n *\n * Provides a single point to load common data needed by most commands:\n * - dataSyncDir: the path to the data sync directory\n * - mapping: the ID mapping (ULID to short ID)\n * - config: the project configuration\n * - prefix: the display prefix (from config.display.id_prefix)\n *\n * This eliminates the repetitive pattern of loading these individually in each command.\n *\n * For unified CLI + data context with helper methods, use FullCommandContext and\n * loadFullContext() which adds displayId() and other conveniences.\n */\n\nimport type { Command } from 'commander';\nimport type { IdMapping } from '../../file/id-mapping.js';\nimport { loadIdMapping, resolveToInternalId } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\nimport type { Config } from '../../lib/types.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport type { CommandContext } from './context.js';\nimport { getCommandContext } from './context.js';\nimport { requireInit, NotFoundError } from './errors.js';\n\n/**\n * Data context containing commonly needed data for tbd commands.\n */\nexport interface TbdDataContext {\n  /** Path to the data sync directory */\n  dataSyncDir: string;\n  /** ID mapping (ULID to short ID and vice versa) */\n  mapping: IdMapping;\n  /** Project configuration */\n  config: Config;\n  /** Display prefix from config (convenience accessor) */\n  prefix: string;\n}\n\n/**\n * Full command context combining CLI options with data context.\n * Provides unified access to all command needs with helper methods.\n */\nexport interface FullCommandContext extends TbdDataContext {\n  /** CLI options (dryRun, verbose, json, debug, etc.) */\n  cli: CommandContext;\n  /**\n   * Format an internal issue ID for display.\n   * Automatically respects debug mode to show full internal ID.\n   */\n  displayId(internalId: string): string;\n  /**\n   * Resolve user input ID to internal ID.\n   * @throws NotFoundError if the ID cannot be resolved\n   */\n  resolveId(inputId: string): string;\n}\n\n/**\n * Load all common data context needed by tbd commands.\n *\n * This loads:\n * - dataSyncDir from resolveDataSyncDir()\n * - mapping from loadIdMapping()\n * - config from readConfig()\n * - prefix from config.display.id_prefix\n *\n * Call this once at the start of a command handler instead of\n * loading each piece separately.\n *\n * @param tbdRoot - The tbd repository root directory (from requireInit or findTbdRoot)\n * @throws Error if any of the resources fail to load\n */\nexport async function loadDataContext(tbdRoot: string): Promise<TbdDataContext> {\n  const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n  const [mapping, config] = await Promise.all([loadIdMapping(dataSyncDir), readConfig(tbdRoot)]);\n\n  return {\n    dataSyncDir,\n    mapping,\n    config,\n    prefix: config.display.id_prefix,\n  };\n}\n\n/**\n * Load unified command context with CLI options, data, and helper methods.\n *\n * This is the recommended way to initialize command context. It:\n * 1. Checks that tbd is initialized (calls requireInit)\n * 2. Loads data context (dataSyncDir, mapping, config, prefix)\n * 3. Extracts CLI context from Commander\n * 4. Provides helper methods like displayId() and resolveId()\n *\n * Usage:\n * ```ts\n * class MyHandler extends BaseCommand {\n *   async run(id: string): Promise<void> {\n *     const ctx = await loadFullContext(this.command);\n *     const internalId = ctx.resolveId(id);\n *     const issue = await readIssue(ctx.dataSyncDir, internalId);\n *     console.log(ctx.displayId(issue.id));\n *   }\n * }\n * ```\n *\n * @param command - The Commander command instance\n * @throws Error if tbd is not initialized or resources fail to load\n */\nexport async function loadFullContext(command: Command): Promise<FullCommandContext> {\n  const tbdRoot = await requireInit();\n\n  const cli = getCommandContext(command);\n  const dataCtx = await loadDataContext(tbdRoot);\n\n  return {\n    ...dataCtx,\n    cli,\n    displayId(internalId: string): string {\n      return cli.debug\n        ? formatDebugId(internalId, dataCtx.mapping, dataCtx.prefix)\n        : formatDisplayId(internalId, dataCtx.mapping, dataCtx.prefix);\n    },\n    resolveId(inputId: string): string {\n      try {\n        return resolveToInternalId(inputId, dataCtx.mapping);\n      } catch {\n        throw new NotFoundError('Issue', inputId);\n      }\n    },\n  };\n}\n","/**\n * Status formatting utilities.\n *\n * Status values: open, in_progress, blocked, deferred, closed.\n */\n\nimport { ICONS, type createColors } from '../cli/lib/output.js';\nimport type { IssueStatusType } from './types.js';\n\n/**\n * Get the icon for a status value.\n *\n * - open: ○ (empty circle)\n * - in_progress: ◐ (half-filled circle)\n * - blocked: ● (filled circle)\n * - deferred: ○ (empty circle, same as open)\n * - closed: ✓ (checkmark)\n */\nexport function getStatusIcon(status: IssueStatusType): string {\n  switch (status) {\n    case 'open':\n      return ICONS.OPEN;\n    case 'in_progress':\n      return ICONS.IN_PROGRESS;\n    case 'blocked':\n      return ICONS.BLOCKED;\n    case 'deferred':\n      return ICONS.DEFERRED;\n    case 'closed':\n      return ICONS.CLOSED;\n    default:\n      return '';\n  }\n}\n\n/**\n * Format a status for display with icon prefix.\n * Format: \"icon status\" (e.g., \"○ open\", \"◐ in_progress\")\n *\n * @example formatStatus('open') → \"○ open\"\n * @example formatStatus('blocked') → \"● blocked\"\n */\nexport function formatStatus(status: IssueStatusType): string {\n  const icon = getStatusIcon(status);\n  return `${icon} ${status}`;\n}\n\n/**\n * Get the color function for a status value.\n *\n * - open: blue (info)\n * - in_progress: green (success)\n * - blocked: red (error)\n * - deferred: dim\n * - closed: dim\n *\n * @param status - The status value\n * @param colors - The colors object from createColors()\n * @returns A function that applies the appropriate color\n */\nexport function getStatusColor(\n  status: IssueStatusType,\n  colors: ReturnType<typeof createColors>,\n): (s: string) => string {\n  switch (status) {\n    case 'open':\n      return colors.info;\n    case 'in_progress':\n      return colors.success;\n    case 'blocked':\n      return colors.error;\n    case 'deferred':\n      return colors.dim;\n    case 'closed':\n      return colors.dim;\n    default:\n      return (s) => s;\n  }\n}\n","/**\n * Text truncation utilities for CLI output.\n *\n * Provides consistent truncation with Unicode ellipsis character.\n */\n\n/**\n * Unicode ellipsis character (U+2026). Use this instead of '...'.\n */\nexport const ELLIPSIS = '…';\n\n/**\n * Options for truncate function.\n */\nexport interface TruncateOptions {\n  /** If true, truncate at last word boundary before maxLength. */\n  wordBoundary?: boolean;\n}\n\n/**\n * Truncate text to maxLength, appending ellipsis if truncated.\n *\n * @param text - Text to truncate\n * @param maxLength - Maximum length including ellipsis\n * @param options - Truncation options\n * @returns Truncated text with ellipsis, or original if short enough\n */\nexport function truncate(text: string, maxLength: number, options?: TruncateOptions): string {\n  if (maxLength <= 0) {\n    return '';\n  }\n\n  if (text.length <= maxLength) {\n    return text;\n  }\n\n  if (maxLength === 1) {\n    return ELLIPSIS;\n  }\n\n  const truncatedLength = maxLength - 1; // Reserve space for ellipsis\n\n  if (options?.wordBoundary) {\n    // Find last space within the truncation limit\n    const lastSpace = text.lastIndexOf(' ', truncatedLength);\n    if (lastSpace > 0) {\n      return text.slice(0, lastSpace) + ELLIPSIS;\n    }\n  }\n\n  // Character-level truncation\n  return text.slice(0, truncatedLength) + ELLIPSIS;\n}\n\n/**\n * Truncate text from the middle, preserving start and end.\n * Useful for paths and IDs where both prefix and suffix are meaningful.\n *\n * @param text - Text to truncate\n * @param maxLength - Maximum length including ellipsis\n * @returns Truncated text with ellipsis in middle, or original if short enough\n */\nexport function truncateMiddle(text: string, maxLength: number): string {\n  if (maxLength <= 0) {\n    return '';\n  }\n\n  if (text.length <= maxLength) {\n    return text;\n  }\n\n  if (maxLength === 1) {\n    return ELLIPSIS;\n  }\n\n  if (maxLength === 2) {\n    // Only room for one char + ellipsis\n    return text[0] + ELLIPSIS;\n  }\n\n  // Calculate how many characters to keep on each side\n  // Subtract 1 for the ellipsis\n  const availableChars = maxLength - 1;\n  const endLength = Math.floor(availableChars / 2);\n  const startLength = availableChars - endLength;\n\n  const start = text.slice(0, startLength);\n  const end = text.slice(text.length - endLength);\n\n  return start + ELLIPSIS + end;\n}\n","/**\n * Issue formatting utilities for consistent CLI output.\n *\n * Provides standardized formatting for issue display across all commands.\n */\n\nimport { formatPriority, getPriorityColor } from '../../lib/priority.js';\nimport { getStatusIcon, getStatusColor } from '../../lib/status.js';\nimport { truncate, ELLIPSIS } from '../../lib/truncate.js';\nimport type { createColors } from './output.js';\nimport type { IssueKindType, IssueStatusType } from '../../lib/types.js';\n\n/**\n * Column width constants for issue tables.\n */\nexport const ISSUE_COLUMNS = {\n  ID: 12,\n  PRIORITY: 5,\n  STATUS: 16,\n  ASSIGNEE: 10,\n} as const;\n\n/**\n * Issue data structure for formatting.\n */\nexport interface IssueForDisplay {\n  id: string;\n  priority: number;\n  status: IssueStatusType;\n  kind: IssueKindType;\n  title: string;\n  description?: string;\n  labels?: string[];\n  assignee?: string;\n}\n\n/**\n * Format a kind in brackets.\n *\n * @example formatKind('bug') → \"[bug]\"\n * @example formatKind('feature') → \"[feature]\"\n */\nexport function formatKind(kind: IssueKindType): string {\n  return `[${kind}]`;\n}\n\n/**\n * Format a standard issue line for table display.\n *\n * Format: {ID}  {PRI}  {STATUS}  [kind] {TITLE}\n *\n * @example \"bd-a1b2     P0   ● blocked        [bug] Fix authentication timeout\"\n */\nexport function formatIssueLine(\n  issue: IssueForDisplay,\n  colors: ReturnType<typeof createColors>,\n): string {\n  const idCol = colors.id(issue.id.padEnd(ISSUE_COLUMNS.ID));\n  const priCol = getPriorityColor(\n    issue.priority,\n    colors,\n  )(formatPriority(issue.priority).padEnd(ISSUE_COLUMNS.PRIORITY));\n  const statusText = `${getStatusIcon(issue.status)} ${issue.status}`;\n  const statusCol = getStatusColor(issue.status, colors)(statusText.padEnd(ISSUE_COLUMNS.STATUS));\n  const kindPrefix = colors.dim(formatKind(issue.kind));\n\n  return `${idCol}${priCol}${statusCol}${kindPrefix} ${issue.title}`;\n}\n\n/**\n * Format an extended issue line with assignee column.\n *\n * Format: {ID}  {PRI}  {STATUS}  {ASSIGNEE}  [kind] {TITLE}\n */\nexport function formatIssueLineExtended(\n  issue: IssueForDisplay,\n  colors: ReturnType<typeof createColors>,\n): string {\n  const idCol = colors.id(issue.id.padEnd(ISSUE_COLUMNS.ID));\n  const priCol = getPriorityColor(\n    issue.priority,\n    colors,\n  )(formatPriority(issue.priority).padEnd(ISSUE_COLUMNS.PRIORITY));\n  const statusText = `${getStatusIcon(issue.status)} ${issue.status}`;\n  const statusCol = getStatusColor(issue.status, colors)(statusText.padEnd(ISSUE_COLUMNS.STATUS));\n  const assigneeText = issue.assignee ? `@${issue.assignee}` : '-';\n  const assigneeCol = assigneeText.padEnd(ISSUE_COLUMNS.ASSIGNEE);\n  const kindPrefix = colors.dim(formatKind(issue.kind));\n\n  return `${idCol}${priCol}${statusCol}${assigneeCol}${kindPrefix} ${issue.title}`;\n}\n\n/**\n * Format an issue line with labels.\n *\n * Format: {ID}  {PRI}  {STATUS}  [kind] {TITLE}  [labels]\n */\nexport function formatIssueWithLabels(\n  issue: IssueForDisplay,\n  colors: ReturnType<typeof createColors>,\n): string {\n  const baseLine = formatIssueLine(issue, colors);\n\n  if (!issue.labels || issue.labels.length === 0) {\n    return baseLine;\n  }\n\n  const labelsText = colors.label(`[${issue.labels.join(', ')}]`);\n  return `${baseLine}  ${labelsText}`;\n}\n\n/**\n * Format a compact issue reference.\n *\n * Format: {ID} {STATUS_ICON} {TITLE}\n * (No kind shown)\n *\n * @example \"bd-a1b2 ● Fix authentication timeout\"\n */\nexport function formatIssueCompact(\n  issue: IssueForDisplay,\n  colors: ReturnType<typeof createColors>,\n): string {\n  const icon = getStatusIcon(issue.status);\n  return `${colors.id(issue.id)} ${icon} ${issue.title}`;\n}\n\n/**\n * Format an inline issue mention.\n *\n * Format: {ID} ({TITLE})\n * (No kind shown)\n *\n * @example \"bd-a1b2 (Fix authentication timeout)\"\n */\nexport function formatIssueInline(issue: IssueForDisplay): string {\n  return `${issue.id} (${issue.title})`;\n}\n\n/**\n * Format the table header row for issue listings.\n */\nexport function formatIssueHeader(colors: ReturnType<typeof createColors>): string {\n  const idHeader = 'ID'.padEnd(ISSUE_COLUMNS.ID);\n  const priHeader = 'PRI'.padEnd(ISSUE_COLUMNS.PRIORITY);\n  const statusHeader = 'STATUS'.padEnd(ISSUE_COLUMNS.STATUS);\n  const titleHeader = 'TITLE';\n\n  return colors.dim(`${idHeader}${priHeader}${statusHeader}${titleHeader}`);\n}\n\n/**\n * Format the extended table header row with assignee column.\n */\nexport function formatIssueHeaderExtended(colors: ReturnType<typeof createColors>): string {\n  const idHeader = 'ID'.padEnd(ISSUE_COLUMNS.ID);\n  const priHeader = 'PRI'.padEnd(ISSUE_COLUMNS.PRIORITY);\n  const statusHeader = 'STATUS'.padEnd(ISSUE_COLUMNS.STATUS);\n  const assigneeHeader = 'ASSIGNEE'.padEnd(ISSUE_COLUMNS.ASSIGNEE);\n  const titleHeader = 'TITLE';\n\n  return colors.dim(`${idHeader}${priHeader}${statusHeader}${assigneeHeader}${titleHeader}`);\n}\n\n/**\n * Format an issue with long format (includes description on second line).\n *\n * Description is indented 6 spaces, dim color, max 2 lines.\n */\nexport function formatIssueLong(\n  issue: IssueForDisplay,\n  colors: ReturnType<typeof createColors>,\n  maxWidth = 80,\n): string {\n  const firstLine = formatIssueLine(issue, colors);\n\n  if (!issue.description) {\n    return firstLine;\n  }\n\n  const descLines = wrapDescription(issue.description, 6, 2, maxWidth);\n  if (!descLines) {\n    return firstLine;\n  }\n\n  return `${firstLine}\\n${colors.dim(descLines)}`;\n}\n\n/**\n * Word-wrap description text with indentation.\n *\n * @param text - The text to wrap\n * @param indent - Number of spaces to indent each line\n * @param maxLines - Maximum number of lines (truncates with ellipsis)\n * @param maxWidth - Maximum width per line (including indent)\n */\nexport function wrapDescription(\n  text: string,\n  indent: number,\n  maxLines: number,\n  maxWidth: number,\n): string {\n  if (!text) return '';\n\n  const indentStr = ' '.repeat(indent);\n  const contentWidth = maxWidth - indent;\n\n  // Split into words and wrap\n  const words = text.split(/\\s+/);\n  const lines: string[] = [];\n  let currentLine = '';\n\n  for (const word of words) {\n    if (!currentLine) {\n      currentLine = word;\n    } else if (currentLine.length + 1 + word.length <= contentWidth) {\n      currentLine += ' ' + word;\n    } else {\n      lines.push(currentLine);\n      currentLine = word;\n\n      // Stop if we've hit max lines\n      if (lines.length >= maxLines) {\n        break;\n      }\n    }\n  }\n\n  // Add remaining content\n  if (currentLine && lines.length < maxLines) {\n    lines.push(currentLine);\n  }\n\n  // Truncate last line if we have more content\n  if (lines.length === maxLines && currentLine && !lines.includes(currentLine)) {\n    const lastLine = lines[maxLines - 1];\n    if (lastLine) {\n      lines[maxLines - 1] = truncate(lastLine, contentWidth - 1) + ELLIPSIS;\n    }\n  }\n\n  return lines.map((line) => indentStr + line).join('\\n');\n}\n","/**\n * Tree view utilities for displaying issues with parent-child relationships.\n *\n * Used by `tbd list --pretty` to show hierarchical issue structure.\n */\n\nimport type { createColors } from './output.js';\nimport { formatPriority, getPriorityColor } from '../../lib/priority.js';\nimport { getStatusIcon, getStatusColor } from '../../lib/status.js';\nimport {\n  formatKind,\n  wrapDescription,\n  ISSUE_COLUMNS,\n  type IssueForDisplay,\n} from './issue-format.js';\n\n/**\n * Options for tree rendering.\n */\nexport interface TreeRenderOptions {\n  /** Show descriptions (--long mode) */\n  long?: boolean;\n  /** Terminal width for description wrapping */\n  maxWidth?: number;\n}\n\n/**\n * Tree node representing an issue with its children.\n */\nexport interface TreeNode {\n  issue: IssueForDisplay;\n  children: TreeNode[];\n}\n\n/**\n * Unicode box-drawing characters for tree display.\n */\nconst TREE_CHARS = {\n  /** Middle child connector: ├── */\n  BRANCH: '├── ',\n  /** Last child connector: └── */\n  LAST: '└── ',\n  /** Vertical line continuation: │    */\n  VERTICAL: '│   ',\n  /** Empty space for alignment:      */\n  SPACE: '    ',\n} as const;\n\n/**\n * Build a tree structure from a flat list of issues.\n *\n * Groups children under their parents based on parent_id.\n * Issues without a parent (or whose parent is not in the list) become root nodes.\n *\n * @param issues - Flat list of issues with optional parent_id\n * @returns Array of root tree nodes with nested children\n */\nexport function buildIssueTree(issues: (IssueForDisplay & { parentId?: string })[]): TreeNode[] {\n  // Create a map for quick lookup by ID\n  const issueMap = new Map<string, TreeNode>();\n  const roots: TreeNode[] = [];\n\n  // First pass: create nodes for all issues\n  for (const issue of issues) {\n    issueMap.set(issue.id, { issue, children: [] });\n  }\n\n  // Second pass: build parent-child relationships\n  for (const issue of issues) {\n    const node = issueMap.get(issue.id)!;\n\n    if (issue.parentId && issueMap.has(issue.parentId)) {\n      // Has a parent that's in our list - add as child\n      const parentNode = issueMap.get(issue.parentId)!;\n      parentNode.children.push(node);\n    } else {\n      // No parent or parent not in list - this is a root\n      roots.push(node);\n    }\n  }\n\n  return roots;\n}\n\n/**\n * Format a single issue line for tree view (no header, compact format).\n *\n * Format: {ID}  {PRI}  {STATUS}  [kind] {TITLE}\n *\n * ID column is padded to ISSUE_COLUMNS.ID width for consistent alignment.\n */\nfunction formatTreeIssueLine(\n  issue: IssueForDisplay,\n  colors: ReturnType<typeof createColors>,\n): string {\n  const id = colors.id(issue.id.padEnd(ISSUE_COLUMNS.ID));\n  const pri = getPriorityColor(issue.priority, colors)(formatPriority(issue.priority));\n  const statusText = `${getStatusIcon(issue.status)} ${issue.status}`;\n  const status = getStatusColor(issue.status, colors)(statusText);\n  const kind = colors.dim(formatKind(issue.kind));\n\n  return `${id}  ${pri}  ${status}  ${kind} ${issue.title}`;\n}\n\n/**\n * Render a tree node and its children as formatted lines.\n *\n * @param node - The tree node to render\n * @param colors - Color functions for formatting\n * @param prefix - Current line prefix (for nested indentation)\n * @param options - Rendering options (long mode, max width)\n * @returns Array of formatted lines\n */\nfunction renderTreeNode(\n  node: TreeNode,\n  colors: ReturnType<typeof createColors>,\n  prefix = '',\n  options: TreeRenderOptions = {},\n): string[] {\n  const lines: string[] = [];\n  const { long = false, maxWidth = 80 } = options;\n\n  // Render this node\n  const issueLine = formatTreeIssueLine(node.issue, colors);\n  lines.push(prefix + issueLine);\n\n  // Render description if --long and description exists\n  if (long && node.issue.description) {\n    // Calculate indent: prefix length + 6 spaces for description alignment\n    const descIndent = prefix.length + 6;\n    const descWidth = maxWidth - descIndent;\n    if (descWidth > 20) {\n      const wrapped = wrapDescription(node.issue.description, 6, 2, descWidth + 6);\n      if (wrapped) {\n        // Add prefix to each description line\n        const descLines = wrapped.split('\\n');\n        for (const descLine of descLines) {\n          lines.push(prefix + colors.dim(descLine));\n        }\n      }\n    }\n  }\n\n  // Render children\n  const childCount = node.children.length;\n  node.children.forEach((child, index) => {\n    const isLastChild = index === childCount - 1;\n\n    // Determine the connector for this child\n    const connector = isLastChild ? TREE_CHARS.LAST : TREE_CHARS.BRANCH;\n\n    // Determine the prefix for continuation lines (descriptions, grandchildren)\n    // If this child is not last, we need a vertical line; otherwise space\n    const childPrefix = prefix + (isLastChild ? TREE_CHARS.SPACE : TREE_CHARS.VERTICAL);\n\n    // Render child with childPrefix so it knows the correct indentation for descriptions\n    const childLines = renderTreeNode(child, colors, childPrefix, options);\n\n    // Process lines: first line gets connector, others keep childPrefix\n    childLines.forEach((line, lineIndex) => {\n      if (lineIndex === 0) {\n        // Replace childPrefix with connector for the first line\n        const lineWithoutPrefix = line.slice(childPrefix.length);\n        lines.push(colors.dim(connector) + lineWithoutPrefix);\n      } else {\n        // Keep childPrefix for continuation lines (already included)\n        lines.push(line);\n      }\n    });\n  });\n\n  return lines;\n}\n\n/**\n * Render a complete tree view of issues.\n *\n * @param roots - Array of root tree nodes\n * @param colors - Color functions for formatting\n * @param options - Rendering options (long mode, max width)\n * @returns Array of formatted lines (without header, count is separate)\n */\nexport function renderIssueTree(\n  roots: TreeNode[],\n  colors: ReturnType<typeof createColors>,\n  options: TreeRenderOptions = {},\n): string[] {\n  const lines: string[] = [];\n\n  for (const root of roots) {\n    const rootLines = renderTreeNode(root, colors, '', options);\n    lines.push(...rootLines);\n  }\n\n  return lines;\n}\n\n/**\n * Count total issues in a tree (including all nested children).\n */\nexport function countTreeIssues(roots: TreeNode[]): number {\n  let count = 0;\n\n  function countNode(node: TreeNode): void {\n    count++;\n    for (const child of node.children) {\n      countNode(child);\n    }\n  }\n\n  for (const root of roots) {\n    countNode(root);\n  }\n\n  return count;\n}\n","/**\n * Spec path matching utilities.\n *\n * Provides gradual path matching for linking beads to spec documents.\n * Supports matching by filename, partial path suffix, or full path.\n *\n * See: plan-2026-01-26-spec-linking.md §Gradual Path Matching Algorithm\n */\n\nimport { basename } from 'node:path';\n\n/**\n * Check if a stored spec path matches a query path using gradual matching.\n *\n * Matching rules (in order of precedence):\n * 1. Exact match after normalization\n * 2. Suffix match: stored path ends with query path at a path separator\n * 3. Filename match: query matches the filename portion of stored path\n *\n * @param storedPath - The spec_path stored in the issue (e.g., \"docs/specs/plan-feature.md\")\n * @param queryPath - The path to match against (e.g., \"plan-feature.md\" or \"specs/plan-feature.md\")\n * @returns true if the paths match\n *\n * @example\n * // All these queries match stored path \"docs/project/specs/active/plan-2026-01-26-feature.md\":\n * matchesSpecPath(stored, \"plan-2026-01-26-feature.md\")           // filename match\n * matchesSpecPath(stored, \"feature.md\")                           // partial filename - NO MATCH (too ambiguous)\n * matchesSpecPath(stored, \"active/plan-2026-01-26-feature.md\")    // suffix match\n * matchesSpecPath(stored, \"docs/project/specs/active/plan-2026-01-26-feature.md\")  // exact match\n */\nexport function matchesSpecPath(storedPath: string, queryPath: string): boolean {\n  // Handle empty/null cases\n  if (!storedPath || !queryPath) {\n    return false;\n  }\n\n  // Normalize paths: remove leading ./ and trailing /\n  const normalizedStored = normalizePath(storedPath);\n  const normalizedQuery = normalizePath(queryPath);\n\n  // Empty after normalization\n  if (!normalizedStored || !normalizedQuery) {\n    return false;\n  }\n\n  // 1. Exact match\n  if (normalizedStored === normalizedQuery) {\n    return true;\n  }\n\n  // 2. Suffix match: stored path ends with /query\n  // This handles partial path matches like \"active/plan.md\" matching \"docs/specs/active/plan.md\"\n  if (normalizedStored.endsWith('/' + normalizedQuery)) {\n    return true;\n  }\n\n  // 3. Filename match: query is just a filename that matches stored's filename\n  const storedFilename = basename(normalizedStored);\n  const queryFilename = basename(normalizedQuery);\n\n  // Only do filename match if query has no directory components\n  // (otherwise it would have matched in suffix check above)\n  if (!normalizedQuery.includes('/') && storedFilename === normalizedQuery) {\n    return true;\n  }\n\n  // Also match if both have same filename and query is just a filename\n  if (!normalizedQuery.includes('/') && storedFilename === queryFilename) {\n    return true;\n  }\n\n  return false;\n}\n\n/**\n * Normalize a path for comparison.\n * - Removes leading ./\n * - Removes trailing /\n * - Collapses multiple slashes\n */\nfunction normalizePath(path: string): string {\n  return path\n    .replace(/^\\.\\//, '') // Remove leading ./\n    .replace(/\\/+$/, '') // Remove trailing /\n    .replace(/\\/+/g, '/'); // Collapse multiple slashes\n}\n","/**\n * `tbd list` - List issues.\n *\n * See: tbd-design.md §4.4 List\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, CLIError } from '../lib/errors.js';\nimport { loadDataContext, type TbdDataContext } from '../lib/data-context.js';\nimport type { Issue, IssueStatusType, IssueKindType } from '../../lib/types.js';\nimport { listIssues } from '../../file/storage.js';\nimport { formatDisplayId, formatDebugId, extractUlidFromInternalId } from '../../lib/ids.js';\nimport type { IdMapping } from '../../file/id-mapping.js';\nimport { resolveToInternalId } from '../../file/id-mapping.js';\nimport { naturalCompare } from '../../lib/sort.js';\nimport {\n  formatIssueLine,\n  formatIssueLong,\n  formatIssueHeader,\n  type IssueForDisplay,\n} from '../lib/issue-format.js';\nimport { parsePriority } from '../../lib/priority.js';\nimport { buildIssueTree, renderIssueTree } from '../lib/tree-view.js';\nimport { getTerminalWidth } from '../lib/output.js';\nimport { matchesSpecPath } from '../../lib/spec-matching.js';\n\ninterface ListOptions {\n  status?: IssueStatusType;\n  all?: boolean;\n  type?: IssueKindType;\n  priority?: string;\n  assignee?: string;\n  label?: string[];\n  parent?: string;\n  spec?: string;\n  deferred?: boolean;\n  deferBefore?: string;\n  sort?: string;\n  limit?: string;\n  count?: boolean;\n  long?: boolean;\n  pretty?: boolean;\n}\n\nclass ListHandler extends BaseCommand {\n  async run(options: ListOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    let issues: Issue[];\n    let dataCtx: TbdDataContext;\n\n    try {\n      // Load shared data context (dataSyncDir, mapping, config, prefix)\n      dataCtx = await loadDataContext(tbdRoot);\n      issues = await listIssues(dataCtx.dataSyncDir);\n    } catch {\n      throw new CLIError('Failed to read issues');\n    }\n\n    // Apply filters\n    issues = this.filterIssues(issues, options, dataCtx.mapping);\n\n    // Sort results (with secondary sort by short ID for stable ordering)\n    issues = this.sortIssues(issues, options.sort ?? 'priority', dataCtx.mapping);\n\n    // Apply limit\n    if (options.limit) {\n      const limit = parseInt(options.limit, 10);\n      if (!isNaN(limit) && limit > 0) {\n        issues = issues.slice(0, limit);\n      }\n    }\n\n    // Count-only mode for testing\n    if (options.count) {\n      this.output.data({ count: issues.length }, () => {\n        console.log(issues.length);\n      });\n      return;\n    }\n\n    const showDebug = this.ctx.debug;\n    const { mapping, prefix } = dataCtx;\n\n    // Format output - use short display IDs instead of internal ULIDs\n    const displayIssues = issues.map((i) => ({\n      id: showDebug ? formatDebugId(i.id, mapping, prefix) : formatDisplayId(i.id, mapping, prefix),\n      internalId: i.id,\n      parentId: i.parent_id\n        ? showDebug\n          ? formatDebugId(i.parent_id, mapping, prefix)\n          : formatDisplayId(i.parent_id, mapping, prefix)\n        : undefined,\n      priority: i.priority,\n      status: i.status,\n      kind: i.kind,\n      title: i.title,\n      description: i.description,\n      assignee: i.assignee,\n      labels: i.labels,\n      spec_path: i.spec_path,\n    }));\n\n    this.output.data(displayIssues, () => {\n      if (issues.length === 0) {\n        console.log('No issues found');\n        return;\n      }\n\n      const colors = this.output.getColors();\n\n      if (options.pretty) {\n        // Tree view: show parent-child relationships\n        const tree = buildIssueTree(displayIssues as (IssueForDisplay & { parentId?: string })[]);\n        const lines = renderIssueTree(tree, colors, {\n          long: options.long,\n          maxWidth: getTerminalWidth(),\n        });\n        for (const line of lines) {\n          console.log(line);\n        }\n      } else {\n        // Table view: standard tabular format\n        console.log(formatIssueHeader(colors));\n        for (const issue of displayIssues) {\n          if (options.long) {\n            console.log(formatIssueLong(issue as IssueForDisplay, colors));\n          } else {\n            console.log(formatIssueLine(issue as IssueForDisplay, colors));\n          }\n        }\n      }\n\n      console.log('');\n      console.log(colors.dim(`${issues.length} issue(s)`));\n    });\n  }\n\n  private filterIssues(issues: Issue[], options: ListOptions, mapping: IdMapping): Issue[] {\n    // Resolve parent filter to internal ID if provided\n    let resolvedParentId: string | undefined;\n    if (options.parent) {\n      try {\n        resolvedParentId = resolveToInternalId(options.parent, mapping);\n      } catch {\n        // If parent ID cannot be resolved, no issues will match\n        return [];\n      }\n    }\n\n    return issues.filter((issue) => {\n      // By default, exclude closed issues unless --all or --status closed\n      if (!options.all && options.status !== 'closed' && issue.status === 'closed') {\n        return false;\n      }\n\n      // Status filter\n      if (options.status && issue.status !== options.status) {\n        return false;\n      }\n\n      // Type filter\n      if (options.type && issue.kind !== options.type) {\n        return false;\n      }\n\n      // Priority filter - supports both numeric (1) and prefixed (P1) formats\n      if (options.priority !== undefined) {\n        const priority = parsePriority(options.priority);\n        if (priority !== undefined && issue.priority !== priority) {\n          return false;\n        }\n      }\n\n      // Assignee filter\n      if (options.assignee && issue.assignee !== options.assignee) {\n        return false;\n      }\n\n      // Label filter (all must match)\n      if (options.label && options.label.length > 0) {\n        const hasAllLabels = options.label.every((l) => issue.labels.includes(l));\n        if (!hasAllLabels) {\n          return false;\n        }\n      }\n\n      // Parent filter (compare resolved internal IDs)\n      if (resolvedParentId && issue.parent_id !== resolvedParentId) {\n        return false;\n      }\n\n      // Spec path filter (uses gradual matching)\n      if (options.spec) {\n        if (!issue.spec_path || !matchesSpecPath(issue.spec_path, options.spec)) {\n          return false;\n        }\n      }\n\n      // Deferred filter\n      if (options.deferred && issue.status !== 'deferred') {\n        return false;\n      }\n\n      return true;\n    });\n  }\n\n  private sortIssues(issues: Issue[], sortField: string, mapping: IdMapping): Issue[] {\n    // Helper to get short ID for secondary sort\n    const getShortId = (issue: Issue): string => {\n      const ulid = extractUlidFromInternalId(issue.id);\n      return mapping.ulidToShort.get(ulid) ?? ulid;\n    };\n\n    return [...issues].sort((a, b) => {\n      let primaryCompare: number;\n\n      switch (sortField) {\n        case 'priority':\n          primaryCompare = a.priority - b.priority;\n          break;\n        case 'created':\n          primaryCompare = new Date(b.created_at).getTime() - new Date(a.created_at).getTime();\n          break;\n        case 'updated':\n          primaryCompare = new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime();\n          break;\n        default:\n          primaryCompare = a.priority - b.priority;\n      }\n\n      // Secondary sort by short ID using natural ordering for stable, intuitive results\n      if (primaryCompare !== 0) {\n        return primaryCompare;\n      }\n      return naturalCompare(getShortId(a), getShortId(b));\n    });\n  }\n}\n\nexport const listCommand = new Command('list')\n  .description('List issues')\n  .option('--status <status>', 'Filter: open, in_progress, blocked, deferred, closed')\n  .option('--all', 'Include closed issues')\n  .option('--type <type>', 'Filter: bug, feature, task, epic')\n  .option('--priority <0-4>', 'Filter by priority')\n  .option('--assignee <name>', 'Filter by assignee')\n  .option('--label <label>', 'Filter by label (repeatable)', (val, prev: string[] = []) => [\n    ...prev,\n    val,\n  ])\n  .option('--parent <id>', 'List children of parent')\n  .option(\n    '--spec <path>',\n    'Filter by spec path (matches full path, partial path suffix, or filename)',\n  )\n  .option('--deferred', 'Show only deferred issues')\n  .option('--defer-before <date>', 'Deferred before date')\n  .option('--sort <field>', 'Sort by: priority, created, updated', 'priority')\n  .option('--limit <n>', 'Limit results')\n  .option('--count', 'Output only the count of matching issues')\n  .option('--long', 'Show descriptions')\n  .option('--pretty', 'Show tree view with parent-child relationships')\n  .action(async (options, command) => {\n    const handler = new ListHandler(command);\n    await handler.run(options);\n  });\n","/**\n * `tbd show` - Show issue details.\n *\n * See: tbd-design.md §4.4 Show\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { NotFoundError } from '../lib/errors.js';\nimport { loadFullContext } from '../lib/data-context.js';\nimport { readIssue } from '../../file/storage.js';\nimport { serializeIssue } from '../../file/parser.js';\nimport { formatPriority, getPriorityColor } from '../../lib/priority.js';\nimport { getStatusColor } from '../../lib/status.js';\nimport type { IssueStatusType } from '../../lib/types.js';\n\nclass ShowHandler extends BaseCommand {\n  async run(id: string, command: Command): Promise<void> {\n    // Load unified context with data and helpers\n    const ctx = await loadFullContext(command);\n\n    // Resolve input ID to internal ID using helper\n    const internalId = ctx.resolveId(id);\n\n    let issue;\n    try {\n      issue = await readIssue(ctx.dataSyncDir, internalId);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Format display ID using helper (respects debug mode automatically)\n    const displayId = ctx.displayId(issue.id);\n\n    // Create display version with short display ID\n    const displayIssue = {\n      ...issue,\n      displayId,\n    };\n\n    this.output.data(displayIssue, () => {\n      const colors = this.output.getColors();\n\n      // Output as YAML+Markdown format (same as storage format)\n      const serialized = serializeIssue(issue);\n\n      // Add some color highlighting for text output\n      const lines = serialized.split('\\n');\n      for (const line of lines) {\n        if (line === '---') {\n          console.log(colors.dim(line));\n        } else if (line.startsWith('id:')) {\n          console.log(`${colors.dim('id:')} ${colors.id(line.slice(4))}`);\n        } else if (line.startsWith('status:')) {\n          const status = line.slice(8).trim() as IssueStatusType;\n          const statusColor = getStatusColor(status, colors);\n          console.log(`${colors.dim('status:')} ${statusColor(status)}`);\n        } else if (line.startsWith('priority:')) {\n          const priority = parseInt(line.slice(10).trim(), 10);\n          const priorityColor = getPriorityColor(priority, colors);\n          console.log(`${colors.dim('priority:')} ${priorityColor(formatPriority(priority))}`);\n        } else if (line.startsWith('title:')) {\n          console.log(`${colors.dim('title:')} ${colors.bold(line.slice(7))}`);\n        } else if (line.startsWith('spec_path:')) {\n          console.log(`${colors.dim('spec_path:')} ${colors.id(line.slice(11))}`);\n        } else if (line.startsWith('## Notes')) {\n          console.log(colors.bold(line));\n        } else if (line.startsWith('  - ')) {\n          console.log(`  - ${colors.label(line.slice(4))}`);\n        } else {\n          console.log(line);\n        }\n      }\n    });\n  }\n}\n\nexport const showCommand = new Command('show')\n  .description('Show issue details')\n  .argument('<id>', 'Issue ID')\n  .action(async (id, _options, command) => {\n    const handler = new ShowHandler(command);\n    await handler.run(id, command);\n  });\n","/**\n * `tbd update` - Update an issue.\n *\n * See: tbd-design.md §4.4 Update\n */\n\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotFoundError, ValidationError, CLIError } from '../lib/errors.js';\nimport { readIssue, writeIssue, listIssues } from '../../file/storage.js';\nimport { parseMarkdownWithFrontmatter } from '../../file/parser.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { IssueStatus, IssueKind } from '../../lib/schemas.js';\nimport { parsePriority } from '../../lib/priority.js';\nimport type { IssueStatusType, IssueKindType, PriorityType } from '../../lib/types.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { now } from '../../utils/time-utils.js';\nimport { loadIdMapping, resolveToInternalId, type IdMapping } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\nimport { resolveAndValidatePath, getPathErrorMessage } from '../../lib/project-paths.js';\n\ninterface UpdateOptions {\n  fromFile?: string;\n  title?: string;\n  status?: string;\n  type?: string;\n  priority?: string;\n  assignee?: string;\n  description?: string;\n  notes?: string;\n  notesFile?: string;\n  due?: string;\n  defer?: string;\n  addLabel?: string[];\n  removeLabel?: string[];\n  parent?: string;\n  spec?: string;\n}\n\nclass UpdateHandler extends BaseCommand {\n  async run(id: string, options: UpdateOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load ID mapping for resolution\n    const mapping = await loadIdMapping(dataSyncDir);\n\n    // Resolve input ID to internal ID\n    let internalId: string;\n    try {\n      internalId = resolveToInternalId(id, mapping);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Load existing issue\n    let issue;\n    try {\n      issue = await readIssue(dataSyncDir, internalId);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Parse and validate options\n    const updates = await this.parseUpdates(options, mapping, tbdRoot);\n    if (updates === null) return;\n\n    if (this.checkDryRun('Would update issue', { id: internalId, ...updates })) {\n      return;\n    }\n\n    // Capture old spec_path before applying updates (for propagation)\n    const oldSpecPath = issue.spec_path;\n\n    // Apply updates\n    if (updates.title !== undefined) issue.title = updates.title;\n    if (updates.status !== undefined) issue.status = updates.status;\n    if (updates.kind !== undefined) issue.kind = updates.kind;\n    if (updates.priority !== undefined) issue.priority = updates.priority;\n    if (updates.assignee !== undefined) issue.assignee = updates.assignee;\n    if (updates.description !== undefined) issue.description = updates.description;\n    if (updates.notes !== undefined) issue.notes = updates.notes;\n    if (updates.due_date !== undefined) issue.due_date = updates.due_date;\n    if (updates.deferred_until !== undefined) issue.deferred_until = updates.deferred_until;\n    if (updates.parent_id !== undefined) issue.parent_id = updates.parent_id;\n    if (updates.spec_path !== undefined) issue.spec_path = updates.spec_path;\n\n    // Inherit spec_path from new parent when re-parenting without explicit --spec\n    if (updates.parent_id && options.spec === undefined && !issue.spec_path) {\n      try {\n        const parentIssue = await readIssue(dataSyncDir, updates.parent_id);\n        if (parentIssue.spec_path) {\n          issue.spec_path = parentIssue.spec_path;\n        }\n      } catch {\n        // Parent not found — skip inheritance\n      }\n    }\n\n    // Handle full labels replacement (from --from-file)\n    if (updates.labels !== undefined) {\n      issue.labels = updates.labels;\n    }\n\n    // Handle label updates\n    if (updates.addLabels && updates.addLabels.length > 0) {\n      const labelsSet = new Set(issue.labels);\n      for (const label of updates.addLabels) {\n        labelsSet.add(label);\n      }\n      issue.labels = [...labelsSet];\n    }\n    if (updates.removeLabels && updates.removeLabels.length > 0) {\n      const removeSet = new Set(updates.removeLabels);\n      issue.labels = issue.labels.filter((l) => !removeSet.has(l));\n    }\n\n    // Update metadata\n    issue.version += 1;\n    issue.updated_at = now();\n\n    // Save\n    await this.execute(async () => {\n      await writeIssue(dataSyncDir, issue);\n    }, 'Failed to update issue');\n\n    // Propagate spec_path to children when parent's spec changes\n    if (updates.spec_path !== undefined && issue.spec_path && issue.spec_path !== oldSpecPath) {\n      const allIssues = await listIssues(dataSyncDir);\n      const children = allIssues.filter((i) => i.parent_id === issue.id);\n      const timestamp = now();\n      for (const child of children) {\n        if (!child.spec_path || child.spec_path === oldSpecPath) {\n          child.spec_path = issue.spec_path;\n          child.version += 1;\n          child.updated_at = timestamp;\n          await writeIssue(dataSyncDir, child);\n        }\n      }\n    }\n\n    // Use already loaded mapping for display\n    const showDebug = this.ctx.debug;\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const displayId = showDebug\n      ? formatDebugId(issue.id, mapping, prefix)\n      : formatDisplayId(issue.id, mapping, prefix);\n\n    this.output.data({ id: displayId, updated: true }, () => {\n      this.output.success(`Updated ${displayId}`);\n    });\n  }\n\n  private async parseUpdates(\n    options: UpdateOptions,\n    mapping: IdMapping,\n    tbdRoot: string,\n  ): Promise<{\n    title?: string;\n    status?: IssueStatusType;\n    kind?: IssueKindType;\n    priority?: PriorityType;\n    assignee?: string | null;\n    description?: string | null;\n    notes?: string | null;\n    due_date?: string | null;\n    deferred_until?: string | null;\n    parent_id?: string | null;\n    spec_path?: string | null;\n    addLabels?: string[];\n    removeLabels?: string[];\n    labels?: string[];\n  } | null> {\n    const updates: {\n      title?: string;\n      status?: IssueStatusType;\n      kind?: IssueKindType;\n      priority?: PriorityType;\n      assignee?: string | null;\n      description?: string | null;\n      notes?: string | null;\n      due_date?: string | null;\n      deferred_until?: string | null;\n      parent_id?: string | null;\n      spec_path?: string | null;\n      addLabels?: string[];\n      removeLabels?: string[];\n      labels?: string[];\n    } = {};\n\n    // Handle --from-file: read all mutable fields from YAML+Markdown file\n    if (options.fromFile) {\n      let content: string;\n      try {\n        content = await readFile(options.fromFile, 'utf-8');\n      } catch {\n        throw new CLIError(`Failed to read file: ${options.fromFile}`);\n      }\n\n      try {\n        const { frontmatter, description, notes } = parseMarkdownWithFrontmatter(content);\n\n        // Extract mutable fields from frontmatter\n        if (typeof frontmatter.title === 'string') {\n          updates.title = frontmatter.title;\n        }\n        if (typeof frontmatter.status === 'string') {\n          const result = IssueStatus.safeParse(frontmatter.status);\n          if (result.success) {\n            updates.status = result.data;\n          }\n        }\n        if (typeof frontmatter.kind === 'string') {\n          const result = IssueKind.safeParse(frontmatter.kind);\n          if (result.success) {\n            updates.kind = result.data;\n          }\n        }\n        if (typeof frontmatter.priority === 'number') {\n          const priority = parsePriority(String(frontmatter.priority));\n          if (priority !== undefined) {\n            updates.priority = priority;\n          }\n        }\n        if (frontmatter.assignee !== undefined) {\n          updates.assignee = typeof frontmatter.assignee === 'string' ? frontmatter.assignee : null;\n        }\n        if (frontmatter.due_date !== undefined) {\n          updates.due_date = typeof frontmatter.due_date === 'string' ? frontmatter.due_date : null;\n        }\n        if (frontmatter.deferred_until !== undefined) {\n          updates.deferred_until =\n            typeof frontmatter.deferred_until === 'string' ? frontmatter.deferred_until : null;\n        }\n        if (frontmatter.parent_id !== undefined) {\n          updates.parent_id =\n            typeof frontmatter.parent_id === 'string' ? frontmatter.parent_id : null;\n        }\n        if (frontmatter.spec_path !== undefined) {\n          if (typeof frontmatter.spec_path === 'string' && frontmatter.spec_path) {\n            // Validate and normalize the spec path from file\n            try {\n              const resolved = await resolveAndValidatePath(\n                frontmatter.spec_path,\n                tbdRoot,\n                process.cwd(),\n              );\n              updates.spec_path = resolved.relativePath;\n            } catch (error) {\n              throw new ValidationError(getPathErrorMessage(error));\n            }\n          } else {\n            updates.spec_path = null;\n          }\n        }\n        if (Array.isArray(frontmatter.labels)) {\n          updates.labels = frontmatter.labels.filter((l): l is string => typeof l === 'string');\n        }\n\n        // Set description and notes from body\n        updates.description = description || null;\n        updates.notes = notes || null;\n      } catch (error) {\n        throw new CLIError(\n          `Failed to parse file: ${options.fromFile}: ${error instanceof Error ? error.message : String(error)}`,\n        );\n      }\n\n      return updates;\n    }\n\n    if (options.title !== undefined) {\n      if (!options.title.trim()) {\n        throw new ValidationError('Title cannot be empty');\n      }\n      updates.title = options.title;\n    }\n\n    if (options.status) {\n      const result = IssueStatus.safeParse(options.status);\n      if (!result.success) {\n        throw new ValidationError(`Invalid status: ${options.status}`);\n      }\n      updates.status = result.data;\n    }\n\n    if (options.type) {\n      const result = IssueKind.safeParse(options.type);\n      if (!result.success) {\n        throw new ValidationError(`Invalid type: ${options.type}`);\n      }\n      updates.kind = result.data;\n    }\n\n    if (options.priority) {\n      // Use shared parsePriority which accepts both \"P1\" and \"1\" formats\n      const priority = parsePriority(options.priority);\n      if (priority === undefined) {\n        throw new ValidationError(`Invalid priority: ${options.priority}. Use P0-P4 or 0-4.`);\n      }\n      updates.priority = priority;\n    }\n\n    if (options.assignee !== undefined) {\n      updates.assignee = options.assignee || null;\n    }\n\n    if (options.description !== undefined) {\n      updates.description = options.description || null;\n    }\n\n    if (options.notes !== undefined) {\n      updates.notes = options.notes || null;\n    }\n\n    if (options.notesFile) {\n      try {\n        updates.notes = await readFile(options.notesFile, 'utf-8');\n      } catch {\n        throw new CLIError(`Failed to read notes from file: ${options.notesFile}`);\n      }\n    }\n\n    if (options.due !== undefined) {\n      updates.due_date = options.due || null;\n    }\n\n    if (options.defer !== undefined) {\n      updates.deferred_until = options.defer || null;\n    }\n\n    if (options.parent !== undefined) {\n      if (options.parent) {\n        try {\n          updates.parent_id = resolveToInternalId(options.parent, mapping);\n        } catch {\n          throw new ValidationError(`Invalid parent ID: ${options.parent}`);\n        }\n      } else {\n        updates.parent_id = null;\n      }\n    }\n\n    if (options.spec !== undefined) {\n      if (options.spec) {\n        // Non-empty spec path: validate and normalize\n        try {\n          const resolved = await resolveAndValidatePath(options.spec, tbdRoot, process.cwd());\n          updates.spec_path = resolved.relativePath;\n        } catch (error) {\n          throw new ValidationError(getPathErrorMessage(error));\n        }\n      } else {\n        // Empty string: clear the spec path (no validation needed)\n        updates.spec_path = null;\n      }\n    }\n\n    if (options.addLabel && options.addLabel.length > 0) {\n      updates.addLabels = options.addLabel;\n    }\n\n    if (options.removeLabel && options.removeLabel.length > 0) {\n      updates.removeLabels = options.removeLabel;\n    }\n\n    return updates;\n  }\n}\n\nexport const updateCommand = new Command('update')\n  .description('Update an issue')\n  .argument('<id>', 'Issue ID')\n  .option('--from-file <path>', 'Update all fields from YAML+Markdown file')\n  .option('--title <text>', 'Set title')\n  .option('--status <status>', 'Set status')\n  .option('--type <type>', 'Set type')\n  .option('--priority <0-4>', 'Set priority')\n  .option('--assignee <name>', 'Set assignee')\n  .option('--description <text>', 'Set description')\n  .option('--notes <text>', 'Set working notes')\n  .option('--notes-file <path>', 'Set notes from file')\n  .option('--due <date>', 'Set due date')\n  .option('--defer <date>', 'Set deferred until date')\n  .option('--add-label <label>', 'Add label', (val, prev: string[] = []) => [...prev, val])\n  .option('--remove-label <label>', 'Remove label', (val, prev: string[] = []) => [...prev, val])\n  .option('--parent <id>', 'Set parent')\n  .option('--spec <path>', 'Set or clear spec path (empty string clears)')\n  .action(async (id, options, command) => {\n    const handler = new UpdateHandler(command);\n    await handler.run(id, options);\n  });\n","/**\n * `tbd close` - Close an issue.\n *\n * See: tbd-design.md §4.4 Close\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotFoundError } from '../lib/errors.js';\nimport { readIssue, writeIssue } from '../../file/storage.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { now } from '../../utils/time-utils.js';\nimport { loadIdMapping, resolveToInternalId } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\n\ninterface CloseOptions {\n  reason?: string;\n}\n\nclass CloseHandler extends BaseCommand {\n  async run(id: string, options: CloseOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load ID mapping for resolution\n    const mapping = await loadIdMapping(dataSyncDir);\n\n    // Resolve input ID to internal ID\n    let internalId: string;\n    try {\n      internalId = resolveToInternalId(id, mapping);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Load existing issue\n    let issue;\n    try {\n      issue = await readIssue(dataSyncDir, internalId);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Get display ID for output\n    const showDebug = this.ctx.debug;\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const displayId = showDebug\n      ? formatDebugId(issue.id, mapping, prefix)\n      : formatDisplayId(issue.id, mapping, prefix);\n\n    // Idempotent: if already closed, succeed silently without modification\n    if (issue.status === 'closed') {\n      this.output.data({ id: displayId, closed: true, alreadyClosed: true }, () => {\n        this.output.success(`Closed ${displayId}`);\n      });\n      return;\n    }\n\n    if (this.checkDryRun('Would close issue', { id: internalId, reason: options.reason })) {\n      return;\n    }\n\n    // Update issue\n    issue.status = 'closed';\n    issue.closed_at = now();\n    issue.close_reason = options.reason ?? null;\n    issue.version += 1;\n    issue.updated_at = now();\n\n    // Save\n    await this.execute(async () => {\n      await writeIssue(dataSyncDir, issue);\n    }, 'Failed to close issue');\n\n    this.output.data({ id: displayId, closed: true }, () => {\n      this.output.success(`Closed ${displayId}`);\n    });\n  }\n}\n\nexport const closeCommand = new Command('close')\n  .description('Close an issue')\n  .argument('<id>', 'Issue ID')\n  .option('--reason <text>', 'Close reason')\n  .action(async (id, options, command) => {\n    const handler = new CloseHandler(command);\n    await handler.run(id, options);\n  });\n","/**\n * `tbd reopen` - Reopen a closed issue.\n *\n * See: tbd-design.md §4.4 Reopen\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotFoundError, CLIError } from '../lib/errors.js';\nimport { readIssue, writeIssue } from '../../file/storage.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { now } from '../../utils/time-utils.js';\nimport { loadIdMapping, resolveToInternalId } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\n\ninterface ReopenOptions {\n  reason?: string;\n}\n\nclass ReopenHandler extends BaseCommand {\n  async run(id: string, options: ReopenOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load ID mapping for resolution\n    const mapping = await loadIdMapping(dataSyncDir);\n\n    // Resolve input ID to internal ID\n    let internalId: string;\n    try {\n      internalId = resolveToInternalId(id, mapping);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Load existing issue\n    let issue;\n    try {\n      issue = await readIssue(dataSyncDir, internalId);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Check if not closed\n    if (issue.status !== 'closed') {\n      throw new CLIError(`Issue ${id} is not closed (status: ${issue.status})`);\n    }\n\n    if (this.checkDryRun('Would reopen issue', { id: internalId, reason: options.reason })) {\n      return;\n    }\n\n    // Update issue\n    issue.status = 'open';\n    issue.closed_at = null;\n    issue.close_reason = null;\n    issue.version += 1;\n    issue.updated_at = now();\n\n    // Optionally store reopen reason in notes if provided\n    if (options.reason) {\n      const reopenNote = `Reopened: ${options.reason}`;\n      issue.notes = issue.notes ? `${issue.notes}\\n\\n${reopenNote}` : reopenNote;\n    }\n\n    // Save\n    await this.execute(async () => {\n      await writeIssue(dataSyncDir, issue);\n    }, 'Failed to reopen issue');\n\n    // Use already loaded mapping for display\n    const showDebug = this.ctx.debug;\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const displayId = showDebug\n      ? formatDebugId(issue.id, mapping, prefix)\n      : formatDisplayId(issue.id, mapping, prefix);\n\n    this.output.data({ id: displayId, reopened: true }, () => {\n      this.output.success(`Reopened ${displayId}`);\n    });\n  }\n}\n\nexport const reopenCommand = new Command('reopen')\n  .description('Reopen a closed issue')\n  .argument('<id>', 'Issue ID')\n  .option('--reason <text>', 'Reopen reason')\n  .action(async (id, options, command) => {\n    const handler = new ReopenHandler(command);\n    await handler.run(id, options);\n  });\n","/**\n * `tbd ready` - List issues ready to work on.\n *\n * See: tbd-design.md §4.4 Ready\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotInitializedError, ValidationError } from '../lib/errors.js';\nimport { listIssues } from '../../file/storage.js';\nimport { IssueKind } from '../../lib/schemas.js';\nimport type { Issue, IssueKindType } from '../../lib/types.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { loadIdMapping } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\nimport {\n  formatIssueLine,\n  formatIssueLong,\n  formatIssueHeader,\n  type IssueForDisplay,\n} from '../lib/issue-format.js';\n\ninterface ReadyOptions {\n  type?: string;\n  limit?: string;\n  long?: boolean;\n}\n\nclass ReadyHandler extends BaseCommand {\n  async run(options: ReadyOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    // Load all issues\n    let issues: Issue[];\n    let dataSyncDir: string;\n    try {\n      dataSyncDir = await resolveDataSyncDir(tbdRoot);\n      issues = await listIssues(dataSyncDir);\n    } catch {\n      throw new NotInitializedError('No issue store found. Run `tbd init` first.');\n    }\n\n    // Build lookup map for dependency resolution\n    const issueMap = new Map(issues.map((i) => [i.id, i]));\n\n    // Build reverse lookup: which issues are blocked by which\n    // \"blocks\" dependency means \"this issue blocks target\"\n    const blockedByMap = new Map<string, string[]>();\n    for (const issue of issues) {\n      for (const dep of issue.dependencies) {\n        if (dep.type === 'blocks') {\n          const existing = blockedByMap.get(dep.target) ?? [];\n          existing.push(issue.id);\n          blockedByMap.set(dep.target, existing);\n        }\n      }\n    }\n\n    // Filter for ready issues\n    let readyIssues = issues.filter((issue) => {\n      // Must be open (not in_progress, blocked, deferred, or closed)\n      if (issue.status !== 'open') return false;\n\n      // Must not have an assignee\n      if (issue.assignee) return false;\n\n      // Must not have unresolved blocking dependencies\n      const blockers = blockedByMap.get(issue.id) ?? [];\n      const hasUnresolvedBlocker = blockers.some((blockerId) => {\n        const blocker = issueMap.get(blockerId);\n        return blocker && blocker.status !== 'closed';\n      });\n      if (hasUnresolvedBlocker) return false;\n\n      return true;\n    });\n\n    // Filter by type if specified\n    if (options.type) {\n      const result = IssueKind.safeParse(options.type);\n      if (!result.success) {\n        throw new ValidationError(`Invalid type: ${options.type}`);\n      }\n      const kind: IssueKindType = result.data;\n      readyIssues = readyIssues.filter((i) => i.kind === kind);\n    }\n\n    // Sort by priority (lowest number = highest priority)\n    readyIssues.sort((a, b) => a.priority - b.priority);\n\n    // Apply limit\n    if (options.limit) {\n      const limit = parseInt(options.limit, 10);\n      if (!isNaN(limit) && limit > 0) {\n        readyIssues = readyIssues.slice(0, limit);\n      }\n    }\n\n    // Load ID mapping and config for display\n    const mapping = await loadIdMapping(dataSyncDir);\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const showDebug = this.ctx.debug;\n\n    // Format output\n    const outputIssues = readyIssues.map((i) => ({\n      id: showDebug ? formatDebugId(i.id, mapping, prefix) : formatDisplayId(i.id, mapping, prefix),\n      priority: i.priority,\n      status: i.status,\n      kind: i.kind,\n      title: i.title,\n      description: i.description,\n    }));\n\n    this.output.data(outputIssues, () => {\n      if (outputIssues.length === 0) {\n        this.output.info('No ready issues found');\n        return;\n      }\n\n      const colors = this.output.getColors();\n      console.log(formatIssueHeader(colors));\n      for (const issue of outputIssues) {\n        if (options.long) {\n          console.log(formatIssueLong(issue as IssueForDisplay, colors));\n        } else {\n          console.log(formatIssueLine(issue as IssueForDisplay, colors));\n        }\n      }\n    });\n  }\n}\n\nexport const readyCommand = new Command('ready')\n  .description('List issues ready to work on (open, unblocked, unclaimed)')\n  .option('--type <type>', 'Filter by type')\n  .option('--limit <n>', 'Limit results')\n  .option('--long', 'Show descriptions')\n  .action(async (options, command) => {\n    const handler = new ReadyHandler(command);\n    await handler.run(options);\n  });\n","/**\n * `tbd blocked` - List blocked issues.\n *\n * See: tbd-design.md §4.4 Blocked\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotInitializedError } from '../lib/errors.js';\nimport { listIssues } from '../../file/storage.js';\nimport type { Issue } from '../../lib/types.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { loadIdMapping } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\nimport {\n  formatIssueLine,\n  formatIssueLong,\n  formatIssueHeader,\n  formatIssueCompact,\n  type IssueForDisplay,\n} from '../lib/issue-format.js';\n\ninterface BlockedOptions {\n  limit?: string;\n  long?: boolean;\n}\n\nclass BlockedHandler extends BaseCommand {\n  async run(options: BlockedOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    // Load all issues\n    let issues: Issue[];\n    let dataSyncDir: string;\n    try {\n      dataSyncDir = await resolveDataSyncDir(tbdRoot);\n      issues = await listIssues(dataSyncDir);\n    } catch {\n      throw new NotInitializedError('No issue store found. Run `tbd init` first.');\n    }\n\n    // Load ID mapping and config for display\n    const mapping = await loadIdMapping(dataSyncDir);\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const showDebug = this.ctx.debug;\n\n    // Build lookup map for dependency resolution\n    const issueMap = new Map(issues.map((i) => [i.id, i]));\n\n    // Build reverse lookup: which issues are blocked by which\n    // \"blocks\" dependency means \"this issue blocks target\"\n    const blockedByMap = new Map<string, string[]>();\n    for (const issue of issues) {\n      for (const dep of issue.dependencies) {\n        if (dep.type === 'blocks') {\n          const existing = blockedByMap.get(dep.target) ?? [];\n          existing.push(issue.id);\n          blockedByMap.set(dep.target, existing);\n        }\n      }\n    }\n\n    // Find blocked issues (status=blocked OR has unresolved blocking dependencies)\n    let blockedIssues: {\n      issue: Issue;\n      blockedBy: { id: string; issue: Issue }[];\n      explicitlyBlocked?: boolean;\n    }[] = [];\n\n    for (const issue of issues) {\n      // Skip closed issues\n      if (issue.status === 'closed') continue;\n\n      const unresolvedBlockers: { id: string; issue: Issue }[] = [];\n\n      // Check if status is explicitly blocked\n      const isExplicitlyBlocked = issue.status === 'blocked';\n\n      // Check for unresolved blocking dependencies (from reverse lookup)\n      const blockerIds = blockedByMap.get(issue.id) ?? [];\n      for (const blockerId of blockerIds) {\n        const blocker = issueMap.get(blockerId);\n        if (blocker && blocker.status !== 'closed') {\n          const blockerDisplayId = showDebug\n            ? formatDebugId(blockerId, mapping, prefix)\n            : formatDisplayId(blockerId, mapping, prefix);\n          unresolvedBlockers.push({ id: blockerDisplayId, issue: blocker });\n        }\n      }\n\n      if (isExplicitlyBlocked || unresolvedBlockers.length > 0) {\n        blockedIssues.push({\n          issue,\n          blockedBy: unresolvedBlockers,\n          explicitlyBlocked: isExplicitlyBlocked && unresolvedBlockers.length === 0,\n        });\n      }\n    }\n\n    // Sort by priority\n    blockedIssues.sort((a, b) => a.issue.priority - b.issue.priority);\n\n    // Apply limit\n    if (options.limit) {\n      const limit = parseInt(options.limit, 10);\n      if (!isNaN(limit) && limit > 0) {\n        blockedIssues = blockedIssues.slice(0, limit);\n      }\n    }\n\n    // Format output\n    const colors = this.output.getColors();\n    const outputIssues = blockedIssues.map((b) => {\n      const displayId = showDebug\n        ? formatDebugId(b.issue.id, mapping, prefix)\n        : formatDisplayId(b.issue.id, mapping, prefix);\n      return {\n        id: displayId,\n        priority: b.issue.priority,\n        status: b.issue.status,\n        kind: b.issue.kind,\n        title: b.issue.title,\n        description: b.issue.description,\n        blockedBy: b.explicitlyBlocked\n          ? ['(explicitly blocked)']\n          : b.blockedBy.map((blocker) =>\n              formatIssueCompact(\n                {\n                  id: blocker.id,\n                  priority: blocker.issue.priority,\n                  status: blocker.issue.status,\n                  kind: blocker.issue.kind,\n                  title: blocker.issue.title.slice(0, 20),\n                },\n                colors,\n              ),\n            ),\n      };\n    });\n\n    this.output.data(outputIssues, () => {\n      if (outputIssues.length === 0) {\n        this.output.info('No blocked issues found');\n        return;\n      }\n\n      console.log(formatIssueHeader(colors));\n      for (const issue of outputIssues) {\n        if (options.long) {\n          console.log(formatIssueLong(issue as IssueForDisplay, colors));\n        } else {\n          console.log(formatIssueLine(issue as IssueForDisplay, colors));\n        }\n        // Show blockers on indented line\n        console.log(`      ${colors.dim('blocked by:')} ${issue.blockedBy.join(', ')}`);\n      }\n    });\n  }\n}\n\nexport const blockedCommand = new Command('blocked')\n  .description('List blocked issues')\n  .option('--limit <n>', 'Limit results')\n  .option('--long', 'Show descriptions')\n  .action(async (options, command) => {\n    const handler = new BlockedHandler(command);\n    await handler.run(options);\n  });\n","/**\n * `tbd stale` - List stale issues.\n *\n * See: tbd-design.md §4.4 Stale\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotInitializedError, ValidationError } from '../lib/errors.js';\nimport { listIssues } from '../../file/storage.js';\nimport { IssueStatus } from '../../lib/schemas.js';\nimport type { Issue, IssueStatusType } from '../../lib/types.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { nowDate, parseDate } from '../../utils/time-utils.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { loadIdMapping } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\n\ninterface StaleOptions {\n  days?: string;\n  status?: string;\n  limit?: string;\n}\n\nclass StaleHandler extends BaseCommand {\n  async run(options: StaleOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    // Load all issues\n    let issues: Issue[];\n    let dataSyncDir: string;\n    try {\n      dataSyncDir = await resolveDataSyncDir(tbdRoot);\n      issues = await listIssues(dataSyncDir);\n    } catch {\n      throw new NotInitializedError('No issue store found. Run `tbd init` first.');\n    }\n\n    // Parse days threshold (default: 7)\n    const daysThreshold = options.days ? parseInt(options.days, 10) : 7;\n    if (isNaN(daysThreshold) || daysThreshold < 0) {\n      throw new ValidationError('Invalid days value. Must be a positive number.');\n    }\n\n    // Parse status filter (default: open, in_progress)\n    const allowedStatuses = new Set<IssueStatusType>();\n    if (options.status) {\n      const statuses = options.status.split(',').map((s) => s.trim());\n      for (const s of statuses) {\n        const result = IssueStatus.safeParse(s);\n        if (!result.success) {\n          throw new ValidationError(`Invalid status: ${s}`);\n        }\n        allowedStatuses.add(result.data);\n      }\n    } else {\n      // Default: open and in_progress\n      allowedStatuses.add('open');\n      allowedStatuses.add('in_progress');\n    }\n\n    const currentTime = nowDate();\n    const msPerDay = 24 * 60 * 60 * 1000;\n\n    // Filter stale issues\n    let staleIssues: { issue: Issue; daysSinceUpdate: number }[] = [];\n\n    for (const issue of issues) {\n      // Check status filter\n      if (!allowedStatuses.has(issue.status)) continue;\n\n      // Calculate days since last update\n      const updatedAt = parseDate(issue.updated_at);\n      if (!updatedAt) continue;\n      const daysSinceUpdate = Math.floor((currentTime.getTime() - updatedAt.getTime()) / msPerDay);\n\n      if (daysSinceUpdate >= daysThreshold) {\n        staleIssues.push({ issue, daysSinceUpdate });\n      }\n    }\n\n    // Sort by days since update (most stale first)\n    staleIssues.sort((a, b) => b.daysSinceUpdate - a.daysSinceUpdate);\n\n    // Apply limit\n    if (options.limit) {\n      const limit = parseInt(options.limit, 10);\n      if (!isNaN(limit) && limit > 0) {\n        staleIssues = staleIssues.slice(0, limit);\n      }\n    }\n\n    // Load ID mapping and config for display\n    const mapping = await loadIdMapping(dataSyncDir);\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const showDebug = this.ctx.debug;\n\n    // Format output\n    const outputIssues = staleIssues.map((s) => ({\n      id: showDebug\n        ? formatDebugId(s.issue.id, mapping, prefix)\n        : formatDisplayId(s.issue.id, mapping, prefix),\n      days: s.daysSinceUpdate,\n      status: s.issue.status,\n      title: s.issue.title,\n    }));\n\n    this.output.data(outputIssues, () => {\n      if (outputIssues.length === 0) {\n        this.output.info(`No stale issues found (threshold: ${daysThreshold} days)`);\n        return;\n      }\n\n      const colors = this.output.getColors();\n      console.log(\n        `${colors.dim('ISSUE'.padEnd(12))}${colors.dim('DAYS'.padEnd(6))}${colors.dim('STATUS'.padEnd(14))}${colors.dim('TITLE')}`,\n      );\n      for (const issue of outputIssues) {\n        console.log(\n          `${colors.id(issue.id.padEnd(12))}${String(issue.days).padEnd(6)}${issue.status.padEnd(14)}${issue.title}`,\n        );\n      }\n    });\n  }\n}\n\nexport const staleCommand = new Command('stale')\n  .description('List issues not updated recently')\n  .option('--days <n>', 'Days since last update (default: 7)')\n  .option('--status <status>', 'Filter by status (default: open, in_progress)')\n  .option('--limit <n>', 'Limit results')\n  .action(async (options, command) => {\n    const handler = new StaleHandler(command);\n    await handler.run(options);\n  });\n","/**\n * `tbd label` - Label management commands.\n *\n * See: tbd-design.md §4.5 Label Commands\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotFoundError, NotInitializedError } from '../lib/errors.js';\nimport { readIssue, writeIssue, listIssues } from '../../file/storage.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { now } from '../../utils/time-utils.js';\nimport { loadIdMapping, resolveToInternalId } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\n\n// Add label\nclass LabelAddHandler extends BaseCommand {\n  async run(id: string, labels: string[]): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load ID mapping for resolution\n    const mapping = await loadIdMapping(dataSyncDir);\n\n    // Resolve input ID to internal ID\n    let internalId: string;\n    try {\n      internalId = resolveToInternalId(id, mapping);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Load existing issue\n    let issue;\n    try {\n      issue = await readIssue(dataSyncDir, internalId);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    if (this.checkDryRun('Would add labels', { id: internalId, labels })) {\n      return;\n    }\n\n    // Add labels (avoiding duplicates)\n    const labelsSet = new Set(issue.labels);\n    let added = 0;\n    for (const label of labels) {\n      if (!labelsSet.has(label)) {\n        labelsSet.add(label);\n        added++;\n      }\n    }\n\n    if (added === 0) {\n      this.output.info('All labels already present');\n      return;\n    }\n\n    issue.labels = [...labelsSet];\n    issue.version += 1;\n    issue.updated_at = now();\n\n    await this.execute(async () => {\n      await writeIssue(dataSyncDir, issue);\n    }, 'Failed to update issue');\n\n    // Use already loaded mapping for display\n    const showDebug = this.ctx.debug;\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const displayId = showDebug\n      ? formatDebugId(issue.id, mapping, prefix)\n      : formatDisplayId(issue.id, mapping, prefix);\n\n    this.output.data({ id: displayId, addedLabels: labels }, () => {\n      this.output.success(`Added labels to ${displayId}: ${labels.join(', ')}`);\n    });\n  }\n}\n\n// Remove label\nclass LabelRemoveHandler extends BaseCommand {\n  async run(id: string, labels: string[]): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load ID mapping for resolution\n    const mapping = await loadIdMapping(dataSyncDir);\n\n    // Resolve input ID to internal ID\n    let internalId: string;\n    try {\n      internalId = resolveToInternalId(id, mapping);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Load existing issue\n    let issue;\n    try {\n      issue = await readIssue(dataSyncDir, internalId);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    if (this.checkDryRun('Would remove labels', { id: internalId, labels })) {\n      return;\n    }\n\n    // Remove labels\n    const removeSet = new Set(labels);\n    const originalCount = issue.labels.length;\n    issue.labels = issue.labels.filter((l) => !removeSet.has(l));\n    const removed = originalCount - issue.labels.length;\n\n    if (removed === 0) {\n      this.output.info('No matching labels found');\n      return;\n    }\n\n    issue.version += 1;\n    issue.updated_at = now();\n\n    await this.execute(async () => {\n      await writeIssue(dataSyncDir, issue);\n    }, 'Failed to update issue');\n\n    // Use already loaded mapping for display\n    const showDebug = this.ctx.debug;\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const displayId = showDebug\n      ? formatDebugId(issue.id, mapping, prefix)\n      : formatDisplayId(issue.id, mapping, prefix);\n\n    this.output.data({ id: displayId, removedLabels: labels }, () => {\n      this.output.success(`Removed labels from ${displayId}: ${labels.join(', ')}`);\n    });\n  }\n}\n\n// List labels\nclass LabelListHandler extends BaseCommand {\n  async run(): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load all issues and collect unique labels\n    let issues;\n    try {\n      issues = await listIssues(dataSyncDir);\n    } catch {\n      throw new NotInitializedError('No issue store found. Run `tbd init` first.');\n    }\n\n    // Collect labels with counts\n    const labelCounts = new Map<string, number>();\n    for (const issue of issues) {\n      for (const label of issue.labels) {\n        labelCounts.set(label, (labelCounts.get(label) ?? 0) + 1);\n      }\n    }\n\n    // Sort by count (descending), then alphabetically\n    const sortedLabels = [...labelCounts.entries()].sort((a, b) => {\n      if (b[1] !== a[1]) return b[1] - a[1];\n      return a[0].localeCompare(b[0]);\n    });\n\n    const output = sortedLabels.map(([label, count]) => ({ label, count }));\n\n    this.output.data(output, () => {\n      if (output.length === 0) {\n        this.output.info('No labels in use');\n        return;\n      }\n\n      const colors = this.output.getColors();\n      console.log(`${colors.dim('LABEL'.padEnd(24))}${colors.dim('COUNT')}`);\n      for (const { label, count } of output) {\n        console.log(`${colors.label(label.padEnd(24))}${count}`);\n      }\n    });\n  }\n}\n\nconst addCommand = new Command('add')\n  .description('Add labels to an issue')\n  .argument('<id>', 'Issue ID')\n  .argument('<labels...>', 'Labels to add')\n  .action(async (id, labels, _options, command) => {\n    const handler = new LabelAddHandler(command);\n    await handler.run(id, labels);\n  });\n\nconst removeCommand = new Command('remove')\n  .description('Remove labels from an issue')\n  .argument('<id>', 'Issue ID')\n  .argument('<labels...>', 'Labels to remove')\n  .action(async (id, labels, _options, command) => {\n    const handler = new LabelRemoveHandler(command);\n    await handler.run(id, labels);\n  });\n\nconst listLabelCommand = new Command('list')\n  .description('List all labels in use')\n  .action(async (_options, command) => {\n    const handler = new LabelListHandler(command);\n    await handler.run();\n  });\n\nexport const labelCommand = new Command('label')\n  .description('Manage issue labels')\n  .addCommand(addCommand)\n  .addCommand(removeCommand)\n  .addCommand(listLabelCommand);\n","/**\n * `tbd dep` - Dependency management commands.\n *\n * See: tbd-design.md §4.6 Dependency Commands\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotFoundError, ValidationError } from '../lib/errors.js';\nimport { readIssue, writeIssue, listIssues } from '../../file/storage.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport type { Issue } from '../../lib/types.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { now } from '../../utils/time-utils.js';\nimport { loadIdMapping, resolveToInternalId } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\n\n// Add dependency: \"A depends on B\" means B blocks A\nclass DependsAddHandler extends BaseCommand {\n  async run(issueId: string, dependsOnId: string): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load ID mapping for resolution\n    const mapping = await loadIdMapping(dataSyncDir);\n\n    // Resolve both IDs to internal IDs\n    // issueId = the issue that depends on something\n    // dependsOnId = the issue it depends on (the blocker)\n    let internalIssueId: string;\n    let internalDependsOnId: string;\n    try {\n      internalIssueId = resolveToInternalId(issueId, mapping);\n    } catch {\n      throw new NotFoundError('Issue', issueId);\n    }\n    try {\n      internalDependsOnId = resolveToInternalId(dependsOnId, mapping);\n    } catch {\n      throw new NotFoundError('Issue', dependsOnId);\n    }\n\n    // Verify issueId exists\n    try {\n      await readIssue(dataSyncDir, internalIssueId);\n    } catch {\n      throw new NotFoundError('Issue', issueId);\n    }\n\n    // Load the blocking issue (dependsOnId) - this is where we add the dependency\n    let blockerIssue;\n    try {\n      blockerIssue = await readIssue(dataSyncDir, internalDependsOnId);\n    } catch {\n      throw new NotFoundError('Issue', dependsOnId);\n    }\n\n    // Check for self-reference\n    if (internalIssueId === internalDependsOnId) {\n      throw new ValidationError('Issue cannot depend on itself');\n    }\n\n    if (\n      this.checkDryRun('Would add dependency', {\n        issue: internalIssueId,\n        dependsOn: internalDependsOnId,\n      })\n    ) {\n      return;\n    }\n\n    // Check if dependency already exists (dependsOnId blocks issueId)\n    const exists = blockerIssue.dependencies.some(\n      (dep) => dep.type === 'blocks' && dep.target === internalIssueId,\n    );\n    if (exists) {\n      this.output.info('Dependency already exists');\n      return;\n    }\n\n    // Add the dependency: dependsOnId blocks issueId\n    blockerIssue.dependencies.push({ type: 'blocks', target: internalIssueId });\n    blockerIssue.version += 1;\n    blockerIssue.updated_at = now();\n\n    await this.execute(async () => {\n      await writeIssue(dataSyncDir, blockerIssue);\n    }, 'Failed to update issue');\n\n    // Use already loaded mapping for display\n    const showDebug = this.ctx.debug;\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const displayIssueId = showDebug\n      ? formatDebugId(internalIssueId, mapping, prefix)\n      : formatDisplayId(internalIssueId, mapping, prefix);\n    const displayDependsOnId = showDebug\n      ? formatDebugId(internalDependsOnId, mapping, prefix)\n      : formatDisplayId(internalDependsOnId, mapping, prefix);\n\n    this.output.data({ issue: displayIssueId, dependsOn: displayDependsOnId }, () => {\n      this.output.success(`${displayIssueId} now depends on ${displayDependsOnId}`);\n    });\n  }\n}\n\n// Remove dependency: \"A no longer depends on B\" means B no longer blocks A\nclass DependsRemoveHandler extends BaseCommand {\n  async run(issueId: string, dependsOnId: string): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load ID mapping for resolution\n    const mapping = await loadIdMapping(dataSyncDir);\n\n    // Resolve both IDs to internal IDs\n    let internalIssueId: string;\n    let internalDependsOnId: string;\n    try {\n      internalIssueId = resolveToInternalId(issueId, mapping);\n    } catch {\n      throw new NotFoundError('Issue', issueId);\n    }\n    try {\n      internalDependsOnId = resolveToInternalId(dependsOnId, mapping);\n    } catch {\n      throw new NotFoundError('Issue', dependsOnId);\n    }\n\n    // Load the blocker issue (dependsOnId) - this is where the dependency is stored\n    let blockerIssue;\n    try {\n      blockerIssue = await readIssue(dataSyncDir, internalDependsOnId);\n    } catch {\n      throw new NotFoundError('Issue', dependsOnId);\n    }\n\n    if (\n      this.checkDryRun('Would remove dependency', {\n        issue: internalIssueId,\n        dependsOn: internalDependsOnId,\n      })\n    ) {\n      return;\n    }\n\n    // Find and remove the dependency (dependsOnId blocks issueId)\n    const initialLength = blockerIssue.dependencies.length;\n    blockerIssue.dependencies = blockerIssue.dependencies.filter(\n      (dep) => !(dep.type === 'blocks' && dep.target === internalIssueId),\n    );\n\n    if (blockerIssue.dependencies.length === initialLength) {\n      this.output.info('Dependency not found');\n      return;\n    }\n\n    blockerIssue.version += 1;\n    blockerIssue.updated_at = now();\n\n    await this.execute(async () => {\n      await writeIssue(dataSyncDir, blockerIssue);\n    }, 'Failed to update issue');\n\n    // Use already loaded mapping for display\n    const showDebug = this.ctx.debug;\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const displayIssueId = showDebug\n      ? formatDebugId(internalIssueId, mapping, prefix)\n      : formatDisplayId(internalIssueId, mapping, prefix);\n    const displayDependsOnId = showDebug\n      ? formatDebugId(internalDependsOnId, mapping, prefix)\n      : formatDisplayId(internalDependsOnId, mapping, prefix);\n\n    this.output.data({ issue: displayIssueId, removed: displayDependsOnId }, () => {\n      this.output.success(`${displayIssueId} no longer depends on ${displayDependsOnId}`);\n    });\n  }\n}\n\n// List dependencies\nclass DependsListHandler extends BaseCommand {\n  async run(id: string): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load ID mapping for resolution and display\n    const mapping = await loadIdMapping(dataSyncDir);\n\n    // Resolve input ID to internal ID\n    let internalId: string;\n    try {\n      internalId = resolveToInternalId(id, mapping);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Load the issue\n    let issue;\n    try {\n      issue = await readIssue(dataSyncDir, internalId);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Load all issues to find reverse dependencies\n    let allIssues: Issue[];\n    try {\n      allIssues = await listIssues(dataSyncDir);\n    } catch {\n      allIssues = [];\n    }\n\n    const showDebug = this.ctx.debug;\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n\n    // Find what this issue blocks (from its dependencies)\n    const blocks = issue.dependencies\n      .filter((dep) => dep.type === 'blocks')\n      .map((dep) =>\n        showDebug\n          ? formatDebugId(dep.target, mapping, prefix)\n          : formatDisplayId(dep.target, mapping, prefix),\n      );\n\n    // Find what blocks this issue (reverse lookup)\n    const blockedBy: string[] = [];\n    for (const other of allIssues) {\n      for (const dep of other.dependencies) {\n        if (dep.type === 'blocks' && dep.target === internalId) {\n          blockedBy.push(\n            showDebug\n              ? formatDebugId(other.id, mapping, prefix)\n              : formatDisplayId(other.id, mapping, prefix),\n          );\n        }\n      }\n    }\n\n    const deps = { blocks, blockedBy };\n    this.output.data(deps, () => {\n      const colors = this.output.getColors();\n      if (deps.blocks.length > 0) {\n        console.log(`${colors.bold('Blocks:')} ${deps.blocks.join(', ')}`);\n      }\n      if (deps.blockedBy.length > 0) {\n        console.log(`${colors.bold('Blocked by:')} ${deps.blockedBy.join(', ')}`);\n      }\n      if (deps.blocks.length === 0 && deps.blockedBy.length === 0) {\n        console.log('No dependencies');\n      }\n    });\n  }\n}\n\nconst addCommand = new Command('add')\n  .description('Add dependency (issue depends on depends-on)')\n  .argument('<issue>', 'Issue ID that depends on something')\n  .argument('<depends-on>', 'Issue ID that must be completed first')\n  .action(async (issue, dependsOn, _options, command) => {\n    const handler = new DependsAddHandler(command);\n    await handler.run(issue, dependsOn);\n  });\n\nconst removeCommand = new Command('remove')\n  .description('Remove dependency (issue no longer depends on depends-on)')\n  .argument('<issue>', 'Issue ID')\n  .argument('<depends-on>', 'Issue ID it depended on')\n  .action(async (issue, dependsOn, _options, command) => {\n    const handler = new DependsRemoveHandler(command);\n    await handler.run(issue, dependsOn);\n  });\n\nconst listDepsCommand = new Command('list')\n  .description('List dependencies for an issue')\n  .argument('<id>', 'Issue ID')\n  .action(async (id, _options, command) => {\n    const handler = new DependsListHandler(command);\n    await handler.run(id);\n  });\n\nexport const depCommand = new Command('dep')\n  .description('Manage issue dependencies')\n  .addCommand(addCommand)\n  .addCommand(removeCommand)\n  .addCommand(listDepsCommand);\n","/**\n * Sync summary formatting utilities.\n *\n * Provides consistent formatting for sync operation results.\n */\n\n/**\n * Tallies for a sync direction (sent or received).\n */\nexport interface SyncTallies {\n  new: number;\n  updated: number;\n  deleted: number;\n}\n\n/**\n * Full sync summary with both directions.\n */\nexport interface SyncSummary {\n  sent: SyncTallies;\n  received: SyncTallies;\n  conflicts: number;\n}\n\n/**\n * Create empty sync tallies.\n */\nexport function emptyTallies(): SyncTallies {\n  return { new: 0, updated: 0, deleted: 0 };\n}\n\n/**\n * Create empty sync summary.\n */\nexport function emptySummary(): SyncSummary {\n  return {\n    sent: emptyTallies(),\n    received: emptyTallies(),\n    conflicts: 0,\n  };\n}\n\n/**\n * Check if tallies have any non-zero values.\n */\nexport function hasTallies(tallies: SyncTallies): boolean {\n  return tallies.new > 0 || tallies.updated > 0 || tallies.deleted > 0;\n}\n\n/**\n * Format tallies for display (e.g., \"1 new, 2 updated\").\n * Omits zero counts.\n */\nexport function formatTallies(tallies: SyncTallies): string {\n  const parts: string[] = [];\n\n  if (tallies.new > 0) {\n    parts.push(`${tallies.new} new`);\n  }\n  if (tallies.updated > 0) {\n    parts.push(`${tallies.updated} updated`);\n  }\n  if (tallies.deleted > 0) {\n    parts.push(`${tallies.deleted} deleted`);\n  }\n\n  return parts.join(', ');\n}\n\n/**\n * Format sync summary for display.\n *\n * Examples:\n * - \"sent 1 new\"\n * - \"sent 2 updated, received 1 new\"\n * - \"received 3 new, 1 updated\"\n * - \"\" (empty if nothing to report - caller should show \"Already in sync\")\n */\nexport function formatSyncSummary(summary: SyncSummary): string {\n  const parts: string[] = [];\n\n  const sentStr = formatTallies(summary.sent);\n  const receivedStr = formatTallies(summary.received);\n\n  if (sentStr) {\n    parts.push(`sent ${sentStr}`);\n  }\n  if (receivedStr) {\n    parts.push(`received ${receivedStr}`);\n  }\n\n  if (parts.length === 0) {\n    return '';\n  }\n\n  let result = parts.join(', ');\n\n  if (summary.conflicts > 0) {\n    result += ` (${summary.conflicts} conflict${summary.conflicts === 1 ? '' : 's'} resolved)`;\n  }\n\n  return result;\n}\n\n/**\n * Parse git status --porcelain output to get tallies.\n *\n * @param statusOutput - Output from `git status --porcelain`\n * @returns Tallies for new, updated, deleted files\n */\nexport function parseGitStatus(statusOutput: string): SyncTallies {\n  const tallies = emptyTallies();\n\n  if (!statusOutput || statusOutput.trim() === '') {\n    return tallies;\n  }\n\n  for (const line of statusOutput.split('\\n')) {\n    if (!line) continue;\n\n    const statusCode = line.slice(0, 2).trim();\n\n    switch (statusCode) {\n      case 'A':\n      case '??':\n        tallies.new++;\n        break;\n      case 'M':\n      case 'MM':\n        tallies.updated++;\n        break;\n      case 'D':\n        tallies.deleted++;\n        break;\n    }\n  }\n\n  return tallies;\n}\n\n/**\n * Parse git diff --name-status output to get tallies.\n *\n * @param diffOutput - Output from `git diff --name-status`\n * @returns Tallies for new, updated, deleted files\n */\nexport function parseGitDiff(diffOutput: string): SyncTallies {\n  const tallies = emptyTallies();\n\n  if (!diffOutput || diffOutput.trim() === '') {\n    return tallies;\n  }\n\n  for (const line of diffOutput.split('\\n')) {\n    if (!line) continue;\n\n    const statusCode = line[0];\n\n    switch (statusCode) {\n      case 'A':\n        tallies.new++;\n        break;\n      case 'M':\n        tallies.updated++;\n        break;\n      case 'D':\n        tallies.deleted++;\n        break;\n    }\n  }\n\n  return tallies;\n}\n","/**\n * `tbd sync` - Synchronization commands.\n *\n * See: tbd-design.md §4.7 Sync Commands\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotInitializedError, SyncError } from '../lib/errors.js';\nimport { readConfig } from '../../file/config.js';\nimport { listIssues, readIssue, writeIssue } from '../../file/storage.js';\nimport {\n  git,\n  withIsolatedIndex,\n  mergeIssues,\n  pushWithRetry,\n  type ConflictEntry,\n  type PushResult,\n} from '../../file/git.js';\nimport { resolveDataSyncDir, DATA_SYNC_DIR, WORKTREE_DIR } from '../../lib/paths.js';\nimport { join } from 'node:path';\nimport {\n  type SyncSummary,\n  type SyncTallies,\n  emptySummary,\n  emptyTallies,\n  hasTallies,\n  formatSyncSummary,\n  parseGitStatus,\n  parseGitDiff,\n} from '../../lib/sync-summary.js';\n\ninterface SyncOptions {\n  push?: boolean;\n  pull?: boolean;\n  status?: boolean;\n  force?: boolean;\n}\n\ninterface SyncStatus {\n  synced: boolean;\n  localChanges: string[];\n  remoteChanges: string[];\n  syncBranch: string;\n  remote: string;\n  ahead: number;\n  behind: number;\n}\n\nclass SyncHandler extends BaseCommand {\n  private dataSyncDir = '';\n\n  async run(options: SyncOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    this.dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load config to get sync branch\n    let config;\n    try {\n      config = await readConfig(tbdRoot);\n    } catch {\n      throw new NotInitializedError('Not a tbd repository. Run `tbd init` first.');\n    }\n\n    const syncBranch = config.sync.branch;\n    const remote = config.sync.remote;\n\n    if (options.status) {\n      await this.showStatus(syncBranch, remote);\n      return;\n    }\n\n    if (this.checkDryRun('Would sync repository', { syncBranch, remote })) {\n      return;\n    }\n\n    if (options.pull) {\n      await this.pullChanges(syncBranch, remote);\n    } else if (options.push) {\n      await this.pushChanges(syncBranch, remote);\n    } else {\n      // Full sync: pull then push\n      await this.fullSync(syncBranch, remote, options.force);\n    }\n  }\n\n  private async showStatus(syncBranch: string, remote: string): Promise<void> {\n    const status = await this.getSyncStatus(syncBranch, remote);\n\n    this.output.data(status, () => {\n      const colors = this.output.getColors();\n\n      if (status.synced) {\n        this.output.success('Repository is in sync');\n        return;\n      }\n\n      console.log(colors.bold(`Sync status: ${syncBranch} ↔ ${remote}/${syncBranch}`));\n      console.log('');\n\n      if (status.ahead > 0) {\n        console.log(`  ${colors.id(`↑ ${status.ahead}`)} commit(s) ahead (to push)`);\n      }\n      if (status.behind > 0) {\n        console.log(`  ${colors.dim(`↓ ${status.behind}`)} commit(s) behind (to pull)`);\n      }\n\n      if (status.localChanges.length > 0) {\n        console.log('');\n        console.log(colors.bold('Local changes (not yet pushed):'));\n        for (const change of status.localChanges) {\n          console.log(`  ${change}`);\n        }\n      }\n\n      if (status.remoteChanges.length > 0) {\n        console.log('');\n        console.log(colors.bold('Remote changes (not yet pulled):'));\n        for (const change of status.remoteChanges) {\n          console.log(`  ${change}`);\n        }\n      }\n    });\n  }\n\n  private async getSyncStatus(syncBranch: string, remote: string): Promise<SyncStatus> {\n    const localChanges: string[] = [];\n    const remoteChanges: string[] = [];\n    let ahead = 0;\n    let behind = 0;\n\n    // Check for local issues\n    try {\n      const issues = await listIssues(this.dataSyncDir);\n      // Check for uncommitted changes in the worktree\n      if (issues.length > 0) {\n        try {\n          const status = await git('status', '--porcelain', DATA_SYNC_DIR);\n          if (status) {\n            for (const line of status.split('\\n')) {\n              if (!line) continue;\n              const statusCode = line.slice(0, 2).trim();\n              const file = line.slice(3);\n              if (statusCode === 'M') {\n                localChanges.push(`modified: ${file}`);\n              } else if (statusCode === 'A' || statusCode === '??') {\n                localChanges.push(`new: ${file}`);\n              } else if (statusCode === 'D') {\n                localChanges.push(`deleted: ${file}`);\n              }\n            }\n          }\n        } catch {\n          this.output.debug('Git not available or not a git repo');\n        }\n      }\n    } catch {\n      this.output.debug('No issues directory');\n    }\n\n    // Check for remote changes\n    try {\n      await git('fetch', remote, syncBranch);\n\n      // Count commits ahead/behind\n      try {\n        const aheadOutput = await git(\n          'rev-list',\n          '--count',\n          `${remote}/${syncBranch}..${syncBranch}`,\n        );\n        ahead = parseInt(aheadOutput, 10) || 0;\n      } catch {\n        this.output.debug('Branch does not exist locally');\n      }\n\n      try {\n        const behindOutput = await git(\n          'rev-list',\n          '--count',\n          `${syncBranch}..${remote}/${syncBranch}`,\n        );\n        behind = parseInt(behindOutput, 10) || 0;\n      } catch {\n        this.output.debug('Remote branch does not exist');\n      }\n\n      // Get commit messages for remote changes\n      if (behind > 0) {\n        const logOutput = await git(\n          'log',\n          '--oneline',\n          `${syncBranch}..${remote}/${syncBranch}`,\n          '--limit=10',\n        );\n        for (const line of logOutput.split('\\n')) {\n          if (line) {\n            remoteChanges.push(line);\n          }\n        }\n      }\n    } catch {\n      this.output.debug('Remote not available or sync branch does not exist');\n    }\n\n    return {\n      synced:\n        localChanges.length === 0 && remoteChanges.length === 0 && ahead === 0 && behind === 0,\n      localChanges,\n      remoteChanges,\n      syncBranch,\n      remote,\n      ahead,\n      behind,\n    };\n  }\n\n  private async pullChanges(syncBranch: string, remote: string): Promise<void> {\n    const spinner = this.output.spinner('Pulling from remote...');\n    try {\n      await git('fetch', remote, syncBranch);\n\n      // Get list of changed files\n      let behind = 0;\n      try {\n        const behindOutput = await git(\n          'rev-list',\n          '--count',\n          `${syncBranch}..${remote}/${syncBranch}`,\n        );\n        behind = parseInt(behindOutput, 10) || 0;\n      } catch {\n        this.output.debug('Branch does not exist');\n      }\n\n      spinner.stop();\n      if (behind === 0) {\n        this.output.success('Already up to date');\n        return;\n      }\n\n      // Merge changes using isolated index\n      await withIsolatedIndex(async () => {\n        // Read the remote tree\n        await git('read-tree', `${remote}/${syncBranch}`);\n\n        // Update local branch to remote\n        const remoteCommit = await git('rev-parse', `${remote}/${syncBranch}`);\n        await git('update-ref', `refs/heads/${syncBranch}`, remoteCommit);\n      });\n\n      this.output.success(`Pulled ${behind} change(s) from ${remote}/${syncBranch}`);\n    } catch (error) {\n      spinner.stop();\n      const msg = (error as Error).message;\n      if (msg.includes('not found') || msg.includes('does not exist')) {\n        this.output.info(`Remote branch ${remote}/${syncBranch} does not exist yet`);\n      } else {\n        throw new SyncError(`Failed to pull: ${msg}`);\n      }\n    }\n  }\n\n  /**\n   * Commit any uncommitted changes in the worktree to the sync branch.\n   * This must be called before pushing to ensure changes are captured.\n   *\n   * @returns Tallies of new/updated/deleted files committed\n   */\n  private async commitWorktreeChanges(): Promise<SyncTallies> {\n    const worktreePath = join(process.cwd(), WORKTREE_DIR);\n\n    try {\n      // Check for uncommitted changes (untracked, modified, or deleted)\n      const status = await git('-C', worktreePath, 'status', '--porcelain');\n      if (!status || status.trim() === '') {\n        return emptyTallies(); // Nothing to commit\n      }\n\n      // Parse status to get tallies\n      const tallies = parseGitStatus(status);\n      const fileCount = tallies.new + tallies.updated + tallies.deleted;\n\n      // Stage all changes\n      await git('-C', worktreePath, 'add', '-A');\n\n      // Commit the changes\n      const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);\n      await git(\n        '-C',\n        worktreePath,\n        'commit',\n        '-m',\n        `tbd sync: ${timestamp} (${fileCount} file${fileCount === 1 ? '' : 's'})`,\n      );\n\n      return tallies;\n    } catch (error) {\n      // If commit fails (e.g., nothing to commit after staging), that's ok\n      const msg = (error as Error).message;\n      if (msg.includes('nothing to commit')) {\n        return emptyTallies();\n      }\n      throw error;\n    }\n  }\n\n  private async pushChanges(syncBranch: string, remote: string): Promise<void> {\n    const spinner = this.output.spinner('Pushing to remote...');\n    try {\n      // Commit any uncommitted changes in the worktree before pushing\n      const committedTallies = await this.commitWorktreeChanges();\n      const committedCount =\n        committedTallies.new + committedTallies.updated + committedTallies.deleted;\n      if (committedCount > 0) {\n        this.output.info(`Committed ${committedCount} file(s) to sync branch`);\n      }\n\n      // Check how many commits we're ahead of remote\n      let ahead = 0;\n      try {\n        await git('fetch', remote, syncBranch);\n        const aheadOutput = await git(\n          'rev-list',\n          '--count',\n          `${remote}/${syncBranch}..${syncBranch}`,\n        );\n        ahead = parseInt(aheadOutput, 10) || 0;\n        this.output.debug(`Ahead of remote by ${ahead} commit(s)`);\n      } catch {\n        // Remote branch doesn't exist - count all local commits\n        try {\n          const countOutput = await git('rev-list', '--count', syncBranch);\n          ahead = parseInt(countOutput, 10) || 0;\n          this.output.debug(`Remote branch not found, ${ahead} local commit(s) to push`);\n        } catch {\n          ahead = 0;\n          this.output.debug('Could not count local commits');\n        }\n      }\n\n      if (ahead === 0) {\n        spinner.stop();\n        this.output.success('Already up to date');\n        return;\n      }\n\n      // Use push with retry\n      const result = await this.doPushWithRetry(syncBranch, remote);\n      spinner.stop();\n\n      if (result.success) {\n        this.output.success(`Pushed ${ahead} commit(s) to ${remote}/${syncBranch}`);\n      } else if (result.conflicts && result.conflicts.length > 0) {\n        this.output.warn(\n          `Push completed with ${result.conflicts.length} conflict(s) (see attic for details)`,\n        );\n      } else {\n        throw new SyncError(`Failed to push: ${result.error}`);\n      }\n    } catch (error) {\n      spinner.stop();\n      if (error instanceof SyncError) throw error;\n      throw new SyncError(`Failed to push: ${(error as Error).message}`);\n    }\n  }\n\n  private async doPushWithRetry(syncBranch: string, remote: string): Promise<PushResult> {\n    return pushWithRetry(syncBranch, remote, async () => {\n      // Merge callback - called when we need to merge remote changes\n      const conflicts: ConflictEntry[] = [];\n\n      // Get list of issues that need merging\n      const localIssues = await listIssues(this.dataSyncDir);\n\n      for (const localIssue of localIssues) {\n        try {\n          // Try to get the remote version (use relative path for git show)\n          const remoteContent = await git(\n            'show',\n            `${remote}/${syncBranch}:${DATA_SYNC_DIR}/issues/${localIssue.id}.md`,\n          );\n\n          if (remoteContent) {\n            // Parse remote issue and merge\n            const remoteIssue = await readIssue(this.dataSyncDir, localIssue.id);\n            const result = mergeIssues(null, localIssue, remoteIssue);\n\n            // Write merged result\n            await writeIssue(this.dataSyncDir, result.merged);\n            conflicts.push(...result.conflicts);\n          }\n        } catch {\n          // Issue doesn't exist remotely - no merge needed\n          this.output.debug(`Issue ${localIssue.id} not on remote, no merge needed`);\n        }\n      }\n\n      return conflicts;\n    });\n  }\n\n  /**\n   * Show git log --stat output in debug mode.\n   * Used to display commits that were synced.\n   */\n  private async showGitLogDebug(range: string, label: string): Promise<void> {\n    try {\n      const logOutput = await git('log', '--stat', '--oneline', range);\n      if (logOutput.trim()) {\n        this.output.debug(`${label}:`);\n        for (const line of logOutput.split('\\n')) {\n          this.output.debug(`  ${line}`);\n        }\n      }\n    } catch {\n      // Ignore errors - log is just for debugging\n    }\n  }\n\n  private async fullSync(syncBranch: string, remote: string, _force?: boolean): Promise<void> {\n    const spinner = this.output.spinner('Syncing with remote...');\n    const summary: SyncSummary = emptySummary();\n    const conflicts: ConflictEntry[] = [];\n    const worktreePath = join(process.cwd(), WORKTREE_DIR);\n\n    try {\n      // STEP 1: Commit local changes FIRST (before pulling)\n      // This ensures local work is preserved before we incorporate remote changes.\n      const committedTallies = await this.commitWorktreeChanges();\n      // Add committed changes to sent tallies\n      summary.sent.new += committedTallies.new;\n      summary.sent.updated += committedTallies.updated;\n      summary.sent.deleted += committedTallies.deleted;\n      if (hasTallies(committedTallies)) {\n        const count = committedTallies.new + committedTallies.updated + committedTallies.deleted;\n        this.output.debug(`Committed ${count} file(s) to sync branch`);\n      }\n\n      // STEP 2: Fetch remote\n      await git('fetch', remote, syncBranch);\n\n      // Get file-level changes from remote using git diff\n      let behindCommits = 0;\n      try {\n        const behindOutput = await git(\n          'rev-list',\n          '--count',\n          `${syncBranch}..${remote}/${syncBranch}`,\n        );\n        behindCommits = parseInt(behindOutput, 10) || 0;\n        this.output.debug(`Behind remote by ${behindCommits} commit(s)`);\n\n        // Get file-level tallies for received changes\n        if (behindCommits > 0) {\n          try {\n            const diffOutput = await git(\n              'diff',\n              '--name-status',\n              `${syncBranch}..${remote}/${syncBranch}`,\n            );\n            const receivedTallies = parseGitDiff(diffOutput);\n            summary.received.new += receivedTallies.new;\n            summary.received.updated += receivedTallies.updated;\n            summary.received.deleted += receivedTallies.deleted;\n          } catch {\n            // If we can't get detailed diff, just track commit count\n            this.output.debug('Could not get detailed diff for received changes');\n          }\n        }\n      } catch {\n        // Branch doesn't exist on remote\n        this.output.debug('Remote sync branch does not exist yet');\n      }\n\n      // STEP 3: If remote has changes, merge them in\n      if (behindCommits > 0) {\n        // Track HEAD before merge for debug log\n        let headBeforeMerge = '';\n        try {\n          headBeforeMerge = (await git('-C', worktreePath, 'rev-parse', 'HEAD')).trim();\n        } catch {\n          // Ignore - just won't show debug log\n        }\n\n        // Merge remote into local using worktree\n        // This is a proper git merge that preserves both local and remote changes\n        try {\n          await git(\n            '-C',\n            worktreePath,\n            'merge',\n            `${remote}/${syncBranch}`,\n            '-m',\n            'tbd sync: merge remote changes',\n          );\n          this.output.debug(`Merged ${behindCommits} commit(s) from remote`);\n\n          // Show received commits in debug mode\n          if (headBeforeMerge) {\n            await this.showGitLogDebug(`${headBeforeMerge}..HEAD`, 'Commits received');\n          }\n        } catch {\n          // Merge conflict - try to resolve at file level\n          this.output.info(`Merge conflict, attempting file-level resolution`);\n\n          // For each conflicted issue, do field-level merge\n          const localIssues = await listIssues(this.dataSyncDir);\n          for (const localIssue of localIssues) {\n            try {\n              const remoteContent = await git(\n                'show',\n                `${remote}/${syncBranch}:${DATA_SYNC_DIR}/issues/${localIssue.id}.md`,\n              );\n              if (remoteContent) {\n                const remoteIssue = await readIssue(this.dataSyncDir, localIssue.id);\n                const result = mergeIssues(null, localIssue, remoteIssue);\n                await writeIssue(this.dataSyncDir, result.merged);\n                conflicts.push(...result.conflicts);\n              }\n            } catch {\n              // Issue doesn't exist remotely - keep local version\n              this.output.debug(`Issue ${localIssue.id} not on remote, keeping local`);\n            }\n          }\n\n          // Stage resolved files and complete merge\n          await git('-C', worktreePath, 'add', '-A');\n          try {\n            await git('-C', worktreePath, 'commit', '-m', 'tbd sync: resolved merge conflicts');\n          } catch {\n            // May fail if no conflicts needed resolving\n            this.output.debug('No merge commit needed (conflicts already resolved)');\n          }\n        }\n      }\n    } catch (error) {\n      // Remote not available - that's ok for first sync\n      this.output.debug(`Fetch failed (may be first sync): ${(error as Error).message}`);\n    }\n\n    // Check how many commits we're ahead of remote (if any)\n    let aheadCommits = 0;\n    try {\n      const aheadOutput = await git(\n        'rev-list',\n        '--count',\n        `${remote}/${syncBranch}..${syncBranch}`,\n      );\n      aheadCommits = parseInt(aheadOutput, 10) || 0;\n      this.output.debug(`Ahead of remote by ${aheadCommits} commit(s)`);\n    } catch {\n      // Remote branch doesn't exist - count all local commits on sync branch\n      try {\n        const countOutput = await git('rev-list', '--count', syncBranch);\n        aheadCommits = parseInt(countOutput, 10) || 0;\n        this.output.debug(`Remote branch not found, ${aheadCommits} local commit(s) to push`);\n      } catch {\n        aheadCommits = 0;\n        this.output.debug('Could not count local commits');\n      }\n    }\n\n    // Push if we have commits ahead of remote\n    if (aheadCommits > 0) {\n      this.output.debug(`Pushing ${aheadCommits} commit(s) to remote`);\n      const result = await this.doPushWithRetry(syncBranch, remote);\n      if (result.conflicts) {\n        conflicts.push(...result.conflicts);\n      }\n      if (!result.success) {\n        this.output.debug(`Push failed: ${result.error}`);\n      } else {\n        // Show pushed commits in debug mode\n        await this.showGitLogDebug(`-${aheadCommits}`, 'Commits sent');\n      }\n    } else {\n      this.output.debug('No commits to push');\n    }\n\n    summary.conflicts = conflicts.length;\n    spinner.stop();\n\n    this.output.data({ summary, conflicts: conflicts.length }, () => {\n      const summaryText = formatSyncSummary(summary);\n      if (!summaryText) {\n        this.output.success('Already in sync');\n      } else {\n        this.output.success(`Synced: ${summaryText}`);\n      }\n    });\n  }\n}\n\nexport const syncCommand = new Command('sync')\n  .description('Synchronize with remote')\n  .option('--push', 'Push local changes only')\n  .option('--pull', 'Pull remote changes only')\n  .option('--status', 'Show sync status')\n  .option('--force', 'Force sync (overwrite conflicts)')\n  .action(async (options, command) => {\n    const handler = new SyncHandler(command);\n    await handler.run(options);\n  });\n","/**\n * `tbd search` - Search issues.\n *\n * See: tbd-design.md §4.8 Search Commands\n */\n\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\n\nimport { writeFile } from 'atomically';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotInitializedError, ValidationError } from '../lib/errors.js';\nimport { listIssues } from '../../file/storage.js';\nimport { IssueStatus } from '../../lib/schemas.js';\nimport type { Issue, IssueStatusType, LocalState } from '../../lib/types.js';\nimport { resolveDataSyncDir, STATE_FILE } from '../../lib/paths.js';\nimport { now } from '../../utils/time-utils.js';\nimport { formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { loadIdMapping } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\nimport { formatIssueCompact, type IssueForDisplay } from '../lib/issue-format.js';\n\n// Staleness threshold for worktree (5 minutes)\nconst STALE_THRESHOLD_MS = 5 * 60 * 1000;\n\ninterface SearchOptions {\n  status?: string;\n  limit?: string;\n  noRefresh?: boolean;\n  field?: string;\n  caseSensitive?: boolean;\n}\n\ninterface SearchResult {\n  issue: Issue;\n  matchField: string;\n  matchText: string;\n}\n\n/**\n * Read local state file.\n */\nasync function readState(): Promise<LocalState> {\n  try {\n    const content = await readFile(STATE_FILE, 'utf-8');\n    return parseYaml(content) as LocalState;\n  } catch {\n    return {};\n  }\n}\n\n/**\n * Update local state file.\n */\nasync function updateState(updates: Partial<LocalState>): Promise<void> {\n  const state = await readState();\n  const newState = { ...state, ...updates };\n  await writeFile(STATE_FILE, stringifyYaml(newState));\n}\n\n/**\n * Check if worktree is stale and needs refresh.\n */\nasync function isWorktreeStale(): Promise<boolean> {\n  const state = await readState();\n  if (!state.last_sync_at) {\n    return true; // Never synced\n  }\n\n  const lastSync = new Date(state.last_sync_at).getTime();\n  const now = Date.now();\n  return now - lastSync > STALE_THRESHOLD_MS;\n}\n\nclass SearchHandler extends BaseCommand {\n  async run(query: string, options: SearchOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    // Check worktree staleness and auto-refresh if needed\n    if (!options.noRefresh) {\n      const stale = await isWorktreeStale();\n      if (stale) {\n        this.output.info('Refreshing worktree...');\n        // Update state to mark as fresh (in a full implementation, would actually sync)\n        await updateState({ last_sync_at: now() });\n      }\n    }\n\n    // Load all issues\n    let issues: Issue[];\n    let dataSyncDir: string;\n    try {\n      dataSyncDir = await resolveDataSyncDir(tbdRoot);\n      issues = await listIssues(dataSyncDir);\n    } catch {\n      throw new NotInitializedError('No issue store found. Run `tbd init` first.');\n    }\n\n    // Parse status filter\n    let statusFilter: IssueStatusType | null = null;\n    if (options.status) {\n      const result = IssueStatus.safeParse(options.status);\n      if (!result.success) {\n        throw new ValidationError(`Invalid status: ${options.status}`);\n      }\n      statusFilter = result.data;\n    }\n\n    // Search (case-insensitive by default)\n    const caseSensitive = options.caseSensitive ?? false;\n    const queryForMatch = caseSensitive ? query : query.toLowerCase();\n    let results: SearchResult[] = [];\n\n    for (const issue of issues) {\n      // Apply status filter\n      if (statusFilter && issue.status !== statusFilter) continue;\n\n      // Determine which fields to search\n      const searchFields = options.field\n        ? [options.field]\n        : ['title', 'description', 'notes', 'labels'];\n\n      for (const field of searchFields) {\n        const match = this.searchField(issue, field, queryForMatch, caseSensitive);\n        if (match) {\n          results.push(match);\n          break; // Only one match per issue\n        }\n      }\n    }\n\n    // Apply limit\n    if (options.limit) {\n      const limit = parseInt(options.limit, 10);\n      if (!isNaN(limit) && limit > 0) {\n        results = results.slice(0, limit);\n      }\n    }\n\n    // Load ID mapping and config for display\n    const mapping = await loadIdMapping(dataSyncDir);\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const showDebug = this.ctx.debug;\n\n    // Format output\n    const output = results.map((r) => ({\n      id: showDebug\n        ? formatDebugId(r.issue.id, mapping, prefix)\n        : formatDisplayId(r.issue.id, mapping, prefix),\n      priority: r.issue.priority,\n      status: r.issue.status,\n      kind: r.issue.kind,\n      title: r.issue.title,\n      matchField: r.matchField,\n      match: r.matchText,\n    }));\n\n    this.output.data(output, () => {\n      if (output.length === 0) {\n        this.output.info(`No issues matching \"${query}\"`);\n        return;\n      }\n\n      const colors = this.output.getColors();\n      console.log(`Found ${output.length} result${output.length === 1 ? '' : 's'}:\\n`);\n      for (const result of output) {\n        console.log(formatIssueCompact(result as IssueForDisplay, colors));\n        console.log(`  ${colors.dim(`[${result.matchField}]`)} ${result.match}`);\n        console.log('');\n      }\n    });\n  }\n\n  private searchField(\n    issue: Issue,\n    field: string,\n    query: string,\n    caseSensitive: boolean,\n  ): SearchResult | null {\n    switch (field) {\n      case 'title': {\n        const text = caseSensitive ? issue.title : issue.title.toLowerCase();\n        if (text.includes(query)) {\n          return { issue, matchField: 'title', matchText: issue.title };\n        }\n        break;\n      }\n      case 'description': {\n        if (issue.description) {\n          const text = caseSensitive ? issue.description : issue.description.toLowerCase();\n          if (text.includes(query)) {\n            const snippet = this.extractSnippet(issue.description, query, caseSensitive);\n            return { issue, matchField: 'description', matchText: snippet };\n          }\n        }\n        break;\n      }\n      case 'notes': {\n        if (issue.notes) {\n          const text = caseSensitive ? issue.notes : issue.notes.toLowerCase();\n          if (text.includes(query)) {\n            const snippet = this.extractSnippet(issue.notes, query, caseSensitive);\n            return { issue, matchField: 'notes', matchText: snippet };\n          }\n        }\n        break;\n      }\n      case 'labels': {\n        for (const label of issue.labels) {\n          const text = caseSensitive ? label : label.toLowerCase();\n          if (text.includes(query)) {\n            return { issue, matchField: 'labels', matchText: `label: ${label}` };\n          }\n        }\n        break;\n      }\n    }\n    return null;\n  }\n\n  private extractSnippet(text: string, query: string, caseSensitive: boolean): string {\n    const searchText = caseSensitive ? text : text.toLowerCase();\n    const index = searchText.indexOf(query);\n    if (index === -1) return text.slice(0, 60);\n\n    // Extract snippet around match\n    const start = Math.max(0, index - 20);\n    const end = Math.min(text.length, index + query.length + 40);\n    let snippet = text.slice(start, end);\n\n    if (start > 0) snippet = '...' + snippet;\n    if (end < text.length) snippet = snippet + '...';\n\n    return snippet.replace(/\\n/g, ' ');\n  }\n}\n\nexport const searchCommand = new Command('search')\n  .description('Search issues by text')\n  .argument('<query>', 'Search query')\n  .option('--status <status>', 'Filter by status')\n  .option('--field <field>', 'Search specific field (title, description, notes, labels)')\n  .option('--limit <n>', 'Limit results')\n  .option('--no-refresh', 'Skip worktree refresh')\n  .option('--case-sensitive', 'Case-sensitive search')\n  .action(async (query, options, command) => {\n    const handler = new SearchHandler(command);\n    await handler.run(query, options);\n  });\n","/**\n * `tbd status` - Show repository status and orientation.\n *\n * This is the \"orientation\" command—like `git status`, it works regardless of\n * initialization state and helps users understand where they are.\n *\n * Unlike Beads where `bd status` is just an alias for `bd stats`, `tbd status`\n * is a distinct command that provides system orientation, not issue statistics.\n *\n * See: tbd-design.md §4.9 Status\n */\n\nimport { Command } from 'commander';\nimport { access, readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\nimport { VERSION } from '../lib/version.js';\nimport { BaseCommand } from '../lib/base-command.js';\nimport { formatHeading } from '../lib/output.js';\nimport { readConfig, findTbdRoot } from '../../file/config.js';\nimport { WORKTREE_DIR } from '../../lib/paths.js';\nimport {\n  git,\n  getCurrentBranch,\n  checkWorktreeHealth,\n  checkGitVersion,\n  MIN_GIT_VERSION,\n} from '../../file/git.js';\n\ninterface StatusData {\n  initialized: boolean;\n  tbd_version: string;\n  working_directory: string;\n\n  // Git info (always available)\n  git_repository: boolean;\n  git_branch: string | null;\n  git_version: string | null;\n  git_version_supported: boolean;\n\n  // Beads detection (pre-init only)\n  beads_detected: boolean;\n  beads_issue_count: number | null;\n\n  // Post-init only\n  sync_branch: string | null;\n  remote: string | null;\n  display_prefix: string | null;\n  worktree_path: string | null;\n  worktree_healthy: boolean | null;\n\n  // Integrations\n  integrations: {\n    claude_code: boolean;\n    claude_code_path: string;\n    codex: boolean;\n    codex_path: string;\n  };\n}\n\nclass StatusHandler extends BaseCommand {\n  async run(): Promise<void> {\n    const cwd = process.cwd();\n\n    // Find tbd root (may be in parent directory)\n    const tbdRoot = await findTbdRoot(cwd);\n\n    const statusData: StatusData = {\n      initialized: tbdRoot !== null,\n      tbd_version: VERSION,\n      working_directory: cwd,\n      git_repository: false,\n      git_branch: null,\n      git_version: null,\n      git_version_supported: false,\n      beads_detected: false,\n      beads_issue_count: null,\n      sync_branch: null,\n      remote: null,\n      display_prefix: null,\n      worktree_path: null,\n      worktree_healthy: null,\n      integrations: {\n        claude_code: false,\n        claude_code_path: '~/.claude/settings.json',\n        codex: false,\n        codex_path: './AGENTS.md',\n      },\n    };\n\n    // Check git repository\n    const gitInfo = await this.checkGitRepo();\n    statusData.git_repository = gitInfo.isRepo;\n    statusData.git_branch = gitInfo.branch;\n\n    // Check git version (only if git is available)\n    if (gitInfo.isRepo) {\n      try {\n        const { version, supported } = await checkGitVersion();\n        statusData.git_version = `${version.major}.${version.minor}.${version.patch}`;\n        statusData.git_version_supported = supported;\n      } catch {\n        // Git version check failed - leave as null/false\n      }\n    }\n\n    // Check for beads\n    const beadsInfo = await this.checkBeads(cwd);\n    statusData.beads_detected = beadsInfo.detected;\n    statusData.beads_issue_count = beadsInfo.issueCount;\n\n    // Check integrations (always show)\n    statusData.integrations = await this.checkIntegrations(cwd);\n\n    if (statusData.initialized && tbdRoot) {\n      // Load config and issue info\n      await this.loadPostInitInfo(tbdRoot, statusData);\n    }\n\n    this.output.data(statusData, () => {\n      this.renderText(statusData);\n    });\n  }\n\n  private async checkGitRepo(): Promise<{ isRepo: boolean; branch: string | null }> {\n    try {\n      const branch = await getCurrentBranch();\n      return { isRepo: true, branch };\n    } catch {\n      // getCurrentBranch may fail in repos with no commits\n      // Fall back to checking if we're in a git repo using git rev-parse --git-dir\n      try {\n        await git('rev-parse', '--git-dir');\n        // We're in a git repo but can't get branch (maybe no commits)\n        return { isRepo: true, branch: null };\n      } catch {\n        return { isRepo: false, branch: null };\n      }\n    }\n  }\n\n  private async checkBeads(cwd: string): Promise<{ detected: boolean; issueCount: number | null }> {\n    const beadsDir = join(cwd, '.beads');\n    try {\n      await access(beadsDir);\n      // Count issues in beads\n      const issuesFile = join(beadsDir, 'issues.jsonl');\n      try {\n        const content = await readFile(issuesFile, 'utf-8');\n        const lines = content\n          .trim()\n          .split('\\n')\n          .filter((l) => l.trim());\n        return { detected: true, issueCount: lines.length };\n      } catch {\n        return { detected: true, issueCount: null };\n      }\n    } catch {\n      return { detected: false, issueCount: null };\n    }\n  }\n\n  private async checkIntegrations(cwd: string): Promise<StatusData['integrations']> {\n    const claudeSettingsPath = join(homedir(), '.claude', 'settings.json');\n    const agentsPath = join(cwd, 'AGENTS.md');\n\n    const result: StatusData['integrations'] = {\n      claude_code: false,\n      claude_code_path: claudeSettingsPath.replace(homedir(), '~'),\n      codex: false,\n      codex_path: './AGENTS.md',\n    };\n\n    // Check Claude Code hooks\n    try {\n      await access(claudeSettingsPath);\n      const content = await readFile(claudeSettingsPath, 'utf-8');\n      const settings = JSON.parse(content) as Record<string, unknown>;\n      const hooks = settings.hooks as Record<string, unknown> | undefined;\n      if (hooks) {\n        const sessionStart = hooks.SessionStart as { hooks?: { command?: string }[] }[];\n        result.claude_code =\n          sessionStart?.some((h) => h.hooks?.some((hook) => hook.command?.includes('tbd'))) ??\n          false;\n      }\n    } catch {\n      // Not installed\n    }\n\n    // Check Codex AGENTS.md (also used by Cursor since v1.6)\n    try {\n      await access(agentsPath);\n      const content = await readFile(agentsPath, 'utf-8');\n      result.codex = content.includes('BEGIN TBD INTEGRATION');\n    } catch {\n      // Not installed\n    }\n\n    return result;\n  }\n\n  private async loadPostInitInfo(cwd: string, data: StatusData): Promise<void> {\n    // Load config\n    try {\n      const config = await readConfig(cwd);\n      data.sync_branch = config.sync.branch;\n      data.remote = config.sync.remote;\n      data.display_prefix = config.display.id_prefix;\n    } catch {\n      // Config read failed\n    }\n\n    // Check worktree health\n    const worktreePath = join(cwd, WORKTREE_DIR);\n    const worktreeHealth = await checkWorktreeHealth(cwd);\n    data.worktree_path = worktreePath;\n    data.worktree_healthy = worktreeHealth.valid;\n  }\n\n  private renderText(data: StatusData): void {\n    const colors = this.output.getColors();\n\n    if (!data.initialized) {\n      // Pre-init output\n      console.log(`${colors.warn('Not a tbd repository.')}`);\n      console.log('');\n      console.log('Detected:');\n\n      // Git status\n      if (data.git_repository) {\n        const branchInfo = data.git_branch ? ` (${data.git_branch} branch)` : '';\n        console.log(`  ${colors.success('✓')} Git repository${branchInfo}`);\n        // Show git version\n        if (data.git_version) {\n          const versionStatus = data.git_version_supported ? colors.success('✓') : colors.warn('⚠');\n          const versionNote = data.git_version_supported\n            ? ''\n            : ` ${colors.dim(`(requires ${MIN_GIT_VERSION}+)`)}`;\n          console.log(`  ${versionStatus} Git ${data.git_version}${versionNote}`);\n        }\n      } else {\n        console.log(`  ${colors.error('✗')} Git repository not found`);\n      }\n\n      // Beads status\n      if (data.beads_detected) {\n        const countInfo =\n          data.beads_issue_count !== null ? ` (.beads/ with ${data.beads_issue_count} issues)` : '';\n        console.log(`  ${colors.success('✓')} Beads repository${countInfo}`);\n      } else {\n        console.log(`  ${colors.dim('✗')} Beads not detected`);\n      }\n\n      // tbd status\n      console.log(`  ${colors.error('✗')} tbd not initialized`);\n\n      console.log('');\n      console.log('To get started:');\n      if (data.beads_detected) {\n        console.log(\n          `  ${colors.bold('tbd setup --auto')}          # Migrate from Beads (recommended)`,\n        );\n      } else {\n        console.log(\n          `  ${colors.bold('tbd setup --auto --prefix=<name>')}   # Full setup with prefix`,\n        );\n      }\n      console.log(`  ${colors.bold('tbd init --prefix=X')}       # Surgical init only`);\n      return;\n    }\n\n    // Post-init output\n    console.log(`${colors.bold('tbd')} v${data.tbd_version}`);\n    console.log('');\n    console.log(`Repository: ${data.working_directory}`);\n    console.log(`  ${colors.success('✓')} Initialized (.tbd/)`);\n\n    if (data.git_repository) {\n      const branchInfo = data.git_branch ? ` (${data.git_branch})` : '';\n      console.log(`  ${colors.success('✓')} Git repository${branchInfo}`);\n      // Show git version\n      if (data.git_version) {\n        const versionStatus = data.git_version_supported ? colors.success('✓') : colors.warn('⚠');\n        const versionNote = data.git_version_supported\n          ? ''\n          : ` ${colors.dim(`(requires ${MIN_GIT_VERSION}+)`)}`;\n        console.log(`  ${versionStatus} Git ${data.git_version}${versionNote}`);\n      }\n    }\n\n    // Beads coexistence warning\n    if (data.beads_detected) {\n      console.log('');\n      console.log(`${colors.warn('⚠')}  Beads directory detected alongside tbd`);\n      console.log(`   This may cause confusion for AI agents.`);\n      console.log(`   Run ${colors.bold('tbd setup beads --disable')} for migration options`);\n    }\n\n    // Config info\n    if (data.sync_branch || data.remote || data.display_prefix) {\n      console.log('');\n      if (data.sync_branch) {\n        console.log(`${colors.dim('Sync branch:')} ${data.sync_branch}`);\n      }\n      if (data.remote) {\n        console.log(`${colors.dim('Remote:')} ${data.remote}`);\n      }\n      if (data.display_prefix) {\n        console.log(`${colors.dim('ID prefix:')} ${data.display_prefix}-`);\n      }\n    }\n\n    // Integrations\n    console.log('');\n    console.log(colors.bold(formatHeading('Integrations')));\n\n    // Track if any integrations are missing\n    let hasMissingIntegrations = false;\n\n    if (data.integrations.claude_code) {\n      console.log(\n        `  ${colors.success('✓')} Claude Code hooks ${colors.dim(`(${data.integrations.claude_code_path})`)}`,\n      );\n    } else {\n      console.log(\n        `  ${colors.dim('✗')} Claude Code hooks ${colors.dim(`(${data.integrations.claude_code_path})`)}`,\n      );\n      hasMissingIntegrations = true;\n    }\n    if (data.integrations.codex) {\n      console.log(\n        `  ${colors.success('✓')} Codex AGENTS.md ${colors.dim(`(${data.integrations.codex_path})`)}`,\n      );\n    } else {\n      console.log(\n        `  ${colors.dim('✗')} Codex AGENTS.md ${colors.dim(`(${data.integrations.codex_path})`)}`,\n      );\n      hasMissingIntegrations = true;\n    }\n\n    if (hasMissingIntegrations) {\n      console.log('');\n      console.log(`Run ${colors.bold('tbd setup auto')} to configure detected agents`);\n    }\n\n    // Worktree health\n    if (data.worktree_healthy !== null) {\n      console.log('');\n      if (data.worktree_healthy) {\n        console.log(`${colors.dim('Worktree:')} ${data.worktree_path} (healthy)`);\n      } else {\n        console.log(\n          `${colors.warn('Worktree:')} ${data.worktree_path} (${colors.error('unhealthy')})`,\n        );\n        console.log(`  Run: tbd doctor --fix`);\n      }\n    }\n\n    console.log('');\n    console.log(\n      `Use ${colors.bold(\"'tbd stats'\")} for issue statistics, ${colors.bold(\"'tbd doctor'\")} for health checks.`,\n    );\n  }\n}\n\nexport const statusCommand = new Command('status')\n  .description('Show repository status and orientation')\n  .action(async (_options, command) => {\n    const handler = new StatusHandler(command);\n    await handler.run();\n  });\n","/**\n * `tbd stats` - Show repository statistics.\n *\n * See: tbd-design.md §4.9 Stats\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotInitializedError } from '../lib/errors.js';\nimport { listIssues } from '../../file/storage.js';\nimport type { Issue, IssueStatusType, IssueKindType } from '../../lib/types.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { formatPriority } from '../../lib/priority.js';\n\nclass StatsHandler extends BaseCommand {\n  async run(): Promise<void> {\n    await requireInit();\n\n    // Load all issues\n    let issues: Issue[];\n    try {\n      const dataSyncDir = await resolveDataSyncDir();\n      issues = await listIssues(dataSyncDir);\n    } catch {\n      throw new NotInitializedError('No issue store found. Run `tbd init` first.');\n    }\n\n    // Count by status\n    const byStatus: Record<IssueStatusType, number> = {\n      open: 0,\n      in_progress: 0,\n      blocked: 0,\n      deferred: 0,\n      closed: 0,\n    };\n\n    // Count by kind\n    const byKind: Record<IssueKindType, number> = {\n      bug: 0,\n      feature: 0,\n      task: 0,\n      epic: 0,\n      chore: 0,\n    };\n\n    // Count by priority\n    const byPriority: Record<number, number> = {\n      0: 0,\n      1: 0,\n      2: 0,\n      3: 0,\n      4: 0,\n    };\n\n    // Build set of blocked issue IDs (issues that have open blockers)\n    const blockedIds = new Set<string>();\n    for (const issue of issues) {\n      for (const dep of issue.dependencies) {\n        if (dep.type === 'blocks') {\n          // The target issue is blocked by this issue\n          const blockedIssue = issues.find((i) => i.id === dep.target);\n          if (blockedIssue && blockedIssue.status !== 'closed') {\n            blockedIds.add(dep.target);\n          }\n        }\n      }\n    }\n\n    // Count ready issues (open and not blocked)\n    let readyCount = 0;\n\n    // Accumulate counts\n    for (const issue of issues) {\n      byStatus[issue.status]++;\n      byKind[issue.kind]++;\n      if (issue.priority >= 0 && issue.priority <= 4) {\n        byPriority[issue.priority]!++;\n      }\n      // Count ready: open and not blocked\n      if (issue.status === 'open' && !blockedIds.has(issue.id)) {\n        readyCount++;\n      }\n    }\n\n    const stats = {\n      total: issues.length,\n      ready: readyCount,\n      blocked: blockedIds.size,\n      byStatus,\n      byKind,\n      byPriority,\n    };\n\n    this.output.data(stats, () => {\n      const colors = this.output.getColors();\n\n      // Summary section\n      console.log(colors.bold('Summary:'));\n      console.log(`  Ready:       ${stats.ready}`);\n      console.log(`  In progress: ${stats.byStatus.in_progress}`);\n      console.log(`  Blocked:     ${stats.blocked}`);\n      console.log(`  Open:        ${stats.byStatus.open}`);\n      console.log(`  Total:       ${stats.total}`);\n\n      if (stats.total === 0) {\n        console.log('');\n        console.log(\n          `Use ${colors.bold(\"'tbd status'\")} for setup info, ${colors.bold(\"'tbd doctor'\")} for health checks.`,\n        );\n        return;\n      }\n\n      console.log('');\n      console.log(colors.bold('By status:'));\n      for (const [status, count] of Object.entries(stats.byStatus)) {\n        if (count > 0) {\n          console.log(`  ${status.padEnd(14)} ${count}`);\n        }\n      }\n\n      console.log('');\n      console.log(colors.bold('By kind:'));\n      for (const [kind, count] of Object.entries(stats.byKind)) {\n        if (count > 0) {\n          console.log(`  ${kind.padEnd(14)} ${count}`);\n        }\n      }\n\n      console.log('');\n      console.log(colors.bold('By priority:'));\n      const priorityLabels = ['Critical', 'High', 'Medium', 'Low', 'Lowest'];\n      for (let i = 0; i <= 4; i++) {\n        const count = stats.byPriority[i];\n        if (count !== undefined && count > 0) {\n          console.log(`  ${formatPriority(i)} (${priorityLabels[i]!.padEnd(8)}) ${count}`);\n        }\n      }\n\n      console.log('');\n      console.log(\n        `Use ${colors.bold(\"'tbd status'\")} for setup info, ${colors.bold(\"'tbd doctor'\")} for health checks.`,\n      );\n    });\n  }\n}\n\nexport const statsCommand = new Command('stats')\n  .description('Show repository statistics')\n  .action(async (_options, command) => {\n    const handler = new StatsHandler(command);\n    await handler.run();\n  });\n","/**\n * Shared diagnostic output utilities for consistent diagnostic messages\n * across doctor, setup --check, and status commands.\n *\n * See: plan-2026-01-17-cli-output-design-system.md\n */\n\nimport { ICONS } from './output.js';\n\n/**\n * Result of a diagnostic check. Used by doctor, setup --check, and status commands\n * to report configuration and health status.\n *\n * @property name - Display name of the check (e.g., \"Config file\", \"Git version\")\n * @property status - Check result: ok (pass), warn (non-blocking issue), error (failure)\n * @property message - Optional message with additional context (e.g., version number, count)\n * @property path - Optional file/directory path being checked\n * @property details - Optional list of specific items when issues found (e.g., orphaned deps)\n * @property fixable - Whether the issue can be auto-fixed (shown as [fixable] suffix)\n * @property suggestion - Optional actionable fix suggestion (e.g., \"Run: tbd setup claude\")\n */\nexport interface DiagnosticResult {\n  name: string;\n  status: 'ok' | 'warn' | 'error';\n  message?: string;\n  path?: string;\n  details?: string[];\n  fixable?: boolean;\n  suggestion?: string;\n}\n\n/**\n * Color function type for consistent coloring across the module.\n */\ntype ColorFn = (text: string) => string;\n\n/**\n * Colors interface matching createColors() return type.\n */\ninterface Colors {\n  success: ColorFn;\n  error: ColorFn;\n  warn: ColorFn;\n  dim: ColorFn;\n}\n\n/**\n * Render a single diagnostic result to console.\n *\n * Format examples:\n * - ✓ Config file (.tbd/config.yml)\n * - ⚠ Dependencies - 2 orphaned reference(s) [fixable]\n *     tbd-abc1 -> tbd-xyz9 (missing)\n *     tbd-def2 -> tbd-uvw8 (missing)\n * - ✗ Issue validity - 2 invalid issue(s) (.tbd/issues)\n *     tbd-aaa1: missing required field 'title'\n *     Run: tbd doctor --fix\n *\n * @param result - The diagnostic result to render\n * @param colors - Color functions from createColors()\n */\nexport function renderDiagnostic(result: DiagnosticResult, colors: Colors): void {\n  // Build the main line\n  let line = '';\n\n  // Icon based on status\n  const icon =\n    result.status === 'ok'\n      ? colors.success(ICONS.SUCCESS)\n      : result.status === 'warn'\n        ? colors.warn(ICONS.WARN)\n        : colors.error(ICONS.ERROR);\n\n  line += `${icon} ${result.name}`;\n\n  // Message after dash\n  if (result.message) {\n    line += ` - ${result.message}`;\n  }\n\n  // Path in parentheses\n  if (result.path) {\n    line += ` ${colors.dim(`(${result.path})`)}`;\n  }\n\n  // Fixable suffix (only for non-ok)\n  if (result.fixable && result.status !== 'ok') {\n    line += ` ${colors.dim('[fixable]')}`;\n  }\n\n  console.log(line);\n\n  // Details (only for non-ok status)\n  if (result.details && result.details.length > 0 && result.status !== 'ok') {\n    for (const detail of result.details) {\n      console.log(`    ${colors.dim(detail)}`);\n    }\n  }\n\n  // Suggestion (only for non-ok status)\n  if (result.suggestion && result.status !== 'ok') {\n    console.log(`    ${colors.dim(result.suggestion)}`);\n  }\n}\n\n/**\n * Render multiple diagnostic results.\n *\n * @param results - Array of diagnostic results to render\n * @param colors - Color functions from createColors()\n */\nexport function renderDiagnostics(results: DiagnosticResult[], colors: Colors): void {\n  for (const result of results) {\n    renderDiagnostic(result, colors);\n  }\n}\n","/**\n * `tbd doctor` - Diagnose and repair repository.\n *\n * A comprehensive health check that includes status, stats, and health checks.\n *\n * See: tbd-design.md §4.9 Doctor\n */\n\nimport { Command } from 'commander';\nimport { access, readdir, readFile, unlink } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit } from '../lib/errors.js';\nimport { listIssues } from '../../file/storage.js';\nimport { readConfig } from '../../file/config.js';\nimport type { Config, Issue, IssueStatusType } from '../../lib/types.js';\nimport { resolveDataSyncDir, TBD_DIR, WORKTREE_DIR } from '../../lib/paths.js';\nimport { validateIssueId } from '../../lib/ids.js';\nimport {\n  checkGitVersion,\n  MIN_GIT_VERSION,\n  getCurrentBranch,\n  checkWorktreeHealth,\n} from '../../file/git.js';\nimport { type DiagnosticResult, renderDiagnostics } from '../lib/diagnostics.js';\nimport { VERSION } from '../lib/version.js';\nimport { formatHeading } from '../lib/output.js';\n\nconst CONFIG_DIR = TBD_DIR;\n\ninterface DoctorOptions {\n  fix?: boolean;\n}\n\nclass DoctorHandler extends BaseCommand {\n  private dataSyncDir = '';\n  private cwd = '';\n  private config: Config | null = null;\n  private issues: Issue[] = [];\n\n  async run(options: DoctorOptions): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    this.cwd = tbdRoot;\n    this.dataSyncDir = await resolveDataSyncDir(tbdRoot);\n\n    // Load config\n    try {\n      this.config = await readConfig(this.cwd);\n    } catch {\n      // Config may be invalid - will be caught by health checks\n    }\n\n    // Load issues\n    try {\n      this.issues = await listIssues(this.dataSyncDir);\n    } catch {\n      // May fail if no issues yet\n    }\n\n    // Gather status info\n    const statusInfo = await this.gatherStatusInfo();\n\n    // Gather stats info\n    const statsInfo = this.gatherStatsInfo();\n\n    // Run health checks (core system checks)\n    const healthChecks: DiagnosticResult[] = [];\n\n    // Check 1: Git version\n    healthChecks.push(await this.checkGitVersion());\n\n    // Check 2: Config directory and file\n    healthChecks.push(await this.checkConfig());\n\n    // Check 3: Issues directory\n    healthChecks.push(await this.checkIssuesDirectory());\n\n    // Check 4: Orphaned dependencies\n    healthChecks.push(this.checkOrphanedDependencies(this.issues));\n\n    // Check 5: Duplicate IDs\n    healthChecks.push(this.checkDuplicateIds(this.issues));\n\n    // Check 6: Orphaned temp files\n    healthChecks.push(await this.checkTempFiles(options.fix));\n\n    // Check 7: Issue validity\n    healthChecks.push(this.checkIssueValidity(this.issues));\n\n    // Check 8: Worktree health\n    healthChecks.push(await this.checkWorktree());\n\n    // Run integration checks (optional IDE/agent integrations)\n    const integrationChecks: DiagnosticResult[] = [];\n\n    // Integration 1: Claude Code skill file\n    integrationChecks.push(await this.checkClaudeSkill());\n\n    // Integration 2: Codex AGENTS.md (also used by Cursor since v1.6)\n    integrationChecks.push(await this.checkCodexAgents());\n\n    // Combine for overall status\n    const allChecks = [...healthChecks, ...integrationChecks];\n    const allOk = allChecks.every((c) => c.status === 'ok');\n    const hasFixable = allChecks.some((c) => c.fixable && c.status !== 'ok');\n\n    this.output.data(\n      { statusInfo, statsInfo, healthChecks, integrationChecks, healthy: allOk },\n      () => {\n        const colors = this.output.getColors();\n\n        // REPOSITORY section (matches status command)\n        console.log(colors.bold(formatHeading('Repository')));\n        console.log(`tbd v${VERSION}`);\n        console.log(`Repository: ${this.cwd}`);\n        console.log(`  ${colors.success('✓')} Initialized (.tbd/)`);\n        if (statusInfo.gitBranch) {\n          console.log(`  ${colors.success('✓')} Git repository (${statusInfo.gitBranch})`);\n        }\n        if (this.config) {\n          console.log('');\n          console.log(`${colors.dim('Sync branch:')} ${this.config.sync.branch}`);\n          console.log(`${colors.dim('Remote:')} ${this.config.sync.remote}`);\n          if (this.config.display.id_prefix) {\n            console.log(`${colors.dim('ID prefix:')} ${this.config.display.id_prefix}-`);\n          }\n        }\n\n        // STATISTICS section\n        console.log('');\n        console.log(colors.bold(formatHeading('Statistics')));\n        console.log(`  Ready:       ${statsInfo.ready}`);\n        console.log(`  In progress: ${statsInfo.inProgress}`);\n        console.log(`  Blocked:     ${statsInfo.blocked}`);\n        console.log(`  Open:        ${statsInfo.open}`);\n        console.log(`  Total:       ${statsInfo.total}`);\n\n        // INTEGRATIONS section (matches status command)\n        console.log('');\n        console.log(colors.bold(formatHeading('Integrations')));\n        renderDiagnostics(integrationChecks, colors);\n\n        // HEALTH CHECKS section\n        console.log('');\n        console.log(colors.bold(formatHeading('Health Checks')));\n        renderDiagnostics(healthChecks, colors);\n\n        // Final summary\n        console.log('');\n        if (allOk) {\n          this.output.success('Repository is healthy');\n        } else if (hasFixable && !options.fix) {\n          this.output.warn('Issues found. Run with --fix to repair.');\n        } else {\n          this.output.warn('Issues found that may require manual intervention.');\n        }\n      },\n    );\n  }\n\n  private async gatherStatusInfo(): Promise<{\n    gitBranch: string | null;\n    worktreeHealthy: boolean;\n  }> {\n    let gitBranch: string | null = null;\n    try {\n      gitBranch = await getCurrentBranch();\n    } catch {\n      // Not in a git repo or no commits\n    }\n\n    const worktreeHealth = await checkWorktreeHealth(this.cwd);\n\n    return {\n      gitBranch,\n      worktreeHealthy: worktreeHealth.valid,\n    };\n  }\n\n  private gatherStatsInfo(): {\n    total: number;\n    ready: number;\n    inProgress: number;\n    blocked: number;\n    open: number;\n  } {\n    // Count by status\n    const byStatus: Record<IssueStatusType, number> = {\n      open: 0,\n      in_progress: 0,\n      blocked: 0,\n      deferred: 0,\n      closed: 0,\n    };\n\n    // Build set of blocked issue IDs\n    const blockedIds = new Set<string>();\n    for (const issue of this.issues) {\n      for (const dep of issue.dependencies) {\n        if (dep.type === 'blocks') {\n          const blockedIssue = this.issues.find((i) => i.id === dep.target);\n          if (blockedIssue && blockedIssue.status !== 'closed') {\n            blockedIds.add(dep.target);\n          }\n        }\n      }\n    }\n\n    // Count ready issues (open and not blocked)\n    let readyCount = 0;\n\n    for (const issue of this.issues) {\n      byStatus[issue.status]++;\n      if (issue.status === 'open' && !blockedIds.has(issue.id)) {\n        readyCount++;\n      }\n    }\n\n    return {\n      total: this.issues.length,\n      ready: readyCount,\n      inProgress: byStatus.in_progress,\n      blocked: blockedIds.size,\n      open: byStatus.open,\n    };\n  }\n\n  private async checkGitVersion(): Promise<DiagnosticResult> {\n    try {\n      const { version, supported } = await checkGitVersion();\n      const versionStr = `${version.major}.${version.minor}.${version.patch}`;\n\n      if (supported) {\n        return {\n          name: 'Git version',\n          status: 'ok',\n          message: versionStr,\n        };\n      }\n\n      return {\n        name: 'Git version',\n        status: 'error',\n        message: `${versionStr} (requires ${MIN_GIT_VERSION}+)`,\n        suggestion: 'Upgrade Git: https://git-scm.com/downloads',\n      };\n    } catch (error) {\n      const msg = error instanceof Error ? error.message : String(error);\n      if (msg.includes('git') || msg.includes('not found') || msg.includes('ENOENT')) {\n        return {\n          name: 'Git version',\n          status: 'error',\n          message: 'Git not found',\n          suggestion: 'Install Git: https://git-scm.com/downloads',\n        };\n      }\n      return {\n        name: 'Git version',\n        status: 'warn',\n        message: `Unable to check: ${msg}`,\n      };\n    }\n  }\n\n  private async checkConfig(): Promise<DiagnosticResult> {\n    const configPath = join(CONFIG_DIR, 'config.yml');\n    try {\n      await access(join(this.cwd, configPath));\n      await readConfig(this.cwd);\n      return { name: 'Config file', status: 'ok', path: configPath };\n    } catch (error) {\n      const msg = (error as Error).message;\n      if (msg.includes('ENOENT')) {\n        return {\n          name: 'Config file',\n          status: 'error',\n          message: 'not found',\n          path: configPath,\n          suggestion: 'Run: tbd init',\n        };\n      }\n      return {\n        name: 'Config file',\n        status: 'error',\n        message: 'Invalid config file',\n        path: configPath,\n      };\n    }\n  }\n\n  private async checkIssuesDirectory(): Promise<DiagnosticResult> {\n    const issuesPath = join(CONFIG_DIR, 'issues');\n    try {\n      await access(join(this.dataSyncDir, 'issues'));\n      return { name: 'Issues directory', status: 'ok', path: issuesPath };\n    } catch {\n      // No issues directory is normal for a fresh/empty repo\n      return {\n        name: 'Issues directory',\n        status: 'ok',\n        message: 'empty (no issues yet)',\n        path: issuesPath,\n      };\n    }\n  }\n\n  private checkOrphanedDependencies(issues: Issue[]): DiagnosticResult {\n    const issueIds = new Set(issues.map((i) => i.id));\n    const orphans: string[] = [];\n\n    for (const issue of issues) {\n      for (const dep of issue.dependencies) {\n        if (!issueIds.has(dep.target)) {\n          orphans.push(`${issue.id} -> ${dep.target} (missing)`);\n        }\n      }\n    }\n\n    if (orphans.length === 0) {\n      return { name: 'Dependencies', status: 'ok' };\n    }\n\n    return {\n      name: 'Dependencies',\n      status: 'warn',\n      message: `${orphans.length} orphaned reference(s)`,\n      details: orphans,\n      fixable: true,\n      suggestion: 'Run: tbd doctor --fix',\n    };\n  }\n\n  private checkDuplicateIds(issues: Issue[]): DiagnosticResult {\n    const seen = new Set<string>();\n    const duplicates: string[] = [];\n\n    for (const issue of issues) {\n      if (seen.has(issue.id)) {\n        duplicates.push(issue.id);\n      }\n      seen.add(issue.id);\n    }\n\n    if (duplicates.length === 0) {\n      return { name: 'Unique IDs', status: 'ok' };\n    }\n\n    return {\n      name: 'Unique IDs',\n      status: 'error',\n      message: `${duplicates.length} duplicate ID(s)`,\n      details: duplicates.map((id) => `${id} (duplicate)`),\n      suggestion: 'Manually remove duplicate issue files',\n    };\n  }\n\n  private async checkTempFiles(fix?: boolean): Promise<DiagnosticResult> {\n    const issuesPath = join(CONFIG_DIR, 'issues');\n    const issuesDir = join(this.dataSyncDir, 'issues');\n    let tempFiles: string[] = [];\n\n    try {\n      const files = await readdir(issuesDir);\n      tempFiles = files.filter((f) => f.endsWith('.tmp'));\n    } catch {\n      // Directory doesn't exist - no temp files\n      return { name: 'Temp files', status: 'ok', path: issuesPath };\n    }\n\n    if (tempFiles.length === 0) {\n      return { name: 'Temp files', status: 'ok', path: issuesPath };\n    }\n\n    if (fix) {\n      // Clean up temp files\n      for (const file of tempFiles) {\n        try {\n          await unlink(join(issuesDir, file));\n        } catch {\n          // Ignore errors\n        }\n      }\n      return {\n        name: 'Temp files',\n        status: 'ok',\n        message: `Cleaned ${tempFiles.length} temp file(s)`,\n        path: issuesPath,\n      };\n    }\n\n    return {\n      name: 'Temp files',\n      status: 'warn',\n      message: `${tempFiles.length} orphaned temp file(s)`,\n      path: issuesPath,\n      details: tempFiles,\n      fixable: true,\n      suggestion: 'Run: tbd doctor --fix',\n    };\n  }\n\n  private checkIssueValidity(issues: Issue[]): DiagnosticResult {\n    const invalid: { id: string; reason: string }[] = [];\n\n    for (const issue of issues) {\n      const issueId = issue.id ?? 'unknown';\n      // Check required fields\n      if (!issue.id) {\n        invalid.push({ id: issueId, reason: 'missing required field: id' });\n        continue;\n      }\n      if (!issue.title) {\n        invalid.push({ id: issueId, reason: 'missing required field: title' });\n        continue;\n      }\n      if (!issue.status) {\n        invalid.push({ id: issueId, reason: 'missing required field: status' });\n        continue;\n      }\n      if (!issue.kind) {\n        invalid.push({ id: issueId, reason: 'missing required field: kind' });\n        continue;\n      }\n      // Check ID format\n      if (!validateIssueId(issue.id)) {\n        invalid.push({ id: issueId, reason: 'invalid ID format' });\n        continue;\n      }\n      // Check priority range\n      if (issue.priority < 0 || issue.priority > 4) {\n        invalid.push({ id: issueId, reason: `invalid priority ${issue.priority} (must be 0-4)` });\n      }\n    }\n\n    if (invalid.length === 0) {\n      return { name: 'Issue validity', status: 'ok' };\n    }\n\n    return {\n      name: 'Issue validity',\n      status: 'error',\n      message: `${invalid.length} invalid issue(s)`,\n      details: invalid.map((i) => `${i.id}: ${i.reason}`),\n      suggestion: 'Manually fix or delete invalid issue files',\n    };\n  }\n\n  private async checkClaudeSkill(): Promise<DiagnosticResult> {\n    const skillRelPath = join('.claude', 'skills', 'tbd', 'SKILL.md');\n    const skillPath = join(process.cwd(), skillRelPath);\n    try {\n      await access(skillPath);\n      return { name: 'Claude Code skill', status: 'ok', path: skillRelPath };\n    } catch {\n      return {\n        name: 'Claude Code skill',\n        status: 'warn',\n        message: 'not installed',\n        path: skillRelPath,\n        suggestion: 'Run: tbd setup --auto',\n      };\n    }\n  }\n\n  private async checkCodexAgents(): Promise<DiagnosticResult> {\n    const agentsRelPath = 'AGENTS.md';\n    const agentsPath = join(this.cwd, agentsRelPath);\n    try {\n      await access(agentsPath);\n      const content = await readFile(agentsPath, 'utf-8');\n      if (content.includes('BEGIN TBD INTEGRATION')) {\n        return { name: 'Codex AGENTS.md', status: 'ok', path: agentsRelPath };\n      }\n      return {\n        name: 'Codex AGENTS.md',\n        status: 'warn',\n        message: 'exists but missing tbd integration',\n        path: agentsRelPath,\n        suggestion: 'Run: tbd setup --auto',\n      };\n    } catch {\n      return {\n        name: 'Codex AGENTS.md',\n        status: 'warn',\n        message: 'not installed',\n        path: agentsRelPath,\n        suggestion: 'Run: tbd setup --auto',\n      };\n    }\n  }\n\n  private async checkWorktree(): Promise<DiagnosticResult> {\n    const worktreePath = WORKTREE_DIR;\n    const worktreeHealth = await checkWorktreeHealth(this.cwd);\n    if (worktreeHealth.valid) {\n      return { name: 'Worktree', status: 'ok', path: worktreePath };\n    }\n    if (!worktreeHealth.exists) {\n      // Worktree not existing is OK - it's created on demand\n      return { name: 'Worktree', status: 'ok', message: 'not created yet', path: worktreePath };\n    }\n    return {\n      name: 'Worktree',\n      status: 'warn',\n      message: worktreeHealth.error ?? 'unhealthy',\n      path: worktreePath,\n      fixable: true,\n      suggestion: 'Run: tbd doctor --fix',\n    };\n  }\n}\n\nexport const doctorCommand = new Command('doctor')\n  .description('Diagnose and repair repository')\n  .option('--fix', 'Attempt to fix issues')\n  .action(async (options, command) => {\n    const handler = new DoctorHandler(command);\n    await handler.run(options);\n  });\n","/**\n * `tbd config` - Configuration management.\n *\n * See: tbd-design.md §4.9 Config\n */\n\nimport { Command } from 'commander';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotInitializedError, ValidationError } from '../lib/errors.js';\nimport { readConfig, writeConfig } from '../../file/config.js';\nimport type { Config } from '../../lib/types.js';\n\n// Show config\nclass ConfigShowHandler extends BaseCommand {\n  async run(): Promise<void> {\n    await requireInit();\n\n    let config: Config;\n    try {\n      config = await readConfig('.');\n    } catch {\n      throw new NotInitializedError('No configuration found. Run `tbd init` first.');\n    }\n\n    this.output.data(config, () => {\n      // Output as YAML format\n      const colors = this.output.getColors();\n      console.log(`${colors.dim('tbd_version:')} ${config.tbd_version}`);\n      console.log(`${colors.dim('sync:')}`);\n      console.log(`  ${colors.dim('branch:')} ${config.sync.branch}`);\n      console.log(`  ${colors.dim('remote:')} ${config.sync.remote}`);\n      console.log(`${colors.dim('display:')}`);\n      console.log(`  ${colors.dim('id_prefix:')} ${config.display.id_prefix}`);\n      console.log(`${colors.dim('settings:')}`);\n      console.log(`  ${colors.dim('auto_sync:')} ${config.settings.auto_sync}`);\n    });\n  }\n}\n\n// Set config value\nclass ConfigSetHandler extends BaseCommand {\n  async run(key: string, value: string): Promise<void> {\n    await requireInit();\n\n    let config: Config;\n    try {\n      config = await readConfig('.');\n    } catch {\n      throw new NotInitializedError('No configuration found. Run `tbd init` first.');\n    }\n\n    if (this.checkDryRun('Would set config', { key, value })) {\n      return;\n    }\n\n    // Parse the key path and set value\n    const keys = key.split('.');\n    const parsedValue = this.parseValue(value);\n\n    try {\n      this.setNestedValue(config, keys, parsedValue);\n    } catch {\n      throw new ValidationError(`Invalid key: ${key}`);\n    }\n\n    await this.execute(async () => {\n      await writeConfig('.', config);\n    }, 'Failed to write config');\n\n    this.output.success(`Set ${key} = ${value}`);\n  }\n\n  private parseValue(value: string): unknown {\n    // Parse boolean\n    if (value === 'true') return true;\n    if (value === 'false') return false;\n    // Parse number\n    const num = Number(value);\n    if (!isNaN(num)) return num;\n    // Return as string\n    return value;\n  }\n\n  private setNestedValue(obj: Record<string, unknown>, keys: string[], value: unknown): void {\n    let current = obj;\n    for (let i = 0; i < keys.length - 1; i++) {\n      const key = keys[i]!;\n      if (typeof current[key] !== 'object' || current[key] === null) {\n        throw new Error(`Invalid path: ${keys.slice(0, i + 1).join('.')}`);\n      }\n      current = current[key] as Record<string, unknown>;\n    }\n    const lastKey = keys[keys.length - 1]!;\n    if (!(lastKey in current)) {\n      throw new Error(`Unknown key: ${keys.join('.')}`);\n    }\n    current[lastKey] = value;\n  }\n}\n\n// Get config value\nclass ConfigGetHandler extends BaseCommand {\n  async run(key: string): Promise<void> {\n    await requireInit();\n\n    let config: Config;\n    try {\n      config = await readConfig('.');\n    } catch {\n      throw new NotInitializedError('No configuration found. Run `tbd init` first.');\n    }\n\n    const keys = key.split('.');\n    let value: unknown = config;\n\n    for (const k of keys) {\n      if (typeof value !== 'object' || value === null || !(k in value)) {\n        throw new ValidationError(`Unknown key: ${key}`);\n      }\n      value = (value as Record<string, unknown>)[k];\n    }\n\n    this.output.data({ key, value }, () => {\n      console.log(String(value));\n    });\n  }\n}\n\nconst showConfigCommand = new Command('show')\n  .description('Show all configuration')\n  .action(async (_options, command) => {\n    const handler = new ConfigShowHandler(command);\n    await handler.run();\n  });\n\nconst setConfigCommand = new Command('set')\n  .description('Set a configuration value')\n  .argument('<key>', 'Configuration key (e.g., sync.branch)')\n  .argument('<value>', 'Value to set')\n  .action(async (key, value, _options, command) => {\n    const handler = new ConfigSetHandler(command);\n    await handler.run(key, value);\n  });\n\nconst getConfigCommand = new Command('get')\n  .description('Get a configuration value')\n  .argument('<key>', 'Configuration key')\n  .action(async (key, _options, command) => {\n    const handler = new ConfigGetHandler(command);\n    await handler.run(key);\n  });\n\nexport const configCommand = new Command('config')\n  .description('Manage configuration')\n  .addCommand(showConfigCommand)\n  .addCommand(setConfigCommand)\n  .addCommand(getConfigCommand);\n","/**\n * `tbd attic` - Attic (conflict archive) commands.\n *\n * See: tbd-design.md §4.11 Attic Commands\n */\n\nimport { Command } from 'commander';\nimport { readdir, readFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml, stringify as stringifyYaml } from 'yaml';\n\nimport { writeFile } from 'atomically';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, NotFoundError, ValidationError } from '../lib/errors.js';\nimport { readIssue, writeIssue } from '../../file/storage.js';\nimport { normalizeIssueId, formatDisplayId, formatDebugId } from '../../lib/ids.js';\nimport { resolveDataSyncDir, resolveAtticDir } from '../../lib/paths.js';\nimport { now } from '../../utils/time-utils.js';\nimport { loadIdMapping } from '../../file/id-mapping.js';\nimport { readConfig } from '../../file/config.js';\nimport type { AtticEntry } from '../../lib/types.js';\n\n/**\n * Get attic entry filename from components.\n */\nfunction getAtticFilename(entityId: string, timestamp: string, field: string): string {\n  // Convert timestamp colons to hyphens for filesystem safety\n  const safeTimestamp = timestamp.replace(/:/g, '-');\n  return `${entityId}_${safeTimestamp}_${field}.yml`;\n}\n\n/**\n * Parse attic entry filename to components.\n */\nfunction parseAtticFilename(\n  filename: string,\n): { entityId: string; timestamp: string; field: string } | null {\n  // Format: is-abc123_2025-01-07T10-30-00Z_description.yml\n  const match = /^(is-[a-f0-9]+)_(.+)_([^_]+)\\.yml$/.exec(filename);\n  if (!match) return null;\n  const [, entityId, timestamp, field] = match;\n  // Convert hyphens back to colons in timestamp\n  const isoTimestamp = timestamp!.replace(/T(\\d{2})-(\\d{2})-(\\d{2})/, 'T$1:$2:$3');\n  return { entityId: entityId!, timestamp: isoTimestamp, field: field! };\n}\n\n/**\n * List all attic entries.\n */\nasync function listAtticEntries(filterById?: string): Promise<AtticEntry[]> {\n  const atticPath = await resolveAtticDir();\n  let files: string[];\n\n  try {\n    files = await readdir(atticPath);\n  } catch {\n    // Attic directory doesn't exist - return empty\n    return [];\n  }\n\n  const entries: AtticEntry[] = [];\n\n  for (const file of files) {\n    if (!file.endsWith('.yml')) continue;\n\n    const parsed = parseAtticFilename(file);\n    if (!parsed) continue;\n\n    // Filter by ID if specified\n    if (filterById && parsed.entityId !== filterById) continue;\n\n    try {\n      const content = await readFile(join(atticPath, file), 'utf-8');\n      const entry = parseYaml(content) as AtticEntry;\n      entries.push(entry);\n    } catch {\n      // Skip invalid files\n    }\n  }\n\n  // Sort by timestamp descending (most recent first)\n  entries.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n\n  return entries;\n}\n\n/**\n * Save an attic entry.\n */\nexport async function saveAtticEntry(entry: AtticEntry): Promise<void> {\n  const atticPath = await resolveAtticDir();\n  await mkdir(atticPath, { recursive: true });\n\n  const filename = getAtticFilename(entry.entity_id, entry.timestamp, entry.field);\n  const filepath = join(atticPath, filename);\n  const content = stringifyYaml(entry, { sortMapEntries: true });\n\n  await writeFile(filepath, content);\n}\n\n// List attic entries\nclass AtticListHandler extends BaseCommand {\n  async run(id?: string): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const filterId = id ? normalizeIssueId(id) : undefined;\n    const entries = await listAtticEntries(filterId);\n\n    // Load ID mapping and config for display\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n    const mapping = await loadIdMapping(dataSyncDir);\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const showDebug = this.ctx.debug;\n\n    const output = entries.map((e) => ({\n      id: showDebug\n        ? formatDebugId(e.entity_id, mapping, prefix)\n        : formatDisplayId(e.entity_id, mapping, prefix),\n      timestamp: e.timestamp,\n      field: e.field,\n      winner: e.winner_source,\n    }));\n\n    this.output.data(output, () => {\n      const colors = this.output.getColors();\n      if (output.length === 0) {\n        console.log('No attic entries');\n        return;\n      }\n      console.log(\n        `${colors.dim('ID'.padEnd(12))}${colors.dim('TIMESTAMP'.padEnd(22))}${colors.dim('FIELD'.padEnd(14))}${colors.dim('WINNER')}`,\n      );\n      for (const entry of output) {\n        console.log(\n          `${colors.id(entry.id.padEnd(12))}${entry.timestamp.padEnd(22)}${entry.field.padEnd(14)}${entry.winner}`,\n        );\n      }\n    });\n  }\n}\n\n// Show attic entry\nclass AtticShowHandler extends BaseCommand {\n  async run(id: string, timestamp: string): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const normalizedId = normalizeIssueId(id);\n    const entries = await listAtticEntries(normalizedId);\n\n    // Find entry matching timestamp (approximate match for different formats)\n    const entry = entries.find(\n      (e) => e.timestamp === timestamp || e.timestamp.replace(/:/g, '-') === timestamp,\n    );\n\n    if (!entry) {\n      throw new NotFoundError('Attic entry', `${id} at ${timestamp}`);\n    }\n\n    // Load ID mapping and config for display\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n    const mapping = await loadIdMapping(dataSyncDir);\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const showDebug = this.ctx.debug;\n    const displayId = showDebug\n      ? formatDebugId(entry.entity_id, mapping, prefix)\n      : formatDisplayId(entry.entity_id, mapping, prefix);\n\n    this.output.data(entry, () => {\n      const colors = this.output.getColors();\n      console.log(`${colors.bold('Entity:')} ${displayId}`);\n      console.log(`${colors.bold('Timestamp:')} ${entry.timestamp}`);\n      console.log(`${colors.bold('Field:')} ${entry.field}`);\n      console.log(`${colors.bold('Winner:')} ${entry.winner_source}`);\n      console.log(`${colors.bold('Loser:')} ${entry.loser_source}`);\n      console.log('');\n      console.log(`${colors.bold('Lost value:')}`);\n      console.log(entry.lost_value);\n      console.log('');\n      console.log(`${colors.bold('Context:')}`);\n      console.log(`  Local version: ${entry.context.local_version}`);\n      console.log(`  Remote version: ${entry.context.remote_version}`);\n      console.log(`  Local updated: ${entry.context.local_updated_at}`);\n      console.log(`  Remote updated: ${entry.context.remote_updated_at}`);\n    });\n  }\n}\n\n// Restore from attic\nclass AtticRestoreHandler extends BaseCommand {\n  async run(id: string, timestamp: string): Promise<void> {\n    const tbdRoot = await requireInit();\n\n    const normalizedId = normalizeIssueId(id);\n    const entries = await listAtticEntries(normalizedId);\n\n    // Find entry matching timestamp\n    const entry = entries.find(\n      (e) => e.timestamp === timestamp || e.timestamp.replace(/:/g, '-') === timestamp,\n    );\n\n    if (!entry) {\n      throw new NotFoundError('Attic entry', `${id} at ${timestamp}`);\n    }\n\n    if (this.checkDryRun('Would restore from attic', { id: normalizedId, field: entry.field })) {\n      return;\n    }\n\n    // Load the current issue\n    const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n    let issue;\n    try {\n      issue = await readIssue(dataSyncDir, normalizedId);\n    } catch {\n      throw new NotFoundError('Issue', id);\n    }\n\n    // Restore the field value\n    const field = entry.field as keyof typeof issue;\n    if (field === 'description' || field === 'notes' || field === 'title') {\n      (issue as Record<string, unknown>)[field] = entry.lost_value;\n    } else {\n      throw new ValidationError(`Cannot restore field: ${entry.field}`);\n    }\n\n    issue.version += 1;\n    issue.updated_at = now();\n\n    await this.execute(async () => {\n      await writeIssue(dataSyncDir, issue);\n    }, 'Failed to restore from attic');\n\n    // Load ID mapping and config for display\n    const mapping = await loadIdMapping(dataSyncDir);\n    const config = await readConfig(tbdRoot);\n    const prefix = config.display.id_prefix;\n    const showDebug = this.ctx.debug;\n    const displayId = showDebug\n      ? formatDebugId(normalizedId, mapping, prefix)\n      : formatDisplayId(normalizedId, mapping, prefix);\n\n    this.output.success(`Restored ${entry.field} for ${displayId} from attic entry ${timestamp}`);\n  }\n}\n\ninterface AtticListOptions {\n  since?: string;\n  limit?: string;\n}\n\nconst listAtticCommand = new Command('list')\n  .description('List attic entries')\n  .argument('[id]', 'Filter by issue ID')\n  .option('--since <date>', 'Entries since date')\n  .option('--limit <n>', 'Limit results')\n  .action(async (id, options: AtticListOptions, command) => {\n    const handler = new AtticListHandler(command);\n    await handler.run(id);\n  });\n\nconst showAtticCommand = new Command('show')\n  .description('Show attic entry details')\n  .argument('<id>', 'Issue ID')\n  .argument('<timestamp>', 'Entry timestamp')\n  .action(async (id, timestamp, _options, command) => {\n    const handler = new AtticShowHandler(command);\n    await handler.run(id, timestamp);\n  });\n\nconst restoreAtticCommand = new Command('restore')\n  .description('Restore lost value from attic')\n  .argument('<id>', 'Issue ID')\n  .argument('<timestamp>', 'Entry timestamp')\n  .action(async (id, timestamp, _options, command) => {\n    const handler = new AtticRestoreHandler(command);\n    await handler.run(id, timestamp);\n  });\n\nexport const atticCommand = new Command('attic')\n  .description('Manage conflict archive (attic)')\n  .addCommand(listAtticCommand)\n  .addCommand(showAtticCommand)\n  .addCommand(restoreAtticCommand);\n","/**\n * `tbd import` - Import from Beads or other sources.\n *\n * See: tbd-design.md §5.1 Import Strategy\n */\n\nimport { Command } from 'commander';\nimport { readFile, access } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { requireInit, ValidationError, NotFoundError } from '../lib/errors.js';\nimport { writeIssue, listIssues } from '../../file/storage.js';\nimport {\n  generateInternalId,\n  extractShortId,\n  extractUlidFromInternalId,\n  makeInternalId,\n  extractPrefix,\n} from '../../lib/ids.js';\nimport {\n  loadIdMapping,\n  saveIdMapping,\n  addIdMapping,\n  hasShortId,\n  generateUniqueShortId,\n} from '../../file/id-mapping.js';\nimport { IssueStatus, IssueKind } from '../../lib/schemas.js';\nimport type { Issue, IssueStatusType, IssueKindType, DependencyType } from '../../lib/types.js';\nimport { resolveDataSyncDir } from '../../lib/paths.js';\nimport { now, normalizeTimestamp } from '../../utils/time-utils.js';\nimport { readConfig, writeConfig } from '../../file/config.js';\n\ninterface ImportOptions {\n  beadsDir?: string;\n  merge?: boolean;\n  verbose?: boolean;\n  validate?: boolean;\n}\n\ninterface ValidationIssue {\n  beadsId: string;\n  tbdId?: string;\n  issue: string;\n  severity: 'error' | 'warning';\n}\n\n/**\n * Beads issue structure (from JSONL export).\n */\ninterface BeadsIssue {\n  id: string;\n  title: string;\n  description?: string;\n  notes?: string;\n  type?: string;\n  issue_type?: string;\n  status: string;\n  priority?: number;\n  assignee?: string;\n  labels?: string[];\n  dependencies?: { type: string; target: string }[];\n  created_at: string;\n  updated_at: string;\n  closed_at?: string;\n  close_reason?: string;\n  due?: string;\n  defer?: string;\n  parent?: string;\n}\n\n/**\n * BeadsTotbd mapping: maps beads external ID to tbd internal ID.\n * This is a local structure used during import processing.\n */\ntype BeadsTotbdMapping = Record<string, string>;\n\n/**\n * Map Beads status to tbd status.\n */\nfunction mapStatus(beadsStatus: string): IssueStatusType {\n  const statusMap: Record<string, IssueStatusType> = {\n    open: 'open',\n    in_progress: 'in_progress',\n    blocked: 'blocked',\n    deferred: 'deferred',\n    done: 'closed', // Beads uses 'done' for completed items\n    closed: 'closed',\n    tombstone: 'closed',\n  };\n  const result = IssueStatus.safeParse(statusMap[beadsStatus] ?? beadsStatus);\n  return result.success ? result.data : 'open';\n}\n\n/**\n * Map Beads issue type to tbd kind.\n */\nfunction mapKind(beadsType?: string): IssueKindType {\n  const kindMap: Record<string, IssueKindType> = {\n    bug: 'bug',\n    feature: 'feature',\n    task: 'task',\n    epic: 'epic',\n    chore: 'chore',\n  };\n  if (!beadsType) return 'task';\n  const result = IssueKind.safeParse(kindMap[beadsType] ?? beadsType);\n  return result.success ? result.data : 'task';\n}\n\n/**\n * Convert Beads issue to tbd issue.\n */\nfunction convertIssue(beads: BeadsIssue, tbdId: string, depMapping: BeadsTotbdMapping): Issue {\n  // Convert dependencies, translating IDs\n  const dependencies: DependencyType[] = [];\n  if (beads.dependencies) {\n    for (const dep of beads.dependencies) {\n      if (dep.type === 'blocks' || dep.type === 'blocked_by') {\n        const targetId = depMapping[dep.target];\n        if (targetId) {\n          // \"blocked_by\" in Beads means the target blocks this issue\n          // In tbd, we only have \"blocks\", so we need to handle this carefully\n          // For now, we store \"blocks\" dependencies directly\n          if (dep.type === 'blocks') {\n            dependencies.push({ type: 'blocks', target: targetId });\n          }\n          // Note: blocked_by would need to be added to the target issue's dependencies\n        }\n      }\n    }\n  }\n\n  return {\n    type: 'is',\n    id: tbdId,\n    version: 1,\n    kind: mapKind(beads.type ?? beads.issue_type),\n    title: beads.title,\n    description: beads.description,\n    notes: beads.notes,\n    status: mapStatus(beads.status),\n    priority: beads.priority ?? 2,\n    assignee: beads.assignee,\n    labels: beads.labels ?? [],\n    dependencies,\n    created_at: normalizeTimestamp(beads.created_at) ?? now(),\n    updated_at: normalizeTimestamp(beads.updated_at) ?? now(),\n    closed_at: normalizeTimestamp(beads.closed_at),\n    close_reason: beads.close_reason ?? null,\n    due_date: normalizeTimestamp(beads.due),\n    deferred_until: normalizeTimestamp(beads.defer),\n    parent_id: beads.parent ? depMapping[beads.parent] : null,\n    extensions: {\n      beads: {\n        original_id: beads.id,\n        imported_at: now(),\n      },\n    },\n  };\n}\n\nclass ImportHandler extends BaseCommand {\n  private dataSyncDir = '';\n\n  async run(file: string | undefined, options: ImportOptions): Promise<void> {\n    // Validate input first\n    if (!file && !options.validate) {\n      throw new ValidationError(\n        'Provide a JSONL file path to import.\\n\\n' +\n          'For Beads migration, use: tbd setup --from-beads',\n      );\n    }\n\n    // Handle validation mode - requires init\n    if (options.validate) {\n      await requireInit();\n      this.dataSyncDir = await resolveDataSyncDir();\n      await this.validateImport(options);\n      return;\n    }\n\n    // File import requires initialization\n    if (file) {\n      await requireInit();\n      this.dataSyncDir = await resolveDataSyncDir();\n      await this.importFromFile(file, options);\n    }\n  }\n\n  /**\n   * Validate import by comparing Beads source with imported tbd issues.\n   * Reports any discrepancies or missing issues.\n   */\n  private async validateImport(options: ImportOptions): Promise<void> {\n    const beadsDir = options.beadsDir ?? '.beads';\n    const jsonlPath = join(beadsDir, 'issues.jsonl');\n\n    try {\n      await access(jsonlPath);\n    } catch {\n      throw new NotFoundError('Beads database', `${beadsDir} (use --beads-dir to specify)`);\n    }\n\n    console.log('Validating import...\\n');\n\n    // Load Beads issues\n    const content = await readFile(jsonlPath, 'utf-8');\n    const lines = content\n      .trim()\n      .split('\\n')\n      .filter((l) => l);\n    const beadsIssues: BeadsIssue[] = [];\n\n    for (const line of lines) {\n      try {\n        const issue = JSON.parse(line) as BeadsIssue;\n        if (issue.id && issue.title) {\n          beadsIssues.push(issue);\n        }\n      } catch {\n        // Skip invalid lines\n      }\n    }\n\n    // Load tbd issues and short ID mapping\n    const tbdIssues = await this.loadExistingIssues();\n    const shortIdMapping = await loadIdMapping(this.dataSyncDir);\n\n    // Build mapping from beads ID to tbd internal ID using preserved short IDs\n    // e.g., \"tbd-100\" -> extract \"100\" -> lookup in shortIdMapping -> \"is-{ulid}\"\n    const beadsTotbd: BeadsTotbdMapping = {};\n    const reverseMapping: Record<string, string> = {};\n\n    for (const beads of beadsIssues) {\n      const shortId = extractShortId(beads.id);\n      const ulid = shortIdMapping.shortToUlid.get(shortId);\n      if (ulid) {\n        const internalId = makeInternalId(ulid);\n        beadsTotbd[beads.id] = internalId;\n        reverseMapping[internalId] = beads.id;\n      }\n    }\n\n    // Build lookup by tbd ID\n    const tbdById = new Map<string, Issue>();\n    for (const issue of tbdIssues) {\n      tbdById.set(issue.id, issue);\n    }\n\n    // Validate each Beads issue\n    const issues: ValidationIssue[] = [];\n    let validCount = 0;\n\n    for (const beads of beadsIssues) {\n      const tbdId = beadsTotbd[beads.id];\n\n      if (!tbdId) {\n        issues.push({\n          beadsId: beads.id,\n          issue: 'Not imported - no ID mapping exists',\n          severity: 'error',\n        });\n        continue;\n      }\n\n      const tbdIssue = tbdById.get(tbdId);\n      if (!tbdIssue) {\n        issues.push({\n          beadsId: beads.id,\n          tbdId,\n          issue: 'ID mapping exists but issue file not found',\n          severity: 'error',\n        });\n        continue;\n      }\n\n      // Validate fields\n      const fieldIssues: string[] = [];\n\n      if (tbdIssue.title !== beads.title) {\n        fieldIssues.push(`title mismatch: \"${tbdIssue.title}\" vs \"${beads.title}\"`);\n      }\n\n      const expectedStatus = mapStatus(beads.status);\n      if (tbdIssue.status !== expectedStatus) {\n        fieldIssues.push(`status mismatch: \"${tbdIssue.status}\" vs expected \"${expectedStatus}\"`);\n      }\n\n      const expectedKind = mapKind(beads.type ?? beads.issue_type);\n      if (tbdIssue.kind !== expectedKind) {\n        fieldIssues.push(`kind mismatch: \"${tbdIssue.kind}\" vs expected \"${expectedKind}\"`);\n      }\n\n      if ((beads.priority ?? 2) !== tbdIssue.priority) {\n        fieldIssues.push(`priority mismatch: ${tbdIssue.priority} vs ${beads.priority ?? 2}`);\n      }\n\n      // Check labels\n      const beadsLabels = new Set(beads.labels ?? []);\n      const tbdLabels = new Set(tbdIssue.labels ?? []);\n      const missingLabels = [...beadsLabels].filter((l) => !tbdLabels.has(l));\n      if (missingLabels.length > 0) {\n        fieldIssues.push(`missing labels: ${missingLabels.join(', ')}`);\n      }\n\n      if (fieldIssues.length > 0) {\n        issues.push({\n          beadsId: beads.id,\n          tbdId,\n          issue: fieldIssues.join('; '),\n          severity: 'warning',\n        });\n      } else {\n        validCount++;\n      }\n    }\n\n    // Check for orphaned tbd issues (not in Beads)\n    const beadsIds = new Set(beadsIssues.map((b) => b.id));\n    for (const tbdIssue of tbdIssues) {\n      const beadsId = reverseMapping[tbdIssue.id];\n      if (beadsId && !beadsIds.has(beadsId)) {\n        issues.push({\n          beadsId,\n          tbdId: tbdIssue.id,\n          issue: 'tbd issue has mapping but Beads issue no longer exists',\n          severity: 'warning',\n        });\n      }\n    }\n\n    // Report results\n    const errors = issues.filter((i) => i.severity === 'error');\n    const warnings = issues.filter((i) => i.severity === 'warning');\n\n    console.log('Validation Results');\n    console.log('─'.repeat(60));\n    console.log(`Total Beads issues:    ${beadsIssues.length}`);\n    console.log(`Total tbd issues:      ${tbdIssues.length}`);\n    console.log(`Valid imports:         ${validCount}`);\n    console.log(`Errors:                ${errors.length}`);\n    console.log(`Warnings:              ${warnings.length}`);\n    console.log('─'.repeat(60));\n\n    if (errors.length > 0) {\n      console.log('\\nErrors:');\n      for (const err of errors) {\n        console.log(`  ✗ ${err.beadsId}: ${err.issue}`);\n      }\n    }\n\n    if (warnings.length > 0 && options.verbose) {\n      console.log('\\nWarnings:');\n      for (const warn of warnings) {\n        console.log(`  ⚠ ${warn.beadsId}: ${warn.issue}`);\n      }\n    }\n\n    console.log();\n    if (errors.length === 0 && warnings.length === 0) {\n      this.output.success('All imports validated successfully!');\n    } else if (errors.length === 0) {\n      this.output.warn(`Validation complete with ${warnings.length} warnings`);\n      if (!options.verbose) {\n        console.log('  Use --verbose to see warning details');\n      }\n    } else {\n      this.output.error(`Validation failed with ${errors.length} errors`);\n    }\n\n    // Output JSON for programmatic use\n    this.output.data({\n      valid: validCount,\n      errors: errors.length,\n      warnings: warnings.length,\n      total: beadsIssues.length,\n      issues: options.verbose ? issues : undefined,\n    });\n  }\n\n  private async importFromFile(filePath: string, options: ImportOptions): Promise<void> {\n    // Check file exists\n    try {\n      await access(filePath);\n    } catch {\n      throw new NotFoundError('File', filePath);\n    }\n\n    if (this.checkDryRun('Would import issues', { file: filePath })) {\n      // For dry run, still parse and show what would happen\n      const content = await readFile(filePath, 'utf-8');\n      const lines = content\n        .trim()\n        .split('\\n')\n        .filter((l) => l);\n      this.output.info(`Would import ${lines.length} issues from ${filePath}`);\n      return;\n    }\n\n    // Load file content\n    const content = await readFile(filePath, 'utf-8');\n    const lines = content\n      .trim()\n      .split('\\n')\n      .filter((l) => l);\n\n    // Parse JSONL\n    const beadsIssues: BeadsIssue[] = [];\n    for (const line of lines) {\n      try {\n        const issue = JSON.parse(line) as BeadsIssue;\n        if (issue.id && issue.title) {\n          beadsIssues.push(issue);\n        }\n      } catch {\n        if (options.verbose) {\n          this.output.warn(`Skipping invalid JSON line`);\n        }\n      }\n    }\n\n    if (beadsIssues.length === 0) {\n      this.output.info('No valid issues found in file');\n      return;\n    }\n\n    // Auto-detect prefix from imported issues and update config if needed\n    const detectedPrefix = this.detectPrefixFromIssues(beadsIssues);\n    await this.updateConfigPrefixIfNeeded(detectedPrefix);\n\n    // Load existing issues and short ID mapping\n    const existingIssues = await this.loadExistingIssues();\n    const shortIdMapping = await loadIdMapping(this.dataSyncDir);\n\n    // Build lookup maps\n    const existingByBeadsId = new Map<string, Issue>();\n    const existingByShortId = new Map<string, Issue>();\n\n    // Build reverse lookup from extensions and from short ID mapping\n    for (const issue of existingIssues) {\n      const beadsExt = issue.extensions?.beads as { original_id?: string } | undefined;\n      if (beadsExt?.original_id) {\n        existingByBeadsId.set(beadsExt.original_id, issue);\n      }\n      // Also track by short ID\n      const ulid = extractUlidFromInternalId(issue.id);\n      const shortId = shortIdMapping.ulidToShort.get(ulid);\n      if (shortId) {\n        existingByShortId.set(shortId, issue);\n      }\n    }\n\n    // Build beads-to-tbd mapping, preserving original short IDs\n    // e.g., \"tbd-100\" preserves \"100\" as the short ID\n    const beadsTotbd: BeadsTotbdMapping = {};\n\n    // First pass: assign IDs to all issues (needed for dependency translation)\n    for (const beads of beadsIssues) {\n      // Extract the short ID from beads ID (e.g., \"tbd-100\" -> \"100\")\n      const shortId = extractShortId(beads.id);\n\n      // Check if we already have this issue by beads ID (from previous import)\n      const existingByBeads = existingByBeadsId.get(beads.id);\n      if (existingByBeads) {\n        beadsTotbd[beads.id] = existingByBeads.id;\n        continue;\n      }\n\n      // Check if we already have a mapping for this short ID\n      const existingByShort = existingByShortId.get(shortId);\n      if (existingByShort) {\n        beadsTotbd[beads.id] = existingByShort.id;\n        continue;\n      }\n\n      // Check if the short ID is already in the mapping (collision check)\n      if (hasShortId(shortIdMapping, shortId)) {\n        // Short ID already exists but for a different issue - generate a new one\n        if (options.verbose) {\n          this.output.warn(\n            `Short ID \"${shortId}\" already exists, generating new ID for ${beads.id}`,\n          );\n        }\n        const internalId = generateInternalId();\n        beadsTotbd[beads.id] = internalId;\n        // Generate a random short ID since the original is taken\n        const ulid = extractUlidFromInternalId(internalId);\n        const newShortId = generateUniqueShortId(shortIdMapping);\n        addIdMapping(shortIdMapping, ulid, newShortId);\n      } else {\n        // Create new mapping, preserving the original short ID\n        const internalId = generateInternalId();\n        beadsTotbd[beads.id] = internalId;\n        const ulid = extractUlidFromInternalId(internalId);\n        addIdMapping(shortIdMapping, ulid, shortId);\n      }\n    }\n\n    // Second pass: convert and save issues\n    let imported = 0;\n    let skipped = 0;\n    let merged = 0;\n\n    for (const beads of beadsIssues) {\n      const tbdId = beadsTotbd[beads.id]!;\n      const existing = existingByBeadsId.get(beads.id);\n\n      if (existing && !options.merge) {\n        // Check if Beads is newer\n        if (new Date(beads.updated_at) <= new Date(existing.updated_at)) {\n          skipped++;\n          continue;\n        }\n      }\n\n      const issue = convertIssue(beads, tbdId, beadsTotbd);\n\n      if (existing) {\n        // Merge: keep higher version, update fields\n        issue.version = existing.version + 1;\n        merged++;\n      } else {\n        imported++;\n      }\n\n      try {\n        await writeIssue(this.dataSyncDir, issue);\n      } catch (error) {\n        if (options.verbose) {\n          this.output.warn(`Failed to write issue ${beads.id}: ${(error as Error).message}`);\n        }\n      }\n    }\n\n    // Save updated short ID mapping (no separate beads.yml needed - IDs are preserved)\n    await saveIdMapping(this.dataSyncDir, shortIdMapping);\n\n    const result = { imported, skipped, merged, total: beadsIssues.length };\n\n    this.output.data(result, () => {\n      this.output.success(`Import complete from ${filePath}`);\n      console.log(`  New issues:   ${imported}`);\n      console.log(`  Merged:       ${merged}`);\n      console.log(`  Skipped:      ${skipped}`);\n    });\n  }\n\n  private async loadExistingIssues(): Promise<Issue[]> {\n    try {\n      return await listIssues(this.dataSyncDir);\n    } catch {\n      return [];\n    }\n  }\n\n  /**\n   * Detect the prefix used by beads issues from a file path.\n   * Reads the first few issues and extracts the common prefix pattern.\n   * Falls back to 'tbd' if no consistent prefix is found.\n   */\n  private async detectBeadsPrefix(jsonlPath: string): Promise<string> {\n    try {\n      const content = await readFile(jsonlPath, 'utf-8');\n      const lines = content\n        .trim()\n        .split('\\n')\n        .filter((l) => l)\n        .slice(0, 10); // Sample first 10 issues\n\n      const issues: BeadsIssue[] = [];\n      for (const line of lines) {\n        try {\n          const issue = JSON.parse(line) as BeadsIssue;\n          if (issue.id) {\n            issues.push(issue);\n          }\n        } catch {\n          // Skip invalid lines\n        }\n      }\n\n      return this.detectPrefixFromIssues(issues);\n    } catch {\n      return 'tbd'; // Default fallback\n    }\n  }\n\n  /**\n   * Detect the prefix used by a list of beads issues.\n   * Extracts the common prefix pattern from issue IDs.\n   * Falls back to 'tbd' if no consistent prefix is found.\n   */\n  private detectPrefixFromIssues(issues: BeadsIssue[]): string {\n    const prefixes = new Map<string, number>();\n\n    for (const issue of issues.slice(0, 10)) {\n      // Sample first 10\n      if (issue.id) {\n        const prefix = extractPrefix(issue.id);\n        if (prefix) {\n          prefixes.set(prefix, (prefixes.get(prefix) ?? 0) + 1);\n        }\n      }\n    }\n\n    // Find the most common prefix\n    let maxCount = 0;\n    let mostCommonPrefix = 'tbd';\n    for (const [prefix, count] of prefixes) {\n      if (count > maxCount) {\n        maxCount = count;\n        mostCommonPrefix = prefix;\n      }\n    }\n\n    return mostCommonPrefix;\n  }\n\n  /**\n   * Update config prefix if it differs from the detected prefix.\n   * Returns true if prefix was updated.\n   */\n  private async updateConfigPrefixIfNeeded(detectedPrefix: string): Promise<boolean> {\n    const cwd = process.cwd();\n    try {\n      const config = await readConfig(cwd);\n      if (config.display.id_prefix !== detectedPrefix) {\n        const oldPrefix = config.display.id_prefix;\n        config.display.id_prefix = detectedPrefix;\n        await writeConfig(cwd, config);\n        this.output.info(`Updated ID prefix: ${oldPrefix} → ${detectedPrefix}`);\n        return true;\n      }\n      return false;\n    } catch {\n      // Config doesn't exist or can't be read - skip update\n      return false;\n    }\n  }\n}\n\nexport const importCommand = new Command('import')\n  .description(\n    'Import issues from JSONL file.\\n' + 'For Beads migration, use: tbd setup --from-beads',\n  )\n  .argument('[file]', 'JSONL file to import')\n  .option('--beads-dir <path>', 'Beads data directory (for --validate)')\n  .option('--merge', 'Merge with existing issues instead of skipping duplicates')\n  .option('--verbose', 'Show detailed import progress')\n  .option('--validate', 'Validate existing import against Beads source')\n  .action(async (file, options, command) => {\n    const handler = new ImportHandler(command);\n    await handler.run(file, options);\n  });\n","/**\n * DocSync - Sync documentation files from configured sources.\n *\n * Syncs docs from internal bundled sources and external URLs to .tbd/docs/.\n *\n * See: docs/project/specs/active/plan-2026-01-26-configurable-doc-cache-sync.md\n */\n\nimport { readdir, readFile, rm, mkdir, access } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { writeFile } from 'atomically';\nimport { fileURLToPath } from 'node:url';\n\nimport { TBD_DOCS_DIR } from '../lib/paths.js';\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * A parsed document source.\n */\nexport interface DocSource {\n  /** Source type: internal bundled or external URL */\n  type: 'internal' | 'url';\n  /** The source location - either a relative path or full URL */\n  location: string;\n}\n\n/**\n * Result of a sync operation.\n */\nexport interface SyncResult {\n  /** Paths of newly downloaded/copied docs */\n  added: string[];\n  /** Paths of updated docs (content changed) */\n  updated: string[];\n  /** Paths of removed docs (no longer in config) */\n  removed: string[];\n  /** Errors encountered during sync */\n  errors: { path: string; error: string }[];\n  /** Whether the sync was successful overall */\n  success: boolean;\n}\n\n/**\n * Options for sync operations.\n */\nexport interface SyncOptions {\n  /** If true, don't actually write/delete files (dry run) */\n  dryRun?: boolean;\n  /** If true, suppress normal output (only report errors) */\n  silent?: boolean;\n}\n\n// =============================================================================\n// Constants\n// =============================================================================\n\n/** Prefix for internal bundled doc sources */\nconst INTERNAL_PREFIX = 'internal:';\n\n/** Timeout for URL fetches in milliseconds */\nconst FETCH_TIMEOUT = 30000;\n\n// =============================================================================\n// DocSync Class\n// =============================================================================\n\n/**\n * Syncs documentation files from configured sources.\n *\n * Supports:\n * - Internal bundled docs (using internal: prefix)\n * - External URLs (raw.githubusercontent.com, etc.)\n */\nexport class DocSync {\n  private readonly docsDir: string;\n\n  /**\n   * Create a new DocSync instance.\n   *\n   * @param tbdRoot - The tbd project root directory (parent of .tbd/)\n   * @param config - The doc_cache configuration mapping dest paths to sources\n   */\n  constructor(\n    private readonly tbdRoot: string,\n    private readonly config: Record<string, string>,\n  ) {\n    this.docsDir = join(tbdRoot, TBD_DOCS_DIR);\n  }\n\n  /**\n   * Parse a source string into a DocSource.\n   *\n   * @example\n   * parseSource('internal:shortcuts/standard/commit-code.md')\n   * // => { type: 'internal', location: 'shortcuts/standard/commit-code.md' }\n   *\n   * @example\n   * parseSource('https://raw.githubusercontent.com/org/repo/main/file.md')\n   * // => { type: 'url', location: 'https://...' }\n   */\n  parseSource(source: string): DocSource {\n    if (source.startsWith(INTERNAL_PREFIX)) {\n      return {\n        type: 'internal',\n        location: source.slice(INTERNAL_PREFIX.length),\n      };\n    }\n\n    // Anything else is treated as a URL\n    return {\n      type: 'url',\n      location: source,\n    };\n  }\n\n  /**\n   * Fetch content from a source.\n   *\n   * @throws If the source cannot be fetched\n   */\n  async fetchContent(source: DocSource): Promise<string> {\n    if (source.type === 'internal') {\n      return this.fetchInternalContent(source.location);\n    }\n    return this.fetchUrlContent(source.location);\n  }\n\n  /**\n   * Fetch content from an internal bundled doc.\n   */\n  private async fetchInternalContent(location: string): Promise<string> {\n    const basePaths = getDocsBasePath();\n\n    for (const basePath of basePaths) {\n      const fullPath = join(basePath, location);\n      try {\n        await access(fullPath);\n        return await readFile(fullPath, 'utf-8');\n      } catch {\n        // Try next path\n      }\n    }\n\n    throw new Error(`Internal doc not found: ${location}`);\n  }\n\n  /**\n   * Fetch content from a URL.\n   */\n  private async fetchUrlContent(url: string): Promise<string> {\n    const controller = new AbortController();\n    const timeout = setTimeout(() => {\n      controller.abort();\n    }, FETCH_TIMEOUT);\n\n    try {\n      const response = await fetch(url, {\n        signal: controller.signal,\n        headers: {\n          'User-Agent': 'tbd-git/1.0',\n          Accept: 'text/plain, text/markdown, */*',\n        },\n      });\n\n      if (!response.ok) {\n        throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n      }\n\n      return await response.text();\n    } finally {\n      clearTimeout(timeout);\n    }\n  }\n\n  /**\n   * Get the current state of the docs directory.\n   * Returns a set of relative paths that exist in .tbd/docs/.\n   */\n  async getCurrentState(): Promise<Set<string>> {\n    const paths = new Set<string>();\n\n    try {\n      await access(this.docsDir);\n    } catch {\n      // Directory doesn't exist yet\n      return paths;\n    }\n\n    await this.scanDirectory(this.docsDir, '', paths);\n    return paths;\n  }\n\n  /**\n   * Recursively scan a directory and add all .md file paths to the set.\n   */\n  private async scanDirectory(baseDir: string, prefix: string, paths: Set<string>): Promise<void> {\n    try {\n      const dirEntries = await readdir(baseDir, { withFileTypes: true });\n\n      for (const entry of dirEntries) {\n        const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;\n\n        if (entry.isDirectory()) {\n          await this.scanDirectory(join(baseDir, entry.name), relativePath, paths);\n        } else if (entry.isFile() && entry.name.endsWith('.md')) {\n          paths.add(relativePath);\n        }\n      }\n    } catch {\n      // Directory doesn't exist or not readable\n    }\n  }\n\n  /**\n   * Sync all docs from config to .tbd/docs/.\n   *\n   * - Downloads/copies new docs\n   * - Updates docs whose source has changed\n   * - Removes docs no longer in config\n   *\n   * @param options - Sync options (dryRun, silent)\n   */\n  async sync(options: SyncOptions = {}): Promise<SyncResult> {\n    const result: SyncResult = {\n      added: [],\n      updated: [],\n      removed: [],\n      errors: [],\n      success: true,\n    };\n\n    // Get current state\n    const currentPaths = await this.getCurrentState();\n    const configPaths = new Set(Object.keys(this.config));\n\n    // Process each doc in config\n    for (const [destPath, sourceStr] of Object.entries(this.config)) {\n      try {\n        const source = this.parseSource(sourceStr);\n        const content = await this.fetchContent(source);\n        const fullPath = join(this.docsDir, destPath);\n\n        // Check if file exists and compare content\n        let exists = false;\n        let existingContent = '';\n\n        try {\n          existingContent = await readFile(fullPath, 'utf-8');\n          exists = true;\n        } catch {\n          // File doesn't exist\n        }\n\n        if (!exists) {\n          // New file\n          if (!options.dryRun) {\n            await mkdir(dirname(fullPath), { recursive: true });\n            await writeFile(fullPath, content);\n          }\n          result.added.push(destPath);\n        } else if (existingContent !== content) {\n          // Content changed\n          if (!options.dryRun) {\n            await writeFile(fullPath, content);\n          }\n          result.updated.push(destPath);\n        }\n        // else: unchanged, do nothing\n      } catch (err) {\n        result.errors.push({\n          path: destPath,\n          error: (err as Error).message,\n        });\n        result.success = false;\n      }\n    }\n\n    // Remove docs not in config\n    for (const existingPath of currentPaths) {\n      if (!configPaths.has(existingPath)) {\n        try {\n          if (!options.dryRun) {\n            await rm(join(this.docsDir, existingPath));\n          }\n          result.removed.push(existingPath);\n        } catch (err) {\n          result.errors.push({\n            path: existingPath,\n            error: `Failed to remove: ${(err as Error).message}`,\n          });\n        }\n      }\n    }\n\n    return result;\n  }\n\n  /**\n   * Get a status of what would change without actually making changes.\n   */\n  async status(): Promise<SyncResult> {\n    return this.sync({ dryRun: true });\n  }\n}\n\n// =============================================================================\n// Helper Functions\n// =============================================================================\n\n/**\n * Get base docs paths (with fallbacks for development).\n * Matches the logic in setup.ts.\n */\nfunction getDocsBasePath(): string[] {\n  const __filename = fileURLToPath(import.meta.url);\n  const __dirname = dirname(__filename);\n  return [\n    // Bundled location (dist/docs/)\n    join(__dirname, 'docs'),\n    // Development: packages/tbd/docs/\n    join(__dirname, '..', '..', 'docs'),\n  ];\n}\n\n/**\n * Generate default doc_cache config by scanning bundled docs.\n *\n * This creates a config entry for each .md file found in the bundled\n * docs directories (shortcuts, guidelines, templates).\n *\n * @returns A doc_cache config mapping destination paths to internal: sources\n */\nexport async function generateDefaultDocCacheConfig(): Promise<Record<string, string>> {\n  const config: Record<string, string> = {};\n  const basePaths = getDocsBasePath();\n\n  // Find the first valid base path\n  let docsDir: string | null = null;\n  for (const path of basePaths) {\n    try {\n      await access(path);\n      docsDir = path;\n      break;\n    } catch {\n      // Try next path\n    }\n  }\n\n  if (!docsDir) {\n    return config;\n  }\n\n  // Directories to scan\n  const scanDirs = [\n    { subdir: 'shortcuts/system', prefix: 'shortcuts/system' },\n    { subdir: 'shortcuts/standard', prefix: 'shortcuts/standard' },\n    { subdir: 'guidelines', prefix: 'guidelines' },\n    { subdir: 'templates', prefix: 'templates' },\n  ];\n\n  for (const { subdir, prefix } of scanDirs) {\n    const fullDir = join(docsDir, subdir);\n    try {\n      const entries = await readdir(fullDir, { withFileTypes: true });\n      for (const entry of entries) {\n        if (entry.isFile() && entry.name.endsWith('.md')) {\n          const relativePath = `${prefix}/${entry.name}`;\n          config[relativePath] = `${INTERNAL_PREFIX}${relativePath}`;\n        }\n      }\n    } catch {\n      // Directory doesn't exist, skip\n    }\n  }\n\n  return config;\n}\n\n/**\n * Merge user's doc_cache config with default bundled docs.\n *\n * This ensures:\n * - New bundled docs from tbd updates are added to existing configs\n * - User's custom sources (URLs, etc.) are preserved\n * - User's overrides of bundled docs are respected\n *\n * @param userConfig - The user's existing doc_cache config (may be undefined/empty)\n * @param defaults - The default config from generateDefaultDocCacheConfig()\n * @returns Merged config with defaults as base, user config overlaid\n */\nexport function mergeDocCacheConfig(\n  userConfig: Record<string, string> | undefined,\n  defaults: Record<string, string>,\n): Record<string, string> {\n  // Start with defaults, overlay user config (user takes precedence)\n  return {\n    ...defaults,\n    ...userConfig,\n  };\n}\n\n/**\n * Check if docs are stale based on last sync time and configured hours.\n *\n * @param lastSyncAt - ISO timestamp of last sync (or undefined if never synced)\n * @param autoSyncHours - Hours between auto-syncs (0 = disabled)\n * @returns true if docs should be synced\n */\nexport function isDocsStale(lastSyncAt: string | undefined, autoSyncHours: number): boolean {\n  // Auto-sync disabled\n  if (autoSyncHours <= 0) {\n    return false;\n  }\n\n  // Never synced\n  if (!lastSyncAt) {\n    return true;\n  }\n\n  const lastSync = new Date(lastSyncAt).getTime();\n  const now = Date.now();\n  const hoursSinceSync = (now - lastSync) / (1000 * 60 * 60);\n\n  return hoursSinceSync >= autoSyncHours;\n}\n","/**\n * `tbd docs` - Display CLI documentation and manage doc cache.\n *\n * Shows the bundled documentation for tbd CLI.\n * Documentation can be filtered by section.\n *\n * Also provides --refresh and --status for syncing the doc cache from config.\n */\n\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { CLIError, NotFoundError, NotInitializedError } from '../lib/errors.js';\nimport { renderMarkdown } from '../lib/output.js';\nimport type { DocSection } from '../../lib/types.js';\nimport GithubSlugger from 'github-slugger';\nimport { findTbdRoot, readConfig, updateLocalState } from '../../file/config.js';\nimport {\n  DocSync,\n  generateDefaultDocCacheConfig,\n  mergeDocCacheConfig,\n} from '../../file/doc-sync.js';\n\n/**\n * Get the path to the bundled docs file.\n * The docs file is copied to dist/docs/ during build.\n */\nfunction getDocsPath(): string {\n  const __filename = fileURLToPath(import.meta.url);\n  const __dirname = dirname(__filename);\n  // When bundled, runs from dist/bin.mjs or dist/cli.mjs\n  // Docs are at dist/docs/tbd-docs.md (same level as the bundle)\n  return join(__dirname, 'docs', 'tbd-docs.md');\n}\n\ninterface DocsOptions {\n  section?: string;\n  list?: boolean;\n  all?: boolean;\n  refresh?: boolean;\n  status?: boolean;\n}\n\nclass DocsHandler extends BaseCommand {\n  async run(topic: string | undefined, options: DocsOptions): Promise<void> {\n    // Handle doc cache sync options first\n    if (options.refresh) {\n      await this.handleRefresh();\n      return;\n    }\n\n    if (options.status) {\n      await this.handleStatus();\n      return;\n    }\n\n    let content: string;\n    try {\n      content = await readFile(getDocsPath(), 'utf-8');\n    } catch {\n      // Fallback: try to read from source location during development\n      try {\n        const __filename = fileURLToPath(import.meta.url);\n        const __dirname = dirname(__filename);\n        // During development: src/cli/commands -> packages/tbd/docs\n        const devPath = join(__dirname, '..', '..', '..', 'docs', 'tbd-docs.md');\n        content = await readFile(devPath, 'utf-8');\n      } catch {\n        throw new CLIError('Documentation file not found. Please rebuild the CLI.');\n      }\n    }\n\n    const sections = this.extractSections(content);\n\n    // Show comprehensive documentation listing\n    if (options.all) {\n      await this.showComprehensiveListing();\n      return;\n    }\n\n    // List available sections\n    if (options.list) {\n      this.output.data(sections, () => {\n        const colors = this.output.getColors();\n        console.log(colors.bold('Available documentation sections:'));\n        console.log('');\n        // Calculate max slug length for alignment\n        const maxSlugLen = Math.max(...sections.map((s) => s.slug.length));\n        for (const section of sections) {\n          const paddedSlug = section.slug.padEnd(maxSlugLen);\n          console.log(`  ${colors.id(paddedSlug)}  ${section.title}`);\n        }\n        console.log('');\n        console.log(`Use ${colors.dim('tbd docs <topic>')} to view a specific section.`);\n      });\n      return;\n    }\n\n    // Determine which section to show (positional topic takes precedence)\n    const sectionQuery = topic ?? options.section;\n\n    // Filter by section if specified\n    if (sectionQuery) {\n      const sectionContent = this.extractSection(content, sections, sectionQuery);\n      if (!sectionContent) {\n        throw new NotFoundError(\n          'Section',\n          `\"${sectionQuery}\" (use --list to see available sections)`,\n        );\n      }\n      content = sectionContent;\n    }\n\n    // Output the documentation with Markdown colorization\n    console.log(renderMarkdown(content, this.ctx.color));\n  }\n\n  /**\n   * Extract section metadata from the documentation.\n   * Sections are top-level headers (## ).\n   * Returns title and slugified ID for each section.\n   */\n  private extractSections(content: string): DocSection[] {\n    const sections: DocSection[] = [];\n    const lines = content.split('\\n');\n    const slugger = new GithubSlugger();\n\n    for (const line of lines) {\n      if (line.startsWith('## ')) {\n        const title = line.slice(3).trim();\n        const slug = slugger.slug(title);\n        sections.push({ title, slug });\n      }\n    }\n\n    return sections;\n  }\n\n  /**\n   * Extract a specific section from the documentation.\n   * Matches by slug or partial title match.\n   * Returns content from the section header to the next section header.\n   */\n  private extractSection(content: string, sections: DocSection[], query: string): string | null {\n    const lowerQuery = query.toLowerCase();\n\n    // Find matching section - first try exact slug match, then partial title match\n    const matchedSection =\n      sections.find((s) => s.slug === lowerQuery) ??\n      sections.find((s) => s.title.toLowerCase().includes(lowerQuery));\n\n    if (!matchedSection) {\n      return null;\n    }\n\n    const lines = content.split('\\n');\n    let inSection = false;\n    const sectionLines: string[] = [];\n\n    for (const line of lines) {\n      if (line.startsWith('## ')) {\n        if (inSection) {\n          // End of our section\n          break;\n        }\n        const currentTitle = line.slice(3).trim();\n        if (currentTitle === matchedSection.title) {\n          inSection = true;\n          sectionLines.push(line);\n        }\n      } else if (inSection) {\n        sectionLines.push(line);\n      }\n    }\n\n    if (sectionLines.length === 0) {\n      return null;\n    }\n\n    // Trim trailing empty lines\n    while (sectionLines.length > 0) {\n      const lastLine = sectionLines[sectionLines.length - 1];\n      if (lastLine?.trim() === '') {\n        sectionLines.pop();\n      } else {\n        break;\n      }\n    }\n\n    return sectionLines.join('\\n');\n  }\n\n  /**\n   * Handle --refresh: Sync docs from config.\n   * Merges user's config with defaults to ensure new bundled docs are included.\n   */\n  private async handleRefresh(): Promise<void> {\n    const cwd = process.cwd();\n    const tbdRoot = await findTbdRoot(cwd);\n\n    if (!tbdRoot) {\n      throw new NotInitializedError(cwd);\n    }\n\n    const config = await readConfig(tbdRoot);\n    const colors = this.output.getColors();\n\n    // Merge user's config with defaults (ensures new bundled docs are added)\n    const defaults = await generateDefaultDocCacheConfig();\n    const filesConfig = mergeDocCacheConfig(config.docs_cache?.files, defaults);\n\n    const sync = new DocSync(tbdRoot, filesConfig);\n    const result = await sync.sync();\n\n    // Update last sync time\n    await updateLocalState(tbdRoot, {\n      last_doc_sync_at: new Date().toISOString(),\n    });\n\n    // Report results\n    this.output.data(result, () => {\n      if (result.added.length > 0) {\n        console.log(colors.success(`Added ${result.added.length} doc(s)`));\n        for (const path of result.added) {\n          console.log(`  + ${path}`);\n        }\n      }\n\n      if (result.updated.length > 0) {\n        console.log(colors.success(`Updated ${result.updated.length} doc(s)`));\n        for (const path of result.updated) {\n          console.log(`  ~ ${path}`);\n        }\n      }\n\n      if (result.removed.length > 0) {\n        console.log(colors.warn(`Removed ${result.removed.length} doc(s)`));\n        for (const path of result.removed) {\n          console.log(`  - ${path}`);\n        }\n      }\n\n      if (result.errors.length > 0) {\n        console.log(colors.error(`Errors: ${result.errors.length}`));\n        for (const { path, error } of result.errors) {\n          console.log(`  ! ${path}: ${error}`);\n        }\n      }\n\n      if (\n        result.added.length === 0 &&\n        result.updated.length === 0 &&\n        result.removed.length === 0 &&\n        result.errors.length === 0\n      ) {\n        console.log(colors.dim('Docs are up to date.'));\n      }\n    });\n  }\n\n  /**\n   * Handle --status: Show what would change without actually changing files.\n   * Merges user's config with defaults to ensure new bundled docs are included.\n   */\n  private async handleStatus(): Promise<void> {\n    const cwd = process.cwd();\n    const tbdRoot = await findTbdRoot(cwd);\n\n    if (!tbdRoot) {\n      throw new NotInitializedError(cwd);\n    }\n\n    const config = await readConfig(tbdRoot);\n    const colors = this.output.getColors();\n\n    // Merge user's config with defaults (ensures new bundled docs are added)\n    const defaults = await generateDefaultDocCacheConfig();\n    const filesConfig = mergeDocCacheConfig(config.docs_cache?.files, defaults);\n\n    const sync = new DocSync(tbdRoot, filesConfig);\n    const result = await sync.status();\n\n    // Report results\n    this.output.data(result, () => {\n      const total = result.added.length + result.updated.length + result.removed.length;\n\n      if (total === 0 && result.errors.length === 0) {\n        console.log(colors.success('Docs are up to date. No changes needed.'));\n        return;\n      }\n\n      console.log(colors.bold('Doc sync status (dry run):'));\n\n      if (result.added.length > 0) {\n        console.log(`  Would add ${result.added.length} doc(s):`);\n        for (const path of result.added) {\n          console.log(`    + ${path}`);\n        }\n      }\n\n      if (result.updated.length > 0) {\n        console.log(`  Would update ${result.updated.length} doc(s):`);\n        for (const path of result.updated) {\n          console.log(`    ~ ${path}`);\n        }\n      }\n\n      if (result.removed.length > 0) {\n        console.log(`  Would remove ${result.removed.length} doc(s):`);\n        for (const path of result.removed) {\n          console.log(`    - ${path}`);\n        }\n      }\n\n      if (result.errors.length > 0) {\n        console.log(colors.error(`  Errors: ${result.errors.length}`));\n        for (const { path, error } of result.errors) {\n          console.log(`    ! ${path}: ${error}`);\n        }\n      }\n\n      console.log('');\n      console.log(colors.dim('Run tbd docs --refresh to apply these changes.'));\n    });\n  }\n\n  /**\n   * Show a comprehensive listing of all documentation resources organized by purpose.\n   */\n  private async showComprehensiveListing(): Promise<void> {\n    const colors = this.output.getColors();\n\n    console.log(colors.bold('=== tbd Documentation Resources ==='));\n    console.log('');\n\n    // Getting Started\n    console.log(colors.bold('Getting Started:'));\n    console.log('  tbd                          Full orientation and project status');\n    console.log('  tbd prime                    Workflow context and guidance');\n    console.log('  tbd prime --brief            Quick reference (~35 lines)');\n    console.log('  tbd --help                   CLI command reference');\n    console.log('');\n\n    // Workflows (Shortcuts)\n    console.log(colors.bold('Workflows (Shortcuts):'));\n    console.log('  tbd shortcut --list          List all available shortcuts');\n    console.log('  tbd shortcut new-plan-spec   Plan a new feature');\n    console.log('  tbd shortcut commit-code     Commit code properly');\n    console.log('  tbd shortcut create-or-update-pr-simple  Create a pull request');\n    console.log('');\n\n    // Guidelines\n    console.log(colors.bold('Guidelines (Coding Standards):'));\n    console.log('  tbd guidelines --list        List all available guidelines');\n    console.log('  tbd guidelines typescript-rules      TypeScript best practices');\n    console.log('  tbd guidelines general-tdd-guidelines  Test-driven development');\n    console.log('  tbd guidelines golden-testing-guidelines  Snapshot/golden testing');\n    console.log('');\n\n    // Templates\n    console.log(colors.bold('Templates:'));\n    console.log('  tbd template --list          List all available templates');\n    console.log('  tbd template plan-spec       Feature planning template');\n    console.log('  tbd template architecture-doc    Architecture document template');\n    console.log('');\n\n    // Design & Reference\n    console.log(colors.bold('Design & Reference:'));\n    console.log('  tbd docs --list              List documentation sections');\n    console.log('  tbd design                   tbd design document');\n    console.log('  tbd closing                  Session closing protocol');\n    console.log('');\n\n    // Quick Tips\n    console.log(colors.bold('Quick Tips:'));\n    console.log('  - Run tbd ready to see what issues are available to work on');\n    console.log('  - Run tbd shortcut <name> to get step-by-step instructions');\n    console.log('  - Run tbd guidelines <name> to get coding standards');\n    console.log('  - Always run tbd sync at the end of a session');\n  }\n}\n\nexport const docsCommand = new Command('docs')\n  .description('Display CLI documentation and manage doc cache')\n  .argument('[topic]', 'Topic to display (e.g., \"commands\", \"id-system\")')\n  .option('--section <name>', 'Show specific section (e.g., \"commands\", \"workflows\")')\n  .option('--list', 'List available sections')\n  .option('--all', 'Show comprehensive listing of all documentation resources')\n  .option('--refresh', 'Sync docs from config to .tbd/docs/')\n  .option('--status', 'Show what would change without actually syncing')\n  .action(async (topic: string | undefined, options: DocsOptions, command: Command) => {\n    const handler = new DocsHandler(command);\n    await handler.run(topic, options);\n  });\n","/**\n * `tbd closing` - Display the session closing protocol reminder.\n *\n * Shows the close protocol checklist for completing work.\n * Used by the Claude Code PostToolUse hook after git push.\n */\n\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { CLIError } from '../lib/errors.js';\nimport { renderMarkdown } from '../lib/output.js';\n\n/**\n * Get the path to the bundled closing file.\n * The file is copied to dist/docs/ during build.\n */\nfunction getCloseProtocolPath(): string {\n  const __filename = fileURLToPath(import.meta.url);\n  const __dirname = dirname(__filename);\n  return join(__dirname, 'docs', 'tbd-closing.md');\n}\n\nclass CloseProtocolHandler extends BaseCommand {\n  async run(): Promise<void> {\n    let content: string;\n    try {\n      content = await readFile(getCloseProtocolPath(), 'utf-8');\n    } catch {\n      // Fallback: try to read from source location during development\n      try {\n        const __filename = fileURLToPath(import.meta.url);\n        const __dirname = dirname(__filename);\n        const devPath = join(__dirname, '..', '..', 'docs', 'tbd-closing.md');\n        content = await readFile(devPath, 'utf-8');\n      } catch {\n        // Last fallback: repo-level docs\n        try {\n          const __filename = fileURLToPath(import.meta.url);\n          const __dirname = dirname(__filename);\n          const repoPath = join(__dirname, '..', '..', '..', 'docs', 'tbd-closing.md');\n          content = await readFile(repoPath, 'utf-8');\n        } catch {\n          throw new CLIError('Close protocol file not found. Please rebuild the CLI.');\n        }\n      }\n    }\n\n    console.log(renderMarkdown(content, this.ctx.color));\n  }\n}\n\nexport const closeProtocolCommand = new Command('closing')\n  .description('Display the session closing protocol reminder')\n  .action(async (_options: unknown, command: Command) => {\n    const handler = new CloseProtocolHandler(command);\n    await handler.run();\n  });\n","/**\n * `tbd design` - Display design documentation.\n *\n * Shows the bundled design documentation for tbd,\n * including architecture, design decisions, and Beads comparison.\n */\n\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { CLIError, NotFoundError } from '../lib/errors.js';\nimport { renderMarkdown } from '../lib/output.js';\nimport type { DocSection } from '../../lib/types.js';\nimport GithubSlugger from 'github-slugger';\n\n/**\n * Get the path to the bundled design doc file.\n * The design doc is copied to dist/docs/ during build.\n */\nfunction getDesignPath(): string {\n  const __filename = fileURLToPath(import.meta.url);\n  const __dirname = dirname(__filename);\n  // When bundled, runs from dist/bin.mjs or dist/cli.mjs\n  // Docs are at dist/docs/tbd-design.md (same level as the bundle)\n  return join(__dirname, 'docs', 'tbd-design.md');\n}\n\ninterface DesignOptions {\n  section?: string;\n  list?: boolean;\n}\n\nclass DesignHandler extends BaseCommand {\n  async run(topic: string | undefined, options: DesignOptions): Promise<void> {\n    let content: string;\n    try {\n      content = await readFile(getDesignPath(), 'utf-8');\n    } catch {\n      // Fallback: try to read from source location during development\n      try {\n        const __filename = fileURLToPath(import.meta.url);\n        const __dirname = dirname(__filename);\n        // During development: src/cli/commands -> packages/tbd/docs\n        const devPath = join(__dirname, '..', '..', '..', 'docs', 'tbd-design.md');\n        content = await readFile(devPath, 'utf-8');\n      } catch {\n        throw new CLIError('Design documentation file not found. Please rebuild the CLI.');\n      }\n    }\n\n    const sections = this.extractSections(content);\n\n    // List available sections\n    if (options.list) {\n      this.output.data(sections, () => {\n        const colors = this.output.getColors();\n        console.log(colors.bold('Available design documentation sections:'));\n        console.log('');\n        // Calculate max slug length for alignment\n        const maxSlugLen = Math.max(...sections.map((s) => s.slug.length));\n        for (const section of sections) {\n          const paddedSlug = section.slug.padEnd(maxSlugLen);\n          console.log(`  ${colors.id(paddedSlug)}  ${section.title}`);\n        }\n        console.log('');\n        console.log(`Use ${colors.dim('tbd design <topic>')} to view a specific section.`);\n      });\n      return;\n    }\n\n    // Determine which section to show (positional topic takes precedence)\n    const sectionQuery = topic ?? options.section;\n\n    // Filter by section if specified\n    if (sectionQuery) {\n      const sectionContent = this.extractSection(content, sections, sectionQuery);\n      if (!sectionContent) {\n        throw new NotFoundError(\n          'Section',\n          `\"${sectionQuery}\" (use --list to see available sections)`,\n        );\n      }\n      content = sectionContent;\n    }\n\n    // Output the documentation with Markdown colorization\n    console.log(renderMarkdown(content, this.ctx.color));\n  }\n\n  /**\n   * Extract section metadata from the documentation.\n   * Sections are top-level headers (## ).\n   * Returns title and slugified ID for each section.\n   */\n  private extractSections(content: string): DocSection[] {\n    const sections: DocSection[] = [];\n    const lines = content.split('\\n');\n    const slugger = new GithubSlugger();\n\n    for (const line of lines) {\n      if (line.startsWith('## ')) {\n        const title = line.slice(3).trim();\n        const slug = slugger.slug(title);\n        sections.push({ title, slug });\n      }\n    }\n\n    return sections;\n  }\n\n  /**\n   * Extract a specific section from the documentation.\n   * Matches by slug or partial title match.\n   * Returns content from the section header to the next section header.\n   */\n  private extractSection(content: string, sections: DocSection[], query: string): string | null {\n    const lowerQuery = query.toLowerCase();\n\n    // Find matching section - first try exact slug match, then partial title match\n    const matchedSection =\n      sections.find((s) => s.slug === lowerQuery) ??\n      sections.find((s) => s.title.toLowerCase().includes(lowerQuery));\n\n    if (!matchedSection) {\n      return null;\n    }\n\n    const lines = content.split('\\n');\n    let inSection = false;\n    const sectionLines: string[] = [];\n\n    for (const line of lines) {\n      if (line.startsWith('## ')) {\n        if (inSection) {\n          // End of our section\n          break;\n        }\n        const currentTitle = line.slice(3).trim();\n        if (currentTitle === matchedSection.title) {\n          inSection = true;\n          sectionLines.push(line);\n        }\n      } else if (inSection) {\n        sectionLines.push(line);\n      }\n    }\n\n    if (sectionLines.length === 0) {\n      return null;\n    }\n\n    // Trim trailing empty lines\n    while (sectionLines.length > 0) {\n      const lastLine = sectionLines[sectionLines.length - 1];\n      if (lastLine?.trim() === '') {\n        sectionLines.pop();\n      } else {\n        break;\n      }\n    }\n\n    return sectionLines.join('\\n');\n  }\n}\n\nexport const designCommand = new Command('design')\n  .description('Display design documentation and Beads comparison')\n  .argument('[topic]', 'Topic to display (e.g., \"architecture\", \"tbd-vs-beads\")')\n  .option('--section <name>', 'Show specific section')\n  .option('--list', 'List available sections')\n  .action(async (topic: string | undefined, options: DesignOptions, command: Command) => {\n    const handler = new DesignHandler(command);\n    await handler.run(topic, options);\n  });\n","/**\n * `tbd readme` - Display the README.\n *\n * Shows the bundled README (same as the GitHub landing page).\n */\n\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\nimport { dirname, join } from 'node:path';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { CLIError } from '../lib/errors.js';\nimport { renderMarkdown } from '../lib/output.js';\n\n/**\n * Get the path to the bundled README file.\n * The README is copied to dist/docs/ during build.\n */\nfunction getReadmePath(): string {\n  const __filename = fileURLToPath(import.meta.url);\n  const __dirname = dirname(__filename);\n  // When bundled, runs from dist/bin.mjs or dist/cli.mjs\n  // README is at dist/docs/README.md (same level as the bundle)\n  return join(__dirname, 'docs', 'README.md');\n}\n\nclass ReadmeHandler extends BaseCommand {\n  async run(): Promise<void> {\n    let content: string;\n    try {\n      content = await readFile(getReadmePath(), 'utf-8');\n    } catch {\n      // Fallback: try to read from source location during development\n      try {\n        const __filename = fileURLToPath(import.meta.url);\n        const __dirname = dirname(__filename);\n        // During development without bundle: src/cli/commands -> repo root\n        const devPath = join(__dirname, '..', '..', '..', '..', '..', 'README.md');\n        content = await readFile(devPath, 'utf-8');\n      } catch {\n        // Last fallback: try package-level README\n        try {\n          const __filename = fileURLToPath(import.meta.url);\n          const __dirname = dirname(__filename);\n          // From packages/tbd/src/cli/commands -> packages/tbd/README.md\n          const pkgPath = join(__dirname, '..', '..', '..', 'README.md');\n          content = await readFile(pkgPath, 'utf-8');\n        } catch {\n          throw new CLIError('README file not found. Please rebuild the CLI.');\n        }\n      }\n    }\n\n    // Output the README with Markdown colorization\n    console.log(renderMarkdown(content, this.ctx.color));\n  }\n}\n\nexport const readmeCommand = new Command('readme')\n  .description('Display the README (same as GitHub landing page)')\n  .action(async (_options: object, command: Command) => {\n    const handler = new ReadmeHandler(command);\n    await handler.run();\n  });\n","/**\n * `tbd uninstall` - Remove tbd from a repository.\n *\n * Removes the .tbd directory, worktree, and optionally the sync branch.\n */\n\nimport { Command } from 'commander';\nimport { rm, access, readdir, stat } from 'node:fs/promises';\nimport { execSync } from 'node:child_process';\nimport { join } from 'node:path';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { NotInitializedError, CLIError } from '../lib/errors.js';\nimport { readConfig } from '../../file/config.js';\nimport { SYNC_BRANCH } from '../../lib/paths.js';\n\ninterface UninstallOptions {\n  confirm?: boolean;\n  keepBranch?: boolean;\n  removeRemote?: boolean;\n}\n\nclass UninstallHandler extends BaseCommand {\n  async run(options: UninstallOptions): Promise<void> {\n    const colors = this.output.getColors();\n\n    // Check if tbd is initialized\n    try {\n      await access('.tbd');\n    } catch {\n      throw new NotInitializedError('No .tbd directory found. Nothing to uninstall.');\n    }\n\n    // Read config to get branch info\n    let config;\n    try {\n      config = await readConfig('.');\n    } catch {\n      config = null;\n    }\n\n    const syncBranch = config?.sync.branch ?? SYNC_BRANCH;\n    const remote = config?.sync.remote ?? 'origin';\n    const worktreePath = join('.tbd', 'data-sync-worktree');\n\n    // Check what exists\n    const items: string[] = [];\n\n    // Check worktree\n    let worktreeExists = false;\n    try {\n      await access(worktreePath);\n      worktreeExists = true;\n      const worktreeStats = await this.getDirectoryStats(worktreePath);\n      items.push(`  - Worktree: ${worktreePath} (${worktreeStats.files} files)`);\n    } catch {\n      // Worktree doesn't exist\n    }\n\n    // Check local sync branch\n    let localBranchExists = false;\n    try {\n      execSync(`git rev-parse --verify ${syncBranch}`, {\n        encoding: 'utf-8',\n        stdio: ['ignore', 'pipe', 'ignore'],\n      });\n      localBranchExists = true;\n      if (!options.keepBranch) {\n        items.push(`  - Local branch: ${syncBranch}`);\n      }\n    } catch {\n      // Branch doesn't exist\n    }\n\n    // Check remote sync branch\n    let remoteBranchExists = false;\n    if (options.removeRemote) {\n      try {\n        execSync(`git rev-parse --verify ${remote}/${syncBranch}`, {\n          encoding: 'utf-8',\n          stdio: ['ignore', 'pipe', 'ignore'],\n        });\n        remoteBranchExists = true;\n        items.push(`  - Remote branch: ${remote}/${syncBranch}`);\n      } catch {\n        // Remote branch doesn't exist\n      }\n    }\n\n    // Count .tbd contents\n    const tbdStats = await this.getDirectoryStats('.tbd');\n    items.push(`  - Directory: .tbd/ (${tbdStats.files} files)`);\n\n    // Show what will be removed\n    console.log(colors.bold('The following will be removed:'));\n    console.log('');\n    for (const item of items) {\n      console.log(colors.warn(item));\n    }\n    console.log('');\n\n    if (!options.confirm) {\n      console.log(`This action is ${colors.bold('irreversible')}.`);\n      console.log('');\n      console.log(`To confirm, run: ${colors.dim('tbd uninstall --confirm')}`);\n      if (!options.keepBranch && localBranchExists) {\n        console.log(\n          `To keep the sync branch: ${colors.dim('tbd uninstall --confirm --keep-branch')}`,\n        );\n      }\n      if (!options.removeRemote) {\n        console.log(\n          `To also remove from remote: ${colors.dim('tbd uninstall --confirm --remove-remote')}`,\n        );\n      }\n      return;\n    }\n\n    // Check dry-run\n    if (this.checkDryRun('Would remove tbd from repository', { items })) {\n      return;\n    }\n\n    // Perform uninstall\n    this.output.info('Uninstalling tbd...');\n\n    // 1. Remove worktree first (git worktree remove)\n    if (worktreeExists) {\n      try {\n        // First try to remove the worktree through git\n        execSync(`git worktree remove --force \"${worktreePath}\"`, {\n          encoding: 'utf-8',\n          stdio: ['ignore', 'pipe', 'ignore'],\n        });\n        console.log(`  ${colors.success('✓')} Removed git worktree`);\n      } catch {\n        // If git worktree remove fails, force delete the directory\n        try {\n          await rm(worktreePath, { recursive: true, force: true });\n          console.log(`  ${colors.success('✓')} Removed worktree directory`);\n        } catch {\n          console.log(`  ${colors.warn('⚠')} Could not remove worktree directory`);\n        }\n      }\n    }\n\n    // 2. Remove local sync branch\n    if (localBranchExists && !options.keepBranch) {\n      try {\n        execSync(`git branch -D ${syncBranch}`, {\n          encoding: 'utf-8',\n          stdio: ['ignore', 'pipe', 'ignore'],\n        });\n        console.log(`  ${colors.success('✓')} Removed local branch: ${syncBranch}`);\n      } catch {\n        console.log(`  ${colors.warn('⚠')} Could not remove local branch: ${syncBranch}`);\n      }\n    }\n\n    // 3. Remove remote sync branch\n    if (remoteBranchExists && options.removeRemote) {\n      try {\n        execSync(`git push ${remote} --delete ${syncBranch}`, {\n          encoding: 'utf-8',\n          stdio: ['ignore', 'pipe', 'ignore'],\n        });\n        console.log(`  ${colors.success('✓')} Removed remote branch: ${remote}/${syncBranch}`);\n      } catch {\n        console.log(\n          `  ${colors.warn('⚠')} Could not remove remote branch: ${remote}/${syncBranch}`,\n        );\n      }\n    }\n\n    // 4. Clean up orphaned worktree references\n    try {\n      execSync('git worktree prune', {\n        encoding: 'utf-8',\n        stdio: ['ignore', 'pipe', 'ignore'],\n      });\n    } catch {\n      // Ignore errors\n    }\n\n    // 5. Remove .tbd directory\n    try {\n      await rm('.tbd', { recursive: true, force: true });\n      console.log(`  ${colors.success('✓')} Removed .tbd directory`);\n    } catch {\n      throw new CLIError('Failed to remove .tbd directory');\n    }\n\n    console.log('');\n    this.output.success('tbd has been uninstalled from this repository.');\n\n    if (options.keepBranch && localBranchExists) {\n      console.log('');\n      console.log(colors.dim(`Note: The ${syncBranch} branch was preserved. Delete it with:`));\n      console.log(colors.dim(`  git branch -D ${syncBranch}`));\n    }\n\n    if (!options.removeRemote && remoteBranchExists) {\n      console.log('');\n      console.log(\n        colors.dim(\n          `Note: The remote ${remote}/${syncBranch} branch was preserved. Delete it with:`,\n        ),\n      );\n      console.log(colors.dim(`  git push ${remote} --delete ${syncBranch}`));\n    }\n  }\n\n  /**\n   * Get stats about a directory (file count, size).\n   */\n  private async getDirectoryStats(dirPath: string): Promise<{ files: number; size: number }> {\n    let files = 0;\n    let size = 0;\n\n    const walk = async (dir: string): Promise<void> => {\n      try {\n        const entries = await readdir(dir, { withFileTypes: true });\n        for (const entry of entries) {\n          const fullPath = join(dir, entry.name);\n          if (entry.isDirectory()) {\n            await walk(fullPath);\n          } else {\n            files++;\n            try {\n              const stats = await stat(fullPath);\n              size += stats.size;\n            } catch {\n              // Ignore stat errors\n            }\n          }\n        }\n      } catch {\n        // Ignore errors\n      }\n    };\n\n    await walk(dirPath);\n    return { files, size };\n  }\n}\n\nexport const uninstallCommand = new Command('uninstall')\n  .description('Remove tbd from this repository')\n  .option('--confirm', 'Confirm removal (required to proceed)')\n  .option('--keep-branch', 'Keep the local sync branch')\n  .option('--remove-remote', 'Also remove the remote sync branch')\n  .action(async (options, command) => {\n    const handler = new UninstallHandler(command);\n    await handler.run(options);\n  });\n","/**\n * Markdown utilities for processing markdown content.\n *\n * Uses gray-matter for consistent frontmatter parsing across the codebase.\n */\n\nimport matter from 'gray-matter';\n\nexport interface ParsedMarkdown {\n  /** Raw frontmatter string (without --- delimiters), or null if no frontmatter */\n  frontmatter: string | null;\n  /** Body content after frontmatter, with leading newlines trimmed */\n  body: string;\n}\n\n/**\n * Normalize line endings to LF.\n */\nfunction normalizeLineEndings(content: string): string {\n  return content.replace(/\\r\\n/g, '\\n').replace(/\\r/g, '\\n');\n}\n\n/**\n * Parse markdown content into frontmatter and body.\n * Handles both LF and CRLF line endings.\n *\n * @returns Object with frontmatter (null if none) and body\n */\nexport function parseMarkdown(content: string): ParsedMarkdown {\n  const normalized = normalizeLineEndings(content);\n\n  if (!matter.test(normalized)) {\n    return { frontmatter: null, body: content };\n  }\n\n  try {\n    const parsed = matter(normalized);\n\n    // Extract frontmatter from parsed.data by stringifying back to YAML\n    // The matter property is unreliable, so we reconstruct from data\n    const data = parsed.data;\n    let frontmatter: string | null = null;\n\n    if (data && Object.keys(data).length > 0) {\n      // Reconstruct frontmatter as YAML lines\n      const lines: string[] = [];\n      for (const [key, value] of Object.entries(data)) {\n        if (Array.isArray(value)) {\n          lines.push(`${key}:`);\n          for (const item of value) {\n            lines.push(`  - ${String(item)}`);\n          }\n        } else if (typeof value === 'object' && value !== null) {\n          lines.push(`${key}:`);\n          for (const [subKey, subValue] of Object.entries(value as Record<string, unknown>)) {\n            lines.push(`  ${subKey}: ${String(subValue)}`);\n          }\n        } else {\n          lines.push(`${key}: ${String(value)}`);\n        }\n      }\n      frontmatter = lines.join('\\n');\n    } else {\n      // Empty frontmatter (just --- followed by ---)\n      frontmatter = '';\n    }\n\n    // Body with leading newlines trimmed\n    const body = parsed.content.replace(/^\\n+/, '');\n\n    return { frontmatter, body };\n  } catch {\n    // Invalid/unclosed frontmatter - treat as no frontmatter\n    return { frontmatter: null, body: content };\n  }\n}\n\n/**\n * Parse YAML frontmatter from markdown content.\n * Returns the frontmatter content (without delimiters) or null if no valid frontmatter.\n * Handles both LF and CRLF line endings.\n */\nexport function parseFrontmatter(content: string): string | null {\n  return parseMarkdown(content).frontmatter;\n}\n\n/**\n * Strip YAML frontmatter from markdown content.\n * Returns the body content without frontmatter, with leading newlines trimmed.\n * Handles both LF and CRLF line endings.\n */\nexport function stripFrontmatter(content: string): string {\n  return parseMarkdown(content).body;\n}\n\n/**\n * Insert content after YAML frontmatter.\n * If no frontmatter exists, prepends the content.\n * Content is inserted directly after ---. Include leading newlines in toInsert if needed.\n */\nexport function insertAfterFrontmatter(content: string, toInsert: string): string {\n  const { frontmatter, body } = parseMarkdown(content);\n\n  if (frontmatter === null) {\n    return toInsert + content;\n  }\n\n  const frontmatterBlock = frontmatter ? `---\\n${frontmatter}\\n---` : '---\\n---';\n  return `${frontmatterBlock}\\n${toInsert}\\n\\n${body}`;\n}\n","/**\n * DocCache - Path-ordered markdown document cache with lookup.\n *\n * Provides document lookups for the `tbd shortcut` command, supporting\n * both exact matching by filename and fuzzy matching against metadata.\n *\n * Also provides auto-sync functionality when docs are stale (per spec).\n *\n * See: docs/project/specs/active/plan-2026-01-22-doc-cache-abstraction.md\n * See: docs/project/specs/active/plan-2026-01-26-configurable-doc-cache-sync.md\n */\n\nimport { readdir, readFile } from 'node:fs/promises';\nimport { join, basename } from 'node:path';\nimport matter from 'gray-matter';\n\nimport { readConfig, readLocalState, updateLocalState, findTbdRoot } from './config.js';\nimport { DocSync, generateDefaultDocCacheConfig, isDocsStale } from './doc-sync.js';\n\n// =============================================================================\n// Scoring Constants\n// =============================================================================\n\n/** Score for exact filename match (with or without .md extension) */\nexport const SCORE_EXACT_MATCH = 1.0;\n\n/** Score when query is a prefix of the filename */\nexport const SCORE_PREFIX_MATCH = 0.9;\n\n/** Score when filename contains all query words */\nexport const SCORE_CONTAINS_ALL = 0.8;\n\n/** Base score for partial word matches (multiplied by matched/total ratio) */\nexport const SCORE_PARTIAL_BASE = 0.7;\n\n/** Minimum score threshold to return a fuzzy match result */\nexport const SCORE_MIN_THRESHOLD = 0.5;\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/**\n * Frontmatter fields used for shortcut documents.\n * These are the expected fields in YAML frontmatter for searchability.\n */\nexport interface DocFrontmatter {\n  /** Display title for the shortcut */\n  title?: string;\n  /** Brief description for fuzzy matching and listing */\n  description?: string;\n  /** Optional categorization tags */\n  tags?: string[];\n}\n\n/**\n * A cached document loaded from the doc path.\n */\nexport interface CachedDoc {\n  /** Full filesystem path to the document */\n  path: string;\n  /** Filename without extension (used for lookups) */\n  name: string;\n  /** Parsed YAML frontmatter, if present */\n  frontmatter?: DocFrontmatter;\n  /** Full file content (including frontmatter for output) */\n  content: string;\n  /** Which directory in the path this doc came from */\n  sourceDir: string;\n}\n\n/**\n * A document match with relevance score.\n */\nexport interface DocMatch {\n  /** The matched document */\n  doc: CachedDoc;\n  /** Match score: 1.0 = exact, lower = fuzzier */\n  score: number;\n}\n\n// =============================================================================\n// DocCache Class\n// =============================================================================\n\n/**\n * Options for loading the doc cache.\n */\nexport interface DocCacheLoadOptions {\n  /** If true, suppress auto-sync output (default: false) */\n  quiet?: boolean;\n}\n\n/**\n * Path-ordered markdown document cache.\n *\n * Loads all .md files from configured paths in order, with earlier paths\n * taking precedence (like shell $PATH). Supports exact lookup by filename\n * and fuzzy search across filename + frontmatter metadata.\n */\nexport class DocCache {\n  /** Active docs (first occurrence of each name) */\n  private docs: CachedDoc[] = [];\n\n  /** All docs including shadowed ones */\n  private allDocs: CachedDoc[] = [];\n\n  /** Track names we've seen for shadow detection */\n  private seenNames = new Set<string>();\n\n  /** Whether the cache has been loaded */\n  private loaded = false;\n\n  /**\n   * Create a new DocCache.\n   *\n   * @param paths - Ordered array of directory paths to search (relative to baseDir)\n   * @param baseDir - Base directory for resolving relative paths (default: cwd)\n   */\n  constructor(\n    private readonly paths: string[],\n    private readonly baseDir: string = process.cwd(),\n  ) {}\n\n  /**\n   * Load all documents from configured paths.\n   *\n   * Reads all .md files from each path in order. Documents with the same\n   * name in later paths are shadowed (tracked but not returned by default).\n   *\n   * If auto-sync is enabled and docs are stale, triggers a sync first.\n   *\n   * @param options - Load options (quiet: suppress auto-sync output)\n   */\n  async load(options?: DocCacheLoadOptions): Promise<void> {\n    if (this.loaded) return;\n\n    // Check for auto-sync before loading\n    await this.checkAutoSync(options?.quiet ?? false);\n\n    for (const relativePath of this.paths) {\n      const dirPath = join(this.baseDir, relativePath);\n      await this.loadDirectory(dirPath, relativePath);\n    }\n\n    this.loaded = true;\n  }\n\n  /**\n   * Check if docs are stale and auto-sync if needed.\n   * Respects the quiet option - only silent when explicitly requested.\n   *\n   * @param quiet - If true, suppress sync output\n   */\n  private async checkAutoSync(quiet: boolean): Promise<void> {\n    try {\n      // Find tbd root\n      const tbdRoot = await findTbdRoot(this.baseDir);\n      if (!tbdRoot) return;\n\n      // Read config and state\n      const config = await readConfig(tbdRoot);\n      const state = await readLocalState(tbdRoot);\n\n      // Check if auto-sync is enabled and docs are stale\n      const autoSyncHours = config.settings?.doc_auto_sync_hours ?? 24;\n      if (!isDocsStale(state.last_doc_sync_at, autoSyncHours)) {\n        return;\n      }\n\n      // Get doc cache files config\n      let filesConfig = config.docs_cache?.files;\n      if (!filesConfig || Object.keys(filesConfig).length === 0) {\n        filesConfig = await generateDefaultDocCacheConfig();\n      }\n\n      // Sync docs, respecting quiet option\n      const sync = new DocSync(tbdRoot, filesConfig);\n      await sync.sync({ silent: quiet });\n\n      // Update last sync time\n      await updateLocalState(tbdRoot, {\n        last_doc_sync_at: new Date().toISOString(),\n      });\n    } catch {\n      // Auto-sync errors are silent - don't interrupt the user\n    }\n  }\n\n  /**\n   * Load documents from a single directory.\n   */\n  private async loadDirectory(dirPath: string, sourceDir: string): Promise<void> {\n    let entries: string[];\n\n    try {\n      entries = await readdir(dirPath);\n    } catch {\n      // Directory doesn't exist or isn't readable - skip silently\n      // This is expected when paths haven't been initialized yet\n      return;\n    }\n\n    for (const entry of entries) {\n      if (!entry.endsWith('.md')) continue;\n\n      const filePath = join(dirPath, entry);\n      const name = basename(entry, '.md');\n\n      try {\n        const content = await readFile(filePath, 'utf-8');\n        const frontmatter = this.parseFrontmatterData(content);\n\n        const doc: CachedDoc = {\n          path: filePath,\n          name,\n          frontmatter,\n          content,\n          sourceDir,\n        };\n\n        // Track all docs\n        this.allDocs.push(doc);\n\n        // Only add to active docs if not shadowed\n        if (!this.seenNames.has(name)) {\n          this.docs.push(doc);\n          this.seenNames.add(name);\n        }\n      } catch (error) {\n        // Failed to read or parse file - skip with warning context\n        console.warn(`Failed to load shortcut ${filePath}: ${(error as Error).message}`);\n      }\n    }\n  }\n\n  /**\n   * Parse YAML frontmatter from content and return typed data.\n   * Uses gray-matter for consistent frontmatter parsing.\n   */\n  private parseFrontmatterData(content: string): DocFrontmatter | undefined {\n    if (!matter.test(content)) {\n      return undefined;\n    }\n\n    try {\n      const parsed = matter(content).data as Record<string, unknown>;\n      return {\n        title: typeof parsed.title === 'string' ? parsed.title : undefined,\n        description: typeof parsed.description === 'string' ? parsed.description : undefined,\n        tags: Array.isArray(parsed.tags)\n          ? parsed.tags.filter((t) => typeof t === 'string')\n          : undefined,\n      };\n    } catch {\n      // Invalid YAML in frontmatter - return undefined\n      return undefined;\n    }\n  }\n\n  /**\n   * Get a document by exact name match.\n   *\n   * @param name - Filename to match (with or without .md extension)\n   * @returns Match with score SCORE_EXACT_MATCH, or null if not found\n   */\n  get(name: string): DocMatch | null {\n    // Strip .md extension if present\n    const lookupName = name.endsWith('.md') ? name.slice(0, -3) : name;\n\n    const doc = this.docs.find((d) => d.name === lookupName);\n    if (!doc) return null;\n\n    return { doc, score: SCORE_EXACT_MATCH };\n  }\n\n  /**\n   * Search for documents matching a query.\n   *\n   * Performs fuzzy matching against filename, title, and description.\n   * Returns matches sorted by score descending.\n   *\n   * @param query - Search query string\n   * @param limit - Maximum number of results (default: 10)\n   * @returns Array of matches sorted by score descending\n   */\n  search(query: string, limit = 10): DocMatch[] {\n    const matches: DocMatch[] = [];\n\n    for (const doc of this.docs) {\n      const score = this.calculateScore(doc, query);\n      if (score >= SCORE_MIN_THRESHOLD) {\n        matches.push({ doc, score });\n      }\n    }\n\n    // Sort by score descending, then by name for stability\n    matches.sort((a, b) => {\n      if (b.score !== a.score) return b.score - a.score;\n      return a.doc.name.localeCompare(b.doc.name);\n    });\n\n    return matches.slice(0, limit);\n  }\n\n  /**\n   * Calculate relevance score for a document against a query.\n   */\n  private calculateScore(doc: CachedDoc, query: string): number {\n    const queryLower = query.toLowerCase().trim();\n\n    // Empty query matches nothing\n    if (queryLower.length === 0) {\n      return 0;\n    }\n\n    const nameLower = doc.name.toLowerCase();\n    const titleLower = doc.frontmatter?.title?.toLowerCase() ?? '';\n    const descLower = doc.frontmatter?.description?.toLowerCase() ?? '';\n\n    // Exact match on name\n    if (nameLower === queryLower) {\n      return SCORE_EXACT_MATCH;\n    }\n\n    // Prefix match on name\n    if (nameLower.startsWith(queryLower)) {\n      return SCORE_PREFIX_MATCH;\n    }\n\n    // Split query into words for multi-word matching\n    const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n    const searchableText = `${nameLower} ${titleLower} ${descLower}`;\n\n    // Check if all query words are contained\n    const allWordsMatch = queryWords.every((word) => searchableText.includes(word));\n    if (allWordsMatch && queryWords.length > 0) {\n      return SCORE_CONTAINS_ALL;\n    }\n\n    // Partial match - count how many words match\n    const matchedWords = queryWords.filter((word) => searchableText.includes(word));\n    if (matchedWords.length > 0) {\n      const ratio = matchedWords.length / queryWords.length;\n      return SCORE_PARTIAL_BASE * ratio;\n    }\n\n    return 0;\n  }\n\n  /**\n   * List all documents.\n   *\n   * @param includeAll - If true, include shadowed documents\n   * @returns Array of cached documents\n   */\n  list(includeAll = false): CachedDoc[] {\n    return includeAll ? this.allDocs : this.docs;\n  }\n\n  /**\n   * Check if a document is shadowed by an earlier path.\n   *\n   * @param doc - Document to check\n   * @returns True if this doc is shadowed (not the first with this name)\n   */\n  isShadowed(doc: CachedDoc): boolean {\n    const firstDoc = this.docs.find((d) => d.name === doc.name);\n    return firstDoc !== doc;\n  }\n\n  /**\n   * Check if the cache has been loaded.\n   */\n  isLoaded(): boolean {\n    return this.loaded;\n  }\n}\n\n// =============================================================================\n// Shortcut Directory Generation\n// =============================================================================\n\n/**\n * Marker comments for shortcut directory section in skill files.\n * Used for incremental updates without overwriting user content.\n */\nconst SHORTCUT_DIRECTORY_BEGIN = '<!-- BEGIN SHORTCUT DIRECTORY -->';\nconst SHORTCUT_DIRECTORY_END = '<!-- END SHORTCUT DIRECTORY -->';\n\n/**\n * Generate a formatted markdown shortcut directory from a list of cached documents.\n *\n * The output includes:\n * 1. Marker comments for incremental updates\n * 2. A header explaining how to use shortcuts\n * 3. A markdown table with name, title, and description columns\n *\n * @param docs - Array of CachedDoc objects from DocCache.list()\n * @returns Formatted markdown string with shortcut directory\n *\n * @example\n * const cache = new DocCache(paths);\n * await cache.load();\n * const directory = generateShortcutDirectory(cache.list());\n * // Returns:\n * // <!-- BEGIN SHORTCUT DIRECTORY -->\n * // ## Available Shortcuts\n * // Run `tbd shortcut <name>` to use any of these shortcuts:\n * // | Name | Title | Description |\n * // |------|-------|-------------|\n * // | new-plan-spec | New Plan Spec | Create a new feature planning specification document |\n * // ...\n * // <!-- END SHORTCUT DIRECTORY -->\n */\nexport function generateShortcutDirectory(docs: CachedDoc[]): string {\n  // Sort docs by name for consistent output\n  const sortedDocs = [...docs].sort((a, b) => a.name.localeCompare(b.name));\n\n  // Build table rows\n  const rows: string[] = [];\n  for (const doc of sortedDocs) {\n    // Skip system docs like skill.md and shortcut-explanation.md\n    // These are meta-docs, not shortcuts users would invoke directly\n    if (doc.name === 'skill' || doc.name === 'skill-brief' || doc.name === 'shortcut-explanation') {\n      continue;\n    }\n\n    const name = doc.name;\n    const title = doc.frontmatter?.title ?? '';\n    const description = doc.frontmatter?.description ?? '';\n\n    // Escape pipe characters to avoid breaking the table\n    const escapedTitle = title.replace(/\\|/g, '\\\\|');\n    const escapedDescription = description.replace(/\\|/g, '\\\\|');\n\n    rows.push(`| ${name} | ${escapedTitle} | ${escapedDescription} |`);\n  }\n\n  // If no shortcuts to list, return a minimal directory\n  if (rows.length === 0) {\n    return [\n      SHORTCUT_DIRECTORY_BEGIN,\n      '## Available Shortcuts',\n      '',\n      'No shortcuts available. Create shortcuts in `.tbd/docs/shortcuts/standard/`.',\n      '',\n      SHORTCUT_DIRECTORY_END,\n    ].join('\\n');\n  }\n\n  // Build the full directory\n  return [\n    SHORTCUT_DIRECTORY_BEGIN,\n    '## Available Shortcuts',\n    '',\n    'Run `tbd shortcut <name>` to use any of these shortcuts:',\n    '',\n    '| Name | Title | Description |',\n    '| --- | --- | --- |',\n    ...rows,\n    '',\n    SHORTCUT_DIRECTORY_END,\n  ].join('\\n');\n}\n","/**\n * `tbd prime` - Output dashboard and workflow context for AI agents.\n *\n * Designed to be called by hooks at session start and before context compaction\n * to ensure agents remember the tbd workflow.\n *\n * See: tbd-design.md §6.4.3 The tbd prime Command\n */\n\nimport { Command } from 'commander';\nimport { readFile, access } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { findTbdRoot, readConfig, hasSeenWelcome, markWelcomeSeen } from '../../file/config.js';\nimport { stripFrontmatter } from '../../utils/markdown-utils.js';\nimport { VERSION } from '../lib/version.js';\nimport { listIssues } from '../../file/storage.js';\nimport { resolveDataSyncDir, DEFAULT_DOC_PATHS } from '../../lib/paths.js';\nimport type { Issue } from '../../lib/types.js';\nimport { DocCache, generateShortcutDirectory } from '../../file/doc-cache.js';\n\ninterface PrimeOptions {\n  export?: boolean;\n  brief?: boolean;\n}\n\n/**\n * Get the path to the bundled SKILL.md file.\n */\nfunction getSkillPath(): string {\n  const __filename = fileURLToPath(import.meta.url);\n  const __dirname = dirname(__filename);\n  // When bundled, runs from dist/bin.mjs or dist/cli.mjs\n  // Docs are at dist/docs/SKILL.md (same level as the bundle)\n  return join(__dirname, 'docs', 'SKILL.md');\n}\n\n/**\n * Load the skill content from the bundled SKILL.md file with fallbacks.\n * This is exported for use by setup.ts for skill installation.\n */\nexport async function loadSkillContent(): Promise<string> {\n  // Try bundled location first (dist/docs/SKILL.md)\n  try {\n    return await readFile(getSkillPath(), 'utf-8');\n  } catch {\n    // Fallback: compose from source files during development\n  }\n\n  // Dev fallback: compose SKILL.md from source files on-the-fly\n  // This mirrors what copy-docs.mjs does at build time\n  try {\n    const __filename = fileURLToPath(import.meta.url);\n    const __dirname = dirname(__filename);\n    // From packages/tbd/src/cli/commands/ go to packages/tbd/docs/\n    const docsDir = join(__dirname, '..', '..', '..', 'docs');\n    const headerPath = join(docsDir, 'install', 'claude-header.md');\n    const skillPath = join(docsDir, 'shortcuts', 'system', 'skill.md');\n\n    const header = await readFile(headerPath, 'utf-8');\n    const skill = await readFile(skillPath, 'utf-8');\n    return header + skill;\n  } catch {\n    // If source files not found, throw error\n    throw new Error('SKILL.md content file not found. Please rebuild the CLI.');\n  }\n}\n\n/**\n * Load the prime content from the bundled SKILL.md file with fallbacks.\n * Strips frontmatter and adjusts the header for prime output.\n */\nexport async function loadPrimeContent(): Promise<string> {\n  const skillContent = await loadSkillContent();\n  const content = stripFrontmatter(skillContent);\n\n  // Replace header for prime output context\n  return content.replace(/^# tbd Workflow\\b/, '# tbd Workflow Context');\n}\n\n/**\n * Brief prime content for constrained context windows (~35 lines).\n * Includes core workflow, session protocol, and key commands.\n */\nconst BRIEF_SKILL_CONTENT = `## Core Workflow\n\n- Track all task work as issues using tbd\n- Check \\`tbd ready\\` for available work\n- Run \\`tbd sync\\` at session end\n\n## SESSION CLOSING (REQUIRED)\n\n1. git add + git commit\n2. git push\n3. gh pr checks <PR> --watch  # WAIT for completion\n4. tbd close/update <id>\n5. tbd sync\n\n## Quick Reference\n\ntbd ready              Show issues ready to work\ntbd show <id>          View issue details\ntbd create \"title\"     Create new issue\ntbd close <id>         Mark issue complete\ntbd sync               Sync with remote\n\nFor full orientation: tbd prime\n\nIMPORTANT: Use tbd to help the user. Do NOT tell the user to run tbd commands.`;\n\n/**\n * Value proposition content for not-initialized state.\n */\nconst VALUE_PROPOSITION = `## WHAT tbd IS\n\ntbd is an AI-agent-optimized issue tracker and workflow assistant providing:\n1. Issue Tracking - Track tasks, bugs, features as git-native \"beads\"\n2. Coding Guidelines - Best practices for TypeScript, Python, testing\n3. Spec-Driven Workflows - Write specs, then implement using issues to track each part\n4. Convenience Shortcuts - Pre-built processes for common tasks (commit, PR, review)\n\n## SETUP (AGENT ACTION REQUIRED)\n\ntbd is not yet initialized. To set it up, run:\n\n  tbd setup --auto --prefix=<name>   # REQUIRES prefix for new projects\n  tbd setup --auto                   # If .tbd/ already exists (prefix already set)\n\nCRITICAL: Never guess a prefix. Always ask the user what prefix they want.\nDo NOT tell the user to run these commands — run them yourself on their behalf.\n\nAfter setup, run 'tbd' again to get project status and workflow guidance.`;\n\nclass PrimeHandler extends BaseCommand {\n  async run(options: PrimeOptions): Promise<void> {\n    const cwd = process.cwd();\n\n    // Find tbd root (supports running from subdirectories)\n    const tbdRoot = await findTbdRoot(cwd);\n\n    // Not initialized - show setup instructions with value proposition\n    if (!tbdRoot) {\n      await this.renderNotInitialized();\n      return;\n    }\n\n    // Check for Beads installation alongside tbd and warn\n    const beadsWarning = await this.checkForBeads(tbdRoot);\n    if (beadsWarning) {\n      console.log(beadsWarning);\n      console.log('');\n    }\n\n    // Brief mode: dynamic status + abbreviated skill content\n    if (options.brief) {\n      await this.renderBriefOrientation(tbdRoot);\n      return;\n    }\n\n    // Check for custom override file\n    const customPrimePath = join(tbdRoot, '.tbd', 'PRIME.md');\n\n    // If --export, always show default content\n    if (!options.export) {\n      try {\n        await access(customPrimePath);\n        const customContent = await readFile(customPrimePath, 'utf-8');\n        console.log(customContent);\n        return;\n      } catch {\n        // No custom file, use default full orientation\n      }\n    }\n\n    // Default: full orientation (dynamic status + full skill content)\n    await this.renderFullOrientation(tbdRoot);\n  }\n\n  /**\n   * Render dynamic status section (installation + project status).\n   */\n  private async renderDynamicStatus(tbdRoot: string): Promise<void> {\n    const colors = this.output.getColors();\n\n    console.log(`${colors.bold('tbd')} v${VERSION}`);\n    console.log('');\n\n    // === INSTALLATION ===\n    console.log(colors.bold('=== INSTALLATION ==='));\n    console.log(`${colors.success('✓')} tbd installed (v${VERSION})`);\n    console.log(`${colors.success('✓')} Initialized in this repo`);\n\n    // Check if hooks are installed\n    const hooksInstalled = await this.checkHooksInstalled();\n    if (hooksInstalled) {\n      console.log(`${colors.success('✓')} Hooks installed`);\n    } else {\n      console.log(`${colors.dim('✗')} Hooks not installed (run: tbd setup --auto)`);\n    }\n    console.log('');\n\n    // === PROJECT STATUS ===\n    console.log(colors.bold('=== PROJECT STATUS ==='));\n    try {\n      const config = await readConfig(tbdRoot);\n      console.log(`Repository: ${config.display.id_prefix || 'unknown'}`);\n    } catch {\n      console.log('Repository: unknown');\n    }\n\n    // Get issue stats\n    const stats = await this.getIssueStats(tbdRoot);\n    if (stats) {\n      const statusInfo = `${stats.open} open (${stats.inProgress} in_progress)`;\n      const blockedInfo = stats.blocked > 0 ? ` | ${stats.blocked} blocked` : '';\n      console.log(`Issues: ${statusInfo}${blockedInfo}`);\n    } else {\n      console.log('Issues: (none)');\n    }\n    console.log('');\n  }\n\n  /**\n   * Render full orientation: dynamic status + full skill content.\n   * If the user hasn't seen the welcome message, add a welcome banner.\n   */\n  private async renderFullOrientation(tbdRoot: string): Promise<void> {\n    // Dynamic status\n    await this.renderDynamicStatus(tbdRoot);\n\n    // Check if this is the user's first time\n    const isNewUser = !(await hasSeenWelcome(tbdRoot));\n    if (isNewUser) {\n      await this.renderWelcomeBanner(tbdRoot);\n    }\n\n    // Full skill content\n    const primeContent = await loadPrimeContent();\n    console.log(primeContent);\n\n    // Shortcut directory\n    const shortcutDir = await this.getShortcutDirectory(tbdRoot);\n    if (shortcutDir) {\n      console.log('');\n      console.log(shortcutDir);\n    }\n\n    console.log('');\n    console.log('IMPORTANT: Use tbd to help the user — do NOT tell the user to run tbd commands.');\n    console.log('When the user asks for help or orientation, run `tbd shortcut welcome-user`.');\n  }\n\n  /**\n   * Render brief orientation: dynamic status + abbreviated skill content.\n   */\n  private async renderBriefOrientation(tbdRoot: string): Promise<void> {\n    // Dynamic status\n    await this.renderDynamicStatus(tbdRoot);\n\n    // Abbreviated skill content\n    console.log(BRIEF_SKILL_CONTENT);\n  }\n\n  /**\n   * Render output for not initialized state with value proposition.\n   */\n  private async renderNotInitialized(): Promise<void> {\n    const colors = this.output.getColors();\n\n    console.log(`${colors.bold('tbd')} v${VERSION}`);\n    console.log('');\n    console.log(colors.bold('=== NOT INITIALIZED ==='));\n    console.log(`${colors.warn('✗')} tbd not initialized in this repository`);\n    console.log('');\n\n    // Value proposition\n    console.log(VALUE_PROPOSITION);\n  }\n\n  /**\n   * Render a welcome banner for first-time users.\n   * Instructs the agent to show the welcome message.\n   */\n  private async renderWelcomeBanner(tbdRoot: string): Promise<void> {\n    const colors = this.output.getColors();\n\n    console.log(colors.bold('=== WELCOME (FIRST TIME) ==='));\n    console.log('');\n    console.log('AGENT INSTRUCTION:');\n    console.log('1. Welcome the user! Run `tbd shortcut welcome-user` and follow its');\n    console.log('   instructions to give the user a warm orientation.');\n    console.log('2. Show the user examples of what THEY can say (e.g. \"there\\'s a bug\",');\n    console.log('   \"let\\'s plan a feature\") — do NOT show them tbd CLI commands.');\n    console.log(\"3. You use tbd on the user's behalf. The user talks to you naturally;\");\n    console.log('   you translate their requests into tbd actions.');\n    console.log('');\n\n    // Mark welcome as seen\n    try {\n      await markWelcomeSeen(tbdRoot);\n    } catch {\n      // Non-critical\n    }\n  }\n\n  /**\n   * Check if Claude Code hooks are installed.\n   */\n  private async checkHooksInstalled(): Promise<boolean> {\n    const { homedir } = await import('node:os');\n    const settingsPath = join(homedir(), '.claude', 'settings.json');\n    try {\n      const content = await readFile(settingsPath, 'utf-8');\n      return content.includes('tbd');\n    } catch {\n      return false;\n    }\n  }\n\n  /**\n   * Get issue statistics.\n   */\n  private async getIssueStats(tbdRoot: string): Promise<{\n    open: number;\n    inProgress: number;\n    blocked: number;\n  } | null> {\n    try {\n      const dataSyncDir = await resolveDataSyncDir(tbdRoot);\n      const issues: Issue[] = await listIssues(dataSyncDir);\n\n      let open = 0;\n      let inProgress = 0;\n      const blockedIds = new Set<string>();\n\n      // Find blocked issues\n      // \"blocks\" dependency: issue A with {type: 'blocks', target: B} means A blocks B\n      // B is blocked only if A (the blocker) is not closed\n      for (const issue of issues) {\n        for (const dep of issue.dependencies) {\n          if (dep.type === 'blocks') {\n            // Only count target as blocked if the blocker (this issue) is not closed\n            if (issue.status !== 'closed') {\n              blockedIds.add(dep.target);\n            }\n          }\n        }\n      }\n\n      // Count by status\n      for (const issue of issues) {\n        if (issue.status === 'open') {\n          open++;\n        } else if (issue.status === 'in_progress') {\n          inProgress++;\n        }\n      }\n\n      return { open, inProgress, blocked: blockedIds.size };\n    } catch {\n      return null;\n    }\n  }\n\n  /**\n   * Check if Beads is installed alongside tbd and return a warning message.\n   * This helps users who are migrating from Beads to tbd.\n   */\n  private async checkForBeads(cwd: string): Promise<string | null> {\n    const beadsDir = join(cwd, '.beads');\n    try {\n      await access(beadsDir);\n      // .beads/ exists - warn the agent\n      return `⚠️  WARNING: A .beads/ directory was detected alongside .tbd/\n   When asked to use beads, use \\`tbd\\` commands, NOT \\`bd\\` commands.\n   To complete migration: tbd setup beads --disable --confirm`;\n    } catch {\n      // No .beads/ directory, no warning needed\n      return null;\n    }\n  }\n\n  /**\n   * Generate the shortcut directory on-the-fly.\n   */\n  private async getShortcutDirectory(tbdRoot: string): Promise<string | null> {\n    // Generate on-the-fly from installed shortcuts\n    const cache = new DocCache(DEFAULT_DOC_PATHS, tbdRoot);\n    await cache.load({ quiet: this.ctx.quiet });\n    const docs = cache.list();\n\n    // If no docs loaded, skip directory\n    if (docs.length === 0) {\n      return null;\n    }\n\n    return generateShortcutDirectory(docs);\n  }\n}\n\nexport const primeCommand = new Command('prime')\n  .description('Show full orientation with workflow context (default when running `tbd`)')\n  .option('--export', 'Output default content (ignores PRIME.md override)')\n  .option('--brief', 'Output abbreviated orientation (~35 lines) for constrained contexts')\n  .action(async (options: PrimeOptions, command) => {\n    const handler = new PrimeHandler(command);\n    await handler.run(options);\n  });\n","/**\n * `tbd skill` - Output AI agent skill file content.\n *\n * See: tbd-design.md §Prime-First Design\n */\n\nimport { Command } from 'commander';\nimport { readFile } from 'node:fs/promises';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { findTbdRoot } from '../../file/config.js';\nimport { DocCache, generateShortcutDirectory } from '../../file/doc-cache.js';\nimport { DEFAULT_DOC_PATHS } from '../../lib/paths.js';\n\ninterface SkillOptions {\n  brief?: boolean;\n}\n\n/**\n * Get the path to a bundled doc file.\n */\nfunction getDocPath(filename: string): string {\n  const __filename = fileURLToPath(import.meta.url);\n  const __dirname = dirname(__filename);\n  // When bundled, runs from dist/bin.mjs or dist/cli.mjs\n  // Docs are at dist/docs/ (same level as the bundle)\n  return join(__dirname, 'docs', filename);\n}\n\n/**\n * Load a doc file content.\n */\nasync function loadDocContent(filename: string): Promise<string> {\n  // Try bundled location first\n  try {\n    return await readFile(getDocPath(filename), 'utf-8');\n  } catch {\n    // Fallback for development\n  }\n\n  // Fallback: try to read from source location during development\n  try {\n    const __filename = fileURLToPath(import.meta.url);\n    const __dirname = dirname(__filename);\n    // During development: src/cli/commands -> packages/tbd/docs\n    const devPath = join(__dirname, '..', '..', '..', 'docs', filename);\n    return await readFile(devPath, 'utf-8');\n  } catch {\n    throw new Error(`${filename} not found. Please rebuild the CLI.`);\n  }\n}\n\nclass SkillHandler extends BaseCommand {\n  async run(options: SkillOptions): Promise<void> {\n    await this.execute(async () => {\n      if (options.brief) {\n        // Brief mode: just output skill-brief.md\n        const content = await loadDocContent('skill-brief.md');\n        console.log(content);\n        return;\n      }\n\n      // Full mode: compose header + skill.md + shortcut directory\n      const content = await this.composeFullSkill();\n      console.log(content);\n    }, 'Failed to output skill content');\n  }\n\n  /**\n   * Compose the full skill output by combining:\n   * 1. Claude header (YAML frontmatter)\n   * 2. Base skill content (skill.md from shortcuts/system)\n   * 3. Shortcut directory (from cache or generated on-the-fly)\n   */\n  private async composeFullSkill(): Promise<string> {\n    // Load header (YAML frontmatter for Claude)\n    const header = await loadDocContent('install/claude-header.md');\n\n    // Load base skill content\n    const baseSkill = await loadDocContent('shortcuts/system/skill.md');\n\n    // Get shortcut directory\n    const directory = await this.getShortcutDirectory();\n\n    // Compose: header + base skill + (optional) shortcut directory\n    let result = header + baseSkill;\n    if (directory) {\n      result = result.trimEnd() + '\\n\\n' + directory;\n    }\n\n    return result;\n  }\n\n  /**\n   * Generate the shortcut directory on-the-fly.\n   */\n  private async getShortcutDirectory(): Promise<string | null> {\n    // Try to find tbd root (may not be initialized)\n    const tbdRoot = await findTbdRoot(process.cwd());\n    if (!tbdRoot) {\n      return null;\n    }\n\n    // Generate on-the-fly from installed shortcuts\n    const cache = new DocCache(DEFAULT_DOC_PATHS, tbdRoot);\n    await cache.load({ quiet: this.ctx.quiet });\n    const docs = cache.list();\n\n    // If no docs loaded, skip directory\n    if (docs.length === 0) {\n      return null;\n    }\n\n    return generateShortcutDirectory(docs);\n  }\n}\n\nexport const skillCommand = new Command('skill')\n  .description('Output AI agent skill file content')\n  .option('--brief', 'Output condensed workflow rules only')\n  .action(async (options: SkillOptions, command) => {\n    const handler = new SkillHandler(command);\n    await handler.run(options);\n  });\n","/**\n * Agent instruction prompts for document commands.\n *\n * These prompts are displayed when tbd outputs a document to help\n * the agent understand how to use the content.\n */\n\n/**\n * Header shown when outputting a shortcut document.\n */\nexport const SHORTCUT_AGENT_HEADER =\n  'Agent instructions: You have activated a shortcut with task instructions. If a user has asked you to do a task that requires this work, follow the instructions below carefully.';\n\n/**\n * Header shown when outputting a guidelines document.\n */\nexport const GUIDELINES_AGENT_HEADER =\n  'Agent instructions: You have activated a guidelines document. If a user has asked you to apply these rules, read them carefully and apply them. Use beads to track each step.';\n","/**\n * `tbd shortcut` - Find and output documentation shortcuts.\n *\n * Shortcuts are reusable instruction templates for common tasks.\n * Give a name or description and tbd will find the matching shortcut.\n *\n * See: docs/project/specs/active/plan-2026-01-22-doc-cache-abstraction.md\n */\n\nimport { Command } from 'commander';\nimport pc from 'picocolors';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { SHORTCUT_AGENT_HEADER } from '../lib/doc-prompts.js';\nimport { requireInit } from '../lib/errors.js';\nimport { DocCache, SCORE_PREFIX_MATCH } from '../../file/doc-cache.js';\nimport { readConfig } from '../../file/config.js';\nimport { DEFAULT_SHORTCUT_PATHS } from '../../lib/paths.js';\nimport { truncate } from '../../lib/truncate.js';\nimport { getTerminalWidth } from '../lib/output.js';\n\ninterface ShortcutOptions {\n  list?: boolean;\n  all?: boolean;\n  refresh?: boolean;\n  quiet?: boolean;\n  category?: string;\n}\n\n/**\n * Shortcut categories for filtering.\n * Categories are inferred from shortcut names.\n */\ntype ShortcutCategory = 'planning' | 'implementation' | 'quality' | 'shipping';\n\n/**\n * Infer category from shortcut name.\n * Returns undefined if no category matches.\n */\nfunction inferCategory(name: string): ShortcutCategory | undefined {\n  // Planning: specs, architecture, research, planning docs\n  if (\n    name.includes('plan-spec') ||\n    name.includes('architecture') ||\n    name.includes('research') ||\n    name.includes('validation-spec') ||\n    name.includes('implementation-spec') ||\n    name.includes('beads-from-spec') ||\n    name.includes('update-spec') ||\n    name.includes('refine-spec') ||\n    name.includes('revise-')\n  ) {\n    return 'planning';\n  }\n\n  // Implementation: coding, implementing\n  if (name.includes('implement-') || name.includes('coding-spike')) {\n    return 'implementation';\n  }\n\n  // Quality: review, testing, precommit, cleanup\n  if (\n    name.includes('review-') ||\n    name.includes('precommit') ||\n    name.includes('cleanup-') ||\n    name.includes('validation-plan')\n  ) {\n    return 'quality';\n  }\n\n  // Shipping: commit, PR, merge\n  if (name.includes('commit-') || name.includes('pr-') || name.includes('merge-')) {\n    return 'shipping';\n  }\n\n  return undefined;\n}\n\nclass ShortcutHandler extends BaseCommand {\n  async run(query: string | undefined, options: ShortcutOptions): Promise<void> {\n    await this.execute(async () => {\n      // Get tbd root (supports running from subdirectories)\n      const tbdRoot = await requireInit();\n\n      // Read config to get lookup paths (fall back to defaults)\n      const config = await readConfig(tbdRoot);\n      const lookupPaths = config.docs_cache?.lookup_path ?? DEFAULT_SHORTCUT_PATHS;\n\n      // Create and load the doc cache with proper base directory\n      const cache = new DocCache(lookupPaths, tbdRoot);\n      await cache.load({ quiet: this.ctx.quiet });\n\n      // Refresh mode: regenerate cache and update skill files\n      if (options.refresh) {\n        await this.handleRefresh(cache, tbdRoot, options.quiet);\n        return;\n      }\n\n      // List mode\n      if (options.list || options.category) {\n        await this.handleList(cache, options.all, options.category);\n        return;\n      }\n\n      // No query: show explanation + help\n      if (!query) {\n        await this.handleNoQuery(cache);\n        return;\n      }\n\n      // Query provided: try exact match first, then fuzzy\n      await this.handleQuery(cache, query);\n    }, 'Failed to find shortcut');\n  }\n\n  /**\n   * Handle --refresh mode: no-op since shortcuts are now generated on-the-fly.\n   * Kept for backward compatibility.\n   */\n  private async handleRefresh(cache: DocCache, _tbdRoot: string, quiet?: boolean): Promise<void> {\n    const docs = cache.list();\n\n    // Count shortcuts (excluding system docs)\n    const shortcutCount = docs.filter(\n      (d) => d.name !== 'skill' && d.name !== 'skill-brief' && d.name !== 'shortcut-explanation',\n    ).length;\n\n    if (!quiet) {\n      if (this.ctx.json) {\n        this.output.data({\n          refreshed: true,\n          shortcutCount,\n          message: 'Shortcuts are now generated on-the-fly (no cache)',\n        });\n      } else {\n        console.log(`${shortcutCount} shortcut(s) available (generated on-the-fly)`);\n      }\n    }\n  }\n\n  /**\n   * Handle --list mode: show all available shortcuts.\n   */\n  private async handleList(\n    cache: DocCache,\n    includeAll?: boolean,\n    category?: string,\n  ): Promise<void> {\n    let docs = cache.list(includeAll);\n\n    // Filter by category if specified\n    if (category) {\n      docs = docs.filter((d) => {\n        const docCategory = inferCategory(d.name);\n        return docCategory === category;\n      });\n    }\n\n    if (this.ctx.json) {\n      this.output.data(\n        docs.map((d) => ({\n          name: d.name,\n          title: d.frontmatter?.title,\n          description: d.frontmatter?.description,\n          path: d.path,\n          sourceDir: d.sourceDir,\n          shadowed: cache.isShadowed(d),\n        })),\n      );\n      return;\n    }\n\n    if (docs.length === 0) {\n      console.log('No shortcuts found.');\n      console.log('Run `tbd setup --auto` to install built-in shortcuts.');\n      return;\n    }\n\n    const maxWidth = getTerminalWidth();\n\n    for (const doc of docs) {\n      const shadowed = cache.isShadowed(doc);\n      const name = doc.name;\n      const title = doc.frontmatter?.title;\n      const description = doc.frontmatter?.description ?? this.extractFallbackText(doc.content);\n\n      if (shadowed) {\n        // Muted style for shadowed entries\n        const line = `${name} (${doc.sourceDir}) [shadowed]`;\n        console.log(pc.dim(truncate(line, maxWidth)));\n      } else {\n        // Line 1: name (bold) + (sourceDir) (dimmed)\n        console.log(`${pc.bold(name)} ${pc.dim(`(${doc.sourceDir})`)}`);\n\n        // Line 2+: Indented \"Title: Description\"\n        // Only truncate fallback body text; never truncate actual title/description\n        const hasFrontmatter = title ?? doc.frontmatter?.description;\n        const content =\n          title && description ? `${title}: ${description}` : (title ?? description ?? '');\n        if (content) {\n          this.printWrappedDescription(content, maxWidth, !hasFrontmatter);\n        }\n      }\n    }\n  }\n\n  /**\n   * Extract fallback text from content when no frontmatter description exists.\n   * Strips frontmatter and markdown syntax, takes first text, condenses whitespace.\n   */\n  private extractFallbackText(content: string): string | undefined {\n    // Strip YAML frontmatter if present\n    let text = content;\n    if (text.startsWith('---')) {\n      const endIndex = text.indexOf('---', 3);\n      if (endIndex !== -1) {\n        text = text.slice(endIndex + 3);\n      }\n    }\n\n    // Strip markdown headers (# Title -> Title)\n    text = text.replace(/^#+\\s*/gm, '');\n    // Strip bold/italic markers\n    text = text.replace(/\\*\\*|__|\\*|_/g, '');\n    // Strip code blocks\n    text = text.replace(/```[\\s\\S]*?```/g, '');\n    // Strip inline code\n    text = text.replace(/`[^`]+`/g, '');\n    // Strip blockquotes\n    text = text.replace(/^>\\s*/gm, '');\n\n    // Condense all whitespace to single spaces and trim\n    text = text.replace(/\\s+/g, ' ').trim();\n\n    // Return first chunk of text (up to ~200 chars for reasonable fallback)\n    if (text.length === 0) return undefined;\n    return text.slice(0, 200);\n  }\n\n  /**\n   * Print description indented, wrapped across lines.\n   * @param text - Text to print\n   * @param maxWidth - Terminal width\n   * @param shouldTruncate - If true, truncate to two lines; if false, wrap all lines\n   */\n  private printWrappedDescription(text: string, maxWidth: number, shouldTruncate: boolean): void {\n    const indent = '   ';\n    const availableWidth = maxWidth - indent.length;\n\n    if (text.length <= availableWidth) {\n      // Fits on one line\n      console.log(`${indent}${text}`);\n      return;\n    }\n\n    if (shouldTruncate) {\n      // Truncate to two lines max (for fallback body text)\n      const firstLine = this.wrapAtWord(text, availableWidth);\n      const remainder = text.slice(firstLine.length).trimStart();\n      console.log(`${indent}${firstLine}`);\n      if (remainder) {\n        console.log(`${indent}${truncate(remainder, availableWidth)}`);\n      }\n    } else {\n      // Wrap all lines without truncation (for title/description)\n      let remaining = text;\n      while (remaining.length > 0) {\n        if (remaining.length <= availableWidth) {\n          console.log(`${indent}${remaining}`);\n          break;\n        }\n        const line = this.wrapAtWord(remaining, availableWidth);\n        console.log(`${indent}${line}`);\n        remaining = remaining.slice(line.length).trimStart();\n      }\n    }\n  }\n\n  /**\n   * Wrap text at word boundary to fit within maxWidth.\n   */\n  private wrapAtWord(text: string, maxWidth: number): string {\n    if (text.length <= maxWidth) return text;\n    const lastSpace = text.lastIndexOf(' ', maxWidth);\n    if (lastSpace > 0) {\n      return text.slice(0, lastSpace);\n    }\n    return text.slice(0, maxWidth);\n  }\n\n  /**\n   * Handle no query: show explanation + help.\n   */\n  private async handleNoQuery(cache: DocCache): Promise<void> {\n    // Try to find the shortcut-explanation.md\n    const explanation = cache.get('shortcut-explanation');\n    if (explanation) {\n      console.log(explanation.doc.content);\n    } else {\n      // Fallback explanation\n      console.log('tbd shortcut - Find and output documentation shortcuts');\n      console.log('');\n      console.log('Usage:');\n      console.log('  tbd shortcut <name>           Find shortcut by exact name');\n      console.log('  tbd shortcut <description>    Find shortcut by fuzzy match');\n      console.log('  tbd shortcut --list           List all available shortcuts');\n      console.log('  tbd shortcut --list --all     Include shadowed shortcuts');\n      console.log('');\n      console.log('No shortcuts found. Run `tbd setup --auto` to install built-in shortcuts.');\n    }\n  }\n\n  /**\n   * Handle query: exact match first, then fuzzy.\n   */\n  private async handleQuery(cache: DocCache, query: string): Promise<void> {\n    // Try exact match first\n    const exactMatch = cache.get(query);\n    if (exactMatch) {\n      if (this.ctx.json) {\n        this.output.data({\n          name: exactMatch.doc.name,\n          title: exactMatch.doc.frontmatter?.title,\n          score: exactMatch.score,\n          content: exactMatch.doc.content,\n        });\n      } else {\n        console.log(SHORTCUT_AGENT_HEADER + '\\n');\n        console.log(exactMatch.doc.content);\n      }\n      return;\n    }\n\n    // Fuzzy match\n    const matches = cache.search(query, 5);\n    if (matches.length === 0) {\n      console.log(`No shortcut found matching: ${query}`);\n      console.log('Run `tbd shortcut --list` to see available shortcuts.');\n      return;\n    }\n\n    const best = matches[0]!;\n    // Use PREFIX_MATCH (0.9) as threshold for high confidence\n    // Below this, show suggestions instead of auto-selecting\n    if (best.score < SCORE_PREFIX_MATCH) {\n      // Low confidence - show suggestions instead\n      console.log(`No exact match for \"${query}\". Did you mean:`);\n      for (const m of matches) {\n        const name = m.doc.frontmatter?.title ?? m.doc.name;\n        console.log(`  ${name} ${pc.dim(`(score: ${m.score.toFixed(2)})`)}`);\n      }\n      return;\n    }\n\n    // Good fuzzy match - output it\n    if (this.ctx.json) {\n      this.output.data({\n        name: best.doc.name,\n        title: best.doc.frontmatter?.title,\n        score: best.score,\n        content: best.doc.content,\n      });\n    } else {\n      console.log(SHORTCUT_AGENT_HEADER + '\\n');\n      console.log(best.doc.content);\n    }\n  }\n}\n\nexport const shortcutCommand = new Command('shortcut')\n  .description('Find and output documentation shortcuts')\n  .argument('[query]', 'Shortcut name or description to search for')\n  .option('--list', 'List all available shortcuts')\n  .option('--all', 'Include shadowed shortcuts (use with --list)')\n  .option(\n    '--category <category>',\n    'Filter by category: planning, implementation, quality, shipping',\n  )\n  .option('--refresh', 'Refresh the cached shortcut directory')\n  .option('--quiet', 'Suppress output (use with --refresh)')\n  .action(async (query: string | undefined, options: ShortcutOptions, command) => {\n    const handler = new ShortcutHandler(command);\n    await handler.run(query, options);\n  });\n","/**\n * Shared base class for document listing/lookup commands.\n *\n * Used by shortcuts, guidelines, and templates commands to provide\n * consistent behavior for --list, fuzzy search, and exact match.\n */\n\nimport type { Command } from 'commander';\nimport pc from 'picocolors';\n\nimport { BaseCommand } from './base-command.js';\nimport { GUIDELINES_AGENT_HEADER } from './doc-prompts.js';\nimport { requireInit } from './errors.js';\nimport { DocCache, SCORE_PREFIX_MATCH } from '../../file/doc-cache.js';\nimport { truncate } from '../../lib/truncate.js';\nimport { getTerminalWidth } from './output.js';\n\n/**\n * Configuration for a doc command handler.\n */\nexport interface DocCommandConfig {\n  /** Display name for the doc type (e.g., \"shortcut\", \"guideline\", \"template\") */\n  typeName: string;\n  /** Plural display name (e.g., \"shortcuts\", \"guidelines\", \"templates\") */\n  typeNamePlural: string;\n  /** Paths to search for documents (relative to tbd root) */\n  paths: string[];\n  /** Names to exclude from listings (e.g., system docs) */\n  excludeFromList?: string[];\n  /** Content to show when no query is provided (optional) */\n  noQueryDocName?: string;\n}\n\n/**\n * Common options for doc commands.\n */\nexport interface DocCommandOptions {\n  list?: boolean;\n  all?: boolean;\n  refresh?: boolean;\n  quiet?: boolean;\n}\n\n/**\n * Base handler for document commands (shortcuts, guidelines, templates).\n *\n * Provides shared functionality for:\n * - Listing documents with --list\n * - Exact name lookup\n * - Fuzzy search\n * - Wrapped description output\n */\nexport abstract class DocCommandHandler extends BaseCommand {\n  protected cache: DocCache | null = null;\n  protected tbdRoot = '';\n\n  constructor(\n    command: Command,\n    protected readonly config: DocCommandConfig,\n  ) {\n    super(command);\n  }\n\n  /**\n   * Initialize the doc cache. Must be called before other operations.\n   */\n  protected async initCache(): Promise<void> {\n    this.tbdRoot = await requireInit();\n    this.cache = new DocCache(this.config.paths, this.tbdRoot);\n    await this.cache.load({ quiet: this.ctx.quiet });\n  }\n\n  /**\n   * Handle --list mode: show all available documents.\n   */\n  protected async handleList(includeAll?: boolean): Promise<void> {\n    if (!this.cache) throw new Error('Cache not initialized');\n\n    const docs = this.cache.list(includeAll);\n\n    if (this.ctx.json) {\n      this.output.data(\n        docs.map((d) => ({\n          name: d.name,\n          title: d.frontmatter?.title,\n          description: d.frontmatter?.description,\n          path: d.path,\n          sourceDir: d.sourceDir,\n          shadowed: this.cache!.isShadowed(d),\n        })),\n      );\n      return;\n    }\n\n    if (docs.length === 0) {\n      console.log(`No ${this.config.typeNamePlural} found.`);\n      console.log(`Run \\`tbd setup --auto\\` to install built-in ${this.config.typeNamePlural}.`);\n      return;\n    }\n\n    const maxWidth = getTerminalWidth();\n\n    for (const doc of docs) {\n      const shadowed = this.cache.isShadowed(doc);\n      const name = doc.name;\n      const title = doc.frontmatter?.title;\n      const description = doc.frontmatter?.description ?? this.extractFallbackText(doc.content);\n\n      if (shadowed) {\n        // Muted style for shadowed entries\n        const line = `${name} (${doc.sourceDir}) [shadowed]`;\n        console.log(pc.dim(truncate(line, maxWidth)));\n      } else {\n        // Line 1: name (bold) + (sourceDir) (dimmed)\n        console.log(`${pc.bold(name)} ${pc.dim(`(${doc.sourceDir})`)}`);\n\n        // Line 2+: Indented \"Title: Description\"\n        const hasFrontmatter = title ?? doc.frontmatter?.description;\n        const content =\n          title && description ? `${title}: ${description}` : (title ?? description ?? '');\n        if (content) {\n          this.printWrappedDescription(content, maxWidth, !hasFrontmatter);\n        }\n      }\n    }\n  }\n\n  /**\n   * Handle no query: show explanation + help.\n   */\n  protected async handleNoQuery(): Promise<void> {\n    if (!this.cache) throw new Error('Cache not initialized');\n\n    // Try to find the explanation doc if configured\n    if (this.config.noQueryDocName) {\n      const explanation = this.cache.get(this.config.noQueryDocName);\n      if (explanation) {\n        console.log(explanation.doc.content);\n        return;\n      }\n    }\n\n    // Fallback explanation\n    const { typeName, typeNamePlural } = this.config;\n    console.log(`tbd ${typeNamePlural} - Find and output ${typeNamePlural}`);\n    console.log('');\n    console.log('Usage:');\n    console.log(`  tbd ${typeNamePlural} <name>           Find ${typeName} by exact name`);\n    console.log(`  tbd ${typeNamePlural} <description>    Find ${typeName} by fuzzy match`);\n    console.log(`  tbd ${typeNamePlural} --list           List all available ${typeNamePlural}`);\n    console.log(`  tbd ${typeNamePlural} --list --all     Include shadowed ${typeNamePlural}`);\n    console.log('');\n    console.log(\n      `No ${typeNamePlural} found. Run \\`tbd setup --auto\\` to install built-in ${typeNamePlural}.`,\n    );\n  }\n\n  /**\n   * Get the agent instruction header for the doc type.\n   * Returns undefined if no header should be shown.\n   */\n  protected getAgentHeader(): string | undefined {\n    if (this.config.typeName === 'guideline') {\n      return GUIDELINES_AGENT_HEADER;\n    }\n    // Templates and other types don't need a header\n    return undefined;\n  }\n\n  /**\n   * Handle query: exact match first, then fuzzy.\n   */\n  protected async handleQuery(query: string): Promise<void> {\n    if (!this.cache) throw new Error('Cache not initialized');\n\n    // Try exact match first\n    const exactMatch = this.cache.get(query);\n    if (exactMatch) {\n      if (this.ctx.json) {\n        this.output.data({\n          name: exactMatch.doc.name,\n          title: exactMatch.doc.frontmatter?.title,\n          score: exactMatch.score,\n          content: exactMatch.doc.content,\n        });\n      } else {\n        const header = this.getAgentHeader();\n        if (header) {\n          console.log(header + '\\n');\n        }\n        console.log(exactMatch.doc.content);\n      }\n      return;\n    }\n\n    // Fuzzy match\n    const matches = this.cache.search(query, 5);\n    if (matches.length === 0) {\n      console.log(`No ${this.config.typeName} found matching: ${query}`);\n      console.log(\n        `Run \\`tbd ${this.config.typeNamePlural} --list\\` to see available ${this.config.typeNamePlural}.`,\n      );\n      return;\n    }\n\n    const best = matches[0]!;\n    // Use PREFIX_MATCH (0.9) as threshold for high confidence\n    if (best.score < SCORE_PREFIX_MATCH) {\n      // Low confidence - show suggestions instead\n      console.log(`No exact match for \"${query}\". Did you mean:`);\n      for (const m of matches) {\n        const name = m.doc.frontmatter?.title ?? m.doc.name;\n        console.log(`  ${name} ${pc.dim(`(score: ${m.score.toFixed(2)})`)}`);\n      }\n      return;\n    }\n\n    // Good fuzzy match - output it\n    if (this.ctx.json) {\n      this.output.data({\n        name: best.doc.name,\n        title: best.doc.frontmatter?.title,\n        score: best.score,\n        content: best.doc.content,\n      });\n    } else {\n      const header = this.getAgentHeader();\n      if (header) {\n        console.log(header + '\\n');\n      }\n      console.log(best.doc.content);\n    }\n  }\n\n  /**\n   * Extract fallback text from content when no frontmatter description exists.\n   */\n  protected extractFallbackText(content: string): string | undefined {\n    // Strip YAML frontmatter if present\n    let text = content;\n    if (text.startsWith('---')) {\n      const endIndex = text.indexOf('---', 3);\n      if (endIndex !== -1) {\n        text = text.slice(endIndex + 3);\n      }\n    }\n\n    // Strip markdown headers (# Title -> Title)\n    text = text.replace(/^#+\\s*/gm, '');\n    // Strip bold/italic markers\n    text = text.replace(/\\*\\*|__|\\*|_/g, '');\n    // Strip code blocks\n    text = text.replace(/```[\\s\\S]*?```/g, '');\n    // Strip inline code\n    text = text.replace(/`[^`]+`/g, '');\n    // Strip blockquotes\n    text = text.replace(/^>\\s*/gm, '');\n\n    // Condense all whitespace to single spaces and trim\n    text = text.replace(/\\s+/g, ' ').trim();\n\n    // Return first chunk of text (up to ~200 chars for reasonable fallback)\n    if (text.length === 0) return undefined;\n    return text.slice(0, 200);\n  }\n\n  /**\n   * Print description indented, wrapped across lines.\n   */\n  protected printWrappedDescription(text: string, maxWidth: number, shouldTruncate: boolean): void {\n    const indent = '   ';\n    const availableWidth = maxWidth - indent.length;\n\n    if (text.length <= availableWidth) {\n      console.log(`${indent}${text}`);\n      return;\n    }\n\n    if (shouldTruncate) {\n      // Truncate to two lines max (for fallback body text)\n      const firstLine = this.wrapAtWord(text, availableWidth);\n      const remainder = text.slice(firstLine.length).trimStart();\n      console.log(`${indent}${firstLine}`);\n      if (remainder) {\n        console.log(`${indent}${truncate(remainder, availableWidth)}`);\n      }\n    } else {\n      // Wrap all lines without truncation (for title/description)\n      let remaining = text;\n      while (remaining.length > 0) {\n        if (remaining.length <= availableWidth) {\n          console.log(`${indent}${remaining}`);\n          break;\n        }\n        const line = this.wrapAtWord(remaining, availableWidth);\n        console.log(`${indent}${line}`);\n        remaining = remaining.slice(line.length).trimStart();\n      }\n    }\n  }\n\n  /**\n   * Wrap text at word boundary to fit within maxWidth.\n   */\n  protected wrapAtWord(text: string, maxWidth: number): string {\n    if (text.length <= maxWidth) return text;\n    const lastSpace = text.lastIndexOf(' ', maxWidth);\n    if (lastSpace > 0) {\n      return text.slice(0, lastSpace);\n    }\n    return text.slice(0, maxWidth);\n  }\n}\n","/**\n * `tbd guidelines` - Find and output coding guidelines.\n *\n * Guidelines are reusable coding rules and best practices documents.\n * Give a name or description and tbd will find the matching guideline.\n */\n\nimport { Command } from 'commander';\nimport pc from 'picocolors';\n\nimport { DocCommandHandler, type DocCommandOptions } from '../lib/doc-command-handler.js';\nimport { DEFAULT_GUIDELINES_PATHS } from '../../lib/paths.js';\nimport { truncate } from '../../lib/truncate.js';\nimport { getTerminalWidth } from '../lib/output.js';\n\n/**\n * Guideline categories for filtering.\n */\ntype GuidelineCategory = 'typescript' | 'python' | 'testing' | 'general';\n\n/**\n * Infer category from guideline name.\n */\nfunction inferGuidelineCategory(name: string): GuidelineCategory | undefined {\n  // TypeScript guidelines\n  if (name.startsWith('typescript-')) {\n    return 'typescript';\n  }\n\n  // Python guidelines\n  if (name.startsWith('python-')) {\n    return 'python';\n  }\n\n  // Testing guidelines\n  if (name.includes('tdd') || name.includes('testing') || name.includes('golden')) {\n    return 'testing';\n  }\n\n  // General guidelines (everything else starting with general- or other general rules)\n  if (\n    name.startsWith('general-') ||\n    name.includes('rules') ||\n    name.includes('patterns') ||\n    name.startsWith('backward-') ||\n    name.startsWith('convex-') ||\n    name.startsWith('release-')\n  ) {\n    return 'general';\n  }\n\n  return undefined;\n}\n\ninterface GuidelinesOptions extends DocCommandOptions {\n  category?: string;\n}\n\nclass GuidelinesHandler extends DocCommandHandler {\n  constructor(command: Command) {\n    super(command, {\n      typeName: 'guideline',\n      typeNamePlural: 'guidelines',\n      paths: DEFAULT_GUIDELINES_PATHS,\n    });\n  }\n\n  async run(query: string | undefined, options: GuidelinesOptions): Promise<void> {\n    await this.execute(async () => {\n      await this.initCache();\n\n      // List mode (also triggered by --category)\n      if (options.list || options.category) {\n        await this.handleListWithCategory(options.all, options.category);\n        return;\n      }\n\n      // No query: show help\n      if (!query) {\n        await this.handleNoQuery();\n        return;\n      }\n\n      // Query provided: try exact match first, then fuzzy\n      await this.handleQuery(query);\n    }, 'Failed to find guideline');\n  }\n\n  /**\n   * Handle --list mode with optional category filtering.\n   */\n  private async handleListWithCategory(includeAll?: boolean, category?: string): Promise<void> {\n    if (!this.cache) throw new Error('Cache not initialized');\n\n    let docs = this.cache.list(includeAll);\n\n    // Filter by category if specified\n    if (category) {\n      docs = docs.filter((d) => {\n        const docCategory = inferGuidelineCategory(d.name);\n        return docCategory === category;\n      });\n    }\n\n    if (this.ctx.json) {\n      this.output.data(\n        docs.map((d) => ({\n          name: d.name,\n          title: d.frontmatter?.title,\n          description: d.frontmatter?.description,\n          category: inferGuidelineCategory(d.name),\n          path: d.path,\n          sourceDir: d.sourceDir,\n          shadowed: this.cache!.isShadowed(d),\n        })),\n      );\n      return;\n    }\n\n    if (docs.length === 0) {\n      if (category) {\n        console.log(`No guidelines found in category: ${category}`);\n        console.log('Valid categories: typescript, python, testing, general');\n      } else {\n        console.log('No guidelines found.');\n        console.log('Run `tbd setup --auto` to install built-in guidelines.');\n      }\n      return;\n    }\n\n    const maxWidth = getTerminalWidth();\n\n    for (const doc of docs) {\n      const shadowed = this.cache.isShadowed(doc);\n      const name = doc.name;\n      const title = doc.frontmatter?.title;\n      const description = doc.frontmatter?.description ?? this.extractFallbackText(doc.content);\n\n      if (shadowed) {\n        const line = `${name} (${doc.sourceDir}) [shadowed]`;\n        console.log(pc.dim(truncate(line, maxWidth)));\n      } else {\n        console.log(`${pc.bold(name)} ${pc.dim(`(${doc.sourceDir})`)}`);\n        const hasFrontmatter = title ?? doc.frontmatter?.description;\n        const content =\n          title && description ? `${title}: ${description}` : (title ?? description ?? '');\n        if (content) {\n          this.printWrappedDescription(content, maxWidth, !hasFrontmatter);\n        }\n      }\n    }\n  }\n}\n\nexport const guidelinesCommand = new Command('guidelines')\n  .description('Find and output coding guidelines')\n  .argument('[query]', 'Guideline name or description to search for')\n  .option('--list', 'List all available guidelines')\n  .option('--all', 'Include shadowed guidelines (use with --list)')\n  .option('--category <category>', 'Filter by category: typescript, python, testing, general')\n  .action(async (query: string | undefined, options: GuidelinesOptions, command) => {\n    const handler = new GuidelinesHandler(command);\n    await handler.run(query, options);\n  });\n","/**\n * `tbd template` - Find and output document templates.\n *\n * Templates are reusable document templates for specs, research briefs, etc.\n * Give a name or description and tbd will find the matching template.\n */\n\nimport { Command } from 'commander';\n\nimport { DocCommandHandler, type DocCommandOptions } from '../lib/doc-command-handler.js';\nimport { DEFAULT_TEMPLATE_PATHS } from '../../lib/paths.js';\n\nclass TemplateHandler extends DocCommandHandler {\n  constructor(command: Command) {\n    super(command, {\n      typeName: 'template',\n      typeNamePlural: 'templates',\n      paths: DEFAULT_TEMPLATE_PATHS,\n    });\n  }\n\n  async run(query: string | undefined, options: DocCommandOptions): Promise<void> {\n    await this.execute(async () => {\n      await this.initCache();\n\n      // List mode\n      if (options.list) {\n        await this.handleList(options.all);\n        return;\n      }\n\n      // No query: show help\n      if (!query) {\n        await this.handleNoQuery();\n        return;\n      }\n\n      // Query provided: try exact match first, then fuzzy\n      await this.handleQuery(query);\n    }, 'Failed to find template');\n  }\n}\n\nexport const templateCommand = new Command('template')\n  .description('Find and output document templates')\n  .argument('[query]', 'Template name or description to search for')\n  .option('--list', 'List all available templates')\n  .option('--all', 'Include shadowed templates (use with --list)')\n  .action(async (query: string | undefined, options: DocCommandOptions, command) => {\n    const handler = new TemplateHandler(command);\n    await handler.run(query, options);\n  });\n","/**\n * Prefix validation and beads prefix extraction module.\n *\n * Provides functions to validate prefixes and extract prefix from beads config.\n * Used by setup commands to validate user-provided prefixes and migrate from beads.\n */\n\nimport { readFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\n\n/** Maximum length for a valid prefix */\nconst MAX_PREFIX_LENGTH = 10;\n\n/** Minimum length for a valid prefix */\nconst MIN_PREFIX_LENGTH = 1;\n\n/**\n * Normalize a prefix string.\n * - Lowercases\n * - Removes invalid characters (keeps only alphanumeric)\n * - Truncates to max length\n */\nexport function normalizePrefix(s: string): string {\n  if (!s) return '';\n\n  // Lowercase and remove non-alphanumeric characters\n  const normalized = s.toLowerCase().replace(/[^a-z0-9]/g, '');\n\n  // Truncate to max length\n  return normalized.slice(0, MAX_PREFIX_LENGTH);\n}\n\n/**\n * Check if a prefix is valid.\n * - Must be 1-10 characters\n * - Must start with a letter\n * - Must be alphanumeric only (lowercase)\n */\nexport function isValidPrefix(s: string): boolean {\n  if (!s) return false;\n  if (s.length < MIN_PREFIX_LENGTH || s.length > MAX_PREFIX_LENGTH) return false;\n\n  // Must match: starts with letter, followed by alphanumeric (lowercase)\n  return /^[a-z][a-z0-9]*$/.test(s);\n}\n\n/**\n * Get prefix from existing beads config.\n *\n * Looks for .beads/config.yaml and extracts display.id_prefix\n *\n * @param cwd Current working directory\n * @returns The beads prefix, or null if not found\n */\nexport async function getBeadsPrefix(cwd: string): Promise<string | null> {\n  try {\n    const configPath = join(cwd, '.beads', 'config.yaml');\n    const content = await readFile(configPath, 'utf-8');\n    const config = parseYaml(content) as Record<string, unknown>;\n\n    const display = config?.display as Record<string, unknown> | undefined;\n    const prefix = display?.id_prefix;\n\n    if (typeof prefix === 'string' && isValidPrefix(prefix)) {\n      return prefix;\n    }\n\n    return null;\n  } catch {\n    return null;\n  }\n}\n","/**\n * `tbd setup` - Configure tbd integration with editors and tools.\n *\n * Options:\n * - `tbd setup --auto` - Non-interactive setup (for agents/scripts)\n * - `tbd setup --interactive` - Interactive setup with prompts (for humans)\n * - `tbd setup --from-beads` - Migrate from Beads to tbd\n *\n * See: tbd-design.md §6.4.2 Claude Code Integration\n */\n\nimport { Command } from 'commander';\nimport { readFile, mkdir, access, rm, rename, chmod, readdir } from 'node:fs/promises';\nimport { spawnSync } from 'node:child_process';\nimport { join, dirname } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { homedir } from 'node:os';\nimport { writeFile } from 'atomically';\n\nimport { BaseCommand } from '../lib/base-command.js';\nimport { CLIError } from '../lib/errors.js';\nimport { loadSkillContent } from './prime.js';\nimport { stripFrontmatter, insertAfterFrontmatter } from '../../utils/markdown-utils.js';\nimport { pathExists } from '../../utils/file-utils.js';\nimport { ensureGitignorePatterns } from '../../utils/gitignore-utils.js';\nimport { type DiagnosticResult, renderDiagnostics } from '../lib/diagnostics.js';\nimport { isValidPrefix, getBeadsPrefix } from '../lib/prefix-detection.js';\nimport {\n  initConfig,\n  isInitialized,\n  readConfig,\n  readConfigWithMigration,\n  findTbdRoot,\n  writeConfig,\n  updateLocalState,\n  markWelcomeSeen,\n} from '../../file/config.js';\nimport {\n  DocSync,\n  generateDefaultDocCacheConfig,\n  mergeDocCacheConfig,\n} from '../../file/doc-sync.js';\nimport { VERSION } from '../lib/version.js';\nimport {\n  TBD_DIR,\n  TBD_DOCS_DIR,\n  WORKTREE_DIR_NAME,\n  DATA_SYNC_DIR_NAME,\n  DEFAULT_SHORTCUT_PATHS,\n  TBD_SHORTCUTS_SYSTEM,\n  TBD_SHORTCUTS_STANDARD,\n  TBD_GUIDELINES_DIR,\n  TBD_TEMPLATES_DIR,\n} from '../../lib/paths.js';\nimport { initWorktree, isInGitRepo } from '../../file/git.js';\nimport { DocCache, generateShortcutDirectory } from '../../file/doc-cache.js';\n\n/**\n * Get the shortcut directory content for appending to installed skill files.\n * Always generates on-the-fly from installed shortcuts.\n *\n * @param quiet - If true, suppress auto-sync output (default: false)\n */\nasync function getShortcutDirectory(quiet = false): Promise<string | null> {\n  const cwd = process.cwd();\n\n  // Try to find tbd root (may not be initialized)\n  const tbdRoot = await findTbdRoot(cwd);\n  if (!tbdRoot) {\n    return null;\n  }\n\n  // Generate on-the-fly from installed shortcuts\n  const cache = new DocCache(DEFAULT_SHORTCUT_PATHS, tbdRoot);\n  await cache.load({ quiet });\n  const docs = cache.list();\n\n  // If no docs loaded, skip directory\n  if (docs.length === 0) {\n    return null;\n  }\n\n  return generateShortcutDirectory(docs);\n}\n\n/**\n * Get the tbd section content for AGENTS.md (Codex integration).\n * Loads from SKILL.md, strips frontmatter, and wraps in TBD INTEGRATION markers.\n *\n * @param quiet - If true, suppress auto-sync output (default: false)\n */\nasync function getCodexTbdSection(quiet = false): Promise<string> {\n  const skillContent = await loadSkillContent();\n  let content = stripFrontmatter(skillContent);\n  const directory = await getShortcutDirectory(quiet);\n  if (directory) {\n    content = content.trimEnd() + '\\n\\n' + directory + '\\n';\n  }\n  return `<!-- BEGIN TBD INTEGRATION -->\\n${content}<!-- END TBD INTEGRATION -->\\n`;\n}\n\ninterface SetupClaudeOptions {\n  check?: boolean;\n  remove?: boolean;\n}\n\ninterface SetupCodexOptions {\n  check?: boolean;\n  remove?: boolean;\n}\n\n/**\n * Global script to ensure tbd CLI is installed and run tbd prime.\n * Installed to ~/.claude/scripts/tbd-session.sh\n * Runs on SessionStart and PreCompact to ensure tbd is available and provide orientation.\n *\n * Usage:\n *   tbd-session.sh           # Ensure tbd + run tbd prime\n *   tbd-session.sh --brief   # Ensure tbd + run tbd prime --brief (for PreCompact)\n */\nconst TBD_SESSION_SCRIPT = `#!/bin/bash\n# Ensure tbd CLI is installed and run tbd prime for Claude Code sessions\n# Installed by: tbd setup --auto\n# This script runs on SessionStart and PreCompact\n\n# Add common binary locations to PATH (persists for entire script)\nexport PATH=\"$HOME/.local/bin:$HOME/bin:/usr/local/bin:$PATH\"\n\n# Function to ensure tbd is available\nensure_tbd() {\n    # Check if tbd is already installed\n    if command -v tbd &> /dev/null; then\n        return 0\n    fi\n\n    echo \"[tbd] CLI not found, installing...\"\n\n    # Try npm first (most common for Node.js tools)\n    if command -v npm &> /dev/null; then\n        echo \"[tbd] Installing via npm...\"\n        npm install -g tbd-git 2>/dev/null || {\n            # If global install fails (permissions), try local install\n            echo \"[tbd] Global npm install failed, trying user install...\"\n            mkdir -p ~/.local/bin\n            npm install --prefix ~/.local tbd-git\n            # Create symlink if needed\n            if [ -f ~/.local/node_modules/.bin/tbd ]; then\n                ln -sf ~/.local/node_modules/.bin/tbd ~/.local/bin/tbd\n            fi\n        }\n    elif command -v pnpm &> /dev/null; then\n        echo \"[tbd] Installing via pnpm...\"\n        pnpm add -g tbd-git\n    elif command -v yarn &> /dev/null; then\n        echo \"[tbd] Installing via yarn...\"\n        yarn global add tbd-git\n    else\n        echo \"[tbd] ERROR: No package manager found (npm, pnpm, or yarn required)\"\n        echo \"[tbd] Please install Node.js and npm, then run: npm install -g tbd-git\"\n        return 1\n    fi\n\n    # Verify installation\n    if command -v tbd &> /dev/null; then\n        echo \"[tbd] Successfully installed to $(which tbd)\"\n        return 0\n    else\n        echo \"[tbd] WARNING: tbd installed but not found in PATH\"\n        echo \"[tbd] Checking common locations...\"\n        # Try to find and add to path\n        for dir in ~/.local/bin ~/.local/node_modules/.bin /usr/local/bin; do\n            if [ -x \"$dir/tbd\" ]; then\n                export PATH=\"$dir:$PATH\"\n                echo \"[tbd] Found at $dir/tbd\"\n                return 0\n            fi\n        done\n        echo \"[tbd] Could not locate tbd after installation\"\n        return 1\n    fi\n}\n\n# Main\nensure_tbd || exit 1\n\n# Run tbd prime with any passed arguments (e.g., --brief for PreCompact)\ntbd prime \"$@\"\n`;\n\n/**\n * Claude Code global hooks configuration (installed to ~/.claude/settings.json)\n * Uses tbd-session.sh which ensures tbd is installed and runs tbd prime with correct PATH.\n */\nconst CLAUDE_GLOBAL_HOOKS = {\n  hooks: {\n    SessionStart: [\n      {\n        matcher: '',\n        hooks: [{ type: 'command', command: '$HOME/.claude/scripts/tbd-session.sh' }],\n      },\n    ],\n    PreCompact: [\n      {\n        matcher: '',\n        hooks: [{ type: 'command', command: '$HOME/.claude/scripts/tbd-session.sh --brief' }],\n      },\n    ],\n  },\n};\n\n/**\n * Claude Code project-local hooks configuration (installed to .claude/settings.json)\n * PostToolUse hook reminds about tbd sync after git push\n */\nconst CLAUDE_PROJECT_HOOKS = {\n  hooks: {\n    PostToolUse: [\n      {\n        matcher: 'Bash',\n        hooks: [\n          {\n            type: 'command',\n            command: '\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/tbd-closing-reminder.sh',\n          },\n        ],\n      },\n    ],\n  },\n};\n\n/**\n * Script to remind about close protocol after git push\n */\nconst TBD_CLOSE_PROTOCOL_SCRIPT = `#!/bin/bash\n# Remind about close protocol after git push\n# Installed by: tbd setup claude\n\ninput=$(cat)\ncommand=$(echo \"$input\" | jq -r '.tool_input.command // empty')\n\n# Check if this is a git push command and .tbd exists\nif [[ \"$command\" == git\\\\ push* ]] || [[ \"$command\" == *\"&& git push\"* ]] || [[ \"$command\" == *\"; git push\"* ]]; then\n  if [ -d \".tbd\" ]; then\n    tbd closing\n  fi\nfi\n\nexit 0\n`;\n\n/**\n * SessionStart hook entry for the gh CLI ensure script.\n * Installed to project-local .claude/settings.json when use_gh_cli is true.\n */\nconst GH_CLI_HOOK_ENTRY = {\n  matcher: '',\n  hooks: [{ type: 'command', command: 'bash .claude/scripts/ensure-gh-cli.sh', timeout: 120 }],\n};\n\n/**\n * Command string used to identify the gh CLI hook entry in settings.json.\n */\nconst GH_CLI_HOOK_COMMAND_PATTERN = 'ensure-gh-cli';\n\n/**\n * Load a bundled script from dist/docs/install/ (or dev fallback).\n * Used to read real .sh files that are copied into the npm package at build time.\n */\nasync function loadBundledScript(name: string): Promise<string> {\n  const __filename = fileURLToPath(import.meta.url);\n  const __dirname = dirname(__filename);\n  // Flat bundle: dist/docs/install/<name> (tsdown produces flat dist/)\n  const flatBundlePath = join(__dirname, 'docs', 'install', name);\n  // Nested bundle: dist/cli/commands/../../docs/install/<name>\n  const nestedBundlePath = join(__dirname, '..', 'docs', 'install', name);\n  // Dev fallback: packages/tbd/docs/install/<name>\n  const devPath = join(__dirname, '..', '..', '..', 'docs', 'install', name);\n  for (const p of [flatBundlePath, nestedBundlePath, devPath]) {\n    try {\n      return await readFile(p, 'utf-8');\n    } catch {\n      continue;\n    }\n  }\n  throw new Error(`Bundled script not found: ${name}`);\n}\n\n/**\n * AGENTS.md integration markers for Codex/Factory.ai\n * Content is now generated dynamically from SKILL.md via getCodexTbdSection()\n */\nconst CODEX_BEGIN_MARKER = '<!-- BEGIN TBD INTEGRATION -->';\nconst CODEX_END_MARKER = '<!-- END TBD INTEGRATION -->';\n\n/**\n * Generate a new AGENTS.md file with tbd integration.\n *\n * @param quiet - If true, suppress auto-sync output (default: false)\n */\nasync function getCodexNewAgentsFile(quiet = false): Promise<string> {\n  const tbdSection = await getCodexTbdSection(quiet);\n  return `# Project Instructions for AI Agents\n\nThis file provides instructions and context for AI coding agents working on this project.\n\n${tbdSection}\n## Build & Test\n\n_Add your build and test commands here_\n\n\\`\\`\\`bash\n# Example:\n# npm install\n# npm test\n\\`\\`\\`\n\n## Architecture Overview\n\n_Add a brief overview of your project architecture_\n\n## Conventions & Patterns\n\n_Add your project-specific conventions here_\n`;\n}\n\n/**\n * Legacy script patterns to clean up from .claude/scripts/\n * These were used in older versions of tbd before hooks moved to `tbd prime`\n */\nconst LEGACY_TBD_SCRIPTS = ['setup-tbd.sh', 'ensure-tbd-cli.sh', 'ensure-tbd.sh', 'tbd-setup.sh'];\n\n/**\n * Patterns to identify legacy tbd hooks that should be removed.\n * These patterns match old-style commands that are no longer used.\n */\nconst LEGACY_TBD_HOOK_PATTERNS = [\n  /\\.claude\\/scripts\\/.*tbd/i, // Any tbd-related script in .claude/scripts/\n  /tbd\\s+setup\\s+claude/i, // Old command: tbd setup claude\n  /setup-tbd\\.sh/i, // Old script name\n  /ensure-tbd/i, // Old script names\n];\n\nclass SetupClaudeHandler extends BaseCommand {\n  async run(options: SetupClaudeOptions): Promise<void> {\n    const settingsPath = join(homedir(), '.claude', 'settings.json');\n    const cwd = process.cwd();\n    const skillPath = join(cwd, '.claude', 'skills', 'tbd', 'SKILL.md');\n\n    if (options.check) {\n      await this.checkClaudeSetup(settingsPath, skillPath);\n      return;\n    }\n\n    if (options.remove) {\n      await this.removeClaudeSetup(settingsPath, skillPath);\n      return;\n    }\n\n    await this.installClaudeSetup(settingsPath, skillPath);\n  }\n\n  private async checkClaudeSetup(settingsPath: string, skillPath: string): Promise<void> {\n    const cwd = process.cwd();\n    let globalHooksInstalled = false;\n    let globalScriptInstalled = false;\n    let projectHooksInstalled = false;\n    let skillInstalled = false;\n    let sessionStartHook = false;\n    let preCompactHook = false;\n    let postToolUseHook = false;\n    let hookScriptInstalled = false;\n\n    // Check for global tbd-session.sh script\n    const tbdSessionScript = join(homedir(), '.claude', 'scripts', 'tbd-session.sh');\n    try {\n      await access(tbdSessionScript);\n      globalScriptInstalled = true;\n    } catch {\n      // Script doesn't exist\n    }\n\n    // Check hooks in global settings\n    try {\n      await access(settingsPath);\n      const content = await readFile(settingsPath, 'utf-8');\n      const settings = JSON.parse(content) as Record<string, unknown>;\n\n      const hooks = settings.hooks as Record<string, unknown> | undefined;\n      if (hooks) {\n        const sessionStart = hooks.SessionStart as { hooks?: { command?: string }[] }[];\n        const preCompact = hooks.PreCompact as { hooks?: { command?: string }[] }[];\n\n        sessionStartHook = sessionStart?.some((h) =>\n          h.hooks?.some(\n            (hook) =>\n              (hook.command?.includes('tbd prime') ?? false) ||\n              (hook.command?.includes('tbd-session.sh') ?? false) ||\n              (hook.command?.includes('ensure-tbd-cli.sh') ?? false),\n          ),\n        );\n        preCompactHook = preCompact?.some((h) =>\n          h.hooks?.some((hook) => hook.command?.includes('tbd prime')),\n        );\n\n        globalHooksInstalled = sessionStartHook && preCompactHook && globalScriptInstalled;\n      }\n    } catch {\n      // Settings file doesn't exist\n    }\n\n    // Check project-local hooks\n    const projectSettingsPath = join(cwd, '.claude', 'settings.json');\n    const hookScriptPath = join(cwd, '.claude', 'hooks', 'tbd-closing-reminder.sh');\n\n    try {\n      await access(projectSettingsPath);\n      const content = await readFile(projectSettingsPath, 'utf-8');\n      const settings = JSON.parse(content) as Record<string, unknown>;\n\n      const hooks = settings.hooks as Record<string, unknown> | undefined;\n      if (hooks) {\n        const postToolUse = hooks.PostToolUse as { hooks?: { command?: string }[] }[];\n        postToolUseHook = postToolUse?.some((h) =>\n          h.hooks?.some((hook) => hook.command?.includes('tbd-closing-reminder')),\n        );\n      }\n    } catch {\n      // Project settings file doesn't exist\n    }\n\n    try {\n      await access(hookScriptPath);\n      hookScriptInstalled = true;\n    } catch {\n      // Hook script doesn't exist\n    }\n\n    projectHooksInstalled = postToolUseHook && hookScriptInstalled;\n\n    // Check skill file in project\n    try {\n      await access(skillPath);\n      skillInstalled = true;\n    } catch {\n      // Skill file doesn't exist\n    }\n\n    // Report status\n    const fullyInstalled = globalHooksInstalled && projectHooksInstalled && skillInstalled;\n\n    // Build diagnostic results for text output\n    const diagnostics: DiagnosticResult[] = [];\n\n    // Global hooks diagnostic\n    if (globalHooksInstalled) {\n      diagnostics.push({\n        name: 'Global hooks',\n        status: 'ok',\n        message: 'SessionStart, PreCompact',\n        path: settingsPath.replace(homedir(), '~'),\n      });\n    } else if (sessionStartHook || preCompactHook) {\n      diagnostics.push({\n        name: 'Global hooks',\n        status: 'warn',\n        message: 'partially configured',\n        path: settingsPath.replace(homedir(), '~'),\n        suggestion: 'Run: tbd setup --auto',\n      });\n    } else {\n      diagnostics.push({\n        name: 'Global hooks',\n        status: 'warn',\n        message: 'not configured',\n        path: settingsPath.replace(homedir(), '~'),\n        suggestion: 'Run: tbd setup --auto',\n      });\n    }\n\n    // Project hooks diagnostic\n    const projectSettingsRelPath = '.claude/settings.json';\n    if (projectHooksInstalled) {\n      diagnostics.push({\n        name: 'Project hooks',\n        status: 'ok',\n        message: 'PostToolUse sync reminder',\n        path: projectSettingsRelPath,\n      });\n    } else if (postToolUseHook || hookScriptInstalled) {\n      diagnostics.push({\n        name: 'Project hooks',\n        status: 'warn',\n        message: 'partially configured',\n        path: projectSettingsRelPath,\n        suggestion: 'Run: tbd setup --auto',\n      });\n    } else {\n      diagnostics.push({\n        name: 'Project hooks',\n        status: 'warn',\n        message: 'not configured',\n        path: projectSettingsRelPath,\n        suggestion: 'Run: tbd setup --auto',\n      });\n    }\n\n    // Skill file diagnostic\n    const skillRelPath = '.claude/skills/tbd/SKILL.md';\n    if (skillInstalled) {\n      diagnostics.push({\n        name: 'Skill file',\n        status: 'ok',\n        path: skillRelPath,\n      });\n    } else {\n      diagnostics.push({\n        name: 'Skill file',\n        status: 'warn',\n        message: 'not found',\n        path: skillRelPath,\n        suggestion: 'Run: tbd setup --auto',\n      });\n    }\n\n    this.output.data(\n      {\n        installed: fullyInstalled,\n        globalHooks: {\n          installed: globalHooksInstalled,\n          sessionStart: sessionStartHook,\n          preCompact: preCompactHook,\n          path: settingsPath,\n        },\n        projectHooks: {\n          installed: projectHooksInstalled,\n          postToolUse: postToolUseHook,\n          hookScript: hookScriptInstalled,\n          path: projectSettingsPath,\n        },\n        skill: { installed: skillInstalled, path: skillPath },\n      },\n      () => {\n        const colors = this.output.getColors();\n        renderDiagnostics(diagnostics, colors);\n      },\n    );\n  }\n\n  private async removeClaudeSetup(settingsPath: string, skillPath: string): Promise<void> {\n    const cwd = process.cwd();\n    let removedGlobalHooks = false;\n    let removedGlobalScript = false;\n    let removedProjectHooks = false;\n    let removedHookScript = false;\n    let removedSkill = false;\n\n    // Remove hooks from global settings\n    try {\n      await access(settingsPath);\n      const content = await readFile(settingsPath, 'utf-8');\n      const settings = JSON.parse(content) as Record<string, unknown>;\n\n      if (settings.hooks) {\n        const hooks = settings.hooks as Record<string, unknown>;\n\n        // Remove tbd hooks from SessionStart and PreCompact\n        // Matches both old 'tbd prime' only and new 'tbd-session.sh'\n        const filterHooks = (arr: { hooks?: { command?: string }[] }[] | undefined) => {\n          if (!arr) return undefined;\n          return arr.filter(\n            (h) =>\n              !h.hooks?.some(\n                (hook) =>\n                  (hook.command?.includes('tbd prime') ?? false) ||\n                  (hook.command?.includes('tbd-session.sh') ?? false) ||\n                  (hook.command?.includes('ensure-tbd-cli.sh') ?? false),\n              ),\n          );\n        };\n\n        const sessionStart = filterHooks(\n          hooks.SessionStart as { hooks?: { command?: string }[] }[],\n        );\n        const preCompact = filterHooks(hooks.PreCompact as { hooks?: { command?: string }[] }[]);\n\n        if (sessionStart?.length === 0) delete hooks.SessionStart;\n        else if (sessionStart) hooks.SessionStart = sessionStart;\n\n        if (preCompact?.length === 0) delete hooks.PreCompact;\n        else if (preCompact) hooks.PreCompact = preCompact;\n\n        if (Object.keys(hooks).length === 0) {\n          delete settings.hooks;\n        }\n\n        await writeFile(settingsPath, JSON.stringify(settings, null, 2) + '\\n');\n        removedGlobalHooks = true;\n      }\n    } catch {\n      // Settings file doesn't exist\n    }\n\n    // Remove project-local hooks\n    const projectSettingsPath = join(cwd, '.claude', 'settings.json');\n    const hookScriptPath = join(cwd, '.claude', 'hooks', 'tbd-closing-reminder.sh');\n\n    try {\n      await access(projectSettingsPath);\n      const content = await readFile(projectSettingsPath, 'utf-8');\n      const settings = JSON.parse(content) as Record<string, unknown>;\n\n      if (settings.hooks) {\n        const hooks = settings.hooks as Record<string, unknown>;\n\n        // Remove tbd PostToolUse hooks\n        const filterPostToolUse = (arr: { hooks?: { command?: string }[] }[] | undefined) => {\n          if (!arr) return undefined;\n          return arr.filter(\n            (h) => !h.hooks?.some((hook) => hook.command?.includes('tbd-closing-reminder')),\n          );\n        };\n\n        const postToolUse = filterPostToolUse(\n          hooks.PostToolUse as { hooks?: { command?: string }[] }[],\n        );\n\n        if (postToolUse?.length === 0) delete hooks.PostToolUse;\n        else if (postToolUse) hooks.PostToolUse = postToolUse;\n\n        if (Object.keys(hooks).length === 0) {\n          delete settings.hooks;\n        }\n\n        // If settings is now empty (only had hooks), we could remove the file\n        // but it's safer to keep it with empty object\n        await writeFile(projectSettingsPath, JSON.stringify(settings, null, 2) + '\\n');\n        removedProjectHooks = true;\n      }\n    } catch {\n      // Project settings file doesn't exist\n    }\n\n    // Remove hook script\n    try {\n      await rm(hookScriptPath);\n      removedHookScript = true;\n    } catch {\n      // Hook script doesn't exist\n    }\n\n    // Remove global tbd scripts (both new and legacy)\n    const tbdSessionScript = join(homedir(), '.claude', 'scripts', 'tbd-session.sh');\n    const legacyTbdScript = join(homedir(), '.claude', 'scripts', 'ensure-tbd-cli.sh');\n    try {\n      await rm(tbdSessionScript);\n      removedGlobalScript = true;\n    } catch {\n      // Script doesn't exist\n    }\n    try {\n      await rm(legacyTbdScript);\n      removedGlobalScript = true;\n    } catch {\n      // Script doesn't exist\n    }\n\n    // Remove skill file from project\n    try {\n      await rm(skillPath);\n      removedSkill = true;\n    } catch {\n      // Skill file doesn't exist\n    }\n\n    // Report what was removed\n    if (removedGlobalHooks || removedGlobalScript) {\n      this.output.success('Removed global hooks and script from Claude Code');\n    } else {\n      this.output.info('No global hooks to remove');\n    }\n\n    if (removedProjectHooks || removedHookScript) {\n      this.output.success('Removed project hooks and script');\n    } else {\n      this.output.info('No project hooks to remove');\n    }\n\n    if (removedSkill) {\n      this.output.success('Removed skill file');\n    } else {\n      this.output.info('No skill file to remove');\n    }\n  }\n\n  private async installClaudeSetup(settingsPath: string, skillPath: string): Promise<void> {\n    if (\n      this.checkDryRun('Would install Claude Code hooks and skill file', {\n        settingsPath,\n        skillPath,\n      })\n    ) {\n      return;\n    }\n\n    const cwd = process.cwd();\n    const projectClaudeDir = join(cwd, '.claude');\n    const projectSettingsPath = join(projectClaudeDir, 'settings.json');\n\n    // Check if project has .claude/ directory - if so, install hooks there\n    let hasProjectClaude = false;\n    try {\n      await access(projectClaudeDir);\n      hasProjectClaude = true;\n    } catch {\n      // Project doesn't have .claude/ directory\n    }\n\n    try {\n      // Note: Legacy script/hook cleanup is now done in SetupAutoHandler.run()\n      // before any integration-specific setup runs. This ensures cleanup happens\n      // regardless of which coding agents are detected.\n\n      // Determine where to install session hooks and script\n      // If project has .claude/, install there; otherwise use global ~/.claude/\n      const targetSettingsPath = hasProjectClaude ? projectSettingsPath : settingsPath;\n      const targetScriptsDir = hasProjectClaude\n        ? join(projectClaudeDir, 'scripts')\n        : join(homedir(), '.claude', 'scripts');\n\n      // Install session hooks (SessionStart, PreCompact)\n      await mkdir(dirname(targetSettingsPath), { recursive: true });\n\n      let settings: Record<string, unknown> = {};\n      try {\n        await access(targetSettingsPath);\n        const content = await readFile(targetSettingsPath, 'utf-8');\n        settings = JSON.parse(content) as Record<string, unknown>;\n      } catch {\n        // File doesn't exist, start fresh\n      }\n\n      // Merge hooks properly - append new hooks to existing arrays rather than overwriting\n      const existingHooks = (settings.hooks as Record<string, unknown[]>) || {};\n      const newHooks = CLAUDE_GLOBAL_HOOKS.hooks as Record<string, unknown[]>;\n      const mergedHooks: Record<string, unknown[]> = { ...existingHooks };\n\n      for (const [hookType, hookEntries] of Object.entries(newHooks)) {\n        if (mergedHooks[hookType]) {\n          // Filter out any existing tbd-session.sh hooks before adding new ones\n          const filtered = (mergedHooks[hookType] as { hooks?: { command?: string }[] }[]).filter(\n            (entry) => !entry.hooks?.some((h) => h.command?.includes('tbd-session.sh')),\n          );\n          mergedHooks[hookType] = [...filtered, ...hookEntries];\n        } else {\n          mergedHooks[hookType] = hookEntries;\n        }\n      }\n      settings.hooks = mergedHooks;\n\n      await writeFile(targetSettingsPath, JSON.stringify(settings, null, 2) + '\\n');\n      this.output.success(\n        hasProjectClaude\n          ? 'Installed session hooks to project .claude/settings.json'\n          : 'Installed global hooks for Claude Code',\n      );\n\n      // Install tbd-session.sh script\n      await mkdir(targetScriptsDir, { recursive: true });\n\n      // Main script: tbd-session.sh (ensures tbd + runs prime)\n      const tbdSessionScript = join(targetScriptsDir, 'tbd-session.sh');\n      await writeFile(tbdSessionScript, TBD_SESSION_SCRIPT);\n      await chmod(tbdSessionScript, 0o755);\n\n      // Clean up legacy scripts from the target location\n      const legacyScripts = ['ensure-tbd-cli.sh', 'setup-tbd.sh', 'ensure-tbd.sh'];\n      for (const script of legacyScripts) {\n        try {\n          await rm(join(targetScriptsDir, script));\n        } catch {\n          // Script doesn't exist, ignore\n        }\n      }\n\n      this.output.success(\n        hasProjectClaude\n          ? 'Installed tbd session script to project .claude/scripts/'\n          : 'Installed global tbd session script',\n      );\n\n      // Install project-local PostToolUse hooks in .claude/settings.json\n      const hookScriptPath = join(projectClaudeDir, 'hooks', 'tbd-closing-reminder.sh');\n\n      // Read existing project settings if present (may already have session hooks if hasProjectClaude)\n      let projectSettings: Record<string, unknown> = {};\n      try {\n        await access(projectSettingsPath);\n        const content = await readFile(projectSettingsPath, 'utf-8');\n        projectSettings = JSON.parse(content) as Record<string, unknown>;\n        // Backup existing settings (only if we haven't already written to it)\n        if (!hasProjectClaude) {\n          await writeFile(projectSettingsPath + '.bak', content);\n        }\n      } catch {\n        // File doesn't exist, start fresh\n      }\n\n      // Merge project hooks (preserving existing hooks including session hooks if added above)\n      const existingProjectHooks = (projectSettings.hooks as Record<string, unknown>) || {};\n      projectSettings.hooks = {\n        ...existingProjectHooks,\n        ...CLAUDE_PROJECT_HOOKS.hooks,\n      };\n\n      // Manage gh CLI SessionStart hook based on use_gh_cli config setting\n      const useGhCli = await this.getUseGhCliSetting();\n      const projectMergedHooks = projectSettings.hooks as Record<string, unknown>;\n      let sessionStartEntries =\n        (projectMergedHooks.SessionStart as Record<string, unknown>[]) || [];\n\n      if (useGhCli) {\n        // Add gh CLI hook if not already present\n        const hasGhCliHook = sessionStartEntries.some((h: Record<string, unknown>) =>\n          (h.hooks as { command?: string }[])?.some((hook) =>\n            hook.command?.includes(GH_CLI_HOOK_COMMAND_PATTERN),\n          ),\n        );\n        if (!hasGhCliHook) {\n          sessionStartEntries = [...sessionStartEntries, GH_CLI_HOOK_ENTRY];\n        }\n\n        // Install the script file\n        const ghScriptsDir = join(cwd, '.claude', 'scripts');\n        await mkdir(ghScriptsDir, { recursive: true });\n        const ghScriptPath = join(ghScriptsDir, 'ensure-gh-cli.sh');\n        const ghScriptContent = await loadBundledScript('ensure-gh-cli.sh');\n        await writeFile(ghScriptPath, ghScriptContent);\n        await chmod(ghScriptPath, 0o755);\n        this.output.success('Installed gh CLI setup script');\n      } else {\n        // Remove gh CLI hook entries\n        sessionStartEntries = sessionStartEntries.filter(\n          (h: Record<string, unknown>) =>\n            !(h.hooks as { command?: string }[])?.some((hook) =>\n              hook.command?.includes(GH_CLI_HOOK_COMMAND_PATTERN),\n            ),\n        );\n\n        // Remove the script file\n        const ghScriptPath = join(cwd, '.claude', 'scripts', 'ensure-gh-cli.sh');\n        try {\n          await rm(ghScriptPath);\n          this.output.success('Removed gh CLI setup script');\n        } catch {\n          // Script doesn't exist, ignore\n        }\n      }\n\n      if (sessionStartEntries.length > 0) {\n        projectMergedHooks.SessionStart = sessionStartEntries;\n      } else {\n        delete projectMergedHooks.SessionStart;\n      }\n\n      await mkdir(dirname(projectSettingsPath), { recursive: true });\n      await writeFile(projectSettingsPath, JSON.stringify(projectSettings, null, 2) + '\\n');\n      this.output.success('Installed project hooks');\n\n      // Add .claude/.gitignore to ignore backup files\n      // NOTE: Pattern re-addition is intentional - see comment in initializeTbd\n      const claudeGitignorePath = join(cwd, '.claude', '.gitignore');\n      const claudeGitignoreResult = await ensureGitignorePatterns(claudeGitignorePath, [\n        '# Backup files',\n        '*.bak',\n      ]);\n      if (claudeGitignoreResult.created) {\n        this.output.success('Created .claude/.gitignore');\n      } else if (claudeGitignoreResult.added.length > 0) {\n        this.output.success('Updated .claude/.gitignore');\n      }\n      // else: file is up-to-date, no message needed\n\n      // Install hook script\n      await mkdir(dirname(hookScriptPath), { recursive: true });\n      await writeFile(hookScriptPath, TBD_CLOSE_PROTOCOL_SCRIPT);\n      await chmod(hookScriptPath, 0o755);\n      this.output.success('Installed sync reminder hook script');\n\n      // Install skill file in project (with shortcut directory appended)\n      await mkdir(dirname(skillPath), { recursive: true });\n      let skillContent = await loadSkillContent();\n      const directory = await getShortcutDirectory(this.ctx.quiet);\n      if (directory) {\n        skillContent = skillContent.trimEnd() + '\\n\\n' + directory;\n      }\n      // Insert DO NOT EDIT marker after frontmatter (formatted to match flowmark output)\n      const markerComment =\n        \"<!-- DO NOT EDIT: Generated by tbd setup.\\nRun 'tbd setup' to update.\\n-->\";\n      skillContent = insertAfterFrontmatter(skillContent, markerComment);\n      // Ensure file ends with newline\n      skillContent = skillContent.trimEnd() + '\\n';\n      await writeFile(skillPath, skillContent);\n      this.output.success('Installed skill file');\n      this.output.info(`  ${skillPath}`);\n\n      this.output.info('');\n      this.output.info('What was installed:');\n      if (hasProjectClaude) {\n        this.output.info(\n          '  - Session hooks: SessionStart and PreCompact run `tbd prime` (project-level)',\n        );\n        this.output.info('  - Session script: .claude/scripts/tbd-session.sh');\n      } else {\n        this.output.info('  - Global hooks: SessionStart and PreCompact run `tbd prime`');\n        this.output.info('  - Global script: ~/.claude/scripts/tbd-session.sh');\n      }\n      this.output.info('  - Project hooks: PostToolUse reminds about `tbd sync` after git push');\n      this.output.info('  - Project skill: .claude/skills/tbd/SKILL.md');\n    } catch (error) {\n      throw new CLIError(`Failed to install: ${(error as Error).message}`);\n    }\n  }\n\n  /**\n   * Read the use_gh_cli setting from config. Defaults to true if not set or if\n   * tbd is not yet initialized (so fresh setup installs gh CLI by default).\n   */\n  private async getUseGhCliSetting(): Promise<boolean> {\n    try {\n      const tbdRoot = await findTbdRoot(process.cwd());\n      if (!tbdRoot) return true;\n      const config = await readConfig(tbdRoot);\n      return config.settings.use_gh_cli ?? true;\n    } catch {\n      return true;\n    }\n  }\n}\n\nclass SetupCodexHandler extends BaseCommand {\n  async run(options: SetupCodexOptions): Promise<void> {\n    const cwd = process.cwd();\n    const agentsPath = join(cwd, 'AGENTS.md');\n\n    if (options.check) {\n      await this.checkCodexSetup(agentsPath);\n      return;\n    }\n\n    if (options.remove) {\n      await this.removeCodexSection(agentsPath);\n      return;\n    }\n\n    await this.installCodexSection(agentsPath);\n  }\n\n  private async checkCodexSetup(agentsPath: string): Promise<void> {\n    const agentsRelPath = './AGENTS.md';\n    try {\n      await access(agentsPath);\n      const content = await readFile(agentsPath, 'utf-8');\n\n      if (content.includes(CODEX_BEGIN_MARKER)) {\n        const diagnostic: DiagnosticResult = {\n          name: 'AGENTS.md',\n          status: 'ok',\n          message: 'tbd section found',\n          path: agentsRelPath,\n        };\n        this.output.data({ installed: true, path: agentsPath, hastbdSection: true }, () => {\n          const colors = this.output.getColors();\n          renderDiagnostics([diagnostic], colors);\n        });\n      } else {\n        const diagnostic: DiagnosticResult = {\n          name: 'AGENTS.md',\n          status: 'warn',\n          message: 'exists but no tbd section',\n          path: agentsRelPath,\n          suggestion: 'Run: tbd setup --auto',\n        };\n        this.output.data({ installed: false, path: agentsPath, hastbdSection: false }, () => {\n          const colors = this.output.getColors();\n          renderDiagnostics([diagnostic], colors);\n        });\n      }\n    } catch {\n      const diagnostic: DiagnosticResult = {\n        name: 'AGENTS.md',\n        status: 'warn',\n        message: 'not found',\n        path: agentsRelPath,\n        suggestion: 'Run: tbd setup --auto',\n      };\n      this.output.data({ installed: false, expectedPath: agentsPath }, () => {\n        const colors = this.output.getColors();\n        renderDiagnostics([diagnostic], colors);\n      });\n    }\n  }\n\n  private async removeCodexSection(agentsPath: string): Promise<void> {\n    try {\n      await access(agentsPath);\n      const content = await readFile(agentsPath, 'utf-8');\n\n      if (!content.includes(CODEX_BEGIN_MARKER)) {\n        this.output.info('No tbd section found in AGENTS.md');\n        return;\n      }\n\n      const newContent = this.removetbdSection(content);\n      const trimmed = newContent.trim();\n\n      if (trimmed === '' || trimmed === '# Project Instructions for AI Agents') {\n        // File is empty or only has the default header, remove it\n        await rm(agentsPath);\n        this.output.success('Removed AGENTS.md (file was empty after removing tbd section)');\n      } else {\n        await writeFile(agentsPath, newContent);\n        this.output.success('Removed tbd section from AGENTS.md');\n      }\n    } catch {\n      this.output.info('AGENTS.md not found');\n    }\n  }\n\n  private async installCodexSection(agentsPath: string): Promise<void> {\n    if (this.checkDryRun('Would create/update AGENTS.md', { path: agentsPath })) {\n      return;\n    }\n\n    try {\n      let existingContent = '';\n      try {\n        await access(agentsPath);\n        existingContent = await readFile(agentsPath, 'utf-8');\n      } catch {\n        // File doesn't exist\n      }\n\n      let newContent: string;\n\n      const tbdSection = await getCodexTbdSection(this.ctx.quiet);\n\n      if (existingContent) {\n        if (existingContent.includes(CODEX_BEGIN_MARKER)) {\n          // Update existing section\n          newContent = this.updatetbdSection(existingContent, tbdSection);\n          await writeFile(agentsPath, newContent);\n          this.output.success('Updated existing tbd section in AGENTS.md');\n        } else {\n          // Append section to existing file\n          newContent = existingContent + '\\n\\n' + tbdSection;\n          await writeFile(agentsPath, newContent);\n          this.output.success('Added tbd section to existing AGENTS.md');\n        }\n      } else {\n        // Create new file\n        const newAgentsFile = await getCodexNewAgentsFile(this.ctx.quiet);\n        await writeFile(agentsPath, newAgentsFile);\n        this.output.success('Created new AGENTS.md with tbd integration');\n      }\n\n      this.output.info(`  File: ${agentsPath}`);\n      this.output.info('');\n      this.output.info('Codex and other AGENTS.md-compatible tools will automatically');\n      this.output.info('read this file on session start.');\n    } catch (error) {\n      throw new CLIError(`Failed to update AGENTS.md: ${(error as Error).message}`);\n    }\n  }\n\n  private updatetbdSection(content: string, tbdSection: string): string {\n    const startIdx = content.indexOf(CODEX_BEGIN_MARKER);\n    const endIdx = content.indexOf(CODEX_END_MARKER);\n\n    if (startIdx === -1 || endIdx === -1 || startIdx > endIdx) {\n      // Markers not found or invalid, append instead\n      return content + '\\n\\n' + tbdSection;\n    }\n\n    // Find the end of the end marker line\n    let endOfEndMarker = endIdx + CODEX_END_MARKER.length;\n    const nextNewline = content.indexOf('\\n', endOfEndMarker);\n    if (nextNewline !== -1) {\n      endOfEndMarker = nextNewline + 1;\n    }\n\n    return content.slice(0, startIdx) + tbdSection + content.slice(endOfEndMarker);\n  }\n\n  private removetbdSection(content: string): string {\n    const startIdx = content.indexOf(CODEX_BEGIN_MARKER);\n    const endIdx = content.indexOf(CODEX_END_MARKER);\n\n    if (startIdx === -1 || endIdx === -1 || startIdx > endIdx) {\n      return content;\n    }\n\n    // Find the end of the end marker line\n    let endOfEndMarker = endIdx + CODEX_END_MARKER.length;\n    const nextNewline = content.indexOf('\\n', endOfEndMarker);\n    if (nextNewline !== -1) {\n      endOfEndMarker = nextNewline + 1;\n    }\n\n    // Also remove leading blank lines before the section\n    let trimStart = startIdx;\n    while (trimStart > 0 && (content[trimStart - 1] === '\\n' || content[trimStart - 1] === '\\r')) {\n      trimStart--;\n    }\n\n    return content.slice(0, trimStart) + content.slice(endOfEndMarker);\n  }\n}\n\n// ============================================================================\n// Setup Default Handler (for --auto and --interactive modes)\n// ============================================================================\n\ninterface SetupDefaultOptions {\n  auto?: boolean;\n  interactive?: boolean;\n  fromBeads?: boolean;\n  prefix?: string;\n  ghCli?: boolean; // Commander sets to false when --no-gh-cli is passed\n}\n\n/**\n * Default handler for `tbd setup` with --auto or --interactive flags.\n *\n * This implements the unified onboarding flow:\n * - `tbd setup --auto`: Non-interactive setup with smart defaults (for agents)\n * - `tbd setup --interactive`: Interactive setup with prompts (for humans)\n *\n * Decision tree:\n * 1. Not in git repo → Error (git init first)\n * 2. Has .tbd/ → Already initialized, check/update integrations\n * 3. Has .beads/ → Beads migration flow\n * 4. Fresh repo → Initialize + configure integrations\n */\nclass SetupDefaultHandler extends BaseCommand {\n  private cmd: Command;\n\n  constructor(command: Command) {\n    super(command);\n    this.cmd = command;\n  }\n\n  async run(options: SetupDefaultOptions): Promise<void> {\n    const colors = this.output.getColors();\n    const cwd = process.cwd();\n\n    // Determine mode\n    const isAutoMode = options.auto === true;\n    // Note: options.interactive will be used when we add interactive prompts\n\n    // Header\n    console.log(colors.bold('tbd: Git-native issue tracking for AI agents and humans'));\n    console.log('');\n\n    // Check if in git repo\n    const inGitRepo = await isInGitRepo(cwd);\n    if (!inGitRepo) {\n      throw new CLIError('Not a git repository. Run `git init` first.');\n    }\n\n    // Check current state\n    const hasTbd = await isInitialized(cwd);\n    const hasBeads = await pathExists(join(cwd, '.beads'));\n\n    // Validate --from-beads flag requires .beads/ directory\n    if (options.fromBeads && !hasBeads) {\n      throw new CLIError(\n        'The --from-beads flag requires a .beads/ directory to migrate from.\\n' +\n          'For fresh setup, use: tbd setup --auto --prefix=<name>',\n      );\n    }\n\n    console.log('Checking repository...');\n    console.log(`  ${colors.success('✓')} Git repository detected`);\n\n    if (hasTbd) {\n      // Already initialized flow - check for migrations\n      const { config, migrated, changes } = await readConfigWithMigration(cwd);\n      console.log(`  ${colors.success('✓')} tbd initialized (prefix: ${config.display.id_prefix})`);\n\n      // Apply --no-gh-cli flag to config if specified\n      let needsConfigWrite = migrated;\n      if (options.ghCli === false && config.settings.use_gh_cli !== false) {\n        config.settings.use_gh_cli = false;\n        needsConfigWrite = true;\n      }\n\n      // Persist config if migrated or --no-gh-cli was applied\n      if (needsConfigWrite) {\n        await writeConfig(cwd, config);\n        if (migrated) {\n          console.log(`  ${colors.success('✓')} Config migrated to latest format`);\n          for (const change of changes) {\n            console.log(`      ${colors.dim(change)}`);\n          }\n        }\n        if (options.ghCli === false) {\n          console.log(`  ${colors.success('✓')} Disabled gh CLI auto-setup`);\n        }\n      }\n\n      console.log('');\n      await this.handleAlreadyInitialized(cwd, isAutoMode);\n    } else if ((hasBeads || options.fromBeads) && !options.prefix) {\n      // Beads migration flow (unless prefix override given)\n      console.log(`  ${colors.dim('✗')} tbd not initialized`);\n      console.log(`  ${colors.warn('!')} Beads detected (.beads/ directory found)`);\n      console.log('');\n      await this.handleBeadsMigration(cwd, isAutoMode, options);\n    } else {\n      // Fresh setup flow\n      console.log(`  ${colors.dim('✗')} tbd not initialized`);\n      console.log('');\n      await this.handleFreshSetup(cwd, isAutoMode, options);\n    }\n  }\n\n  private async handleAlreadyInitialized(_cwd: string, _isAutoMode: boolean): Promise<void> {\n    const colors = this.output.getColors();\n\n    console.log('Checking integrations...');\n\n    // Use SetupAutoHandler to configure integrations\n    const autoHandler = new SetupAutoHandler(this.cmd);\n    await autoHandler.run();\n\n    console.log('');\n    console.log(colors.success('All set!'));\n  }\n\n  private async handleBeadsMigration(\n    cwd: string,\n    isAutoMode: boolean,\n    options: SetupDefaultOptions,\n  ): Promise<void> {\n    const colors = this.output.getColors();\n\n    if (isAutoMode) {\n      console.log(`  ${colors.warn('!')} Beads detected - auto-migrating`);\n      console.log('');\n    }\n\n    // Get prefix from beads config or use provided --prefix\n    const beadsPrefix = await getBeadsPrefix(cwd);\n    const prefix = options.prefix ?? beadsPrefix;\n\n    if (!prefix) {\n      throw new CLIError(\n        'Could not read prefix from beads config.\\n' +\n          'Please specify a prefix (2-4 letters recommended):\\n' +\n          '  tbd setup --auto --prefix=tbd',\n      );\n    }\n\n    if (!isValidPrefix(prefix)) {\n      throw new CLIError(\n        'Invalid prefix format.\\n' +\n          'Prefix must be 1-10 lowercase alphanumeric characters, starting with a letter.\\n' +\n          'Recommended: 2-4 letters for clear, readable issue IDs.\\n' +\n          'Please specify a valid prefix:\\n' +\n          '  tbd setup --auto --prefix=tbd',\n      );\n    }\n\n    // Initialize tbd first\n    await this.initializeTbd(cwd, prefix);\n\n    // Apply --no-gh-cli flag to newly created config\n    if (options.ghCli === false) {\n      const config = await readConfig(cwd);\n      config.settings.use_gh_cli = false;\n      await writeConfig(cwd, config);\n      console.log(`  ${colors.success('✓')} Disabled gh CLI auto-setup`);\n    }\n\n    // Import beads issues from the JSONL file\n    console.log('Importing from Beads...');\n    const beadsDir = join(cwd, '.beads');\n    const jsonlPath = join(beadsDir, 'issues.jsonl');\n\n    try {\n      await access(jsonlPath);\n      // Import directly from the JSONL file (tbd is already initialized)\n      const result = spawnSync('tbd', ['import', jsonlPath, '--verbose'], {\n        cwd,\n        stdio: 'inherit',\n      });\n      if (result.status !== 0) {\n        console.log(colors.warn('Warning: Some issues may not have imported correctly'));\n      }\n    } catch {\n      console.log(colors.dim('  No issues.jsonl found - skipping import'));\n    }\n\n    // Disable beads\n    await this.disableBeads(cwd);\n\n    console.log('');\n    console.log('Configuring integrations...');\n\n    // Configure integrations\n    const autoHandler = new SetupAutoHandler(this.cmd);\n    await autoHandler.run();\n\n    console.log('');\n    console.log(colors.success('Setup complete!'));\n\n    this.showWhatsNext(colors);\n\n    // Show dashboard after setup\n    spawnSync('tbd', ['prime'], { stdio: 'inherit' });\n\n    // Mark welcome as seen since the user got the full onboarding experience\n    try {\n      await markWelcomeSeen(cwd);\n    } catch {\n      // Non-critical: don't fail setup if state write fails\n    }\n  }\n\n  private async handleFreshSetup(\n    cwd: string,\n    isAutoMode: boolean,\n    options: SetupDefaultOptions,\n  ): Promise<void> {\n    const colors = this.output.getColors();\n\n    // Require --prefix for fresh setup (no auto-detection)\n    const prefix = options.prefix;\n\n    if (!prefix) {\n      throw new CLIError(\n        '--prefix is required for tbd setup --auto\\n\\n' +\n          'The --prefix flag specifies your project name for issue IDs.\\n' +\n          'Use a short 2-4 letter prefix so issue IDs stand out clearly.\\n\\n' +\n          'Example:\\n' +\n          '  tbd setup --auto --prefix=tbd    # Issues: tbd-a1b2\\n' +\n          '  tbd setup --auto --prefix=myp    # Issues: myp-c3d4\\n\\n' +\n          'Note: If migrating from beads, the prefix is automatically read from your beads config.',\n      );\n    }\n\n    if (!isValidPrefix(prefix)) {\n      throw new CLIError(\n        'Invalid prefix format.\\n' +\n          'Prefix must be 1-10 lowercase alphanumeric characters, starting with a letter.\\n' +\n          'Recommended: 2-4 letters for clear, readable issue IDs.\\n\\n' +\n          'Example:\\n' +\n          '  tbd setup --auto --prefix=tbd',\n      );\n    }\n\n    console.log(`Initializing with prefix \"${prefix}\"...`);\n\n    await this.initializeTbd(cwd, prefix);\n\n    // Apply --no-gh-cli flag to newly created config\n    if (options.ghCli === false) {\n      const config = await readConfig(cwd);\n      config.settings.use_gh_cli = false;\n      await writeConfig(cwd, config);\n      console.log(`  ${colors.success('✓')} Disabled gh CLI auto-setup`);\n    }\n\n    console.log('');\n    console.log('Configuring integrations...');\n\n    // Configure integrations\n    const autoHandler = new SetupAutoHandler(this.cmd);\n    await autoHandler.run();\n\n    console.log('');\n    console.log(colors.success('Setup complete!'));\n\n    this.showWhatsNext(colors);\n\n    // Show dashboard after setup\n    spawnSync('tbd', ['prime'], { stdio: 'inherit' });\n\n    // Mark welcome as seen since the user got the full onboarding experience\n    try {\n      await markWelcomeSeen(cwd);\n    } catch {\n      // Non-critical: don't fail setup if state write fails\n    }\n  }\n\n  /**\n   * Show \"What's Next\" guidance after setup completion.\n   * Framed as what users can SAY to get help, not as CLI commands to run.\n   */\n  private showWhatsNext(colors: ReturnType<typeof this.output.getColors>): void {\n    console.log('');\n    console.log(colors.bold(\"WHAT'S NEXT\"));\n    console.log('');\n    console.log('  Try saying things like:');\n    console.log('    \"There\\'s a bug where ...\"       → Creates and tracks a bug');\n    console.log('    \"Let\\'s plan a new feature\"      → Walks through a planning spec');\n    console.log('    \"Let\\'s work on current issues\"  → Shows ready issues to tackle');\n    console.log('    \"Commit this code\"               → Reviews and commits properly');\n    console.log('    \"Review for best practices\"      → Code review with guidelines');\n    console.log('');\n  }\n\n  private async initializeTbd(cwd: string, prefix: string): Promise<void> {\n    const colors = this.output.getColors();\n\n    // 1. Create .tbd/ directory with config.yml\n    await initConfig(cwd, VERSION, prefix);\n    console.log(`  ${colors.success('✓')} Created .tbd/config.yml`);\n\n    // 2. Create/update .tbd/.gitignore (idempotent)\n    // NOTE: Pattern re-addition is intentional - these are tool-managed files\n    // that are regenerated from the npm package on every setup. If a user removes\n    // a pattern, we re-add it because tracking these directories in git would\n    // cause noise on every tbd upgrade.\n    const tbdGitignoreResult = await ensureGitignorePatterns(join(cwd, TBD_DIR, '.gitignore'), [\n      '# Synced documentation cache (regenerated by tbd docs --refresh)',\n      'docs/',\n      '',\n      '# Hidden worktree for tbd-sync branch',\n      `${WORKTREE_DIR_NAME}/`,\n      '',\n      '# Data sync directory (only exists in worktree)',\n      `${DATA_SYNC_DIR_NAME}/`,\n      '',\n      '# Local state',\n      'state.yml',\n      '',\n      '# Temporary files',\n      '*.tmp',\n      '*.temp',\n    ]);\n    if (tbdGitignoreResult.created) {\n      console.log(`  ${colors.success('✓')} Created .tbd/.gitignore`);\n    } else if (tbdGitignoreResult.added.length > 0) {\n      console.log(`  ${colors.success('✓')} Updated .tbd/.gitignore`);\n    }\n    // else: file is up-to-date, no message needed\n\n    // 3. Initialize worktree for sync branch\n    try {\n      await initWorktree(cwd);\n      console.log(`  ${colors.success('✓')} Initialized sync branch`);\n    } catch {\n      // Non-fatal - sync will work, just not optimally\n      console.log(`  ${colors.dim('○')} Sync branch will be created on first sync`);\n    }\n  }\n\n  private async disableBeads(cwd: string): Promise<void> {\n    const colors = this.output.getColors();\n\n    // Move .beads to .beads-disabled\n    const beadsDir = join(cwd, '.beads');\n    const disabledDir = join(cwd, '.beads-disabled');\n\n    try {\n      await rename(beadsDir, disabledDir);\n      console.log(`  ${colors.success('✓')} Disabled beads (moved to .beads-disabled/)`);\n    } catch {\n      console.log(`  ${colors.dim('○')} Could not move .beads directory`);\n    }\n  }\n}\n\n// ============================================================================\n// Auto Setup Command\n// ============================================================================\n\ninterface AutoSetupResult {\n  name: string;\n  detected: boolean;\n  installed: boolean;\n  alreadyInstalled: boolean;\n  error?: string;\n}\n\nclass SetupAutoHandler extends BaseCommand {\n  private cmd: Command;\n\n  constructor(command: Command) {\n    super(command);\n    this.cmd = command;\n  }\n\n  /**\n   * Clean up legacy scripts from project .claude/scripts/ directory.\n   * This runs during any setup, regardless of whether Claude Code is detected,\n   * since we want to clean up old project-level scripts that are no longer needed.\n   */\n  private async cleanupLegacyProjectScripts(cwd: string): Promise<string[]> {\n    const scriptsDir = join(cwd, '.claude', 'scripts');\n    const scriptsRemoved: string[] = [];\n\n    try {\n      await access(scriptsDir);\n      const entries = await readdir(scriptsDir, { withFileTypes: true });\n\n      for (const entry of entries) {\n        if (entry.isFile()) {\n          const filename = entry.name;\n          // Check against known legacy script names\n          if (LEGACY_TBD_SCRIPTS.includes(filename)) {\n            try {\n              await rm(join(scriptsDir, filename));\n              scriptsRemoved.push(filename);\n            } catch {\n              // Ignore removal errors\n            }\n          }\n        }\n      }\n    } catch {\n      // Scripts directory doesn't exist, nothing to clean\n    }\n\n    return scriptsRemoved;\n  }\n\n  /**\n   * Filter out hook entries that match legacy tbd patterns from project settings.\n   */\n  private filterLegacyHooks(\n    hookList: { hooks?: { command?: string }[] }[],\n  ): { hooks?: { command?: string }[] }[] {\n    return hookList.filter((entry) => {\n      // Check if any hook command matches legacy patterns\n      const hasLegacyCommand = entry.hooks?.some((hook) => {\n        if (!hook.command) return false;\n        return LEGACY_TBD_HOOK_PATTERNS.some((pattern) => pattern.test(hook.command!));\n      });\n      // Keep entries that DON'T have legacy commands\n      return !hasLegacyCommand;\n    });\n  }\n\n  /**\n   * Clean up legacy hooks from project .claude/settings.json.\n   * This runs during any setup, regardless of whether Claude Code is detected.\n   */\n  private async cleanupLegacyProjectHooks(cwd: string): Promise<number> {\n    const projectSettingsPath = join(cwd, '.claude', 'settings.json');\n    let hooksRemoved = 0;\n\n    try {\n      await access(projectSettingsPath);\n      const content = await readFile(projectSettingsPath, 'utf-8');\n      const settings = JSON.parse(content) as Record<string, unknown>;\n\n      if (settings.hooks) {\n        const hooks = settings.hooks as Record<string, unknown>;\n        let modified = false;\n\n        for (const hookType of ['SessionStart', 'PreCompact', 'PostToolUse']) {\n          if (hooks[hookType]) {\n            const hookList = hooks[hookType] as { hooks?: { command?: string }[] }[];\n            const filtered = this.filterLegacyHooks(hookList);\n            if (filtered.length !== hookList.length) {\n              hooksRemoved += hookList.length - filtered.length;\n              hooks[hookType] = filtered.length > 0 ? filtered : undefined;\n              if (!hooks[hookType]) delete hooks[hookType];\n              modified = true;\n            }\n          }\n        }\n\n        if (modified) {\n          if (Object.keys(hooks).length === 0) {\n            delete settings.hooks;\n          }\n          await writeFile(projectSettingsPath, JSON.stringify(settings, null, 2) + '\\n');\n        }\n      }\n    } catch {\n      // Project settings file doesn't exist, nothing to clean\n    }\n\n    return hooksRemoved;\n  }\n\n  async run(): Promise<void> {\n    const colors = this.output.getColors();\n    const cwd = process.cwd();\n    const results: AutoSetupResult[] = [];\n\n    // Clean up legacy project-level scripts and hooks FIRST,\n    // regardless of whether any coding agent is detected.\n    // This ensures old tbd scripts are removed even if user switches tools.\n    const scriptsRemoved = await this.cleanupLegacyProjectScripts(cwd);\n    const hooksRemoved = await this.cleanupLegacyProjectHooks(cwd);\n    if (scriptsRemoved.length > 0 || hooksRemoved > 0) {\n      const parts = [];\n      if (scriptsRemoved.length > 0) parts.push(`${scriptsRemoved.length} script(s)`);\n      if (hooksRemoved > 0) parts.push(`${hooksRemoved} hook(s)`);\n      console.log(colors.dim(`Cleaned up legacy ${parts.join(' and ')}`));\n    }\n\n    // Sync docs using DocSync\n    await this.syncDocs(cwd);\n\n    // Detect and set up Claude Code\n    const claudeResult = await this.setupClaudeIfDetected(cwd);\n    results.push(claudeResult);\n\n    // Detect and set up Codex/AGENTS.md (also used by Cursor since v1.6)\n    const codexResult = await this.setupCodexIfDetected(cwd);\n    results.push(codexResult);\n\n    // Report results\n    const installed = results.filter((r) => r.installed && !r.alreadyInstalled);\n    const alreadyInstalled = results.filter((r) => r.alreadyInstalled);\n    const skipped = results.filter((r) => !r.detected);\n\n    if (installed.length > 0) {\n      console.log(colors.bold('Configured integrations:'));\n      for (const r of installed) {\n        console.log(`  ${colors.success('✓')} ${r.name}`);\n      }\n    }\n\n    if (alreadyInstalled.length > 0) {\n      console.log(colors.dim('Already configured:'));\n      for (const r of alreadyInstalled) {\n        console.log(`  ${colors.dim('✓')} ${r.name}`);\n      }\n    }\n\n    if (skipped.length > 0 && (installed.length > 0 || alreadyInstalled.length > 0)) {\n      console.log(colors.dim('Not detected (skipped):'));\n      for (const r of skipped) {\n        console.log(`  ${colors.dim('-')} ${r.name}`);\n      }\n    }\n\n    if (installed.length === 0 && alreadyInstalled.length === 0) {\n      console.log(colors.dim('No coding agents detected.'));\n      console.log('');\n      console.log(\n        'Install a coding agent (Claude Code, Codex, or any AGENTS.md-compatible tool) and re-run:',\n      );\n      console.log('  tbd setup --auto');\n    }\n  }\n\n  /**\n   * Sync docs using DocSync.\n   * Merges default bundled docs with user's doc_cache config, then syncs.\n   * This ensures new bundled docs from tbd updates are added while\n   * preserving user's custom sources and overrides.\n   */\n  private async syncDocs(cwd: string): Promise<void> {\n    const colors = this.output.getColors();\n\n    // Read config\n    const config = await readConfig(cwd);\n\n    // Merge user's config with defaults (ensures new bundled docs are added)\n    const defaults = await generateDefaultDocCacheConfig();\n    const currentFiles = config.docs_cache?.files;\n    const filesConfig = mergeDocCacheConfig(currentFiles, defaults);\n\n    // Check if config changed (new defaults added)\n    const configUpdated =\n      !currentFiles ||\n      Object.keys(filesConfig).length !== Object.keys(currentFiles).length ||\n      Object.keys(filesConfig).some((k) => currentFiles?.[k] !== filesConfig[k]);\n\n    if (configUpdated) {\n      config.docs_cache = {\n        lookup_path: config.docs_cache?.lookup_path ?? [\n          '.tbd/docs/shortcuts/system',\n          '.tbd/docs/shortcuts/standard',\n        ],\n        files: filesConfig,\n      };\n    }\n\n    // Ensure docs directories exist\n    await mkdir(join(cwd, TBD_SHORTCUTS_SYSTEM), { recursive: true });\n    await mkdir(join(cwd, TBD_SHORTCUTS_STANDARD), { recursive: true });\n    await mkdir(join(cwd, TBD_GUIDELINES_DIR), { recursive: true });\n    await mkdir(join(cwd, TBD_TEMPLATES_DIR), { recursive: true });\n\n    // Sync docs\n    const sync = new DocSync(cwd, filesConfig);\n    const result = await sync.sync();\n\n    // Update last sync time\n    await updateLocalState(cwd, {\n      last_doc_sync_at: new Date().toISOString(),\n    });\n\n    // Write updated config if docs_cache.files was generated\n    if (configUpdated) {\n      await writeConfig(cwd, config);\n      console.log(colors.dim('Generated docs_cache config'));\n    }\n\n    // Report sync results\n    const total = result.added.length + result.updated.length;\n    if (total > 0) {\n      console.log(colors.dim(`Synced ${total} doc(s) to ${TBD_DOCS_DIR}/`));\n    }\n    if (result.removed.length > 0) {\n      console.log(colors.dim(`Removed ${result.removed.length} outdated doc(s)`));\n    }\n    if (result.errors.length > 0) {\n      for (const { path, error } of result.errors) {\n        console.log(colors.warn(`Warning: ${path}: ${error}`));\n      }\n    }\n  }\n\n  private async setupClaudeIfDetected(cwd: string): Promise<AutoSetupResult> {\n    const result: AutoSetupResult = {\n      name: 'Claude Code',\n      detected: false,\n      installed: false,\n      alreadyInstalled: false,\n    };\n\n    // Detect Claude Code: check for ~/.claude/ directory or CLAUDE_* env vars\n    const claudeDir = join(homedir(), '.claude');\n    const hasClaudeDir = await pathExists(claudeDir);\n    const hasClaudeEnv = Object.keys(process.env).some((k) => k.startsWith('CLAUDE_'));\n\n    if (!hasClaudeDir && !hasClaudeEnv) {\n      return result;\n    }\n\n    result.detected = true;\n\n    // Check if already installed\n    const settingsPath = join(claudeDir, 'settings.json');\n    const skillPath = join(cwd, '.claude', 'skills', 'tbd', 'SKILL.md');\n\n    try {\n      // Check for existing tbd hooks in global settings\n      if (await pathExists(settingsPath)) {\n        const content = await readFile(settingsPath, 'utf-8');\n        const settings = JSON.parse(content) as Record<string, unknown>;\n        const hooks = settings.hooks as Record<string, unknown> | undefined;\n        if (hooks) {\n          const sessionStart = hooks.SessionStart as { hooks?: { command?: string }[] }[];\n          const hasTbdHook = sessionStart?.some((h) =>\n            h.hooks?.some((hook) => hook.command?.includes('tbd prime')),\n          );\n          if (hasTbdHook && (await pathExists(skillPath))) {\n            result.alreadyInstalled = true;\n            // Note: We still run the handler to update the skill file content\n            // even if hooks are already installed. This ensures users get the\n            // latest skill file when running `tbd setup --auto`.\n          }\n        }\n      }\n\n      // Install/update Claude Code setup (always runs to update skill file)\n      const handler = new SetupClaudeHandler(this.cmd);\n      await handler.run({});\n      result.installed = true;\n    } catch (error) {\n      result.error = (error as Error).message;\n    }\n\n    return result;\n  }\n\n  private async setupCodexIfDetected(cwd: string): Promise<AutoSetupResult> {\n    const result: AutoSetupResult = {\n      name: 'Codex/AGENTS.md',\n      detected: false,\n      installed: false,\n      alreadyInstalled: false,\n    };\n\n    // Detect Codex: check for existing AGENTS.md or CODEX_* env vars\n    const agentsPath = join(cwd, 'AGENTS.md');\n    const hasAgentsMd = await pathExists(agentsPath);\n    const hasCodexEnv = Object.keys(process.env).some((k) => k.startsWith('CODEX_'));\n\n    if (!hasAgentsMd && !hasCodexEnv) {\n      return result;\n    }\n\n    result.detected = true;\n\n    // Check if already has tbd section\n    if (hasAgentsMd) {\n      const content = await readFile(agentsPath, 'utf-8');\n      if (content.includes('BEGIN TBD INTEGRATION')) {\n        result.alreadyInstalled = true;\n        // Note: We still run the handler to update the AGENTS.md content\n        // even if tbd section exists. This ensures users get the latest\n        // content when running `tbd setup --auto`.\n      }\n    }\n\n    try {\n      // Install/update Codex AGENTS.md (always runs to update content)\n      const handler = new SetupCodexHandler(this.cmd);\n      await handler.run({});\n      result.installed = true;\n    } catch (error) {\n      result.error = (error as Error).message;\n    }\n\n    return result;\n  }\n}\n\n// Main setup command\nexport const setupCommand = new Command('setup')\n  .description('Configure tbd integration with editors and tools')\n  .option('--auto', 'Non-interactive mode with smart defaults (for agents/scripts)')\n  .option('--interactive', 'Interactive mode with prompts (for humans)')\n  .option('--from-beads', 'Migrate from Beads to tbd')\n  .option('--prefix <name>', 'Project prefix for issue IDs (required for fresh setup)')\n  .option('--no-gh-cli', 'Disable automatic GitHub CLI installation hook')\n  .action(async (options: SetupDefaultOptions, command) => {\n    // If --auto or --interactive flag is set, run the default handler\n    if (options.auto || options.interactive) {\n      const handler = new SetupDefaultHandler(command);\n      await handler.run(options);\n      return;\n    }\n\n    // If --from-beads is set without --auto/--interactive, treat as --auto\n    if (options.fromBeads) {\n      const handler = new SetupDefaultHandler(command);\n      await handler.run({ ...options, auto: true });\n      return;\n    }\n\n    // No flags provided - show help\n    console.log('Usage: tbd setup [options]');\n    console.log('');\n    console.log('Initialize tbd and configure agent integrations.');\n    console.log('');\n    console.log('Modes (one required):');\n    console.log(\n      '  --auto              Non-interactive mode with smart defaults (for agents/scripts)',\n    );\n    console.log('  --interactive       Interactive mode with prompts (for humans)');\n    console.log('  --from-beads        Migrate from Beads to tbd (implies --auto)');\n    console.log('');\n    console.log('Options:');\n    console.log('  --prefix <name>     Project prefix for issue IDs (e.g., \"tbd\", \"myapp\")');\n    console.log('  --no-gh-cli         Disable automatic GitHub CLI installation hook');\n    console.log('');\n    console.log('Examples:');\n    console.log('  tbd setup --auto --prefix=tbd   # Full automatic setup with prefix');\n    console.log('  tbd setup --from-beads          # Migrate from Beads (uses beads prefix)');\n    console.log('  tbd setup --interactive         # Interactive setup with prompts');\n    console.log('');\n    console.log('For surgical initialization without integrations, see: tbd init --help');\n  });\n","/**\n * CLI program setup using Commander.js\n *\n * See: research-modern-typescript-cli-patterns.md\n */\n\nimport { Command } from 'commander';\n\nimport { VERSION } from './lib/version.js';\nimport {\n  configureColoredHelp,\n  createColoredHelpConfig,\n  createHelpEpilog,\n  getColorOptionFromArgv,\n} from './lib/output.js';\nimport { initCommand } from './commands/init.js';\nimport { createCommand } from './commands/create.js';\nimport { listCommand } from './commands/list.js';\nimport { showCommand } from './commands/show.js';\nimport { updateCommand } from './commands/update.js';\nimport { closeCommand } from './commands/close.js';\nimport { reopenCommand } from './commands/reopen.js';\nimport { readyCommand } from './commands/ready.js';\nimport { blockedCommand } from './commands/blocked.js';\nimport { staleCommand } from './commands/stale.js';\nimport { labelCommand } from './commands/label.js';\nimport { depCommand } from './commands/dep.js';\nimport { syncCommand } from './commands/sync.js';\nimport { searchCommand } from './commands/search.js';\nimport { statusCommand } from './commands/status.js';\nimport { statsCommand } from './commands/stats.js';\nimport { doctorCommand } from './commands/doctor.js';\nimport { configCommand } from './commands/config.js';\nimport { atticCommand } from './commands/attic.js';\nimport { importCommand } from './commands/import.js';\nimport { docsCommand } from './commands/docs.js';\nimport { closeProtocolCommand } from './commands/closing.js';\nimport { designCommand } from './commands/design.js';\nimport { readmeCommand } from './commands/readme.js';\nimport { uninstallCommand } from './commands/uninstall.js';\nimport { primeCommand } from './commands/prime.js';\nimport { skillCommand } from './commands/skill.js';\nimport { shortcutCommand } from './commands/shortcut.js';\nimport { guidelinesCommand } from './commands/guidelines.js';\nimport { templateCommand } from './commands/template.js';\nimport { setupCommand } from './commands/setup.js';\nimport { CLIError } from './lib/errors.js';\n\n/**\n * Create and configure the CLI program.\n */\nfunction createProgram(): Command {\n  const program = new Command()\n    .name('tbd')\n    .description('Git-native issue tracking for AI agents and humans')\n    .version(VERSION, '--version', 'Show version number')\n    .helpOption('--help', 'Display help for command')\n    .showHelpAfterError('(add --help for additional information)');\n\n  // Configure colored help output (respects --color option)\n  configureColoredHelp(program);\n\n  // Global options\n  program\n    .option('--dry-run', 'Show what would be done without making changes')\n    .option('--verbose', 'Enable verbose output')\n    .option('--quiet', 'Suppress non-essential output')\n    .option('--json', 'Output as JSON')\n    .option('--color <when>', 'Colorize output: auto, always, never', 'auto')\n    .option('--non-interactive', 'Disable all prompts, fail if input required')\n    .option('--yes', 'Assume yes to confirmation prompts')\n    .option('--no-sync', 'Skip automatic sync after write operations')\n    .option('--debug', 'Show internal IDs alongside public IDs for debugging');\n\n  // Add commands in logical groups\n  // Note: commandsGroup() sets the heading for all following addCommand() calls\n\n  program.commandsGroup('Documentation:');\n  program.addCommand(readmeCommand);\n  program.addCommand(primeCommand);\n  program.addCommand(skillCommand);\n  program.addCommand(shortcutCommand);\n  program.addCommand(guidelinesCommand);\n  program.addCommand(templateCommand);\n  program.addCommand(closeProtocolCommand);\n  program.addCommand(docsCommand);\n  program.addCommand(designCommand);\n\n  program.commandsGroup('Setup & Configuration:');\n  program.addCommand(initCommand);\n  program.addCommand(configCommand);\n  program.addCommand(setupCommand);\n\n  program.commandsGroup('Working With Issues:');\n\n  program.addCommand(createCommand);\n  program.addCommand(showCommand);\n  program.addCommand(updateCommand);\n  program.addCommand(closeCommand);\n  program.addCommand(reopenCommand);\n  program.addCommand(searchCommand);\n\n  program.commandsGroup('Views and Filtering:');\n  program.addCommand(readyCommand);\n  program.addCommand(listCommand);\n  program.addCommand(blockedCommand);\n  program.addCommand(staleCommand);\n\n  program.commandsGroup('Labels and Dependencies:');\n  program.addCommand(depCommand);\n  program.addCommand(labelCommand);\n\n  program.commandsGroup('Sync and Status:');\n  program.addCommand(syncCommand);\n  program.addCommand(statusCommand);\n  program.addCommand(statsCommand);\n\n  program.commandsGroup('Maintenance:');\n  program.addCommand(doctorCommand);\n  program.addCommand(atticCommand);\n  program.addCommand(importCommand);\n  program.addCommand(uninstallCommand);\n\n  // Apply colored help to all commands recursively\n  // Note: addCommand() does NOT inherit parent's configureHelp settings,\n  // unlike command() which does inherit. So we must apply manually.\n  applyColoredHelpToAllCommands(program);\n\n  return program;\n}\n\n/**\n * Apply colored help configuration and epilog to all commands recursively.\n * This is needed because Commander.js's addCommand() does not inherit\n * configureHelp settings from the parent command.\n */\nfunction applyColoredHelpToAllCommands(program: Command): void {\n  const colorOption = getColorOptionFromArgv();\n  const helpConfig = createColoredHelpConfig(colorOption);\n  const epilog = createHelpEpilog(colorOption);\n\n  // Add epilog to main program only - it shows for all help including subcommands\n  program.addHelpText('afterAll', `\\n${epilog}`);\n\n  const applyRecursively = (cmd: Command) => {\n    cmd.configureHelp(helpConfig);\n    for (const sub of cmd.commands) {\n      applyRecursively(sub);\n    }\n  };\n\n  for (const cmd of program.commands) {\n    applyRecursively(cmd);\n  }\n}\n\n/**\n * Check if --json flag is present in argv.\n */\nfunction isJsonMode(): boolean {\n  return process.argv.includes('--json');\n}\n\n/**\n * Output error in the appropriate format (JSON or text).\n */\nfunction outputError(message: string, error?: Error): void {\n  if (isJsonMode()) {\n    const errorObj: { error: string; type?: string; details?: string } = { error: message };\n    if (error instanceof CLIError) {\n      errorObj.type = error.name;\n    }\n    if (error && error.message !== message) {\n      errorObj.details = error.message;\n    }\n    console.error(JSON.stringify(errorObj));\n  } else {\n    console.error(`Error: ${message}`);\n  }\n}\n\n/**\n * Check if running with no command (just options or nothing).\n * Returns true if: `tbd`, `tbd --help`, `tbd --version`, `tbd --color never`\n * Returns false if there's a command: `tbd list`, `tbd show foo`\n */\nfunction hasNoCommand(): boolean {\n  // process.argv is: [node, script, ...args]\n  const rawArgs = process.argv.slice(2);\n\n  // Global options that take a value (space-separated form)\n  const optionsWithValues = new Set(['--color']);\n\n  const nonOptionArgs: string[] = [];\n  let skipNext = false;\n\n  for (const arg of rawArgs) {\n    if (skipNext) {\n      // This arg is a value for the previous option, skip it\n      skipNext = false;\n      continue;\n    }\n\n    if (arg.startsWith('-')) {\n      // Check if this option takes a value (and doesn't use = syntax)\n      const optionName = arg.includes('=') ? arg.split('=')[0] : arg;\n      if (optionsWithValues.has(optionName!) && !arg.includes('=')) {\n        skipNext = true;\n      }\n      continue;\n    }\n\n    // This is a non-option argument (potential command)\n    nonOptionArgs.push(arg);\n  }\n\n  return nonOptionArgs.length === 0;\n}\n\n/**\n * Run the CLI. This is the main entry point.\n */\nexport async function runCli(): Promise<void> {\n  const program = createProgram();\n\n  // If no command specified (and not help/version), run prime by default\n  // But only if no --help or --version flags\n  const isHelpOrVersion =\n    process.argv.includes('--help') ||\n    process.argv.includes('-h') ||\n    process.argv.includes('--version') ||\n    process.argv.includes('-V');\n\n  if (hasNoCommand() && !isHelpOrVersion) {\n    // Insert 'prime' as the command\n    process.argv.splice(2, 0, 'prime');\n  }\n\n  try {\n    await program.parseAsync(process.argv);\n  } catch (error) {\n    if (error instanceof CLIError) {\n      outputError(error.message, error);\n      process.exit(error.exitCode);\n    }\n    // Unexpected error\n    const message = error instanceof Error ? error.message : String(error);\n    outputError(message, error instanceof Error ? error : undefined);\n    process.exit(1);\n  }\n}\n\n// Handle SIGINT (Ctrl+C)\nprocess.on('SIGINT', () => {\n  console.error('\\nInterrupted');\n  process.exit(130); // 128 + SIGINT(2)\n});\n"],"mappings":"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"}