@outcomeeng/spx 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/audit/paths.ts","../src/audit/reader.ts","../src/audit/semantic.ts","../src/audit/structural.ts","../src/audit/verify.ts","../src/audit/cli.ts","../src/commands/claude/init.ts","../src/commands/claude/settings/consolidate.ts","../src/lib/claude/permissions/discovery.ts","../src/lib/claude/permissions/parser.ts","../src/scanner/walk.ts","../src/lib/claude/permissions/subsumption.ts","../src/lib/claude/permissions/merger.ts","../src/lib/claude/settings/backup.ts","../src/lib/claude/settings/reporter.ts","../src/lib/claude/settings/writer.ts","../src/domains/claude/index.ts","../src/commands/config/defaults.ts","../src/commands/config/show.ts","../src/commands/config/types.ts","../src/commands/config/validate.ts","../src/config/index.ts","../src/spec/config.ts","../src/validation/literal/config.ts","../src/config/registry.ts","../src/domains/config/root.ts","../src/domains/config/index.ts","../src/commands/session/archive.ts","../src/git/root.ts","../src/config/defaults.ts","../src/session/archive.ts","../src/session/batch.ts","../src/session/errors.ts","../src/commands/session/delete.ts","../src/session/delete.ts","../src/session/show.ts","../src/session/list.ts","../src/session/timestamp.ts","../src/session/types.ts","../src/commands/session/handoff.ts","../src/session/create.ts","../src/commands/session/list.ts","../src/commands/session/pickup.ts","../src/session/pickup.ts","../src/commands/session/prune.ts","../src/session/prune.ts","../src/commands/session/release.ts","../src/session/release.ts","../src/commands/session/show.ts","../src/domains/session/help.ts","../src/domains/session/index.ts","../src/domains/spec/index.ts","../src/scanner/scanner.ts","../src/status/state.ts","../src/tree/build.ts","../src/commands/spec/next.ts","../src/reporter/json.ts","../src/reporter/markdown.ts","../src/reporter/table.ts","../src/reporter/text.ts","../src/commands/spec/status.ts","../src/spec/apply/exclude/adapters/detect.ts","../src/spec/apply/exclude/constants.ts","../src/spec/apply/exclude/mappings.ts","../src/spec/apply/exclude/adapters/python.ts","../src/spec/apply/exclude/help.ts","../src/spec/apply/exclude/exclude-file.ts","../src/spec/apply/exclude/command.ts","../src/validation/literal/allowlist-existing.ts","../src/validation/literal/index.ts","../src/validation/literal/detector.ts","../src/validation/literal/exclude.ts","../src/validation/literal/walker.ts","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/string-intern.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/parser.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js","../src/validation/config/scope.ts","../src/validation/discovery/tool-finder.ts","../src/validation/discovery/constants.ts","../src/validation/discovery/language-finder.ts","../src/validation/steps/circular.ts","../src/commands/validation/circular.ts","../src/commands/validation/format.ts","../src/validation/steps/eslint.ts","../src/validation/types.ts","../src/validation/steps/constants.ts","../src/validation/steps/knip.ts","../src/commands/validation/knip.ts","../src/commands/validation/lint.ts","../src/commands/validation/literal.ts","../src/validation/steps/markdown.ts","../src/commands/validation/markdown.ts","../src/validation/steps/typescript.ts","../src/commands/validation/typescript.ts","../src/commands/validation/all.ts","../src/lib/sanitize-cli-argument.ts","../src/domains/validation/index.ts"],"sourcesContent":["/**\n * CLI entry point for spx\n */\nimport { Command } from \"commander\";\nimport { createRequire } from \"node:module\";\nimport { auditDomain } from \"./audit/cli\";\nimport { claudeDomain } from \"./domains/claude\";\nimport { configDomain } from \"./domains/config\";\nimport { sessionDomain } from \"./domains/session\";\nimport { specDomain } from \"./domains/spec\";\nimport { validationDomain } from \"./domains/validation\";\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\") as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(\"spx\")\n .description(\"Fast, deterministic CLI tool for spec workflow management\")\n .version(version);\n\n// Register domains\nauditDomain.register(program);\nclaudeDomain.register(program);\nconfigDomain.register(program);\nsessionDomain.register(program);\nspecDomain.register(program);\nvalidationDomain.register(program);\n\nprogram.parse();\n","import { existsSync } from \"node:fs\";\nimport { relative, resolve } from \"node:path\";\n\nimport type { AuditVerdict } from \"@/audit/reader\";\n\nexport function validatePaths(verdict: AuditVerdict, projectRoot: string): readonly string[] {\n const defects: string[] = [];\n const root = resolve(projectRoot);\n\n for (const gate of verdict.gates) {\n for (const finding of gate.findings) {\n checkPath(finding.spec_file, root, defects);\n checkPath(finding.test_file, root, defects);\n }\n }\n\n return defects;\n}\n\nfunction checkPath(filePath: string | undefined, root: string, defects: string[]): void {\n if (!filePath) return;\n\n const rel = relative(root, resolve(root, filePath));\n if (rel.startsWith(\"..\")) {\n defects.push(`path escapes project root: ${filePath}`);\n return;\n }\n\n if (!existsSync(resolve(root, filePath))) {\n defects.push(`missing file: ${filePath}`);\n }\n}\n","/**\n * Audit verdict reader — parses an audit verdict XML file from disk into a\n * typed in-memory representation.\n *\n * All downstream verify stages (structural, semantic, paths) import\n * AuditVerdict from this module and operate on the parsed representation\n * rather than raw XML.\n *\n * @module audit/reader\n */\n\nimport { readFile } from \"node:fs/promises\";\n\nimport { XMLParser, XMLValidator } from \"fast-xml-parser\";\n\nexport interface AuditFinding {\n readonly spec_file?: string;\n readonly test_file?: string;\n}\n\nexport interface AuditGate {\n readonly name?: string;\n readonly status?: string;\n readonly skipped_reason?: string;\n readonly count?: string;\n readonly findings: readonly AuditFinding[];\n}\n\nexport interface AuditVerdictHeader {\n readonly spec_node?: string;\n readonly verdict?: string;\n readonly timestamp?: string;\n}\n\nexport interface AuditVerdict {\n readonly header?: AuditVerdictHeader;\n readonly gates: readonly AuditGate[];\n}\n\nconst ARRAY_TAGS = new Set([\"gate\", \"finding\"]);\n\nconst PARSER_OPTIONS = {\n ignoreAttributes: false,\n attributeNamePrefix: \"@_\",\n parseTagValue: false,\n parseAttributeValue: false,\n isArray: (name: string) => ARRAY_TAGS.has(name),\n} as const;\n\n/**\n * Reads and parses an audit verdict XML file from disk.\n *\n * @throws {Error} When the file does not exist — message includes filePath.\n * @throws {Error} When the file is not well-formed XML — message includes filePath.\n */\nexport async function readVerdictFile(filePath: string): Promise<AuditVerdict> {\n let xml: string;\n try {\n xml = await readFile(filePath, \"utf-8\");\n } catch (cause) {\n throw new Error(`Failed to read verdict file: ${filePath}`, { cause });\n }\n\n const validation = XMLValidator.validate(xml);\n if (validation !== true) {\n throw new Error(\n `Malformed XML in verdict file: ${filePath}: ${validation.err.msg}`,\n );\n }\n\n const parser = new XMLParser(PARSER_OPTIONS);\n const parsed = parser.parse(xml) as Record<string, unknown>;\n\n return buildVerdict(parsed);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction buildVerdict(parsed: Record<string, unknown>): AuditVerdict {\n const rootUnknown = parsed[\"audit_verdict\"];\n if (!isObject(rootUnknown)) {\n return { gates: [] };\n }\n\n const headerUnknown = rootUnknown[\"header\"];\n const gatesUnknown = rootUnknown[\"gates\"];\n\n return {\n header: isObject(headerUnknown) ? buildHeader(headerUnknown) : undefined,\n gates: isObject(gatesUnknown) ? buildGates(gatesUnknown) : [],\n };\n}\n\nfunction buildHeader(raw: Record<string, unknown>): AuditVerdictHeader {\n return {\n spec_node: asString(raw[\"spec_node\"]),\n verdict: asString(raw[\"verdict\"]),\n timestamp: asString(raw[\"timestamp\"]),\n };\n}\n\nfunction buildGates(raw: Record<string, unknown>): readonly AuditGate[] {\n const gatesUnknown = raw[\"gate\"];\n if (!Array.isArray(gatesUnknown)) return [];\n return gatesUnknown.filter(isObject).map(buildGate);\n}\n\nfunction buildGate(raw: Record<string, unknown>): AuditGate {\n const findingsUnknown = raw[\"findings\"];\n return {\n name: asString(raw[\"name\"]),\n status: asString(raw[\"status\"]),\n skipped_reason: asString(raw[\"skipped_reason\"]),\n count: isObject(findingsUnknown) ? asString(findingsUnknown[\"@_count\"]) : undefined,\n findings: isObject(findingsUnknown) ? buildFindings(findingsUnknown) : [],\n };\n}\n\nfunction buildFindings(raw: Record<string, unknown>): readonly AuditFinding[] {\n const findingsUnknown = raw[\"finding\"];\n if (!Array.isArray(findingsUnknown)) return [];\n return findingsUnknown.filter(isObject).map(buildFinding);\n}\n\nfunction buildFinding(raw: Record<string, unknown>): AuditFinding {\n return {\n spec_file: asString(raw[\"spec_file\"]),\n test_file: asString(raw[\"test_file\"]),\n };\n}\n","import type { AuditVerdict } from \"@/audit/reader\";\n\nexport function validateSemantics(verdict: AuditVerdict): readonly string[] {\n const defects: string[] = [];\n\n const hasFail = verdict.gates.some((g) => g.status === \"FAIL\");\n const hasSkipped = verdict.gates.some((g) => g.status === \"SKIPPED\");\n\n if (verdict.header?.verdict === \"APPROVED\" && (hasFail || hasSkipped)) {\n defects.push(\"incoherent verdict: APPROVED but at least one gate is not PASS\");\n } else if (verdict.header?.verdict === \"REJECT\" && !hasFail && !hasSkipped) {\n defects.push(\"incoherent verdict: REJECT but all gates are PASS\");\n }\n\n for (const gate of verdict.gates) {\n const label = gate.name ? `gate \"${gate.name}\"` : \"gate\";\n\n if (gate.status === \"FAIL\" && gate.findings.length === 0) {\n defects.push(`failed gate has no findings: ${label}`);\n }\n\n if (gate.status === \"SKIPPED\" && !gate.skipped_reason) {\n defects.push(`skipped gate missing reason: ${label}`);\n }\n }\n\n return defects;\n}\n","import type { AuditVerdict } from \"@/audit/reader\";\n\nconst VALID_VERDICTS = new Set([\"APPROVED\", \"REJECT\"]);\nconst VALID_GATE_STATUSES = new Set([\"PASS\", \"FAIL\", \"SKIPPED\"]);\n\nexport function validateStructure(verdict: AuditVerdict): readonly string[] {\n const defects: string[] = [];\n\n if (!verdict.header) {\n defects.push(\"missing required element: <header>\");\n return defects;\n }\n\n if (!verdict.header.spec_node) {\n defects.push(\"missing required element: <spec_node>\");\n }\n\n if (!verdict.header.verdict) {\n defects.push(\"missing required element: <verdict> in <header>\");\n } else if (!VALID_VERDICTS.has(verdict.header.verdict)) {\n defects.push(\n `invalid enum value: verdict \"${verdict.header.verdict}\" is not one of APPROVED, REJECT`,\n );\n }\n\n if (!verdict.header.timestamp) {\n defects.push(\"missing required element: <timestamp>\");\n }\n\n if (verdict.gates.length === 0) {\n defects.push(\"missing required element: at least one <gate> in <gates>\");\n }\n\n for (const gate of verdict.gates) {\n const label = gate.name ? `gate \"${gate.name}\"` : \"gate\";\n\n if (gate.status !== undefined && !VALID_GATE_STATUSES.has(gate.status)) {\n defects.push(\n `invalid enum value: ${label} status \"${gate.status}\" is not one of PASS, FAIL, SKIPPED`,\n );\n }\n\n if (gate.count !== undefined) {\n const declared = parseInt(gate.count, 10);\n const actual = gate.findings.length;\n if (isNaN(declared) || declared !== actual) {\n defects.push(\n `count mismatch: ${label} declares count=\"${gate.count}\" but has ${actual} finding(s)`,\n );\n }\n }\n }\n\n return defects;\n}\n","import { validatePaths } from \"@/audit/paths\";\nimport { readVerdictFile } from \"@/audit/reader\";\nimport { validateSemantics } from \"@/audit/semantic\";\nimport { validateStructure } from \"@/audit/structural\";\n\nexport interface VerifyOutput {\n readonly lines: readonly string[];\n readonly exitCode: 0 | 1;\n readonly verdict?: string;\n}\n\nexport async function runVerifyPipeline(\n filePath: string,\n projectRoot: string,\n): Promise<VerifyOutput> {\n let verdict;\n try {\n verdict = await readVerdictFile(filePath);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { lines: [`reader: ${message}`], exitCode: 1 };\n }\n\n const structuralDefects = validateStructure(verdict);\n if (structuralDefects.length > 0) {\n return { lines: structuralDefects.map((d) => `structural: ${d}`), exitCode: 1 };\n }\n\n const semanticDefects = validateSemantics(verdict);\n if (semanticDefects.length > 0) {\n return { lines: semanticDefects.map((d) => `semantic: ${d}`), exitCode: 1 };\n }\n\n const pathDefects = validatePaths(verdict, projectRoot);\n if (pathDefects.length > 0) {\n return { lines: pathDefects.map((d) => `paths: ${d}`), exitCode: 1 };\n }\n\n return { lines: [], exitCode: 0, verdict: verdict.header?.verdict };\n}\n","import type { Command } from \"commander\";\n\nimport { runVerifyPipeline } from \"@/audit/verify\";\nimport type { Domain } from \"@/domains/types\";\n\nexport async function runVerifyCommand(\n filePath: string,\n projectRoot: string,\n writeLine: (line: string) => void,\n): Promise<0 | 1> {\n const result = await runVerifyPipeline(filePath, projectRoot);\n if (result.exitCode === 0) {\n writeLine(result.verdict ?? \"\");\n } else {\n for (const line of result.lines) {\n writeLine(line);\n }\n }\n return result.exitCode;\n}\n\nexport const auditDomain: Domain = {\n name: \"audit\",\n description: \"Audit verdict verification\",\n register: (program: Command) => {\n const auditCmd = program.command(\"audit\").description(\"Audit verdict verification\");\n\n auditCmd\n .command(\"verify <file>\")\n .description(\"Verify an audit verdict XML file\")\n .action(async (file: string) => {\n const exitCode = await runVerifyCommand(file, process.cwd(), console.log);\n process.exit(exitCode);\n });\n },\n};\n","/**\n * Init command implementation\n *\n * Wrapper around `claude plugin marketplace` to install/update outcomeeng marketplace\n */\nimport { execa } from \"execa\";\n\n/**\n * Options for init command\n */\nexport interface InitOptions {\n /** Working directory (for testing) */\n cwd?: string;\n}\n\n/**\n * Execute claude init command\n *\n * Wraps the Claude CLI's `plugin marketplace` commands to manage\n * the outcomeeng marketplace installation.\n *\n * Behavior:\n * 1. Check if outcomeeng marketplace exists via `claude plugin marketplace list`\n * 2. If missing: shell `claude plugin marketplace add outcomeeng/claude`\n * 3. If exists: shell `claude plugin marketplace update outcomeeng`\n * 4. Parse output and return status message\n *\n * @param options - Command options\n * @returns Status message\n * @throws Error if claude CLI not available or commands fail\n *\n * @example\n * ```typescript\n * const output = await initCommand();\n * console.log(output);\n * // Output: \"✓ outcomeeng marketplace installed successfully\"\n * // or: \"✓ outcomeeng marketplace updated successfully\"\n * ```\n */\nexport async function initCommand(\n options: InitOptions = {},\n): Promise<string> {\n const cwd = options.cwd || process.cwd();\n\n try {\n // Step 1: Check if outcomeeng marketplace exists\n const { stdout: listOutput } = await execa(\n \"claude\",\n [\"plugin\", \"marketplace\", \"list\"],\n { cwd },\n );\n\n const exists = listOutput.includes(\"outcomeeng\");\n\n // Step 2: Add or update based on existence\n if (!exists) {\n // Add marketplace\n await execa(\n \"claude\",\n [\"plugin\", \"marketplace\", \"add\", \"outcomeeng/claude\"],\n { cwd },\n );\n\n return \"✓ outcomeeng marketplace installed successfully\\n\\nRun 'claude plugin marketplace list' to view all marketplaces.\";\n } else {\n // Update marketplace\n await execa(\"claude\", [\"plugin\", \"marketplace\", \"update\", \"outcomeeng\"], {\n cwd,\n });\n\n return \"✓ outcomeeng marketplace updated successfully\\n\\nThe marketplace is now up to date.\";\n }\n } catch (error) {\n if (error instanceof Error) {\n // Check for specific error conditions\n if (\n error.message.includes(\"ENOENT\")\n || error.message.includes(\"command not found\")\n ) {\n throw new Error(\n \"Claude CLI not found. Please install Claude Code first.\\n\\nVisit: https://docs.anthropic.com/claude-code\",\n );\n }\n\n throw new Error(`Failed to initialize marketplace: ${error.message}`);\n }\n throw error;\n }\n}\n","/**\n * Consolidate command implementation\n *\n * Orchestrates the full consolidation pipeline:\n * 1. Discovery - Find all settings.local.json files\n * 2. Parsing - Extract permissions from each file\n * 3. Merging - Combine with subsumption and conflict resolution\n * 4. Backup - Create timestamped backup (if not dry-run)\n * 5. Writing - Atomically write merged settings (if not dry-run)\n * 6. Reporting - Format and return result summary\n */\nimport os from \"os\";\nimport path from \"path\";\nimport { findSettingsFiles } from \"../../../lib/claude/permissions/discovery.js\";\nimport { mergePermissions } from \"../../../lib/claude/permissions/merger.js\";\nimport { parseAllSettings, parseSettingsFile } from \"../../../lib/claude/permissions/parser.js\";\nimport { createBackup } from \"../../../lib/claude/settings/backup.js\";\nimport { formatReport } from \"../../../lib/claude/settings/reporter.js\";\nimport { writeSettings } from \"../../../lib/claude/settings/writer.js\";\n\n/**\n * Options for consolidate command\n */\nexport interface ConsolidateOptions {\n /** Root directory to scan for settings files (default: ~/Code) */\n root?: string;\n /** Write changes to global settings file (default: false = preview only) */\n write?: boolean;\n /** Write merged settings to specified file instead of global settings */\n outputFile?: string;\n /** Path to global settings file (for testing; default: ~/.claude/settings.json) */\n globalSettings?: string;\n}\n\n/**\n * Execute settings consolidate command\n *\n * Consolidates permissions from project-local settings files into\n * the global Claude Code settings file.\n *\n * Features:\n * - Discovers all `.claude/settings.local.json` files recursively\n * - Applies subsumption to remove narrower permissions\n * - Resolves conflicts (deny wins over allow)\n * - Deduplicates and sorts permissions\n * - Creates backup before modifications\n * - Supports dry-run mode for preview\n *\n * @param options - Command options\n * @returns Formatted report string\n * @throws Error if discovery, parsing, or writing fails\n *\n * @example\n * ```typescript\n * // Normal consolidation\n * const output = await consolidateCommand({ root: \"~/Code\" });\n * console.log(output);\n *\n * // Dry-run preview\n * const preview = await consolidateCommand({ root: \"~/Code\", dryRun: true });\n * console.log(preview);\n * ```\n */\nexport async function consolidateCommand(\n options: ConsolidateOptions = {},\n): Promise<string> {\n // Resolve paths\n const root = options.root\n ? path.resolve(options.root.replace(/^~/, os.homedir()))\n : path.join(os.homedir(), \"Code\");\n\n const globalSettingsPath = options.globalSettings\n || path.join(os.homedir(), \".claude\", \"settings.json\");\n\n const shouldWrite = options.write || false;\n const outputFile = options.outputFile;\n const previewOnly = !shouldWrite && !outputFile;\n\n // Step 1: Discovery - find all settings.local.json files\n const settingsFiles = await findSettingsFiles(root);\n\n if (settingsFiles.length === 0) {\n return `No settings files found in ${root}\\n\\nSearched for: **/.claude/settings.local.json`;\n }\n\n // Step 2: Parsing - extract permissions from each file\n const localPermissions = await parseAllSettings(settingsFiles);\n\n // Step 3: Read global settings\n let globalSettings = await parseSettingsFile(globalSettingsPath);\n\n // If global settings doesn't exist, create empty structure\n if (!globalSettings) {\n globalSettings = {\n permissions: {\n allow: [],\n deny: [],\n ask: [],\n },\n };\n }\n\n // Ensure permissions object exists\n if (!globalSettings.permissions) {\n globalSettings.permissions = {\n allow: [],\n deny: [],\n ask: [],\n };\n }\n\n // Step 4: Merge with subsumption and conflict resolution\n const { merged, result } = mergePermissions(\n globalSettings.permissions,\n localPermissions,\n );\n\n // Step 5: Backup (only when writing to global settings)\n if (shouldWrite) {\n try {\n result.backupPath = await createBackup(globalSettingsPath);\n } catch (error) {\n // If backup fails because file doesn't exist, that's okay (first time)\n if (error instanceof Error && !error.message.includes(\"not found\")) {\n throw error;\n }\n }\n }\n\n // Step 6: Write (if --write or --output-file specified)\n if (shouldWrite) {\n const updatedSettings = {\n ...globalSettings,\n permissions: merged,\n };\n await writeSettings(globalSettingsPath, updatedSettings);\n } else if (outputFile) {\n const updatedSettings = {\n ...globalSettings,\n permissions: merged,\n };\n const resolvedOutputPath = path.resolve(outputFile.replace(/^~/, os.homedir()));\n await writeSettings(resolvedOutputPath, updatedSettings);\n result.outputPath = resolvedOutputPath;\n }\n\n // Step 7: Report\n return formatReport(result, previewOnly, globalSettingsPath, outputFile);\n}\n","/**\n * Discovery of Claude Code settings files across project directories\n */\nimport fs from \"fs/promises\";\nimport path from \"path\";\n\n/**\n * Recursively find all .claude/settings.local.json files under a root directory\n *\n * Walks the directory tree looking for files matching the pattern:\n * `**\\/.claude/settings.local.json`\n *\n * @param root - Root directory path to start searching from\n * @param visited - Set of visited paths to avoid symlink loops (internal use)\n * @returns Promise resolving to array of absolute paths to settings.local.json files\n * @throws Error if root directory doesn't exist or permission denied\n *\n * @example\n * ```typescript\n * const files = await findSettingsFiles(\"~/Code\");\n * // Returns: [\n * // \"/Users/user/Code/project-a/.claude/settings.local.json\",\n * // \"/Users/user/Code/project-b/.claude/settings.local.json\"\n * // ]\n * ```\n */\nexport async function findSettingsFiles(\n root: string,\n visited: Set<string> = new Set(),\n): Promise<string[]> {\n // Normalize and resolve path to handle symlinks and ~ expansion\n const normalizedRoot = path.resolve(root.replace(/^~/, process.env.HOME || \"~\"));\n\n // Check for symlink loops\n if (visited.has(normalizedRoot)) {\n return []; // Skip already visited directories\n }\n visited.add(normalizedRoot);\n\n try {\n // Stat the root to verify it exists and is a directory\n const stats = await fs.stat(normalizedRoot);\n if (!stats.isDirectory()) {\n throw new Error(`Path is not a directory: ${normalizedRoot}`);\n }\n\n // Read directory contents\n const entries = await fs.readdir(normalizedRoot, { withFileTypes: true });\n const results: string[] = [];\n\n for (const entry of entries) {\n const fullPath = path.join(normalizedRoot, entry.name);\n\n // If this is a .claude directory, check for settings.local.json\n if (entry.isDirectory() && entry.name === \".claude\") {\n const settingsPath = path.join(fullPath, \"settings.local.json\");\n if (await isValidSettingsFile(settingsPath)) {\n results.push(settingsPath);\n }\n }\n\n // Recursively search subdirectories (skip .claude to avoid double-checking)\n if (entry.isDirectory() && entry.name !== \".claude\") {\n const subFiles = await findSettingsFiles(fullPath, visited);\n results.push(...subFiles);\n }\n }\n\n return results;\n } catch (error) {\n // Re-throw with more context\n if (error instanceof Error) {\n if (error.message.includes(\"ENOENT\")) {\n throw new Error(`Directory not found: ${normalizedRoot}`);\n }\n if (error.message.includes(\"EACCES\")) {\n throw new Error(`Permission denied: ${normalizedRoot}`);\n }\n throw new Error(`Failed to search directory \"${normalizedRoot}\": ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Check if a given path is a valid settings.local.json file\n *\n * Validates that:\n * - File exists\n * - File is readable\n * - File has .json extension\n *\n * @param filePath - Absolute path to check\n * @returns Promise resolving to true if valid settings file, false otherwise\n *\n * @example\n * ```typescript\n * const isValid = await isValidSettingsFile(\"/path/to/.claude/settings.local.json\");\n * // Returns: true or false\n * ```\n */\nexport async function isValidSettingsFile(filePath: string): Promise<boolean> {\n try {\n // Check if file exists and is readable\n await fs.access(filePath, fs.constants.R_OK);\n\n // Check if it's actually a file (not a directory)\n const stats = await fs.stat(filePath);\n if (!stats.isFile()) {\n return false;\n }\n\n // Validate it has .json extension\n return path.extname(filePath) === \".json\";\n } catch {\n // File doesn't exist or isn't readable\n return false;\n }\n}\n","/**\n * Parser for Claude Code settings files and permissions\n */\nimport fs from \"fs/promises\";\nimport type { ClaudeSettings, Permission, PermissionCategory, Permissions } from \"./types.js\";\n\n/**\n * Parse a settings.json file and extract permissions\n *\n * Handles:\n * - Malformed JSON (returns null)\n * - Missing permissions object (returns empty permissions)\n * - Validates basic structure\n *\n * @param filePath - Absolute path to settings.json file\n * @returns Promise resolving to ClaudeSettings object, or null if malformed\n *\n * @example\n * ```typescript\n * const settings = await parseSettingsFile(\"/path/to/.claude/settings.json\");\n * if (settings) {\n * console.log(settings.permissions?.allow);\n * }\n * ```\n */\nexport async function parseSettingsFile(filePath: string): Promise<ClaudeSettings | null> {\n try {\n // Read file contents\n const content = await fs.readFile(filePath, \"utf-8\");\n\n // Parse JSON\n const parsed = JSON.parse(content);\n\n // Basic validation: should be an object\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n\n return parsed as ClaudeSettings;\n } catch {\n // JSON parse error or file read error\n return null;\n }\n}\n\n/**\n * Parse a permission string into structured components\n *\n * Permission format: \"Type(scope)\"\n * Examples:\n * - \"Bash(git:*)\" => { type: \"Bash\", scope: \"git:*\" }\n * - \"Read(file_path:/Users/user/Code/**)\" => { type: \"Read\", scope: \"file_path:/Users/user/Code/**\" }\n * - \"WebFetch(domain:github.com)\" => { type: \"WebFetch\", scope: \"domain:github.com\" }\n *\n * @param raw - Raw permission string\n * @param category - Permission category (allow/deny/ask)\n * @returns Parsed Permission object\n * @throws Error if permission string is malformed\n *\n * @example\n * ```typescript\n * const perm = parsePermission(\"Bash(git:*)\", \"allow\");\n * // Returns: { raw: \"Bash(git:*)\", type: \"Bash\", scope: \"git:*\", category: \"allow\" }\n * ```\n */\nexport function parsePermission(raw: string, category: PermissionCategory): Permission {\n // Match pattern: Type(scope)\n const match = raw.match(/^([^(]+)\\((.+)\\)$/);\n\n if (!match) {\n throw new Error(`Malformed permission string: \"${raw}\"`);\n }\n\n const [, type, scope] = match;\n\n return {\n raw,\n type: type.trim(),\n scope: scope.trim(),\n category,\n };\n}\n\n/**\n * Parse all permissions from a Permissions object\n *\n * Converts permission strings to structured Permission objects,\n * grouped by category (allow/deny/ask).\n *\n * @param permissions - Permissions object from settings.json\n * @returns Array of parsed Permission objects\n *\n * @example\n * ```typescript\n * const permissions = {\n * allow: [\"Bash(git:*)\", \"Bash(npm:*)\"],\n * deny: [\"Bash(rm -rf:*)\"]\n * };\n * const parsed = parseAllPermissions(permissions);\n * // Returns array of Permission objects with category set\n * ```\n */\nexport function parseAllPermissions(permissions: Permissions): Permission[] {\n const result: Permission[] = [];\n\n // Parse allow permissions\n if (permissions.allow) {\n for (const perm of permissions.allow) {\n try {\n result.push(parsePermission(perm, \"allow\"));\n } catch {\n // Skip malformed permissions\n continue;\n }\n }\n }\n\n // Parse deny permissions\n if (permissions.deny) {\n for (const perm of permissions.deny) {\n try {\n result.push(parsePermission(perm, \"deny\"));\n } catch {\n // Skip malformed permissions\n continue;\n }\n }\n }\n\n // Parse ask permissions\n if (permissions.ask) {\n for (const perm of permissions.ask) {\n try {\n result.push(parsePermission(perm, \"ask\"));\n } catch {\n // Skip malformed permissions\n continue;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Read and parse multiple settings files\n *\n * Processes an array of file paths, reading and parsing each one.\n * Skips files that can't be read or parsed.\n *\n * @param filePaths - Array of absolute paths to settings files\n * @returns Promise resolving to array of Permissions objects (one per valid file)\n *\n * @example\n * ```typescript\n * const files = [\n * \"/Users/user/Code/project-a/.claude/settings.local.json\",\n * \"/Users/user/Code/project-b/.claude/settings.local.json\"\n * ];\n * const allPermissions = await parseAllSettings(files);\n * // Returns: [{ allow: [...], deny: [...] }, { allow: [...] }]\n * ```\n */\nexport async function parseAllSettings(filePaths: string[]): Promise<Permissions[]> {\n const results: Permissions[] = [];\n\n for (const filePath of filePaths) {\n const settings = await parseSettingsFile(filePath);\n if (settings?.permissions) {\n results.push(settings.permissions);\n }\n }\n\n return results;\n}\n","/**\n * Directory walking and filesystem traversal\n */\nimport fs from \"fs/promises\";\nimport path from \"path\";\nimport type { DirectoryEntry, WorkItem } from \"../types.js\";\nimport { parseWorkItemName } from \"./patterns.js\";\n\n/**\n * Recursively walk a directory tree and return all subdirectories\n *\n * @param root - Root directory path to start walking from\n * @param visited - Set of visited paths to avoid symlink loops (internal use)\n * @returns Promise resolving to array of directory entries\n * @throws Error if root directory doesn't exist or permission denied\n *\n * @example\n * ```typescript\n * const entries = await walkDirectory(\"/path/to/specs\");\n * // Returns: [{ name: \"capability-21_test\", path: \"/path/to/specs/capability-21_test\", isDirectory: true }, ...]\n * ```\n */\nexport async function walkDirectory(\n root: string,\n visited: Set<string> = new Set(),\n): Promise<DirectoryEntry[]> {\n // Normalize and resolve path to handle symlinks\n const normalizedRoot = path.resolve(root);\n\n // Check for symlink loops\n if (visited.has(normalizedRoot)) {\n return []; // Skip already visited directories\n }\n visited.add(normalizedRoot);\n\n try {\n // Read directory contents\n const entries = await fs.readdir(normalizedRoot, { withFileTypes: true });\n const results: DirectoryEntry[] = [];\n\n for (const entry of entries) {\n const fullPath = path.join(normalizedRoot, entry.name);\n\n // Only process directories\n if (entry.isDirectory()) {\n // Add current directory\n results.push({\n name: entry.name,\n path: fullPath,\n isDirectory: true,\n });\n\n // Recursively walk subdirectories\n const subEntries = await walkDirectory(fullPath, visited);\n results.push(...subEntries);\n }\n }\n\n return results;\n } catch (error) {\n // Re-throw with more context\n if (error instanceof Error) {\n throw new Error(\n `Failed to walk directory \"${normalizedRoot}\": ${error.message}`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Filter directory entries to include only work item directories\n *\n * Uses parseWorkItemName() to validate directory names match work item patterns.\n * Excludes directories that don't match capability/feature/story patterns.\n *\n * @param entries - Array of directory entries to filter\n * @returns Filtered array containing only valid work item directories\n *\n * @example\n * ```typescript\n * const entries = [\n * { name: \"capability-21_test\", path: \"/specs/capability-21_test\", isDirectory: true },\n * { name: \"node_modules\", path: \"/specs/node_modules\", isDirectory: true },\n * ];\n * const filtered = filterWorkItemDirectories(entries);\n * // Returns: [{ name: \"capability-21_test\", ... }]\n * ```\n */\nexport function filterWorkItemDirectories(\n entries: DirectoryEntry[],\n): DirectoryEntry[] {\n return entries.filter((entry) => {\n try {\n // Try to parse the directory name as a work item\n parseWorkItemName(entry.name);\n return true; // Valid work item pattern\n } catch {\n return false; // Not a work item pattern\n }\n });\n}\n\n/**\n * Convert directory entries to WorkItem objects\n *\n * Parses each directory entry name to extract work item metadata (kind, number, slug)\n * and combines it with the full filesystem path.\n *\n * @param entries - Filtered directory entries (work items only)\n * @returns Array of WorkItem objects with full metadata\n * @throws Error if any entry has invalid work item pattern\n *\n * @example\n * ```typescript\n * const entries = [\n * { name: \"capability-21_core-cli\", path: \"/specs/capability-21_core-cli\", isDirectory: true },\n * ];\n * const workItems = buildWorkItemList(entries);\n * // Returns: [{ kind: \"capability\", number: 20, slug: \"core-cli\", path: \"/specs/capability-21_core-cli\" }]\n * ```\n */\nexport function buildWorkItemList(entries: DirectoryEntry[]): WorkItem[] {\n return entries.map((entry) => ({\n ...parseWorkItemName(entry.name),\n path: entry.path,\n }));\n}\n\n/**\n * Normalize path separators for cross-platform consistency\n *\n * Converts Windows backslashes to forward slashes for consistent path handling\n * across different operating systems.\n *\n * @param filepath - Path to normalize\n * @returns Normalized path with forward slashes\n *\n * @example\n * ```typescript\n * normalizePath(\"C:\\\\Users\\\\test\\\\specs\"); // Returns: \"C:/Users/test/specs\"\n * normalizePath(\"/home/user/specs\"); // Returns: \"/home/user/specs\"\n * ```\n */\nexport function normalizePath(filepath: string): string {\n // Replace all backslashes with forward slashes for cross-platform consistency\n return filepath.replace(/\\\\/g, \"/\");\n}\n","/**\n * Permission subsumption detection\n *\n * Detects when broader permissions subsume narrower ones:\n * - Bash(git:*) subsumes Bash(git log:*), Bash(git worktree:*), etc.\n * - Read(file_path:/Users/user/Code/**) subsumes Read(file_path:/Users/user/Code/project-a/**)\n */\nimport { normalizePath } from \"../../../scanner/walk.js\";\nimport { parsePermission } from \"./parser.js\";\nimport type { Permission, PermissionCategory, ScopePattern, SubsumptionResult } from \"./types.js\";\n\n/**\n * Parse a scope string to extract pattern type and value\n *\n * Determines whether the scope is a command pattern (e.g., \"git:*\")\n * or a path pattern (e.g., \"file_path:/Users/user/Code/**\").\n *\n * @param scope - Scope string from permission\n * @returns ScopePattern with type and pattern\n *\n * @example\n * ```typescript\n * parseScopePattern(\"git:*\")\n * // Returns: { type: \"command\", pattern: \"git:*\" }\n *\n * parseScopePattern(\"file_path:/Users/user/Code/**\")\n * // Returns: { type: \"path\", pattern: \"/Users/user/Code/**\" }\n * ```\n */\nexport function parseScopePattern(scope: string): ScopePattern {\n // Check if scope contains path indicators\n if (\n scope.includes(\"file_path:\") ||\n scope.includes(\"directory_path:\") ||\n scope.includes(\"path:\")\n ) {\n // Extract path after the colon\n const colonIndex = scope.indexOf(\":\");\n const pattern = colonIndex >= 0 ? scope.substring(colonIndex + 1) : scope;\n return { type: \"path\", pattern };\n }\n\n // Default to command pattern (e.g., \"git:*\", \"npm:*\")\n return { type: \"command\", pattern: scope };\n}\n\n/**\n * Check if permission A subsumes permission B\n *\n * Subsumption rules:\n * 1. Same type required (Bash subsumes Bash, not Read)\n * 2. Identical scopes = not subsumption (exact match)\n * 3. Broader scope subsumes narrower scope:\n * - Command: \"git:*\" subsumes \"git log:*\", \"git worktree:*\"\n * - Path: \"/Users/user/Code/**\" subsumes \"/Users/user/Code/project-a/**\"\n *\n * @param broader - Permission that might subsume the other\n * @param narrower - Permission that might be subsumed\n * @returns true if broader subsumes narrower, false otherwise\n *\n * @example\n * ```typescript\n * subsumes(\n * parsePermission(\"Bash(git:*)\", \"allow\"),\n * parsePermission(\"Bash(git log:*)\", \"allow\")\n * )\n * // Returns: true\n *\n * subsumes(\n * parsePermission(\"Read(file_path:/Users/user/Code/**)\", \"allow\"),\n * parsePermission(\"Read(file_path:/Users/user/Code/project-a/**)\", \"allow\")\n * )\n * // Returns: true\n *\n * subsumes(\n * parsePermission(\"Bash(git:*)\", \"allow\"),\n * parsePermission(\"Read(file_path:/Users/user/Code/**)\", \"allow\")\n * )\n * // Returns: false (different types)\n * ```\n */\nexport function subsumes(broader: Permission, narrower: Permission): boolean {\n // 1. Type must match\n if (broader.type !== narrower.type) {\n return false;\n }\n\n // 2. Identical = not subsumption (this is just a duplicate)\n if (broader.scope === narrower.scope) {\n return false;\n }\n\n // 3. Parse scope patterns\n const broaderScope = parseScopePattern(broader.scope);\n const narrowerScope = parseScopePattern(narrower.scope);\n\n // 4. Handle command patterns (e.g., \"git:*\")\n if (broaderScope.type === \"command\" && narrowerScope.type === \"command\") {\n // Extract base command by removing :* suffix\n const broaderBase = broaderScope.pattern.replace(/:?\\*+$/, \"\");\n const narrowerFull = narrowerScope.pattern.replace(/:?\\*+$/, \"\");\n\n // Check if narrower starts with broader prefix\n // \"git:*\" subsumes \"git log:*\" if:\n // - narrowerFull starts with broaderBase\n // - narrowerFull is longer (more specific)\n if (narrowerFull.startsWith(broaderBase)) {\n // Additional specificity check: narrower must add more detail\n // e.g., \"git\" subsumes \"git log\", but not \"git\" subsumes \"git\"\n return narrowerFull.length > broaderBase.length;\n }\n }\n\n // 5. Handle path patterns (e.g., \"/Users/user/Code/**\")\n if (broaderScope.type === \"path\" && narrowerScope.type === \"path\") {\n // Normalize paths for comparison\n const broaderPath = normalizePath(broaderScope.pattern.replace(/\\/?\\*+$/, \"\"));\n const narrowerPath = normalizePath(narrowerScope.pattern.replace(/\\/?\\*+$/, \"\"));\n\n // Check if narrower is a sub-path of broader\n // \"/Users/user/Code\" subsumes \"/Users/user/Code/project-a\" if:\n // - narrowerPath starts with broaderPath + \"/\"\n return narrowerPath.startsWith(broaderPath + \"/\");\n }\n\n // 6. Mixed pattern types don't subsume each other\n return false;\n}\n\n/**\n * Find all subsumption relationships in a permission list\n *\n * Returns a map of broader permissions to the narrower permissions\n * they subsume. This allows identifying which permissions can be\n * removed from the list.\n *\n * @param permissions - Array of permissions to analyze\n * @returns Array of subsumption results\n *\n * @example\n * ```typescript\n * const permissions = [\n * parsePermission(\"Bash(git:*)\", \"allow\"),\n * parsePermission(\"Bash(git log:*)\", \"allow\"),\n * parsePermission(\"Bash(git worktree:*)\", \"allow\"),\n * parsePermission(\"Bash(npm:*)\", \"allow\"),\n * ];\n *\n * const results = detectSubsumptions(permissions);\n * // Returns: [\n * // {\n * // broader: { raw: \"Bash(git:*)\", ... },\n * // narrower: [\n * // { raw: \"Bash(git log:*)\", ... },\n * // { raw: \"Bash(git worktree:*)\", ... }\n * // ]\n * // }\n * // ]\n * ```\n */\nexport function detectSubsumptions(permissions: Permission[]): SubsumptionResult[] {\n const results: SubsumptionResult[] = [];\n const processedBroader = new Set<string>();\n\n for (let i = 0; i < permissions.length; i++) {\n const broader = permissions[i];\n\n // Skip if already processed as a broader permission\n if (processedBroader.has(broader.raw)) {\n continue;\n }\n\n const narrowerPerms: Permission[] = [];\n\n // Check all other permissions to see if this one subsumes them\n for (let j = 0; j < permissions.length; j++) {\n if (i === j) continue; // Skip comparing with self\n\n const narrower = permissions[j];\n\n if (subsumes(broader, narrower)) {\n narrowerPerms.push(narrower);\n }\n }\n\n // If this permission subsumes others, record it\n if (narrowerPerms.length > 0) {\n results.push({\n broader,\n narrower: narrowerPerms,\n });\n processedBroader.add(broader.raw);\n }\n }\n\n return results;\n}\n\n/**\n * Remove subsumed permissions from a list, keeping only the broadest ones\n *\n * This is the main function for consolidating permissions.\n * It finds all subsumption relationships and removes narrower\n * permissions, leaving only the broadest ones.\n *\n * @param permissionStrings - Array of raw permission strings\n * @param category - Permission category (for parsing)\n * @returns Array of permission strings with subsumed ones removed\n *\n * @example\n * ```typescript\n * const permissions = [\n * \"Bash(git:*)\",\n * \"Bash(git log:*)\",\n * \"Bash(git worktree:*)\",\n * \"Bash(npm:*)\",\n * ];\n *\n * const result = removeSubsumed(permissions, \"allow\");\n * // Returns: [\"Bash(git:*)\", \"Bash(npm:*)\"]\n * ```\n */\nexport function removeSubsumed(\n permissionStrings: string[],\n category: PermissionCategory,\n): string[] {\n // Parse all permission strings\n const permissions = permissionStrings\n .map((raw) => {\n try {\n return parsePermission(raw, category);\n } catch {\n // Keep malformed permissions as-is (don't filter them out)\n return null;\n }\n })\n .filter((p): p is Permission => p !== null);\n\n // Detect subsumptions\n const subsumptions = detectSubsumptions(permissions);\n\n // Build set of narrower permissions to remove\n const toRemove = new Set<string>();\n for (const result of subsumptions) {\n for (const narrower of result.narrower) {\n toRemove.add(narrower.raw);\n }\n }\n\n // Filter out subsumed permissions\n return permissionStrings.filter((perm) => !toRemove.has(perm));\n}\n","/**\n * Permission merging with subsumption and conflict resolution\n */\nimport { parsePermission } from \"./parser.js\";\nimport { removeSubsumed, subsumes } from \"./subsumption.js\";\nimport type { ConsolidationResult, Permissions, PermissionsAdded } from \"./types.js\";\n\n/**\n * Merge permissions from global settings and multiple local settings files\n *\n * Process:\n * 1. Combine all permissions by category (allow/deny/ask)\n * 2. Apply subsumption to remove narrower permissions\n * 3. Resolve conflicts (deny wins over allow)\n * 4. Deduplicate using Sets\n * 5. Sort alphabetically\n *\n * @param global - Global settings permissions (baseline)\n * @param local - Array of local settings permissions to merge in\n * @returns Merged permissions and consolidation statistics\n *\n * @example\n * ```typescript\n * const global = { allow: [\"Bash(ls:*)\"] };\n * const local = [\n * { allow: [\"Bash(git:*)\", \"Bash(git log:*)\"] },\n * { deny: [\"Bash(rm:*)\"] }\n * ];\n *\n * const { merged, result } = mergePermissions(global, local);\n * // merged.allow: [\"Bash(git:*)\", \"Bash(ls:*)\"] // git log:* removed by subsumption\n * // merged.deny: [\"Bash(rm:*)\"]\n * // result.subsumed: [\"Bash(git log:*)\"]\n * ```\n */\nexport function mergePermissions(\n global: Permissions,\n local: Permissions[],\n): { merged: Permissions; result: ConsolidationResult } {\n // Track original global permissions for computing added\n const originalGlobal = {\n allow: new Set(global.allow || []),\n deny: new Set(global.deny || []),\n ask: new Set(global.ask || []),\n };\n\n // Step 1: Combine all permissions by category\n const combined: Permissions = {\n allow: [...(global.allow || [])],\n deny: [...(global.deny || [])],\n ask: [...(global.ask || [])],\n };\n\n let filesProcessed = 0;\n let filesSkipped = 0;\n\n for (const localPerms of local) {\n let hasPerms = false;\n\n if (localPerms.allow && localPerms.allow.length > 0) {\n combined.allow?.push(...localPerms.allow);\n hasPerms = true;\n }\n if (localPerms.deny && localPerms.deny.length > 0) {\n combined.deny?.push(...localPerms.deny);\n hasPerms = true;\n }\n if (localPerms.ask && localPerms.ask.length > 0) {\n combined.ask?.push(...localPerms.ask);\n hasPerms = true;\n }\n\n if (hasPerms) {\n filesProcessed++;\n } else {\n filesSkipped++;\n }\n }\n\n // Step 2: Apply subsumption to each category\n const allSubsumed: string[] = [];\n\n const afterSubsumption: Permissions = {};\n\n if (combined.allow && combined.allow.length > 0) {\n const before = new Set(combined.allow);\n combined.allow = removeSubsumed(combined.allow, \"allow\");\n const after = new Set(combined.allow);\n\n // Track what was removed\n for (const perm of before) {\n if (!after.has(perm)) {\n allSubsumed.push(perm);\n }\n }\n }\n\n if (combined.deny && combined.deny.length > 0) {\n const before = new Set(combined.deny);\n combined.deny = removeSubsumed(combined.deny, \"deny\");\n const after = new Set(combined.deny);\n\n // Track what was removed\n for (const perm of before) {\n if (!after.has(perm)) {\n allSubsumed.push(perm);\n }\n }\n }\n\n if (combined.ask && combined.ask.length > 0) {\n const before = new Set(combined.ask);\n combined.ask = removeSubsumed(combined.ask, \"ask\");\n const after = new Set(combined.ask);\n\n // Track what was removed\n for (const perm of before) {\n if (!after.has(perm)) {\n allSubsumed.push(perm);\n }\n }\n }\n\n afterSubsumption.allow = combined.allow;\n afterSubsumption.deny = combined.deny;\n afterSubsumption.ask = combined.ask;\n\n // Step 3: Resolve conflicts (deny wins over allow)\n const {\n resolved,\n conflictCount,\n subsumed: conflictSubsumed,\n } = resolveConflicts(afterSubsumption);\n\n // Combine subsumptions from step 2 and step 3\n const subsumed = [...allSubsumed, ...conflictSubsumed];\n\n // Step 4: Deduplicate using Sets and sort\n const merged: Permissions = {};\n\n if (resolved.allow && resolved.allow.length > 0) {\n merged.allow = Array.from(new Set(resolved.allow)).sort();\n }\n\n if (resolved.deny && resolved.deny.length > 0) {\n merged.deny = Array.from(new Set(resolved.deny)).sort();\n }\n\n if (resolved.ask && resolved.ask.length > 0) {\n merged.ask = Array.from(new Set(resolved.ask)).sort();\n }\n\n // Step 5: Compute what was added\n const added: PermissionsAdded = {\n allow: [],\n deny: [],\n ask: [],\n };\n\n for (const perm of merged.allow || []) {\n if (!originalGlobal.allow.has(perm)) {\n added.allow.push(perm);\n }\n }\n\n for (const perm of merged.deny || []) {\n if (!originalGlobal.deny.has(perm)) {\n added.deny.push(perm);\n }\n }\n\n for (const perm of merged.ask || []) {\n if (!originalGlobal.ask.has(perm)) {\n added.ask.push(perm);\n }\n }\n\n // Build result\n const result: ConsolidationResult = {\n filesScanned: local.length,\n filesProcessed,\n filesSkipped,\n added,\n subsumed,\n conflictsResolved: conflictCount,\n };\n\n return { merged, result };\n}\n\n/**\n * Resolve conflicts between allow and deny permissions\n *\n * Rules:\n * - If exact match in both allow and deny: keep in deny, remove from allow\n * - If deny has broader permission that subsumes allow: remove from allow\n *\n * This implements a security-first approach: deny always wins.\n *\n * @param permissions - Permissions with potential conflicts\n * @returns Resolved permissions with conflicts removed, count of conflicts, and list of subsumed permissions\n *\n * @example\n * ```typescript\n * const permissions = {\n * allow: [\"Bash(git log:*)\", \"Bash(npm:*)\"],\n * deny: [\"Bash(git:*)\"]\n * };\n *\n * const { resolved, conflictCount } = resolveConflicts(permissions);\n * // resolved.allow: [\"Bash(npm:*)\"] // git log:* removed (subsumed by deny git:*)\n * // resolved.deny: [\"Bash(git:*)\"]\n * // conflictCount: 1\n * ```\n */\nexport function resolveConflicts(permissions: Permissions): {\n resolved: Permissions;\n conflictCount: number;\n subsumed: string[];\n} {\n const allow = permissions.allow || [];\n const deny = permissions.deny || [];\n const ask = permissions.ask || [];\n\n const denySet = new Set(deny);\n const subsumed: string[] = [];\n let conflictCount = 0;\n\n // Check each allow permission against deny permissions\n const allowToRemove = new Set<string>();\n\n for (const allowPerm of allow) {\n // Exact match: move to deny\n if (denySet.has(allowPerm)) {\n allowToRemove.add(allowPerm);\n conflictCount++;\n continue;\n }\n\n // Check if any deny permission subsumes this allow permission\n for (const denyPerm of deny) {\n try {\n const allowParsed = parsePermission(allowPerm, \"allow\");\n const denyParsed = parsePermission(denyPerm, \"deny\");\n\n if (subsumes(denyParsed, allowParsed)) {\n // Deny subsumes allow - remove from allow\n allowToRemove.add(allowPerm);\n subsumed.push(allowPerm);\n conflictCount++;\n break;\n }\n } catch {\n // Skip malformed permissions\n continue;\n }\n }\n }\n\n // Build resolved permissions\n const resolved: Permissions = {\n allow: allow.filter((p) => !allowToRemove.has(p)),\n deny,\n ask,\n };\n\n return { resolved, conflictCount, subsumed };\n}\n","/**\n * Backup management for Claude Code settings files\n */\nimport fs from \"fs/promises\";\n\n/**\n * Create a timestamped backup of a settings file\n *\n * Backup format: `<original-path>.backup.YYYY-MM-DD-HHmmss`\n *\n * Example: `settings.json.backup.2026-01-08-143022`\n *\n * @param settingsPath - Absolute path to settings file to back up\n * @returns Promise resolving to backup file path\n * @throws Error if source file doesn't exist or backup fails\n *\n * @example\n * ```typescript\n * const backupPath = await createBackup(\"/Users/shz/.claude/settings.json\");\n * // Returns: \"/Users/shz/.claude/settings.json.backup.2026-01-08-143022\"\n * ```\n */\nexport async function createBackup(settingsPath: string): Promise<string> {\n try {\n // Verify source file exists\n await fs.access(settingsPath, fs.constants.R_OK);\n\n // Generate timestamp: YYYY-MM-DD-HHmmss\n const now = new Date();\n const timestamp = [\n now.getFullYear(),\n String(now.getMonth() + 1).padStart(2, \"0\"),\n String(now.getDate()).padStart(2, \"0\"),\n ].join(\"-\") + \"-\" + [\n String(now.getHours()).padStart(2, \"0\"),\n String(now.getMinutes()).padStart(2, \"0\"),\n String(now.getSeconds()).padStart(2, \"0\"),\n ].join(\"\");\n\n // Build backup path\n const backupPath = `${settingsPath}.backup.${timestamp}`;\n\n // Copy file to backup location\n await fs.copyFile(settingsPath, backupPath);\n\n return backupPath;\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes(\"ENOENT\")) {\n throw new Error(`Settings file not found: ${settingsPath}`);\n }\n if (error.message.includes(\"EACCES\")) {\n throw new Error(`Permission denied: ${settingsPath}`);\n }\n throw new Error(`Failed to create backup: ${error.message}`);\n }\n throw error;\n }\n}\n","/**\n * Formatting and reporting of consolidation results\n */\nimport type { ConsolidationResult } from \"../permissions/types.js\";\n\n/**\n * Format consolidation result as user-friendly text report\n *\n * Shows:\n * - Files scanned/processed/skipped\n * - Permissions added by category (allow/deny/ask)\n * - Conflicts resolved\n * - Subsumed permissions removed\n * - Backup path (if created)\n * - Instructions (if preview mode) or confirmation (if written)\n *\n * @param result - Consolidation result data\n * @param previewOnly - Whether this is preview-only mode (default behavior)\n * @param globalSettingsPath - Path to global settings file\n * @param outputFile - Optional output file path\n * @returns Formatted report string\n *\n * @example\n * ```typescript\n * const result = {\n * filesScanned: 12,\n * filesProcessed: 10,\n * filesSkipped: 2,\n * added: {\n * allow: [\"Bash(git:*)\", \"Bash(npm:*)\"],\n * deny: [\"Bash(rm:*)\"],\n * ask: []\n * },\n * subsumed: [\"Bash(git log:*)\", \"Bash(git worktree:*)\"],\n * conflictsResolved: 1,\n * backupPath: \"/Users/shz/.claude/settings.json.backup.2026-01-08-143022\"\n * };\n *\n * console.log(formatReport(result, true, \"/Users/shz/.claude/settings.json\"));\n * // Outputs formatted report with instructions\n * ```\n */\nexport function formatReport(\n result: ConsolidationResult,\n previewOnly: boolean,\n globalSettingsPath?: string,\n outputFile?: string,\n): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"Scanning for Claude Code settings files...\");\n lines.push(\"\");\n\n // Files summary\n lines.push(`Found ${result.filesScanned} settings files`);\n lines.push(` Processed: ${result.filesProcessed}`);\n if (result.filesSkipped > 0) {\n lines.push(` Skipped: ${result.filesSkipped} (no permissions)`);\n }\n lines.push(\"\");\n\n // Permissions added\n const totalAdded = result.added.allow.length\n + result.added.deny.length\n + result.added.ask.length;\n\n if (totalAdded > 0) {\n lines.push(`Permissions to add: ${totalAdded}`);\n\n if (result.added.allow.length > 0) {\n lines.push(\"\");\n lines.push(\" allow:\");\n for (const perm of result.added.allow) {\n lines.push(` + ${perm}`);\n }\n }\n\n if (result.added.deny.length > 0) {\n lines.push(\"\");\n lines.push(\" deny:\");\n for (const perm of result.added.deny) {\n lines.push(` + ${perm}`);\n }\n }\n\n if (result.added.ask.length > 0) {\n lines.push(\"\");\n lines.push(\" ask:\");\n for (const perm of result.added.ask) {\n lines.push(` + ${perm}`);\n }\n }\n } else {\n lines.push(\"No new permissions to add (all permissions already in global settings)\");\n }\n\n lines.push(\"\");\n\n // Subsumption results\n if (result.subsumed.length > 0) {\n lines.push(`Subsumed permissions removed: ${result.subsumed.length}`);\n lines.push(\" (narrower permissions replaced by broader ones)\");\n for (const perm of result.subsumed) {\n lines.push(` - ${perm}`);\n }\n lines.push(\"\");\n }\n\n // Conflicts\n if (result.conflictsResolved > 0) {\n lines.push(`Conflicts resolved: ${result.conflictsResolved}`);\n lines.push(\" (permissions moved from allow to deny)\");\n lines.push(\"\");\n }\n\n // Backup\n if (result.backupPath) {\n lines.push(`Backup created: ${result.backupPath}`);\n lines.push(\"\");\n }\n\n // Summary\n lines.push(\"Summary:\");\n lines.push(` Files scanned: ${result.filesScanned}`);\n lines.push(\n ` Permissions added: ${result.added.allow.length} allow, ${result.added.deny.length} deny, ${result.added.ask.length} ask`,\n );\n if (result.subsumed.length > 0) {\n lines.push(` Subsumed removed: ${result.subsumed.length}`);\n }\n if (result.conflictsResolved > 0) {\n lines.push(` Conflicts resolved: ${result.conflictsResolved}`);\n }\n\n // Final status message\n lines.push(\"\");\n if (previewOnly) {\n lines.push(\"ℹ️ Preview mode: No changes written\");\n lines.push(\"\");\n lines.push(\"To apply changes:\");\n lines.push(` • Modify global settings: spx claude settings consolidate --write`);\n lines.push(` • Write to file: spx claude settings consolidate --output-file /path/to/file`);\n } else if (outputFile) {\n lines.push(`✓ Settings written to: ${result.outputPath || outputFile}`);\n lines.push(\"\");\n lines.push(\"To apply to your global settings:\");\n lines.push(` • Review the file, then copy to: ${globalSettingsPath || \"~/.claude/settings.json\"}`);\n lines.push(` • Or run: spx claude settings consolidate --write`);\n } else {\n lines.push(`✓ Global settings updated: ${globalSettingsPath || \"~/.claude/settings.json\"}`);\n }\n\n return lines.join(\"\\n\");\n}\n","/**\n * Atomic file writing for Claude Code settings\n */\nimport fs from \"fs/promises\";\nimport os from \"os\";\nimport path from \"path\";\nimport type { ClaudeSettings } from \"../permissions/types.js\";\n\n/**\n * Filesystem abstraction for dependency injection\n *\n * Enables testing error paths without mocking.\n */\nexport interface FileSystem {\n writeFile(path: string, content: string): Promise<void>;\n rename(oldPath: string, newPath: string): Promise<void>;\n unlink(path: string): Promise<void>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n}\n\n/**\n * Production filesystem implementation\n */\nconst realFs: FileSystem = {\n writeFile: (path, content) => fs.writeFile(path, content, \"utf-8\"),\n rename: fs.rename,\n unlink: fs.unlink,\n mkdir: async (path, options) => {\n await fs.mkdir(path, options);\n },\n};\n\n/**\n * Atomically write settings to a file\n *\n * Uses temp file + rename pattern for atomicity:\n * 1. Write to temporary file\n * 2. Rename to target (atomic operation on most filesystems)\n *\n * Preserves JSON formatting with 2-space indentation.\n *\n * @param filePath - Absolute path to settings file\n * @param settings - Settings object to write\n * @param deps - Dependencies (for testing)\n * @throws Error if write fails\n *\n * @example\n * ```typescript\n * const settings = {\n * permissions: {\n * allow: [\"Bash(git:*)\", \"Bash(npm:*)\"]\n * }\n * };\n * await writeSettings(\"/Users/shz/.claude/settings.json\", settings);\n * ```\n */\nexport async function writeSettings(\n filePath: string,\n settings: ClaudeSettings,\n deps: { fs: FileSystem } = { fs: realFs },\n): Promise<void> {\n // Ensure directory exists\n const dir = path.dirname(filePath);\n await deps.fs.mkdir(dir, { recursive: true });\n\n // Generate temporary file path\n const tempPath = path.join(\n os.tmpdir(),\n `settings-${Date.now()}-${Math.random().toString(36).substring(7)}.json`,\n );\n\n try {\n // Format JSON with 2-space indentation and trailing newline\n const content = JSON.stringify(settings, null, 2) + \"\\n\";\n\n // Write to temp file\n await deps.fs.writeFile(tempPath, content);\n\n // Atomic rename\n await deps.fs.rename(tempPath, filePath);\n } catch (error) {\n // Cleanup temp file on failure\n try {\n await deps.fs.unlink(tempPath);\n } catch {\n // Ignore cleanup errors\n }\n\n // Re-throw original error\n if (error instanceof Error) {\n throw new Error(`Failed to write settings: ${error.message}`);\n }\n throw error;\n }\n}\n","/**\n * Claude domain - Manage Claude Code settings and plugins\n */\nimport type { Command } from \"commander\";\nimport { initCommand } from \"../../commands/claude/init.js\";\nimport { consolidateCommand } from \"../../commands/claude/settings/consolidate.js\";\nimport type { Domain } from \"../types.js\";\n\n/**\n * Register claude domain commands\n *\n * @param claudeCmd - Commander.js claude domain command\n */\nfunction registerClaudeCommands(claudeCmd: Command): void {\n // init command\n claudeCmd\n .command(\"init\")\n .description(\"Initialize or update outcomeeng marketplace plugin\")\n .action(async () => {\n try {\n const output = await initCommand({ cwd: process.cwd() });\n console.log(output);\n } catch (error) {\n console.error(\n \"Error:\",\n error instanceof Error ? error.message : String(error),\n );\n process.exit(1);\n }\n });\n\n // settings subcommand group\n const settingsCmd = claudeCmd\n .command(\"settings\")\n .description(\"Manage Claude Code settings\");\n\n // settings consolidate command\n settingsCmd\n .command(\"consolidate\")\n .description(\n \"Consolidate permissions from project-specific settings into global settings\",\n )\n .option(\"--write\", \"Write changes to global settings file (default: preview only)\")\n .option(\n \"--output-file <path>\",\n \"Write merged settings to specified file instead of global settings\",\n )\n .option(\n \"--root <path>\",\n \"Root directory to scan for settings files (default: ~/Code)\",\n )\n .option(\n \"--global-settings <path>\",\n \"Path to global settings file (default: ~/.claude/settings.json)\",\n )\n .action(\n async (options: {\n write?: boolean;\n outputFile?: string;\n root?: string;\n globalSettings?: string;\n }) => {\n try {\n // Validate mutually exclusive options\n if (options.write && options.outputFile) {\n console.error(\n \"Error: --write and --output-file are mutually exclusive\\n\"\n + \"Use --write to modify global settings, or --output-file to write to a different location\",\n );\n process.exit(1);\n }\n\n const output = await consolidateCommand({\n write: options.write,\n outputFile: options.outputFile,\n root: options.root,\n globalSettings: options.globalSettings,\n });\n console.log(output);\n } catch (error) {\n console.error(\n \"Error:\",\n error instanceof Error ? error.message : String(error),\n );\n process.exit(1);\n }\n },\n );\n}\n\n/**\n * Claude domain - Manage Claude Code settings and plugins\n */\nexport const claudeDomain: Domain = {\n name: \"claude\",\n description: \"Manage Claude Code settings and plugins\",\n register: (program: Command) => {\n const claudeCmd = program\n .command(\"claude\")\n .description(\"Manage Claude Code settings and plugins\");\n\n registerClaudeCommands(claudeCmd);\n },\n};\n","import { stringify as yamlStringify } from \"yaml\";\n\nimport type { Config } from \"@/config/types.js\";\n\nimport type { CliDeps, CliResult, DefaultsOptions } from \"./types.js\";\n\nconst JSON_INDENT = 2;\n\nexport function defaultsCommand(options: DefaultsOptions, deps: CliDeps): Promise<CliResult> {\n const config: Record<string, unknown> = {};\n for (const descriptor of deps.descriptors) {\n config[descriptor.section] = descriptor.defaults;\n }\n\n return Promise.resolve({\n stdout: formatConfig(config as Config, options.json === true),\n stderr: \"\",\n exitCode: 0,\n });\n}\n\nfunction formatConfig(config: Config, asJson: boolean): string {\n if (asJson) {\n return `${JSON.stringify(config, null, JSON_INDENT)}\\n`;\n }\n return yamlStringify(config);\n}\n","import { stringify as yamlStringify } from \"yaml\";\n\nimport type { Config } from \"@/config/types.js\";\n\nimport type { CliDeps, CliResult, ShowOptions } from \"./types.js\";\n\nconst JSON_INDENT = 2;\nconst EXIT_CODE_ERROR = 1;\n\nexport async function showCommand(options: ShowOptions, deps: CliDeps): Promise<CliResult> {\n const projectRoot = deps.resolveProjectRoot();\n const result = await deps.resolveConfig(projectRoot);\n\n if (!result.ok) {\n return {\n stdout: \"\",\n stderr: `${result.error}\\n`,\n exitCode: EXIT_CODE_ERROR,\n };\n }\n\n return {\n stdout: formatConfig(result.value, options.json === true),\n stderr: \"\",\n exitCode: 0,\n };\n}\n\nfunction formatConfig(config: Config, asJson: boolean): string {\n if (asJson) {\n return `${JSON.stringify(config, null, JSON_INDENT)}\\n`;\n }\n return yamlStringify(config);\n}\n","import type { Config, ConfigDescriptor, Result } from \"@/config/types.js\";\n\nexport type CliResult = {\n readonly stdout: string;\n readonly stderr: string;\n readonly exitCode: number;\n};\n\nexport type CliDeps = {\n readonly resolveConfig: (projectRoot: string) => Promise<Result<Config>>;\n readonly resolveProjectRoot: () => string;\n readonly descriptors: readonly ConfigDescriptor<unknown>[];\n};\n\nexport type OutputFormatOptions = { readonly json?: boolean };\n\nexport type ShowOptions = OutputFormatOptions;\nexport type DefaultsOptions = OutputFormatOptions;\nexport type ValidateOptions = Record<string, never>;\n\nexport const CONFIG_FILENAME = \"spx.config.yaml\";\n","import type { CliDeps, CliResult, ValidateOptions } from \"./types.js\";\nimport { CONFIG_FILENAME } from \"./types.js\";\n\nconst EXIT_CODE_INVALID = 1;\n\nexport async function validateCommand(_options: ValidateOptions, deps: CliDeps): Promise<CliResult> {\n const projectRoot = deps.resolveProjectRoot();\n const result = await deps.resolveConfig(projectRoot);\n\n if (!result.ok) {\n return {\n stdout: \"\",\n stderr: `${result.error}\\n`,\n exitCode: EXIT_CODE_INVALID,\n };\n }\n\n return {\n stdout: `${CONFIG_FILENAME} at ${projectRoot} passes every registered descriptor's validator.\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parse as parseToml } from \"smol-toml\";\nimport { parse as parseYaml } from \"yaml\";\n\nimport { productionRegistry } from \"./registry.js\";\nimport type { Config, ConfigDescriptor, Result } from \"./types.js\";\n\nexport const CONFIG_FILENAMES = {\n json: \"spx.config.json\",\n yaml: \"spx.config.yaml\",\n toml: \"spx.config.toml\",\n} as const;\n\ntype ConfigFile = { readonly filename: string; readonly raw: string };\n\nexport async function resolveConfig(\n projectRoot: string,\n descriptors: readonly ConfigDescriptor<unknown>[] = productionRegistry,\n): Promise<Result<Config>> {\n const detectedResult = await detectConfigFiles(projectRoot);\n if (!detectedResult.ok) {\n return detectedResult;\n }\n const detected = detectedResult.value;\n\n if (detected.length > 1) {\n const names = detected.map((f) => f.filename).join(\", \");\n return { ok: false, error: `multiple config files found: ${names}` };\n }\n\n const sectionsResult = detected.length === 0\n ? ({ ok: true as const, value: {} as Record<string, unknown> })\n : parseSections(detected[0]);\n if (!sectionsResult.ok) {\n return sectionsResult;\n }\n const sections = sectionsResult.value;\n\n const resolved: Record<string, unknown> = {};\n for (const descriptor of descriptors) {\n const sectionValue = sections[descriptor.section];\n if (sectionValue === undefined) {\n resolved[descriptor.section] = descriptor.defaults;\n continue;\n }\n const validated = descriptor.validate(sectionValue);\n if (!validated.ok) {\n return { ok: false, error: `${descriptor.section}: ${validated.error}` };\n }\n resolved[descriptor.section] = validated.value;\n }\n\n return { ok: true, value: resolved };\n}\n\nasync function detectConfigFiles(projectRoot: string): Promise<Result<ConfigFile[]>> {\n const detected: ConfigFile[] = [];\n for (const filename of Object.values(CONFIG_FILENAMES)) {\n let raw: string;\n try {\n raw = await readFile(join(projectRoot, filename), \"utf8\");\n } catch (error) {\n if (isFileNotFound(error)) continue;\n return { ok: false, error: `failed to read ${filename}: ${toMessage(error)}` };\n }\n detected.push({ filename, raw });\n }\n return { ok: true, value: detected };\n}\n\nfunction parseSections(file: ConfigFile): Result<Record<string, unknown>> {\n switch (file.filename) {\n case CONFIG_FILENAMES.json:\n return parseJsonSections(file.filename, file.raw);\n case CONFIG_FILENAMES.yaml:\n return parseYamlSections(file.filename, file.raw);\n default:\n return parseTomlSections(file.filename, file.raw);\n }\n}\n\nfunction parseJsonSections(filename: string, raw: string): Result<Record<string, unknown>> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw) as unknown;\n } catch (error) {\n return { ok: false, error: `${filename} is not valid json: ${toMessage(error)}` };\n }\n return validateParsedSections(filename, parsed);\n}\n\nfunction parseYamlSections(filename: string, raw: string): Result<Record<string, unknown>> {\n let parsed: unknown;\n try {\n parsed = parseYaml(raw) as unknown;\n } catch (error) {\n return { ok: false, error: `${filename} is not valid yaml: ${toMessage(error)}` };\n }\n if (parsed === null || parsed === undefined) {\n return { ok: true, value: {} };\n }\n return validateParsedSections(filename, parsed);\n}\n\nfunction parseTomlSections(filename: string, raw: string): Result<Record<string, unknown>> {\n let parsed: unknown;\n try {\n parsed = parseToml(raw) as unknown;\n } catch (error) {\n return { ok: false, error: `${filename} is not valid toml: ${toMessage(error)}` };\n }\n return validateParsedSections(filename, parsed);\n}\n\nfunction validateParsedSections(filename: string, parsed: unknown): Result<Record<string, unknown>> {\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return { ok: false, error: `${filename} must parse to a mapping of descriptor sections` };\n }\n return { ok: true, value: parsed as Record<string, unknown> };\n}\n\nfunction isFileNotFound(error: unknown): boolean {\n return error instanceof Error && \"code\" in error && (error as NodeJS.ErrnoException).code === \"ENOENT\";\n}\n\nfunction toMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import type { ConfigDescriptor, Result } from \"@/config/types.js\";\n\nexport const KIND_REGISTRY = {\n enabler: { category: \"node\", suffix: \".enabler\" },\n outcome: { category: \"node\", suffix: \".outcome\" },\n adr: { category: \"decision\", suffix: \".adr.md\" },\n pdr: { category: \"decision\", suffix: \".pdr.md\" },\n} as const;\n\nexport type Kind = keyof typeof KIND_REGISTRY;\nexport type KindDefinition<K extends Kind> = (typeof KIND_REGISTRY)[K];\n\nexport type NodeKind = {\n [K in Kind]: (typeof KIND_REGISTRY)[K][\"category\"] extends \"node\" ? K : never;\n}[Kind];\n\nexport type DecisionKind = {\n [K in Kind]: (typeof KIND_REGISTRY)[K][\"category\"] extends \"decision\" ? K : never;\n}[Kind];\n\nexport const NODE_KINDS: readonly NodeKind[] = (Object.keys(KIND_REGISTRY) as Kind[]).filter(\n (k): k is NodeKind => KIND_REGISTRY[k].category === \"node\",\n);\n\nexport const DECISION_KINDS: readonly DecisionKind[] = (Object.keys(KIND_REGISTRY) as Kind[]).filter(\n (k): k is DecisionKind => KIND_REGISTRY[k].category === \"decision\",\n);\n\nexport const NODE_SUFFIXES: readonly string[] = NODE_KINDS.map((k) => KIND_REGISTRY[k].suffix);\nexport const DECISION_SUFFIXES: readonly string[] = DECISION_KINDS.map((k) => KIND_REGISTRY[k].suffix);\n\nexport type SpecTreeConfig = {\n readonly kinds: { readonly [K in Kind]?: KindDefinition<K> };\n};\n\nconst SPEC_TREE_SECTION = \"specTree\";\n\nfunction isKind(value: string): value is Kind {\n return Object.prototype.hasOwnProperty.call(KIND_REGISTRY, value);\n}\n\nfunction buildDefaults(): SpecTreeConfig {\n return { kinds: { ...KIND_REGISTRY } };\n}\n\nfunction validate(value: unknown): Result<SpecTreeConfig> {\n if (typeof value !== \"object\" || value === null) {\n return { ok: false, error: `${SPEC_TREE_SECTION} section must be an object` };\n }\n const candidate = value as { kinds?: unknown };\n if (\n typeof candidate.kinds !== \"object\"\n || candidate.kinds === null\n || Array.isArray(candidate.kinds)\n ) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds must be an object keyed by kind name`,\n };\n }\n\n const entries: Array<[Kind, KindDefinition<Kind>]> = [];\n const kindEntries = candidate.kinds as Record<string, unknown>;\n for (const [key, entry] of Object.entries(kindEntries)) {\n if (!isKind(key)) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds contains unknown kind \"${key}\"`,\n };\n }\n if (typeof entry !== \"object\" || entry === null) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key} must be an object with category and suffix`,\n };\n }\n const def = entry as { category?: unknown; suffix?: unknown };\n const expected = KIND_REGISTRY[key];\n if (def.category !== expected.category) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key}.category must be \"${expected.category}\"`,\n };\n }\n if (def.suffix !== expected.suffix) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key}.suffix must be \"${expected.suffix}\"`,\n };\n }\n entries.push([key, expected]);\n }\n\n const kinds = Object.fromEntries(entries) as SpecTreeConfig[\"kinds\"];\n return { ok: true, value: { kinds } };\n}\n\nexport const specTreeConfigDescriptor: ConfigDescriptor<SpecTreeConfig> = {\n section: SPEC_TREE_SECTION,\n defaults: buildDefaults(),\n validate,\n};\n","import type { ConfigDescriptor, Result } from \"@/config/types.js\";\n\nexport const LITERAL_SECTION = \"literal\";\nexport const DEFAULT_MIN_STRING_LENGTH = 4;\nexport const DEFAULT_MIN_NUMBER_DIGITS = 4;\n\nexport interface LiteralAllowlistConfig {\n readonly presets?: readonly string[];\n readonly include?: readonly string[];\n readonly exclude?: readonly string[];\n}\n\nexport interface LiteralConfig {\n readonly allowlist: LiteralAllowlistConfig;\n readonly minStringLength: number;\n readonly minNumberDigits: number;\n}\n\nconst WEB_PRESET: ReadonlySet<string> = new Set([\n \"GET\",\n \"POST\",\n \"PUT\",\n \"DELETE\",\n \"PATCH\",\n \"Content-Type\",\n \"Authorization\",\n \"Accept\",\n \"status\",\n \"message\",\n \"error\",\n \"data\",\n \"class\",\n \"id\",\n \"href\",\n \"src\",\n \"type\",\n \"name\",\n \"value\",\n]);\n\nconst PRESET_REGISTRY: ReadonlyMap<string, ReadonlySet<string>> = new Map([\n [\"web\", WEB_PRESET],\n]);\n\nexport function resolveAllowlist(config: LiteralAllowlistConfig): ReadonlySet<string> {\n const effective = new Set<string>();\n\n for (const presetId of config.presets ?? []) {\n const preset = PRESET_REGISTRY.get(presetId);\n if (preset !== undefined) {\n for (const v of preset) effective.add(v);\n }\n }\n\n for (const v of config.include ?? []) {\n effective.add(v);\n }\n\n for (const v of config.exclude ?? []) {\n effective.delete(v);\n }\n\n return effective;\n}\n\nconst defaults: LiteralConfig = {\n allowlist: {},\n minStringLength: DEFAULT_MIN_STRING_LENGTH,\n minNumberDigits: DEFAULT_MIN_NUMBER_DIGITS,\n};\n\nfunction validate(value: unknown): Result<LiteralConfig> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return { ok: false, error: `${LITERAL_SECTION} section must be an object` };\n }\n const candidate = value as Record<string, unknown>;\n\n const allowlistRaw = candidate[\"allowlist\"] ?? {};\n const allowlistResult = validateAllowlist(allowlistRaw);\n if (!allowlistResult.ok) {\n return allowlistResult;\n }\n\n const minStringLength = candidate[\"minStringLength\"] ?? defaults.minStringLength;\n if (typeof minStringLength !== \"number\" || !Number.isInteger(minStringLength) || minStringLength < 0) {\n return {\n ok: false,\n error: `${LITERAL_SECTION}.minStringLength must be a non-negative integer`,\n };\n }\n\n const minNumberDigits = candidate[\"minNumberDigits\"] ?? defaults.minNumberDigits;\n if (typeof minNumberDigits !== \"number\" || !Number.isInteger(minNumberDigits) || minNumberDigits < 0) {\n return {\n ok: false,\n error: `${LITERAL_SECTION}.minNumberDigits must be a non-negative integer`,\n };\n }\n\n return { ok: true, value: { allowlist: allowlistResult.value, minStringLength, minNumberDigits } };\n}\n\nfunction validateAllowlist(raw: unknown): Result<LiteralAllowlistConfig> {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist must be an object` };\n }\n const candidate = raw as Record<string, unknown>;\n\n const presets = candidate[\"presets\"];\n if (presets !== undefined) {\n if (!Array.isArray(presets) || !presets.every((x) => typeof x === \"string\")) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist.presets must be an array of strings` };\n }\n for (const id of presets as string[]) {\n if (!PRESET_REGISTRY.has(id)) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist.presets: unrecognized preset \"${id}\"` };\n }\n }\n }\n\n const include = candidate[\"include\"];\n if (include !== undefined && (!Array.isArray(include) || !include.every((x) => typeof x === \"string\"))) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist.include must be an array of strings` };\n }\n\n const exclude = candidate[\"exclude\"];\n if (exclude !== undefined && (!Array.isArray(exclude) || !exclude.every((x) => typeof x === \"string\"))) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist.exclude must be an array of strings` };\n }\n\n return {\n ok: true,\n value: {\n presets: presets as readonly string[] | undefined,\n include: include as readonly string[] | undefined,\n exclude: exclude as readonly string[] | undefined,\n },\n };\n}\n\nexport const literalConfigDescriptor: ConfigDescriptor<LiteralConfig> = {\n section: LITERAL_SECTION,\n defaults,\n validate,\n};\n","import { specTreeConfigDescriptor } from \"@/spec/config.js\";\nimport { literalConfigDescriptor } from \"@/validation/literal/config.js\";\n\nimport type { ConfigDescriptor } from \"./types.js\";\n\nexport const productionRegistry: readonly ConfigDescriptor<unknown>[] = [\n specTreeConfigDescriptor,\n literalConfigDescriptor,\n] as const;\n","import { execSync } from \"node:child_process\";\nimport { resolve } from \"node:path\";\n\nconst GIT_TOPLEVEL_CMD = \"git rev-parse --show-toplevel\";\nconst GIT_NOT_REPO_MARKER = \"not a git repository\";\n\nexport type ResolvedProjectRoot = {\n readonly projectRoot: string;\n readonly warning?: string;\n};\n\nexport function resolveProjectRoot(cwd: string = process.cwd()): ResolvedProjectRoot {\n const resolvedCwd = resolve(cwd);\n try {\n const stdout = execSync(GIT_TOPLEVEL_CMD, {\n cwd: resolvedCwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n encoding: \"utf8\",\n });\n const toplevel = stdout.trim();\n if (toplevel.length > 0) {\n return { projectRoot: resolve(toplevel) };\n }\n } catch {\n // fall through to cwd fallback\n }\n\n return {\n projectRoot: resolvedCwd,\n warning:\n `warning: ${resolvedCwd} is not inside a git worktree — falling back to the current working directory. ${GIT_NOT_REPO_MARKER}.`,\n };\n}\n","import type { Command } from \"commander\";\n\nimport { defaultsCommand } from \"@/commands/config/defaults.js\";\nimport { showCommand } from \"@/commands/config/show.js\";\nimport type { CliDeps, CliResult, ShowOptions, ValidateOptions } from \"@/commands/config/types.js\";\nimport { validateCommand } from \"@/commands/config/validate.js\";\nimport { resolveConfig } from \"@/config/index.js\";\nimport { productionRegistry } from \"@/config/registry.js\";\n\nimport type { Domain } from \"../types.js\";\nimport { resolveProjectRoot } from \"./root.js\";\n\nfunction buildDefaultDeps(): CliDeps {\n return {\n resolveConfig,\n resolveProjectRoot: (): string => {\n const resolved = resolveProjectRoot();\n if (resolved.warning !== undefined) {\n process.stderr.write(`${resolved.warning}\\n`);\n }\n return resolved.projectRoot;\n },\n descriptors: productionRegistry,\n };\n}\n\nasync function emit(result: CliResult): Promise<never> {\n if (result.stdout.length > 0) {\n process.stdout.write(result.stdout);\n }\n if (result.stderr.length > 0) {\n process.stderr.write(result.stderr);\n }\n return process.exit(result.exitCode);\n}\n\nfunction registerConfigCommands(configCmd: Command): void {\n configCmd\n .command(\"show\")\n .description(\"Print the resolved configuration as YAML (or JSON with --json)\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (options: ShowOptions) => {\n await emit(await showCommand(options, buildDefaultDeps()));\n });\n\n configCmd\n .command(\"validate\")\n .description(\"Verify that spx.config.yaml passes every registered descriptor's validator\")\n .action(async (options: ValidateOptions) => {\n await emit(await validateCommand(options, buildDefaultDeps()));\n });\n\n configCmd\n .command(\"defaults\")\n .description(\"Print each registered descriptor's defaults — ignores spx.config.yaml\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (options: ShowOptions) => {\n await emit(await defaultsCommand(options, buildDefaultDeps()));\n });\n}\n\nexport const configDomain: Domain = {\n name: \"config\",\n description: \"Inspect and validate the resolved spx configuration\",\n register: (program: Command) => {\n const configCmd = program\n .command(\"config\")\n .description(\"Inspect and validate the resolved spx configuration\");\n registerConfigCommands(configCmd);\n },\n};\n","/**\n * Session archive CLI command handler.\n *\n * @module commands/session/archive\n */\n\nimport { mkdir, rename, stat } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { resolveSessionConfig } from \"../../git/root.js\";\nimport {\n buildArchivePaths,\n type ExistingPathsMap,\n findSessionForArchive,\n SESSION_FILE_EXTENSION,\n} from \"../../session/archive.js\";\nimport { processBatch } from \"../../session/batch.js\";\nimport { SessionNotFoundError } from \"../../session/errors.js\";\nimport type { SessionDirectoryConfig } from \"../../session/show.js\";\n\n/**\n * Options for the archive command.\n */\nexport interface ArchiveOptions {\n /** Session ID(s) to archive */\n sessionIds: string[];\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Error thrown when a session is already archived.\n */\nexport class SessionAlreadyArchivedError extends Error {\n /** The session ID that is already archived */\n readonly sessionId: string;\n\n constructor(sessionId: string) {\n super(`Session already archived: ${sessionId}.`);\n this.name = \"SessionAlreadyArchivedError\";\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Checks whether a path exists as a file.\n */\nasync function fileExists(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Builds an ExistingPathsMap by probing the filesystem for a session ID\n * across all status directories.\n *\n * @param sessionId - Session ID to locate\n * @param config - Directory configuration\n * @returns Map of existing paths (null for directories where file is absent)\n */\nasync function probeSessionPaths(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<ExistingPathsMap> {\n const filename = `${sessionId}${SESSION_FILE_EXTENSION}`;\n const todoPath = join(config.todoDir, filename);\n const doingPath = join(config.doingDir, filename);\n const archivePath = join(config.archiveDir, filename);\n\n return {\n todo: await fileExists(todoPath) ? todoPath : null,\n doing: await fileExists(doingPath) ? doingPath : null,\n archive: await fileExists(archivePath) ? archivePath : null,\n };\n}\n\n/**\n * Resolves source and target paths for archiving a session.\n *\n * I/O: probes filesystem to locate the session.\n * Path logic: delegated to src/session/archive.ts pure functions.\n *\n * @param sessionId - Session ID to archive\n * @param config - Directory configuration\n * @returns Source and target paths for the archive rename\n * @throws {SessionNotFoundError} When session is not found in todo or doing\n * @throws {SessionAlreadyArchivedError} When session is already in archive\n */\nexport async function resolveArchivePaths(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<{ source: string; target: string }> {\n const existingPaths = await probeSessionPaths(sessionId, config);\n\n if (existingPaths.archive !== null) {\n throw new SessionAlreadyArchivedError(sessionId);\n }\n\n const location = findSessionForArchive(existingPaths);\n\n if (!location) {\n throw new SessionNotFoundError(sessionId);\n }\n\n const paths = buildArchivePaths(sessionId, location.status, config);\n return paths;\n}\n\n/**\n * Executes the archive command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {SessionNotFoundError} When session not found\n * @throws {SessionAlreadyArchivedError} When session is already archived\n */\n/**\n * Archives a single session by ID.\n */\nasync function archiveSingle(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<string> {\n const { source, target } = await resolveArchivePaths(sessionId, config);\n await mkdir(dirname(target), { recursive: true });\n await rename(source, target);\n return `Archived session: ${sessionId}\\nArchive location: ${target}`;\n}\n\n/**\n * Executes the archive command for one or more session IDs.\n *\n * @param options - Command options with one or more session IDs\n * @returns Formatted output for display\n * @throws {BatchError} When one or more IDs fail\n * @throws {SessionNotFoundError} When session not found (single ID)\n * @throws {SessionAlreadyArchivedError} When session already archived (single ID)\n */\nexport async function archiveCommand(options: ArchiveOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n return processBatch(options.sessionIds, (id) => archiveSingle(id, config));\n}\n","/**\n * Git repository root detection utilities.\n *\n * Provides git root detection with dependency injection for testability.\n * Sessions should be created at the git repository root, not relative to cwd.\n *\n * @module git/root\n */\n\nimport { execa } from \"execa\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\n\nimport { DEFAULT_CONFIG } from \"../config/defaults.js\";\nimport type { SessionDirectoryConfig } from \"../session/show.js\";\n\n/**\n * Result from git root detection.\n */\nexport interface GitRootResult {\n /** Absolute path to git root (or cwd if not in git repo) */\n root: string;\n /** Whether the directory is inside a git repository */\n isGitRepo: boolean;\n /** Warning message when not in a git repo (undefined if in repo) */\n warning?: string;\n}\n\n/**\n * Minimal result type for command execution.\n * Captures only the fields git root detection depends on.\n */\nexport interface ExecResult {\n /** Process exit code */\n exitCode: number;\n /** Standard output */\n stdout: string;\n /** Standard error */\n stderr: string;\n}\n\n/**\n * Dependencies for git operations (injectable for testing).\n */\nexport interface GitDependencies {\n /**\n * Execute a command.\n *\n * @param command - Command to execute\n * @param args - Command arguments\n * @param options - Execution options\n * @returns Promise resolving to command result\n */\n execa: (\n command: string,\n args: string[],\n options?: { cwd?: string; reject?: boolean },\n ) => Promise<ExecResult>;\n}\n\n/**\n * Default dependencies using real execa.\n */\nconst defaultDeps: GitDependencies = {\n execa: async (command, args, options) => {\n const result = await execa(command, args, options);\n return {\n exitCode: result.exitCode ?? 0,\n stdout: typeof result.stdout === \"string\" ? result.stdout : String(result.stdout),\n stderr: typeof result.stderr === \"string\" ? result.stderr : String(result.stderr),\n };\n },\n};\n\n/**\n * Warning message emitted when not in a git repository.\n */\nconst NOT_GIT_REPO_WARNING =\n \"Warning: Not in a git repository. Sessions will be created relative to current directory.\";\n\n/**\n * Detects the git repository root directory.\n *\n * Uses `git rev-parse --show-toplevel` to find the repository root.\n * If not in a git repository, returns the current working directory with a warning.\n *\n * @param cwd - Current working directory (defaults to process.cwd())\n * @param deps - Injectable dependencies for testing\n * @returns GitRootResult with root path, git status, and optional warning\n *\n * @example\n * ```typescript\n * // In a git repo subdirectory\n * const result = await detectGitRoot('/repo/src/components');\n * // => { root: '/repo', isGitRepo: true }\n *\n * // Not in a git repo\n * const result = await detectGitRoot('/tmp/random');\n * // => { root: '/tmp/random', isGitRepo: false, warning: '...' }\n * ```\n */\nexport async function detectGitRoot(\n cwd: string = process.cwd(),\n deps: GitDependencies = defaultDeps,\n): Promise<GitRootResult> {\n try {\n const result = await deps.execa(\n \"git\",\n [\"rev-parse\", \"--show-toplevel\"],\n { cwd, reject: false },\n );\n\n // Git command succeeded - we're in a repo\n if (result.exitCode === 0 && result.stdout) {\n return {\n root: extractStdout(result.stdout),\n isGitRepo: true,\n };\n }\n\n // Git command failed - not in a repo\n return {\n root: cwd,\n isGitRepo: false,\n warning: NOT_GIT_REPO_WARNING,\n };\n } catch {\n // Command execution failed (git not installed, permission error, etc.)\n return {\n root: cwd,\n isGitRepo: false,\n warning: NOT_GIT_REPO_WARNING,\n };\n }\n}\n\n/**\n * Extracts a trimmed string from execa stdout, handling all possible output types.\n */\nfunction extractStdout(stdout: unknown): string {\n if (!stdout) return \"\";\n const str = typeof stdout === \"string\" ? stdout : String(stdout);\n return str.trim().replace(/\\/+$/, \"\");\n}\n\n/**\n * Detects the main repository root, resolving through git worktrees.\n *\n * Uses `git rev-parse --git-common-dir` to find the shared `.git` directory,\n * then returns its parent as the main repository root. In a non-worktree\n * repository, this returns the same path as `detectGitRoot`.\n *\n * Per PDR-15, this function is used for `.spx/` (gitignored) operations\n * where state must be shared across all worktrees.\n *\n * @param cwd - Current working directory (defaults to process.cwd())\n * @param deps - Injectable dependencies for testing\n * @returns GitRootResult with main repo root path\n */\nexport async function detectMainRepoRoot(\n cwd: string = process.cwd(),\n deps: GitDependencies = defaultDeps,\n): Promise<GitRootResult> {\n try {\n // Step 1: Get the worktree/repo root via --show-toplevel\n const toplevelResult = await deps.execa(\n \"git\",\n [\"rev-parse\", \"--show-toplevel\"],\n { cwd, reject: false },\n );\n\n if (toplevelResult.exitCode !== 0 || !toplevelResult.stdout) {\n return {\n root: cwd,\n isGitRepo: false,\n warning: NOT_GIT_REPO_WARNING,\n };\n }\n\n const toplevel = extractStdout(toplevelResult.stdout);\n\n // Step 2: Get the common git directory via --git-common-dir\n const commonDirResult = await deps.execa(\n \"git\",\n [\"rev-parse\", \"--git-common-dir\"],\n { cwd, reject: false },\n );\n\n if (commonDirResult.exitCode !== 0 || !commonDirResult.stdout) {\n // Fallback: if --git-common-dir fails, use toplevel\n return {\n root: toplevel,\n isGitRepo: true,\n };\n }\n\n const commonDir = extractStdout(commonDirResult.stdout);\n\n // Step 3: Resolve the common dir to an absolute path\n // --git-common-dir may return a relative path (e.g., \".git\" or \"../../../.git\")\n const absoluteCommonDir = isAbsolute(commonDir)\n ? commonDir\n : resolve(toplevel, commonDir);\n\n // Step 4: The main repo root is the parent of the common .git directory\n const mainRepoRoot = dirname(absoluteCommonDir);\n\n return {\n root: mainRepoRoot,\n isGitRepo: true,\n };\n } catch {\n return {\n root: cwd,\n isGitRepo: false,\n warning: NOT_GIT_REPO_WARNING,\n };\n }\n}\n\n/**\n * Options for resolving session directory configuration.\n */\nexport interface ResolveSessionConfigOptions {\n /** Explicit sessions directory (overrides auto-detection) */\n sessionsDir?: string;\n /** Current working directory for git detection */\n cwd?: string;\n /** Injectable dependencies for testing */\n deps?: GitDependencies;\n}\n\n/**\n * Result of session config resolution.\n */\nexport interface ResolveSessionConfigResult {\n /** Resolved session directory configuration with absolute paths */\n config: SessionDirectoryConfig;\n /** Warning message if not in a git repository */\n warning?: string;\n}\n\n/**\n * Resolves session directory configuration with worktree-aware root detection.\n *\n * If `sessionsDir` is provided, uses it directly. Otherwise, detects the main\n * repository root via `detectMainRepoRoot` and builds absolute paths from\n * `DEFAULT_CONFIG`.\n *\n * Per PDR-15, session operations always resolve against the main repository\n * root (root worktree) so that `.spx/sessions/` is shared across all worktrees.\n *\n * @param options - Resolution options\n * @returns Resolved config with absolute paths and optional warning\n */\nexport async function resolveSessionConfig(\n options: ResolveSessionConfigOptions = {},\n): Promise<ResolveSessionConfigResult> {\n const { sessionsDir, cwd, deps } = options;\n const { statusDirs } = DEFAULT_CONFIG.sessions;\n\n // Explicit directory provided — use as-is\n if (sessionsDir) {\n return {\n config: {\n todoDir: join(sessionsDir, statusDirs.todo),\n doingDir: join(sessionsDir, statusDirs.doing),\n archiveDir: join(sessionsDir, statusDirs.archive),\n },\n };\n }\n\n // Auto-detect main repo root for .spx/ operations\n const gitResult = await detectMainRepoRoot(cwd, deps);\n const baseDir = join(gitResult.root, DEFAULT_CONFIG.sessions.dir);\n\n return {\n config: {\n todoDir: join(baseDir, statusDirs.todo),\n doingDir: join(baseDir, statusDirs.doing),\n archiveDir: join(baseDir, statusDirs.archive),\n },\n warning: gitResult.warning,\n };\n}\n\n/**\n * Builds an absolute session file path from git root and session ID.\n *\n * Pure function that constructs the path without I/O.\n * All path components come from the config parameter (single source of truth).\n *\n * @param gitRoot - Absolute path to git repository root\n * @param sessionId - Session timestamp ID (e.g., \"2026-01-13_08-01-05\")\n * @param config - Session directory configuration\n * @returns Absolute path to session file in todo directory\n *\n * @example\n * ```typescript\n * const path = buildSessionPathFromRoot(\n * '/Users/dev/myproject',\n * '2026-01-13_08-01-05',\n * DEFAULT_SESSION_CONFIG,\n * );\n * // => '/Users/dev/myproject/.spx/sessions/todo/2026-01-13_08-01-05.md'\n * ```\n */\nexport function buildSessionPathFromRoot(\n gitRoot: string,\n sessionId: string,\n config: SessionDirectoryConfig,\n): string {\n const filename = `${sessionId}.md`;\n\n // Build absolute path: git root + todo dir + filename\n // All components come from config (no hardcoded strings)\n return join(gitRoot, config.todoDir, filename);\n}\n","/**\n * Default configuration for spx CLI\n *\n * This module defines the default directory structure and configuration\n * constants used throughout the spx CLI. All directory paths should reference\n * this configuration instead of using hardcoded strings.\n *\n * @module config/defaults\n */\n\n/**\n * Configuration schema for spx CLI directory structure\n */\nexport interface SpxConfig {\n /**\n * Specifications directory configuration\n */\n specs: {\n /**\n * Base directory for all specification files\n * @default \"specs\"\n */\n root: string;\n\n /**\n * Work items organization\n */\n work: {\n /**\n * Container directory for all work items\n * @default \"work\"\n */\n dir: string;\n\n /**\n * Status-based subdirectories for work items\n */\n statusDirs: {\n /**\n * Active work directory\n * @default \"doing\"\n */\n doing: string;\n\n /**\n * Future work directory\n * @default \"backlog\"\n */\n backlog: string;\n\n /**\n * Completed work directory\n * @default \"archive\"\n */\n done: string;\n };\n };\n\n /**\n * Product-level architecture decision records directory\n * @default \"decisions\"\n */\n decisions: string;\n\n /**\n * Templates directory (optional)\n * @default \"templates\"\n */\n templates?: string;\n };\n\n /**\n * Session handoff files configuration\n */\n sessions: {\n /**\n * Directory for session handoff files\n * @default \".spx/sessions\"\n */\n dir: string;\n\n /**\n * Status-based subdirectories for sessions\n */\n statusDirs: {\n /**\n * Available sessions directory\n * @default \"todo\"\n */\n todo: string;\n\n /**\n * Claimed sessions directory\n * @default \"doing\"\n */\n doing: string;\n\n /**\n * Archived sessions directory\n * @default \"archive\"\n */\n archive: string;\n };\n };\n}\n\n/**\n * Default configuration constant\n *\n * This is the embedded default configuration that spx uses when no\n * .spx/config.json file exists in the product.\n *\n * DO NOT modify this constant at runtime - it should remain immutable.\n */\nexport const DEFAULT_CONFIG = {\n specs: {\n root: \"specs\",\n work: {\n dir: \"work\",\n statusDirs: {\n doing: \"doing\",\n backlog: \"backlog\",\n done: \"archive\",\n },\n },\n decisions: \"decisions\",\n templates: \"templates\",\n },\n sessions: {\n dir: \".spx/sessions\",\n statusDirs: {\n todo: \"todo\",\n doing: \"doing\",\n archive: \"archive\",\n },\n },\n} as const satisfies SpxConfig;\n","/**\n * Session archiving utilities with pure functions for path resolution.\n *\n * This module provides pure functions for archive path building and session\n * location finding. Actual filesystem operations are handled by the CLI\n * command handler in commands/session/archive.ts.\n *\n * @module session/archive\n */\n\nimport type { SessionStatus } from \"./types.js\";\n\n/**\n * File extension for session files.\n */\nexport const SESSION_FILE_EXTENSION = \".md\";\n\n/**\n * Configuration for archive path building.\n */\nexport interface ArchivePathConfig {\n /** Directory for todo sessions */\n todoDir: string;\n /** Directory for doing (claimed) sessions */\n doingDir: string;\n /** Directory for archived sessions */\n archiveDir: string;\n}\n\n/**\n * Result of building archive paths.\n */\nexport interface ArchivePaths {\n /** Source path where session currently exists */\n source: string;\n /** Target path in archive directory */\n target: string;\n}\n\n/**\n * Map of existing paths for session lookup.\n * Each key maps to the full path if file exists, or null if not found.\n */\nexport interface ExistingPathsMap {\n /** Path in todo directory, or null if not found */\n todo: string | null;\n /** Path in doing directory, or null if not found */\n doing: string | null;\n /** Path in archive directory, or null if not found */\n archive: string | null;\n}\n\n/**\n * Archivable statuses — sessions can only be archived from todo or doing.\n */\nexport type ArchivableStatus = Exclude<SessionStatus, \"archive\">;\n\n/**\n * Result of finding a session for archiving.\n */\nexport interface SessionLocation {\n /** Status/directory where session was found */\n status: ArchivableStatus;\n /** Full path to the session file */\n path: string;\n}\n\n/**\n * Builds source and target paths for archiving a session.\n *\n * This is a pure function that computes paths based on session ID,\n * current status, and directory configuration.\n *\n * @param sessionId - Session ID (timestamp format)\n * @param currentStatus - Current status/directory of the session\n * @param config - Directory configuration\n * @returns Source and target paths for the archive operation\n *\n * @example\n * ```typescript\n * const paths = buildArchivePaths(\"2026-01-13_08-01-05\", \"todo\", {\n * todoDir: \".spx/sessions/todo\",\n * archiveDir: \".spx/sessions/archive\",\n * });\n * // paths.source === \".spx/sessions/todo/2026-01-13_08-01-05.md\"\n * // paths.target === \".spx/sessions/archive/2026-01-13_08-01-05.md\"\n * ```\n */\n/**\n * Maps archivable status to the corresponding config directory key.\n */\nconst ARCHIVABLE_DIR_KEY: Record<ArchivableStatus, \"todoDir\" | \"doingDir\"> = {\n todo: \"todoDir\",\n doing: \"doingDir\",\n};\n\nexport function buildArchivePaths(\n sessionId: string,\n currentStatus: ArchivableStatus,\n config: ArchivePathConfig,\n): ArchivePaths {\n const filename = `${sessionId}${SESSION_FILE_EXTENSION}`;\n const dirKey = ARCHIVABLE_DIR_KEY[currentStatus];\n const sourceDir = config[dirKey];\n\n return {\n source: `${sourceDir}/${filename}`,\n target: `${config.archiveDir}/${filename}`,\n };\n}\n\n/**\n * Finds a session's location for archiving.\n *\n * This is a pure function that determines the session's location based\n * on a map of existing paths. Returns null if the session is already\n * archived or not found.\n *\n * @param existingPaths - Map of paths where session might exist\n * @returns Session location if found in todo or doing, null otherwise\n *\n * @example\n * ```typescript\n * // Session in todo\n * const location = findSessionForArchive({\n * todo: \".spx/sessions/todo/test.md\",\n * doing: null,\n * archive: null,\n * });\n * // location === { status: \"todo\", path: \".spx/sessions/todo/test.md\" }\n *\n * // Session already archived\n * const location = findSessionForArchive({\n * todo: null,\n * doing: null,\n * archive: \".spx/sessions/archive/test.md\",\n * });\n * // location === null\n * ```\n */\n/**\n * Statuses to check when looking for a session to archive, in priority order.\n */\nconst ARCHIVE_SEARCH_ORDER: readonly ArchivableStatus[] = [\"todo\", \"doing\"] as const;\n\nexport function findSessionForArchive(\n existingPaths: ExistingPathsMap,\n): SessionLocation | null {\n // If session is already in archive, return null\n if (existingPaths.archive !== null) {\n return null;\n }\n\n // Check archivable directories in priority order\n for (const status of ARCHIVE_SEARCH_ORDER) {\n if (existingPaths[status] !== null) {\n return { status, path: existingPaths[status] };\n }\n }\n\n // Session not found anywhere\n return null;\n}\n","/**\n * Batch processing utilities for session commands.\n *\n * Provides a shared pattern for processing multiple session IDs:\n * run a handler per ID, collect results, report per-ID outcomes,\n * throw if any failed.\n *\n * @module session/batch\n */\n\n/**\n * Result of processing a single session ID within a batch.\n */\nexport interface BatchItemResult {\n /** The session ID that was processed. */\n id: string;\n /** Whether the operation succeeded. */\n ok: boolean;\n /** Output message on success, error message on failure. */\n message: string;\n}\n\n/**\n * Error thrown when a batch operation has partial or total failures.\n * Contains per-ID results so the caller knows which succeeded and which failed.\n */\nexport class BatchError extends Error {\n readonly results: readonly BatchItemResult[];\n\n constructor(results: readonly BatchItemResult[]) {\n const failures = results.filter((r) => !r.ok);\n const successes = results.filter((r) => r.ok);\n super(\n `${failures.length} of ${results.length} operations failed. `\n + `${successes.length} succeeded.`,\n );\n this.name = \"BatchError\";\n this.results = results;\n }\n}\n\n/**\n * Processes multiple session IDs through a handler function.\n *\n * IDs are processed sequentially in argument order (left-to-right).\n * All IDs are processed regardless of individual failures.\n * Throws BatchError if any ID fails.\n *\n * @param ids - Session IDs to process\n * @param handler - Async function that processes a single ID and returns output\n * @returns Combined output string with per-ID results\n * @throws {BatchError} When one or more IDs fail\n */\nexport async function processBatch(\n ids: readonly string[],\n handler: (id: string) => Promise<string>,\n): Promise<string> {\n const results: BatchItemResult[] = [];\n\n for (const id of ids) {\n try {\n const output = await handler(id);\n results.push({ id, ok: true, message: output });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n results.push({ id, ok: false, message });\n }\n }\n\n const output = results\n .map((r) => r.ok ? r.message : `Error (${r.id}): ${r.message}`)\n .join(\"\\n\\n\");\n\n const hasFailures = results.some((r) => !r.ok);\n if (hasFailures) {\n const err = new BatchError(results);\n err.message = `${err.message}\\n\\n${output}`;\n throw err;\n }\n\n return output;\n}\n","/**\n * Session-specific error types.\n *\n * @module session/errors\n */\n\n/**\n * Base class for session errors.\n */\nexport class SessionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SessionError\";\n }\n}\n\n/**\n * Error thrown when a session cannot be found.\n */\nexport class SessionNotFoundError extends SessionError {\n /** The session ID that was not found */\n readonly sessionId: string;\n\n constructor(sessionId: string) {\n super(`Session not found: ${sessionId}. Check the session ID and try again.`);\n this.name = \"SessionNotFoundError\";\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown when a session is not available for claiming (already claimed).\n */\nexport class SessionNotAvailableError extends SessionError {\n /** The session ID that is not available */\n readonly sessionId: string;\n\n constructor(sessionId: string) {\n super(`Session not available: ${sessionId}. It may have been claimed by another agent.`);\n this.name = \"SessionNotAvailableError\";\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown when session content is invalid.\n */\nexport class SessionInvalidContentError extends SessionError {\n constructor(reason: string) {\n super(`Invalid session content: ${reason}`);\n this.name = \"SessionInvalidContentError\";\n }\n}\n\n/**\n * Error thrown when trying to release a session that is not currently claimed.\n */\nexport class SessionNotClaimedError extends SessionError {\n /** The session ID that is not claimed */\n readonly sessionId: string;\n\n constructor(sessionId: string) {\n super(`Session not claimed: ${sessionId}. The session is not in the doing directory.`);\n this.name = \"SessionNotClaimedError\";\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown when no sessions are available for auto-pickup.\n */\nexport class NoSessionsAvailableError extends SessionError {\n constructor() {\n super(\"No sessions available. The todo directory is empty.\");\n this.name = \"NoSessionsAvailableError\";\n }\n}\n","/**\n * Session delete CLI command handler.\n *\n * @module commands/session/delete\n */\n\nimport { stat, unlink } from \"node:fs/promises\";\n\nimport { resolveSessionConfig } from \"../../git/root.js\";\nimport { processBatch } from \"../../session/batch.js\";\nimport { resolveDeletePath } from \"../../session/delete.js\";\nimport { resolveSessionPaths, type SessionDirectoryConfig } from \"../../session/show.js\";\n\n/**\n * Options for the delete command.\n */\nexport interface DeleteOptions {\n /** Session ID(s) to delete */\n sessionIds: string[];\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Checks which paths exist.\n */\nasync function findExistingPaths(paths: string[]): Promise<string[]> {\n const existing: string[] = [];\n\n for (const path of paths) {\n try {\n const stats = await stat(path);\n if (stats.isFile()) {\n existing.push(path);\n }\n } catch {\n // File doesn't exist, skip\n }\n }\n\n return existing;\n}\n\n/**\n * Executes the delete command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {SessionNotFoundError} When session not found\n */\n/**\n * Deletes a single session by ID.\n */\nasync function deleteSingle(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<string> {\n const paths = resolveSessionPaths(sessionId, config);\n const existingPaths = await findExistingPaths(paths);\n const pathToDelete = resolveDeletePath(sessionId, existingPaths);\n await unlink(pathToDelete);\n return `Deleted session: ${sessionId}`;\n}\n\n/**\n * Executes the delete command for one or more session IDs.\n *\n * @param options - Command options with one or more session IDs\n * @returns Formatted output for display\n * @throws {BatchError} When one or more IDs fail\n * @throws {SessionNotFoundError} When session not found (single ID)\n */\nexport async function deleteCommand(options: DeleteOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n return processBatch(options.sessionIds, (id) => deleteSingle(id, config));\n}\n","/**\n * Session deletion utilities.\n *\n * @module session/delete\n */\n\nimport { SessionNotFoundError } from \"./errors\";\n\n/**\n * Resolves the path to delete for a session ID.\n *\n * Given a session ID and a list of existing paths (checked by caller),\n * returns the first path that contains the session ID.\n *\n * @param sessionId - Session ID to find\n * @param existingPaths - Paths that were found to exist\n * @returns The path to the session file\n * @throws {SessionNotFoundError} When session is not found in any directory\n *\n * @example\n * ```typescript\n * // Caller checks which paths exist, passes only existing ones\n * const existingPaths = ['.spx/sessions/doing/2026-01-13_08-01-05.md'];\n * const path = resolveDeletePath('2026-01-13_08-01-05', existingPaths);\n * // => '.spx/sessions/doing/2026-01-13_08-01-05.md'\n * ```\n */\nexport function resolveDeletePath(\n sessionId: string,\n existingPaths: string[],\n): string {\n // Find the first existing path that matches the session ID\n const matchingPath = existingPaths.find((path) => path.includes(sessionId));\n\n if (!matchingPath) {\n throw new SessionNotFoundError(sessionId);\n }\n\n return matchingPath;\n}\n","/**\n * Session display utilities for showing session content without claiming.\n *\n * @module session/show\n */\n\nimport { join } from \"node:path\";\n\nimport { DEFAULT_CONFIG } from \"../config/defaults.js\";\nimport { parseSessionMetadata } from \"./list.js\";\nimport { SESSION_STATUSES, type SessionStatus } from \"./types.js\";\n\n/**\n * Configuration for session directory paths.\n */\nexport interface SessionDirectoryConfig {\n /** Path to todo directory */\n todoDir: string;\n /** Path to doing directory */\n doingDir: string;\n /** Path to archive directory */\n archiveDir: string;\n}\n\n/**\n * Default session directory configuration.\n *\n * Derived from DEFAULT_CONFIG to ensure single source of truth for all path components.\n * NEVER hardcode path strings like \".spx\", \"sessions\", \"todo\" - always derive from config.\n */\nconst { dir: sessionsBaseDir, statusDirs } = DEFAULT_CONFIG.sessions;\n\nexport const DEFAULT_SESSION_CONFIG: SessionDirectoryConfig = {\n todoDir: join(sessionsBaseDir, statusDirs.todo),\n doingDir: join(sessionsBaseDir, statusDirs.doing),\n archiveDir: join(sessionsBaseDir, statusDirs.archive),\n};\n\n/**\n * Order to search directories (matches priority: todo first, then doing, then archive).\n * Derived from SESSION_STATUSES to maintain single source of truth per ADR 21-directory-structure.\n */\nexport const SEARCH_ORDER: SessionStatus[] = [...SESSION_STATUSES];\n\n/**\n * Options for formatting show output.\n */\nexport interface ShowOutputOptions {\n /** Current status of the session */\n status: SessionStatus;\n}\n\n/**\n * Resolves possible file paths for a session ID across all status directories.\n *\n * @param id - Session ID (timestamp format)\n * @param config - Directory configuration\n * @returns Array of possible file paths in search order\n *\n * @example\n * ```typescript\n * const paths = resolveSessionPaths('2026-01-13_08-01-05', {\n * todoDir: '.spx/sessions/todo',\n * doingDir: '.spx/sessions/doing',\n * archiveDir: '.spx/sessions/archive',\n * });\n * // => [\n * // '.spx/sessions/todo/2026-01-13_08-01-05.md',\n * // '.spx/sessions/doing/2026-01-13_08-01-05.md',\n * // '.spx/sessions/archive/2026-01-13_08-01-05.md',\n * // ]\n * ```\n */\nexport function resolveSessionPaths(\n id: string,\n config: SessionDirectoryConfig = DEFAULT_SESSION_CONFIG,\n): string[] {\n const filename = `${id}.md`;\n\n return [\n `${config.todoDir}/${filename}`,\n `${config.doingDir}/${filename}`,\n `${config.archiveDir}/${filename}`,\n ];\n}\n\n/**\n * Formats session content for display with metadata header.\n *\n * @param content - Raw session file content\n * @param options - Display options including status\n * @returns Formatted output string with metadata header\n *\n * @example\n * ```typescript\n * const output = formatShowOutput(sessionContent, { status: 'todo' });\n * // => \"Status: todo\\nPriority: high\\n---\\n# Session Content...\"\n * ```\n */\nexport function formatShowOutput(\n content: string,\n options: ShowOutputOptions,\n): string {\n const metadata = parseSessionMetadata(content);\n\n // Build header with extracted metadata\n const headerLines: string[] = [\n `Status: ${options.status}`,\n `Priority: ${metadata.priority}`,\n ];\n\n // Add optional metadata if present\n if (metadata.id) {\n headerLines.unshift(`ID: ${metadata.id}`);\n }\n if (metadata.branch) {\n headerLines.push(`Branch: ${metadata.branch}`);\n }\n if (metadata.tags.length > 0) {\n headerLines.push(`Tags: ${metadata.tags.join(\", \")}`);\n }\n if (metadata.createdAt) {\n headerLines.push(`Created: ${metadata.createdAt}`);\n }\n\n // Combine header with separator and original content\n const header = headerLines.join(\"\\n\");\n const separator = \"\\n\" + \"─\".repeat(40) + \"\\n\\n\";\n\n return header + separator + content;\n}\n","/**\n * Session listing and sorting utilities.\n *\n * @module session/list\n */\n\nimport { parse as parseYaml } from \"yaml\";\n\nimport { parseSessionId } from \"./timestamp\";\nimport {\n DEFAULT_PRIORITY,\n PRIORITY_ORDER,\n type Session,\n SESSION_FRONT_MATTER,\n type SessionMetadata,\n type SessionPriority,\n} from \"./types\";\n\n/**\n * Regular expression to match YAML front matter.\n * Matches content between opening `---` and closing `---` or `...`\n */\nconst FRONT_MATTER_PATTERN = /^---\\r?\\n([\\s\\S]*?)\\r?\\n(?:---|\\.\\.\\.)\\r?\\n?/;\n\n/**\n * Validates if a value is a valid priority.\n */\nfunction isValidPriority(value: unknown): value is SessionPriority {\n return value === \"high\" || value === \"medium\" || value === \"low\";\n}\n\n/**\n * Parses YAML front matter from session content to extract metadata.\n *\n * @param content - Full session file content\n * @returns Extracted metadata with defaults for missing fields\n *\n * @example\n * ```typescript\n * const metadata = parseSessionMetadata(`---\n * priority: high\n * tags: [bug, urgent]\n * ---\n * # Session content`);\n * // => { priority: 'high', tags: ['bug', 'urgent'] }\n * ```\n */\nexport function parseSessionMetadata(content: string): SessionMetadata {\n const match = FRONT_MATTER_PATTERN.exec(content);\n\n if (!match) {\n return {\n priority: DEFAULT_PRIORITY,\n tags: [],\n };\n }\n\n try {\n const parsed = parseYaml(match[1]) as Record<string, unknown>;\n\n if (!parsed || typeof parsed !== \"object\") {\n return {\n priority: DEFAULT_PRIORITY,\n tags: [],\n };\n }\n\n const rawPriority = parsed[SESSION_FRONT_MATTER.PRIORITY];\n const priority = isValidPriority(rawPriority) ? rawPriority : DEFAULT_PRIORITY;\n\n const rawTags = parsed[SESSION_FRONT_MATTER.TAGS];\n const tags: string[] = Array.isArray(rawTags)\n ? rawTags.filter((t): t is string => typeof t === \"string\")\n : [];\n\n const metadata: SessionMetadata = { priority, tags };\n\n const id = parsed[SESSION_FRONT_MATTER.ID];\n if (typeof id === \"string\") metadata.id = id;\n\n const branch = parsed[SESSION_FRONT_MATTER.BRANCH];\n if (typeof branch === \"string\") metadata.branch = branch;\n\n const createdAt = parsed[SESSION_FRONT_MATTER.CREATED_AT];\n if (typeof createdAt === \"string\") metadata.createdAt = createdAt;\n\n const agentSessionId = parsed[SESSION_FRONT_MATTER.AGENT_SESSION_ID];\n if (typeof agentSessionId === \"string\") metadata.agentSessionId = agentSessionId;\n\n const workingDirectory = parsed[SESSION_FRONT_MATTER.WORKING_DIRECTORY];\n if (typeof workingDirectory === \"string\") metadata.workingDirectory = workingDirectory;\n\n const specs = parsed[SESSION_FRONT_MATTER.SPECS];\n if (Array.isArray(specs)) {\n metadata.specs = specs.filter((s): s is string => typeof s === \"string\");\n }\n\n const files = parsed[SESSION_FRONT_MATTER.FILES];\n if (Array.isArray(files)) {\n metadata.files = files.filter((f): f is string => typeof f === \"string\");\n }\n\n return metadata;\n } catch {\n // Malformed YAML, return defaults\n return {\n priority: DEFAULT_PRIORITY,\n tags: [],\n };\n }\n}\n\n/**\n * Sorts sessions by priority (high first) then by timestamp (newest first).\n *\n * @param sessions - Array of sessions to sort\n * @returns New sorted array (does not mutate input)\n *\n * @example\n * ```typescript\n * const sorted = sortSessions([\n * { id: 'a', metadata: { priority: 'low' } },\n * { id: 'b', metadata: { priority: 'high' } },\n * ]);\n * // => [{ id: 'b', ... }, { id: 'a', ... }]\n * ```\n */\nexport function sortSessions(sessions: Session[]): Session[] {\n return [...sessions].sort((a, b) => {\n // First: sort by priority (high = 0, medium = 1, low = 2)\n const priorityA = PRIORITY_ORDER[a.metadata.priority];\n const priorityB = PRIORITY_ORDER[b.metadata.priority];\n\n if (priorityA !== priorityB) {\n return priorityA - priorityB;\n }\n\n // Second: sort by timestamp (newest first = descending)\n const dateA = parseSessionId(a.id);\n const dateB = parseSessionId(b.id);\n\n // Handle invalid session IDs by treating them as oldest\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1; // a goes after b\n if (!dateB) return -1; // b goes after a\n\n return dateB.getTime() - dateA.getTime();\n });\n}\n","/**\n * Session timestamp utilities for generating and parsing session IDs.\n *\n * Session IDs use the format YYYY-MM-DD_HH-mm-ss as specified in\n * ADR-32 (Timestamp Format).\n *\n * @module session/timestamp\n */\n\n/**\n * Regular expression pattern for validating session IDs.\n * Format: YYYY-MM-DD_HH-mm-ss (all components zero-padded)\n *\n * Exported for use in validation and testing.\n */\nexport const SESSION_ID_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})_(\\d{2})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Separator between date and time components in session IDs.\n */\nexport const SESSION_ID_SEPARATOR = \"_\";\n\n/**\n * Options for generating session IDs.\n */\nexport interface GenerateSessionIdOptions {\n /**\n * Function that returns the current time.\n * Defaults to `() => new Date()` for production use.\n * Injectable for deterministic testing.\n */\n now?: () => Date;\n}\n\n/**\n * Generates a session ID from the current (or injected) time.\n *\n * @param options - Optional configuration including time source\n * @returns Session ID in format YYYY-MM-DD_HH-mm-ss\n *\n * @example\n * ```typescript\n * // Production usage\n * const id = generateSessionId();\n * // => \"2026-01-13_08-01-05\"\n *\n * // Testing with injected time\n * const id = generateSessionId({ now: () => new Date('2026-01-13T08:01:05') });\n * // => \"2026-01-13_08-01-05\"\n * ```\n */\nexport function generateSessionId(options: GenerateSessionIdOptions = {}): string {\n const now = options.now ?? (() => new Date());\n const date = now();\n\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day}${SESSION_ID_SEPARATOR}${hours}-${minutes}-${seconds}`;\n}\n\n/**\n * Parses a session ID string back into a Date object.\n *\n * @param id - Session ID string to parse\n * @returns Date object if valid, null if invalid format\n *\n * @example\n * ```typescript\n * const date = parseSessionId('2026-01-13_08-01-05');\n * // => Date representing 2026-01-13T08:01:05 (local time)\n *\n * const invalid = parseSessionId('invalid-format');\n * // => null\n * ```\n */\nexport function parseSessionId(id: string): Date | null {\n const match = SESSION_ID_PATTERN.exec(id);\n\n if (!match) {\n return null;\n }\n\n const [, yearStr, monthStr, dayStr, hoursStr, minutesStr, secondsStr] = match;\n\n const year = parseInt(yearStr, 10);\n const month = parseInt(monthStr, 10) - 1; // Date months are 0-indexed\n const day = parseInt(dayStr, 10);\n const hours = parseInt(hoursStr, 10);\n const minutes = parseInt(minutesStr, 10);\n const seconds = parseInt(secondsStr, 10);\n\n // Validate component ranges\n if (month < 0 || month > 11) return null;\n if (day < 1 || day > 31) return null;\n if (hours < 0 || hours > 23) return null;\n if (minutes < 0 || minutes > 59) return null;\n if (seconds < 0 || seconds > 59) return null;\n\n return new Date(year, month, day, hours, minutes, seconds);\n}\n","/**\n * Session type definitions for the session management domain.\n *\n * @module session/types\n */\n\n/**\n * Priority levels for session ordering.\n * Sessions are sorted: high → medium → low\n */\nexport type SessionPriority = \"high\" | \"medium\" | \"low\";\n\n/**\n * All valid session statuses, derived from directory structure per ADR-21.\n * This is the single source of truth — SessionStatus type derives from it.\n */\nexport const SESSION_STATUSES = [\"todo\", \"doing\", \"archive\"] as const;\n\n/**\n * Status derived from directory location per ADR-21.\n */\nexport type SessionStatus = (typeof SESSION_STATUSES)[number];\n\n/**\n * Default statuses shown by `spx session list` when no --status filter is provided.\n * Excludes archive — use `--status archive` to see archived sessions.\n */\nexport const DEFAULT_LIST_STATUSES: readonly SessionStatus[] = [\"doing\", \"todo\"] as const;\n\n/**\n * Priority sort order (lower number = higher priority).\n */\nexport const PRIORITY_ORDER: Record<SessionPriority, number> = {\n high: 0,\n medium: 1,\n low: 2,\n} as const;\n\n/**\n * Default priority when not specified in YAML front matter.\n */\nexport const DEFAULT_PRIORITY: SessionPriority = \"medium\";\n\n/**\n * YAML front matter keys for session files.\n * Single source of truth for the serialized session schema.\n */\nexport const SESSION_FRONT_MATTER = {\n PRIORITY: \"priority\",\n TAGS: \"tags\",\n ID: \"id\",\n BRANCH: \"branch\",\n CREATED_AT: \"created_at\",\n AGENT_SESSION_ID: \"agent_session_id\",\n WORKING_DIRECTORY: \"working_directory\",\n SPECS: \"specs\",\n FILES: \"files\",\n} as const;\n\n/**\n * Metadata extracted from session YAML front matter.\n */\nexport interface SessionMetadata {\n /** Session ID (from filename or YAML) */\n id?: string;\n /** Priority level for sorting */\n priority: SessionPriority;\n /** Free-form tags for filtering */\n tags: string[];\n /** Git branch associated with session */\n branch?: string;\n /** Spec files to auto-inject on pickup */\n specs?: string[];\n /** Code files to auto-inject on pickup */\n files?: string[];\n /** ISO 8601 timestamp when session was created */\n createdAt?: string;\n /** Agent session ID from CLAUDE_SESSION_ID or CODEX_THREAD_ID at handoff time */\n agentSessionId?: string;\n /** Working directory path */\n workingDirectory?: string;\n}\n\n/**\n * Complete session information including status and metadata.\n */\nexport interface Session {\n /** Session ID (timestamp format: YYYY-MM-DD_HH-mm-ss) */\n id: string;\n /** Status derived from directory location */\n status: SessionStatus;\n /** Metadata from YAML front matter */\n metadata: SessionMetadata;\n /** Full path to session file */\n path: string;\n}\n","/**\n * Session handoff CLI command handler.\n *\n * Creates a new session for handoff to another agent context.\n * Metadata (priority, tags) should be included in the content as YAML frontmatter.\n *\n * @module commands/session/handoff\n */\n\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport { resolveSessionConfig } from \"../../git/root.js\";\nimport { preFillSessionContent, validateSessionContent } from \"../../session/create.js\";\nimport { SessionInvalidContentError } from \"../../session/errors.js\";\nimport { generateSessionId } from \"../../session/timestamp.js\";\n\n/**\n * Regex to detect YAML frontmatter presence.\n * Matches opening `---` at start of content.\n */\nconst FRONT_MATTER_START = /^---\\r?\\n/;\n\n/**\n * Options for the handoff command.\n */\nexport interface HandoffOptions {\n /** Session content (from stdin). Should include YAML frontmatter with priority/tags. */\n content?: string;\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Checks if content has YAML frontmatter.\n *\n * @param content - Raw session content\n * @returns True if content starts with frontmatter delimiter\n */\nexport function hasFrontmatter(content: string): boolean {\n return FRONT_MATTER_START.test(content);\n}\n\n/**\n * Builds session content, adding default frontmatter only if not present.\n *\n * If content already has frontmatter, returns as-is (preserves agent-provided metadata).\n * If content lacks frontmatter, adds default frontmatter with medium priority.\n *\n * @param content - Raw content from stdin\n * @returns Content ready to be written to session file\n */\nexport function buildSessionContent(content: string | undefined): string {\n // Default content if none provided\n if (!content || content.trim().length === 0) {\n return `---\npriority: medium\n---\n\n# New Session\n\nDescribe your task here.`;\n }\n\n // If content already has frontmatter, preserve it as-is\n if (hasFrontmatter(content)) {\n return content;\n }\n\n // Add default frontmatter to content without it\n return `---\npriority: medium\n---\n\n${content}`;\n}\n\n/**\n * Executes the handoff command.\n *\n * Creates a new session in the todo directory for pickup by another context.\n * Output includes `<HANDOFF_ID>` tag for easy parsing by automation tools.\n *\n * When no --sessions-dir is provided, sessions are created at the git repository root\n * (if in a git repo) to ensure consistent location across subdirectories.\n *\n * Metadata (priority, tags) should be included in the content as YAML frontmatter:\n * ```\n * ---\n * priority: high\n * tags: [feature, api]\n * ---\n * # Session content...\n * ```\n *\n * @param options - Command options\n * @returns Formatted output for display with parseable session ID\n * @throws {SessionInvalidContentError} When content validation fails\n */\nexport async function handoffCommand(options: HandoffOptions): Promise<string> {\n const { config, warning } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n // Generate session ID\n const sessionId = generateSessionId();\n\n const baseContent = buildSessionContent(options.content);\n const agentSessionId = process.env.CLAUDE_SESSION_ID ?? process.env.CODEX_THREAD_ID;\n const fullContent = preFillSessionContent(baseContent, {\n createdAt: new Date(),\n agentSessionId,\n });\n\n const validation = validateSessionContent(fullContent);\n if (!validation.valid) {\n throw new SessionInvalidContentError(validation.error ?? \"Unknown validation error\");\n }\n\n // Build path to session file\n const filename = `${sessionId}.md`;\n const sessionPath = join(config.todoDir, filename);\n const absolutePath = resolve(sessionPath);\n\n // Ensure directory exists\n await mkdir(config.todoDir, { recursive: true });\n\n // Write file\n await writeFile(sessionPath, fullContent, \"utf-8\");\n\n // Emit warning to stderr if not in git repo\n if (warning) {\n process.stderr.write(`${warning}\\n`);\n }\n\n return `Created handoff session <HANDOFF_ID>${sessionId}</HANDOFF_ID>\\n<SESSION_FILE>${absolutePath}</SESSION_FILE>`;\n}\n","/**\n * Session creation utilities.\n *\n * @module session/create\n */\n\nimport { SESSION_FRONT_MATTER } from \"./types.js\";\n\nexport const MIN_CONTENT_LENGTH = 1;\n\nconst FRONT_MATTER_OPEN = /^---\\r?\\n/;\n\nexport interface PreFillParams {\n createdAt: Date;\n agentSessionId?: string;\n}\n\n/**\n * Result of session content validation.\n */\nexport interface ValidationResult {\n /** Whether the content is valid */\n valid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\nexport function preFillSessionContent(content: string, params: PreFillParams): string {\n const match = FRONT_MATTER_OPEN.exec(content);\n if (!match) return content;\n const lines = [`${SESSION_FRONT_MATTER.CREATED_AT}: \"${params.createdAt.toISOString()}\"`];\n if (params.agentSessionId !== undefined) {\n lines.push(`${SESSION_FRONT_MATTER.AGENT_SESSION_ID}: \"${params.agentSessionId}\"`);\n }\n return match[0] + lines.join(\"\\n\") + \"\\n\" + content.slice(match[0].length);\n}\n\nexport function validateSessionContent(content: string): ValidationResult {\n if (!content || content.trim().length < MIN_CONTENT_LENGTH) {\n return {\n valid: false,\n error: \"Session content cannot be empty\",\n };\n }\n\n return { valid: true };\n}\n","/**\n * Session list CLI command handler.\n *\n * @module commands/session/list\n */\n\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { resolveSessionConfig } from \"../../git/root.js\";\nimport { parseSessionMetadata, sortSessions } from \"../../session/list.js\";\nimport type { SessionDirectoryConfig } from \"../../session/show.js\";\nimport { DEFAULT_LIST_STATUSES, type Session, SESSION_STATUSES, type SessionStatus } from \"../../session/types.js\";\n\n/**\n * Options for the list command.\n * Note: status is string (not SessionStatus) because it comes from user input via Commander.js.\n * Validation happens inside listCommand per ADR 001-cli-framework.\n */\nexport interface ListOptions {\n /** Filter by status (validated against SESSION_STATUSES) */\n status?: string;\n /** Custom sessions directory */\n sessionsDir?: string;\n /** Output format */\n format?: \"text\" | \"json\";\n}\n\n/**\n * Loads sessions from a specific directory.\n */\nasync function loadSessionsFromDir(\n dir: string,\n status: SessionStatus,\n): Promise<Session[]> {\n try {\n const files = await readdir(dir);\n const sessions: Session[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".md\")) continue;\n\n const id = file.replace(\".md\", \"\");\n const filePath = join(dir, file);\n const content = await readFile(filePath, \"utf-8\");\n const metadata = parseSessionMetadata(content);\n\n sessions.push({\n id,\n status,\n path: filePath,\n metadata,\n });\n }\n\n return sessions;\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Maps a session status to its directory path in the config.\n */\nconst STATUS_DIR_KEY: Record<SessionStatus, keyof SessionDirectoryConfig> = {\n todo: \"todoDir\",\n doing: \"doingDir\",\n archive: \"archiveDir\",\n};\n\n/**\n * Formats sessions for text output.\n */\nfunction formatTextOutput(sessions: Session[]): string {\n if (sessions.length === 0) {\n return ` (no sessions)`;\n }\n\n return sessions\n .map((s) => {\n const priority = s.metadata.priority !== \"medium\" ? ` [${s.metadata.priority}]` : \"\";\n const tags = s.metadata.tags.length > 0 ? ` (${s.metadata.tags.join(\", \")})` : \"\";\n return ` ${s.id}${priority}${tags}`;\n })\n .join(\"\\n\");\n}\n\n/**\n * Executes the list command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n */\n/**\n * Validates a user-supplied status string against SESSION_STATUSES.\n * Returns the validated SessionStatus or throws with valid values listed.\n */\nfunction validateStatus(input: string): SessionStatus {\n if (SESSION_STATUSES.includes(input as SessionStatus)) {\n return input as SessionStatus;\n }\n throw new Error(\n `Invalid status: \"${input}\". Valid values: ${SESSION_STATUSES.join(\", \")}`,\n );\n}\n\nexport async function listCommand(options: ListOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n // Validate and resolve statuses per ADR 001-cli-framework\n const statuses: readonly SessionStatus[] = options.status !== undefined\n ? [validateStatus(options.status)]\n : DEFAULT_LIST_STATUSES;\n\n const sessionsByStatus: Partial<Record<SessionStatus, Session[]>> = {};\n\n for (const status of statuses) {\n const dirKey = STATUS_DIR_KEY[status];\n const sessions = await loadSessionsFromDir(config[dirKey], status);\n sessionsByStatus[status] = sortSessions(sessions);\n }\n\n // Format output\n if (options.format === \"json\") {\n return JSON.stringify(sessionsByStatus, null, 2);\n }\n\n // Text format\n const lines: string[] = [];\n\n for (const status of statuses) {\n lines.push(`${status.toUpperCase()}:`);\n lines.push(formatTextOutput(sessionsByStatus[status] ?? []));\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\").trim();\n}\n","/**\n * Session pickup CLI command handler.\n *\n * @module commands/session/pickup\n */\n\nimport { mkdir, readdir, readFile, rename } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { resolveSessionConfig } from \"../../git/root.js\";\nimport { NoSessionsAvailableError } from \"../../session/errors.js\";\nimport { parseSessionMetadata } from \"../../session/list.js\";\nimport { buildClaimPaths, classifyClaimError, selectBestSession } from \"../../session/pickup.js\";\nimport { formatShowOutput, type SessionDirectoryConfig } from \"../../session/show.js\";\nimport { type Session, SESSION_STATUSES, type SessionStatus } from \"../../session/types.js\";\n\n/** Status of sessions available for pickup. */\nconst PICKUP_SOURCE_STATUS: SessionStatus = SESSION_STATUSES[0]; // todo\n/** Status of sessions after being claimed. */\nconst PICKUP_TARGET_STATUS: SessionStatus = SESSION_STATUSES[1]; // doing\n\n/**\n * Options for the pickup command.\n */\nexport interface PickupOptions {\n /** Session ID to pickup (mutually exclusive with auto) */\n sessionId?: string;\n /** Auto-select highest priority session */\n auto?: boolean;\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Loads sessions from the todo directory.\n */\nasync function loadTodoSessions(config: SessionDirectoryConfig): Promise<Session[]> {\n try {\n const files = await readdir(config.todoDir);\n const sessions: Session[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".md\")) continue;\n\n const id = file.replace(\".md\", \"\");\n const filePath = join(config.todoDir, file);\n const content = await readFile(filePath, \"utf-8\");\n const metadata = parseSessionMetadata(content);\n\n sessions.push({\n id,\n status: PICKUP_SOURCE_STATUS,\n path: filePath,\n metadata,\n });\n }\n\n return sessions;\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Executes the pickup command.\n *\n * Claims a session from the todo queue and moves it to doing.\n * Output includes `<PICKUP_ID>` tag for easy parsing by automation tools.\n *\n * @param options - Command options\n * @returns Formatted output for display with parseable session ID\n * @throws {NoSessionsAvailableError} When no sessions in todo for auto mode\n * @throws {SessionNotAvailableError} When session already claimed\n */\nexport async function pickupCommand(options: PickupOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n let sessionId: string;\n\n if (options.auto) {\n // Auto mode: select best session\n const sessions = await loadTodoSessions(config);\n const selected = selectBestSession(sessions);\n\n if (!selected) {\n throw new NoSessionsAvailableError();\n }\n\n sessionId = selected.id;\n } else if (options.sessionId) {\n sessionId = options.sessionId;\n } else {\n throw new Error(\"Either session ID or --auto flag is required\");\n }\n\n // Build paths and ensure doing directory exists\n const paths = buildClaimPaths(sessionId, config);\n await mkdir(config.doingDir, { recursive: true });\n\n // Perform atomic claim\n try {\n await rename(paths.source, paths.target);\n } catch (error) {\n throw classifyClaimError(error, sessionId);\n }\n\n // Read and format content\n const content = await readFile(paths.target, \"utf-8\");\n const output = formatShowOutput(content, { status: PICKUP_TARGET_STATUS });\n\n // Output with parseable PICKUP_ID tag\n return `Claimed session <PICKUP_ID>${sessionId}</PICKUP_ID>\\n\\n${output}`;\n}\n","/**\n * Session pickup/claiming utilities.\n *\n * This module provides pure functions for atomic session claiming:\n * - Path construction for claim operations\n * - Error classification for claim failures\n * - Session selection for auto-pickup\n *\n * @module session/pickup\n */\n\nimport { SessionNotAvailableError } from \"./errors\";\nimport { parseSessionId } from \"./timestamp\";\nimport { PRIORITY_ORDER, type Session } from \"./types\";\n\n/**\n * Configuration for session claim paths.\n */\nexport interface ClaimPathConfig {\n /** Directory containing sessions to be claimed */\n todoDir: string;\n /** Directory for claimed sessions */\n doingDir: string;\n}\n\n/**\n * Result of building claim paths.\n */\nexport interface ClaimPaths {\n /** Source path (session in todo) */\n source: string;\n /** Target path (session in doing) */\n target: string;\n}\n\n/**\n * Builds source and target paths for claiming a session.\n *\n * @param sessionId - The session ID (timestamp format)\n * @param config - Directory configuration\n * @returns Source and target paths for the claim operation\n *\n * @example\n * ```typescript\n * const paths = buildClaimPaths(\"2026-01-13_08-01-05\", {\n * todoDir: \".spx/sessions/todo\",\n * doingDir: \".spx/sessions/doing\",\n * });\n * // => { source: \".spx/sessions/todo/2026-01-13_08-01-05.md\", target: \".spx/sessions/doing/2026-01-13_08-01-05.md\" }\n * ```\n */\nexport function buildClaimPaths(sessionId: string, config: ClaimPathConfig): ClaimPaths {\n return {\n source: `${config.todoDir}/${sessionId}.md`,\n target: `${config.doingDir}/${sessionId}.md`,\n };\n}\n\n/**\n * Classifies a filesystem error that occurred during claiming.\n *\n * When a claim operation fails, this function maps the raw filesystem\n * error to an appropriate domain error:\n * - ENOENT: Session was claimed by another agent (SessionNotAvailable)\n * - Other errors: Rethrown as-is\n *\n * @param error - The error from the claim operation\n * @param sessionId - The session ID being claimed\n * @returns A SessionNotAvailableError if ENOENT\n * @throws The original error if not ENOENT\n *\n * @example\n * ```typescript\n * const err = Object.assign(new Error(\"ENOENT\"), { code: \"ENOENT\" });\n * const classified = classifyClaimError(err, \"test-id\");\n * // => SessionNotAvailableError\n * ```\n */\nexport function classifyClaimError(error: unknown, sessionId: string): SessionNotAvailableError {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return new SessionNotAvailableError(sessionId);\n }\n throw error;\n}\n\n/**\n * Selects the best session for auto-pickup based on priority and timestamp.\n *\n * Selection criteria:\n * 1. Highest priority (high > medium > low)\n * 2. Oldest timestamp (FIFO) for sessions with equal priority\n *\n * @param sessions - Available sessions to choose from\n * @returns The best session to claim, or null if no sessions available\n *\n * @example\n * ```typescript\n * const sessions = [\n * { id: \"low-1\", metadata: { priority: \"low\" } },\n * { id: \"high-1\", metadata: { priority: \"high\" } },\n * ];\n * const best = selectBestSession(sessions);\n * // => { id: \"high-1\", ... }\n * ```\n */\nexport function selectBestSession(sessions: Session[]): Session | null {\n if (sessions.length === 0) {\n return null;\n }\n\n // Sort by priority (high first) then by timestamp (oldest first for FIFO)\n const sorted = [...sessions].sort((a, b) => {\n // First: sort by priority (high = 0, medium = 1, low = 2)\n const priorityA = PRIORITY_ORDER[a.metadata.priority];\n const priorityB = PRIORITY_ORDER[b.metadata.priority];\n\n if (priorityA !== priorityB) {\n return priorityA - priorityB;\n }\n\n // Second: sort by timestamp (oldest first = FIFO = ascending)\n const dateA = parseSessionId(a.id);\n const dateB = parseSessionId(b.id);\n\n // Handle invalid session IDs by treating them as newest (go last)\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1; // a goes after b\n if (!dateB) return -1; // b goes after a\n\n return dateA.getTime() - dateB.getTime();\n });\n\n return sorted[0];\n}\n","/**\n * Session prune CLI command handler.\n *\n * @module commands/session/prune\n */\n\nimport { readdir, readFile, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { resolveSessionConfig } from \"../../git/root.js\";\nimport { parseSessionMetadata } from \"../../session/list.js\";\nimport { DEFAULT_KEEP_COUNT, selectSessionsToDelete } from \"../../session/prune.js\";\nimport type { SessionDirectoryConfig } from \"../../session/show.js\";\nimport { type Session, SESSION_STATUSES, type SessionStatus } from \"../../session/types.js\";\n\nexport { DEFAULT_KEEP_COUNT };\n\n/** Prune operates only on archived sessions. */\nconst PRUNE_STATUS: SessionStatus = SESSION_STATUSES[2]; // archive\n\n/**\n * Options for the prune command.\n */\nexport interface PruneOptions {\n /** Number of sessions to keep (default: 5) */\n keep?: number;\n /** Show what would be deleted without actually deleting */\n dryRun?: boolean;\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Error thrown when prune options are invalid.\n */\nexport class PruneValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PruneValidationError\";\n }\n}\n\n/**\n * Validates prune options.\n *\n * @param options - Options to validate\n * @throws {PruneValidationError} When options are invalid\n */\nexport function validatePruneOptions(options: PruneOptions): void {\n if (options.keep !== undefined) {\n if (!Number.isInteger(options.keep) || options.keep < 1) {\n throw new PruneValidationError(\n `Invalid --keep value: ${options.keep}. Must be a positive integer.`,\n );\n }\n }\n}\n\n/**\n * Loads sessions from the archive directory.\n */\nasync function loadArchiveSessions(config: SessionDirectoryConfig): Promise<Session[]> {\n try {\n const files = await readdir(config.archiveDir);\n const sessions: Session[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".md\")) continue;\n\n const id = file.replace(\".md\", \"\");\n const filePath = join(config.archiveDir, file);\n const content = await readFile(filePath, \"utf-8\");\n const metadata = parseSessionMetadata(content);\n\n sessions.push({\n id,\n status: PRUNE_STATUS,\n path: filePath,\n metadata,\n });\n }\n\n return sessions;\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Executes the prune command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {PruneValidationError} When options are invalid\n */\nexport async function pruneCommand(options: PruneOptions): Promise<string> {\n // Validate options\n validatePruneOptions(options);\n\n const keep = options.keep ?? DEFAULT_KEEP_COUNT;\n const dryRun = options.dryRun ?? false;\n\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n // Load and sort sessions\n const sessions = await loadArchiveSessions(config);\n const toPrune = selectSessionsToDelete(sessions, { keep });\n\n if (toPrune.length === 0) {\n return `No sessions to prune. ${sessions.length} sessions kept.`;\n }\n\n // Dry run mode\n if (dryRun) {\n const lines = [\n `Would delete ${toPrune.length} sessions:`,\n ...toPrune.map((s) => ` - ${s.id}`),\n \"\",\n `${sessions.length - toPrune.length} sessions would be kept.`,\n ];\n return lines.join(\"\\n\");\n }\n\n // Delete sessions\n for (const session of toPrune) {\n await unlink(session.path);\n }\n\n const lines = [\n `Deleted ${toPrune.length} sessions:`,\n ...toPrune.map((s) => ` - ${s.id}`),\n \"\",\n `${sessions.length - toPrune.length} sessions kept.`,\n ];\n return lines.join(\"\\n\");\n}\n","/**\n * Session pruning utilities for cleaning up old sessions.\n *\n * @module session/prune\n */\n\nimport { parseSessionId } from \"./timestamp\";\nimport type { Session } from \"./types\";\n\n/**\n * Default number of sessions to keep when pruning.\n */\nexport const DEFAULT_KEEP_COUNT = 5;\n\n/**\n * Options for selecting sessions to delete.\n */\nexport interface SelectSessionsOptions {\n /**\n * Number of most recent sessions to keep.\n * Defaults to DEFAULT_KEEP_COUNT (5).\n */\n keep?: number;\n}\n\n/**\n * Selects sessions to delete based on keep count.\n *\n * Sessions are sorted by timestamp (oldest first), and the oldest sessions\n * beyond the keep count are selected for deletion.\n *\n * @param sessions - Array of sessions to consider\n * @param options - Selection options including keep count\n * @returns Array of sessions to delete (oldest sessions beyond keep count)\n *\n * @example\n * ```typescript\n * // Given 10 sessions, keep 5 newest\n * const toDelete = selectSessionsToDelete(sessions, { keep: 5 });\n * // Returns the 5 oldest sessions\n *\n * // Using default keep count (5)\n * const toDelete = selectSessionsToDelete(sessions);\n * ```\n */\nexport function selectSessionsToDelete(\n sessions: Session[],\n options: SelectSessionsOptions = {},\n): Session[] {\n const keep = options.keep ?? DEFAULT_KEEP_COUNT;\n\n // If we have fewer sessions than the keep count, delete nothing\n if (sessions.length <= keep) {\n return [];\n }\n\n // Sort sessions by timestamp (oldest first for deletion selection)\n const sorted = [...sessions].sort((a, b) => {\n const dateA = parseSessionId(a.id);\n const dateB = parseSessionId(b.id);\n\n // Handle invalid session IDs by treating them as oldest (delete first)\n if (!dateA && !dateB) return 0;\n if (!dateA) return -1; // a (invalid) goes before b (to be deleted first)\n if (!dateB) return 1; // b (invalid) goes before a\n\n return dateA.getTime() - dateB.getTime();\n });\n\n // Return the oldest sessions (those beyond the keep count)\n const deleteCount = sessions.length - keep;\n return sorted.slice(0, deleteCount);\n}\n","/**\n * Session release CLI command handler.\n *\n * @module commands/session/release\n */\n\nimport { readdir, rename } from \"node:fs/promises\";\n\nimport { resolveSessionConfig } from \"../../git/root.js\";\nimport { processBatch } from \"../../session/batch.js\";\nimport { SessionNotClaimedError } from \"../../session/errors.js\";\nimport { buildReleasePaths, findCurrentSession } from \"../../session/release.js\";\nimport type { SessionDirectoryConfig } from \"../../session/show.js\";\n\n/**\n * Options for the release command.\n */\nexport interface ReleaseOptions {\n /** Session IDs to release. Empty array defaults to most recent in doing. */\n sessionIds: string[];\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Loads session refs from the doing directory.\n */\nasync function loadDoingSessions(config: SessionDirectoryConfig): Promise<Array<{ id: string }>> {\n try {\n const files = await readdir(config.doingDir);\n return files\n .filter((file) => file.endsWith(\".md\"))\n .map((file) => ({ id: file.replace(\".md\", \"\") }));\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Releases a single claimed session by ID.\n */\nasync function releaseSingle(sessionId: string, config: SessionDirectoryConfig): Promise<string> {\n const paths = buildReleasePaths(sessionId, config);\n\n try {\n await rename(paths.source, paths.target);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n throw new SessionNotClaimedError(sessionId);\n }\n throw error;\n }\n\n return `Released session: ${sessionId}\\nSession returned to todo directory.`;\n}\n\n/**\n * Executes the release command for zero or more session IDs.\n *\n * When `sessionIds` is empty, the most recently claimed session in doing is released.\n * When one or more IDs are provided, all are processed in argument order.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {BatchError} When one or more IDs fail\n * @throws {SessionNotClaimedError} When no session is claimed (empty IDs) or session not in doing (single ID)\n */\nexport async function releaseCommand(options: ReleaseOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n let ids = options.sessionIds;\n\n if (ids.length === 0) {\n const sessions = await loadDoingSessions(config);\n const current = findCurrentSession(sessions);\n\n if (!current) {\n throw new SessionNotClaimedError(\"(none)\");\n }\n\n ids = [current.id];\n }\n\n return processBatch(ids, (id) => releaseSingle(id, config));\n}\n","/**\n * Session release utilities.\n *\n * This module provides pure functions for releasing claimed sessions:\n * - Path construction for release operations\n * - Finding the current session in doing directory\n *\n * @module session/release\n */\n\nimport { parseSessionId } from \"./timestamp\";\n\n/**\n * Configuration for session release paths.\n */\nexport interface ReleasePathConfig {\n /** Directory containing claimed sessions */\n doingDir: string;\n /** Directory for released sessions */\n todoDir: string;\n}\n\n/**\n * Result of building release paths.\n */\nexport interface ReleasePaths {\n /** Source path (session in doing) */\n source: string;\n /** Target path (session in todo) */\n target: string;\n}\n\n/**\n * Session reference with minimal required fields.\n */\nexport interface SessionRef {\n id: string;\n}\n\n/**\n * Builds source and target paths for releasing a session.\n *\n * @param sessionId - The session ID (timestamp format)\n * @param config - Directory configuration\n * @returns Source and target paths for the release operation\n *\n * @example\n * ```typescript\n * const paths = buildReleasePaths(\"2026-01-13_08-01-05\", {\n * doingDir: \".spx/sessions/doing\",\n * todoDir: \".spx/sessions/todo\",\n * });\n * // => { source: \".spx/sessions/doing/2026-01-13_08-01-05.md\", target: \".spx/sessions/todo/2026-01-13_08-01-05.md\" }\n * ```\n */\nexport function buildReleasePaths(sessionId: string, config: ReleasePathConfig): ReleasePaths {\n return {\n source: `${config.doingDir}/${sessionId}.md`,\n target: `${config.todoDir}/${sessionId}.md`,\n };\n}\n\n/**\n * Finds the most recent session in the doing directory.\n *\n * When no session ID is provided to release, this function\n * selects the most recently claimed session (newest timestamp).\n *\n * @param doingSessions - Sessions currently in doing directory\n * @returns The most recent session, or null if empty\n *\n * @example\n * ```typescript\n * const sessions = [\n * { id: \"2026-01-10_08-00-00\" },\n * { id: \"2026-01-13_08-00-00\" },\n * ];\n * const current = findCurrentSession(sessions);\n * // => { id: \"2026-01-13_08-00-00\" }\n * ```\n */\nexport function findCurrentSession(doingSessions: SessionRef[]): SessionRef | null {\n if (doingSessions.length === 0) {\n return null;\n }\n\n // Sort by timestamp descending (newest first)\n const sorted = [...doingSessions].sort((a, b) => {\n const dateA = parseSessionId(a.id);\n const dateB = parseSessionId(b.id);\n\n // Handle invalid session IDs by treating them as oldest\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1; // a goes after b\n if (!dateB) return -1; // b goes after a\n\n return dateB.getTime() - dateA.getTime();\n });\n\n return sorted[0];\n}\n","/**\n * Session show CLI command handler.\n *\n * @module commands/session/show\n */\n\nimport { readFile, stat } from \"node:fs/promises\";\n\nimport { resolveSessionConfig } from \"../../git/root.js\";\nimport { processBatch } from \"../../session/batch.js\";\nimport { SessionNotFoundError } from \"../../session/errors.js\";\nimport {\n formatShowOutput,\n resolveSessionPaths,\n SEARCH_ORDER,\n type SessionDirectoryConfig,\n} from \"../../session/show.js\";\nimport type { SessionStatus } from \"../../session/types.js\";\n\n/**\n * Options for the show command.\n */\nexport interface ShowOptions {\n /** Session ID(s) to show */\n sessionIds: string[];\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Finds the first existing path and its status.\n */\nasync function findExistingPath(\n paths: string[],\n _config: SessionDirectoryConfig,\n): Promise<{ path: string; status: SessionStatus } | null> {\n for (let i = 0; i < paths.length; i++) {\n const filePath = paths[i];\n try {\n const stats = await stat(filePath);\n if (stats.isFile()) {\n return { path: filePath, status: SEARCH_ORDER[i] };\n }\n } catch {\n // File doesn't exist, continue\n }\n }\n return null;\n}\n\n/**\n * Executes the show command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {SessionNotFoundError} When session not found\n */\n/**\n * Shows a single session by ID.\n */\nasync function showSingle(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<string> {\n const paths = resolveSessionPaths(sessionId, config);\n const found = await findExistingPath(paths, config);\n\n if (!found) {\n throw new SessionNotFoundError(sessionId);\n }\n\n const content = await readFile(found.path, \"utf-8\");\n return formatShowOutput(content, { status: found.status });\n}\n\n/**\n * Executes the show command for one or more session IDs.\n *\n * @param options - Command options with one or more session IDs\n * @returns Formatted output for display\n * @throws {BatchError} When one or more IDs fail\n * @throws {SessionNotFoundError} When session not found (single ID)\n */\nexport async function showCommand(options: ShowOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n return processBatch(options.sessionIds, (id) => showSingle(id, config));\n}\n","/**\n * Shared help text for session commands.\n *\n * Centralizes help text to ensure consistency across subcommands.\n *\n * @module domains/session/help\n */\n\n/**\n * Session file format description for the main session help.\n */\nexport const SESSION_FORMAT_HELP = `\nSession File Format:\n Sessions are markdown files with YAML frontmatter for metadata.\n\n ---\n priority: high | medium | low\n tags: [tag1, tag2]\n ---\n # Session Title\n\n Session content...\n\nWorkflow:\n 1. handoff - Create session (todo)\n 2. pickup - Claim session (todo -> doing)\n 3. release - Return session (doing -> todo)\n 4. archive - Move session to archive\n 5. delete - Remove session permanently\n`;\n\n/**\n * Frontmatter details for handoff command.\n */\nexport const HANDOFF_FRONTMATTER_HELP = `\nUsage:\n Option 1: Pipe content with frontmatter via stdin\n Option 2: Run without stdin, then edit the created file directly\n\nFrontmatter Format:\n ---\n priority: high # high | medium | low (default: medium)\n tags: [feat, api] # optional labels for categorization\n ---\n # Your session content here...\n\nOutput Tags (for automation):\n <HANDOFF_ID>session-id</HANDOFF_ID> - Session identifier\n <SESSION_FILE>/path/to/file</SESSION_FILE> - Absolute path to edit\n\nExamples:\n # With stdin content:\n echo '---\n priority: high\n ---\n # Fix login' | spx session handoff\n\n # Without stdin (creates empty session, edit file directly):\n spx session handoff\n`;\n\n/**\n * Selection logic for pickup command.\n */\nexport const PICKUP_SELECTION_HELP = `\nSelection Logic (--auto):\n Sessions are selected by priority, then age (FIFO):\n 1. high priority first\n 2. medium priority second\n 3. low priority last\n 4. Within same priority: oldest session first\n\nOutput:\n <PICKUP_ID>session-id</PICKUP_ID> tag for automation parsing\n`;\n","/**\n * Session domain - Manage session workflow\n */\nimport type { Command } from \"commander\";\n\nimport {\n archiveCommand,\n deleteCommand,\n handoffCommand,\n listCommand,\n pickupCommand,\n pruneCommand,\n PruneValidationError,\n releaseCommand,\n SessionAlreadyArchivedError,\n showCommand,\n} from \"../../commands/session/index.js\";\nimport { SESSION_STATUSES } from \"../../session/types.js\";\nimport type { Domain } from \"../types.js\";\nimport { HANDOFF_FRONTMATTER_HELP, PICKUP_SELECTION_HELP, SESSION_FORMAT_HELP } from \"./help.js\";\n\n/**\n * Reads content from stdin if available (piped input).\n * Returns undefined if stdin is a TTY (interactive terminal).\n */\nasync function readStdin(): Promise<string | undefined> {\n // Check if stdin is a TTY (interactive) - if so, don't wait for input\n if (process.stdin.isTTY) {\n return undefined;\n }\n\n return new Promise((resolve) => {\n let data = \"\";\n process.stdin.setEncoding(\"utf-8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim() || undefined);\n });\n // Handle case where stdin closes without data\n process.stdin.on(\"error\", () => {\n resolve(undefined);\n });\n });\n}\n\n/**\n * Handles command errors with consistent formatting.\n */\nfunction handleError(error: unknown): never {\n console.error(\"Error:\", error instanceof Error ? error.message : String(error));\n process.exit(1);\n}\n\n/**\n * Register session domain commands\n *\n * @param sessionCmd - Commander.js session domain command\n */\nfunction registerSessionCommands(sessionCmd: Command): void {\n // list command\n sessionCmd\n .command(\"list\")\n .description(\"List active sessions (doing + todo by default)\")\n .option(\"--status <status>\", \"Filter by status (todo|doing|archive); defaults to doing + todo\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (options: { status?: string; json?: boolean; sessionsDir?: string }) => {\n try {\n const output = await listCommand({\n status: options.status,\n format: options.json ? \"json\" : \"text\",\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // todo command (convenience alias for list --status todo)\n sessionCmd\n .command(\"todo\")\n .description(\"List todo sessions\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (options: { json?: boolean; sessionsDir?: string }) => {\n try {\n const output = await listCommand({\n status: SESSION_STATUSES[0],\n format: options.json ? \"json\" : \"text\",\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // show command\n sessionCmd\n .command(\"show <id...>\")\n .description(\"Show session content\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (ids: string[], options: { sessionsDir?: string }) => {\n try {\n const output = await showCommand({\n sessionIds: ids,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // pickup command\n sessionCmd\n .command(\"pickup [id]\")\n .description(\"Claim a session (move from todo to doing)\")\n .option(\"--auto\", \"Auto-select highest priority session\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .addHelpText(\"after\", PICKUP_SELECTION_HELP)\n .action(async (id: string | undefined, options: { auto?: boolean; sessionsDir?: string }) => {\n try {\n if (!id && !options.auto) {\n console.error(\"Error: Either session ID or --auto flag is required\");\n process.exit(1);\n }\n const output = await pickupCommand({\n sessionId: id,\n auto: options.auto,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // release command\n sessionCmd\n .command(\"release [ids...]\")\n .description(\"Release one or more sessions (move from doing to todo)\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (ids: string[], options: { sessionsDir?: string }) => {\n try {\n const output = await releaseCommand({\n sessionIds: ids,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // handoff command\n // Note: --priority and --tags removed. Metadata should be in content frontmatter.\n // This makes the command deterministic for Claude Code permission pre-approval.\n sessionCmd\n .command(\"handoff\")\n .description(\"Create a handoff session (reads content with frontmatter from stdin)\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .addHelpText(\"after\", HANDOFF_FRONTMATTER_HELP)\n .action(async (options: { sessionsDir?: string }) => {\n try {\n // Read content from stdin if available\n const content = await readStdin();\n\n const output = await handoffCommand({\n content,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // delete command\n sessionCmd\n .command(\"delete <id...>\")\n .description(\"Delete one or more sessions\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (ids: string[], options: { sessionsDir?: string }) => {\n try {\n const output = await deleteCommand({\n sessionIds: ids,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // prune command\n sessionCmd\n .command(\"prune\")\n .description(\"Remove old todo sessions, keeping the most recent N\")\n .option(\"--keep <count>\", \"Number of sessions to keep (default: 5)\", \"5\")\n .option(\"--dry-run\", \"Show what would be deleted without deleting\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (options: { keep?: string; dryRun?: boolean; sessionsDir?: string }) => {\n try {\n const keep = options.keep ? Number.parseInt(options.keep, 10) : undefined;\n const output = await pruneCommand({\n keep,\n dryRun: options.dryRun,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n if (error instanceof PruneValidationError) {\n console.error(\"Error:\", error.message);\n process.exit(1);\n }\n handleError(error);\n }\n });\n\n // archive command\n sessionCmd\n .command(\"archive <id...>\")\n .description(\"Move one or more sessions to the archive directory\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (ids: string[], options: { sessionsDir?: string }) => {\n try {\n const output = await archiveCommand({\n sessionIds: ids,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n if (error instanceof SessionAlreadyArchivedError) {\n console.error(\"Error:\", error.message);\n process.exit(1);\n }\n handleError(error);\n }\n });\n}\n\n/**\n * Session domain - Manage session workflow\n */\nexport const sessionDomain: Domain = {\n name: \"session\",\n description: \"Manage session workflow\",\n register: (program: Command) => {\n const sessionCmd = program\n .command(\"session\")\n .description(\"Manage session workflow\")\n .addHelpText(\"after\", SESSION_FORMAT_HELP);\n\n registerSessionCommands(sessionCmd);\n },\n};\n","/**\n * Spec domain - Manage spec workflow\n */\nimport { access, readFile, writeFile } from \"node:fs/promises\";\n\nimport type { Command } from \"commander\";\n\nimport { nextCommand } from \"../../commands/spec/next.js\";\nimport { type OutputFormat, statusCommand } from \"../../commands/spec/status.js\";\nimport { APPLY_HELP } from \"../../spec/apply/exclude/help.js\";\nimport { applyExcludeCommand } from \"../../spec/apply/exclude/index.js\";\nimport type { Domain } from \"../types.js\";\n\nconst VALID_STATUS_FORMATS: readonly OutputFormat[] = [\n \"text\",\n \"json\",\n \"markdown\",\n \"table\",\n];\n\nfunction handleCommandError(error: unknown): never {\n console.error(\"Error:\", error instanceof Error ? error.message : String(error));\n process.exit(1);\n}\n\nfunction resolveStatusFormat(options: { json?: boolean; format?: string }): OutputFormat {\n if (options.json === true) {\n return \"json\";\n }\n\n if (options.format === undefined) {\n return \"text\";\n }\n\n if (VALID_STATUS_FORMATS.includes(options.format as OutputFormat)) {\n return options.format as OutputFormat;\n }\n\n throw new Error(\n `Invalid format \"${options.format}\". Must be one of: ${VALID_STATUS_FORMATS.join(\", \")}`,\n );\n}\n\nfunction registerSpecCommands(specCmd: Command): void {\n specCmd\n .command(\"status\")\n .description(\"Get project status\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--format <format>\", \"Output format (text|json|markdown|table)\")\n .action(async (options: { json?: boolean; format?: string }) => {\n try {\n const output = await statusCommand({\n cwd: process.cwd(),\n format: resolveStatusFormat(options),\n });\n console.log(output);\n } catch (error) {\n handleCommandError(error);\n }\n });\n\n specCmd\n .command(\"next\")\n .description(\"Find next work item to work on\")\n .action(async () => {\n try {\n const output = await nextCommand({ cwd: process.cwd() });\n console.log(output);\n } catch (error) {\n handleCommandError(error);\n }\n });\n\n specCmd\n .command(\"apply\")\n .description(\"Apply spec-tree state to project configuration\")\n .addHelpText(\"after\", APPLY_HELP)\n .action(async () => {\n try {\n const result = await applyExcludeCommand({\n cwd: process.cwd(),\n deps: {\n readFile: (path: string) => readFile(path, \"utf-8\"),\n writeFile: (path: string, content: string) => writeFile(path, content, \"utf-8\"),\n fileExists: async (path: string) => {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n },\n },\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n } catch (error) {\n handleCommandError(error);\n }\n });\n}\n\n/**\n * Spec domain - Manage spec workflow\n */\nexport const specDomain: Domain = {\n name: \"spec\",\n description: \"Manage spec workflow\",\n register: (program: Command) => {\n const specCmd = program\n .command(\"spec\")\n .description(\"Manage spec workflow\");\n\n registerSpecCommands(specCmd);\n },\n};\n","/**\n * Scanner class for discovering work items in a project\n *\n * Encapsulates directory walking, filtering, and work item building with\n * configurable paths via dependency injection.\n *\n * @module scanner/scanner\n */\nimport path from \"node:path\";\nimport type { SpxConfig } from \"../config/defaults.js\";\nimport type { WorkItem } from \"../types.js\";\nimport { buildWorkItemList, filterWorkItemDirectories, walkDirectory } from \"./walk.js\";\n\n/**\n * Scanner for discovering work items in a project\n *\n * Uses dependency injection for configuration, eliminating hardcoded paths.\n * All directory paths are derived from the injected SpxConfig.\n *\n * @example\n * ```typescript\n * import { DEFAULT_CONFIG } from \"@/config/defaults\";\n *\n * const scanner = new Scanner(\"/path/to/project\", DEFAULT_CONFIG);\n * const workItems = await scanner.scan();\n * ```\n */\nexport class Scanner {\n /**\n * Create a new Scanner instance\n *\n * @param projectRoot - Absolute path to the project root directory\n * @param config - Configuration object defining directory structure\n */\n constructor(\n private readonly projectRoot: string,\n private readonly config: SpxConfig,\n ) {}\n\n /**\n * Scan the project for work items in the \"doing\" status directory\n *\n * Walks the configured specs/work/doing directory, filters for valid\n * work item directories, and returns structured work item data.\n *\n * @returns Array of work items found in the doing directory\n * @throws Error if the directory doesn't exist or is inaccessible\n */\n async scan(): Promise<WorkItem[]> {\n const doingPath = this.getDoingPath();\n\n // Walk directory to find all subdirectories\n const allEntries = await walkDirectory(doingPath);\n\n // Filter to only valid work item directories\n const workItemEntries = filterWorkItemDirectories(allEntries);\n\n // Build work item list with metadata\n return buildWorkItemList(workItemEntries);\n }\n\n /**\n * Get the full path to the \"doing\" status directory\n *\n * Constructs path from config: {projectRoot}/{specs.root}/{work.dir}/{statusDirs.doing}\n *\n * @returns Absolute path to the doing directory\n */\n getDoingPath(): string {\n return path.join(\n this.projectRoot,\n this.config.specs.root,\n this.config.specs.work.dir,\n this.config.specs.work.statusDirs.doing,\n );\n }\n\n /**\n * Get the full path to the \"backlog\" status directory\n *\n * @returns Absolute path to the backlog directory\n */\n getBacklogPath(): string {\n return path.join(\n this.projectRoot,\n this.config.specs.root,\n this.config.specs.work.dir,\n this.config.specs.work.statusDirs.backlog,\n );\n }\n\n /**\n * Get the full path to the \"done\" status directory\n *\n * @returns Absolute path to the done/archive directory\n */\n getDonePath(): string {\n return path.join(\n this.projectRoot,\n this.config.specs.root,\n this.config.specs.work.dir,\n this.config.specs.work.statusDirs.done,\n );\n }\n\n /**\n * Get the full path to the specs root directory\n *\n * @returns Absolute path to the specs root\n */\n getSpecsRootPath(): string {\n return path.join(this.projectRoot, this.config.specs.root);\n }\n\n /**\n * Get the full path to the work directory\n *\n * @returns Absolute path to the work directory\n */\n getWorkPath(): string {\n return path.join(\n this.projectRoot,\n this.config.specs.root,\n this.config.specs.work.dir,\n );\n }\n}\n","/**\n * Status determination state machine for work items\n */\nimport { access, readdir, stat } from \"fs/promises\";\nimport path from \"path\";\nimport type { WorkItemStatus } from \"../types\";\n\n/**\n * Input flags for status determination\n */\nexport interface StatusFlags {\n /** Whether tests/ directory exists */\n hasTestsDir: boolean;\n /** Whether tests/DONE.md exists */\n hasDoneMd: boolean;\n /** Whether tests/ directory is empty (excluding DONE.md) */\n testsIsEmpty: boolean;\n}\n\n/**\n * Determines work item status based on tests/ directory state\n *\n * Truth Table:\n * | hasTestsDir | testsIsEmpty | hasDoneMd | Status |\n * |-------------|--------------|-----------|-------------|\n * | false | N/A | N/A | OPEN |\n * | true | true | false | OPEN |\n * | true | true | true | DONE |\n * | true | false | false | IN_PROGRESS |\n * | true | false | true | DONE |\n *\n * @param flags - Status determination flags\n * @returns Work item status as OPEN, IN_PROGRESS, or DONE\n *\n * @example\n * ```typescript\n * // No tests directory\n * determineStatus({ hasTestsDir: false, hasDoneMd: false, testsIsEmpty: true })\n * // => \"OPEN\"\n *\n * // Tests directory with files, no DONE.md\n * determineStatus({ hasTestsDir: true, hasDoneMd: false, testsIsEmpty: false })\n * // => \"IN_PROGRESS\"\n *\n * // Tests directory with DONE.md\n * determineStatus({ hasTestsDir: true, hasDoneMd: true, testsIsEmpty: false })\n * // => \"DONE\"\n * ```\n */\nexport function determineStatus(flags: StatusFlags): WorkItemStatus {\n // No tests directory → OPEN\n if (!flags.hasTestsDir) {\n return \"OPEN\";\n }\n\n // Has DONE.md → DONE (regardless of other files)\n if (flags.hasDoneMd) {\n return \"DONE\";\n }\n\n // Has tests directory but empty → OPEN\n if (flags.testsIsEmpty) {\n return \"OPEN\";\n }\n\n // Has tests directory with files, no DONE.md → IN_PROGRESS\n return \"IN_PROGRESS\";\n}\n\n/**\n * Checks if a work item has a tests/ directory\n *\n * @param workItemPath - Absolute path to the work item directory\n * @returns Promise resolving to true if tests/ exists, false otherwise\n *\n * @example\n * ```typescript\n * const hasTests = await hasTestsDirectory('/path/to/story-21');\n * // => true if /path/to/story-21/tests exists\n * ```\n */\nexport async function hasTestsDirectory(\n workItemPath: string,\n): Promise<boolean> {\n try {\n const testsPath = path.join(workItemPath, \"tests\");\n await access(testsPath);\n return true;\n } catch (error) {\n // ENOENT means directory doesn't exist → return false\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return false;\n }\n // Re-throw permission errors and other failures\n throw error;\n }\n}\n\n/**\n * Checks if a tests/ directory is empty (has no test files)\n *\n * A directory is considered empty if it contains no files, or only contains:\n * - DONE.md (completion marker, not a test)\n * - Dotfiles like .gitkeep (version control artifacts, not tests)\n *\n * @param testsPath - Absolute path to the tests/ directory\n * @returns Promise resolving to true if empty, false if has test files\n *\n * @example\n * ```typescript\n * // Directory with only DONE.md\n * await isTestsDirectoryEmpty('/path/to/tests');\n * // => true (DONE.md doesn't count as a test)\n *\n * // Directory with test files\n * await isTestsDirectoryEmpty('/path/to/tests');\n * // => false\n * ```\n */\nexport async function isTestsDirectoryEmpty(\n testsPath: string,\n): Promise<boolean> {\n try {\n const entries = await readdir(testsPath);\n\n // Filter out DONE.md and dotfiles\n const testFiles = entries.filter((entry) => {\n // Exclude DONE.md\n if (entry === \"DONE.md\") {\n return false;\n }\n // Exclude dotfiles (.gitkeep, .DS_Store, etc.)\n if (entry.startsWith(\".\")) {\n return false;\n }\n return true;\n });\n\n // Empty if no test files remain after filtering\n return testFiles.length === 0;\n } catch (error) {\n // ENOENT means directory doesn't exist → treat as empty\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return true;\n }\n // Re-throw permission errors and other failures\n throw error;\n }\n}\n\n/**\n * Checks if a tests/ directory contains a DONE.md file\n *\n * Verifies that DONE.md exists and is a regular file (not a directory).\n * The check is case-sensitive: only \"DONE.md\" is accepted.\n *\n * @param testsPath - Absolute path to the tests/ directory\n * @returns Promise resolving to true if DONE.md exists, false otherwise\n *\n * @example\n * ```typescript\n * // Tests directory with DONE.md\n * await hasDoneMd('/path/to/tests');\n * // => true\n *\n * // Tests directory without DONE.md\n * await hasDoneMd('/path/to/tests');\n * // => false\n * ```\n */\nexport async function hasDoneMd(testsPath: string): Promise<boolean> {\n try {\n // Case-sensitive check: read directory and verify exact filename\n const entries = await readdir(testsPath);\n\n // Check if \"DONE.md\" exists in the directory listing (case-sensitive)\n if (!entries.includes(\"DONE.md\")) {\n return false;\n }\n\n // Verify it's a regular file, not a directory\n const donePath = path.join(testsPath, \"DONE.md\");\n const stats = await stat(donePath);\n return stats.isFile();\n } catch (error) {\n // ENOENT means directory doesn't exist → return false\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return false;\n }\n // Re-throw permission errors and other failures\n throw error;\n }\n}\n\n/**\n * Custom error for status determination failures\n */\nexport class StatusDeterminationError extends Error {\n constructor(\n public readonly workItemPath: string,\n public readonly cause: unknown,\n ) {\n const errorMessage = cause instanceof Error ? cause.message : String(cause);\n super(`Failed to determine status for ${workItemPath}: ${errorMessage}`);\n this.name = \"StatusDeterminationError\";\n }\n}\n\n/**\n * Determines the status of a work item by checking its tests/ directory\n *\n * This is the main orchestration function that combines all status checks:\n * 1. Checks if tests/ directory exists\n * 2. Checks if tests/ has DONE.md\n * 3. Checks if tests/ is empty (excluding DONE.md)\n * 4. Determines final status based on these flags\n *\n * Performance: Uses caching strategy to minimize filesystem calls.\n * All checks for a single work item are performed in one pass.\n *\n * @param workItemPath - Absolute path to the work item directory\n * @returns Promise resolving to OPEN, IN_PROGRESS, or DONE\n * @throws {StatusDeterminationError} If work item doesn't exist or has permission errors\n *\n * @example\n * ```typescript\n * // Work item with no tests directory\n * await getWorkItemStatus('/path/to/story-21');\n * // => \"OPEN\"\n *\n * // Work item with tests but no DONE.md\n * await getWorkItemStatus('/path/to/story-32');\n * // => \"IN_PROGRESS\"\n *\n * // Work item with DONE.md\n * await getWorkItemStatus('/path/to/story-43');\n * // => \"DONE\"\n * ```\n */\nexport async function getWorkItemStatus(\n workItemPath: string,\n): Promise<WorkItemStatus> {\n try {\n const testsPath = path.join(workItemPath, \"tests\");\n let entries: string[];\n\n try {\n // Read tests/ once and reuse the listing for all subsequent checks.\n entries = await readdir(testsPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n try {\n await access(workItemPath);\n } catch (workItemError) {\n if ((workItemError as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new Error(`Work item not found: ${workItemPath}`);\n }\n\n throw workItemError;\n }\n\n return determineStatus({\n hasTestsDir: false,\n hasDoneMd: false,\n testsIsEmpty: true,\n });\n }\n\n throw error;\n }\n\n // Check for DONE.md from the cached entries before any extra stat call.\n const hasDone = entries.includes(\"DONE.md\");\n if (hasDone) {\n // Verify it's a file, not a directory\n const donePath = path.join(testsPath, \"DONE.md\");\n const stats = await stat(donePath);\n if (!stats.isFile()) {\n // DONE.md is a directory, treat as no DONE.md\n return determineStatus({\n hasTestsDir: true,\n hasDoneMd: false,\n testsIsEmpty: isEmptyFromEntries(entries),\n });\n }\n }\n\n // Check if empty from the same cached entries.\n const isEmpty = isEmptyFromEntries(entries);\n\n return determineStatus({\n hasTestsDir: true,\n hasDoneMd: hasDone,\n testsIsEmpty: isEmpty,\n });\n } catch (error) {\n // Wrap all errors with work item context\n throw new StatusDeterminationError(workItemPath, error);\n }\n}\n\n/**\n * Helper: Check if directory is empty from readdir entries\n * @param entries - Directory entries from readdir\n * @returns true if no test files (excluding DONE.md and dotfiles)\n */\nfunction isEmptyFromEntries(entries: string[]): boolean {\n const testFiles = entries.filter((entry) => {\n // Exclude DONE.md\n if (entry === \"DONE.md\") {\n return false;\n }\n // Exclude dotfiles (.gitkeep, .DS_Store, etc.)\n if (entry.startsWith(\".\")) {\n return false;\n }\n return true;\n });\n return testFiles.length === 0;\n}\n","/**\n * Tree building functions for converting flat work item lists to hierarchical trees\n *\n * Part of Feature 54 (Tree Building)\n */\nimport { getWorkItemStatus } from \"../status/state.js\";\nimport type { WorkItem } from \"../types.js\";\nimport type { TreeNode, WorkItemTree } from \"./types.js\";\n\n/**\n * Dependencies for tree building (for testing)\n */\nexport interface TreeBuildDeps {\n getStatus?: (path: string) => Promise<string>;\n}\n\n/**\n * Build hierarchical tree from flat list of work items\n *\n * Creates parent-child relationships based on directory paths.\n * Per ADR-002, children are BSP-sorted and status is rolled up from children.\n *\n * @param workItems - Flat list of work items from scanner\n * @param deps - Optional dependencies (for testing)\n * @returns Hierarchical tree structure\n * @throws Error if orphan work items detected (items without valid parents)\n *\n * @example\n * ```typescript\n * const workItems = await walkSpecs(\"/specs\");\n * const tree = await buildTree(workItems);\n * // tree.nodes contains top-level capabilities with nested children\n * ```\n */\nexport async function buildTree(\n workItems: WorkItem[],\n deps: TreeBuildDeps = {},\n): Promise<WorkItemTree> {\n const getStatus = deps.getStatus || getWorkItemStatus;\n\n // Step 1: Determine status for each work item\n const itemsWithStatus = await Promise.all(\n workItems.map(async (item) => ({\n ...item,\n status: await getStatus(item.path),\n })),\n );\n\n // Step 2: Separate work items by kind\n const capabilities = itemsWithStatus.filter(\n (item) => item.kind === \"capability\",\n );\n const features = itemsWithStatus.filter((item) => item.kind === \"feature\");\n const stories = itemsWithStatus.filter((item) => item.kind === \"story\");\n\n // Step 3: Build tree nodes for each level (with BSP sorting)\n const storyNodes = stories.map((item) => createTreeNode(item, []));\n const featureNodes = features.map((item) => {\n const children = storyNodes\n .filter((story) => isChildOf(story.path, item.path))\n .sort((a, b) => a.number - b.number); // Sort by BSP number\n return createTreeNode(item, children);\n });\n const capabilityNodes = capabilities.map((item) => {\n const children = featureNodes\n .filter((feature) => isChildOf(feature.path, item.path))\n .sort((a, b) => a.number - b.number); // Sort by BSP number\n return createTreeNode(item, children);\n });\n\n // Step 4: Detect orphans\n detectOrphans(stories, featureNodes);\n detectOrphans(features, capabilityNodes);\n\n // Step 5: Sort top-level capabilities by BSP number\n const sortedCapabilities = capabilityNodes.sort((a, b) => a.number - b.number);\n\n // Step 6: Roll up status from children to parents\n rollupStatus(sortedCapabilities);\n\n return {\n nodes: sortedCapabilities,\n };\n}\n\n/**\n * Create a TreeNode from a work item with status and children\n */\nfunction createTreeNode(\n item: WorkItem & { status: string },\n children: TreeNode[],\n): TreeNode {\n return {\n kind: item.kind,\n number: item.number,\n slug: item.slug,\n path: item.path,\n status: item.status as \"OPEN\" | \"IN_PROGRESS\" | \"DONE\",\n children,\n };\n}\n\n/**\n * Check if childPath is a direct child of parentPath\n *\n * A path is a child if it starts with the parent path followed by a separator.\n *\n * @param childPath - Potential child path\n * @param parentPath - Potential parent path\n * @returns true if childPath is a direct child of parentPath\n */\nfunction isChildOf(childPath: string, parentPath: string): boolean {\n // Normalize paths to ensure consistent comparison\n const normalizedChild = childPath.replace(/\\/$/, \"\");\n const normalizedParent = parentPath.replace(/\\/$/, \"\");\n\n // Check if child starts with parent followed by path separator\n if (!normalizedChild.startsWith(normalizedParent + \"/\")) {\n return false;\n }\n\n // Ensure it's a direct child (not a grandchild)\n const relativePath = normalizedChild.slice(normalizedParent.length + 1);\n return !relativePath.includes(\"/\");\n}\n\n/**\n * Detect orphan work items (items without valid parents)\n *\n * @param items - Work items to check\n * @param potentialParents - Potential parent nodes\n * @throws Error if orphans detected\n */\nfunction detectOrphans(\n items: (WorkItem & { status: string })[],\n potentialParents: TreeNode[],\n): void {\n for (const item of items) {\n const hasParent = potentialParents.some((parent) => isChildOf(item.path, parent.path));\n\n if (!hasParent) {\n throw new Error(\n `Orphan work item detected: ${item.kind} \"${item.slug}\" at ${item.path} has no valid parent`,\n );\n }\n }\n}\n\n/**\n * Roll up status from children to parents\n *\n * Recursively aggregates status from child nodes to parent nodes.\n * Parent status requires BOTH own tests/DONE.md AND all children complete.\n *\n * Rollup rules (ownStatus = status from parent's own tests/DONE.md):\n * - DONE: ownStatus is DONE AND all children are DONE\n * - OPEN: ownStatus is OPEN AND all children are OPEN\n * - IN_PROGRESS: everything else (any mismatch between own and child status)\n *\n * @param nodes - Tree nodes to process (modified in place)\n */\nfunction rollupStatus(nodes: TreeNode[]): void {\n for (const node of nodes) {\n if (node.children.length > 0) {\n // First, recursively roll up status for children\n rollupStatus(node.children);\n\n // Capture node's own status (from its tests/DONE.md)\n const ownStatus = node.status;\n\n // Then, aggregate status from children\n const childStatuses = node.children.map((child) => child.status);\n const allChildrenDone = childStatuses.every(\n (status) => status === \"DONE\",\n );\n const allChildrenOpen = childStatuses.every(\n (status) => status === \"OPEN\",\n );\n\n // DONE: own status is DONE AND all children are DONE\n if (ownStatus === \"DONE\" && allChildrenDone) {\n node.status = \"DONE\";\n } // OPEN: own status is OPEN AND all children are OPEN\n else if (ownStatus === \"OPEN\" && allChildrenOpen) {\n node.status = \"OPEN\";\n } // IN_PROGRESS: everything else\n else {\n node.status = \"IN_PROGRESS\";\n }\n }\n // Leaf nodes (stories) keep their original status\n }\n}\n","import { DEFAULT_CONFIG } from \"@/config/defaults.js\";\nimport { Scanner } from \"@/scanner/scanner.js\";\nimport { buildTree } from \"@/tree/build.js\";\nimport type { TreeNode, WorkItemTree } from \"@/tree/types.js\";\nimport { LEAF_KIND } from \"@/types.js\";\n\nconst EMPTY_WORK_ITEMS_MESSAGE = \"No work items found in specs/work/doing\";\nconst ALL_COMPLETE_MESSAGE = \"All work items are complete! 🎉\";\nconst NEXT_WORK_ITEM_HEADING = \"Next work item:\";\nconst STATUS_LABEL = \"Status\";\nconst PATH_LABEL = \"Path\";\nconst INDENT = \" \";\nconst BLANK_LINE = \"\";\nconst PATH_SEPARATOR = \" > \";\n\nexport interface NextOptions {\n cwd?: string;\n}\n\nexport function findNextWorkItem(tree: WorkItemTree): TreeNode | null {\n return findFirstNonDoneLeaf(tree.nodes);\n}\n\nfunction findFirstNonDoneLeaf(nodes: TreeNode[]): TreeNode | null {\n for (const node of nodes) {\n if (node.kind === LEAF_KIND) {\n if (node.status !== \"DONE\") {\n return node;\n }\n\n continue;\n }\n\n const found = findFirstNonDoneLeaf(node.children);\n if (found !== null) {\n return found;\n }\n }\n\n return null;\n}\n\nfunction formatWorkItemName(node: TreeNode): string {\n const displayNumber = node.kind === \"capability\" ? node.number + 1 : node.number;\n return `${node.kind}-${displayNumber}_${node.slug}`;\n}\n\nfunction findParents(\n nodes: TreeNode[],\n target: TreeNode,\n): { capability?: TreeNode; feature?: TreeNode } {\n for (const capability of nodes) {\n for (const feature of capability.children) {\n for (const story of feature.children) {\n if (story.path === target.path) {\n return { capability, feature };\n }\n }\n }\n }\n\n return {};\n}\n\nexport async function nextCommand(options: NextOptions = {}): Promise<string> {\n const cwd = options.cwd ?? process.cwd();\n const scanner = new Scanner(cwd, DEFAULT_CONFIG);\n const workItems = await scanner.scan();\n\n if (workItems.length === 0) {\n return EMPTY_WORK_ITEMS_MESSAGE;\n }\n\n const tree = await buildTree(workItems);\n const next = findNextWorkItem(tree);\n\n if (next === null) {\n return ALL_COMPLETE_MESSAGE;\n }\n\n const parents = findParents(tree.nodes, next);\n const pathLine = parents.capability !== undefined && parents.feature !== undefined\n ? `${INDENT}${formatWorkItemName(parents.capability)}${PATH_SEPARATOR}${\n formatWorkItemName(parents.feature)\n }${PATH_SEPARATOR}${formatWorkItemName(next)}`\n : `${INDENT}${formatWorkItemName(next)}`;\n\n return [\n NEXT_WORK_ITEM_HEADING,\n BLANK_LINE,\n pathLine,\n BLANK_LINE,\n `${INDENT}${STATUS_LABEL}: ${next.status}`,\n `${INDENT}${PATH_LABEL}: ${next.path}`,\n ].join(\"\\n\");\n}\n","/**\n * JSON formatter for work item trees\n *\n * Produces structured JSON with summary statistics and full tree data.\n * Part of Feature 65 (Output Formatting), Story 32.\n */\nimport type { SpxConfig } from \"@/config/defaults\";\nimport type { TreeNode, WorkItemTree } from \"@/tree/types\";\n\n/** JSON indentation (2 spaces per ADR-002 and user requirements) */\nconst JSON_INDENT = 2;\n\n/**\n * Summary counts for capabilities and features only (NOT stories)\n */\ninterface Summary {\n done: number;\n inProgress: number;\n open: number;\n}\n\n/**\n * JSON output structure\n */\ninterface JSONOutput {\n config: {\n specs: SpxConfig[\"specs\"];\n sessions: SpxConfig[\"sessions\"];\n };\n summary: Summary;\n capabilities: unknown[];\n}\n\n/**\n * Format tree as JSON with summary statistics\n *\n * Summary counts capabilities + features only (per user requirement).\n * Display numbers (per ADR-002):\n * - Capabilities: internal + 1\n * - Features/Stories: as-is\n *\n * @param tree - Work item tree to format\n * @param config - SpxConfig used for path resolution\n * @returns JSON string with 2-space indentation\n */\nexport function formatJSON(tree: WorkItemTree, config: SpxConfig): string {\n const capabilities = tree.nodes.map((node) => nodeToJSON(node));\n const summary = calculateSummary(tree);\n\n const output: JSONOutput = {\n config: {\n specs: config.specs,\n sessions: config.sessions,\n },\n summary,\n capabilities,\n };\n\n return JSON.stringify(output, null, JSON_INDENT);\n}\n\n/**\n * Convert tree node to JSON structure with display numbers\n *\n * @param node - Tree node to convert\n * @returns JSON-serializable object\n */\nfunction nodeToJSON(node: TreeNode): unknown {\n const displayNumber = getDisplayNumber(node);\n\n const base = {\n kind: node.kind,\n number: displayNumber,\n slug: node.slug,\n status: node.status,\n };\n\n // Add children based on kind\n if (node.kind === \"capability\") {\n return {\n ...base,\n features: node.children.map((child) => nodeToJSON(child)),\n };\n } else if (node.kind === \"feature\") {\n return {\n ...base,\n stories: node.children.map((child) => nodeToJSON(child)),\n };\n } else {\n // Stories have no children\n return base;\n }\n}\n\n/**\n * Calculate summary statistics\n *\n * Counts capabilities + features only (NOT stories per user requirement)\n *\n * @param tree - Work item tree\n * @returns Summary counts\n */\nfunction calculateSummary(tree: WorkItemTree): Summary {\n const summary: Summary = {\n done: 0,\n inProgress: 0,\n open: 0,\n };\n\n for (const capability of tree.nodes) {\n // Count capability\n countNode(capability, summary);\n\n // Count features (but NOT stories)\n for (const feature of capability.children) {\n countNode(feature, summary);\n }\n }\n\n return summary;\n}\n\n/**\n * Count a single node in summary\n *\n * @param node - Node to count\n * @param summary - Summary object to update\n */\nfunction countNode(node: TreeNode, summary: Summary): void {\n switch (node.status) {\n case \"DONE\":\n summary.done++;\n break;\n case \"IN_PROGRESS\":\n summary.inProgress++;\n break;\n case \"OPEN\":\n summary.open++;\n break;\n }\n}\n\n/**\n * Get display number for a work item\n *\n * Per ADR-002:\n * - Capabilities: internal + 1 (dir capability-21 has internal 20)\n * - Features/Stories: as-is\n */\nfunction getDisplayNumber(node: TreeNode): number {\n return node.kind === \"capability\" ? node.number + 1 : node.number;\n}\n","/**\n * Markdown formatter for work item trees\n *\n * Renders trees with heading hierarchy and status lines.\n * Part of Feature 65 (Output Formatting), Story 43.\n */\nimport type { TreeNode, WorkItemTree } from \"../tree/types.js\";\n\n/**\n * Format tree as markdown with heading hierarchy\n *\n * Heading levels:\n * - Capabilities: #\n * - Features: ##\n * - Stories: ###\n *\n * Display numbers (per ADR-002):\n * - Capabilities: internal + 1\n * - Features/Stories: as-is\n *\n * @param tree - Work item tree to format\n * @returns Formatted markdown\n *\n * @example\n * ```typescript\n * const tree = buildTreeWithStories();\n * const output = formatMarkdown(tree);\n * // => \"# capability-21_test\\n\\nStatus: DONE\\n\\n## feature-21_test\\n...\"\n * ```\n */\nexport function formatMarkdown(tree: WorkItemTree): string {\n const sections: string[] = [];\n\n for (const node of tree.nodes) {\n formatNode(node, 1, sections);\n }\n\n return sections.join(\"\\n\\n\");\n}\n\n/**\n * Recursively format a tree node as markdown\n *\n * @param node - Current node to format\n * @param level - Heading level (1 = #, 2 = ##, 3 = ###)\n * @param sections - Output sections array\n */\nfunction formatNode(\n node: TreeNode,\n level: number,\n sections: string[],\n): void {\n const displayNumber = getDisplayNumber(node);\n const name = `${node.kind}-${displayNumber}_${node.slug}`;\n const heading = \"#\".repeat(level);\n\n sections.push(`${heading} ${name}`);\n sections.push(`Status: ${node.status}`);\n\n // Recurse for children\n for (const child of node.children) {\n formatNode(child, level + 1, sections);\n }\n}\n\n/**\n * Get display number for a work item\n *\n * Per ADR-002:\n * - Capabilities: internal + 1 (dir capability-21 has internal 20)\n * - Features/Stories: as-is\n */\nfunction getDisplayNumber(node: TreeNode): number {\n return node.kind === \"capability\" ? node.number + 1 : node.number;\n}\n","/**\n * Table formatter for work item trees\n *\n * Renders trees as aligned tables with dynamic column widths.\n * Part of Feature 65 (Output Formatting), Story 54.\n */\nimport type { TreeNode, WorkItemTree } from \"../tree/types.js\";\n\n/**\n * Table row data\n */\ninterface TableRow {\n level: string;\n number: string;\n name: string;\n status: string;\n}\n\n/**\n * Format tree as aligned table with dynamic column widths\n *\n * Columns: Level | Number | Name | Status\n * Level shows indented hierarchy:\n * - \"Capability\" (no indent)\n * - \" Feature\" (2-space indent)\n * - \" Story\" (4-space indent)\n *\n * Display numbers (per ADR-002):\n * - Capabilities: internal + 1\n * - Features/Stories: as-is\n *\n * @param tree - Work item tree to format\n * @returns Formatted table with aligned columns\n */\nexport function formatTable(tree: WorkItemTree): string {\n const rows: TableRow[] = [];\n\n // Collect all rows\n for (const node of tree.nodes) {\n collectRows(node, 0, rows);\n }\n\n // Calculate column widths\n const widths = calculateColumnWidths(rows);\n\n // Format table\n const lines: string[] = [];\n\n // Header row\n lines.push(\n formatRow(\n {\n level: \"Level\",\n number: \"Number\",\n name: \"Name\",\n status: \"Status\",\n },\n widths,\n ),\n );\n\n // Separator row\n lines.push(\n `|${\"-\".repeat(widths.level + 2)}|${\"-\".repeat(widths.number + 2)}|${\"-\".repeat(widths.name + 2)}|${\n \"-\".repeat(widths.status + 2)\n }|`,\n );\n\n // Data rows\n for (const row of rows) {\n lines.push(formatRow(row, widths));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Recursively collect table rows from tree\n *\n * @param node - Current node\n * @param depth - Current depth (0 = capability, 1 = feature, 2 = story)\n * @param rows - Output rows array\n */\nfunction collectRows(node: TreeNode, depth: number, rows: TableRow[]): void {\n const indent = \" \".repeat(depth);\n const levelName = getLevelName(node.kind);\n const displayNumber = getDisplayNumber(node);\n\n rows.push({\n level: `${indent}${levelName}`,\n number: String(displayNumber),\n name: node.slug,\n status: node.status,\n });\n\n // Recurse for children\n for (const child of node.children) {\n collectRows(child, depth + 1, rows);\n }\n}\n\n/**\n * Get level name with proper capitalization\n *\n * @param kind - Work item kind\n * @returns Capitalized level name\n */\nfunction getLevelName(kind: string): string {\n return kind.charAt(0).toUpperCase() + kind.slice(1);\n}\n\n/**\n * Get display number for a work item\n *\n * Per ADR-002:\n * - Capabilities: internal + 1 (dir capability-21 has internal 20)\n * - Features/Stories: as-is\n */\nfunction getDisplayNumber(node: TreeNode): number {\n return node.kind === \"capability\" ? node.number + 1 : node.number;\n}\n\n/**\n * Calculate maximum width for each column\n *\n * @param rows - All table rows including header\n * @returns Column widths\n */\nfunction calculateColumnWidths(rows: TableRow[]): {\n level: number;\n number: number;\n name: number;\n status: number;\n} {\n const widths = {\n level: \"Level\".length,\n number: \"Number\".length,\n name: \"Name\".length,\n status: \"Status\".length,\n };\n\n for (const row of rows) {\n widths.level = Math.max(widths.level, row.level.length);\n widths.number = Math.max(widths.number, row.number.length);\n widths.name = Math.max(widths.name, row.name.length);\n widths.status = Math.max(widths.status, row.status.length);\n }\n\n return widths;\n}\n\n/**\n * Format a single table row with proper padding\n *\n * @param row - Row data\n * @param widths - Column widths\n * @returns Formatted row with | delimiters\n */\nfunction formatRow(\n row: TableRow,\n widths: { level: number; number: number; name: number; status: number },\n): string {\n return `| ${row.level.padEnd(widths.level)} | ${row.number.padEnd(widths.number)} | ${\n row.name.padEnd(widths.name)\n } | ${row.status.padEnd(widths.status)} |`;\n}\n","/**\n * Text formatter for work item trees\n *\n * Renders hierarchical tree with indentation and colored status indicators.\n * Output format:\n * capability-21_name [STATUS] (colored)\n * feature-32_name [STATUS] (colored)\n * story-21_name [STATUS] (colored)\n */\nimport chalk from \"chalk\";\nimport type { TreeNode, WorkItemTree } from \"../tree/types.js\";\nimport type { WorkItemKind } from \"../types.js\";\n\n/**\n * Format work item tree as text with hierarchical indentation\n *\n * @param tree - Work item tree to format\n * @returns Formatted text output with indentation and status\n *\n * @example\n * ```typescript\n * const tree = buildTreeWithStories();\n * const output = formatText(tree);\n * // => \"capability-21_test [DONE]\\n feature-21_test [DONE]\\n story-21_test [DONE]\"\n * ```\n */\nexport function formatText(tree: WorkItemTree): string {\n const lines: string[] = [];\n\n for (const node of tree.nodes) {\n lines.push(formatNode(node, 0));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format a single tree node with indentation and colored status\n *\n * @param node - Tree node to format\n * @param indent - Indentation level (0 = no indent, 2 = feature, 4 = story)\n * @returns Formatted node and all children\n */\nfunction formatNode(node: TreeNode, indent: number): string {\n const lines: string[] = [];\n\n // Format current node\n const name = formatWorkItemName(node.kind, node.number, node.slug);\n const prefix = \" \".repeat(indent);\n const status = formatStatus(node.status);\n const line = `${prefix}${name} ${status}`;\n lines.push(line);\n\n // Recursively format children with increased indentation\n for (const child of node.children) {\n lines.push(formatNode(child, indent + 2));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format work item name for display\n *\n * Converts internal number to display number for capabilities.\n *\n * @param kind - Work item type\n * @param number - Internal BSP number\n * @param slug - URL-safe identifier\n * @returns Formatted name (e.g., \"capability-21_core-cli\")\n */\nfunction formatWorkItemName(\n kind: WorkItemKind,\n number: number,\n slug: string,\n): string {\n // Capabilities: display = internal + 1\n // Features/Stories: display = internal\n const displayNumber = kind === \"capability\" ? number + 1 : number;\n return `${kind}-${displayNumber}_${slug}`;\n}\n\n/**\n * Format status with color\n *\n * Colors:\n * - DONE: green\n * - IN_PROGRESS: yellow\n * - OPEN: gray\n *\n * @param status - Work item status\n * @returns Colored status string with brackets\n */\nfunction formatStatus(status: string): string {\n switch (status) {\n case \"DONE\":\n return chalk.green(`[${status}]`);\n case \"IN_PROGRESS\":\n return chalk.yellow(`[${status}]`);\n case \"OPEN\":\n return chalk.gray(`[${status}]`);\n default:\n return `[${status}]`;\n }\n}\n","import { DEFAULT_CONFIG } from \"@/config/defaults.js\";\nimport { formatJSON } from \"@/reporter/json.js\";\nimport { formatMarkdown } from \"@/reporter/markdown.js\";\nimport { formatTable } from \"@/reporter/table.js\";\nimport { formatText } from \"@/reporter/text.js\";\nimport { Scanner } from \"@/scanner/scanner.js\";\nimport { buildTree } from \"@/tree/build.js\";\n\nconst DEFAULT_FORMAT: OutputFormat = \"text\";\n\nexport type OutputFormat = \"text\" | \"json\" | \"markdown\" | \"table\";\n\nexport interface StatusOptions {\n cwd?: string;\n format?: OutputFormat;\n}\n\nfunction buildMissingDirectoryMessage(): string {\n const {\n root,\n work: {\n dir,\n statusDirs: { doing },\n },\n } = DEFAULT_CONFIG.specs;\n\n return `Directory ${root}/${dir}/${doing} not found.`;\n}\n\nexport async function statusCommand(\n options: StatusOptions = {},\n): Promise<string> {\n const cwd = options.cwd ?? process.cwd();\n const format = options.format ?? DEFAULT_FORMAT;\n const scanner = new Scanner(cwd, DEFAULT_CONFIG);\n\n let workItems;\n try {\n workItems = await scanner.scan();\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"ENOENT\")) {\n throw new Error(buildMissingDirectoryMessage());\n }\n\n throw error;\n }\n\n if (workItems.length === 0) {\n return \"No work items found in specs/work/doing\";\n }\n\n const tree = await buildTree(workItems);\n\n switch (format) {\n case \"json\":\n return formatJSON(tree, DEFAULT_CONFIG);\n case \"markdown\":\n return formatMarkdown(tree);\n case \"table\":\n return formatTable(tree);\n case \"text\":\n return formatText(tree);\n }\n}\n","/**\n * Language detection for apply-exclude.\n *\n * Checks which config files exist in the project to determine the language\n * and return the appropriate adapter.\n */\nimport { join } from \"node:path\";\n\nimport type { ApplyExcludeDeps } from \"../types.js\";\nimport { pythonAdapter } from \"./python.js\";\nimport type { LanguageAdapter } from \"./types.js\";\n\n/** All registered language adapters, checked in order */\nexport const ADAPTERS: readonly LanguageAdapter[] = [pythonAdapter] as const;\n\n/**\n * Detect the project language by checking for config files.\n *\n * @param projectRoot - Absolute path to the project root\n * @param deps - Injected file system dependencies\n * @returns The first matching adapter, or null if no config file is found\n */\nexport async function detectLanguage(\n projectRoot: string,\n deps: Pick<ApplyExcludeDeps, \"fileExists\">,\n): Promise<LanguageAdapter | null> {\n for (const adapter of ADAPTERS) {\n const configPath = join(projectRoot, adapter.configFile);\n const exists = await deps.fileExists(configPath);\n if (exists) {\n return adapter;\n }\n }\n return null;\n}\n","/**\n * Constants for apply-exclude operations.\n */\n\n/** Prefix for all spec-tree paths in config files */\nexport const SPX_PREFIX = \"spx/\";\n\n/** Node type suffixes that identify spec-tree directories */\nexport const NODE_SUFFIXES = [\".outcome/\", \".enabler/\", \".capability/\", \".feature/\", \".story/\"] as const;\n\n/** Comment character in EXCLUDE files */\nexport const COMMENT_CHAR = \"#\";\n\n/** Default name of the EXCLUDE file within spx/ */\nexport const EXCLUDE_FILENAME = \"EXCLUDE\";\n","/**\n * Node path to tool-specific config entry mappings.\n */\nimport { NODE_SUFFIXES, SPX_PREFIX } from \"./constants.js\";\n\n/**\n * Convert a node path to a pytest --ignore flag.\n *\n * @example toPytestIgnore(\"57-subsystems.outcome\") => \"--ignore=spx/57-subsystems.outcome/\"\n */\nexport function toPytestIgnore(node: string): string {\n return `--ignore=${SPX_PREFIX}${node}/`;\n}\n\n/**\n * Escape a string for use in a regular expression.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\-]/g, \"\\\\$&\");\n}\n\n/**\n * Convert a node path to a mypy exclude regex.\n *\n * @example toMypyRegex(\"57-subsystems.outcome\") => \"^spx/57\\\\-subsystems\\\\.outcome/\"\n */\nexport function toMypyRegex(node: string): string {\n const escaped = escapeRegex(`${SPX_PREFIX}${node}/`);\n return `^${escaped}`;\n}\n\n/**\n * Convert a node path to a pyright exclude path.\n *\n * @example toPyrightPath(\"57-subsystems.outcome\") => \"spx/57-subsystems.outcome/\"\n */\nexport function toPyrightPath(node: string): string {\n return `${SPX_PREFIX}${node}/`;\n}\n\n/**\n * Check if a config value was generated from an excluded spec-tree node.\n *\n * Detects entries by value pattern (contains a node-type suffix and spx/ prefix),\n * not by marker comments.\n */\nexport function isExcludedEntry(val: string): boolean {\n const hasPrefix = val.includes(SPX_PREFIX);\n const hasSuffix = NODE_SUFFIXES.some((suffix) => val.includes(suffix));\n return hasPrefix && hasSuffix;\n}\n","/**\n * Python language adapter for apply-exclude.\n *\n * Applies spec-tree exclusions to pyproject.toml using string-based editing.\n * Preserves comments and formatting by only modifying the specific values\n * for pytest addopts, mypy exclude, and pyright exclude — everything else\n * is left untouched.\n */\nimport { isExcludedEntry, toMypyRegex, toPyrightPath, toPytestIgnore } from \"../mappings.js\";\nimport type { ApplyResult } from \"../types.js\";\nimport type { LanguageAdapter } from \"./types.js\";\n\n/** Config file name for Python projects */\nexport const PYTHON_CONFIG_FILE = \"pyproject.toml\";\n\n/** TOML section header for pytest configuration */\nexport const PYTEST_SECTION = \"tool.pytest.ini_options\";\n\n/** TOML section header for mypy configuration */\nexport const MYPY_SECTION = \"tool.mypy\";\n\n/** TOML section header for pyright configuration */\nexport const PYRIGHT_SECTION = \"tool.pyright\";\n\n/** Indentation used for new array entries */\nconst ARRAY_INDENT = \" \";\n\n/**\n * Update pytest addopts string value within pyproject.toml content.\n *\n * Finds `addopts = \"...\"` in `[tool.pytest.ini_options]`, filters out\n * old excluded entries, and appends new ones.\n */\nfunction updatePytestAddopts(content: string, nodes: string[]): string {\n const sectionPattern = new RegExp(`^\\\\[${PYTEST_SECTION.replace(/\\./g, \"\\\\.\")}\\\\]`, \"m\");\n const sectionMatch = sectionPattern.exec(content);\n if (!sectionMatch) return content;\n\n // Find addopts = \"...\" after the section header\n const afterSection = content.slice(sectionMatch.index);\n const addoptsPattern = /^([ \\t]*addopts\\s*=\\s*\")((?:[^\"\\\\]|\\\\.)*)(\")/m;\n const addoptsMatch = addoptsPattern.exec(afterSection);\n if (!addoptsMatch) return content;\n\n const prefix = addoptsMatch[1];\n const currentValue = addoptsMatch[2];\n const suffix = addoptsMatch[3];\n\n // Split by whitespace, filter old excluded entries, add new ones\n const parts = currentValue.split(/\\s+/).filter((p) => p.length > 0);\n const kept = parts.filter((p) => !isExcludedEntry(p));\n const newIgnores = nodes.map(toPytestIgnore);\n const updatedValue = [...kept, ...newIgnores].join(\" \");\n\n const absoluteStart = sectionMatch.index + addoptsMatch.index;\n const absoluteEnd = absoluteStart + addoptsMatch[0].length;\n\n return content.slice(0, absoluteStart) + prefix + updatedValue + suffix + content.slice(absoluteEnd);\n}\n\n/**\n * Find the boundaries of a TOML array value within a specific section.\n */\nfunction findTomlArray(\n content: string,\n sectionHeader: string,\n key: string,\n): { arrayStart: number; arrayEnd: number } | null {\n const sectionPattern = new RegExp(`^\\\\[${sectionHeader.replace(/\\./g, \"\\\\.\")}\\\\]`, \"m\");\n const sectionMatch = sectionPattern.exec(content);\n if (!sectionMatch) return null;\n\n // Find key = [ after section header, before next section\n const afterSection = content.slice(sectionMatch.index);\n const nextSectionMatch = /^\\[(?!.*\\].*=)/m.exec(afterSection.slice(sectionMatch[0].length));\n const sectionEnd = nextSectionMatch\n ? sectionMatch.index + sectionMatch[0].length + nextSectionMatch.index\n : content.length;\n\n const keyPattern = new RegExp(`^([ \\\\t]*${key}\\\\s*=\\\\s*)\\\\[`, \"m\");\n const regionToSearch = content.slice(sectionMatch.index, sectionEnd);\n const keyMatch = keyPattern.exec(regionToSearch);\n if (!keyMatch) return null;\n\n const arrayStart = sectionMatch.index + keyMatch.index + keyMatch[1].length;\n\n // Find the matching closing bracket\n let depth = 0;\n let arrayEnd = arrayStart;\n for (let i = arrayStart; i < content.length; i++) {\n if (content[i] === \"[\") depth++;\n if (content[i] === \"]\") {\n depth--;\n if (depth === 0) {\n arrayEnd = i + 1;\n break;\n }\n }\n }\n\n return { arrayStart, arrayEnd };\n}\n\n/**\n * Update a TOML array in a specific section by filtering out excluded entries\n * and appending new ones.\n *\n * Preserves comments and indentation of non-excluded entries.\n */\nfunction updateTomlArray(content: string, sectionHeader: string, key: string, newEntries: string[]): string {\n const info = findTomlArray(content, sectionHeader, key);\n if (!info) return content;\n\n // Parse the array content line by line to preserve formatting\n const arrayContent = content.slice(info.arrayStart + 1, info.arrayEnd - 1);\n const lines = arrayContent.split(\"\\n\");\n\n // Keep lines that are comments, blank, or contain non-excluded entries\n const keptLines: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n // Keep blank lines and comments\n if (trimmed === \"\" || trimmed.startsWith(\"#\")) {\n keptLines.push(line);\n continue;\n }\n // Check if this line contains a string entry that should be excluded\n const stringMatch = /\"((?:[^\"\\\\]|\\\\.)*)\"/.exec(trimmed);\n if (stringMatch && isExcludedEntry(stringMatch[1])) {\n continue; // Remove this line\n }\n keptLines.push(line);\n }\n\n // Append new entries with trailing commas\n const newLines = newEntries.map((entry) => `${ARRAY_INDENT}\"${entry}\",`);\n\n // Reconstruct the array content\n // Remove trailing empty lines from kept lines before appending\n while (keptLines.length > 0 && keptLines[keptLines.length - 1].trim() === \"\") {\n keptLines.pop();\n }\n\n const reconstructed = [...keptLines, ...newLines, \"\"].join(\"\\n\");\n\n return content.slice(0, info.arrayStart + 1) + reconstructed + content.slice(info.arrayEnd - 1);\n}\n\n/**\n * Python language adapter for apply-exclude.\n *\n * Updates pyproject.toml to exclude specified nodes from pytest, mypy,\n * and pyright. Ruff is never excluded — style is checked regardless of\n * implementation existence.\n */\nexport const pythonAdapter: LanguageAdapter = {\n language: \"Python\",\n configFile: PYTHON_CONFIG_FILE,\n tools: [\"pytest\", \"mypy\", \"pyright\"],\n excluded: [\"ruff (style checked regardless of implementation existence)\"],\n\n applyExclusions(content: string, nodes: string[]): ApplyResult {\n let result = content;\n\n // 1. Update pytest addopts\n result = updatePytestAddopts(result, nodes);\n\n // 2. Update mypy exclude\n const mypyEntries = nodes.map(toMypyRegex);\n result = updateTomlArray(result, MYPY_SECTION, \"exclude\", mypyEntries);\n\n // 3. Update pyright exclude\n const pyrightEntries = nodes.map(toPyrightPath);\n result = updateTomlArray(result, PYRIGHT_SECTION, \"exclude\", pyrightEntries);\n\n return {\n changed: result !== content,\n content: result,\n };\n },\n};\n","/**\n * Dynamic help text for spx spec apply, built from constants and adapter registry.\n */\nimport { ADAPTERS } from \"./adapters/index.js\";\nimport { EXCLUDE_FILENAME, SPX_PREFIX } from \"./constants.js\";\n\n/**\n * Build the help text for spx spec apply.\n *\n * Generates language support table and tool details from the adapter registry,\n * so the help stays in sync with the implementation.\n */\nfunction buildApplyHelp(): string {\n const excludePath = `${SPX_PREFIX}${EXCLUDE_FILENAME}`;\n\n const languageLines = ADAPTERS.map((adapter) => {\n const tools = adapter.tools.join(\", \");\n const excluded = adapter.excluded.length > 0 ? `\\n NOT configured: ${adapter.excluded.join(\", \")}` : \"\";\n return ` ${adapter.language} (${adapter.configFile})\\n Configures: ${tools}${excluded}`;\n });\n\n return `\nReads ${excludePath} and applies exclusions to the project's tool configuration.\nEach excluded node is translated into the appropriate format for the detected\nlanguage's test runner, type checker, and other quality gate tools.\n\nSource:\n ${excludePath}\n One node path per line. Comments (#) and blank lines are ignored.\n Path traversal (..) and absolute paths are rejected.\n\nSupported languages:\n${languageLines.join(\"\\n\\n\")}\n\nDetection:\n The language is auto-detected by checking for config files in order.\n The first match wins.\n\nExamples:\n spx spec apply # Apply exclusions to detected config file\n`;\n}\n\n/** Extended help text appended after the command description */\nexport const APPLY_HELP = buildApplyHelp();\n","/**\n * Parse spx/EXCLUDE files into node paths with validation.\n */\nimport { COMMENT_CHAR } from \"./constants.js\";\n\n/** Characters that are unsafe in TOML string values */\nconst TOML_UNSAFE_PATTERN = /[\"\\\\\\n\\r\\t]/;\n\n/** Path traversal sequences */\nconst PATH_TRAVERSAL_PATTERN = /(?:^|\\/)\\.\\.(?:\\/|$)/;\n\n/**\n * Validate that a node path is safe for use in config file generation.\n *\n * Rejects:\n * - Path traversal (`..` segments)\n * - Absolute paths (starting with `/`)\n * - TOML-unsafe characters (`\"`, `\\`, newlines, tabs)\n *\n * @returns Error message if invalid, null if valid\n */\nexport function validateNodePath(path: string): string | null {\n if (path.startsWith(\"/\")) {\n return `absolute path rejected: ${path}`;\n }\n if (PATH_TRAVERSAL_PATTERN.test(path)) {\n return `path traversal rejected: ${path}`;\n }\n if (TOML_UNSAFE_PATTERN.test(path)) {\n return `TOML-unsafe characters rejected: ${path}`;\n }\n return null;\n}\n\n/**\n * Read node paths from EXCLUDE file content, stripping comments and blanks.\n * Invalid paths are silently filtered out.\n *\n * @param content - Raw content of the EXCLUDE file\n * @returns Array of valid node paths (trimmed, non-empty, non-comment, safe)\n */\nexport function readExcludedNodes(content: string): string[] {\n return content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && !line.startsWith(COMMENT_CHAR))\n .filter((line) => validateNodePath(line) === null);\n}\n","/**\n * Command handler for spx spec apply.\n *\n * Reads spx/EXCLUDE and applies exclusions to the project's language-specific\n * config file using the detected language adapter.\n */\nimport { join } from \"node:path\";\n\nimport { detectLanguage } from \"./adapters/index.js\";\nimport { EXCLUDE_FILENAME, SPX_PREFIX } from \"./constants.js\";\nimport { readExcludedNodes } from \"./exclude-file.js\";\nimport type { ApplyExcludeOptions, ApplyExcludeResult } from \"./types.js\";\n\n/**\n * Run the apply-exclude command.\n *\n * @param options - Command options with injected dependencies\n * @returns Command result with exit code and output message\n */\nexport async function applyExcludeCommand(options: ApplyExcludeOptions): Promise<ApplyExcludeResult> {\n const { cwd, deps } = options;\n const excludePath = join(cwd, SPX_PREFIX, EXCLUDE_FILENAME);\n\n // Check spx/EXCLUDE exists\n const excludeExists = await deps.fileExists(excludePath);\n if (!excludeExists) {\n return { exitCode: 1, output: `error: ${excludePath} not found` };\n }\n\n // Detect project language\n const adapter = await detectLanguage(cwd, deps);\n if (!adapter) {\n return { exitCode: 1, output: \"error: no supported config file found (checked: pyproject.toml)\" };\n }\n\n const configPath = join(cwd, adapter.configFile);\n\n // Read both files\n const excludeContent = await deps.readFile(excludePath);\n const configContent = await deps.readFile(configPath);\n\n // Parse excluded nodes\n const nodes = readExcludedNodes(excludeContent);\n if (nodes.length === 0) {\n return { exitCode: 0, output: \"spx/EXCLUDE is empty — no excluded nodes to apply.\" };\n }\n\n // Apply exclusions\n const result = adapter.applyExclusions(configContent, nodes);\n\n if (result.changed) {\n await deps.writeFile(configPath, result.content);\n return {\n exitCode: 0,\n output: `Updated ${adapter.configFile} from spx/EXCLUDE (${nodes.length} nodes).`,\n };\n }\n\n return { exitCode: 0, output: `${adapter.configFile} is already in sync with spx/EXCLUDE.` };\n}\n","import { readFile, rename, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { parse as tomlParse, stringify as tomlStringify } from \"smol-toml\";\nimport { Document, isMap, parseDocument } from \"yaml\";\n\nimport { CONFIG_FILENAMES } from \"@/config/index.js\";\n\nimport { LITERAL_SECTION, type LiteralConfig, literalConfigDescriptor } from \"./config.js\";\nimport { validateLiteralReuse } from \"./index.js\";\n\nexport type ConfigFormat = \"json\" | \"yaml\" | \"toml\";\n\nexport interface ConfigFileInfo {\n readonly path: string;\n readonly format: ConfigFormat;\n readonly raw: string;\n}\n\nexport type ConfigReadResult =\n | { readonly kind: \"ok\"; readonly file: ConfigFileInfo }\n | { readonly kind: \"ambiguous\"; readonly detected: readonly string[] }\n | { readonly kind: \"absent\" };\n\nexport interface ConfigReader {\n read(projectRoot: string): Promise<ConfigReadResult>;\n}\n\nexport interface ConfigWriter {\n write(filePath: string, content: string): Promise<void>;\n}\n\nexport interface AllowlistExistingOptions {\n readonly projectRoot: string;\n readonly reader?: ConfigReader;\n readonly writer?: ConfigWriter;\n}\n\nexport interface AllowlistExistingResult {\n readonly exitCode: number;\n readonly output: string;\n}\n\nconst EXIT_OK = 0;\nconst EXIT_ERROR = 1;\nconst DEFAULT_FORMAT: ConfigFormat = \"yaml\";\nconst ALLOWLIST_INCLUDE_PATH = [LITERAL_SECTION, \"allowlist\", \"include\"] as const;\nconst TEMP_FILE_PREFIX = \".spx-allowlist-existing-\";\nconst TEMP_FILE_SUFFIX = \".tmp\";\nconst RANDOM_BASE = 36;\nconst RANDOM_PREFIX_SLICE = 2;\nconst RANDOM_TOKEN_LENGTH = 10;\nconst JSON_INDENT = 2;\nconst FORMAT_FILENAMES: Readonly<Record<ConfigFormat, string>> = {\n json: CONFIG_FILENAMES.json,\n yaml: CONFIG_FILENAMES.yaml,\n toml: CONFIG_FILENAMES.toml,\n};\nconst DETECTION_ORDER: readonly ConfigFormat[] = [\"json\", \"yaml\", \"toml\"];\n\nexport const productionReader: ConfigReader = {\n async read(projectRoot: string): Promise<ConfigReadResult> {\n const detected: ConfigFileInfo[] = [];\n for (const format of DETECTION_ORDER) {\n const filename = FORMAT_FILENAMES[format];\n const path = join(projectRoot, filename);\n try {\n const raw = await readFile(path, \"utf8\");\n detected.push({ path, format, raw });\n } catch (error: unknown) {\n if (!isFileNotFound(error)) throw error;\n }\n }\n if (detected.length === 0) return { kind: \"absent\" };\n if (detected.length > 1) {\n return { kind: \"ambiguous\", detected: detected.map((file) => FORMAT_FILENAMES[file.format]) };\n }\n return { kind: \"ok\", file: detected[0] };\n },\n};\n\nexport const productionWriter: ConfigWriter = {\n async write(filePath: string, content: string): Promise<void> {\n const dir = dirname(filePath);\n const random = Math.random()\n .toString(RANDOM_BASE)\n .slice(RANDOM_PREFIX_SLICE, RANDOM_PREFIX_SLICE + RANDOM_TOKEN_LENGTH);\n const tmpPath = join(dir, `${TEMP_FILE_PREFIX}${random}${TEMP_FILE_SUFFIX}`);\n await writeFile(tmpPath, content, \"utf8\");\n await rename(tmpPath, filePath);\n },\n};\n\nexport async function allowlistExisting(\n options: AllowlistExistingOptions,\n): Promise<AllowlistExistingResult> {\n const reader = options.reader ?? productionReader;\n const writer = options.writer ?? productionWriter;\n\n const readResult = await reader.read(options.projectRoot);\n if (readResult.kind === \"ambiguous\") {\n const names = readResult.detected.join(\", \");\n return { exitCode: EXIT_ERROR, output: `multiple config files found: ${names}` };\n }\n\n const currentLiteralConfig = readCurrentLiteralConfig(readResult);\n\n const detection = await validateLiteralReuse({\n projectRoot: options.projectRoot,\n config: currentLiteralConfig,\n });\n\n const findingValues = collectFindingValues(detection.findings);\n const updatedInclude = computeUpdatedInclude(\n currentLiteralConfig.allowlist.include,\n findingValues,\n );\n\n const target: ConfigFileInfo = readResult.kind === \"ok\"\n ? readResult.file\n : {\n path: join(options.projectRoot, FORMAT_FILENAMES[DEFAULT_FORMAT]),\n format: DEFAULT_FORMAT,\n raw: \"\",\n };\n\n const serialized = serializeWithUpdatedInclude(target, updatedInclude);\n await writer.write(target.path, serialized);\n\n return { exitCode: EXIT_OK, output: \"\" };\n}\n\nfunction readCurrentLiteralConfig(read: ConfigReadResult): LiteralConfig {\n if (read.kind !== \"ok\") return literalConfigDescriptor.defaults;\n const sections = parseSections(read.file);\n const literalRaw = sections[LITERAL_SECTION];\n if (literalRaw === undefined) return literalConfigDescriptor.defaults;\n const validated = literalConfigDescriptor.validate(literalRaw);\n return validated.ok ? validated.value : literalConfigDescriptor.defaults;\n}\n\nfunction parseSections(file: ConfigFileInfo): Record<string, unknown> {\n if (file.raw.trim() === \"\") return {};\n switch (file.format) {\n case \"json\":\n return JSON.parse(file.raw) as Record<string, unknown>;\n case \"yaml\": {\n const parsed = parseDocument(file.raw).toJS({ maxAliasCount: 0 }) as Record<string, unknown> | null;\n return parsed ?? {};\n }\n case \"toml\":\n return tomlParse(file.raw) as Record<string, unknown>;\n }\n}\n\nfunction collectFindingValues(\n findings: {\n readonly srcReuse: readonly { readonly value: string }[];\n readonly testDupe: readonly { readonly value: string }[];\n },\n): readonly string[] {\n const values = new Set<string>();\n for (const finding of findings.srcReuse) values.add(finding.value);\n for (const finding of findings.testDupe) values.add(finding.value);\n return [...values];\n}\n\nfunction computeUpdatedInclude(\n existing: readonly string[] | undefined,\n findingValues: readonly string[],\n): readonly string[] {\n const existingArr = existing ?? [];\n const existingSet = new Set(existingArr);\n const additions = findingValues.filter((value) => !existingSet.has(value)).sort();\n return [...existingArr, ...additions];\n}\n\nfunction serializeWithUpdatedInclude(target: ConfigFileInfo, include: readonly string[]): string {\n switch (target.format) {\n case \"yaml\":\n return serializeYaml(target.raw, include);\n case \"json\":\n return serializeJson(target.raw, include);\n case \"toml\":\n return serializeToml(target.raw, include);\n }\n}\n\nfunction serializeYaml(raw: string, include: readonly string[]): string {\n const doc = isEffectivelyEmpty(raw, \"yaml\") ? new Document({}) : parseDocument(raw);\n doc.setIn([...ALLOWLIST_INCLUDE_PATH], [...include]);\n return doc.toString();\n}\n\nfunction serializeJson(raw: string, include: readonly string[]): string {\n const obj = isEffectivelyEmpty(raw, \"json\")\n ? {}\n : (JSON.parse(raw) as Record<string, unknown>);\n setNested(obj, [...ALLOWLIST_INCLUDE_PATH], [...include]);\n return JSON.stringify(obj, null, JSON_INDENT) + \"\\n\";\n}\n\nfunction serializeToml(raw: string, include: readonly string[]): string {\n const obj = isEffectivelyEmpty(raw, \"toml\")\n ? {}\n : (tomlParse(raw) as Record<string, unknown>);\n setNested(obj, [...ALLOWLIST_INCLUDE_PATH], [...include]);\n return tomlStringify(obj);\n}\n\nfunction isEffectivelyEmpty(raw: string, format: ConfigFormat): boolean {\n if (raw.trim() === \"\") return true;\n if (format === \"yaml\") {\n const doc = parseDocument(raw);\n if (doc.contents === null) return true;\n if (isMap(doc.contents) && doc.contents.items.length === 0) return true;\n }\n return false;\n}\n\nfunction setNested(target: Record<string, unknown>, path: readonly string[], value: unknown): void {\n let cursor: Record<string, unknown> = target;\n for (let i = 0; i < path.length - 1; i += 1) {\n const key = path[i];\n const existing = cursor[key];\n if (typeof existing === \"object\" && existing !== null && !Array.isArray(existing)) {\n cursor = existing as Record<string, unknown>;\n } else {\n const fresh: Record<string, unknown> = {};\n cursor[key] = fresh;\n cursor = fresh;\n }\n }\n cursor[path[path.length - 1]] = value;\n}\n\nfunction isFileNotFound(error: unknown): boolean {\n return error instanceof Error\n && \"code\" in error\n && (error as NodeJS.ErrnoException).code === \"ENOENT\";\n}\n","import { readFile } from \"node:fs/promises\";\nimport { isAbsolute, relative, resolve } from \"node:path\";\n\nimport { type LiteralConfig, literalConfigDescriptor, resolveAllowlist } from \"./config.js\";\nimport {\n buildIndex,\n collectLiterals,\n defaultVisitorKeys,\n type DetectionResult,\n detectReuse,\n type LiteralOccurrence,\n} from \"./detector.js\";\nimport { isUnderExcluded, readExcludePaths } from \"./exclude.js\";\nimport { isTestFile, walkTypescriptFiles } from \"./walker.js\";\n\nexport { literalConfigDescriptor, resolveAllowlist } from \"./config.js\";\nexport type { LiteralAllowlistConfig, LiteralConfig } from \"./config.js\";\nexport {\n buildIndex,\n collectLiterals,\n defaultVisitorKeys,\n detectReuse,\n parseLiteralReuseResult,\n REMEDIATION,\n} from \"./detector.js\";\nexport type {\n DetectionResult,\n DupeFinding,\n LiteralIndex,\n LiteralKind,\n LiteralLocation,\n LiteralOccurrence,\n Remediation,\n ReuseFinding,\n VisitorKeysMap,\n} from \"./detector.js\";\n\nexport interface ValidateLiteralReuseInput {\n readonly projectRoot: string;\n readonly files?: readonly string[];\n readonly config?: LiteralConfig;\n}\n\nexport interface ValidateLiteralReuseResult {\n readonly findings: DetectionResult;\n readonly indexedOccurrencesByFile: ReadonlyMap<string, readonly LiteralOccurrence[]>;\n}\n\nexport async function validateLiteralReuse(\n input: ValidateLiteralReuseInput,\n): Promise<ValidateLiteralReuseResult> {\n const config = input.config ?? literalConfigDescriptor.defaults;\n const excludePaths = await readExcludePaths(input.projectRoot);\n\n const candidateFiles = input.files\n ? input.files.map((f) => (isAbsolute(f) ? f : resolve(input.projectRoot, f)))\n : await walkTypescriptFiles(input.projectRoot, excludePaths);\n\n const collectOptions = {\n visitorKeys: defaultVisitorKeys,\n minStringLength: config.minStringLength,\n minNumberDigits: config.minNumberDigits,\n };\n\n const srcOccurrences: LiteralOccurrence[] = [];\n const testOccurrencesByFile = new Map<string, readonly LiteralOccurrence[]>();\n const indexedOccurrencesByFile = new Map<string, readonly LiteralOccurrence[]>();\n\n for (const abs of candidateFiles) {\n const rel = relative(input.projectRoot, abs).split(/[\\\\/]/g).join(\"/\");\n if (isUnderExcluded(rel, excludePaths)) continue;\n\n const content = await readSafe(abs);\n if (content === null) continue;\n\n const occurrences = collectLiterals(content, rel, collectOptions);\n indexedOccurrencesByFile.set(rel, occurrences);\n if (isTestFile(rel)) {\n testOccurrencesByFile.set(rel, occurrences);\n } else {\n srcOccurrences.push(...occurrences);\n }\n }\n\n const srcIndex = buildIndex(srcOccurrences);\n const findings = detectReuse({\n srcIndex,\n testOccurrencesByFile,\n allowlist: resolveAllowlist(config.allowlist),\n });\n\n return { findings, indexedOccurrencesByFile };\n}\n\nasync function readSafe(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf8\");\n } catch (err: unknown) {\n if (typeof err === \"object\" && err !== null && \"code\" in err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\" || code === \"EISDIR\") return null;\n }\n throw err;\n }\n}\n","import { parse as parseTypeScript } from \"@typescript-eslint/parser\";\nimport { visitorKeys as typescriptVisitorKeys } from \"@typescript-eslint/visitor-keys\";\n\nexport type LiteralKind = \"string\" | \"number\";\n\nexport interface LiteralLocation {\n readonly file: string;\n readonly line: number;\n}\n\nexport interface LiteralOccurrence {\n readonly kind: LiteralKind;\n readonly value: string;\n readonly loc: LiteralLocation;\n}\n\nexport type LiteralIndex = ReadonlyMap<string, readonly LiteralLocation[]>;\n\nexport type VisitorKeysMap = Record<string, readonly string[] | undefined>;\n\nexport const REMEDIATION = {\n IMPORT_FROM_SOURCE: \"import-from-source\",\n EXTRACT_TO_SHARED_TEST_SUPPORT: \"extract-to-shared-test-support\",\n} as const;\n\nexport type Remediation = (typeof REMEDIATION)[keyof typeof REMEDIATION];\n\nexport interface ReuseFinding {\n readonly test: LiteralLocation;\n readonly kind: LiteralKind;\n readonly value: string;\n readonly src: readonly LiteralLocation[];\n readonly remediation: typeof REMEDIATION.IMPORT_FROM_SOURCE;\n}\n\nexport interface DupeFinding {\n readonly test: LiteralLocation;\n readonly kind: LiteralKind;\n readonly value: string;\n readonly otherTests: readonly LiteralLocation[];\n readonly remediation: typeof REMEDIATION.EXTRACT_TO_SHARED_TEST_SUPPORT;\n}\n\nexport interface DetectionResult {\n readonly srcReuse: readonly ReuseFinding[];\n readonly testDupe: readonly DupeFinding[];\n}\n\nexport interface CollectLiteralsOptions {\n readonly visitorKeys: VisitorKeysMap;\n readonly minStringLength: number;\n readonly minNumberDigits: number;\n}\n\nexport interface DetectReuseInput {\n readonly srcIndex: LiteralIndex;\n readonly testOccurrencesByFile: ReadonlyMap<string, readonly LiteralOccurrence[]>;\n readonly allowlist: ReadonlySet<string>;\n}\n\nexport const defaultVisitorKeys: VisitorKeysMap = typescriptVisitorKeys;\n\nconst MODULE_NAMING_SKIP: Record<string, ReadonlySet<string>> = {\n ImportDeclaration: new Set([\"source\"]),\n ExportNamedDeclaration: new Set([\"source\"]),\n ExportAllDeclaration: new Set([\"source\"]),\n ImportExpression: new Set([\"source\"]),\n TSImportType: new Set([\"source\", \"argument\"]),\n TSExternalModuleReference: new Set([\"expression\"]),\n};\n\nconst EMPTY_SKIP: ReadonlySet<string> = new Set();\n\ninterface Node {\n readonly type: string;\n readonly loc?: { readonly start?: { readonly line?: number } };\n readonly value?: unknown;\n readonly raw?: unknown;\n readonly [key: string]: unknown;\n}\n\nexport function collectLiterals(\n source: string,\n filename: string,\n options: CollectLiteralsOptions,\n): LiteralOccurrence[] {\n const ast = parseTypeScript(source, {\n loc: true,\n range: true,\n comment: false,\n jsx: true,\n ecmaVersion: \"latest\",\n sourceType: \"module\",\n }) as unknown as Node;\n const out: LiteralOccurrence[] = [];\n walk(ast, filename, options, out);\n return out;\n}\n\nfunction walk(\n node: Node,\n filename: string,\n options: CollectLiteralsOptions,\n out: LiteralOccurrence[],\n): void {\n emitLiteral(node, filename, options, out);\n\n const keys = options.visitorKeys[node.type];\n if (!keys) {\n return;\n }\n const skip = MODULE_NAMING_SKIP[node.type] ?? EMPTY_SKIP;\n for (const key of keys) {\n if (skip.has(key)) continue;\n const child = node[key];\n if (Array.isArray(child)) {\n for (const item of child) {\n if (isNode(item)) walk(item, filename, options, out);\n }\n } else if (isNode(child)) {\n walk(child, filename, options, out);\n }\n }\n}\n\nfunction isNode(value: unknown): value is Node {\n return typeof value === \"object\" && value !== null && typeof (value as Node).type === \"string\";\n}\n\nfunction emitLiteral(\n node: Node,\n filename: string,\n options: CollectLiteralsOptions,\n out: LiteralOccurrence[],\n): void {\n const line = node.loc?.start?.line ?? 0;\n\n if (node.type === \"Literal\") {\n if (typeof node.value === \"string\") {\n if (node.value.length >= options.minStringLength) {\n out.push({ kind: \"string\", value: node.value, loc: { file: filename, line } });\n }\n } else if (typeof node.value === \"number\") {\n const raw = typeof node.raw === \"string\" ? node.raw : String(node.value);\n if (isMeaningfulNumber(raw, options.minNumberDigits)) {\n out.push({ kind: \"number\", value: String(node.value), loc: { file: filename, line } });\n }\n }\n return;\n }\n\n if (node.type === \"TemplateElement\") {\n const value = node.value as { readonly cooked?: string } | undefined;\n const cooked = value?.cooked ?? \"\";\n if (cooked.length >= options.minStringLength) {\n out.push({ kind: \"string\", value: cooked, loc: { file: filename, line } });\n }\n }\n}\n\nfunction isMeaningfulNumber(raw: string, minDigits: number): boolean {\n const digits = raw.replace(/[^0-9]/g, \"\");\n return digits.length >= minDigits;\n}\n\nexport function buildIndex(\n occurrences: Iterable<LiteralOccurrence>,\n): LiteralIndex {\n const map = new Map<string, LiteralLocation[]>();\n for (const occ of occurrences) {\n const key = makeKey(occ.kind, occ.value);\n const existing = map.get(key);\n if (existing) {\n existing.push(occ.loc);\n } else {\n map.set(key, [occ.loc]);\n }\n }\n return map;\n}\n\nfunction makeKey(kind: LiteralKind, value: string): string {\n return `${kind}\\0${value}`;\n}\n\nfunction splitKey(key: string): { kind: LiteralKind; value: string } {\n const idx = key.indexOf(\"\\0\");\n return { kind: key.slice(0, idx) as LiteralKind, value: key.slice(idx + 1) };\n}\n\nexport function detectReuse(input: DetectReuseInput): DetectionResult {\n const srcReuse: ReuseFinding[] = [];\n const testDupe: DupeFinding[] = [];\n\n const testIndex = new Map<string, Map<string, LiteralLocation[]>>();\n for (const [file, occurrences] of input.testOccurrencesByFile) {\n for (const occ of occurrences) {\n if (input.allowlist.has(occ.value)) continue;\n const key = makeKey(occ.kind, occ.value);\n let byFile = testIndex.get(key);\n if (!byFile) {\n byFile = new Map<string, LiteralLocation[]>();\n testIndex.set(key, byFile);\n }\n const locsInFile = byFile.get(file);\n if (locsInFile) locsInFile.push(occ.loc);\n else byFile.set(file, [occ.loc]);\n }\n }\n\n for (const [key, byFile] of testIndex) {\n const { kind, value } = splitKey(key);\n const srcLocs = input.srcIndex.get(key);\n const allTestLocs: LiteralLocation[] = [];\n for (const locs of byFile.values()) allTestLocs.push(...locs);\n\n if (srcLocs && srcLocs.length > 0) {\n for (const testLoc of allTestLocs) {\n srcReuse.push({\n test: testLoc,\n kind,\n value,\n src: srcLocs,\n remediation: REMEDIATION.IMPORT_FROM_SOURCE,\n });\n }\n } else if (byFile.size >= 2) {\n for (let i = 0; i < allTestLocs.length; i += 1) {\n const otherTests = [...allTestLocs.slice(0, i), ...allTestLocs.slice(i + 1)];\n testDupe.push({\n test: allTestLocs[i],\n kind,\n value,\n otherTests,\n remediation: REMEDIATION.EXTRACT_TO_SHARED_TEST_SUPPORT,\n });\n }\n }\n }\n\n return { srcReuse, testDupe };\n}\n\nexport function parseLiteralReuseResult(value: unknown): DetectionResult {\n if (!isPlainObject(value)) {\n throw new Error(\"literal-reuse result must be an object\");\n }\n const obj = value as { srcReuse?: unknown; testDupe?: unknown };\n if (!Array.isArray(obj.srcReuse)) {\n throw new Error(\"literal-reuse result is missing srcReuse array\");\n }\n if (!Array.isArray(obj.testDupe)) {\n throw new Error(\"literal-reuse result is missing testDupe array\");\n }\n for (const f of obj.srcReuse) validateReuseFinding(f);\n for (const f of obj.testDupe) validateDupeFinding(f);\n return { srcReuse: obj.srcReuse as readonly ReuseFinding[], testDupe: obj.testDupe as readonly DupeFinding[] };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction validateLiteralLocation(value: unknown, context: string): void {\n if (!isPlainObject(value)) throw new Error(`${context} must be an object`);\n if (typeof value[\"file\"] !== \"string\") throw new Error(`${context}.file must be a string`);\n if (typeof value[\"line\"] !== \"number\") throw new Error(`${context}.line must be a number`);\n}\n\nfunction validateKindValue(value: unknown, context: string): void {\n if (!isPlainObject(value)) throw new Error(`${context} must be an object`);\n if (value[\"kind\"] !== \"string\" && value[\"kind\"] !== \"number\") {\n throw new Error(`${context}.kind must be \"string\" or \"number\"`);\n }\n if (typeof value[\"value\"] !== \"string\") {\n throw new Error(`${context}.value must be a string`);\n }\n}\n\nfunction validateReuseFinding(value: unknown): void {\n validateKindValue(value, \"srcReuse finding\");\n const obj = value as Record<string, unknown>;\n validateLiteralLocation(obj[\"test\"], \"srcReuse finding.test\");\n if (!Array.isArray(obj[\"src\"])) throw new Error(\"srcReuse finding.src must be an array\");\n for (const loc of obj[\"src\"]) validateLiteralLocation(loc, \"srcReuse finding.src[i]\");\n if (obj[\"remediation\"] !== REMEDIATION.IMPORT_FROM_SOURCE) {\n throw new Error(`srcReuse finding.remediation must be \"${REMEDIATION.IMPORT_FROM_SOURCE}\"`);\n }\n}\n\nfunction validateDupeFinding(value: unknown): void {\n validateKindValue(value, \"testDupe finding\");\n const obj = value as Record<string, unknown>;\n validateLiteralLocation(obj[\"test\"], \"testDupe finding.test\");\n if (!Array.isArray(obj[\"otherTests\"])) {\n throw new Error(\"testDupe finding.otherTests must be an array\");\n }\n for (const loc of obj[\"otherTests\"]) validateLiteralLocation(loc, \"testDupe finding.otherTests[i]\");\n if (obj[\"remediation\"] !== REMEDIATION.EXTRACT_TO_SHARED_TEST_SUPPORT) {\n throw new Error(\n `testDupe finding.remediation must be \"${REMEDIATION.EXTRACT_TO_SHARED_TEST_SUPPORT}\"`,\n );\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nconst EXCLUDE_FILENAME = \"EXCLUDE\";\nconst SPX_DIR = \"spx\";\n\nexport async function readExcludePaths(projectRoot: string): Promise<readonly string[]> {\n const filePath = join(projectRoot, SPX_DIR, EXCLUDE_FILENAME);\n try {\n const content = await readFile(filePath, \"utf8\");\n return parseExcludeContent(content);\n } catch (err: unknown) {\n if (isNodeError(err) && err.code === \"ENOENT\") {\n return [];\n }\n throw err;\n }\n}\n\nexport function isUnderExcluded(\n relPath: string,\n excludePaths: readonly string[],\n): boolean {\n for (const raw of excludePaths) {\n const prefix = `${SPX_DIR}/${raw}`;\n if (relPath === prefix || relPath.startsWith(`${prefix}/`)) {\n return true;\n }\n }\n return false;\n}\n\nfunction parseExcludeContent(content: string): readonly string[] {\n return content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && !line.startsWith(\"#\"));\n}\n\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return typeof err === \"object\" && err !== null && \"code\" in err;\n}\n","import { readdir } from \"node:fs/promises\";\nimport { join, relative } from \"node:path\";\n\nimport { isUnderExcluded } from \"./exclude.js\";\n\nexport const ARTIFACT_DIRECTORIES: ReadonlySet<string> = new Set([\n \"node_modules\",\n \"dist\",\n \"build\",\n \".next\",\n \".source\",\n \".git\",\n \"out\",\n \"coverage\",\n]);\n\nconst TYPESCRIPT_EXTENSIONS: ReadonlySet<string> = new Set([\".ts\", \".tsx\"]);\nconst DECLARATION_SUFFIX = \".d.ts\";\n\nexport async function walkTypescriptFiles(\n projectRoot: string,\n excludePaths: readonly string[],\n): Promise<string[]> {\n const out: string[] = [];\n await walk(projectRoot, projectRoot, excludePaths, out);\n return out;\n}\n\nasync function walk(\n dir: string,\n projectRoot: string,\n excludePaths: readonly string[],\n out: string[],\n): Promise<void> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (err: unknown) {\n if (isNodeError(err) && (err.code === \"ENOENT\" || err.code === \"ENOTDIR\")) {\n return;\n }\n throw err;\n }\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n if (ARTIFACT_DIRECTORIES.has(entry.name)) continue;\n const subdir = join(dir, entry.name);\n const rel = relative(projectRoot, subdir);\n if (isUnderExcluded(rel, excludePaths)) continue;\n await walk(subdir, projectRoot, excludePaths, out);\n } else if (entry.isFile()) {\n if (!isTypescriptSource(entry.name)) continue;\n out.push(join(dir, entry.name));\n }\n }\n}\n\nfunction isTypescriptSource(name: string): boolean {\n if (name.endsWith(DECLARATION_SUFFIX)) return false;\n const ext = extensionOf(name);\n return TYPESCRIPT_EXTENSIONS.has(ext);\n}\n\nfunction extensionOf(name: string): string {\n const idx = name.lastIndexOf(\".\");\n return idx === -1 ? \"\" : name.slice(idx);\n}\n\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return typeof err === \"object\" && err !== null && \"code\" in err;\n}\n\nexport function isTestFile(relPath: string): boolean {\n return /\\.test\\.tsx?$/.test(relPath);\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport function createScanner(text, ignoreTrivia = false) {\n const len = text.length;\n let pos = 0, value = '', tokenOffset = 0, token = 16 /* SyntaxKind.Unknown */, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0 /* ScanError.None */;\n function scanHexDigits(count, exact) {\n let digits = 0;\n let value = 0;\n while (digits < count || !exact) {\n let ch = text.charCodeAt(pos);\n if (ch >= 48 /* CharacterCodes._0 */ && ch <= 57 /* CharacterCodes._9 */) {\n value = value * 16 + ch - 48 /* CharacterCodes._0 */;\n }\n else if (ch >= 65 /* CharacterCodes.A */ && ch <= 70 /* CharacterCodes.F */) {\n value = value * 16 + ch - 65 /* CharacterCodes.A */ + 10;\n }\n else if (ch >= 97 /* CharacterCodes.a */ && ch <= 102 /* CharacterCodes.f */) {\n value = value * 16 + ch - 97 /* CharacterCodes.a */ + 10;\n }\n else {\n break;\n }\n pos++;\n digits++;\n }\n if (digits < count) {\n value = -1;\n }\n return value;\n }\n function setPosition(newPosition) {\n pos = newPosition;\n value = '';\n tokenOffset = 0;\n token = 16 /* SyntaxKind.Unknown */;\n scanError = 0 /* ScanError.None */;\n }\n function scanNumber() {\n let start = pos;\n if (text.charCodeAt(pos) === 48 /* CharacterCodes._0 */) {\n pos++;\n }\n else {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n }\n if (pos < text.length && text.charCodeAt(pos) === 46 /* CharacterCodes.dot */) {\n pos++;\n if (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n }\n else {\n scanError = 3 /* ScanError.UnexpectedEndOfNumber */;\n return text.substring(start, pos);\n }\n }\n let end = pos;\n if (pos < text.length && (text.charCodeAt(pos) === 69 /* CharacterCodes.E */ || text.charCodeAt(pos) === 101 /* CharacterCodes.e */)) {\n pos++;\n if (pos < text.length && text.charCodeAt(pos) === 43 /* CharacterCodes.plus */ || text.charCodeAt(pos) === 45 /* CharacterCodes.minus */) {\n pos++;\n }\n if (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n end = pos;\n }\n else {\n scanError = 3 /* ScanError.UnexpectedEndOfNumber */;\n }\n }\n return text.substring(start, end);\n }\n function scanString() {\n let result = '', start = pos;\n while (true) {\n if (pos >= len) {\n result += text.substring(start, pos);\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n const ch = text.charCodeAt(pos);\n if (ch === 34 /* CharacterCodes.doubleQuote */) {\n result += text.substring(start, pos);\n pos++;\n break;\n }\n if (ch === 92 /* CharacterCodes.backslash */) {\n result += text.substring(start, pos);\n pos++;\n if (pos >= len) {\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n const ch2 = text.charCodeAt(pos++);\n switch (ch2) {\n case 34 /* CharacterCodes.doubleQuote */:\n result += '\\\"';\n break;\n case 92 /* CharacterCodes.backslash */:\n result += '\\\\';\n break;\n case 47 /* CharacterCodes.slash */:\n result += '/';\n break;\n case 98 /* CharacterCodes.b */:\n result += '\\b';\n break;\n case 102 /* CharacterCodes.f */:\n result += '\\f';\n break;\n case 110 /* CharacterCodes.n */:\n result += '\\n';\n break;\n case 114 /* CharacterCodes.r */:\n result += '\\r';\n break;\n case 116 /* CharacterCodes.t */:\n result += '\\t';\n break;\n case 117 /* CharacterCodes.u */:\n const ch3 = scanHexDigits(4, true);\n if (ch3 >= 0) {\n result += String.fromCharCode(ch3);\n }\n else {\n scanError = 4 /* ScanError.InvalidUnicode */;\n }\n break;\n default:\n scanError = 5 /* ScanError.InvalidEscapeCharacter */;\n }\n start = pos;\n continue;\n }\n if (ch >= 0 && ch <= 0x1f) {\n if (isLineBreak(ch)) {\n result += text.substring(start, pos);\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n else {\n scanError = 6 /* ScanError.InvalidCharacter */;\n // mark as error but continue with string\n }\n }\n pos++;\n }\n return result;\n }\n function scanNext() {\n value = '';\n scanError = 0 /* ScanError.None */;\n tokenOffset = pos;\n lineStartOffset = lineNumber;\n prevTokenLineStartOffset = tokenLineStartOffset;\n if (pos >= len) {\n // at the end\n tokenOffset = len;\n return token = 17 /* SyntaxKind.EOF */;\n }\n let code = text.charCodeAt(pos);\n // trivia: whitespace\n if (isWhiteSpace(code)) {\n do {\n pos++;\n value += String.fromCharCode(code);\n code = text.charCodeAt(pos);\n } while (isWhiteSpace(code));\n return token = 15 /* SyntaxKind.Trivia */;\n }\n // trivia: newlines\n if (isLineBreak(code)) {\n pos++;\n value += String.fromCharCode(code);\n if (code === 13 /* CharacterCodes.carriageReturn */ && text.charCodeAt(pos) === 10 /* CharacterCodes.lineFeed */) {\n pos++;\n value += '\\n';\n }\n lineNumber++;\n tokenLineStartOffset = pos;\n return token = 14 /* SyntaxKind.LineBreakTrivia */;\n }\n switch (code) {\n // tokens: []{}:,\n case 123 /* CharacterCodes.openBrace */:\n pos++;\n return token = 1 /* SyntaxKind.OpenBraceToken */;\n case 125 /* CharacterCodes.closeBrace */:\n pos++;\n return token = 2 /* SyntaxKind.CloseBraceToken */;\n case 91 /* CharacterCodes.openBracket */:\n pos++;\n return token = 3 /* SyntaxKind.OpenBracketToken */;\n case 93 /* CharacterCodes.closeBracket */:\n pos++;\n return token = 4 /* SyntaxKind.CloseBracketToken */;\n case 58 /* CharacterCodes.colon */:\n pos++;\n return token = 6 /* SyntaxKind.ColonToken */;\n case 44 /* CharacterCodes.comma */:\n pos++;\n return token = 5 /* SyntaxKind.CommaToken */;\n // strings\n case 34 /* CharacterCodes.doubleQuote */:\n pos++;\n value = scanString();\n return token = 10 /* SyntaxKind.StringLiteral */;\n // comments\n case 47 /* CharacterCodes.slash */:\n const start = pos - 1;\n // Single-line comment\n if (text.charCodeAt(pos + 1) === 47 /* CharacterCodes.slash */) {\n pos += 2;\n while (pos < len) {\n if (isLineBreak(text.charCodeAt(pos))) {\n break;\n }\n pos++;\n }\n value = text.substring(start, pos);\n return token = 12 /* SyntaxKind.LineCommentTrivia */;\n }\n // Multi-line comment\n if (text.charCodeAt(pos + 1) === 42 /* CharacterCodes.asterisk */) {\n pos += 2;\n const safeLength = len - 1; // For lookahead.\n let commentClosed = false;\n while (pos < safeLength) {\n const ch = text.charCodeAt(pos);\n if (ch === 42 /* CharacterCodes.asterisk */ && text.charCodeAt(pos + 1) === 47 /* CharacterCodes.slash */) {\n pos += 2;\n commentClosed = true;\n break;\n }\n pos++;\n if (isLineBreak(ch)) {\n if (ch === 13 /* CharacterCodes.carriageReturn */ && text.charCodeAt(pos) === 10 /* CharacterCodes.lineFeed */) {\n pos++;\n }\n lineNumber++;\n tokenLineStartOffset = pos;\n }\n }\n if (!commentClosed) {\n pos++;\n scanError = 1 /* ScanError.UnexpectedEndOfComment */;\n }\n value = text.substring(start, pos);\n return token = 13 /* SyntaxKind.BlockCommentTrivia */;\n }\n // just a single slash\n value += String.fromCharCode(code);\n pos++;\n return token = 16 /* SyntaxKind.Unknown */;\n // numbers\n case 45 /* CharacterCodes.minus */:\n value += String.fromCharCode(code);\n pos++;\n if (pos === len || !isDigit(text.charCodeAt(pos))) {\n return token = 16 /* SyntaxKind.Unknown */;\n }\n // found a minus, followed by a number so\n // we fall through to proceed with scanning\n // numbers\n case 48 /* CharacterCodes._0 */:\n case 49 /* CharacterCodes._1 */:\n case 50 /* CharacterCodes._2 */:\n case 51 /* CharacterCodes._3 */:\n case 52 /* CharacterCodes._4 */:\n case 53 /* CharacterCodes._5 */:\n case 54 /* CharacterCodes._6 */:\n case 55 /* CharacterCodes._7 */:\n case 56 /* CharacterCodes._8 */:\n case 57 /* CharacterCodes._9 */:\n value += scanNumber();\n return token = 11 /* SyntaxKind.NumericLiteral */;\n // literals and unknown symbols\n default:\n // is a literal? Read the full word.\n while (pos < len && isUnknownContentCharacter(code)) {\n pos++;\n code = text.charCodeAt(pos);\n }\n if (tokenOffset !== pos) {\n value = text.substring(tokenOffset, pos);\n // keywords: true, false, null\n switch (value) {\n case 'true': return token = 8 /* SyntaxKind.TrueKeyword */;\n case 'false': return token = 9 /* SyntaxKind.FalseKeyword */;\n case 'null': return token = 7 /* SyntaxKind.NullKeyword */;\n }\n return token = 16 /* SyntaxKind.Unknown */;\n }\n // some\n value += String.fromCharCode(code);\n pos++;\n return token = 16 /* SyntaxKind.Unknown */;\n }\n }\n function isUnknownContentCharacter(code) {\n if (isWhiteSpace(code) || isLineBreak(code)) {\n return false;\n }\n switch (code) {\n case 125 /* CharacterCodes.closeBrace */:\n case 93 /* CharacterCodes.closeBracket */:\n case 123 /* CharacterCodes.openBrace */:\n case 91 /* CharacterCodes.openBracket */:\n case 34 /* CharacterCodes.doubleQuote */:\n case 58 /* CharacterCodes.colon */:\n case 44 /* CharacterCodes.comma */:\n case 47 /* CharacterCodes.slash */:\n return false;\n }\n return true;\n }\n function scanNextNonTrivia() {\n let result;\n do {\n result = scanNext();\n } while (result >= 12 /* SyntaxKind.LineCommentTrivia */ && result <= 15 /* SyntaxKind.Trivia */);\n return result;\n }\n return {\n setPosition: setPosition,\n getPosition: () => pos,\n scan: ignoreTrivia ? scanNextNonTrivia : scanNext,\n getToken: () => token,\n getTokenValue: () => value,\n getTokenOffset: () => tokenOffset,\n getTokenLength: () => pos - tokenOffset,\n getTokenStartLine: () => lineStartOffset,\n getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,\n getTokenError: () => scanError,\n };\n}\nfunction isWhiteSpace(ch) {\n return ch === 32 /* CharacterCodes.space */ || ch === 9 /* CharacterCodes.tab */;\n}\nfunction isLineBreak(ch) {\n return ch === 10 /* CharacterCodes.lineFeed */ || ch === 13 /* CharacterCodes.carriageReturn */;\n}\nfunction isDigit(ch) {\n return ch >= 48 /* CharacterCodes._0 */ && ch <= 57 /* CharacterCodes._9 */;\n}\nvar CharacterCodes;\n(function (CharacterCodes) {\n CharacterCodes[CharacterCodes[\"lineFeed\"] = 10] = \"lineFeed\";\n CharacterCodes[CharacterCodes[\"carriageReturn\"] = 13] = \"carriageReturn\";\n CharacterCodes[CharacterCodes[\"space\"] = 32] = \"space\";\n CharacterCodes[CharacterCodes[\"_0\"] = 48] = \"_0\";\n CharacterCodes[CharacterCodes[\"_1\"] = 49] = \"_1\";\n CharacterCodes[CharacterCodes[\"_2\"] = 50] = \"_2\";\n CharacterCodes[CharacterCodes[\"_3\"] = 51] = \"_3\";\n CharacterCodes[CharacterCodes[\"_4\"] = 52] = \"_4\";\n CharacterCodes[CharacterCodes[\"_5\"] = 53] = \"_5\";\n CharacterCodes[CharacterCodes[\"_6\"] = 54] = \"_6\";\n CharacterCodes[CharacterCodes[\"_7\"] = 55] = \"_7\";\n CharacterCodes[CharacterCodes[\"_8\"] = 56] = \"_8\";\n CharacterCodes[CharacterCodes[\"_9\"] = 57] = \"_9\";\n CharacterCodes[CharacterCodes[\"a\"] = 97] = \"a\";\n CharacterCodes[CharacterCodes[\"b\"] = 98] = \"b\";\n CharacterCodes[CharacterCodes[\"c\"] = 99] = \"c\";\n CharacterCodes[CharacterCodes[\"d\"] = 100] = \"d\";\n CharacterCodes[CharacterCodes[\"e\"] = 101] = \"e\";\n CharacterCodes[CharacterCodes[\"f\"] = 102] = \"f\";\n CharacterCodes[CharacterCodes[\"g\"] = 103] = \"g\";\n CharacterCodes[CharacterCodes[\"h\"] = 104] = \"h\";\n CharacterCodes[CharacterCodes[\"i\"] = 105] = \"i\";\n CharacterCodes[CharacterCodes[\"j\"] = 106] = \"j\";\n CharacterCodes[CharacterCodes[\"k\"] = 107] = \"k\";\n CharacterCodes[CharacterCodes[\"l\"] = 108] = \"l\";\n CharacterCodes[CharacterCodes[\"m\"] = 109] = \"m\";\n CharacterCodes[CharacterCodes[\"n\"] = 110] = \"n\";\n CharacterCodes[CharacterCodes[\"o\"] = 111] = \"o\";\n CharacterCodes[CharacterCodes[\"p\"] = 112] = \"p\";\n CharacterCodes[CharacterCodes[\"q\"] = 113] = \"q\";\n CharacterCodes[CharacterCodes[\"r\"] = 114] = \"r\";\n CharacterCodes[CharacterCodes[\"s\"] = 115] = \"s\";\n CharacterCodes[CharacterCodes[\"t\"] = 116] = \"t\";\n CharacterCodes[CharacterCodes[\"u\"] = 117] = \"u\";\n CharacterCodes[CharacterCodes[\"v\"] = 118] = \"v\";\n CharacterCodes[CharacterCodes[\"w\"] = 119] = \"w\";\n CharacterCodes[CharacterCodes[\"x\"] = 120] = \"x\";\n CharacterCodes[CharacterCodes[\"y\"] = 121] = \"y\";\n CharacterCodes[CharacterCodes[\"z\"] = 122] = \"z\";\n CharacterCodes[CharacterCodes[\"A\"] = 65] = \"A\";\n CharacterCodes[CharacterCodes[\"B\"] = 66] = \"B\";\n CharacterCodes[CharacterCodes[\"C\"] = 67] = \"C\";\n CharacterCodes[CharacterCodes[\"D\"] = 68] = \"D\";\n CharacterCodes[CharacterCodes[\"E\"] = 69] = \"E\";\n CharacterCodes[CharacterCodes[\"F\"] = 70] = \"F\";\n CharacterCodes[CharacterCodes[\"G\"] = 71] = \"G\";\n CharacterCodes[CharacterCodes[\"H\"] = 72] = \"H\";\n CharacterCodes[CharacterCodes[\"I\"] = 73] = \"I\";\n CharacterCodes[CharacterCodes[\"J\"] = 74] = \"J\";\n CharacterCodes[CharacterCodes[\"K\"] = 75] = \"K\";\n CharacterCodes[CharacterCodes[\"L\"] = 76] = \"L\";\n CharacterCodes[CharacterCodes[\"M\"] = 77] = \"M\";\n CharacterCodes[CharacterCodes[\"N\"] = 78] = \"N\";\n CharacterCodes[CharacterCodes[\"O\"] = 79] = \"O\";\n CharacterCodes[CharacterCodes[\"P\"] = 80] = \"P\";\n CharacterCodes[CharacterCodes[\"Q\"] = 81] = \"Q\";\n CharacterCodes[CharacterCodes[\"R\"] = 82] = \"R\";\n CharacterCodes[CharacterCodes[\"S\"] = 83] = \"S\";\n CharacterCodes[CharacterCodes[\"T\"] = 84] = \"T\";\n CharacterCodes[CharacterCodes[\"U\"] = 85] = \"U\";\n CharacterCodes[CharacterCodes[\"V\"] = 86] = \"V\";\n CharacterCodes[CharacterCodes[\"W\"] = 87] = \"W\";\n CharacterCodes[CharacterCodes[\"X\"] = 88] = \"X\";\n CharacterCodes[CharacterCodes[\"Y\"] = 89] = \"Y\";\n CharacterCodes[CharacterCodes[\"Z\"] = 90] = \"Z\";\n CharacterCodes[CharacterCodes[\"asterisk\"] = 42] = \"asterisk\";\n CharacterCodes[CharacterCodes[\"backslash\"] = 92] = \"backslash\";\n CharacterCodes[CharacterCodes[\"closeBrace\"] = 125] = \"closeBrace\";\n CharacterCodes[CharacterCodes[\"closeBracket\"] = 93] = \"closeBracket\";\n CharacterCodes[CharacterCodes[\"colon\"] = 58] = \"colon\";\n CharacterCodes[CharacterCodes[\"comma\"] = 44] = \"comma\";\n CharacterCodes[CharacterCodes[\"dot\"] = 46] = \"dot\";\n CharacterCodes[CharacterCodes[\"doubleQuote\"] = 34] = \"doubleQuote\";\n CharacterCodes[CharacterCodes[\"minus\"] = 45] = \"minus\";\n CharacterCodes[CharacterCodes[\"openBrace\"] = 123] = \"openBrace\";\n CharacterCodes[CharacterCodes[\"openBracket\"] = 91] = \"openBracket\";\n CharacterCodes[CharacterCodes[\"plus\"] = 43] = \"plus\";\n CharacterCodes[CharacterCodes[\"slash\"] = 47] = \"slash\";\n CharacterCodes[CharacterCodes[\"formFeed\"] = 12] = \"formFeed\";\n CharacterCodes[CharacterCodes[\"tab\"] = 9] = \"tab\";\n})(CharacterCodes || (CharacterCodes = {}));\n","export const cachedSpaces = new Array(20).fill(0).map((_, index) => {\n return ' '.repeat(index);\n});\nconst maxCachedValues = 200;\nexport const cachedBreakLinesWithSpaces = {\n ' ': {\n '\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\n' + ' '.repeat(index);\n }),\n '\\r': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r' + ' '.repeat(index);\n }),\n '\\r\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r\\n' + ' '.repeat(index);\n }),\n },\n '\\t': {\n '\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\n' + '\\t'.repeat(index);\n }),\n '\\r': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r' + '\\t'.repeat(index);\n }),\n '\\r\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r\\n' + '\\t'.repeat(index);\n }),\n }\n};\nexport const supportedEols = ['\\n', '\\r', '\\r\\n'];\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nimport { createScanner } from './scanner';\nvar ParseOptions;\n(function (ParseOptions) {\n ParseOptions.DEFAULT = {\n allowTrailingComma: false\n };\n})(ParseOptions || (ParseOptions = {}));\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport function getLocation(text, position) {\n const segments = []; // strings or numbers\n const earlyReturnException = new Object();\n let previousNode = undefined;\n const previousNodeInst = {\n value: {},\n offset: 0,\n length: 0,\n type: 'object',\n parent: undefined\n };\n let isAtPropertyKey = false;\n function setPreviousNode(value, offset, length, type) {\n previousNodeInst.value = value;\n previousNodeInst.offset = offset;\n previousNodeInst.length = length;\n previousNodeInst.type = type;\n previousNodeInst.colonOffset = undefined;\n previousNode = previousNodeInst;\n }\n try {\n visit(text, {\n onObjectBegin: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n isAtPropertyKey = position > offset;\n segments.push(''); // push a placeholder (will be replaced)\n },\n onObjectProperty: (name, offset, length) => {\n if (position < offset) {\n throw earlyReturnException;\n }\n setPreviousNode(name, offset, length, 'property');\n segments[segments.length - 1] = name;\n if (position <= offset + length) {\n throw earlyReturnException;\n }\n },\n onObjectEnd: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.pop();\n },\n onArrayBegin: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.push(0);\n },\n onArrayEnd: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.pop();\n },\n onLiteralValue: (value, offset, length) => {\n if (position < offset) {\n throw earlyReturnException;\n }\n setPreviousNode(value, offset, length, getNodeType(value));\n if (position <= offset + length) {\n throw earlyReturnException;\n }\n },\n onSeparator: (sep, offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n if (sep === ':' && previousNode && previousNode.type === 'property') {\n previousNode.colonOffset = offset;\n isAtPropertyKey = false;\n previousNode = undefined;\n }\n else if (sep === ',') {\n const last = segments[segments.length - 1];\n if (typeof last === 'number') {\n segments[segments.length - 1] = last + 1;\n }\n else {\n isAtPropertyKey = true;\n segments[segments.length - 1] = '';\n }\n previousNode = undefined;\n }\n }\n });\n }\n catch (e) {\n if (e !== earlyReturnException) {\n throw e;\n }\n }\n return {\n path: segments,\n previousNode,\n isAtPropertyKey,\n matches: (pattern) => {\n let k = 0;\n for (let i = 0; k < pattern.length && i < segments.length; i++) {\n if (pattern[k] === segments[i] || pattern[k] === '*') {\n k++;\n }\n else if (pattern[k] !== '**') {\n return false;\n }\n }\n return k === pattern.length;\n }\n };\n}\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore always check the errors list to find out if the input was valid.\n */\nexport function parse(text, errors = [], options = ParseOptions.DEFAULT) {\n let currentProperty = null;\n let currentParent = [];\n const previousParents = [];\n function onValue(value) {\n if (Array.isArray(currentParent)) {\n currentParent.push(value);\n }\n else if (currentProperty !== null) {\n currentParent[currentProperty] = value;\n }\n }\n const visitor = {\n onObjectBegin: () => {\n const object = {};\n onValue(object);\n previousParents.push(currentParent);\n currentParent = object;\n currentProperty = null;\n },\n onObjectProperty: (name) => {\n currentProperty = name;\n },\n onObjectEnd: () => {\n currentParent = previousParents.pop();\n },\n onArrayBegin: () => {\n const array = [];\n onValue(array);\n previousParents.push(currentParent);\n currentParent = array;\n currentProperty = null;\n },\n onArrayEnd: () => {\n currentParent = previousParents.pop();\n },\n onLiteralValue: onValue,\n onError: (error, offset, length) => {\n errors.push({ error, offset, length });\n }\n };\n visit(text, visitor, options);\n return currentParent[0];\n}\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {\n let currentParent = { type: 'array', offset: -1, length: -1, children: [], parent: undefined }; // artificial root\n function ensurePropertyComplete(endOffset) {\n if (currentParent.type === 'property') {\n currentParent.length = endOffset - currentParent.offset;\n currentParent = currentParent.parent;\n }\n }\n function onValue(valueNode) {\n currentParent.children.push(valueNode);\n return valueNode;\n }\n const visitor = {\n onObjectBegin: (offset) => {\n currentParent = onValue({ type: 'object', offset, length: -1, parent: currentParent, children: [] });\n },\n onObjectProperty: (name, offset, length) => {\n currentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] });\n currentParent.children.push({ type: 'string', value: name, offset, length, parent: currentParent });\n },\n onObjectEnd: (offset, length) => {\n ensurePropertyComplete(offset + length); // in case of a missing value for a property: make sure property is complete\n currentParent.length = offset + length - currentParent.offset;\n currentParent = currentParent.parent;\n ensurePropertyComplete(offset + length);\n },\n onArrayBegin: (offset, length) => {\n currentParent = onValue({ type: 'array', offset, length: -1, parent: currentParent, children: [] });\n },\n onArrayEnd: (offset, length) => {\n currentParent.length = offset + length - currentParent.offset;\n currentParent = currentParent.parent;\n ensurePropertyComplete(offset + length);\n },\n onLiteralValue: (value, offset, length) => {\n onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });\n ensurePropertyComplete(offset + length);\n },\n onSeparator: (sep, offset, length) => {\n if (currentParent.type === 'property') {\n if (sep === ':') {\n currentParent.colonOffset = offset;\n }\n else if (sep === ',') {\n ensurePropertyComplete(offset);\n }\n }\n },\n onError: (error, offset, length) => {\n errors.push({ error, offset, length });\n }\n };\n visit(text, visitor, options);\n const result = currentParent.children[0];\n if (result) {\n delete result.parent;\n }\n return result;\n}\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport function findNodeAtLocation(root, path) {\n if (!root) {\n return undefined;\n }\n let node = root;\n for (let segment of path) {\n if (typeof segment === 'string') {\n if (node.type !== 'object' || !Array.isArray(node.children)) {\n return undefined;\n }\n let found = false;\n for (const propertyNode of node.children) {\n if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {\n node = propertyNode.children[1];\n found = true;\n break;\n }\n }\n if (!found) {\n return undefined;\n }\n }\n else {\n const index = segment;\n if (node.type !== 'array' || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {\n return undefined;\n }\n node = node.children[index];\n }\n }\n return node;\n}\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport function getNodePath(node) {\n if (!node.parent || !node.parent.children) {\n return [];\n }\n const path = getNodePath(node.parent);\n if (node.parent.type === 'property') {\n const key = node.parent.children[0].value;\n path.push(key);\n }\n else if (node.parent.type === 'array') {\n const index = node.parent.children.indexOf(node);\n if (index !== -1) {\n path.push(index);\n }\n }\n return path;\n}\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport function getNodeValue(node) {\n switch (node.type) {\n case 'array':\n return node.children.map(getNodeValue);\n case 'object':\n const obj = Object.create(null);\n for (let prop of node.children) {\n const valueNode = prop.children[1];\n if (valueNode) {\n obj[prop.children[0].value] = getNodeValue(valueNode);\n }\n }\n return obj;\n case 'null':\n case 'string':\n case 'number':\n case 'boolean':\n return node.value;\n default:\n return undefined;\n }\n}\nexport function contains(node, offset, includeRightBound = false) {\n return (offset >= node.offset && offset < (node.offset + node.length)) || includeRightBound && (offset === (node.offset + node.length));\n}\n/**\n * Finds the most inner node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport function findNodeAtOffset(node, offset, includeRightBound = false) {\n if (contains(node, offset, includeRightBound)) {\n const children = node.children;\n if (Array.isArray(children)) {\n for (let i = 0; i < children.length && children[i].offset <= offset; i++) {\n const item = findNodeAtOffset(children[i], offset, includeRightBound);\n if (item) {\n return item;\n }\n }\n }\n return node;\n }\n return undefined;\n}\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport function visit(text, visitor, options = ParseOptions.DEFAULT) {\n const _scanner = createScanner(text, false);\n // Important: Only pass copies of this to visitor functions to prevent accidental modification, and\n // to not affect visitor functions which stored a reference to a previous JSONPath\n const _jsonPath = [];\n // Depth of onXXXBegin() callbacks suppressed. onXXXEnd() decrements this if it isn't 0 already.\n // Callbacks are only called when this value is 0.\n let suppressedCallbacks = 0;\n function toNoArgVisit(visitFunction) {\n return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;\n }\n function toOneArgVisit(visitFunction) {\n return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;\n }\n function toOneArgVisitWithPath(visitFunction) {\n return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;\n }\n function toBeginVisit(visitFunction) {\n return visitFunction ?\n () => {\n if (suppressedCallbacks > 0) {\n suppressedCallbacks++;\n }\n else {\n let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());\n if (cbReturn === false) {\n suppressedCallbacks = 1;\n }\n }\n }\n : () => true;\n }\n function toEndVisit(visitFunction) {\n return visitFunction ?\n () => {\n if (suppressedCallbacks > 0) {\n suppressedCallbacks--;\n }\n if (suppressedCallbacks === 0) {\n visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());\n }\n }\n : () => true;\n }\n const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);\n const disallowComments = options && options.disallowComments;\n const allowTrailingComma = options && options.allowTrailingComma;\n function scanNext() {\n while (true) {\n const token = _scanner.scan();\n switch (_scanner.getTokenError()) {\n case 4 /* ScanError.InvalidUnicode */:\n handleError(14 /* ParseErrorCode.InvalidUnicode */);\n break;\n case 5 /* ScanError.InvalidEscapeCharacter */:\n handleError(15 /* ParseErrorCode.InvalidEscapeCharacter */);\n break;\n case 3 /* ScanError.UnexpectedEndOfNumber */:\n handleError(13 /* ParseErrorCode.UnexpectedEndOfNumber */);\n break;\n case 1 /* ScanError.UnexpectedEndOfComment */:\n if (!disallowComments) {\n handleError(11 /* ParseErrorCode.UnexpectedEndOfComment */);\n }\n break;\n case 2 /* ScanError.UnexpectedEndOfString */:\n handleError(12 /* ParseErrorCode.UnexpectedEndOfString */);\n break;\n case 6 /* ScanError.InvalidCharacter */:\n handleError(16 /* ParseErrorCode.InvalidCharacter */);\n break;\n }\n switch (token) {\n case 12 /* SyntaxKind.LineCommentTrivia */:\n case 13 /* SyntaxKind.BlockCommentTrivia */:\n if (disallowComments) {\n handleError(10 /* ParseErrorCode.InvalidCommentToken */);\n }\n else {\n onComment();\n }\n break;\n case 16 /* SyntaxKind.Unknown */:\n handleError(1 /* ParseErrorCode.InvalidSymbol */);\n break;\n case 15 /* SyntaxKind.Trivia */:\n case 14 /* SyntaxKind.LineBreakTrivia */:\n break;\n default:\n return token;\n }\n }\n }\n function handleError(error, skipUntilAfter = [], skipUntil = []) {\n onError(error);\n if (skipUntilAfter.length + skipUntil.length > 0) {\n let token = _scanner.getToken();\n while (token !== 17 /* SyntaxKind.EOF */) {\n if (skipUntilAfter.indexOf(token) !== -1) {\n scanNext();\n break;\n }\n else if (skipUntil.indexOf(token) !== -1) {\n break;\n }\n token = scanNext();\n }\n }\n }\n function parseString(isValue) {\n const value = _scanner.getTokenValue();\n if (isValue) {\n onLiteralValue(value);\n }\n else {\n onObjectProperty(value);\n // add property name afterwards\n _jsonPath.push(value);\n }\n scanNext();\n return true;\n }\n function parseLiteral() {\n switch (_scanner.getToken()) {\n case 11 /* SyntaxKind.NumericLiteral */:\n const tokenValue = _scanner.getTokenValue();\n let value = Number(tokenValue);\n if (isNaN(value)) {\n handleError(2 /* ParseErrorCode.InvalidNumberFormat */);\n value = 0;\n }\n onLiteralValue(value);\n break;\n case 7 /* SyntaxKind.NullKeyword */:\n onLiteralValue(null);\n break;\n case 8 /* SyntaxKind.TrueKeyword */:\n onLiteralValue(true);\n break;\n case 9 /* SyntaxKind.FalseKeyword */:\n onLiteralValue(false);\n break;\n default:\n return false;\n }\n scanNext();\n return true;\n }\n function parseProperty() {\n if (_scanner.getToken() !== 10 /* SyntaxKind.StringLiteral */) {\n handleError(3 /* ParseErrorCode.PropertyNameExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n return false;\n }\n parseString(false);\n if (_scanner.getToken() === 6 /* SyntaxKind.ColonToken */) {\n onSeparator(':');\n scanNext(); // consume colon\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n }\n else {\n handleError(5 /* ParseErrorCode.ColonExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n _jsonPath.pop(); // remove processed property name\n return true;\n }\n function parseObject() {\n onObjectBegin();\n scanNext(); // consume open brace\n let needsComma = false;\n while (_scanner.getToken() !== 2 /* SyntaxKind.CloseBraceToken */ && _scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n if (_scanner.getToken() === 5 /* SyntaxKind.CommaToken */) {\n if (!needsComma) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n }\n onSeparator(',');\n scanNext(); // consume comma\n if (_scanner.getToken() === 2 /* SyntaxKind.CloseBraceToken */ && allowTrailingComma) {\n break;\n }\n }\n else if (needsComma) {\n handleError(6 /* ParseErrorCode.CommaExpected */, [], []);\n }\n if (!parseProperty()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n needsComma = true;\n }\n onObjectEnd();\n if (_scanner.getToken() !== 2 /* SyntaxKind.CloseBraceToken */) {\n handleError(7 /* ParseErrorCode.CloseBraceExpected */, [2 /* SyntaxKind.CloseBraceToken */], []);\n }\n else {\n scanNext(); // consume close brace\n }\n return true;\n }\n function parseArray() {\n onArrayBegin();\n scanNext(); // consume open bracket\n let isFirstElement = true;\n let needsComma = false;\n while (_scanner.getToken() !== 4 /* SyntaxKind.CloseBracketToken */ && _scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n if (_scanner.getToken() === 5 /* SyntaxKind.CommaToken */) {\n if (!needsComma) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n }\n onSeparator(',');\n scanNext(); // consume comma\n if (_scanner.getToken() === 4 /* SyntaxKind.CloseBracketToken */ && allowTrailingComma) {\n break;\n }\n }\n else if (needsComma) {\n handleError(6 /* ParseErrorCode.CommaExpected */, [], []);\n }\n if (isFirstElement) {\n _jsonPath.push(0);\n isFirstElement = false;\n }\n else {\n _jsonPath[_jsonPath.length - 1]++;\n }\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [4 /* SyntaxKind.CloseBracketToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n needsComma = true;\n }\n onArrayEnd();\n if (!isFirstElement) {\n _jsonPath.pop(); // remove array index\n }\n if (_scanner.getToken() !== 4 /* SyntaxKind.CloseBracketToken */) {\n handleError(8 /* ParseErrorCode.CloseBracketExpected */, [4 /* SyntaxKind.CloseBracketToken */], []);\n }\n else {\n scanNext(); // consume close bracket\n }\n return true;\n }\n function parseValue() {\n switch (_scanner.getToken()) {\n case 3 /* SyntaxKind.OpenBracketToken */:\n return parseArray();\n case 1 /* SyntaxKind.OpenBraceToken */:\n return parseObject();\n case 10 /* SyntaxKind.StringLiteral */:\n return parseString(true);\n default:\n return parseLiteral();\n }\n }\n scanNext();\n if (_scanner.getToken() === 17 /* SyntaxKind.EOF */) {\n if (options.allowEmptyContent) {\n return true;\n }\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n return false;\n }\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n return false;\n }\n if (_scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n handleError(9 /* ParseErrorCode.EndOfFileExpected */, [], []);\n }\n return true;\n}\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport function stripComments(text, replaceCh) {\n let _scanner = createScanner(text), parts = [], kind, offset = 0, pos;\n do {\n pos = _scanner.getPosition();\n kind = _scanner.scan();\n switch (kind) {\n case 12 /* SyntaxKind.LineCommentTrivia */:\n case 13 /* SyntaxKind.BlockCommentTrivia */:\n case 17 /* SyntaxKind.EOF */:\n if (offset !== pos) {\n parts.push(text.substring(offset, pos));\n }\n if (replaceCh !== undefined) {\n parts.push(_scanner.getTokenValue().replace(/[^\\r\\n]/g, replaceCh));\n }\n offset = _scanner.getPosition();\n break;\n }\n } while (kind !== 17 /* SyntaxKind.EOF */);\n return parts.join('');\n}\nexport function getNodeType(value) {\n switch (typeof value) {\n case 'boolean': return 'boolean';\n case 'number': return 'number';\n case 'string': return 'string';\n case 'object': {\n if (!value) {\n return 'null';\n }\n else if (Array.isArray(value)) {\n return 'array';\n }\n return 'object';\n }\n default: return 'null';\n }\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nimport * as formatter from './impl/format';\nimport * as edit from './impl/edit';\nimport * as scanner from './impl/scanner';\nimport * as parser from './impl/parser';\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport const createScanner = scanner.createScanner;\nexport var ScanError;\n(function (ScanError) {\n ScanError[ScanError[\"None\"] = 0] = \"None\";\n ScanError[ScanError[\"UnexpectedEndOfComment\"] = 1] = \"UnexpectedEndOfComment\";\n ScanError[ScanError[\"UnexpectedEndOfString\"] = 2] = \"UnexpectedEndOfString\";\n ScanError[ScanError[\"UnexpectedEndOfNumber\"] = 3] = \"UnexpectedEndOfNumber\";\n ScanError[ScanError[\"InvalidUnicode\"] = 4] = \"InvalidUnicode\";\n ScanError[ScanError[\"InvalidEscapeCharacter\"] = 5] = \"InvalidEscapeCharacter\";\n ScanError[ScanError[\"InvalidCharacter\"] = 6] = \"InvalidCharacter\";\n})(ScanError || (ScanError = {}));\nexport var SyntaxKind;\n(function (SyntaxKind) {\n SyntaxKind[SyntaxKind[\"OpenBraceToken\"] = 1] = \"OpenBraceToken\";\n SyntaxKind[SyntaxKind[\"CloseBraceToken\"] = 2] = \"CloseBraceToken\";\n SyntaxKind[SyntaxKind[\"OpenBracketToken\"] = 3] = \"OpenBracketToken\";\n SyntaxKind[SyntaxKind[\"CloseBracketToken\"] = 4] = \"CloseBracketToken\";\n SyntaxKind[SyntaxKind[\"CommaToken\"] = 5] = \"CommaToken\";\n SyntaxKind[SyntaxKind[\"ColonToken\"] = 6] = \"ColonToken\";\n SyntaxKind[SyntaxKind[\"NullKeyword\"] = 7] = \"NullKeyword\";\n SyntaxKind[SyntaxKind[\"TrueKeyword\"] = 8] = \"TrueKeyword\";\n SyntaxKind[SyntaxKind[\"FalseKeyword\"] = 9] = \"FalseKeyword\";\n SyntaxKind[SyntaxKind[\"StringLiteral\"] = 10] = \"StringLiteral\";\n SyntaxKind[SyntaxKind[\"NumericLiteral\"] = 11] = \"NumericLiteral\";\n SyntaxKind[SyntaxKind[\"LineCommentTrivia\"] = 12] = \"LineCommentTrivia\";\n SyntaxKind[SyntaxKind[\"BlockCommentTrivia\"] = 13] = \"BlockCommentTrivia\";\n SyntaxKind[SyntaxKind[\"LineBreakTrivia\"] = 14] = \"LineBreakTrivia\";\n SyntaxKind[SyntaxKind[\"Trivia\"] = 15] = \"Trivia\";\n SyntaxKind[SyntaxKind[\"Unknown\"] = 16] = \"Unknown\";\n SyntaxKind[SyntaxKind[\"EOF\"] = 17] = \"EOF\";\n})(SyntaxKind || (SyntaxKind = {}));\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport const getLocation = parser.getLocation;\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore, always check the errors list to find out if the input was valid.\n */\nexport const parse = parser.parse;\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport const parseTree = parser.parseTree;\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport const findNodeAtLocation = parser.findNodeAtLocation;\n/**\n * Finds the innermost node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport const findNodeAtOffset = parser.findNodeAtOffset;\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport const getNodePath = parser.getNodePath;\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport const getNodeValue = parser.getNodeValue;\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport const visit = parser.visit;\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport const stripComments = parser.stripComments;\nexport var ParseErrorCode;\n(function (ParseErrorCode) {\n ParseErrorCode[ParseErrorCode[\"InvalidSymbol\"] = 1] = \"InvalidSymbol\";\n ParseErrorCode[ParseErrorCode[\"InvalidNumberFormat\"] = 2] = \"InvalidNumberFormat\";\n ParseErrorCode[ParseErrorCode[\"PropertyNameExpected\"] = 3] = \"PropertyNameExpected\";\n ParseErrorCode[ParseErrorCode[\"ValueExpected\"] = 4] = \"ValueExpected\";\n ParseErrorCode[ParseErrorCode[\"ColonExpected\"] = 5] = \"ColonExpected\";\n ParseErrorCode[ParseErrorCode[\"CommaExpected\"] = 6] = \"CommaExpected\";\n ParseErrorCode[ParseErrorCode[\"CloseBraceExpected\"] = 7] = \"CloseBraceExpected\";\n ParseErrorCode[ParseErrorCode[\"CloseBracketExpected\"] = 8] = \"CloseBracketExpected\";\n ParseErrorCode[ParseErrorCode[\"EndOfFileExpected\"] = 9] = \"EndOfFileExpected\";\n ParseErrorCode[ParseErrorCode[\"InvalidCommentToken\"] = 10] = \"InvalidCommentToken\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfComment\"] = 11] = \"UnexpectedEndOfComment\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfString\"] = 12] = \"UnexpectedEndOfString\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfNumber\"] = 13] = \"UnexpectedEndOfNumber\";\n ParseErrorCode[ParseErrorCode[\"InvalidUnicode\"] = 14] = \"InvalidUnicode\";\n ParseErrorCode[ParseErrorCode[\"InvalidEscapeCharacter\"] = 15] = \"InvalidEscapeCharacter\";\n ParseErrorCode[ParseErrorCode[\"InvalidCharacter\"] = 16] = \"InvalidCharacter\";\n})(ParseErrorCode || (ParseErrorCode = {}));\nexport function printParseErrorCode(code) {\n switch (code) {\n case 1 /* ParseErrorCode.InvalidSymbol */: return 'InvalidSymbol';\n case 2 /* ParseErrorCode.InvalidNumberFormat */: return 'InvalidNumberFormat';\n case 3 /* ParseErrorCode.PropertyNameExpected */: return 'PropertyNameExpected';\n case 4 /* ParseErrorCode.ValueExpected */: return 'ValueExpected';\n case 5 /* ParseErrorCode.ColonExpected */: return 'ColonExpected';\n case 6 /* ParseErrorCode.CommaExpected */: return 'CommaExpected';\n case 7 /* ParseErrorCode.CloseBraceExpected */: return 'CloseBraceExpected';\n case 8 /* ParseErrorCode.CloseBracketExpected */: return 'CloseBracketExpected';\n case 9 /* ParseErrorCode.EndOfFileExpected */: return 'EndOfFileExpected';\n case 10 /* ParseErrorCode.InvalidCommentToken */: return 'InvalidCommentToken';\n case 11 /* ParseErrorCode.UnexpectedEndOfComment */: return 'UnexpectedEndOfComment';\n case 12 /* ParseErrorCode.UnexpectedEndOfString */: return 'UnexpectedEndOfString';\n case 13 /* ParseErrorCode.UnexpectedEndOfNumber */: return 'UnexpectedEndOfNumber';\n case 14 /* ParseErrorCode.InvalidUnicode */: return 'InvalidUnicode';\n case 15 /* ParseErrorCode.InvalidEscapeCharacter */: return 'InvalidEscapeCharacter';\n case 16 /* ParseErrorCode.InvalidCharacter */: return 'InvalidCharacter';\n }\n return '<unknown ParseErrorCode>';\n}\n/**\n * Computes the edit operations needed to format a JSON document.\n *\n * @param documentText The input text\n * @param range The range to format or `undefined` to format the full content\n * @param options The formatting options\n * @returns The edit operations describing the formatting changes to the original document following the format described in {@linkcode EditResult}.\n * To apply the edit operations to the input, use {@linkcode applyEdits}.\n */\nexport function format(documentText, range, options) {\n return formatter.format(documentText, range, options);\n}\n/**\n * Computes the edit operations needed to modify a value in the JSON document.\n *\n * @param documentText The input text\n * @param path The path of the value to change. The path represents either to the document root, a property or an array item.\n * If the path points to an non-existing property or item, it will be created.\n * @param value The new value for the specified property or item. If the value is undefined,\n * the property or item will be removed.\n * @param options Options\n * @returns The edit operations describing the changes to the original document, following the format described in {@linkcode EditResult}.\n * To apply the edit operations to the input, use {@linkcode applyEdits}.\n */\nexport function modify(text, path, value, options) {\n return edit.setProperty(text, path, value, options);\n}\n/**\n * Applies edits to an input string.\n * @param text The input text\n * @param edits Edit operations following the format described in {@linkcode EditResult}.\n * @returns The text with the applied edits.\n * @throws An error if the edit operations are not well-formed as described in {@linkcode EditResult}.\n */\nexport function applyEdits(text, edits) {\n let sortedEdits = edits.slice(0).sort((a, b) => {\n const diff = a.offset - b.offset;\n if (diff === 0) {\n return a.length - b.length;\n }\n return diff;\n });\n let lastModifiedOffset = text.length;\n for (let i = sortedEdits.length - 1; i >= 0; i--) {\n let e = sortedEdits[i];\n if (e.offset + e.length <= lastModifiedOffset) {\n text = edit.applyEdit(text, e);\n }\n else {\n throw new Error('Overlapping edit');\n }\n lastModifiedOffset = e.offset;\n }\n return text;\n}\n","/**\n * TypeScript scope resolution for validation.\n *\n * Provides functions to determine which directories should be validated\n * based on tsconfig.json settings, ensuring alignment between TypeScript\n * and ESLint validation.\n *\n * @module validation/config/scope\n */\n\nimport * as JSONC from \"jsonc-parser\";\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { ScopeConfig, ValidationScope } from \"../types.js\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/**\n * TSConfig file paths for each validation scope.\n */\nexport const TSCONFIG_FILES = {\n full: \"tsconfig.json\",\n production: \"tsconfig.production.json\",\n} as const;\n\n// =============================================================================\n// DEPENDENCY INJECTION INTERFACES\n// =============================================================================\n\n/**\n * Dependencies for scope resolution.\n *\n * Enables dependency injection for testing without mocking.\n */\nexport interface ScopeDeps {\n readFileSync: typeof readFileSync;\n existsSync: typeof existsSync;\n readdirSync: typeof readdirSync;\n}\n\n/**\n * Default production dependencies.\n */\nexport const defaultScopeDeps: ScopeDeps = {\n readFileSync,\n existsSync,\n readdirSync,\n};\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\ninterface TypeScriptConfig {\n include?: string[];\n exclude?: string[];\n extends?: string;\n}\n\n// =============================================================================\n// INTERNAL FUNCTIONS\n// =============================================================================\n\n/**\n * Parse TypeScript configuration using proper JSONC parser.\n *\n * @param configPath - Path to tsconfig file\n * @param deps - Injectable dependencies\n * @returns Parsed TypeScript configuration\n */\nexport function parseTypeScriptConfig(\n configPath: string,\n deps: ScopeDeps = defaultScopeDeps,\n): TypeScriptConfig {\n try {\n const configContent = deps.readFileSync(configPath, \"utf-8\");\n const parsed = JSONC.parse(configContent) as TypeScriptConfig;\n return parsed;\n } catch {\n // Fallback: return minimal config and let directory detection work\n return {\n include: [\"**/*.ts\", \"**/*.tsx\"],\n exclude: [\"node_modules/**\", \".pnpm-store/**\", \"dist/**\"],\n };\n }\n}\n\n/**\n * Resolve complete TypeScript configuration including extends.\n *\n * @param scope - Validation scope\n * @param deps - Injectable dependencies\n * @returns Resolved TypeScript configuration\n */\nexport function resolveTypeScriptConfig(\n scope: ValidationScope,\n deps: ScopeDeps = defaultScopeDeps,\n): TypeScriptConfig {\n const configFile = TSCONFIG_FILES[scope];\n const config = parseTypeScriptConfig(configFile, deps);\n\n if (config.extends) {\n const baseConfig = parseTypeScriptConfig(config.extends, deps);\n return {\n include: config.include ?? baseConfig.include ?? [],\n exclude: [...(baseConfig.exclude ?? []), ...(config.exclude ?? [])],\n };\n }\n\n return {\n include: config.include ?? [],\n exclude: config.exclude ?? [],\n };\n}\n\n/**\n * Check if a directory contains TypeScript files recursively.\n *\n * @param dirPath - Directory to check\n * @param maxDepth - Maximum recursion depth\n * @param deps - Injectable dependencies\n * @returns True if directory contains TypeScript files\n */\nexport function hasTypeScriptFilesRecursive(\n dirPath: string,\n maxDepth: number = 2,\n deps: ScopeDeps = defaultScopeDeps,\n): boolean {\n if (maxDepth <= 0) return false;\n\n try {\n const items = deps.readdirSync(dirPath, { withFileTypes: true });\n\n // Check for TypeScript files in current directory\n const hasDirectTsFiles = items.some(\n (item) => item.isFile() && (item.name.endsWith(\".ts\") || item.name.endsWith(\".tsx\")),\n );\n\n if (hasDirectTsFiles) return true;\n\n // Check subdirectories (limited depth to avoid performance issues)\n const subdirs = items.filter((item) => item.isDirectory() && !item.name.startsWith(\".\"));\n for (const subdir of subdirs.slice(0, 5)) {\n // Limit to first 5 subdirs\n if (hasTypeScriptFilesRecursive(join(dirPath, subdir.name), maxDepth - 1, deps)) {\n return true;\n }\n }\n\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Get top-level directories containing TypeScript files.\n *\n * @param config - TypeScript configuration\n * @param deps - Injectable dependencies\n * @returns Array of directory names\n */\nexport function getTopLevelDirectoriesWithTypeScript(\n config: TypeScriptConfig,\n deps: ScopeDeps = defaultScopeDeps,\n): string[] {\n const allTopLevelItems = deps.readdirSync(\".\", { withFileTypes: true });\n const directories = new Set<string>();\n\n // Find all top-level directories\n const topLevelDirs = allTopLevelItems\n .filter((item) => item.isDirectory())\n .map((item) => item.name)\n .filter((name) => !name.startsWith(\".\"));\n\n // Check if each directory should be included based on tsconfig include/exclude patterns\n for (const dir of topLevelDirs) {\n // Check if directory is explicitly excluded\n const isExcluded = config.exclude?.some((pattern) => {\n // Handle patterns like \"specs/**/*\", \"docs/**/*\"\n if (pattern.includes(\"/**\")) {\n const dirPattern = pattern.split(\"/**\")[0];\n return dirPattern === dir;\n }\n // Handle exact matches and directory patterns\n return pattern === dir || pattern.startsWith(dir + \"/\") || pattern === dir + \"/**\";\n });\n\n if (!isExcluded) {\n // Check if directory has TypeScript files\n try {\n const hasTypeScriptFiles = hasTypeScriptFilesRecursive(dir, 2, deps);\n if (hasTypeScriptFiles) {\n directories.add(dir);\n }\n } catch {\n // Directory access error, skip\n continue;\n }\n }\n }\n\n // Also add explicitly mentioned directories from include patterns\n if (config.include) {\n for (const pattern of config.include) {\n // Extract directory from patterns like \"scripts/**/*.ts\", \"tests/**/*.tsx\"\n if (pattern.includes(\"/\")) {\n const topLevelDir = pattern.split(\"/\")[0];\n if (topLevelDir && !topLevelDir.includes(\"*\") && !topLevelDir.startsWith(\".\")) {\n directories.add(topLevelDir);\n }\n }\n }\n }\n\n return Array.from(directories).sort();\n}\n\n/**\n * Get validation directories based on tsconfig files.\n *\n * @param scope - Validation scope\n * @param deps - Injectable dependencies\n * @returns Array of directory names to validate\n */\nexport function getValidationDirectories(\n scope: ValidationScope,\n deps: ScopeDeps = defaultScopeDeps,\n): string[] {\n // Get TypeScript configuration for the specified mode\n const config = resolveTypeScriptConfig(scope, deps);\n\n // Get directories that contain TypeScript files and respect tsconfig exclude patterns\n const configDirectories = getTopLevelDirectoriesWithTypeScript(config, deps);\n\n // Only include directories that actually exist\n const existingDirectories = configDirectories.filter((dir) => deps.existsSync(dir));\n\n return existingDirectories;\n}\n\n/**\n * Get authoritative validation scope configuration.\n *\n * This is the main entry point for scope resolution. Returns a ScopeConfig\n * object that can be used to configure validation tools.\n *\n * @param scope - Validation scope\n * @param deps - Injectable dependencies\n * @returns Scope configuration\n *\n * @example\n * ```typescript\n * const scopeConfig = getTypeScriptScope(\"full\");\n * console.log(scopeConfig.directories); // [\"src\", \"tests\", \"scripts\"]\n * ```\n */\nexport function getTypeScriptScope(\n scope: ValidationScope,\n deps: ScopeDeps = defaultScopeDeps,\n): ScopeConfig {\n // Use validation-focused directory selection\n const directories = getValidationDirectories(scope, deps);\n\n // Read TypeScript config for patterns\n const config = resolveTypeScriptConfig(scope, deps);\n\n return {\n directories,\n filePatterns: config.include ?? [],\n excludePatterns: config.exclude ?? [],\n };\n}\n","/**\n * Tool discovery for validation infrastructure.\n *\n * Discovers validation tools (eslint, tsc, madge, etc.) using a three-tier\n * priority system: bundled → project → global.\n *\n * @module validation/discovery/tool-finder\n */\n\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\n\nimport { TOOL_DISCOVERY, type ToolSource } from \"./constants.js\";\n\n/**\n * Information about a found tool.\n */\nexport interface ToolLocation {\n /** The tool name */\n tool: string;\n /** Absolute path to the tool executable or package */\n path: string;\n /** Where the tool was found */\n source: ToolSource;\n}\n\n/**\n * Information about a tool that was not found.\n */\nexport interface ToolNotFound {\n /** The tool name that was searched for */\n tool: string;\n /** Human-readable reason why the tool was not found */\n reason: string;\n}\n\n/**\n * Result of tool discovery - either found with location or not found with reason.\n */\nexport type ToolDiscoveryResult =\n | { found: true; location: ToolLocation }\n | { found: false; notFound: ToolNotFound };\n\n/**\n * Dependencies for tool discovery.\n * Enables testing without mocking by accepting controlled implementations.\n */\nexport interface ToolDiscoveryDeps {\n /**\n * Resolve a module path, returns the resolved path or null if not found.\n * @param modulePath - The module path to resolve (e.g., \"eslint/package.json\")\n */\n resolveModule: (modulePath: string) => string | null;\n\n /**\n * Check if a file exists at the given path.\n * @param filePath - The path to check\n */\n existsSync: (filePath: string) => boolean;\n\n /**\n * Find an executable in the system PATH.\n * @param tool - The tool name to find\n * @returns The absolute path to the tool, or null if not found\n */\n whichSync: (tool: string) => string | null;\n}\n\n/**\n * Create a require function for resolving modules.\n * Uses import.meta.url to create a require that resolves from this package.\n */\nconst require = createRequire(import.meta.url);\n\n/**\n * Default production dependencies for tool discovery.\n */\nexport const defaultToolDiscoveryDeps: ToolDiscoveryDeps = {\n resolveModule: (modulePath: string): string | null => {\n try {\n return require.resolve(modulePath);\n } catch {\n return null;\n }\n },\n\n existsSync: fs.existsSync,\n\n whichSync: (tool: string): string | null => {\n try {\n const result = execSync(`which ${tool}`, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n return result.trim() || null;\n } catch {\n return null;\n }\n },\n};\n\n/**\n * Options for tool discovery.\n */\nexport interface DiscoverToolOptions {\n /**\n * Project root directory for checking project-local node_modules.\n * Defaults to current working directory.\n */\n projectRoot?: string;\n\n /**\n * Dependencies for tool discovery.\n * Defaults to production dependencies.\n */\n deps?: ToolDiscoveryDeps;\n}\n\n/**\n * Discover a validation tool using three-tier priority.\n *\n * Discovery order:\n * 1. **Bundled**: Check if the tool is bundled with spx-cli via require.resolve\n * 2. **Project**: Check project's node_modules/.bin directory\n * 3. **Global**: Check system PATH via `which` command\n *\n * @param tool - The tool name to discover (e.g., \"eslint\", \"typescript\", \"madge\")\n * @param options - Discovery options including projectRoot and dependencies\n * @returns Discovery result with found location or not found reason\n *\n * @example\n * ```typescript\n * const result = await discoverTool(\"eslint\");\n * if (result.found) {\n * console.log(`Found ${result.location.tool} at ${result.location.path}`);\n * console.log(`Source: ${result.location.source}`);\n * } else {\n * console.log(`Not found: ${result.notFound.reason}`);\n * }\n * ```\n */\nexport async function discoverTool(\n tool: string,\n options: DiscoverToolOptions = {},\n): Promise<ToolDiscoveryResult> {\n const { projectRoot = process.cwd(), deps = defaultToolDiscoveryDeps } = options;\n\n // Tier 1: Check if bundled with spx-cli\n const bundledPath = deps.resolveModule(`${tool}/package.json`);\n if (bundledPath) {\n return {\n found: true,\n location: {\n tool,\n path: path.dirname(bundledPath),\n source: TOOL_DISCOVERY.SOURCES.BUNDLED,\n },\n };\n }\n\n // Tier 2: Check project's node_modules/.bin\n const projectBinPath = path.join(projectRoot, \"node_modules\", \".bin\", tool);\n if (deps.existsSync(projectBinPath)) {\n return {\n found: true,\n location: {\n tool,\n path: projectBinPath,\n source: TOOL_DISCOVERY.SOURCES.PROJECT,\n },\n };\n }\n\n // Tier 3: Check system PATH\n const globalPath = deps.whichSync(tool);\n if (globalPath) {\n return {\n found: true,\n location: {\n tool,\n path: globalPath,\n source: TOOL_DISCOVERY.SOURCES.GLOBAL,\n },\n };\n }\n\n // Not found anywhere\n return {\n found: false,\n notFound: {\n tool,\n reason: TOOL_DISCOVERY.MESSAGES.NOT_FOUND_REASON(tool),\n },\n };\n}\n\n/**\n * Format a graceful skip message for when a tool is not found.\n *\n * @param stepName - The name of the validation step being skipped\n * @param result - The tool discovery result\n * @returns Formatted skip message, or empty string if tool was found\n *\n * @example\n * ```typescript\n * const result = await discoverTool(\"madge\");\n * const message = formatSkipMessage(\"Circular dependency check\", result);\n * // \"⏭ Skipping Circular dependency check (madge not available)\"\n * ```\n */\nexport function formatSkipMessage(\n stepName: string,\n result: ToolDiscoveryResult,\n): string {\n if (result.found) {\n return \"\";\n }\n return TOOL_DISCOVERY.MESSAGES.SKIP_FORMAT(stepName, result.notFound.tool);\n}\n","/**\n * Constants for tool discovery.\n * @module validation/discovery/constants\n */\n\n/**\n * Tool discovery constants.\n * Using constants ensures DRY principle and makes tests verify behavior via constants.\n */\nexport const TOOL_DISCOVERY = {\n /** Tool source identifiers */\n SOURCES: {\n /** Tool bundled with spx-cli */\n BUNDLED: \"bundled\",\n /** Tool in project's node_modules */\n PROJECT: \"project\",\n /** Tool in system PATH */\n GLOBAL: \"global\",\n } as const,\n\n /** Message templates */\n MESSAGES: {\n /** Prefix for skip messages */\n SKIP_PREFIX: \"\\u23ED\", // ⏭ emoji\n /**\n * Format not found reason message.\n * @param tool - The tool name that was not found\n */\n NOT_FOUND_REASON: (tool: string): string =>\n `${tool} not found in bundled deps, project node_modules, or system PATH`,\n /**\n * Format skip message for graceful degradation.\n * @param step - The validation step name\n * @param tool - The tool that was not found\n */\n SKIP_FORMAT: (step: string, tool: string): string =>\n `${TOOL_DISCOVERY.MESSAGES.SKIP_PREFIX} Skipping ${step} (${tool} not available)`,\n },\n} as const;\n\n/** Type for tool source */\nexport type ToolSource = (typeof TOOL_DISCOVERY.SOURCES)[keyof typeof TOOL_DISCOVERY.SOURCES];\n","/**\n * Language detection for validation infrastructure.\n *\n * Detects which programming languages a project uses based on configuration\n * file presence. Language-specific validation tools (ESLint, tsc, mypy) consult\n * detection results to determine whether to run.\n *\n * @module validation/discovery/language-finder\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/**\n * Marker file for TypeScript projects, checked in the project root.\n */\nexport const TYPESCRIPT_MARKER = \"tsconfig.json\";\n\n/**\n * Marker file for Python projects, checked in the project root.\n */\nexport const PYTHON_MARKER = \"pyproject.toml\";\n\n/**\n * ESLint flat config file names, in priority order.\n *\n * ESLint 9+ uses flat config exclusively. When multiple config files exist in\n * the same directory, the highest-priority one wins.\n */\nexport const ESLINT_CONFIG_FILES = [\n \"eslint.config.ts\",\n \"eslint.config.js\",\n \"eslint.config.mjs\",\n \"eslint.config.cjs\",\n] as const;\n\n/**\n * Type of an ESLint config file name.\n */\nexport type EslintConfigFile = (typeof ESLINT_CONFIG_FILES)[number];\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\n/**\n * Result of TypeScript language detection.\n */\nexport interface TypeScriptDetection {\n /** Whether TypeScript is present in the project. */\n present: boolean;\n /** The ESLint flat config file name found, if any. Only set when `present` is true. */\n eslintConfigFile?: EslintConfigFile;\n}\n\n/**\n * Result of Python language detection.\n */\nexport interface PythonDetection {\n /** Whether Python is present in the project. */\n present: boolean;\n}\n\n/**\n * Result of full language detection.\n */\nexport interface LanguageDetection {\n typescript: TypeScriptDetection;\n python: PythonDetection;\n}\n\n/**\n * Dependencies for language detection.\n *\n * Enables type-safe dependency injection for testing without mocking.\n */\nexport interface LanguageDetectionDeps {\n /**\n * Check whether a file exists at the given absolute path.\n * @param filePath - Absolute path to check.\n */\n existsSync: (filePath: string) => boolean;\n}\n\n/**\n * Default production dependencies.\n */\nexport const defaultLanguageDetectionDeps: LanguageDetectionDeps = {\n existsSync: fs.existsSync,\n};\n\n// =============================================================================\n// DETECTION FUNCTIONS\n// =============================================================================\n\n/**\n * Detect whether a project uses TypeScript.\n *\n * TypeScript is present when `tsconfig.json` exists in the project root. When\n * present, the function also searches for an ESLint flat config file and\n * returns its name in priority order.\n *\n * @param projectRoot - Absolute path to the project root.\n * @param deps - Injectable filesystem dependencies.\n * @returns Detection result with presence flag and optional ESLint config path.\n */\nexport function detectTypeScript(\n projectRoot: string,\n deps: LanguageDetectionDeps = defaultLanguageDetectionDeps,\n): TypeScriptDetection {\n const present = deps.existsSync(path.join(projectRoot, TYPESCRIPT_MARKER));\n\n if (!present) {\n return { present: false };\n }\n\n const eslintConfigFile = ESLINT_CONFIG_FILES.find((configFile) =>\n deps.existsSync(path.join(projectRoot, configFile))\n );\n\n return eslintConfigFile === undefined\n ? { present: true }\n : { present: true, eslintConfigFile };\n}\n\n/**\n * Detect whether a project uses Python.\n *\n * Python is present when `pyproject.toml` exists in the project root.\n *\n * @param projectRoot - Absolute path to the project root.\n * @param deps - Injectable filesystem dependencies.\n * @returns Detection result with presence flag.\n */\nexport function detectPython(\n projectRoot: string,\n deps: LanguageDetectionDeps = defaultLanguageDetectionDeps,\n): PythonDetection {\n const present = deps.existsSync(path.join(projectRoot, PYTHON_MARKER));\n return { present };\n}\n\n/**\n * Detect all supported languages in a project.\n *\n * @param projectRoot - Absolute path to the project root.\n * @param deps - Injectable filesystem dependencies.\n * @returns Detection result for every supported language.\n */\nexport function detectLanguages(\n projectRoot: string,\n deps: LanguageDetectionDeps = defaultLanguageDetectionDeps,\n): LanguageDetection {\n return {\n typescript: detectTypeScript(projectRoot, deps),\n python: detectPython(projectRoot, deps),\n };\n}\n","/**\n * Circular dependency validation step.\n *\n * Uses madge to detect circular imports in the codebase.\n *\n * @module validation/steps/circular\n */\n\nimport madge from \"madge\";\n\nimport { TSCONFIG_FILES } from \"../config/scope.js\";\nimport type { CircularDependencyResult, ScopeConfig, ValidationScope } from \"../types.js\";\n\n// =============================================================================\n// DEPENDENCY INJECTION INTERFACES\n// =============================================================================\n\n/**\n * Dependencies for circular dependency validation.\n *\n * Enables dependency injection for testing.\n */\nexport interface CircularDeps {\n madge: typeof madge;\n}\n\n/**\n * Default production dependencies.\n */\nexport const defaultCircularDeps: CircularDeps = {\n madge,\n};\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate circular dependencies using TypeScript-derived scope.\n *\n * @param scope - Validation scope\n * @param typescriptScope - Scope configuration from tsconfig\n * @param deps - Injectable dependencies\n * @returns Result with success status and any circular dependencies found\n *\n * @example\n * ```typescript\n * const result = await validateCircularDependencies(\"full\", scopeConfig);\n * if (!result.success) {\n * console.error(\"Found circular dependencies:\", result.circularDependencies);\n * }\n * ```\n */\nexport async function validateCircularDependencies(\n scope: ValidationScope,\n typescriptScope: ScopeConfig,\n deps: CircularDeps = defaultCircularDeps,\n): Promise<CircularDependencyResult> {\n try {\n // Use TypeScript-derived directories for perfect scope alignment\n const analyzeDirectories = typescriptScope.directories;\n\n if (analyzeDirectories.length === 0) {\n return { success: true };\n }\n\n // Use the appropriate TypeScript config based on scope\n const tsConfigFile = TSCONFIG_FILES[scope];\n\n // Convert tsconfig exclude patterns to madge excludeRegExp\n const excludeRegExps = typescriptScope.excludePatterns.map((pattern) => {\n // Remove trailing /**/* or /* for cleaner matching\n const cleanPattern = pattern.replace(/\\/\\*\\*?\\/\\*$/, \"\");\n // Escape regex special chars and create regex\n const escaped = cleanPattern.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(escaped);\n });\n\n const result = await deps.madge(analyzeDirectories, {\n fileExtensions: [\"ts\", \"tsx\"],\n tsConfig: tsConfigFile,\n excludeRegExp: excludeRegExps,\n });\n\n const circular = result.circular();\n\n if (circular.length === 0) {\n return { success: true };\n } else {\n return {\n success: false,\n error: `Found ${circular.length} circular dependency cycle(s)`,\n circularDependencies: circular,\n };\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { success: false, error: errorMessage };\n }\n}\n","/**\n * Circular dependency check command.\n *\n * Runs madge to detect circular dependencies.\n */\nimport { getTypeScriptScope } from \"../../validation/config/scope.js\";\nimport { detectTypeScript, discoverTool, formatSkipMessage } from \"../../validation/discovery/index.js\";\nimport { validateCircularDependencies } from \"../../validation/steps/circular.js\";\nimport type { CircularCommandOptions, ValidationCommandResult } from \"./types\";\n\nconst TYPESCRIPT_ABSENT_MESSAGE = \"⏭ Skipping Circular dependencies (TypeScript not detected in project)\";\n\n/**\n * Check for circular dependencies.\n *\n * Gates madge execution on TypeScript language detection: madge walks the\n * TypeScript import graph and has nothing to examine in non-TypeScript\n * projects.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function circularCommand(options: CircularCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, quiet } = options;\n const startTime = Date.now();\n\n // Gate 1: language detection. No TypeScript = skip cleanly.\n const tsDetection = detectTypeScript(cwd);\n if (!tsDetection.present) {\n return {\n exitCode: 0,\n output: quiet ? \"\" : TYPESCRIPT_ABSENT_MESSAGE,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Gate 2: tool discovery.\n const toolResult = await discoverTool(\"madge\", { projectRoot: cwd });\n if (!toolResult.found) {\n const skipMessage = formatSkipMessage(\"circular dependency check\", toolResult);\n return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };\n }\n\n // Get scope configuration from tsconfig (circular always uses full scope)\n const scopeConfig = getTypeScriptScope(\"full\");\n\n // Run circular dependency validation\n const result = await validateCircularDependencies(\"full\", scopeConfig);\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : `Circular dependencies: ✓ None found`;\n return { exitCode: 0, output, durationMs };\n } else {\n // Format circular dependency output\n let output = result.error ?? \"Circular dependencies found\";\n if (result.circularDependencies && result.circularDependencies.length > 0) {\n const cycles = result.circularDependencies\n .map((cycle) => ` ${cycle.join(\" → \")}`)\n .join(\"\\n\");\n output = `Circular dependencies found:\\n${cycles}`;\n }\n return { exitCode: 1, output, durationMs };\n }\n}\n","/**\n * Output formatting functions for validation commands.\n *\n * Pure functions that format validation results for CLI display.\n * These functions have no side effects and are fully testable.\n */\n\n/** Threshold in milliseconds for switching from ms to seconds display */\nexport const DURATION_THRESHOLD_MS = 1000;\n\n/** Symbols used in validation output */\nexport const VALIDATION_SYMBOLS = {\n SUCCESS: \"✓\",\n FAILURE: \"✗\",\n} as const;\n\n/**\n * Format a duration in milliseconds for display.\n *\n * @param ms - Duration in milliseconds\n * @returns Formatted string (e.g., \"500ms\" or \"1.5s\")\n */\nexport function formatDuration(ms: number): string {\n if (ms < DURATION_THRESHOLD_MS) {\n return `${ms}ms`;\n }\n const seconds = ms / 1000;\n return `${seconds.toFixed(1)}s`;\n}\n\n/** Options for formatting a validation step output */\nexport interface FormatStepOptions {\n /** Current step number (1-indexed) */\n stepNumber: number;\n /** Total number of steps */\n totalSteps: number;\n /** Name of the validation step */\n name: string;\n /** Result message (e.g., \"✓ No issues found\") */\n result: string;\n /** Duration in milliseconds */\n durationMs: number;\n}\n\n/**\n * Format a validation step result for display.\n *\n * @param options - Step formatting options\n * @returns Formatted string (e.g., \"[1/4] ESLint: ✓ No issues found (0.8s)\")\n */\nexport function formatStepOutput(options: FormatStepOptions): string {\n const { stepNumber, totalSteps, name, result, durationMs } = options;\n const duration = formatDuration(durationMs);\n return `[${stepNumber}/${totalSteps}] ${name}: ${result} (${duration})`;\n}\n\n/** Options for formatting the validation summary */\nexport interface FormatSummaryOptions {\n /** Whether all required validations passed */\n success: boolean;\n /** Total duration in milliseconds */\n totalDurationMs: number;\n}\n\n/**\n * Format the final validation summary.\n *\n * @param options - Summary formatting options\n * @returns Formatted string (e.g., \"✓ Validation passed (2.7s total)\")\n */\nexport function formatSummary(options: FormatSummaryOptions): string {\n const { success, totalDurationMs } = options;\n const symbol = success ? VALIDATION_SYMBOLS.SUCCESS : VALIDATION_SYMBOLS.FAILURE;\n const status = success ? \"passed\" : \"failed\";\n const duration = formatDuration(totalDurationMs);\n return `${symbol} Validation ${status} (${duration} total)`;\n}\n","/**\n * ESLint validation step.\n *\n * Validates code against ESLint rules with automatic TypeScript scope alignment.\n *\n * @module validation/steps/eslint\n */\n\nimport { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { ExecutionMode, ProcessRunner, ValidationContext } from \"../types.js\";\nimport { EXECUTION_MODES, VALIDATION_SCOPES } from \"../types.js\";\n\nimport { CACHE_PATHS } from \"./constants.js\";\n\n// =============================================================================\n// DEFAULT DEPENDENCIES\n// =============================================================================\n\n/**\n * Default production process runner for ESLint.\n */\nexport const defaultEslintProcessRunner: ProcessRunner = { spawn };\n\n// =============================================================================\n// PURE ARGUMENT BUILDER\n// =============================================================================\n\n/**\n * Default ESLint flat config file name, used when the caller does not supply\n * one. Callers should prefer passing the config file reported by language\n * detection.\n */\nexport const DEFAULT_ESLINT_CONFIG_FILE = \"eslint.config.ts\";\n\n/**\n * Build ESLint CLI arguments based on validation context.\n *\n * Pure function for testability - can be verified at Level 1.\n *\n * @param context - Context for building arguments\n * @returns Array of ESLint CLI arguments\n *\n * @example\n * ```typescript\n * const args = buildEslintArgs({\n * validatedFiles: [\"src/index.ts\"],\n * mode: \"write\",\n * cacheFile: \"dist/.eslintcache\",\n * configFile: \"eslint.config.ts\",\n * });\n * // Returns: [\"eslint\", \"--config\", \"eslint.config.ts\", \"--cache\", ...]\n * ```\n */\nexport function buildEslintArgs(context: {\n validatedFiles?: string[];\n mode?: ExecutionMode;\n cacheFile: string;\n configFile?: string;\n}): string[] {\n const { validatedFiles, mode, cacheFile, configFile = DEFAULT_ESLINT_CONFIG_FILE } = context;\n const fixArg = mode === EXECUTION_MODES.WRITE ? [\"--fix\"] : [];\n const cacheArgs = [\"--cache\", \"--cache-location\", cacheFile];\n\n if (validatedFiles && validatedFiles.length > 0) {\n return [\"eslint\", \"--config\", configFile, ...cacheArgs, ...fixArg, \"--\", ...validatedFiles];\n }\n return [\"eslint\", \".\", \"--config\", configFile, ...cacheArgs, ...fixArg];\n}\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate ESLint compliance using automatic TypeScript scope alignment.\n *\n * @param context - Validation context\n * @param runner - Injectable process runner\n * @returns Promise resolving to validation result\n *\n * @example\n * ```typescript\n * const result = await validateESLint(context);\n * if (!result.success) {\n * console.error(\"ESLint failed:\", result.error);\n * }\n * ```\n */\nexport async function validateESLint(\n context: ValidationContext,\n runner: ProcessRunner = defaultEslintProcessRunner,\n): Promise<{\n success: boolean;\n error?: string;\n}> {\n const { projectRoot, scope, validatedFiles, mode, eslintConfigFile } = context;\n\n return new Promise((resolve) => {\n if (!validatedFiles || validatedFiles.length === 0) {\n if (scope === VALIDATION_SCOPES.PRODUCTION) {\n process.env.ESLINT_PRODUCTION_ONLY = \"1\";\n } else {\n delete process.env.ESLINT_PRODUCTION_ONLY;\n }\n }\n\n const eslintArgs = buildEslintArgs({\n validatedFiles,\n mode,\n cacheFile: CACHE_PATHS.ESLINT,\n configFile: eslintConfigFile,\n });\n\n const localBin = join(projectRoot, \"node_modules\", \".bin\", \"eslint\");\n const binary = existsSync(localBin) ? localBin : \"npx\";\n const spawnArgs = binary === \"npx\" ? eslintArgs : eslintArgs.slice(1);\n const eslintProcess = runner.spawn(binary, spawnArgs, {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n\n eslintProcess.on(\"close\", (code) => {\n if (code === 0) {\n resolve({ success: true });\n } else {\n resolve({ success: false, error: `ESLint exited with code ${code}` });\n }\n });\n\n eslintProcess.on(\"error\", (error) => {\n resolve({ success: false, error: error.message });\n });\n });\n}\n\n// =============================================================================\n// ENVIRONMENT CHECK\n// =============================================================================\n\n/**\n * Check if a validation type is enabled via environment variable.\n *\n * @param envVarKey - Validation key (TYPESCRIPT, ESLINT, KNIP)\n * @param defaults - Default enabled states\n * @returns True if the validation is enabled\n */\nexport function validationEnabled(\n envVarKey: string,\n defaults: Record<string, boolean> = {},\n): boolean {\n const envVar = `${envVarKey}_VALIDATION_ENABLED`;\n const explicitlyDisabled = process.env[envVar] === \"0\";\n const explicitlyEnabled = process.env[envVar] === \"1\";\n\n const defaultValue = defaults[envVarKey] ?? true;\n if (defaultValue) {\n return !explicitlyDisabled;\n }\n return explicitlyEnabled;\n}\n","/**\n * Shared types for the validation module.\n *\n * These types define the contracts for validation steps and their dependencies,\n * enabling dependency injection for testability (per ADR-001).\n *\n * @module validation/types\n */\n\nimport type { ChildProcess, SpawnOptions } from \"node:child_process\";\n\n// =============================================================================\n// DEPENDENCY INJECTION INTERFACES\n// =============================================================================\n\n/**\n * Interface for subprocess execution.\n *\n * Enables dependency injection for testing - production code uses real spawn,\n * tests can provide controlled implementations.\n *\n * @example\n * ```typescript\n * // Production usage\n * const runner: ProcessRunner = { spawn };\n *\n * // Test usage with controlled implementation\n * const testRunner: ProcessRunner = {\n * spawn: (cmd, args, opts) => createMockProcess({ exitCode: 0 }),\n * };\n * ```\n */\nexport interface ProcessRunner {\n spawn(command: string, args: readonly string[], options?: SpawnOptions): ChildProcess;\n}\n\n// =============================================================================\n// VALIDATION SCOPE\n// =============================================================================\n\n/**\n * Validation scope constants.\n *\n * @example\n * ```typescript\n * import { VALIDATION_SCOPES } from \"./types.js\";\n * const scope = VALIDATION_SCOPES.FULL; // \"full\"\n * ```\n */\nexport const VALIDATION_SCOPES = {\n /** Validate entire codebase including tests and scripts */\n FULL: \"full\",\n /** Validate production files only */\n PRODUCTION: \"production\",\n} as const;\n\n/** Type for validation scope values */\nexport type ValidationScope = (typeof VALIDATION_SCOPES)[keyof typeof VALIDATION_SCOPES];\n\n/**\n * Configuration for validation scope.\n *\n * Derived from tsconfig.json settings to ensure alignment between\n * TypeScript and ESLint validation.\n */\nexport interface ScopeConfig {\n /** Directories to include in validation */\n directories: string[];\n /** File patterns to match (from tsconfig include) */\n filePatterns: string[];\n /** Patterns to exclude from validation */\n excludePatterns: string[];\n}\n\n// =============================================================================\n// EXECUTION MODE\n// =============================================================================\n\n/**\n * Execution mode constants.\n */\nexport const EXECUTION_MODES = {\n /** Read-only mode - report errors without fixing */\n READ: \"read\",\n /** Write mode - fix errors when possible (e.g., eslint --fix) */\n WRITE: \"write\",\n} as const;\n\n/** Type for execution mode values */\nexport type ExecutionMode = (typeof EXECUTION_MODES)[keyof typeof EXECUTION_MODES];\n\n// =============================================================================\n// VALIDATION CONTEXT\n// =============================================================================\n\n/**\n * Context object passed to validation steps.\n *\n * Contains all information needed to execute a validation step,\n * enabling pure functions that don't rely on global state.\n */\nexport interface ValidationContext {\n /** Root directory of the project being validated */\n projectRoot: string;\n /** Execution mode (read-only or write/fix) */\n mode?: ExecutionMode;\n /** Validation scope (full or production) */\n scope: ValidationScope;\n /** Scope configuration derived from tsconfig */\n scopeConfig: ScopeConfig;\n /** Which validations are enabled */\n enabledValidations: Partial<Record<string, boolean>>;\n /** Specific files to validate (if file-specific mode) */\n validatedFiles?: string[];\n /** Whether running in file-specific mode */\n isFileSpecificMode: boolean;\n /** ESLint flat config file name, determined by language detection */\n eslintConfigFile?: string;\n}\n\n// =============================================================================\n// VALIDATION RESULTS\n// =============================================================================\n\n/**\n * Result from a validation step.\n *\n * All validation steps return this structure to enable consistent\n * result handling and progress reporting.\n */\nexport interface ValidationStepResult {\n /** Whether the validation passed */\n success: boolean;\n /** Error message if validation failed */\n error?: string;\n /** Duration of the validation step in milliseconds */\n duration: number;\n /** Whether the step was skipped (e.g., tool not available) */\n skipped?: boolean;\n}\n\n/**\n * Result from circular dependency validation.\n *\n * Extends ValidationStepResult with circular dependency details.\n */\nexport interface CircularDependencyResult {\n /** Whether no circular dependencies were found */\n success: boolean;\n /** Error message if circular dependencies found */\n error?: string;\n /** The circular dependency cycles found */\n circularDependencies?: string[][];\n}\n\n// =============================================================================\n// VALIDATION STEP INTERFACE\n// =============================================================================\n\n/**\n * Definition of a validation step.\n *\n * Validation steps are pluggable units that can be enabled/disabled\n * and executed in sequence.\n */\nexport interface ValidationStep {\n /** Unique identifier for the step */\n id: string;\n /** Human-readable name for progress reporting */\n name: string;\n /** Description shown during execution */\n description: string;\n /** Function to determine if step should run */\n enabled: (context: ValidationContext) => boolean;\n /** Function to execute the validation */\n execute: (context: ValidationContext) => Promise<ValidationStepResult>;\n}\n","/**\n * Constants for validation steps.\n *\n * @module validation/steps/constants\n */\n\n/**\n * Cache file locations.\n */\nexport const CACHE_PATHS = {\n ESLINT: \"dist/.eslintcache\",\n TIMINGS: \"dist/.validation-timings.json\",\n} as const;\n","/**\n * Knip validation step.\n *\n * Detects unused exports, dependencies, and files using knip.\n *\n * @module validation/steps/knip\n */\n\nimport { spawn } from \"node:child_process\";\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { ProcessRunner, ScopeConfig } from \"../types.js\";\n\n// =============================================================================\n// DEFAULT DEPENDENCIES\n// =============================================================================\n\n/**\n * Default production process runner for Knip.\n */\nexport const defaultKnipProcessRunner: ProcessRunner = { spawn };\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate unused code using knip with TypeScript-derived scope.\n *\n * @param scope - Validation scope\n * @param typescriptScope - Scope configuration from tsconfig\n * @param runner - Injectable process runner\n * @returns Promise resolving to validation result\n *\n * @example\n * ```typescript\n * const result = await validateKnip(\"full\", scopeConfig);\n * if (!result.success) {\n * console.error(\"Knip found issues:\", result.error);\n * }\n * ```\n */\nexport async function validateKnip(\n typescriptScope: ScopeConfig,\n runner: ProcessRunner = defaultKnipProcessRunner,\n): Promise<{\n success: boolean;\n error?: string;\n}> {\n try {\n // Use TypeScript-derived directories for perfect scope alignment\n const analyzeDirectories = typescriptScope.directories;\n\n if (analyzeDirectories.length === 0) {\n return { success: true };\n }\n\n return new Promise((resolve) => {\n const localBin = join(process.cwd(), \"node_modules\", \".bin\", \"knip\");\n const binary = existsSync(localBin) ? localBin : \"npx\";\n const knipProcess = runner.spawn(binary, binary === \"npx\" ? [\"knip\"] : [], {\n cwd: process.cwd(),\n stdio: \"pipe\",\n });\n\n let knipOutput = \"\";\n let knipError = \"\";\n\n knipProcess.stdout?.on(\"data\", (data: Buffer) => {\n knipOutput += data.toString();\n });\n\n knipProcess.stderr?.on(\"data\", (data: Buffer) => {\n knipError += data.toString();\n });\n\n knipProcess.on(\"close\", (code) => {\n if (code === 0) {\n resolve({ success: true });\n } else {\n const errorOutput = knipOutput || knipError || \"Unused code detected\";\n resolve({\n success: false,\n error: errorOutput,\n });\n }\n });\n\n knipProcess.on(\"error\", (error) => {\n resolve({ success: false, error: error.message });\n });\n });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { success: false, error: errorMessage };\n }\n}\n","/**\n * Knip command for detecting unused code.\n *\n * Runs knip to find unused exports, dependencies, and files.\n * Disabled by default - enable with KNIP_VALIDATION_ENABLED=1.\n */\nimport { getTypeScriptScope } from \"../../validation/config/scope.js\";\nimport { discoverTool, formatSkipMessage } from \"../../validation/discovery/index.js\";\nimport { validationEnabled } from \"../../validation/steps/eslint.js\";\nimport { validateKnip } from \"../../validation/steps/knip.js\";\nimport type { KnipCommandOptions, ValidationCommandResult } from \"./types\";\n\n/**\n * Detect unused code with knip.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function knipCommand(options: KnipCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, quiet } = options;\n const startTime = Date.now();\n\n // Knip is disabled by default - check if explicitly enabled\n if (!validationEnabled(\"KNIP\", { KNIP: false })) {\n const output = quiet ? \"\" : \"Knip: skipped (disabled by default, set KNIP_VALIDATION_ENABLED=1 to enable)\";\n return { exitCode: 0, output, durationMs: Date.now() - startTime };\n }\n\n // Discover knip\n const toolResult = await discoverTool(\"knip\", { projectRoot: cwd });\n if (!toolResult.found) {\n const skipMessage = formatSkipMessage(\"unused code detection\", toolResult);\n return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };\n }\n\n // Get scope configuration from tsconfig (knip uses full scope)\n const scopeConfig = getTypeScriptScope(\"full\");\n\n // Run knip validation\n const result = await validateKnip(scopeConfig);\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : `Knip: ✓ No unused code found`;\n return { exitCode: 0, output, durationMs };\n } else {\n const output = result.error ?? \"Unused code found\";\n return { exitCode: 1, output, durationMs };\n }\n}\n","/**\n * ESLint validation command.\n *\n * Runs ESLint for code quality checks.\n */\nimport { getTypeScriptScope } from \"../../validation/config/scope.js\";\nimport { detectTypeScript, discoverTool, formatSkipMessage } from \"../../validation/discovery/index.js\";\nimport { validateESLint } from \"../../validation/steps/eslint.js\";\nimport type { ValidationContext } from \"../../validation/types.js\";\nimport type { LintCommandOptions, ValidationCommandResult } from \"./types\";\n\nconst TYPESCRIPT_ABSENT_MESSAGE = \"⏭ Skipping ESLint (TypeScript not detected in project)\";\nconst MISSING_CONFIG_MESSAGE =\n \"ESLint config not found: project has tsconfig.json but no eslint.config.{ts,js,mjs,cjs}\";\n\n/**\n * Run ESLint validation.\n *\n * Gates ESLint execution on TypeScript language detection. ESLint runs only\n * when `tsconfig.json` is present AND an ESLint flat config file exists. A\n * project with `tsconfig.json` but no ESLint config produces a non-zero exit\n * with a descriptive error; a project without `tsconfig.json` skips cleanly.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function lintCommand(options: LintCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, scope = \"full\", files, fix, quiet } = options;\n const startTime = Date.now();\n\n // Gate 1: language detection. No TypeScript = skip cleanly.\n const tsDetection = detectTypeScript(cwd);\n if (!tsDetection.present) {\n return {\n exitCode: 0,\n output: quiet ? \"\" : TYPESCRIPT_ABSENT_MESSAGE,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Gate 2: ESLint flat config must exist when TypeScript is present.\n if (tsDetection.eslintConfigFile === undefined) {\n return {\n exitCode: 1,\n output: MISSING_CONFIG_MESSAGE,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Gate 3: tool discovery — ensure ESLint itself is available somewhere.\n const toolResult = await discoverTool(\"eslint\", { projectRoot: cwd });\n if (!toolResult.found) {\n const skipMessage = formatSkipMessage(\"ESLint\", toolResult);\n return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };\n }\n\n // Get scope configuration from tsconfig\n const scopeConfig = getTypeScriptScope(scope);\n\n // Build validation context\n const context: ValidationContext = {\n projectRoot: cwd,\n scope,\n scopeConfig,\n mode: fix ? \"write\" : \"read\",\n enabledValidations: { ESLINT: true },\n validatedFiles: files,\n isFileSpecificMode: Boolean(files && files.length > 0),\n eslintConfigFile: tsDetection.eslintConfigFile,\n };\n\n // Run ESLint validation\n const result = await validateESLint(context);\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : `ESLint: ✓ No issues found`;\n return { exitCode: 0, output, durationMs };\n } else {\n const output = result.error ?? \"ESLint validation failed\";\n return { exitCode: 1, output, durationMs };\n }\n}\n","import { resolveConfig } from \"@/config/index.js\";\nimport { detectTypeScript } from \"@/validation/discovery/index.js\";\nimport { type LiteralConfig, literalConfigDescriptor } from \"@/validation/literal/config.js\";\nimport { type DetectionResult, type LiteralLocation, validateLiteralReuse } from \"@/validation/literal/index.js\";\nimport { validationEnabled } from \"@/validation/steps/eslint.js\";\n\nexport interface LiteralCommandOptions {\n readonly cwd: string;\n readonly files?: readonly string[];\n readonly json?: boolean;\n readonly quiet?: boolean;\n readonly config?: LiteralConfig;\n}\n\nexport interface ValidationCommandResult {\n readonly exitCode: number;\n readonly output: string;\n readonly durationMs: number;\n}\n\nconst EXIT_OK = 0;\nconst EXIT_FINDINGS = 1;\nconst EXIT_CONFIG_ERROR = 2;\nconst TYPESCRIPT_ABSENT_MESSAGE = \"⏭ Skipping Literal (TypeScript not detected in project)\";\nconst DISABLED_MESSAGE = \"⏭ Skipping Literal (LITERAL_VALIDATION_ENABLED=0)\";\n\nexport async function literalCommand(\n options: LiteralCommandOptions,\n): Promise<ValidationCommandResult> {\n const start = Date.now();\n\n const tsDetection = detectTypeScript(options.cwd);\n if (!tsDetection.present) {\n return {\n exitCode: EXIT_OK,\n output: options.quiet ? \"\" : TYPESCRIPT_ABSENT_MESSAGE,\n durationMs: Date.now() - start,\n };\n }\n\n if (!validationEnabled(\"LITERAL\")) {\n return {\n exitCode: EXIT_OK,\n output: options.quiet ? \"\" : DISABLED_MESSAGE,\n durationMs: Date.now() - start,\n };\n }\n\n let resolvedConfig: LiteralConfig;\n if (options.config !== undefined) {\n resolvedConfig = options.config;\n } else {\n const loaded = await resolveConfig(options.cwd, [literalConfigDescriptor]);\n if (!loaded.ok) {\n return {\n exitCode: EXIT_CONFIG_ERROR,\n output: `Literal: ✗ config error — ${loaded.error}`,\n durationMs: Date.now() - start,\n };\n }\n resolvedConfig = loaded.value[literalConfigDescriptor.section] as LiteralConfig;\n }\n\n const result = await validateLiteralReuse({\n projectRoot: options.cwd,\n files: options.files,\n config: resolvedConfig,\n });\n\n const totalFindings = result.findings.srcReuse.length + result.findings.testDupe.length;\n const exitCode = totalFindings === 0 ? EXIT_OK : EXIT_FINDINGS;\n\n const output = options.json\n ? JSON.stringify(result.findings)\n : options.quiet\n ? \"\"\n : totalFindings === 0\n ? \"Literal: ✓ No findings\"\n : `Literal: ✗ ${totalFindings} finding${totalFindings === 1 ? \"\" : \"s\"}\\n${formatText(result.findings)}`;\n\n return { exitCode, output, durationMs: Date.now() - start };\n}\n\nfunction formatText(findings: DetectionResult): string {\n const lines: string[] = [];\n for (const f of findings.srcReuse) {\n lines.push(\n `[reuse] ${formatLoc(f.test)}: ${f.kind} literal \"${f.value}\" also in ${\n f.src\n .map(formatLoc)\n .join(\", \")\n } — import from source`,\n );\n }\n for (const f of findings.testDupe) {\n lines.push(\n `[dupe] ${formatLoc(f.test)}: ${f.kind} literal \"${f.value}\" also in ${\n f.otherTests\n .map(formatLoc)\n .join(\", \")\n } — extract to shared test support`,\n );\n }\n return lines.join(\"\\n\");\n}\n\nfunction formatLoc(loc: LiteralLocation): string {\n return `${loc.file}:${loc.line}`;\n}\n","/**\n * Markdown validation step.\n *\n * Validates markdown files using markdownlint-cli2's programmatic API.\n * Configuration is built in code and passed via optionsOverride --\n * no config files are written to validated directories.\n *\n * @module validation/steps/markdown\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\n\nimport { EXCLUDE_FILENAME } from \"../../spec/apply/exclude/constants.js\";\nimport { readExcludedNodes } from \"../../spec/apply/exclude/exclude-file.js\";\n\n// @ts-expect-error markdownlint-cli2 has no TypeScript type declarations\nimport { main as markdownlintMain } from \"markdownlint-cli2\";\nimport relativeLinksRule from \"markdownlint-rule-relative-links\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/** Default directories to validate when no --files are specified. */\nconst DEFAULT_DIRECTORY_NAMES = [\"spx\", \"docs\"] as const;\n\n/** Built-in markdownlint rules enabled for validation (MD024 excluded — configured per directory). */\nconst ENABLED_RULES = {\n MD001: true,\n MD003: true,\n MD009: true,\n MD010: true,\n MD025: true,\n MD047: true,\n} as const;\n\n/** Directories where MD024 is disabled entirely (generated/repetitive headings are normal). */\nconst MD024_DISABLED_DIRECTORIES = [\"docs\"] as const;\n\n/**\n * Pattern for parsing markdownlint-cli2 default formatter output.\n * Format: filename:line[:column] [severity] ruleName/ruleAlias description [detail] [context]\n */\nconst ERROR_LINE_PATTERN = /^(.+?):(\\d+)(?::\\d+)?\\s+(.+)$/;\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\n/** A structured error from markdown validation. */\nexport interface MarkdownError {\n /** Absolute path to the file containing the error. */\n file: string;\n /** Line number where the error occurs (1-based). */\n line: number;\n /** Description of the error including rule name and detail. */\n detail: string;\n}\n\n/** Result of markdown validation. */\nexport interface MarkdownValidationResult {\n /** Whether all files passed validation. */\n success: boolean;\n /** Structured errors found during validation. */\n errors: MarkdownError[];\n}\n\n/** A markdownlint custom rule object. */\ninterface MarkdownlintRule {\n names: string[];\n description: string;\n tags: string[];\n}\n\n/** Options for the validateMarkdown function. */\nexport interface ValidateMarkdownOptions {\n /** Directories to validate. */\n directories: string[];\n /** Project root for resolving project-absolute links. */\n projectRoot?: string;\n}\n\n// =============================================================================\n// CONFIGURATION\n// =============================================================================\n\n/**\n * Build the markdownlint configuration object.\n *\n * MD024 (no duplicate headings) is configured per directory:\n * - `spx/` and other spec directories: `siblings_only` — allows same heading\n * under different parents, flags true sibling duplicates\n * - `docs/`: disabled — generated/repetitive docs commonly reuse headings\n *\n * @param directoryName - Basename of the directory being validated (e.g. \"spx\", \"docs\")\n * @returns Configuration object for markdownlint-cli2's optionsOverride\n */\nexport function buildMarkdownlintConfig(directoryName: string): {\n default: boolean;\n MD001: boolean;\n MD003: boolean;\n MD009: boolean;\n MD010: boolean;\n MD024: boolean | { siblings_only: boolean };\n MD025: boolean;\n MD047: boolean;\n customRules: MarkdownlintRule[];\n} {\n const md024Disabled = MD024_DISABLED_DIRECTORIES.includes(\n directoryName as (typeof MD024_DISABLED_DIRECTORIES)[number],\n );\n\n return {\n default: false,\n ...ENABLED_RULES,\n MD024: md024Disabled ? false : { siblings_only: true },\n customRules: [relativeLinksRule],\n };\n}\n\n// =============================================================================\n// DEFAULT DIRECTORIES\n// =============================================================================\n\n/**\n * Get the default directories to validate.\n *\n * Returns absolute paths for spx/ and docs/ directories that exist\n * within the given project root. This is a pure function for testability.\n *\n * @param projectRoot - Absolute path to the project root\n * @returns Array of absolute paths to existing default directories\n */\nexport function getDefaultDirectories(projectRoot: string): string[] {\n return DEFAULT_DIRECTORY_NAMES\n .map((name) => join(projectRoot, name))\n .filter((dir) => existsSync(dir));\n}\n\n// =============================================================================\n// EXCLUDE SUPPORT\n// =============================================================================\n\n/**\n * Read node paths from spx/EXCLUDE and return them as ignore globs.\n *\n * Declared-state nodes have [test] links pointing to files that do not\n * exist yet. Listing them in spx/EXCLUDE tells markdown validation to\n * skip those directories so broken [test] links are not flagged.\n *\n * @param spxDir - Absolute path to the spx/ directory being validated\n * @returns Array of glob patterns to ignore (relative to spxDir)\n */\nexport function getExcludeGlobs(spxDir: string): string[] {\n const excludePath = join(spxDir, EXCLUDE_FILENAME);\n if (!existsSync(excludePath)) {\n return [];\n }\n const content = readFileSync(excludePath, \"utf-8\");\n const nodes = readExcludedNodes(content);\n return nodes.map((node) => `${node}/**`);\n}\n\n// =============================================================================\n// ERROR PARSING\n// =============================================================================\n\n/**\n * Pattern matching data URIs (data:image/..., data:text/..., etc.).\n * markdownlint-rule-relative-links does not handle data URIs natively\n * and reports them as broken relative links. Filter them out.\n */\nconst DATA_URI_PATTERN = /\\bdata:/;\n\n/**\n * Parse a line of markdownlint-cli2 default formatter output into a structured error.\n *\n * Filters out false positives from data URIs.\n *\n * @param line - A single line of error output\n * @returns Parsed MarkdownError, or null if the line is not a real error\n */\nfunction parseErrorLine(line: string): MarkdownError | null {\n if (DATA_URI_PATTERN.test(line)) {\n return null;\n }\n const match = ERROR_LINE_PATTERN.exec(line);\n if (!match) {\n return null;\n }\n const [, file, lineStr, detail] = match;\n return {\n file,\n line: parseInt(lineStr, 10),\n detail,\n };\n}\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate markdown files in the specified directories.\n *\n * Uses markdownlint-cli2's programmatic API with in-code configuration.\n * No config files are written to validated directories.\n *\n * @param options - Validation options including directories and project root\n * @returns Validation result with success status and structured errors\n *\n * @example\n * ```typescript\n * const result = await validateMarkdown({\n * directories: [\"/path/to/spx\", \"/path/to/docs\"],\n * projectRoot: \"/path/to/project\",\n * });\n * if (!result.success) {\n * for (const error of result.errors) {\n * console.error(`${error.file}:${error.line} ${error.detail}`);\n * }\n * }\n * ```\n */\nexport async function validateMarkdown(\n options: ValidateMarkdownOptions,\n): Promise<MarkdownValidationResult> {\n const { directories, projectRoot } = options;\n const errors: MarkdownError[] = [];\n\n for (const directory of directories) {\n const dirName = basename(directory);\n const config = buildMarkdownlintConfig(dirName);\n const excludeGlobs = getExcludeGlobs(directory);\n const dirErrors = await validateDirectory(directory, config, projectRoot, excludeGlobs);\n errors.push(...dirErrors);\n }\n\n return {\n success: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Validate a single directory using markdownlint-cli2's programmatic API.\n *\n * @param directory - Absolute path to the directory to validate\n * @param config - Markdownlint configuration object\n * @param projectRoot - Optional project root for resolving project-absolute links\n * @returns Array of structured errors found in the directory\n */\nasync function validateDirectory(\n directory: string,\n config: ReturnType<typeof buildMarkdownlintConfig>,\n projectRoot?: string,\n ignoreGlobs: string[] = [],\n): Promise<MarkdownError[]> {\n const errors: MarkdownError[] = [];\n\n const { customRules, ...markdownlintConfig } = config;\n\n const optionsOverride: Record<string, unknown> = {\n config: {\n ...markdownlintConfig,\n \"relative-links\": projectRoot ? { root_path: projectRoot } : true,\n },\n customRules,\n noProgress: true,\n noBanner: true,\n ...(ignoreGlobs.length > 0 ? { ignores: ignoreGlobs } : {}),\n };\n\n await markdownlintMain({\n directory,\n argv: [\"**/*.md\"],\n optionsOverride,\n noImport: true,\n logMessage: () => {},\n logError: (message: string) => {\n const parsed = parseErrorLine(message);\n if (parsed) {\n errors.push({\n ...parsed,\n file: join(directory, parsed.file),\n });\n }\n },\n });\n\n return errors;\n}\n","/**\n * Markdown validation command.\n *\n * Runs markdownlint-cli2 for markdown link integrity and structural quality.\n * Unlike other validation commands, this does not use discoverTool() --\n * markdownlint-cli2 is a production dependency, always available.\n */\n\nimport { getDefaultDirectories, validateMarkdown } from \"../../validation/steps/markdown.js\";\nimport type { MarkdownCommandOptions, ValidationCommandResult } from \"./types\";\n\n/**\n * Run markdown validation.\n *\n * Validates markdown files in the specified directories (or defaults to\n * spx/ and docs/). Returns structured results with exit code and output.\n *\n * @param options - Command options including cwd and optional file scoping\n * @returns Command result with exit code and output\n *\n * @example\n * ```typescript\n * // Validate default directories\n * const result = await markdownCommand({ cwd: process.cwd() });\n *\n * // Validate specific directories\n * const result = await markdownCommand({\n * cwd: process.cwd(),\n * files: [\"/path/to/spx\"],\n * });\n * ```\n */\nconst MARKDOWN_EXTENSIONS = new Set([\".md\", \".markdown\"]);\n\nfunction isMarkdownOrDirectory(path: string): boolean {\n const lastDot = path.lastIndexOf(\".\");\n if (lastDot < 0) return true;\n const ext = path.slice(lastDot).toLowerCase();\n return MARKDOWN_EXTENSIONS.has(ext);\n}\n\nexport async function markdownCommand(options: MarkdownCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, files, quiet } = options;\n const startTime = Date.now();\n\n const markdownScopedFiles = files?.filter(isMarkdownOrDirectory);\n\n const directories = markdownScopedFiles && markdownScopedFiles.length > 0\n ? markdownScopedFiles\n : files && files.length > 0\n ? []\n : getDefaultDirectories(cwd);\n\n if (directories.length === 0) {\n const reason = files && files.length > 0\n ? \"no markdown files in --files scope\"\n : \"no spx/ or docs/ directories found\";\n const output = quiet ? \"\" : `Markdown: skipped (${reason})`;\n return { exitCode: 0, output, durationMs: Date.now() - startTime };\n }\n\n // Run markdown validation\n const result = await validateMarkdown({\n directories,\n projectRoot: cwd,\n });\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : \"Markdown: No issues found\";\n return { exitCode: 0, output, durationMs };\n } else {\n const errorLines = result.errors.map(\n (error) => ` ${error.file}:${error.line} ${error.detail}`,\n );\n const output = [`Markdown: ${result.errors.length} error(s) found`, ...errorLines].join(\"\\n\");\n return { exitCode: 1, output, durationMs };\n }\n}\n","/**\n * TypeScript validation step.\n *\n * Validates TypeScript code using the tsc compiler.\n *\n * @module validation/steps/typescript\n */\n\nimport { spawn } from \"node:child_process\";\nimport { existsSync, mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { mkdtemp } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\n\nimport { TSCONFIG_FILES } from \"../config/scope.js\";\nimport type { ProcessRunner, ScopeConfig, ValidationScope } from \"../types.js\";\nimport { VALIDATION_SCOPES } from \"../types.js\";\n\n// =============================================================================\n// DEFAULT DEPENDENCIES\n// =============================================================================\n\n/**\n * Default production process runner for TypeScript.\n */\nexport const defaultTypeScriptProcessRunner: ProcessRunner = { spawn };\n\n/**\n * Dependencies for file-specific TypeScript validation.\n */\nexport interface TypeScriptDeps {\n mkdtemp: typeof mkdtemp;\n writeFileSync: typeof writeFileSync;\n rmSync: typeof rmSync;\n existsSync: typeof existsSync;\n mkdirSync: typeof mkdirSync;\n}\n\n/**\n * Default production dependencies.\n */\nexport const defaultTypeScriptDeps: TypeScriptDeps = {\n mkdtemp,\n writeFileSync,\n rmSync,\n existsSync,\n mkdirSync,\n};\n\n// =============================================================================\n// PURE ARGUMENT BUILDER\n// =============================================================================\n\n/**\n * Build TypeScript CLI arguments based on validation scope.\n *\n * Pure function for testability - can be verified at Level 1.\n *\n * @param context - Context for building arguments\n * @returns Array of tsc CLI arguments\n *\n * @example\n * ```typescript\n * const args = buildTypeScriptArgs({ scope: \"full\", configFile: \"tsconfig.json\" });\n * // Returns: [\"tsc\", \"--noEmit\"]\n * ```\n */\nexport function buildTypeScriptArgs(context: { scope: ValidationScope; configFile: string }): string[] {\n const { scope, configFile } = context;\n return scope === VALIDATION_SCOPES.FULL ? [\"tsc\", \"--noEmit\"] : [\"tsc\", \"--project\", configFile];\n}\n\n// =============================================================================\n// FILE-SPECIFIC VALIDATION SUPPORT\n// =============================================================================\n\n/**\n * Create a temporary TypeScript configuration file for file-specific validation.\n *\n * @param scope - Validation scope\n * @param files - Files to validate\n * @param deps - Injectable dependencies\n * @returns Config path and cleanup function\n */\nexport async function createFileSpecificTsconfig(\n scope: ValidationScope,\n files: string[],\n deps: TypeScriptDeps = defaultTypeScriptDeps,\n): Promise<{ configPath: string; tempDir: string; cleanup: () => void }> {\n // Create temporary directory\n const tempDir = await deps.mkdtemp(join(tmpdir(), \"validate-ts-\"));\n const configPath = join(tempDir, \"tsconfig.json\");\n\n // Get base config file\n const baseConfigFile = TSCONFIG_FILES[scope];\n\n // Ensure all file paths are absolute\n const projectRoot = process.cwd();\n const absoluteFiles = files.map((file) => (isAbsolute(file) ? file : join(projectRoot, file)));\n\n // Create temporary tsconfig that extends the base config\n const tempConfig = {\n extends: join(projectRoot, baseConfigFile),\n files: absoluteFiles,\n include: [],\n exclude: [],\n compilerOptions: {\n noEmit: true,\n typeRoots: [join(projectRoot, \"node_modules\", \"@types\")],\n types: [\"node\"],\n },\n };\n\n // Write temporary config\n deps.writeFileSync(configPath, JSON.stringify(tempConfig, null, 2));\n\n // Return config path and cleanup function\n const cleanup = () => {\n try {\n deps.rmSync(tempDir, { recursive: true, force: true });\n } catch {\n // Cleanup error - don't fail validation\n }\n };\n\n return { configPath, tempDir, cleanup };\n}\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate TypeScript using authoritative configuration.\n *\n * @param scope - Validation scope\n * @param typescriptScope - Scope configuration from tsconfig\n * @param files - Optional specific files to validate\n * @param runner - Injectable process runner\n * @param deps - Injectable TypeScript dependencies\n * @returns Promise resolving to validation result\n *\n * @example\n * ```typescript\n * const result = await validateTypeScript(\"full\", scopeConfig);\n * if (!result.success) {\n * console.error(\"TypeScript failed:\", result.error);\n * }\n * ```\n */\nexport async function validateTypeScript(\n scope: ValidationScope,\n typescriptScope: ScopeConfig,\n files?: string[],\n runner: ProcessRunner = defaultTypeScriptProcessRunner,\n deps: TypeScriptDeps = defaultTypeScriptDeps,\n): Promise<{\n success: boolean;\n error?: string;\n skipped?: boolean;\n}> {\n const configFile = TSCONFIG_FILES[scope];\n\n // Determine tool and arguments based on whether specific files are provided\n let tool: string;\n let tscArgs: string[];\n\n if (files && files.length > 0) {\n // File-specific validation using custom temporary tsconfig\n const { configPath, cleanup } = await createFileSpecificTsconfig(scope, files, deps);\n\n try {\n return await new Promise((resolve) => {\n const tscBin = join(process.cwd(), \"node_modules\", \".bin\", \"tsc\");\n const tscBinary = existsSync(tscBin) ? tscBin : \"npx\";\n const tscArgs = tscBinary === \"npx\" ? [\"tsc\", \"--project\", configPath] : [\"--project\", configPath];\n const tscProcess = runner.spawn(tscBinary, tscArgs, {\n cwd: process.cwd(),\n stdio: \"inherit\",\n });\n\n tscProcess.on(\"close\", (code) => {\n cleanup();\n if (code === 0) {\n resolve({ success: true, skipped: false });\n } else {\n resolve({ success: false, error: `TypeScript exited with code ${code}` });\n }\n });\n\n tscProcess.on(\"error\", (error) => {\n cleanup();\n resolve({ success: false, error: error.message });\n });\n });\n } catch (error) {\n cleanup();\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { success: false, error: `Failed to create temporary config: ${errorMessage}` };\n }\n } else {\n // Full validation using tsc\n const tscBin = join(process.cwd(), \"node_modules\", \".bin\", \"tsc\");\n tool = existsSync(tscBin) ? tscBin : \"npx\";\n const rawArgs = buildTypeScriptArgs({ scope, configFile });\n tscArgs = tool === \"npx\" ? rawArgs : rawArgs.slice(1);\n }\n\n return new Promise((resolve) => {\n const tscProcess = runner.spawn(tool, tscArgs, {\n cwd: process.cwd(),\n stdio: \"inherit\",\n });\n\n tscProcess.on(\"close\", (code) => {\n if (code === 0) {\n resolve({ success: true, skipped: false });\n } else {\n resolve({ success: false, error: `TypeScript exited with code ${code}` });\n }\n });\n\n tscProcess.on(\"error\", (error) => {\n resolve({ success: false, error: error.message });\n });\n });\n}\n","/**\n * TypeScript validation command.\n *\n * Runs TypeScript type checking using tsc.\n */\nimport { getTypeScriptScope } from \"../../validation/config/scope.js\";\nimport { detectTypeScript, discoverTool, formatSkipMessage } from \"../../validation/discovery/index.js\";\nimport { validateTypeScript } from \"../../validation/steps/typescript.js\";\nimport type { TypeScriptCommandOptions, ValidationCommandResult } from \"./types\";\n\nconst TYPESCRIPT_ABSENT_MESSAGE = \"⏭ Skipping TypeScript (TypeScript not detected in project)\";\n\n/**\n * Run TypeScript type checking.\n *\n * Gates tsc execution on language detection: without a `tsconfig.json` in the\n * project root there is nothing to type-check, and invoking tsc regardless\n * causes it to walk up and compile an ancestor project instead.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function typescriptCommand(options: TypeScriptCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, scope = \"full\", files, quiet } = options;\n const startTime = Date.now();\n\n // Gate 1: language detection. No TypeScript = skip cleanly.\n const tsDetection = detectTypeScript(cwd);\n if (!tsDetection.present) {\n return {\n exitCode: 0,\n output: quiet ? \"\" : TYPESCRIPT_ABSENT_MESSAGE,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Gate 2: tool discovery — ensure tsc itself is available somewhere.\n const toolResult = await discoverTool(\"typescript\", { projectRoot: cwd });\n if (!toolResult.found) {\n const skipMessage = formatSkipMessage(\"TypeScript\", toolResult);\n return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };\n }\n\n // Get scope configuration from tsconfig\n const scopeConfig = getTypeScriptScope(scope);\n\n // Run TypeScript validation\n const result = await validateTypeScript(scope, scopeConfig, files);\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : `TypeScript: ✓ No type errors`;\n return { exitCode: 0, output, durationMs };\n } else {\n const output = result.error ?? \"TypeScript validation failed\";\n return { exitCode: 1, output, durationMs };\n }\n}\n","/**\n * Run all validations command.\n *\n * Executes all validation steps in sequence:\n * 1. Circular dependencies (fastest)\n * 2. Knip (optional)\n * 3. ESLint\n * 4. TypeScript\n * 5. Markdown\n * 6. Literal reuse\n */\nimport { circularCommand } from \"./circular\";\nimport { formatDuration, formatSummary } from \"./format\";\nimport { knipCommand } from \"./knip\";\nimport { lintCommand } from \"./lint\";\nimport { literalCommand } from \"./literal\";\nimport { markdownCommand } from \"./markdown\";\nimport type { AllCommandOptions, ValidationCommandResult } from \"./types\";\nimport { typescriptCommand } from \"./typescript\";\n\n/** Total number of validation steps */\nconst TOTAL_STEPS = 6;\n\n/**\n * Format step output with step number and timing.\n *\n * @param stepNumber - Current step number (1-indexed)\n * @param result - Validation result\n * @param quiet - Whether to suppress output\n * @returns Formatted output string\n */\nfunction formatStepWithTiming(\n stepNumber: number,\n result: ValidationCommandResult,\n quiet: boolean,\n): string {\n if (quiet || !result.output) return \"\";\n\n const timing = result.durationMs === undefined ? \"\" : ` (${formatDuration(result.durationMs)})`;\n return `[${stepNumber}/${TOTAL_STEPS}] ${result.output}${timing}`;\n}\n\n/**\n * Run all validation steps.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function allCommand(options: AllCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, scope, files, fix, quiet = false, json } = options;\n const startTime = Date.now();\n const outputs: string[] = [];\n let hasFailure = false;\n\n // 1. Circular dependencies\n const circularResult = await circularCommand({ cwd, quiet, json });\n const circularOutput = formatStepWithTiming(1, circularResult, quiet);\n if (circularOutput) outputs.push(circularOutput);\n if (circularResult.exitCode !== 0) hasFailure = true;\n\n // 2. Knip (optional - skip on failure, it's informational)\n const knipResult = await knipCommand({ cwd, quiet, json });\n const knipOutput = formatStepWithTiming(2, knipResult, quiet);\n if (knipOutput) outputs.push(knipOutput);\n // Don't fail on knip - it's optional\n\n // 3. ESLint\n const lintResult = await lintCommand({ cwd, scope, files, fix, quiet, json });\n const lintOutput = formatStepWithTiming(3, lintResult, quiet);\n if (lintOutput) outputs.push(lintOutput);\n if (lintResult.exitCode !== 0) hasFailure = true;\n\n // 4. TypeScript\n const tsResult = await typescriptCommand({ cwd, scope, files, quiet, json });\n const tsOutput = formatStepWithTiming(4, tsResult, quiet);\n if (tsOutput) outputs.push(tsOutput);\n if (tsResult.exitCode !== 0) hasFailure = true;\n\n // 5. Markdown\n const markdownResult = await markdownCommand({ cwd, files, quiet });\n const markdownOutput = formatStepWithTiming(5, markdownResult, quiet);\n if (markdownOutput) outputs.push(markdownOutput);\n if (markdownResult.exitCode !== 0) hasFailure = true;\n\n // 6. Literal reuse\n const literalResult = await literalCommand({ cwd, files, quiet, json });\n const literalOutput = formatStepWithTiming(6, literalResult, quiet);\n if (literalOutput) outputs.push(literalOutput);\n if (literalResult.exitCode !== 0) hasFailure = true;\n\n // Calculate total duration\n const totalDurationMs = Date.now() - startTime;\n\n // Add summary line\n if (!quiet) {\n const summary = formatSummary({ success: !hasFailure, totalDurationMs });\n outputs.push(\"\", summary); // Empty line before summary\n }\n\n return {\n exitCode: hasFailure ? 1 : 0,\n output: outputs.join(\"\\n\"),\n durationMs: totalDurationMs,\n };\n}\n","export const MAX_CLI_ARGUMENT_DISPLAY_LENGTH = 120;\nexport const ELLIPSIS_TOKEN = \"...\";\n\nexport const SENTINEL_UNDEFINED = \"<undefined>\";\nexport const SENTINEL_NULL = \"<null>\";\nexport const SENTINEL_EMPTY = \"<empty>\";\n\nexport const CONTROL_CHAR_UPPER_BOUND = 0x1f;\nexport const DEL_CHAR_CODE = 0x7f;\nexport const FIRST_PRINTABLE_CHAR_CODE = 0x20;\n\nconst HEX_RADIX = 16;\nconst HEX_PAD = 2;\n\nexport function nonStringSentinel(type: string): string {\n return `<non-string:${type}>`;\n}\n\nexport function sanitizeCliArgument(input: unknown): string {\n if (input === undefined) return SENTINEL_UNDEFINED;\n if (input === null) return SENTINEL_NULL;\n if (typeof input !== \"string\") return nonStringSentinel(typeof input);\n if (input.length === 0) return SENTINEL_EMPTY;\n\n const escaped = escapeControlCharacters(input);\n return truncate(escaped);\n}\n\nfunction escapeControlCharacters(value: string): string {\n let out = \"\";\n for (const char of value) {\n const code = char.codePointAt(0);\n if (code === undefined) continue;\n if (code <= CONTROL_CHAR_UPPER_BOUND || code === DEL_CHAR_CODE) {\n out += `\\\\x${code.toString(HEX_RADIX).padStart(HEX_PAD, \"0\")}`;\n } else {\n out += char;\n }\n }\n return out;\n}\n\nfunction truncate(value: string): string {\n if (value.length <= MAX_CLI_ARGUMENT_DISPLAY_LENGTH) return value;\n return value.slice(0, MAX_CLI_ARGUMENT_DISPLAY_LENGTH - ELLIPSIS_TOKEN.length) + ELLIPSIS_TOKEN;\n}\n","/**\n * Validation domain - Run code validation tools\n *\n * Provides CLI commands for running validation tools (TypeScript, ESLint, etc.)\n * as a globally-installed tool across TypeScript projects.\n */\nimport type { Command } from \"commander\";\n\nimport { allowlistExisting } from \"@/validation/literal/allowlist-existing.js\";\nimport {\n allCommand,\n circularCommand,\n knipCommand,\n lintCommand,\n literalCommand,\n markdownCommand,\n typescriptCommand,\n} from \"../../commands/validation\";\nimport { sanitizeCliArgument } from \"../../lib/sanitize-cli-argument\";\nimport type { Domain } from \"../types\";\n\n/** Validation scope options */\ntype ValidationScope = \"full\" | \"production\";\n\ninterface ValidationDomainCommandDefinition {\n readonly commandName: string;\n readonly alias: string;\n readonly description: string;\n}\n\ninterface ValidationSubcommandDefinition {\n readonly commandName: string;\n readonly alias?: string;\n readonly description: string;\n}\n\ninterface ValidationCliDefinition {\n readonly domain: ValidationDomainCommandDefinition;\n readonly subcommands: {\n readonly typescript: ValidationSubcommandDefinition;\n readonly lint: ValidationSubcommandDefinition;\n readonly circular: ValidationSubcommandDefinition;\n readonly knip: ValidationSubcommandDefinition;\n readonly literal: ValidationSubcommandDefinition;\n readonly markdown: ValidationSubcommandDefinition;\n readonly all: ValidationSubcommandDefinition;\n };\n readonly commanderHelpOperands: {\n readonly subcommand: string;\n readonly longFlag: string;\n readonly shortFlag: string;\n };\n readonly diagnostics: {\n readonly unknownSubcommand: {\n readonly messageLabel: string;\n readonly exitCode: number;\n };\n };\n}\n\nexport const validationCliDefinition: ValidationCliDefinition = {\n domain: {\n commandName: \"validation\",\n alias: \"v\",\n description: \"Run code validation tools\",\n },\n subcommands: {\n typescript: {\n commandName: \"typescript\",\n alias: \"ts\",\n description: \"Run TypeScript type checking\",\n },\n lint: {\n commandName: \"lint\",\n description: \"Run ESLint\",\n },\n circular: {\n commandName: \"circular\",\n description: \"Check for circular dependencies\",\n },\n knip: {\n commandName: \"knip\",\n description: \"Detect unused code\",\n },\n literal: {\n commandName: \"literal\",\n description: \"Detect cross-file literal reuse between source and tests\",\n },\n markdown: {\n commandName: \"markdown\",\n alias: \"md\",\n description: \"Validate markdown link integrity and structure\",\n },\n all: {\n commandName: \"all\",\n description: \"Run all validations\",\n },\n },\n commanderHelpOperands: {\n subcommand: \"help\",\n longFlag: \"--help\",\n shortFlag: \"-h\",\n },\n diagnostics: {\n unknownSubcommand: {\n messageLabel: \"unknown subcommand\",\n exitCode: 1,\n },\n },\n} as const;\n\nconst validationSubcommandOperands = Object.values(validationCliDefinition.subcommands).flatMap(\n (subcommand) => {\n const operands = [subcommand.commandName];\n if (subcommand.alias !== undefined) operands.push(subcommand.alias);\n return operands;\n },\n);\n\nexport const validationKnownOperands: ReadonlySet<string> = new Set([\n ...validationSubcommandOperands,\n ...Object.values(validationCliDefinition.commanderHelpOperands),\n]);\nexport const validationOptionPrefix = validationCliDefinition.commanderHelpOperands.longFlag.slice(0, 1);\n\n/** Common options for all validation commands */\ninterface CommonOptions {\n scope?: ValidationScope;\n files?: string[];\n quiet?: boolean;\n json?: boolean;\n}\n\n/** Options for lint command */\ninterface LintOptions extends CommonOptions {\n fix?: boolean;\n}\n\n/**\n * Add common options to a command\n */\nfunction addCommonOptions(cmd: Command): Command {\n return cmd\n .option(\"--scope <scope>\", \"Validation scope (full|production)\", \"full\")\n .option(\"--files <paths...>\", \"Specific files/directories to validate\")\n .option(\"--quiet\", \"Suppress progress output\")\n .option(\"--json\", \"Output results as JSON\");\n}\n\nfunction addValidationSubcommand(\n validationCmd: Command,\n definition: ValidationSubcommandDefinition,\n): Command {\n let subcommand = validationCmd\n .command(definition.commandName)\n .description(definition.description);\n\n if (definition.alias !== undefined) {\n subcommand = subcommand.alias(definition.alias);\n }\n\n return subcommand;\n}\n\n/**\n * Register validation domain commands\n */\nfunction registerValidationCommands(validationCmd: Command): void {\n const { subcommands } = validationCliDefinition;\n\n // typescript command\n const tsCmd = addValidationSubcommand(validationCmd, subcommands.typescript)\n .action(async (options: CommonOptions) => {\n const result = await typescriptCommand({\n cwd: process.cwd(),\n scope: options.scope,\n files: options.files,\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(tsCmd);\n\n // lint command\n const lintCmd = addValidationSubcommand(validationCmd, subcommands.lint)\n .option(\"--fix\", \"Auto-fix issues\")\n .action(async (options: LintOptions) => {\n const result = await lintCommand({\n cwd: process.cwd(),\n scope: options.scope,\n files: options.files,\n fix: options.fix,\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(lintCmd);\n\n // circular command\n const circularCmd = addValidationSubcommand(validationCmd, subcommands.circular)\n .action(async (options: CommonOptions) => {\n const result = await circularCommand({\n cwd: process.cwd(),\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(circularCmd);\n\n // knip command\n const knipCmd = addValidationSubcommand(validationCmd, subcommands.knip)\n .action(async (options: CommonOptions) => {\n const result = await knipCommand({\n cwd: process.cwd(),\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(knipCmd);\n\n // literal command (cross-file literal-reuse detector)\n const literalCmd = addValidationSubcommand(validationCmd, subcommands.literal)\n .option(\n \"--allowlist-existing\",\n \"Append every current finding's value to literal.allowlist.include and exit\",\n )\n .addHelpText(\n \"after\",\n \"\\nEnabled for TypeScript projects by default. Set LITERAL_VALIDATION_ENABLED=0\\n\"\n + \"to skip (useful when migrating a project with many existing violations).\",\n )\n .action(async (options: CommonOptions & { allowlistExisting?: boolean }) => {\n if (options.allowlistExisting) {\n const result = await allowlistExisting({ projectRoot: process.cwd() });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n }\n const result = await literalCommand({\n cwd: process.cwd(),\n files: options.files,\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(literalCmd);\n\n // markdown command\n const markdownCmd = addValidationSubcommand(validationCmd, subcommands.markdown)\n .addHelpText(\n \"after\",\n \"\\nValidates spx/ and docs/ by default. Nodes listed in spx/EXCLUDE are\\n\"\n + \"skipped — use this for declared-state nodes whose [test] links point\\n\"\n + \"to files that do not exist yet.\",\n )\n .action(async (options: CommonOptions) => {\n const result = await markdownCommand({\n cwd: process.cwd(),\n files: options.files,\n quiet: options.quiet,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(markdownCmd);\n\n // all command\n const allCmd = addValidationSubcommand(validationCmd, subcommands.all)\n .option(\"--fix\", \"Auto-fix ESLint issues\")\n .action(async (options: LintOptions) => {\n const result = await allCommand({\n cwd: process.cwd(),\n scope: options.scope,\n files: options.files,\n fix: options.fix,\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(allCmd);\n}\n\n/**\n * Validation domain - Run code validation tools\n */\nfunction handleUnknownSubcommand(operands: readonly string[]): never {\n const [first] = operands;\n const sanitized = sanitizeCliArgument(first);\n const { domain, diagnostics } = validationCliDefinition;\n const { unknownSubcommand } = diagnostics;\n process.stderr.write(`spx ${domain.commandName}: ${unknownSubcommand.messageLabel}: ${sanitized}\\n`);\n process.exit(unknownSubcommand.exitCode);\n}\n\nexport const validationDomain: Domain = {\n name: validationCliDefinition.domain.commandName,\n description: validationCliDefinition.domain.description,\n register: (program: Command) => {\n const { domain } = validationCliDefinition;\n const validationCmd = program\n .command(domain.commandName)\n .alias(domain.alias)\n .description(domain.description);\n\n validationCmd.on(\"command:*\", (operands: readonly string[]) => {\n handleUnknownSubcommand(operands);\n });\n\n registerValidationCommands(validationCmd);\n },\n};\n"],"mappings":"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G,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAA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","names":["createRequire","program","os","path","fs","fs","path","path","fs","fs","fs","path","path","os","program","yamlStringify","JSON_INDENT","formatConfig","readFile","validate","readFile","resolve","program","dirname","join","execa","join","resolve","execa","resolve","statusDirs","join","output","path","join","dirname","stat","path","join","parseYaml","parseYaml","join","path","stat","mkdir","join","resolve","join","resolve","mkdir","readFile","join","join","readFile","mkdir","readdir","readFile","rename","join","readdir","join","readFile","mkdir","rename","readdir","readFile","unlink","join","readdir","join","readFile","lines","unlink","readdir","rename","readdir","rename","readFile","stat","stat","readFile","showCommand","resolve","showCommand","program","access","readFile","writeFile","path","path","readdir","stat","path","path","readdir","stat","JSON_INDENT","getDisplayNumber","getDisplayNumber","formatNode","formatWorkItemName","format","join","NODE_SUFFIXES","NODE_SUFFIXES","join","path","join","join","path","readFile","writeFile","access","program","readFile","rename","writeFile","dirname","join","readFile","isAbsolute","relative","resolve","readFile","join","EXCLUDE_FILENAME","readdir","join","relative","walk","readdir","isNodeError","join","relative","isAbsolute","resolve","relative","path","readFile","DEFAULT_FORMAT","JSON_INDENT","format","path","join","readFile","isFileNotFound","dirname","writeFile","rename","parseSections","value","CharacterCodes","ParseOptions","handleError","ScanError","SyntaxKind","parse","ParseErrorCode","existsSync","join","parse","execSync","fs","path","require","fs","execSync","path","fs","path","fs","path","existsSync","join","resolve","join","existsSync","defaults","spawn","existsSync","join","resolve","TYPESCRIPT_ABSENT_MESSAGE","EXIT_OK","TYPESCRIPT_ABSENT_MESSAGE","formatText","existsSync","readFileSync","join","join","existsSync","readFileSync","path","spawn","existsSync","isAbsolute","join","spawn","existsSync","join","isAbsolute","resolve","tscArgs","TYPESCRIPT_ABSENT_MESSAGE","result","program","require","createRequire"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/domains/audit/paths.ts","../src/domains/audit/reader.ts","../src/domains/audit/semantic.ts","../src/domains/audit/structural.ts","../src/domains/audit/verify.ts","../src/domains/audit/cli.ts","../src/commands/claude/init.ts","../src/lib/claude/permissions/discovery.ts","../src/lib/claude/permissions/parser.ts","../src/lib/file-system/normalizePath.ts","../src/lib/claude/permissions/subsumption.ts","../src/lib/claude/permissions/merger.ts","../src/lib/claude/settings/backup.ts","../src/lib/claude/settings/reporter.ts","../src/lib/claude/settings/writer.ts","../src/commands/claude/settings/consolidate.ts","../src/domains/claude/index.ts","../src/config/index.ts","../src/lib/spec-tree/config.ts","../src/lib/file-inclusion/adapters/eslint.ts","../src/lib/file-inclusion/adapters/knip.ts","../src/lib/file-inclusion/adapters/madge.ts","../src/lib/file-inclusion/adapters/markdownlint.ts","../src/lib/file-inclusion/adapters/pytest.ts","../src/lib/file-inclusion/adapters/tsc.ts","../src/lib/file-inclusion/adapters/vitest.ts","../src/lib/file-inclusion/adapters/index.ts","../src/lib/file-inclusion/ignore-source.ts","../src/lib/file-inclusion/predicates/artifact-directory.ts","../src/lib/file-inclusion/predicates/hidden-prefix.ts","../src/lib/file-inclusion/config.ts","../src/lib/precommit/config.ts","../src/validation/literal/config.ts","../src/validation/config/descriptor.ts","../src/config/registry.ts","../src/commands/config/defaults.ts","../src/commands/config/show.ts","../src/commands/config/validate.ts","../src/domains/config/root.ts","../src/domains/config/index.ts","../src/commands/session/archive.ts","../src/domains/session/archive.ts","../src/domains/session/batch.ts","../src/domains/session/errors.ts","../src/git/root.ts","../src/config/defaults.ts","../src/git/environment.ts","../src/commands/session/delete.ts","../src/domains/session/delete.ts","../src/domains/session/show.ts","../src/domains/session/list.ts","../src/domains/session/timestamp.ts","../src/domains/session/types.ts","../src/commands/session/handoff.ts","../src/domains/session/create.ts","../src/commands/session/list.ts","../src/commands/session/pickup.ts","../src/domains/session/pickup.ts","../src/commands/session/prune.ts","../src/domains/session/prune.ts","../src/commands/session/release.ts","../src/domains/session/release.ts","../src/commands/session/show.ts","../src/domains/session/help.ts","../src/domains/session/index.ts","../src/domains/spec-legacy/index.ts","../src/lib/spec-legacy/scanner/scanner.ts","../src/lib/spec-legacy/scanner/walk.ts","../src/lib/spec-legacy/scanner/validation.ts","../src/lib/spec-legacy/scanner/patterns.ts","../src/lib/spec-legacy/status/state.ts","../src/lib/spec-legacy/tree/build.ts","../src/lib/spec-legacy/types.ts","../src/commands/spec/next.ts","../src/lib/spec-legacy/reporter/json.ts","../src/lib/spec-legacy/reporter/markdown.ts","../src/lib/spec-legacy/reporter/table.ts","../src/lib/spec-legacy/reporter/text.ts","../src/commands/spec/status.ts","../src/domains/spec/apply/exclude/adapters/detect.ts","../src/domains/spec/apply/exclude/constants.ts","../src/domains/spec/apply/exclude/mappings.ts","../src/domains/spec/apply/exclude/adapters/python.ts","../src/domains/spec/apply/exclude/help.ts","../src/domains/spec/apply/exclude/exclude-file.ts","../src/domains/spec/apply/exclude/command.ts","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/string-intern.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/parser.js","../node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/main.js","../src/validation/config/scope.ts","../src/validation/discovery/tool-finder.ts","../src/validation/discovery/constants.ts","../src/validation/discovery/language-finder.ts","../src/validation/steps/circular.ts","../src/commands/validation/circular.ts","../src/commands/validation/format.ts","../src/validation/steps/eslint.ts","../src/lib/process-lifecycle/exit-codes.ts","../src/lib/process-lifecycle/handlers.ts","../src/lib/process-lifecycle/install.ts","../src/lib/process-lifecycle/registry.ts","../src/lib/process-lifecycle/runner.ts","../src/validation/lint-policy.ts","../src/validation/lint-policy-constants.ts","../src/validation/types.ts","../src/validation/steps/knip.ts","../src/commands/validation/knip.ts","../src/commands/validation/lint.ts","../src/validation/literal/index.ts","../src/lib/file-inclusion/predicates/ignore-source.ts","../src/lib/file-inclusion/layer-sequence.ts","../src/lib/file-inclusion/pipeline.ts","../src/validation/literal/detector.ts","../src/domains/spec/fixture-writer-methods.ts","../src/validation/literal/walker.ts","../src/commands/validation/literal.ts","../src/validation/steps/markdown.ts","../src/commands/validation/markdown.ts","../src/validation/steps/typescript.ts","../src/commands/validation/typescript.ts","../src/commands/validation/all.ts","../src/interfaces/cli/sanitize.ts","../src/validation/literal/allowlist-existing.ts","../src/domains/validation/index.ts"],"sourcesContent":["/**\n * CLI entry point for spx\n */\nimport { Command } from \"commander\";\nimport { createRequire } from \"node:module\";\n\nimport { auditDomain } from \"./domains/audit/cli\";\nimport { claudeDomain } from \"./domains/claude\";\nimport { configDomain } from \"./domains/config\";\nimport { sessionDomain } from \"./domains/session/\";\nimport { specDomain } from \"./domains/spec-legacy\";\nimport { validationDomain } from \"./domains/validation\";\nimport { installLifecycle } from \"./lib/process-lifecycle\";\n\ninstallLifecycle();\n\nconst require = createRequire(import.meta.url);\nconst { version } = require(\"../package.json\") as { version: string };\n\nconst program = new Command();\n\nprogram\n .name(\"spx\")\n .description(\"Fast, deterministic CLI tool for spec workflow management\")\n .version(version);\n\n// Register domains\nauditDomain.register(program);\nclaudeDomain.register(program);\nconfigDomain.register(program);\nsessionDomain.register(program);\nspecDomain.register(program);\nvalidationDomain.register(program);\n\nprogram.parse();\n","import { existsSync } from \"node:fs\";\nimport { relative, resolve } from \"node:path\";\nimport { AuditVerdict } from \"./reader\";\n\nexport const AUDIT_PATH_DEFECT = {\n ESCAPES_ROOT: \"path escapes project root\",\n MISSING_FILE: \"missing file\",\n} as const;\n\nexport function validatePaths(verdict: AuditVerdict, projectRoot: string): readonly string[] {\n const defects: string[] = [];\n const root = resolve(projectRoot);\n\n for (const gate of verdict.gates) {\n for (const finding of gate.findings) {\n checkPath(finding.spec_file, root, defects);\n checkPath(finding.test_file, root, defects);\n }\n }\n\n return defects;\n}\n\nfunction checkPath(filePath: string | undefined, root: string, defects: string[]): void {\n if (!filePath) return;\n\n const rel = relative(root, resolve(root, filePath));\n if (rel.startsWith(\"..\")) {\n defects.push(`${AUDIT_PATH_DEFECT.ESCAPES_ROOT}: ${filePath}`);\n return;\n }\n\n if (!existsSync(resolve(root, filePath))) {\n defects.push(`${AUDIT_PATH_DEFECT.MISSING_FILE}: ${filePath}`);\n }\n}\n","/**\n * Audit verdict reader — parses an audit verdict XML file from disk into a\n * typed in-memory representation.\n *\n * All downstream verify stages (structural, semantic, paths) import\n * AuditVerdict from this module and operate on the parsed representation\n * rather than raw XML.\n *\n * @module audit/reader\n */\n\nimport { readFile } from \"node:fs/promises\";\n\nimport { XMLParser, XMLValidator } from \"fast-xml-parser\";\n\nexport interface AuditFinding {\n readonly spec_file?: string;\n readonly test_file?: string;\n}\n\nexport const AUDIT_VERDICT_VALUE = {\n APPROVED: \"APPROVED\",\n REJECT: \"REJECT\",\n} as const;\n\nexport type AuditVerdictValue = (typeof AUDIT_VERDICT_VALUE)[keyof typeof AUDIT_VERDICT_VALUE];\n\nexport const AUDIT_GATE_STATUS = {\n FAIL: \"FAIL\",\n PASS: \"PASS\",\n SKIPPED: \"SKIPPED\",\n} as const;\n\nexport type AuditGateStatus = (typeof AUDIT_GATE_STATUS)[keyof typeof AUDIT_GATE_STATUS];\n\nexport interface AuditGate {\n readonly name?: string;\n readonly status?: string;\n readonly skipped_reason?: string;\n readonly count?: string;\n readonly findings: readonly AuditFinding[];\n}\n\nexport interface AuditVerdictHeader {\n readonly spec_node?: string;\n readonly verdict?: string;\n readonly timestamp?: string;\n}\n\nexport interface AuditVerdict {\n readonly header?: AuditVerdictHeader;\n readonly gates: readonly AuditGate[];\n}\n\nexport const AUDIT_VERDICT_XML = {\n ROOT: \"audit_verdict\",\n HEADER: \"header\",\n SPEC_NODE: \"spec_node\",\n VERDICT: \"verdict\",\n TIMESTAMP: \"timestamp\",\n GATES: \"gates\",\n GATE: \"gate\",\n NAME: \"name\",\n STATUS: \"status\",\n SKIPPED_REASON: \"skipped_reason\",\n FINDINGS: \"findings\",\n FINDING: \"finding\",\n COUNT: \"count\",\n PARSED_COUNT: \"@_count\",\n SPEC_FILE: \"spec_file\",\n TEST_FILE: \"test_file\",\n} as const;\n\nconst ARRAY_TAGS = new Set<string>([AUDIT_VERDICT_XML.GATE, AUDIT_VERDICT_XML.FINDING]);\n\nconst PARSER_OPTIONS = {\n ignoreAttributes: false,\n attributeNamePrefix: \"@_\",\n parseTagValue: false,\n parseAttributeValue: false,\n isArray: (name: string) => ARRAY_TAGS.has(name),\n} as const;\n\n/**\n * Reads and parses an audit verdict XML file from disk.\n *\n * @throws {Error} When the file does not exist — message includes filePath.\n * @throws {Error} When the file is not well-formed XML — message includes filePath.\n */\nexport async function readVerdictFile(filePath: string): Promise<AuditVerdict> {\n let xml: string;\n try {\n xml = await readFile(filePath, \"utf-8\");\n } catch (cause) {\n throw new Error(`Failed to read verdict file: ${filePath}`, { cause });\n }\n\n const validation = XMLValidator.validate(xml);\n if (validation !== true) {\n throw new Error(\n `Malformed XML in verdict file: ${filePath}: ${validation.err.msg}`,\n );\n }\n\n const parser = new XMLParser(PARSER_OPTIONS);\n const parsed = parser.parse(xml) as Record<string, unknown>;\n\n return buildVerdict(parsed);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction buildVerdict(parsed: Record<string, unknown>): AuditVerdict {\n const rootUnknown = parsed[AUDIT_VERDICT_XML.ROOT];\n if (!isObject(rootUnknown)) {\n return { gates: [] };\n }\n\n const headerUnknown = rootUnknown[AUDIT_VERDICT_XML.HEADER];\n const gatesUnknown = rootUnknown[AUDIT_VERDICT_XML.GATES];\n\n return {\n header: isObject(headerUnknown) ? buildHeader(headerUnknown) : undefined,\n gates: isObject(gatesUnknown) ? buildGates(gatesUnknown) : [],\n };\n}\n\nfunction buildHeader(raw: Record<string, unknown>): AuditVerdictHeader {\n return {\n spec_node: asString(raw[AUDIT_VERDICT_XML.SPEC_NODE]),\n verdict: asString(raw[AUDIT_VERDICT_XML.VERDICT]),\n timestamp: asString(raw[AUDIT_VERDICT_XML.TIMESTAMP]),\n };\n}\n\nfunction buildGates(raw: Record<string, unknown>): readonly AuditGate[] {\n const gatesUnknown = raw[AUDIT_VERDICT_XML.GATE];\n if (!Array.isArray(gatesUnknown)) return [];\n return gatesUnknown.filter(isObject).map(buildGate);\n}\n\nfunction buildGate(raw: Record<string, unknown>): AuditGate {\n const findingsUnknown = raw[AUDIT_VERDICT_XML.FINDINGS];\n return {\n name: asString(raw[AUDIT_VERDICT_XML.NAME]),\n status: asString(raw[AUDIT_VERDICT_XML.STATUS]),\n skipped_reason: asString(raw[AUDIT_VERDICT_XML.SKIPPED_REASON]),\n count: isObject(findingsUnknown) ? asString(findingsUnknown[AUDIT_VERDICT_XML.PARSED_COUNT]) : undefined,\n findings: isObject(findingsUnknown) ? buildFindings(findingsUnknown) : [],\n };\n}\n\nfunction buildFindings(raw: Record<string, unknown>): readonly AuditFinding[] {\n const findingsUnknown = raw[AUDIT_VERDICT_XML.FINDING];\n if (!Array.isArray(findingsUnknown)) return [];\n return findingsUnknown.filter(isObject).map(buildFinding);\n}\n\nfunction buildFinding(raw: Record<string, unknown>): AuditFinding {\n return {\n spec_file: asString(raw[AUDIT_VERDICT_XML.SPEC_FILE]),\n test_file: asString(raw[AUDIT_VERDICT_XML.TEST_FILE]),\n };\n}\n","import { AUDIT_GATE_STATUS, AUDIT_VERDICT_VALUE, AuditVerdict } from \"./reader\";\n\nexport function validateSemantics(verdict: AuditVerdict): readonly string[] {\n const defects: string[] = [];\n\n const hasFail = verdict.gates.some((g) => g.status === AUDIT_GATE_STATUS.FAIL);\n const hasSkipped = verdict.gates.some((g) => g.status === AUDIT_GATE_STATUS.SKIPPED);\n\n if (verdict.header?.verdict === AUDIT_VERDICT_VALUE.APPROVED && (hasFail || hasSkipped)) {\n defects.push(\"incoherent verdict: APPROVED but at least one gate is not PASS\");\n } else if (verdict.header?.verdict === AUDIT_VERDICT_VALUE.REJECT && !hasFail && !hasSkipped) {\n defects.push(\"incoherent verdict: REJECT but all gates are PASS\");\n }\n\n for (const gate of verdict.gates) {\n const label = gate.name ? `gate \"${gate.name}\"` : \"gate\";\n\n if (gate.status === AUDIT_GATE_STATUS.FAIL && gate.findings.length === 0) {\n defects.push(`failed gate has no findings: ${label}`);\n }\n\n if (gate.status === AUDIT_GATE_STATUS.SKIPPED && !gate.skipped_reason) {\n defects.push(`skipped gate missing reason: ${label}`);\n }\n }\n\n return defects;\n}\n","import { AUDIT_GATE_STATUS, AUDIT_VERDICT_VALUE, AuditVerdict } from \"./reader\";\n\nconst VALID_VERDICTS = new Set<string>(Object.values(AUDIT_VERDICT_VALUE));\nconst VALID_GATE_STATUSES = new Set<string>(Object.values(AUDIT_GATE_STATUS));\n\nexport const STRUCTURAL_DEFECT_TEXT = {\n MISSING_REQUIRED_ELEMENT: \"missing required element\",\n INVALID_ENUM_VALUE: \"invalid enum value\",\n} as const;\n\nexport function validateStructure(verdict: AuditVerdict): readonly string[] {\n const defects: string[] = [];\n\n if (!verdict.header) {\n defects.push(`${STRUCTURAL_DEFECT_TEXT.MISSING_REQUIRED_ELEMENT}: <header>`);\n return defects;\n }\n\n if (!verdict.header.spec_node) {\n defects.push(`${STRUCTURAL_DEFECT_TEXT.MISSING_REQUIRED_ELEMENT}: <spec_node>`);\n }\n\n if (!verdict.header.verdict) {\n defects.push(`${STRUCTURAL_DEFECT_TEXT.MISSING_REQUIRED_ELEMENT}: <verdict> in <header>`);\n } else if (!VALID_VERDICTS.has(verdict.header.verdict)) {\n defects.push(\n `${STRUCTURAL_DEFECT_TEXT.INVALID_ENUM_VALUE}: verdict \"${verdict.header.verdict}\" is not one of APPROVED, REJECT`,\n );\n }\n\n if (!verdict.header.timestamp) {\n defects.push(`${STRUCTURAL_DEFECT_TEXT.MISSING_REQUIRED_ELEMENT}: <timestamp>`);\n }\n\n if (verdict.gates.length === 0) {\n defects.push(`${STRUCTURAL_DEFECT_TEXT.MISSING_REQUIRED_ELEMENT}: at least one <gate> in <gates>`);\n }\n\n for (const gate of verdict.gates) {\n const label = gate.name ? `gate \"${gate.name}\"` : \"gate\";\n\n if (gate.status !== undefined && !VALID_GATE_STATUSES.has(gate.status)) {\n defects.push(\n `${STRUCTURAL_DEFECT_TEXT.INVALID_ENUM_VALUE}: ${label} status \"${gate.status}\" is not one of PASS, FAIL, SKIPPED`,\n );\n }\n\n if (gate.count !== undefined) {\n const declared = parseInt(gate.count, 10);\n const actual = gate.findings.length;\n if (isNaN(declared) || declared !== actual) {\n defects.push(\n `count mismatch: ${label} declares count=\"${gate.count}\" but has ${actual} finding(s)`,\n );\n }\n }\n }\n\n return defects;\n}\n","import { validatePaths } from \"./paths\";\nimport { readVerdictFile } from \"./reader\";\nimport { validateSemantics } from \"./semantic\";\nimport { validateStructure } from \"./structural\";\n\nexport interface VerifyOutput {\n readonly lines: readonly string[];\n readonly exitCode: 0 | 1;\n readonly verdict?: string;\n}\n\nexport async function runVerifyPipeline(\n filePath: string,\n projectRoot: string,\n): Promise<VerifyOutput> {\n let verdict;\n try {\n verdict = await readVerdictFile(filePath);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { lines: [`reader: ${message}`], exitCode: 1 };\n }\n\n const structuralDefects = validateStructure(verdict);\n if (structuralDefects.length > 0) {\n return { lines: structuralDefects.map((d) => `structural: ${d}`), exitCode: 1 };\n }\n\n const semanticDefects = validateSemantics(verdict);\n if (semanticDefects.length > 0) {\n return { lines: semanticDefects.map((d) => `semantic: ${d}`), exitCode: 1 };\n }\n\n const pathDefects = validatePaths(verdict, projectRoot);\n if (pathDefects.length > 0) {\n return { lines: pathDefects.map((d) => `paths: ${d}`), exitCode: 1 };\n }\n\n return { lines: [], exitCode: 0, verdict: verdict.header?.verdict };\n}\n","import type { Command } from \"commander\";\n\nimport type { Domain } from \"@/domains/types\";\nimport { runVerifyPipeline } from \"./verify\";\n\nexport async function runVerifyCommand(\n filePath: string,\n projectRoot: string,\n writeLine: (line: string) => void,\n): Promise<0 | 1> {\n const result = await runVerifyPipeline(filePath, projectRoot);\n if (result.exitCode === 0) {\n writeLine(result.verdict ?? \"\");\n } else {\n for (const line of result.lines) {\n writeLine(line);\n }\n }\n return result.exitCode;\n}\n\nexport const auditDomain: Domain = {\n name: \"audit\",\n description: \"Audit verdict verification\",\n register: (program: Command) => {\n const auditCmd = program.command(\"audit\").description(\"Audit verdict verification\");\n\n auditCmd\n .command(\"verify <file>\")\n .description(\"Verify an audit verdict XML file\")\n .action(async (file: string) => {\n const exitCode = await runVerifyCommand(file, process.cwd(), console.log);\n process.exit(exitCode);\n });\n },\n};\n","/**\n * Init command implementation\n *\n * Wrapper around `claude plugin marketplace` to install/update outcomeeng marketplace\n */\nimport { execa } from \"execa\";\n\n/**\n * Options for init command\n */\nexport interface InitOptions {\n /** Working directory (for testing) */\n cwd?: string;\n}\n\n/**\n * Execute claude init command\n *\n * Wraps the Claude CLI's `plugin marketplace` commands to manage\n * the outcomeeng marketplace installation.\n *\n * Behavior:\n * 1. Check if outcomeeng marketplace exists via `claude plugin marketplace list`\n * 2. If missing: shell `claude plugin marketplace add outcomeeng/claude`\n * 3. If exists: shell `claude plugin marketplace update outcomeeng`\n * 4. Parse output and return status message\n *\n * @param options - Command options\n * @returns Status message\n * @throws Error if claude CLI not available or commands fail\n *\n * @example\n * ```typescript\n * const output = await initCommand();\n * console.log(output);\n * // Output: \"✓ outcomeeng marketplace installed successfully\"\n * // or: \"✓ outcomeeng marketplace updated successfully\"\n * ```\n */\nexport async function initCommand(\n options: InitOptions = {},\n): Promise<string> {\n const cwd = options.cwd || process.cwd();\n\n try {\n // Step 1: Check if outcomeeng marketplace exists\n const { stdout: listOutput } = await execa(\n \"claude\",\n [\"plugin\", \"marketplace\", \"list\"],\n { cwd },\n );\n\n const exists = listOutput.includes(\"outcomeeng\");\n\n // Step 2: Add or update based on existence\n if (!exists) {\n // Add marketplace\n await execa(\n \"claude\",\n [\"plugin\", \"marketplace\", \"add\", \"outcomeeng/claude\"],\n { cwd },\n );\n\n return \"✓ outcomeeng marketplace installed successfully\\n\\nRun 'claude plugin marketplace list' to view all marketplaces.\";\n } else {\n // Update marketplace\n await execa(\"claude\", [\"plugin\", \"marketplace\", \"update\", \"outcomeeng\"], {\n cwd,\n });\n\n return \"✓ outcomeeng marketplace updated successfully\\n\\nThe marketplace is now up to date.\";\n }\n } catch (error) {\n if (error instanceof Error) {\n // Check for specific error conditions\n if (\n error.message.includes(\"ENOENT\")\n || error.message.includes(\"command not found\")\n ) {\n throw new Error(\n \"Claude CLI not found. Please install Claude Code first.\\n\\nVisit: https://docs.anthropic.com/claude-code\",\n );\n }\n\n throw new Error(`Failed to initialize marketplace: ${error.message}`);\n }\n throw error;\n }\n}\n","/**\n * Discovery of Claude Code settings files across project directories\n */\nimport fs from \"fs/promises\";\nimport path from \"path\";\n\n/**\n * Recursively find all .claude/settings.local.json files under a root directory\n *\n * Walks the directory tree looking for files matching the pattern:\n * `**\\/.claude/settings.local.json`\n *\n * @param root - Root directory path to start searching from\n * @param visited - Set of visited paths to avoid symlink loops (internal use)\n * @returns Promise resolving to array of absolute paths to settings.local.json files\n * @throws Error if root directory doesn't exist or permission denied\n *\n * @example\n * ```typescript\n * const files = await findSettingsFiles(\"~/Code\");\n * // Returns: [\n * // \"/Users/user/Code/project-a/.claude/settings.local.json\",\n * // \"/Users/user/Code/project-b/.claude/settings.local.json\"\n * // ]\n * ```\n */\nexport async function findSettingsFiles(\n root: string,\n visited: Set<string> = new Set(),\n): Promise<string[]> {\n // Normalize and resolve path to handle symlinks and ~ expansion\n const normalizedRoot = path.resolve(root.replace(/^~/, process.env.HOME || \"~\"));\n\n // Check for symlink loops\n if (visited.has(normalizedRoot)) {\n return []; // Skip already visited directories\n }\n visited.add(normalizedRoot);\n\n try {\n // Stat the root to verify it exists and is a directory\n const stats = await fs.stat(normalizedRoot);\n if (!stats.isDirectory()) {\n throw new Error(`Path is not a directory: ${normalizedRoot}`);\n }\n\n // Read directory contents\n const entries = await fs.readdir(normalizedRoot, { withFileTypes: true });\n const results: string[] = [];\n\n for (const entry of entries) {\n const fullPath = path.join(normalizedRoot, entry.name);\n\n // If this is a .claude directory, check for settings.local.json\n if (entry.isDirectory() && entry.name === \".claude\") {\n const settingsPath = path.join(fullPath, \"settings.local.json\");\n if (await isValidSettingsFile(settingsPath)) {\n results.push(settingsPath);\n }\n }\n\n // Recursively search subdirectories (skip .claude to avoid double-checking)\n if (entry.isDirectory() && entry.name !== \".claude\") {\n const subFiles = await findSettingsFiles(fullPath, visited);\n results.push(...subFiles);\n }\n }\n\n return results;\n } catch (error) {\n // Re-throw with more context\n if (error instanceof Error) {\n if (error.message.includes(\"ENOENT\")) {\n throw new Error(`Directory not found: ${normalizedRoot}`);\n }\n if (error.message.includes(\"EACCES\")) {\n throw new Error(`Permission denied: ${normalizedRoot}`);\n }\n throw new Error(`Failed to search directory \"${normalizedRoot}\": ${error.message}`);\n }\n throw error;\n }\n}\n\n/**\n * Check if a given path is a valid settings.local.json file\n *\n * Validates that:\n * - File exists\n * - File is readable\n * - File has .json extension\n *\n * @param filePath - Absolute path to check\n * @returns Promise resolving to true if valid settings file, false otherwise\n *\n * @example\n * ```typescript\n * const isValid = await isValidSettingsFile(\"/path/to/.claude/settings.local.json\");\n * // Returns: true or false\n * ```\n */\nexport async function isValidSettingsFile(filePath: string): Promise<boolean> {\n try {\n // Check if file exists and is readable\n await fs.access(filePath, fs.constants.R_OK);\n\n // Check if it's actually a file (not a directory)\n const stats = await fs.stat(filePath);\n if (!stats.isFile()) {\n return false;\n }\n\n // Validate it has .json extension\n return path.extname(filePath) === \".json\";\n } catch {\n // File doesn't exist or isn't readable\n return false;\n }\n}\n","/**\n * Parser for Claude Code settings files and permissions\n */\nimport fs from \"fs/promises\";\nimport type { ClaudeSettings, Permission, PermissionCategory, Permissions } from \"./types\";\n\n/**\n * Parse a settings.json file and extract permissions\n *\n * Handles:\n * - Malformed JSON (returns null)\n * - Missing permissions object (returns empty permissions)\n * - Validates basic structure\n *\n * @param filePath - Absolute path to settings.json file\n * @returns Promise resolving to ClaudeSettings object, or null if malformed\n *\n * @example\n * ```typescript\n * const settings = await parseSettingsFile(\"/path/to/.claude/settings.json\");\n * if (settings) {\n * console.log(settings.permissions?.allow);\n * }\n * ```\n */\nexport async function parseSettingsFile(filePath: string): Promise<ClaudeSettings | null> {\n try {\n // Read file contents\n const content = await fs.readFile(filePath, \"utf-8\");\n\n // Parse JSON\n const parsed = JSON.parse(content);\n\n // Basic validation: should be an object\n if (typeof parsed !== \"object\" || parsed === null) {\n return null;\n }\n\n return parsed as ClaudeSettings;\n } catch {\n // JSON parse error or file read error\n return null;\n }\n}\n\n/**\n * Parse a permission string into structured components\n *\n * Permission format: \"Type(scope)\"\n * Examples:\n * - \"Bash(git:*)\" => { type: \"Bash\", scope: \"git:*\" }\n * - \"Read(file_path:/Users/user/Code/**)\" => { type: \"Read\", scope: \"file_path:/Users/user/Code/**\" }\n * - \"WebFetch(domain:github.com)\" => { type: \"WebFetch\", scope: \"domain:github.com\" }\n *\n * @param raw - Raw permission string\n * @param category - Permission category (allow/deny/ask)\n * @returns Parsed Permission object\n * @throws Error if permission string is malformed\n *\n * @example\n * ```typescript\n * const perm = parsePermission(\"Bash(git:*)\", \"allow\");\n * // Returns: { raw: \"Bash(git:*)\", type: \"Bash\", scope: \"git:*\", category: \"allow\" }\n * ```\n */\nexport function parsePermission(raw: string, category: PermissionCategory): Permission {\n // Match pattern: Type(scope)\n const match = raw.match(/^([^(]+)\\((.+)\\)$/);\n\n if (!match) {\n throw new Error(`Malformed permission string: \"${raw}\"`);\n }\n\n const [, type, scope] = match;\n\n return {\n raw,\n type: type.trim(),\n scope: scope.trim(),\n category,\n };\n}\n\n/**\n * Parse all permissions from a Permissions object\n *\n * Converts permission strings to structured Permission objects,\n * grouped by category (allow/deny/ask).\n *\n * @param permissions - Permissions object from settings.json\n * @returns Array of parsed Permission objects\n *\n * @example\n * ```typescript\n * const permissions = {\n * allow: [\"Bash(git:*)\", \"Bash(npm:*)\"],\n * deny: [\"Bash(rm -rf:*)\"]\n * };\n * const parsed = parseAllPermissions(permissions);\n * // Returns array of Permission objects with category set\n * ```\n */\nexport function parseAllPermissions(permissions: Permissions): Permission[] {\n const result: Permission[] = [];\n\n // Parse allow permissions\n if (permissions.allow) {\n for (const perm of permissions.allow) {\n try {\n result.push(parsePermission(perm, \"allow\"));\n } catch {\n // Skip malformed permissions\n continue;\n }\n }\n }\n\n // Parse deny permissions\n if (permissions.deny) {\n for (const perm of permissions.deny) {\n try {\n result.push(parsePermission(perm, \"deny\"));\n } catch {\n // Skip malformed permissions\n continue;\n }\n }\n }\n\n // Parse ask permissions\n if (permissions.ask) {\n for (const perm of permissions.ask) {\n try {\n result.push(parsePermission(perm, \"ask\"));\n } catch {\n // Skip malformed permissions\n continue;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Read and parse multiple settings files\n *\n * Processes an array of file paths, reading and parsing each one.\n * Skips files that can't be read or parsed.\n *\n * @param filePaths - Array of absolute paths to settings files\n * @returns Promise resolving to array of Permissions objects (one per valid file)\n *\n * @example\n * ```typescript\n * const files = [\n * \"/Users/user/Code/project-a/.claude/settings.local.json\",\n * \"/Users/user/Code/project-b/.claude/settings.local.json\"\n * ];\n * const allPermissions = await parseAllSettings(files);\n * // Returns: [{ allow: [...], deny: [...] }, { allow: [...] }]\n * ```\n */\nexport async function parseAllSettings(filePaths: string[]): Promise<Permissions[]> {\n const results: Permissions[] = [];\n\n for (const filePath of filePaths) {\n const settings = await parseSettingsFile(filePath);\n if (settings?.permissions) {\n results.push(settings.permissions);\n }\n }\n\n return results;\n}\n","/**\n * Normalize path separators for cross-platform consistency\n *\n * Converts Windows backslashes to forward slashes for consistent path handling\n * across different operating systems.\n *\n * @param filepath - Path to normalize\n * @returns Normalized path with forward slashes\n *\n * @example\n * ```typescript\n * normalizePath(\"C:\\\\Users\\\\test\\\\specs\"); // Returns: \"C:/Users/test/specs\"\n * normalizePath(\"/home/user/specs\"); // Returns: \"/home/user/specs\"\n * ```\n */\n\nexport function normalizePath(filepath: string): string {\n // Replace all backslashes with forward slashes for cross-platform consistency\n return filepath.replace(/\\\\/g, \"/\");\n}\n","/**\n * Permission subsumption detection\n *\n * Detects when broader permissions subsume narrower ones:\n * - Bash(git:*) subsumes Bash(git log:*), Bash(git worktree:*), etc.\n * - Read(file_path:/Users/user/Code/**) subsumes Read(file_path:/Users/user/Code/project-a/**)\n */\nimport { normalizePath } from \"@/lib/file-system/normalizePath\";\nimport { parsePermission } from \"./parser\";\nimport type { Permission, PermissionCategory, ScopePattern, SubsumptionResult } from \"./types\";\n\n/**\n * Parse a scope string to extract pattern type and value\n *\n * Determines whether the scope is a command pattern (e.g., \"git:*\")\n * or a path pattern (e.g., \"file_path:/Users/user/Code/**\").\n *\n * @param scope - Scope string from permission\n * @returns ScopePattern with type and pattern\n *\n * @example\n * ```typescript\n * parseScopePattern(\"git:*\")\n * // Returns: { type: \"command\", pattern: \"git:*\" }\n *\n * parseScopePattern(\"file_path:/Users/user/Code/**\")\n * // Returns: { type: \"path\", pattern: \"/Users/user/Code/**\" }\n * ```\n */\nexport function parseScopePattern(scope: string): ScopePattern {\n // Check if scope contains path indicators\n if (\n scope.includes(\"file_path:\")\n || scope.includes(\"directory_path:\")\n || scope.includes(\"path:\")\n ) {\n // Extract path after the colon\n const colonIndex = scope.indexOf(\":\");\n const pattern = colonIndex >= 0 ? scope.substring(colonIndex + 1) : scope;\n return { type: \"path\", pattern };\n }\n\n // Default to command pattern (e.g., \"git:*\", \"npm:*\")\n return { type: \"command\", pattern: scope };\n}\n\n/**\n * Check if permission A subsumes permission B\n *\n * Subsumption rules:\n * 1. Same type required (Bash subsumes Bash, not Read)\n * 2. Identical scopes = not subsumption (exact match)\n * 3. Broader scope subsumes narrower scope:\n * - Command: \"git:*\" subsumes \"git log:*\", \"git worktree:*\"\n * - Path: \"/Users/user/Code/**\" subsumes \"/Users/user/Code/project-a/**\"\n *\n * @param broader - Permission that might subsume the other\n * @param narrower - Permission that might be subsumed\n * @returns true if broader subsumes narrower, false otherwise\n *\n * @example\n * ```typescript\n * subsumes(\n * parsePermission(\"Bash(git:*)\", \"allow\"),\n * parsePermission(\"Bash(git log:*)\", \"allow\")\n * )\n * // Returns: true\n *\n * subsumes(\n * parsePermission(\"Read(file_path:/Users/user/Code/**)\", \"allow\"),\n * parsePermission(\"Read(file_path:/Users/user/Code/project-a/**)\", \"allow\")\n * )\n * // Returns: true\n *\n * subsumes(\n * parsePermission(\"Bash(git:*)\", \"allow\"),\n * parsePermission(\"Read(file_path:/Users/user/Code/**)\", \"allow\")\n * )\n * // Returns: false (different types)\n * ```\n */\nexport function subsumes(broader: Permission, narrower: Permission): boolean {\n // 1. Type must match\n if (broader.type !== narrower.type) {\n return false;\n }\n\n // 2. Identical = not subsumption (this is just a duplicate)\n if (broader.scope === narrower.scope) {\n return false;\n }\n\n // 3. Parse scope patterns\n const broaderScope = parseScopePattern(broader.scope);\n const narrowerScope = parseScopePattern(narrower.scope);\n\n // 4. Handle command patterns (e.g., \"git:*\")\n if (broaderScope.type === \"command\" && narrowerScope.type === \"command\") {\n // Extract base command by removing :* suffix\n const broaderBase = broaderScope.pattern.replace(/:?\\*+$/, \"\");\n const narrowerFull = narrowerScope.pattern.replace(/:?\\*+$/, \"\");\n\n // Check if narrower starts with broader prefix\n // \"git:*\" subsumes \"git log:*\" if:\n // - narrowerFull starts with broaderBase\n // - narrowerFull is longer (more specific)\n if (narrowerFull.startsWith(broaderBase)) {\n // Additional specificity check: narrower must add more detail\n // e.g., \"git\" subsumes \"git log\", but not \"git\" subsumes \"git\"\n return narrowerFull.length > broaderBase.length;\n }\n }\n\n // 5. Handle path patterns (e.g., \"/Users/user/Code/**\")\n if (broaderScope.type === \"path\" && narrowerScope.type === \"path\") {\n // Normalize paths for comparison\n const broaderPath = normalizePath(broaderScope.pattern.replace(/\\/?\\*+$/, \"\"));\n const narrowerPath = normalizePath(narrowerScope.pattern.replace(/\\/?\\*+$/, \"\"));\n\n // Check if narrower is a sub-path of broader\n // \"/Users/user/Code\" subsumes \"/Users/user/Code/project-a\" if:\n // - narrowerPath starts with broaderPath + \"/\"\n return narrowerPath.startsWith(broaderPath + \"/\");\n }\n\n // 6. Mixed pattern types don't subsume each other\n return false;\n}\n\n/**\n * Find all subsumption relationships in a permission list\n *\n * Returns a map of broader permissions to the narrower permissions\n * they subsume. This allows identifying which permissions can be\n * removed from the list.\n *\n * @param permissions - Array of permissions to analyze\n * @returns Array of subsumption results\n *\n * @example\n * ```typescript\n * const permissions = [\n * parsePermission(\"Bash(git:*)\", \"allow\"),\n * parsePermission(\"Bash(git log:*)\", \"allow\"),\n * parsePermission(\"Bash(git worktree:*)\", \"allow\"),\n * parsePermission(\"Bash(npm:*)\", \"allow\"),\n * ];\n *\n * const results = detectSubsumptions(permissions);\n * // Returns: [\n * // {\n * // broader: { raw: \"Bash(git:*)\", ... },\n * // narrower: [\n * // { raw: \"Bash(git log:*)\", ... },\n * // { raw: \"Bash(git worktree:*)\", ... }\n * // ]\n * // }\n * // ]\n * ```\n */\nexport function detectSubsumptions(permissions: Permission[]): SubsumptionResult[] {\n const results: SubsumptionResult[] = [];\n const processedBroader = new Set<string>();\n\n for (let i = 0; i < permissions.length; i++) {\n const broader = permissions[i];\n\n // Skip if already processed as a broader permission\n if (processedBroader.has(broader.raw)) {\n continue;\n }\n\n const narrowerPerms: Permission[] = [];\n\n // Check all other permissions to see if this one subsumes them\n for (let j = 0; j < permissions.length; j++) {\n if (i === j) continue; // Skip comparing with self\n\n const narrower = permissions[j];\n\n if (subsumes(broader, narrower)) {\n narrowerPerms.push(narrower);\n }\n }\n\n // If this permission subsumes others, record it\n if (narrowerPerms.length > 0) {\n results.push({\n broader,\n narrower: narrowerPerms,\n });\n processedBroader.add(broader.raw);\n }\n }\n\n return results;\n}\n\n/**\n * Remove subsumed permissions from a list, keeping only the broadest ones\n *\n * This is the main function for consolidating permissions.\n * It finds all subsumption relationships and removes narrower\n * permissions, leaving only the broadest ones.\n *\n * @param permissionStrings - Array of raw permission strings\n * @param category - Permission category (for parsing)\n * @returns Array of permission strings with subsumed ones removed\n *\n * @example\n * ```typescript\n * const permissions = [\n * \"Bash(git:*)\",\n * \"Bash(git log:*)\",\n * \"Bash(git worktree:*)\",\n * \"Bash(npm:*)\",\n * ];\n *\n * const result = removeSubsumed(permissions, \"allow\");\n * // Returns: [\"Bash(git:*)\", \"Bash(npm:*)\"]\n * ```\n */\nexport function removeSubsumed(\n permissionStrings: string[],\n category: PermissionCategory,\n): string[] {\n // Parse all permission strings\n const permissions = permissionStrings\n .map((raw) => {\n try {\n return parsePermission(raw, category);\n } catch {\n // Keep malformed permissions as-is (don't filter them out)\n return null;\n }\n })\n .filter((p): p is Permission => p !== null);\n\n // Detect subsumptions\n const subsumptions = detectSubsumptions(permissions);\n\n // Build set of narrower permissions to remove\n const toRemove = new Set<string>();\n for (const result of subsumptions) {\n for (const narrower of result.narrower) {\n toRemove.add(narrower.raw);\n }\n }\n\n // Filter out subsumed permissions\n return permissionStrings.filter((perm) => !toRemove.has(perm));\n}\n","/**\n * Permission merging with subsumption and conflict resolution\n */\nimport { parsePermission } from \"./parser\";\nimport { removeSubsumed, subsumes } from \"./subsumption\";\nimport type { ConsolidationResult, Permissions, PermissionsAdded } from \"./types\";\n\n/**\n * Merge permissions from global settings and multiple local settings files\n *\n * Process:\n * 1. Combine all permissions by category (allow/deny/ask)\n * 2. Apply subsumption to remove narrower permissions\n * 3. Resolve conflicts (deny wins over allow)\n * 4. Deduplicate using Sets\n * 5. Sort alphabetically\n *\n * @param global - Global settings permissions (baseline)\n * @param local - Array of local settings permissions to merge in\n * @returns Merged permissions and consolidation statistics\n *\n * @example\n * ```typescript\n * const global = { allow: [\"Bash(ls:*)\"] };\n * const local = [\n * { allow: [\"Bash(git:*)\", \"Bash(git log:*)\"] },\n * { deny: [\"Bash(rm:*)\"] }\n * ];\n *\n * const { merged, result } = mergePermissions(global, local);\n * // merged.allow: [\"Bash(git:*)\", \"Bash(ls:*)\"] // git log:* removed by subsumption\n * // merged.deny: [\"Bash(rm:*)\"]\n * // result.subsumed: [\"Bash(git log:*)\"]\n * ```\n */\nexport function mergePermissions(\n global: Permissions,\n local: Permissions[],\n): { merged: Permissions; result: ConsolidationResult } {\n // Track original global permissions for computing added\n const originalGlobal = {\n allow: new Set(global.allow || []),\n deny: new Set(global.deny || []),\n ask: new Set(global.ask || []),\n };\n\n // Step 1: Combine all permissions by category\n const combined: Permissions = {\n allow: [...(global.allow || [])],\n deny: [...(global.deny || [])],\n ask: [...(global.ask || [])],\n };\n\n let filesProcessed = 0;\n let filesSkipped = 0;\n\n for (const localPerms of local) {\n let hasPerms = false;\n\n if (localPerms.allow && localPerms.allow.length > 0) {\n combined.allow?.push(...localPerms.allow);\n hasPerms = true;\n }\n if (localPerms.deny && localPerms.deny.length > 0) {\n combined.deny?.push(...localPerms.deny);\n hasPerms = true;\n }\n if (localPerms.ask && localPerms.ask.length > 0) {\n combined.ask?.push(...localPerms.ask);\n hasPerms = true;\n }\n\n if (hasPerms) {\n filesProcessed++;\n } else {\n filesSkipped++;\n }\n }\n\n // Step 2: Apply subsumption to each category\n const allSubsumed: string[] = [];\n\n const afterSubsumption: Permissions = {};\n\n if (combined.allow && combined.allow.length > 0) {\n const before = new Set(combined.allow);\n combined.allow = removeSubsumed(combined.allow, \"allow\");\n const after = new Set(combined.allow);\n\n // Track what was removed\n for (const perm of before) {\n if (!after.has(perm)) {\n allSubsumed.push(perm);\n }\n }\n }\n\n if (combined.deny && combined.deny.length > 0) {\n const before = new Set(combined.deny);\n combined.deny = removeSubsumed(combined.deny, \"deny\");\n const after = new Set(combined.deny);\n\n // Track what was removed\n for (const perm of before) {\n if (!after.has(perm)) {\n allSubsumed.push(perm);\n }\n }\n }\n\n if (combined.ask && combined.ask.length > 0) {\n const before = new Set(combined.ask);\n combined.ask = removeSubsumed(combined.ask, \"ask\");\n const after = new Set(combined.ask);\n\n // Track what was removed\n for (const perm of before) {\n if (!after.has(perm)) {\n allSubsumed.push(perm);\n }\n }\n }\n\n afterSubsumption.allow = combined.allow;\n afterSubsumption.deny = combined.deny;\n afterSubsumption.ask = combined.ask;\n\n // Step 3: Resolve conflicts (deny wins over allow)\n const {\n resolved,\n conflictCount,\n subsumed: conflictSubsumed,\n } = resolveConflicts(afterSubsumption);\n\n // Combine subsumptions from step 2 and step 3\n const subsumed = [...allSubsumed, ...conflictSubsumed];\n\n // Step 4: Deduplicate using Sets and sort\n const merged: Permissions = {};\n\n if (resolved.allow && resolved.allow.length > 0) {\n merged.allow = Array.from(new Set(resolved.allow)).sort();\n }\n\n if (resolved.deny && resolved.deny.length > 0) {\n merged.deny = Array.from(new Set(resolved.deny)).sort();\n }\n\n if (resolved.ask && resolved.ask.length > 0) {\n merged.ask = Array.from(new Set(resolved.ask)).sort();\n }\n\n // Step 5: Compute what was added\n const added: PermissionsAdded = {\n allow: [],\n deny: [],\n ask: [],\n };\n\n for (const perm of merged.allow || []) {\n if (!originalGlobal.allow.has(perm)) {\n added.allow.push(perm);\n }\n }\n\n for (const perm of merged.deny || []) {\n if (!originalGlobal.deny.has(perm)) {\n added.deny.push(perm);\n }\n }\n\n for (const perm of merged.ask || []) {\n if (!originalGlobal.ask.has(perm)) {\n added.ask.push(perm);\n }\n }\n\n // Build result\n const result: ConsolidationResult = {\n filesScanned: local.length,\n filesProcessed,\n filesSkipped,\n added,\n subsumed,\n conflictsResolved: conflictCount,\n };\n\n return { merged, result };\n}\n\n/**\n * Resolve conflicts between allow and deny permissions\n *\n * Rules:\n * - If exact match in both allow and deny: keep in deny, remove from allow\n * - If deny has broader permission that subsumes allow: remove from allow\n *\n * This implements a security-first approach: deny always wins.\n *\n * @param permissions - Permissions with potential conflicts\n * @returns Resolved permissions with conflicts removed, count of conflicts, and list of subsumed permissions\n *\n * @example\n * ```typescript\n * const permissions = {\n * allow: [\"Bash(git log:*)\", \"Bash(npm:*)\"],\n * deny: [\"Bash(git:*)\"]\n * };\n *\n * const { resolved, conflictCount } = resolveConflicts(permissions);\n * // resolved.allow: [\"Bash(npm:*)\"] // git log:* removed (subsumed by deny git:*)\n * // resolved.deny: [\"Bash(git:*)\"]\n * // conflictCount: 1\n * ```\n */\nexport function resolveConflicts(permissions: Permissions): {\n resolved: Permissions;\n conflictCount: number;\n subsumed: string[];\n} {\n const allow = permissions.allow || [];\n const deny = permissions.deny || [];\n const ask = permissions.ask || [];\n\n const denySet = new Set(deny);\n const subsumed: string[] = [];\n let conflictCount = 0;\n\n // Check each allow permission against deny permissions\n const allowToRemove = new Set<string>();\n\n for (const allowPerm of allow) {\n // Exact match: move to deny\n if (denySet.has(allowPerm)) {\n allowToRemove.add(allowPerm);\n conflictCount++;\n continue;\n }\n\n // Check if any deny permission subsumes this allow permission\n for (const denyPerm of deny) {\n try {\n const allowParsed = parsePermission(allowPerm, \"allow\");\n const denyParsed = parsePermission(denyPerm, \"deny\");\n\n if (subsumes(denyParsed, allowParsed)) {\n // Deny subsumes allow - remove from allow\n allowToRemove.add(allowPerm);\n subsumed.push(allowPerm);\n conflictCount++;\n break;\n }\n } catch {\n // Skip malformed permissions\n continue;\n }\n }\n }\n\n // Build resolved permissions\n const resolved: Permissions = {\n allow: allow.filter((p) => !allowToRemove.has(p)),\n deny,\n ask,\n };\n\n return { resolved, conflictCount, subsumed };\n}\n","/**\n * Backup management for Claude Code settings files\n */\nimport fs from \"fs/promises\";\n\n/**\n * Create a timestamped backup of a settings file\n *\n * Backup format: `<original-path>.backup.YYYY-MM-DD-HHmmss`\n *\n * Example: `settings.json.backup.2026-01-08-143022`\n *\n * @param settingsPath - Absolute path to settings file to back up\n * @returns Promise resolving to backup file path\n * @throws Error if source file doesn't exist or backup fails\n *\n * @example\n * ```typescript\n * const backupPath = await createBackup(\"/Users/shz/.claude/settings.json\");\n * // Returns: \"/Users/shz/.claude/settings.json.backup.2026-01-08-143022\"\n * ```\n */\nexport async function createBackup(settingsPath: string): Promise<string> {\n try {\n // Verify source file exists\n await fs.access(settingsPath, fs.constants.R_OK);\n\n // Generate timestamp: YYYY-MM-DD-HHmmss\n const now = new Date();\n const timestamp = [\n now.getFullYear(),\n String(now.getMonth() + 1).padStart(2, \"0\"),\n String(now.getDate()).padStart(2, \"0\"),\n ].join(\"-\") + \"-\" + [\n String(now.getHours()).padStart(2, \"0\"),\n String(now.getMinutes()).padStart(2, \"0\"),\n String(now.getSeconds()).padStart(2, \"0\"),\n ].join(\"\");\n\n // Build backup path\n const backupPath = `${settingsPath}.backup.${timestamp}`;\n\n // Copy file to backup location\n await fs.copyFile(settingsPath, backupPath);\n\n return backupPath;\n } catch (error) {\n if (error instanceof Error) {\n if (error.message.includes(\"ENOENT\")) {\n throw new Error(`Settings file not found: ${settingsPath}`);\n }\n if (error.message.includes(\"EACCES\")) {\n throw new Error(`Permission denied: ${settingsPath}`);\n }\n throw new Error(`Failed to create backup: ${error.message}`);\n }\n throw error;\n }\n}\n","/**\n * Formatting and reporting of consolidation results\n */\nimport type { ConsolidationResult } from \"../permissions/types\";\n\n/**\n * Format consolidation result as user-friendly text report\n *\n * Shows:\n * - Files scanned/processed/skipped\n * - Permissions added by category (allow/deny/ask)\n * - Conflicts resolved\n * - Subsumed permissions removed\n * - Backup path (if created)\n * - Instructions (if preview mode) or confirmation (if written)\n *\n * @param result - Consolidation result data\n * @param previewOnly - Whether this is preview-only mode (default behavior)\n * @param globalSettingsPath - Path to global settings file\n * @param outputFile - Optional output file path\n * @returns Formatted report string\n *\n * @example\n * ```typescript\n * const result = {\n * filesScanned: 12,\n * filesProcessed: 10,\n * filesSkipped: 2,\n * added: {\n * allow: [\"Bash(git:*)\", \"Bash(npm:*)\"],\n * deny: [\"Bash(rm:*)\"],\n * ask: []\n * },\n * subsumed: [\"Bash(git log:*)\", \"Bash(git worktree:*)\"],\n * conflictsResolved: 1,\n * backupPath: \"/Users/shz/.claude/settings.json.backup.2026-01-08-143022\"\n * };\n *\n * console.log(formatReport(result, true, \"/Users/shz/.claude/settings.json\"));\n * // Outputs formatted report with instructions\n * ```\n */\nexport function formatReport(\n result: ConsolidationResult,\n previewOnly: boolean,\n globalSettingsPath?: string,\n outputFile?: string,\n): string {\n const lines: string[] = [];\n\n // Header\n lines.push(\"Scanning for Claude Code settings files...\");\n lines.push(\"\");\n\n // Files summary\n lines.push(`Found ${result.filesScanned} settings files`);\n lines.push(` Processed: ${result.filesProcessed}`);\n if (result.filesSkipped > 0) {\n lines.push(` Skipped: ${result.filesSkipped} (no permissions)`);\n }\n lines.push(\"\");\n\n // Permissions added\n const totalAdded = result.added.allow.length\n + result.added.deny.length\n + result.added.ask.length;\n\n if (totalAdded > 0) {\n lines.push(`Permissions to add: ${totalAdded}`);\n\n if (result.added.allow.length > 0) {\n lines.push(\"\");\n lines.push(\" allow:\");\n for (const perm of result.added.allow) {\n lines.push(` + ${perm}`);\n }\n }\n\n if (result.added.deny.length > 0) {\n lines.push(\"\");\n lines.push(\" deny:\");\n for (const perm of result.added.deny) {\n lines.push(` + ${perm}`);\n }\n }\n\n if (result.added.ask.length > 0) {\n lines.push(\"\");\n lines.push(\" ask:\");\n for (const perm of result.added.ask) {\n lines.push(` + ${perm}`);\n }\n }\n } else {\n lines.push(\"No new permissions to add (all permissions already in global settings)\");\n }\n\n lines.push(\"\");\n\n // Subsumption results\n if (result.subsumed.length > 0) {\n lines.push(`Subsumed permissions removed: ${result.subsumed.length}`);\n lines.push(\" (narrower permissions replaced by broader ones)\");\n for (const perm of result.subsumed) {\n lines.push(` - ${perm}`);\n }\n lines.push(\"\");\n }\n\n // Conflicts\n if (result.conflictsResolved > 0) {\n lines.push(`Conflicts resolved: ${result.conflictsResolved}`);\n lines.push(\" (permissions moved from allow to deny)\");\n lines.push(\"\");\n }\n\n // Backup\n if (result.backupPath) {\n lines.push(`Backup created: ${result.backupPath}`);\n lines.push(\"\");\n }\n\n // Summary\n lines.push(\"Summary:\");\n lines.push(` Files scanned: ${result.filesScanned}`);\n lines.push(\n ` Permissions added: ${result.added.allow.length} allow, ${result.added.deny.length} deny, ${result.added.ask.length} ask`,\n );\n if (result.subsumed.length > 0) {\n lines.push(` Subsumed removed: ${result.subsumed.length}`);\n }\n if (result.conflictsResolved > 0) {\n lines.push(` Conflicts resolved: ${result.conflictsResolved}`);\n }\n\n // Final status message\n lines.push(\"\");\n if (previewOnly) {\n lines.push(\"ℹ️ Preview mode: No changes written\");\n lines.push(\"\");\n lines.push(\"To apply changes:\");\n lines.push(` • Modify global settings: spx claude settings consolidate --write`);\n lines.push(` • Write to file: spx claude settings consolidate --output-file /path/to/file`);\n } else if (outputFile) {\n lines.push(`✓ Settings written to: ${result.outputPath || outputFile}`);\n lines.push(\"\");\n lines.push(\"To apply to your global settings:\");\n lines.push(` • Review the file, then copy to: ${globalSettingsPath || \"~/.claude/settings.json\"}`);\n lines.push(` • Or run: spx claude settings consolidate --write`);\n } else {\n lines.push(`✓ Global settings updated: ${globalSettingsPath || \"~/.claude/settings.json\"}`);\n }\n\n return lines.join(\"\\n\");\n}\n","/**\n * Atomic file writing for Claude Code settings\n */\nimport fs from \"fs/promises\";\nimport os from \"os\";\nimport path from \"path\";\nimport type { ClaudeSettings } from \"../permissions/types\";\n\n/**\n * Filesystem abstraction for dependency injection\n *\n * Enables testing error paths without mocking.\n */\nexport interface FileSystem {\n writeFile(path: string, content: string): Promise<void>;\n rename(oldPath: string, newPath: string): Promise<void>;\n unlink(path: string): Promise<void>;\n mkdir(path: string, options?: { recursive?: boolean }): Promise<void>;\n}\n\n/**\n * Production filesystem implementation\n */\nconst realFs: FileSystem = {\n writeFile: (path, content) => fs.writeFile(path, content, \"utf-8\"),\n rename: fs.rename,\n unlink: fs.unlink,\n mkdir: async (path, options) => {\n await fs.mkdir(path, options);\n },\n};\n\n/**\n * Atomically write settings to a file\n *\n * Uses temp file + rename pattern for atomicity:\n * 1. Write to temporary file\n * 2. Rename to target (atomic operation on most filesystems)\n *\n * Preserves JSON formatting with 2-space indentation.\n *\n * @param filePath - Absolute path to settings file\n * @param settings - Settings object to write\n * @param deps - Dependencies (for testing)\n * @throws Error if write fails\n *\n * @example\n * ```typescript\n * const settings = {\n * permissions: {\n * allow: [\"Bash(git:*)\", \"Bash(npm:*)\"]\n * }\n * };\n * await writeSettings(\"/Users/shz/.claude/settings.json\", settings);\n * ```\n */\nexport async function writeSettings(\n filePath: string,\n settings: ClaudeSettings,\n deps: { fs: FileSystem } = { fs: realFs },\n): Promise<void> {\n // Ensure directory exists\n const dir = path.dirname(filePath);\n await deps.fs.mkdir(dir, { recursive: true });\n\n // Generate temporary file path\n const tempPath = path.join(\n os.tmpdir(),\n `settings-${Date.now()}-${Math.random().toString(36).substring(7)}.json`,\n );\n\n try {\n // Format JSON with 2-space indentation and trailing newline\n const content = JSON.stringify(settings, null, 2) + \"\\n\";\n\n // Write to temp file\n await deps.fs.writeFile(tempPath, content);\n\n // Atomic rename\n await deps.fs.rename(tempPath, filePath);\n } catch (error) {\n // Cleanup temp file on failure\n try {\n await deps.fs.unlink(tempPath);\n } catch {\n // Ignore cleanup errors\n }\n\n // Re-throw original error\n if (error instanceof Error) {\n throw new Error(`Failed to write settings: ${error.message}`);\n }\n throw error;\n }\n}\n","/**\n * Consolidate command implementation\n *\n * Orchestrates the full consolidation pipeline:\n * 1. Discovery - Find all settings.local.json files\n * 2. Parsing - Extract permissions from each file\n * 3. Merging - Combine with subsumption and conflict resolution\n * 4. Backup - Create timestamped backup (if not dry-run)\n * 5. Writing - Atomically write merged settings (if not dry-run)\n * 6. Reporting - Format and return result summary\n */\nimport { findSettingsFiles } from \"@/lib/claude/permissions/discovery\";\nimport { mergePermissions } from \"@/lib/claude/permissions/merger\";\nimport { parseAllSettings, parseSettingsFile } from \"@/lib/claude/permissions/parser\";\nimport { createBackup } from \"@/lib/claude/settings/backup\";\nimport { formatReport } from \"@/lib/claude/settings/reporter\";\nimport { writeSettings } from \"@/lib/claude/settings/writer\";\nimport os from \"os\";\nimport path from \"path\";\n\n/**\n * Options for consolidate command\n */\nexport interface ConsolidateOptions {\n /** Root directory to scan for settings files (default: ~/Code) */\n root?: string;\n /** Write changes to global settings file (default: false = preview only) */\n write?: boolean;\n /** Write merged settings to specified file instead of global settings */\n outputFile?: string;\n /** Path to global settings file (for testing; default: ~/.claude/settings.json) */\n globalSettings?: string;\n}\n\n/**\n * Execute settings consolidate command\n *\n * Consolidates permissions from project-local settings files into\n * the global Claude Code settings file.\n *\n * Features:\n * - Discovers all `.claude/settings.local.json` files recursively\n * - Applies subsumption to remove narrower permissions\n * - Resolves conflicts (deny wins over allow)\n * - Deduplicates and sorts permissions\n * - Creates backup before modifications\n * - Supports dry-run mode for preview\n *\n * @param options - Command options\n * @returns Formatted report string\n * @throws Error if discovery, parsing, or writing fails\n *\n * @example\n * ```typescript\n * // Normal consolidation\n * const output = await consolidateCommand({ root: \"~/Code\" });\n * console.log(output);\n *\n * // Dry-run preview\n * const preview = await consolidateCommand({ root: \"~/Code\", dryRun: true });\n * console.log(preview);\n * ```\n */\nexport async function consolidateCommand(\n options: ConsolidateOptions = {},\n): Promise<string> {\n // Resolve paths\n const root = options.root\n ? path.resolve(options.root.replace(/^~/, os.homedir()))\n : path.join(os.homedir(), \"Code\");\n\n const globalSettingsPath = options.globalSettings\n || path.join(os.homedir(), \".claude\", \"settings.json\");\n\n const shouldWrite = options.write || false;\n const outputFile = options.outputFile;\n const previewOnly = !shouldWrite && !outputFile;\n\n // Step 1: Discovery - find all settings.local.json files\n const settingsFiles = await findSettingsFiles(root);\n\n if (settingsFiles.length === 0) {\n return `No settings files found in ${root}\\n\\nSearched for: **/.claude/settings.local.json`;\n }\n\n // Step 2: Parsing - extract permissions from each file\n const localPermissions = await parseAllSettings(settingsFiles);\n\n // Step 3: Read global settings\n let globalSettings = await parseSettingsFile(globalSettingsPath);\n\n // If global settings doesn't exist, create empty structure\n if (!globalSettings) {\n globalSettings = {\n permissions: {\n allow: [],\n deny: [],\n ask: [],\n },\n };\n }\n\n // Ensure permissions object exists\n if (!globalSettings.permissions) {\n globalSettings.permissions = {\n allow: [],\n deny: [],\n ask: [],\n };\n }\n\n // Step 4: Merge with subsumption and conflict resolution\n const { merged, result } = mergePermissions(\n globalSettings.permissions,\n localPermissions,\n );\n\n // Step 5: Backup (only when writing to global settings)\n if (shouldWrite) {\n try {\n result.backupPath = await createBackup(globalSettingsPath);\n } catch (error) {\n // If backup fails because file doesn't exist, that's okay (first time)\n if (error instanceof Error && !error.message.includes(\"not found\")) {\n throw error;\n }\n }\n }\n\n // Step 6: Write (if --write or --output-file specified)\n if (shouldWrite) {\n const updatedSettings = {\n ...globalSettings,\n permissions: merged,\n };\n await writeSettings(globalSettingsPath, updatedSettings);\n } else if (outputFile) {\n const updatedSettings = {\n ...globalSettings,\n permissions: merged,\n };\n const resolvedOutputPath = path.resolve(outputFile.replace(/^~/, os.homedir()));\n await writeSettings(resolvedOutputPath, updatedSettings);\n result.outputPath = resolvedOutputPath;\n }\n\n // Step 7: Report\n return formatReport(result, previewOnly, globalSettingsPath, outputFile);\n}\n","/**\n * Claude domain - Manage Claude Code settings and plugins\n */\nimport { initCommand } from \"@/commands/claude/init\";\nimport { consolidateCommand } from \"@/commands/claude/settings/consolidate\";\nimport type { Command } from \"commander\";\nimport type { Domain } from \"../types\";\n\n/**\n * Register claude domain commands\n *\n * @param claudeCmd - Commander.js claude domain command\n */\nfunction registerClaudeCommands(claudeCmd: Command): void {\n // init command\n claudeCmd\n .command(\"init\")\n .description(\"Initialize or update outcomeeng marketplace plugin\")\n .action(async () => {\n try {\n const output = await initCommand({ cwd: process.cwd() });\n console.log(output);\n } catch (error) {\n console.error(\n \"Error:\",\n error instanceof Error ? error.message : String(error),\n );\n process.exit(1);\n }\n });\n\n // settings subcommand group\n const settingsCmd = claudeCmd\n .command(\"settings\")\n .description(\"Manage Claude Code settings\");\n\n // settings consolidate command\n settingsCmd\n .command(\"consolidate\")\n .description(\n \"Consolidate permissions from project-specific settings into global settings\",\n )\n .option(\"--write\", \"Write changes to global settings file (default: preview only)\")\n .option(\n \"--output-file <path>\",\n \"Write merged settings to specified file instead of global settings\",\n )\n .option(\n \"--root <path>\",\n \"Root directory to scan for settings files (default: ~/Code)\",\n )\n .option(\n \"--global-settings <path>\",\n \"Path to global settings file (default: ~/.claude/settings.json)\",\n )\n .action(\n async (options: {\n write?: boolean;\n outputFile?: string;\n root?: string;\n globalSettings?: string;\n }) => {\n try {\n // Validate mutually exclusive options\n if (options.write && options.outputFile) {\n console.error(\n \"Error: --write and --output-file are mutually exclusive\\n\"\n + \"Use --write to modify global settings, or --output-file to write to a different location\",\n );\n process.exit(1);\n }\n\n const output = await consolidateCommand({\n write: options.write,\n outputFile: options.outputFile,\n root: options.root,\n globalSettings: options.globalSettings,\n });\n console.log(output);\n } catch (error) {\n console.error(\n \"Error:\",\n error instanceof Error ? error.message : String(error),\n );\n process.exit(1);\n }\n },\n );\n}\n\n/**\n * Claude domain - Manage Claude Code settings and plugins\n */\nexport const claudeDomain: Domain = {\n name: \"claude\",\n description: \"Manage Claude Code settings and plugins\",\n register: (program: Command) => {\n const claudeCmd = program\n .command(\"claude\")\n .description(\"Manage Claude Code settings and plugins\");\n\n registerClaudeCommands(claudeCmd);\n },\n};\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parse as parseToml, stringify as stringifyToml } from \"smol-toml\";\nimport { parse as parseYaml, parseDocument as parseYamlDocument, stringify as stringifyYaml } from \"yaml\";\n\nimport { productionRegistry } from \"./registry\";\nimport type { Config, ConfigDescriptor, Result } from \"./types\";\n\nexport const CONFIG_FILE_FORMAT = {\n JSON: \"json\",\n YAML: \"yaml\",\n TOML: \"toml\",\n} as const;\n\nexport type ConfigFileFormat = (typeof CONFIG_FILE_FORMAT)[keyof typeof CONFIG_FILE_FORMAT];\n\nexport const CONFIG_FILE_DEFINITIONS = {\n [CONFIG_FILE_FORMAT.JSON]: {\n format: CONFIG_FILE_FORMAT.JSON,\n filename: \"spx.config.json\",\n },\n [CONFIG_FILE_FORMAT.YAML]: {\n format: CONFIG_FILE_FORMAT.YAML,\n filename: \"spx.config.yaml\",\n },\n [CONFIG_FILE_FORMAT.TOML]: {\n format: CONFIG_FILE_FORMAT.TOML,\n filename: \"spx.config.toml\",\n },\n} as const;\n\nexport const CONFIG_FILE_FORMAT_ORDER = [\n CONFIG_FILE_FORMAT.JSON,\n CONFIG_FILE_FORMAT.YAML,\n CONFIG_FILE_FORMAT.TOML,\n] as const;\n\nexport const DEFAULT_CONFIG_FILE_FORMAT = CONFIG_FILE_FORMAT.YAML;\n\nexport const CONFIG_FILENAMES = {\n json: CONFIG_FILE_DEFINITIONS[CONFIG_FILE_FORMAT.JSON].filename,\n yaml: CONFIG_FILE_DEFINITIONS[CONFIG_FILE_FORMAT.YAML].filename,\n toml: CONFIG_FILE_DEFINITIONS[CONFIG_FILE_FORMAT.TOML].filename,\n} as const;\n\nexport type ConfigFilename = (typeof CONFIG_FILENAMES)[keyof typeof CONFIG_FILENAMES];\n\nexport const DEFAULT_CONFIG_FILENAME = CONFIG_FILE_DEFINITIONS[DEFAULT_CONFIG_FILE_FORMAT].filename;\n\nexport type ConfigFile = {\n readonly filename: ConfigFilename;\n readonly format: ConfigFileFormat;\n readonly path: string;\n readonly raw: string;\n};\n\nexport type ConfigFileReadResult =\n | { readonly kind: \"ok\"; readonly file: ConfigFile }\n | { readonly kind: \"ambiguous\"; readonly detected: readonly ConfigFilename[] }\n | { readonly kind: \"absent\" };\n\nconst JSON_INDENT = 2;\n\nexport async function resolveConfig(\n projectRoot: string,\n descriptors: readonly ConfigDescriptor<unknown>[] = productionRegistry,\n): Promise<Result<Config>> {\n const detectedResult = await readProjectConfigFile(projectRoot);\n if (!detectedResult.ok) return detectedResult;\n\n const detected = detectedResult.value;\n if (detected.kind === \"ambiguous\") {\n return { ok: false, error: formatConfigFileAmbiguityError(detected.detected) };\n }\n\n const sectionsResult = detected.kind === \"absent\"\n ? ({ ok: true as const, value: {} as Record<string, unknown> })\n : parseConfigFileSections(detected.file);\n if (!sectionsResult.ok) {\n return sectionsResult;\n }\n const sections = sectionsResult.value;\n\n const resolved: Record<string, unknown> = {};\n for (const descriptor of descriptors) {\n const sectionValue = sections[descriptor.section];\n if (sectionValue === undefined) {\n resolved[descriptor.section] = descriptor.defaults;\n continue;\n }\n const validated = descriptor.validate(sectionValue);\n if (!validated.ok) {\n return { ok: false, error: `${descriptor.section}: ${validated.error}` };\n }\n resolved[descriptor.section] = validated.value;\n }\n\n return { ok: true, value: resolved };\n}\n\nexport async function readProjectConfigFile(projectRoot: string): Promise<Result<ConfigFileReadResult>> {\n const detected: ConfigFile[] = [];\n for (const format of CONFIG_FILE_FORMAT_ORDER) {\n const filename = CONFIG_FILE_DEFINITIONS[format].filename;\n const path = join(projectRoot, filename);\n let raw: string;\n try {\n raw = await readFile(path, \"utf8\");\n } catch (error) {\n if (isFileNotFound(error)) continue;\n return { ok: false, error: `failed to read ${filename}: ${toMessage(error)}` };\n }\n detected.push({ filename, format, path, raw });\n }\n if (detected.length === 0) return { ok: true, value: { kind: \"absent\" } };\n if (detected.length > 1) {\n return {\n ok: true,\n value: {\n kind: \"ambiguous\",\n detected: detected.map((file) => file.filename),\n },\n };\n }\n return { ok: true, value: { kind: \"ok\", file: detected[0] } };\n}\n\nexport function configFileForFormat(\n projectRoot: string,\n format: ConfigFileFormat = DEFAULT_CONFIG_FILE_FORMAT,\n raw = \"\",\n): ConfigFile {\n const filename = CONFIG_FILE_DEFINITIONS[format].filename;\n return {\n filename,\n format,\n path: join(projectRoot, filename),\n raw,\n };\n}\n\nexport function formatConfigFileAmbiguityError(detected: readonly ConfigFilename[]): string {\n return `multiple config files found: ${detected.join(\", \")}`;\n}\n\nexport function parseConfigFileSections(file: ConfigFile): Result<Record<string, unknown>> {\n if (file.raw.trim() === \"\") return { ok: true, value: {} };\n switch (file.format) {\n case CONFIG_FILE_FORMAT.JSON:\n return parseJsonSections(file.filename, file.raw);\n case CONFIG_FILE_FORMAT.YAML:\n return parseYamlSections(file.filename, file.raw);\n case CONFIG_FILE_FORMAT.TOML:\n return parseTomlSections(file.filename, file.raw);\n }\n}\n\nexport function serializeConfigFileSections(\n format: ConfigFileFormat,\n sections: Record<string, unknown>,\n): Result<string> {\n switch (format) {\n case CONFIG_FILE_FORMAT.JSON:\n return { ok: true, value: JSON.stringify(sections, null, JSON_INDENT) + \"\\n\" };\n case CONFIG_FILE_FORMAT.YAML:\n return { ok: true, value: stringifyYaml(sections) };\n case CONFIG_FILE_FORMAT.TOML:\n return serializeTomlSections(sections);\n }\n}\n\nexport function serializeConfigFileSectionsWithSetIn(\n file: ConfigFile,\n path: readonly string[],\n value: unknown,\n): Result<string> {\n if (path.length === 0) {\n return { ok: false, error: \"config mutation path must not be empty\" };\n }\n switch (file.format) {\n case CONFIG_FILE_FORMAT.YAML:\n return serializeYamlSectionsWithSetIn(file, path, value);\n case CONFIG_FILE_FORMAT.JSON:\n case CONFIG_FILE_FORMAT.TOML: {\n const sections = parseConfigFileSections(file);\n if (!sections.ok) return sections;\n setNested(sections.value, path, value);\n return serializeConfigFileSections(file.format, sections.value);\n }\n }\n}\n\nfunction parseJsonSections(filename: string, raw: string): Result<Record<string, unknown>> {\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw) as unknown;\n } catch (error) {\n return { ok: false, error: `${filename} is not valid ${CONFIG_FILE_FORMAT.JSON}: ${toMessage(error)}` };\n }\n return validateParsedSections(filename, parsed);\n}\n\nfunction parseYamlSections(filename: string, raw: string): Result<Record<string, unknown>> {\n let parsed: unknown;\n try {\n parsed = parseYaml(raw) as unknown;\n } catch (error) {\n return { ok: false, error: `${filename} is not valid ${CONFIG_FILE_FORMAT.YAML}: ${toMessage(error)}` };\n }\n if (parsed === null || parsed === undefined) {\n return { ok: true, value: {} };\n }\n return validateParsedSections(filename, parsed);\n}\n\nfunction parseTomlSections(filename: string, raw: string): Result<Record<string, unknown>> {\n let parsed: unknown;\n try {\n parsed = parseToml(raw) as unknown;\n } catch (error) {\n return { ok: false, error: `${filename} is not valid ${CONFIG_FILE_FORMAT.TOML}: ${toMessage(error)}` };\n }\n return validateParsedSections(filename, parsed);\n}\n\nfunction serializeTomlSections(sections: Record<string, unknown>): Result<string> {\n try {\n return { ok: true, value: stringifyToml(sections) };\n } catch (error) {\n return {\n ok: false,\n error: `config is not serializable as ${CONFIG_FILE_FORMAT.TOML}: ${toMessage(error)}`,\n };\n }\n}\n\nfunction serializeYamlSectionsWithSetIn(\n file: ConfigFile,\n path: readonly string[],\n value: unknown,\n): Result<string> {\n try {\n const doc = parseYamlDocument(file.raw.trim() === \"\" ? \"{}\\n\" : file.raw);\n if (doc.errors.length > 0) {\n return {\n ok: false,\n error: `${file.filename} is not valid ${CONFIG_FILE_FORMAT.YAML}: ${doc.errors[0].message}`,\n };\n }\n doc.setIn([...path], value);\n return { ok: true, value: String(doc) };\n } catch (error) {\n return { ok: false, error: `${file.filename} is not valid ${CONFIG_FILE_FORMAT.YAML}: ${toMessage(error)}` };\n }\n}\n\nfunction setNested(target: Record<string, unknown>, path: readonly string[], value: unknown): void {\n let cursor: Record<string, unknown> = target;\n for (let i = 0; i < path.length - 1; i += 1) {\n const key = path[i];\n const existing = cursor[key];\n if (typeof existing === \"object\" && existing !== null && !Array.isArray(existing)) {\n cursor = existing as Record<string, unknown>;\n } else {\n const fresh: Record<string, unknown> = {};\n cursor[key] = fresh;\n cursor = fresh;\n }\n }\n cursor[path[path.length - 1]] = value;\n}\n\nfunction validateParsedSections(filename: string, parsed: unknown): Result<Record<string, unknown>> {\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n return { ok: false, error: `${filename} must parse to a mapping of descriptor sections` };\n }\n return { ok: true, value: parsed as Record<string, unknown> };\n}\n\nfunction isFileNotFound(error: unknown): boolean {\n return error instanceof Error && \"code\" in error && (error as NodeJS.ErrnoException).code === \"ENOENT\";\n}\n\nfunction toMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n","import type { ConfigDescriptor, Result } from \"@/config/types\";\n\nconst SPEC_TREE_KIND_CATEGORY_VALUES = {\n NODE: \"node\",\n DECISION: \"decision\",\n} as const;\n\nconst SPEC_TREE_EMPTY_ALIASES = [] as const;\n\nexport const SPEC_TREE_CONFIG = {\n SECTION: \"specTree\",\n ROOT_DIRECTORY: \"spx\",\n PRODUCT: {\n LABEL: \"Product\",\n SUFFIX: \".product.md\",\n },\n CATEGORY: SPEC_TREE_KIND_CATEGORY_VALUES,\n KINDS: {\n enabler: {\n category: SPEC_TREE_KIND_CATEGORY_VALUES.NODE,\n label: \"Enabler\",\n suffix: \".enabler\",\n aliases: SPEC_TREE_EMPTY_ALIASES,\n },\n outcome: {\n category: SPEC_TREE_KIND_CATEGORY_VALUES.NODE,\n label: \"Outcome\",\n suffix: \".outcome\",\n aliases: SPEC_TREE_EMPTY_ALIASES,\n },\n adr: {\n category: SPEC_TREE_KIND_CATEGORY_VALUES.DECISION,\n label: \"ADR\",\n suffix: \".adr.md\",\n aliases: SPEC_TREE_EMPTY_ALIASES,\n },\n pdr: {\n category: SPEC_TREE_KIND_CATEGORY_VALUES.DECISION,\n label: \"PDR\",\n suffix: \".pdr.md\",\n aliases: SPEC_TREE_EMPTY_ALIASES,\n },\n },\n} as const;\n\nexport const SPEC_TREE_KIND_CATEGORY = SPEC_TREE_CONFIG.CATEGORY;\n\nexport type SpecTreeKindCategory = (typeof SPEC_TREE_KIND_CATEGORY)[keyof typeof SPEC_TREE_KIND_CATEGORY];\n\nexport const KIND_REGISTRY = SPEC_TREE_CONFIG.KINDS;\n\nexport type Kind = keyof typeof KIND_REGISTRY;\nexport type KindDefinition<K extends Kind> = (typeof KIND_REGISTRY)[K];\n\nexport type NodeKind = {\n [K in Kind]: (typeof KIND_REGISTRY)[K][\"category\"] extends typeof SPEC_TREE_KIND_CATEGORY.NODE ? K : never;\n}[Kind];\n\nexport type DecisionKind = {\n [K in Kind]: (typeof KIND_REGISTRY)[K][\"category\"] extends typeof SPEC_TREE_KIND_CATEGORY.DECISION ? K : never;\n}[Kind];\n\nexport const SPEC_TREE_ADR_KIND: DecisionKind = \"adr\";\n\nexport const NODE_KINDS: readonly NodeKind[] = (Object.keys(KIND_REGISTRY) as Kind[]).filter(\n (k): k is NodeKind => KIND_REGISTRY[k].category === SPEC_TREE_KIND_CATEGORY.NODE,\n);\n\nexport const DECISION_KINDS: readonly DecisionKind[] = (Object.keys(KIND_REGISTRY) as Kind[]).filter(\n (k): k is DecisionKind => KIND_REGISTRY[k].category === SPEC_TREE_KIND_CATEGORY.DECISION,\n);\n\nexport const NODE_SUFFIXES: readonly string[] = NODE_KINDS.map((k) => KIND_REGISTRY[k].suffix);\nexport const DECISION_SUFFIXES: readonly string[] = DECISION_KINDS.map((k) => KIND_REGISTRY[k].suffix);\n\nexport type SpecTreeConfig = {\n readonly kinds: { readonly [K in Kind]?: KindDefinition<K> };\n};\n\nexport const SPEC_TREE_SECTION = SPEC_TREE_CONFIG.SECTION;\n\nfunction isKind(value: string): value is Kind {\n return Object.prototype.hasOwnProperty.call(KIND_REGISTRY, value);\n}\n\nfunction buildDefaults(): SpecTreeConfig {\n return { kinds: { ...KIND_REGISTRY } };\n}\n\nfunction buildConfigFromKindNames(kindNames: readonly Kind[]): SpecTreeConfig {\n const entries = kindNames.map((kind) => [kind, KIND_REGISTRY[kind]] as const);\n return { kinds: Object.fromEntries(entries) as SpecTreeConfig[\"kinds\"] };\n}\n\nfunction validate(value: unknown): Result<SpecTreeConfig> {\n if (typeof value !== \"object\" || value === null) {\n return { ok: false, error: `${SPEC_TREE_SECTION} section must be an object` };\n }\n const candidate = value as { kinds?: unknown };\n if (Array.isArray(candidate.kinds)) {\n return validateKindList(candidate.kinds);\n }\n if (\n typeof candidate.kinds !== \"object\"\n || candidate.kinds === null\n ) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds must be an array of registry kind names`,\n };\n }\n\n return validateKindDefinitionMap(candidate.kinds as Record<string, unknown>);\n}\n\nfunction validateKindList(kinds: readonly unknown[]): Result<SpecTreeConfig> {\n const kindNames: Kind[] = [];\n for (const entry of kinds) {\n if (typeof entry !== \"string\") {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds entries must be registry kind names`,\n };\n }\n if (!isKind(entry)) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds contains unknown kind \"${entry}\"`,\n };\n }\n kindNames.push(entry);\n }\n\n const duplicateKinds = kindNames.filter((kind, index) => kindNames.indexOf(kind) !== index);\n if (duplicateKinds.length > 0) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds contains duplicate kind \"${duplicateKinds[0]}\"`,\n };\n }\n\n return { ok: true, value: buildConfigFromKindNames(kindNames) };\n}\n\nfunction validateKindDefinitionMap(kindEntries: Record<string, unknown>): Result<SpecTreeConfig> {\n const entries: Array<[Kind, KindDefinition<Kind>]> = [];\n for (const [key, entry] of Object.entries(kindEntries)) {\n if (!isKind(key)) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds contains unknown kind \"${key}\"`,\n };\n }\n if (typeof entry !== \"object\" || entry === null) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key} must be an object with registry metadata`,\n };\n }\n const def = entry as { category?: unknown; suffix?: unknown };\n const expected = KIND_REGISTRY[key];\n if (def.category !== expected.category) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key}.category must be \"${expected.category}\"`,\n };\n }\n if ((entry as { label?: unknown }).label !== expected.label) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key}.label must be \"${expected.label}\"`,\n };\n }\n if (def.suffix !== expected.suffix) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key}.suffix must be \"${expected.suffix}\"`,\n };\n }\n const aliases = (entry as { aliases?: unknown }).aliases;\n if (!Array.isArray(aliases) || aliases.some((alias) => typeof alias !== \"string\")) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key}.aliases must be an array of strings`,\n };\n }\n if (\n aliases.length !== expected.aliases.length || aliases.some((alias, index) => alias !== expected.aliases[index])\n ) {\n return {\n ok: false,\n error: `${SPEC_TREE_SECTION}.kinds.${key}.aliases must match the registry definition`,\n };\n }\n entries.push([key, expected]);\n }\n\n const kinds = Object.fromEntries(entries) as SpecTreeConfig[\"kinds\"];\n return { ok: true, value: { kinds } };\n}\n\nexport const specTreeConfigDescriptor: ConfigDescriptor<SpecTreeConfig> = {\n section: SPEC_TREE_SECTION,\n defaults: buildDefaults(),\n validate,\n};\n","import type { AdapterConfig, ScopeResult } from \"../types\";\n\nexport function eslintAdapter(scope: ScopeResult, config: AdapterConfig): readonly string[] {\n return scope.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);\n}\n","import type { AdapterConfig, ScopeResult } from \"../types\";\n\nexport function knipAdapter(scope: ScopeResult, config: AdapterConfig): readonly string[] {\n return scope.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);\n}\n","import type { AdapterConfig, ScopeResult } from \"../types\";\n\nexport function madgeAdapter(scope: ScopeResult, config: AdapterConfig): readonly string[] {\n return scope.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);\n}\n","import type { AdapterConfig, ScopeResult } from \"../types\";\n\nexport function markdownlintAdapter(scope: ScopeResult, config: AdapterConfig): readonly string[] {\n return scope.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);\n}\n","import type { AdapterConfig, ScopeResult } from \"../types\";\n\nexport function pytestAdapter(scope: ScopeResult, config: AdapterConfig): readonly string[] {\n return scope.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);\n}\n","import type { AdapterConfig, ScopeResult } from \"../types\";\n\nexport function tscAdapter(scope: ScopeResult, config: AdapterConfig): readonly string[] {\n return scope.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);\n}\n","import type { AdapterConfig, ScopeResult } from \"../types\";\n\nexport function vitestAdapter(scope: ScopeResult, config: AdapterConfig): readonly string[] {\n return scope.excluded.flatMap((entry) => [config.ignoreFlag, entry.path]);\n}\n","import type { ScopeResult } from \"../types\";\nimport type { AdapterConfig, ToolAdapterFn, ToolAdaptersConfig } from \"../types\";\n\nimport { eslintAdapter } from \"./eslint\";\nimport { knipAdapter } from \"./knip\";\nimport { madgeAdapter } from \"./madge\";\nimport { markdownlintAdapter } from \"./markdownlint\";\nimport { pytestAdapter } from \"./pytest\";\nimport { tscAdapter } from \"./tsc\";\nimport { vitestAdapter } from \"./vitest\";\n\nexport type { AdapterConfig, ToolAdapterFn, ToolAdaptersConfig };\n\nexport const TOOL_DEFAULT_FLAGS: Readonly<Record<string, string>> = {\n eslint: \"--ignore-pattern\",\n tsc: \"--exclude\",\n madge: \"--exclude\",\n knip: \"--exclude\",\n markdownlint: \"--ignore\",\n pytest: \"--ignore\",\n vitest: \"--exclude\",\n};\n\nconst ADAPTER_MAP: Readonly<Record<string, ToolAdapterFn>> = {\n eslint: eslintAdapter,\n tsc: tscAdapter,\n madge: madgeAdapter,\n knip: knipAdapter,\n markdownlint: markdownlintAdapter,\n pytest: pytestAdapter,\n vitest: vitestAdapter,\n};\n\nexport const REGISTERED_TOOL_NAMES: readonly string[] = Object.keys(ADAPTER_MAP);\n\nexport function toToolArguments(\n scope: ScopeResult,\n toolName: string,\n config: ToolAdaptersConfig,\n): readonly string[] {\n const adapter = ADAPTER_MAP[toolName];\n if (adapter === undefined) {\n throw new Error(\n `Unknown tool \"${toolName}\". Registered tools: ${REGISTERED_TOOL_NAMES.join(\", \")}`,\n );\n }\n const adapterConfig = config.tools[toolName];\n if (adapterConfig === undefined) {\n throw new Error(\n `No adapter config for tool \"${toolName}\". Registered tools: ${REGISTERED_TOOL_NAMES.join(\", \")}`,\n );\n }\n return adapter(scope, adapterConfig);\n}\n","import { readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nexport const IGNORE_SOURCE_FILENAME_DEFAULT = \"EXCLUDE\";\n\nexport type IgnoreSourceReaderConfig = {\n readonly ignoreSourceFilename: string;\n readonly specTreeRootSegment: string;\n};\n\nexport type IgnoreSourceEntry = {\n readonly segment: string;\n readonly lineNumber: number;\n};\n\nexport type IgnoreSourceReader = {\n isUnderIgnoreSource(relativePath: string): boolean;\n entries(): readonly IgnoreSourceEntry[];\n matchedEntry(relativePath: string): IgnoreSourceEntry | undefined;\n};\n\nexport const EMPTY_IGNORE_READER: IgnoreSourceReader = {\n isUnderIgnoreSource(): boolean {\n return false;\n },\n entries(): readonly IgnoreSourceEntry[] {\n return [];\n },\n matchedEntry(): IgnoreSourceEntry | undefined {\n return undefined;\n },\n};\n\nconst COMMENT_PREFIX = \"#\";\n\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && \"code\" in err;\n}\n\nfunction validateEntry(entry: string, lineNumber: number): void {\n if (entry.startsWith(\"/\")) {\n throw new Error(\n `Invalid ignore-source entry \"${entry}\" at line ${lineNumber}: absolute paths are not allowed`,\n );\n }\n const parts = entry.split(\"/\");\n for (const part of parts) {\n if (part === \"..\" || part === \".\" || part === \"\") {\n throw new Error(\n `Invalid ignore-source entry \"${entry}\" at line ${lineNumber}: empty segments, traversal sequences, and dot-relative prefixes are not allowed`,\n );\n }\n }\n}\n\nexport function createIgnoreSourceReader(\n projectRoot: string,\n config: IgnoreSourceReaderConfig,\n): IgnoreSourceReader {\n const { ignoreSourceFilename, specTreeRootSegment } = config;\n const filePath = join(projectRoot, specTreeRootSegment, ignoreSourceFilename);\n\n let content: string;\n try {\n content = readFileSync(filePath, \"utf8\");\n } catch (err) {\n if (isNodeError(err) && err.code === \"ENOENT\") {\n content = \"\";\n } else {\n throw err;\n }\n }\n\n const parsedEntries: IgnoreSourceEntry[] = [];\n const lines = content.split(\"\\n\");\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i]!.trim();\n if (trimmed.length === 0 || trimmed.startsWith(COMMENT_PREFIX)) continue;\n const lineNumber = i + 1;\n validateEntry(trimmed, lineNumber);\n parsedEntries.push({ segment: trimmed, lineNumber });\n }\n\n const prefixes = parsedEntries.map((e) => `${specTreeRootSegment}/${e.segment}/`);\n\n return {\n isUnderIgnoreSource(relativePath: string): boolean {\n return prefixes.some((prefix) => relativePath.startsWith(prefix));\n },\n entries(): readonly IgnoreSourceEntry[] {\n return parsedEntries;\n },\n matchedEntry(relativePath: string): IgnoreSourceEntry | undefined {\n return parsedEntries.find((entry) => relativePath.startsWith(`${specTreeRootSegment}/${entry.segment}/`));\n },\n };\n}\n","import type { ArtifactDirectoryConfig, LayerDecision } from \"../types\";\n\nexport const ARTIFACT_DIRECTORIES_DEFAULT = [\n \"node_modules\",\n \"dist\",\n \"build\",\n \".next\",\n \".source\",\n \".git\",\n \"out\",\n \"coverage\",\n] as const satisfies readonly string[];\n\nexport const ARTIFACT_DIRECTORY_LAYER = \"artifact-directory\";\nconst LAYER = ARTIFACT_DIRECTORY_LAYER;\n\nexport function artifactDirectoryPredicate(\n path: string,\n config: ArtifactDirectoryConfig,\n): LayerDecision {\n const segments = path.split(\"/\");\n for (const segment of segments) {\n if (config.artifactDirectories.includes(segment)) {\n return { matched: true, layer: LAYER, detail: segment };\n }\n }\n return { matched: false, layer: LAYER };\n}\n","import type { HiddenPrefixConfig, LayerDecision } from \"../types\";\n\nexport const HIDDEN_PREFIX_DEFAULT = \".\";\n\nexport const HIDDEN_PREFIX_LAYER = \"hidden-prefix\";\nconst LAYER = HIDDEN_PREFIX_LAYER;\n\nexport function hiddenPrefixPredicate(path: string, config: HiddenPrefixConfig): LayerDecision {\n const segments = path.split(\"/\");\n const basename = segments[segments.length - 1] ?? \"\";\n const matched = basename.startsWith(config.hiddenPrefix);\n return { matched, layer: LAYER };\n}\n","import type { ConfigDescriptor, Result } from \"@/config/types\";\nimport { SPEC_TREE_CONFIG } from \"@/lib/spec-tree/config\";\n\nimport { TOOL_DEFAULT_FLAGS } from \"./adapters\";\nimport { IGNORE_SOURCE_FILENAME_DEFAULT } from \"./ignore-source\";\nimport { ARTIFACT_DIRECTORIES_DEFAULT } from \"./predicates/artifact-directory\";\nimport { HIDDEN_PREFIX_DEFAULT } from \"./predicates/hidden-prefix\";\nimport type { ScopeResolverConfig, ToolAdaptersConfig } from \"./types\";\n\nexport const FILE_INCLUSION_SECTION = \"fileInclusion\";\n\nexport type FileInclusionConfig = {\n readonly scope: ScopeResolverConfig;\n readonly tools: ToolAdaptersConfig;\n};\n\nexport const DEFAULT_SCOPE_CONFIG: ScopeResolverConfig = {\n artifactDirectories: ARTIFACT_DIRECTORIES_DEFAULT,\n hiddenPrefix: HIDDEN_PREFIX_DEFAULT,\n ignoreSourceFilename: IGNORE_SOURCE_FILENAME_DEFAULT,\n specTreeRootSegment: SPEC_TREE_CONFIG.ROOT_DIRECTORY,\n};\n\nexport const DEFAULT_TOOLS_CONFIG: ToolAdaptersConfig = {\n tools: Object.fromEntries(\n Object.entries(TOOL_DEFAULT_FLAGS).map(([name, flag]) => [name, { ignoreFlag: flag }]),\n ),\n};\n\nconst defaults: FileInclusionConfig = {\n scope: DEFAULT_SCOPE_CONFIG,\n tools: DEFAULT_TOOLS_CONFIG,\n};\n\nfunction validate(value: unknown): Result<FileInclusionConfig> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return { ok: false, error: `${FILE_INCLUSION_SECTION} section must be an object` };\n }\n // User-supplied keys are accepted but not yet merged; always returns defaults.\n // Deep merging requires a schema (tracked as a future enhancement).\n return { ok: true, value: defaults };\n}\n\nexport const fileInclusionConfigDescriptor: ConfigDescriptor<FileInclusionConfig> = {\n section: FILE_INCLUSION_SECTION,\n defaults,\n validate,\n};\n","import type { ConfigDescriptor, Result } from \"@/config/types\";\n\nexport const PRECOMMIT_SECTION = \"precommit\";\n\nexport interface PrecommitConfig {\n readonly sourceDirs: readonly string[];\n readonly testPattern: string;\n}\n\nexport const PRECOMMIT_DEFAULTS: PrecommitConfig = {\n sourceDirs: [\"src/\"],\n testPattern: \".test.ts\",\n};\n\nfunction validate(value: unknown): Result<PrecommitConfig> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return { ok: false, error: `${PRECOMMIT_SECTION} section must be an object` };\n }\n const candidate = value as Record<string, unknown>;\n\n const sourceDirs = candidate[\"sourceDirs\"] ?? PRECOMMIT_DEFAULTS.sourceDirs;\n if (!Array.isArray(sourceDirs) || !sourceDirs.every((x) => typeof x === \"string\" && x.length > 0)) {\n return {\n ok: false,\n error: `${PRECOMMIT_SECTION}.sourceDirs must be a non-empty array of non-empty strings`,\n };\n }\n\n const testPattern = candidate[\"testPattern\"] ?? PRECOMMIT_DEFAULTS.testPattern;\n if (typeof testPattern !== \"string\" || testPattern.length === 0) {\n return {\n ok: false,\n error: `${PRECOMMIT_SECTION}.testPattern must be a non-empty string`,\n };\n }\n\n return {\n ok: true,\n value: {\n sourceDirs: sourceDirs as readonly string[],\n testPattern: testPattern as string,\n },\n };\n}\n\nexport const precommitConfigDescriptor: ConfigDescriptor<PrecommitConfig> = {\n section: PRECOMMIT_SECTION,\n defaults: PRECOMMIT_DEFAULTS,\n validate,\n};\n","import type { ConfigDescriptor, Result } from \"@/config/types\";\n\nexport const LITERAL_SECTION = \"literal\";\nexport const DEFAULT_MIN_STRING_LENGTH = 4;\nexport const DEFAULT_MIN_NUMBER_DIGITS = 4;\n\nexport interface LiteralAllowlistConfig {\n readonly presets?: readonly string[];\n readonly include?: readonly string[];\n readonly exclude?: readonly string[];\n}\n\nexport interface LiteralConfig {\n readonly allowlist: LiteralAllowlistConfig;\n readonly minStringLength: number;\n readonly minNumberDigits: number;\n}\n\nexport const PRESET_NAMES = {\n WEB: \"web\",\n} as const;\n\nexport type PresetName = (typeof PRESET_NAMES)[keyof typeof PRESET_NAMES];\n\nexport const WEB_PRESET_TOKENS = [\n \"GET\",\n \"POST\",\n \"PUT\",\n \"DELETE\",\n \"PATCH\",\n \"Content-Type\",\n \"Authorization\",\n \"Accept\",\n \"status\",\n \"message\",\n \"error\",\n \"data\",\n \"class\",\n \"id\",\n \"href\",\n \"src\",\n \"type\",\n \"name\",\n \"value\",\n] as const;\n\nexport type WebPresetToken = (typeof WEB_PRESET_TOKENS)[number];\n\nconst WEB_PRESET: ReadonlySet<WebPresetToken> = new Set(WEB_PRESET_TOKENS);\n\nconst PRESET_REGISTRY: ReadonlyMap<PresetName, ReadonlySet<string>> = new Map([\n [PRESET_NAMES.WEB, WEB_PRESET],\n]);\n\nexport function resolveAllowlist(config: LiteralAllowlistConfig): ReadonlySet<string> {\n const effective = new Set<string>();\n\n for (const presetId of config.presets ?? []) {\n const preset = PRESET_REGISTRY.get(presetId as PresetName);\n if (preset !== undefined) {\n for (const v of preset) effective.add(v);\n }\n }\n\n for (const v of config.include ?? []) {\n effective.add(v);\n }\n\n for (const v of config.exclude ?? []) {\n effective.delete(v);\n }\n\n return effective;\n}\n\nexport const LITERAL_DEFAULTS: LiteralConfig = {\n allowlist: {},\n minStringLength: DEFAULT_MIN_STRING_LENGTH,\n minNumberDigits: DEFAULT_MIN_NUMBER_DIGITS,\n};\n\nfunction validate(value: unknown): Result<LiteralConfig> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return { ok: false, error: `${LITERAL_SECTION} section must be an object` };\n }\n const candidate = value as Record<string, unknown>;\n\n const allowlistRaw = candidate[\"allowlist\"] ?? {};\n const allowlistResult = validateAllowlist(allowlistRaw);\n if (!allowlistResult.ok) {\n return allowlistResult;\n }\n\n const minStringLength = candidate[\"minStringLength\"] ?? LITERAL_DEFAULTS.minStringLength;\n if (typeof minStringLength !== \"number\" || !Number.isInteger(minStringLength) || minStringLength < 0) {\n return {\n ok: false,\n error: `${LITERAL_SECTION}.minStringLength must be a non-negative integer`,\n };\n }\n\n const minNumberDigits = candidate[\"minNumberDigits\"] ?? LITERAL_DEFAULTS.minNumberDigits;\n if (typeof minNumberDigits !== \"number\" || !Number.isInteger(minNumberDigits) || minNumberDigits < 0) {\n return {\n ok: false,\n error: `${LITERAL_SECTION}.minNumberDigits must be a non-negative integer`,\n };\n }\n\n return { ok: true, value: { allowlist: allowlistResult.value, minStringLength, minNumberDigits } };\n}\n\nfunction validateAllowlist(raw: unknown): Result<LiteralAllowlistConfig> {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist must be an object` };\n }\n const candidate = raw as Record<string, unknown>;\n\n const presets = candidate[\"presets\"];\n if (presets !== undefined) {\n if (!Array.isArray(presets) || !presets.every((x) => typeof x === \"string\")) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist.presets must be an array of strings` };\n }\n for (const id of presets as string[]) {\n if (!PRESET_REGISTRY.has(id as PresetName)) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist.presets: unrecognized preset \"${id}\"` };\n }\n }\n }\n\n const include = candidate[\"include\"];\n if (include !== undefined && (!Array.isArray(include) || !include.every((x) => typeof x === \"string\"))) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist.include must be an array of strings` };\n }\n\n const exclude = candidate[\"exclude\"];\n if (exclude !== undefined && (!Array.isArray(exclude) || !exclude.every((x) => typeof x === \"string\"))) {\n return { ok: false, error: `${LITERAL_SECTION}.allowlist.exclude must be an array of strings` };\n }\n\n return {\n ok: true,\n value: {\n presets: presets as readonly string[] | undefined,\n include: include as readonly string[] | undefined,\n exclude: exclude as readonly string[] | undefined,\n },\n };\n}\n\nexport const literalConfigDescriptor: ConfigDescriptor<LiteralConfig> = {\n section: LITERAL_SECTION,\n defaults: LITERAL_DEFAULTS,\n validate,\n};\n","import type { ConfigDescriptor, Result } from \"@/config/types\";\nimport {\n DEFAULT_MIN_NUMBER_DIGITS,\n DEFAULT_MIN_STRING_LENGTH,\n type LiteralConfig,\n literalConfigDescriptor,\n} from \"@/validation/literal/config\";\n\nexport const VALIDATION_SECTION = \"validation\";\nexport const VALIDATION_LITERAL_SUBSECTION = \"literal\";\nexport const VALIDATION_LITERAL_VALUES_SUBSECTION = \"values\";\nexport const VALIDATION_PATHS_SUBSECTION = \"paths\";\n\nexport interface ValidationPathConfig {\n readonly include?: readonly string[];\n readonly exclude?: readonly string[];\n}\n\nexport interface ValidationLiteralConfig {\n readonly values: LiteralConfig;\n}\n\nexport interface ValidationConfig {\n readonly paths: ValidationPathConfig;\n readonly literal: ValidationLiteralConfig;\n}\n\nconst defaults: ValidationConfig = {\n paths: {},\n literal: {\n values: {\n allowlist: {},\n minStringLength: DEFAULT_MIN_STRING_LENGTH,\n minNumberDigits: DEFAULT_MIN_NUMBER_DIGITS,\n },\n },\n};\n\nfunction validatePaths(raw: unknown): Result<ValidationPathConfig> {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n return {\n ok: false,\n error: `${VALIDATION_SECTION}.${VALIDATION_PATHS_SUBSECTION} must be an object`,\n };\n }\n const candidate = raw as Record<string, unknown>;\n\n const include = candidate[\"include\"];\n if (\n include !== undefined\n && (!Array.isArray(include) || !include.every((x) => typeof x === \"string\"))\n ) {\n return {\n ok: false,\n error: `${VALIDATION_SECTION}.${VALIDATION_PATHS_SUBSECTION}.include must be an array of strings`,\n };\n }\n\n const exclude = candidate[\"exclude\"];\n if (\n exclude !== undefined\n && (!Array.isArray(exclude) || !exclude.every((x) => typeof x === \"string\"))\n ) {\n return {\n ok: false,\n error: `${VALIDATION_SECTION}.${VALIDATION_PATHS_SUBSECTION}.exclude must be an array of strings`,\n };\n }\n\n return {\n ok: true,\n value: {\n include: include as readonly string[] | undefined,\n exclude: exclude as readonly string[] | undefined,\n },\n };\n}\n\nfunction validateLiteral(raw: unknown): Result<ValidationLiteralConfig> {\n if (typeof raw !== \"object\" || raw === null || Array.isArray(raw)) {\n return {\n ok: false,\n error: `${VALIDATION_SECTION}.${VALIDATION_LITERAL_SUBSECTION} must be an object`,\n };\n }\n const candidate = raw as Record<string, unknown>;\n const valuesRaw = candidate[VALIDATION_LITERAL_VALUES_SUBSECTION] ?? {};\n const valuesResult = literalConfigDescriptor.validate(valuesRaw);\n if (!valuesResult.ok) {\n return {\n ok: false,\n error:\n `${VALIDATION_SECTION}.${VALIDATION_LITERAL_SUBSECTION}.${VALIDATION_LITERAL_VALUES_SUBSECTION}: ${valuesResult.error}`,\n };\n }\n return { ok: true, value: { values: valuesResult.value } };\n}\n\nfunction validate(value: unknown): Result<ValidationConfig> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n return { ok: false, error: `${VALIDATION_SECTION} section must be an object` };\n }\n const candidate = value as Record<string, unknown>;\n\n const pathsRaw = candidate[VALIDATION_PATHS_SUBSECTION] ?? {};\n const pathsResult = validatePaths(pathsRaw);\n if (!pathsResult.ok) return pathsResult;\n\n const literalRaw = candidate[VALIDATION_LITERAL_SUBSECTION] ?? {};\n const literalResult = validateLiteral(literalRaw);\n if (!literalResult.ok) return literalResult;\n\n return { ok: true, value: { paths: pathsResult.value, literal: literalResult.value } };\n}\n\nexport const validationConfigDescriptor: ConfigDescriptor<ValidationConfig> = {\n section: VALIDATION_SECTION,\n defaults,\n validate,\n};\n","import { fileInclusionConfigDescriptor } from \"@/lib/file-inclusion/config\";\nimport { precommitConfigDescriptor } from \"@/lib/precommit/config\";\nimport { specTreeConfigDescriptor } from \"@/lib/spec-tree/config\";\nimport { validationConfigDescriptor } from \"@/validation/config/descriptor\";\n\nimport type { ConfigDescriptor } from \"./types\";\n\nexport const productionRegistry: readonly ConfigDescriptor<unknown>[] = [\n specTreeConfigDescriptor,\n validationConfigDescriptor,\n fileInclusionConfigDescriptor,\n precommitConfigDescriptor,\n] as const;\n","import { CONFIG_FILE_FORMAT, DEFAULT_CONFIG_FILE_FORMAT, serializeConfigFileSections } from \"@/config/index\";\nimport type { Config } from \"@/config/types\";\n\nimport type { CliDeps, CliResult, DefaultsOptions } from \"./types\";\n\nexport function defaultsCommand(options: DefaultsOptions, deps: CliDeps): Promise<CliResult> {\n const config: Record<string, unknown> = {};\n for (const descriptor of deps.descriptors) {\n config[descriptor.section] = descriptor.defaults;\n }\n\n return Promise.resolve({\n stdout: formatConfig(config as Config, options.json === true),\n stderr: \"\",\n exitCode: 0,\n });\n}\n\nfunction formatConfig(config: Config, asJson: boolean): string {\n const format = asJson ? CONFIG_FILE_FORMAT.JSON : DEFAULT_CONFIG_FILE_FORMAT;\n const serialized = serializeConfigFileSections(format, config as Record<string, unknown>);\n if (!serialized.ok) {\n throw new Error(serialized.error);\n }\n return serialized.value;\n}\n","import { CONFIG_FILE_FORMAT, DEFAULT_CONFIG_FILE_FORMAT, serializeConfigFileSections } from \"@/config/index\";\nimport type { Config } from \"@/config/types\";\n\nimport type { CliDeps, CliResult, ShowOptions } from \"./types\";\n\nconst EXIT_CODE_ERROR = 1;\n\nexport async function showCommand(options: ShowOptions, deps: CliDeps): Promise<CliResult> {\n const projectRoot = deps.resolveProjectRoot();\n const result = await deps.resolveConfig(projectRoot);\n\n if (!result.ok) {\n return {\n stdout: \"\",\n stderr: `${result.error}\\n`,\n exitCode: EXIT_CODE_ERROR,\n };\n }\n\n return {\n stdout: formatConfig(result.value, options.json === true),\n stderr: \"\",\n exitCode: 0,\n };\n}\n\nfunction formatConfig(config: Config, asJson: boolean): string {\n const format = asJson ? CONFIG_FILE_FORMAT.JSON : DEFAULT_CONFIG_FILE_FORMAT;\n const serialized = serializeConfigFileSections(format, config as Record<string, unknown>);\n if (!serialized.ok) {\n throw new Error(serialized.error);\n }\n return serialized.value;\n}\n","import { DEFAULT_CONFIG_FILENAME } from \"@/config/index\";\n\nimport type { CliDeps, CliResult, ValidateOptions } from \"./types\";\n\nconst EXIT_CODE_INVALID = 1;\n\nexport async function validateCommand(_options: ValidateOptions, deps: CliDeps): Promise<CliResult> {\n const projectRoot = deps.resolveProjectRoot();\n const result = await deps.resolveConfig(projectRoot);\n\n if (!result.ok) {\n return {\n stdout: \"\",\n stderr: `${result.error}\\n`,\n exitCode: EXIT_CODE_INVALID,\n };\n }\n\n return {\n stdout: `${DEFAULT_CONFIG_FILENAME} at ${projectRoot} passes every registered descriptor's validator.\\n`,\n stderr: \"\",\n exitCode: 0,\n };\n}\n","import { execSync } from \"node:child_process\";\nimport { resolve } from \"node:path\";\n\nconst GIT_TOPLEVEL_CMD = \"git rev-parse --show-toplevel\";\nconst GIT_NOT_REPO_MARKER = \"not a git repository\";\n\nexport type ResolvedProjectRoot = {\n readonly projectRoot: string;\n readonly warning?: string;\n};\n\nexport function resolveProjectRoot(cwd: string = process.cwd()): ResolvedProjectRoot {\n const resolvedCwd = resolve(cwd);\n try {\n const stdout = execSync(GIT_TOPLEVEL_CMD, {\n cwd: resolvedCwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n encoding: \"utf8\",\n });\n const toplevel = stdout.trim();\n if (toplevel.length > 0) {\n return { projectRoot: resolve(toplevel) };\n }\n } catch {\n // fall through to cwd fallback\n }\n\n return {\n projectRoot: resolvedCwd,\n warning:\n `warning: ${resolvedCwd} is not inside a git worktree — falling back to the current working directory. ${GIT_NOT_REPO_MARKER}.`,\n };\n}\n","import type { Command } from \"commander\";\n\nimport { defaultsCommand } from \"@/commands/config/defaults\";\nimport { showCommand } from \"@/commands/config/show\";\nimport type { CliDeps, CliResult, ShowOptions, ValidateOptions } from \"@/commands/config/types\";\nimport { validateCommand } from \"@/commands/config/validate\";\nimport { CONFIG_FILE_FORMAT, DEFAULT_CONFIG_FILE_FORMAT, DEFAULT_CONFIG_FILENAME, resolveConfig } from \"@/config/index\";\nimport { productionRegistry } from \"@/config/registry\";\n\nimport type { Domain } from \"../types\";\nimport { resolveProjectRoot } from \"./root\";\n\nfunction buildDefaultDeps(): CliDeps {\n return {\n resolveConfig,\n resolveProjectRoot: (): string => {\n const resolved = resolveProjectRoot();\n if (resolved.warning !== undefined) {\n process.stderr.write(`${resolved.warning}\\n`);\n }\n return resolved.projectRoot;\n },\n descriptors: productionRegistry,\n };\n}\n\nasync function emit(result: CliResult): Promise<never> {\n if (result.stdout.length > 0) {\n process.stdout.write(result.stdout);\n }\n if (result.stderr.length > 0) {\n process.stderr.write(result.stderr);\n }\n return process.exit(result.exitCode);\n}\n\nfunction registerConfigCommands(configCmd: Command): void {\n configCmd\n .command(\"show\")\n .description(\n `Print the resolved configuration as ${DEFAULT_CONFIG_FILE_FORMAT.toUpperCase()} `\n + `(or ${CONFIG_FILE_FORMAT.JSON.toUpperCase()} with --json)`,\n )\n .option(\"--json\", `Output as ${CONFIG_FILE_FORMAT.JSON.toUpperCase()}`)\n .action(async (options: ShowOptions) => {\n await emit(await showCommand(options, buildDefaultDeps()));\n });\n\n configCmd\n .command(\"validate\")\n .description(`Verify that ${DEFAULT_CONFIG_FILENAME} passes every registered descriptor's validator`)\n .action(async (options: ValidateOptions) => {\n await emit(await validateCommand(options, buildDefaultDeps()));\n });\n\n configCmd\n .command(\"defaults\")\n .description(`Print each registered descriptor's defaults; ignores ${DEFAULT_CONFIG_FILENAME}`)\n .option(\"--json\", `Output as ${CONFIG_FILE_FORMAT.JSON.toUpperCase()}`)\n .action(async (options: ShowOptions) => {\n await emit(await defaultsCommand(options, buildDefaultDeps()));\n });\n}\n\nexport const configDomain: Domain = {\n name: \"config\",\n description: \"Inspect and validate the resolved spx configuration\",\n register: (program: Command) => {\n const configCmd = program\n .command(\"config\")\n .description(\"Inspect and validate the resolved spx configuration\");\n registerConfigCommands(configCmd);\n },\n};\n","/**\n * Session archive CLI command handler.\n *\n * @module commands/session/archive\n */\n\nimport { mkdir, rename, stat } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport {\n buildArchivePaths,\n ExistingPathsMap,\n findSessionForArchive,\n SESSION_FILE_EXTENSION,\n} from \"@/domains/session/archive\";\nimport { processBatch } from \"@/domains/session/batch\";\nimport { SessionNotFoundError } from \"@/domains/session/errors\";\nimport { SessionDirectoryConfig } from \"@/domains/session/show\";\nimport { resolveSessionConfig } from \"@/git/root\";\n\nexport const SESSION_ARCHIVE_OUTPUT = {\n ARCHIVED: \"Archived session\",\n ARCHIVE_LOCATION: \"Archive location\",\n} as const;\n\n/**\n * Options for the archive command.\n */\nexport interface ArchiveOptions {\n /** Session ID(s) to archive */\n sessionIds: string[];\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Error thrown when a session is already archived.\n */\nexport class SessionAlreadyArchivedError extends Error {\n /** The session ID that is already archived */\n readonly sessionId: string;\n\n constructor(sessionId: string) {\n super(`Session already archived: ${sessionId}.`);\n this.name = \"SessionAlreadyArchivedError\";\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Checks whether a path exists as a file.\n */\nasync function fileExists(path: string): Promise<boolean> {\n try {\n const stats = await stat(path);\n return stats.isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Builds an ExistingPathsMap by probing the filesystem for a session ID\n * across all status directories.\n *\n * @param sessionId - Session ID to locate\n * @param config - Directory configuration\n * @returns Map of existing paths (null for directories where file is absent)\n */\nasync function probeSessionPaths(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<ExistingPathsMap> {\n const filename = `${sessionId}${SESSION_FILE_EXTENSION}`;\n const todoPath = join(config.todoDir, filename);\n const doingPath = join(config.doingDir, filename);\n const archivePath = join(config.archiveDir, filename);\n\n return {\n todo: await fileExists(todoPath) ? todoPath : null,\n doing: await fileExists(doingPath) ? doingPath : null,\n archive: await fileExists(archivePath) ? archivePath : null,\n };\n}\n\n/**\n * Resolves source and target paths for archiving a session.\n *\n * @param sessionId - Session ID to archive\n * @param config - Directory configuration\n * @returns Source and target paths for the archive rename\n * @throws {SessionNotFoundError} When session is not found in todo or doing\n * @throws {SessionAlreadyArchivedError} When session is already in archive\n */\nexport async function resolveArchivePaths(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<{ source: string; target: string }> {\n const existingPaths = await probeSessionPaths(sessionId, config);\n\n if (existingPaths.archive !== null) {\n throw new SessionAlreadyArchivedError(sessionId);\n }\n\n const location = findSessionForArchive(existingPaths);\n\n if (!location) {\n throw new SessionNotFoundError(sessionId);\n }\n\n const paths = buildArchivePaths(sessionId, location.status, config);\n return paths;\n}\n\n/**\n * Executes the archive command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {SessionNotFoundError} When session not found\n * @throws {SessionAlreadyArchivedError} When session is already archived\n */\n/**\n * Archives a single session by ID.\n */\nasync function archiveSingle(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<string> {\n const { source, target } = await resolveArchivePaths(sessionId, config);\n await mkdir(dirname(target), { recursive: true });\n await rename(source, target);\n return `${SESSION_ARCHIVE_OUTPUT.ARCHIVED}: ${sessionId}\\n${SESSION_ARCHIVE_OUTPUT.ARCHIVE_LOCATION}: ${target}`;\n}\n\n/**\n * Executes the archive command for one or more session IDs.\n *\n * @param options - Command options with one or more session IDs\n * @returns Formatted output for display\n * @throws {BatchError} When one or more IDs fail\n * @throws {SessionNotFoundError} When session not found (single ID)\n * @throws {SessionAlreadyArchivedError} When session already archived (single ID)\n */\nexport async function archiveCommand(options: ArchiveOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n return processBatch(options.sessionIds, (id) => archiveSingle(id, config));\n}\n","/**\n * Session archiving utilities with pure functions for path resolution.\n *\n * This module provides pure functions for archive path building and session\n * location finding. Actual filesystem operations are handled by the CLI\n * command handler in commands/session/archive.ts.\n *\n * @module session/archive\n */\n\nimport type { SessionStatus } from \"./types\";\n\n/**\n * File extension for session files.\n */\nexport const SESSION_FILE_EXTENSION = \".md\";\n\n/**\n * Configuration for archive path building.\n */\nexport interface ArchivePathConfig {\n /** Directory for todo sessions */\n todoDir: string;\n /** Directory for doing (claimed) sessions */\n doingDir: string;\n /** Directory for archived sessions */\n archiveDir: string;\n}\n\n/**\n * Result of building archive paths.\n */\nexport interface ArchivePaths {\n /** Source path where session currently exists */\n source: string;\n /** Target path in archive directory */\n target: string;\n}\n\n/**\n * Map of existing paths for session lookup.\n * Each key maps to the full path if file exists, or null if not found.\n */\nexport interface ExistingPathsMap {\n /** Path in todo directory, or null if not found */\n todo: string | null;\n /** Path in doing directory, or null if not found */\n doing: string | null;\n /** Path in archive directory, or null if not found */\n archive: string | null;\n}\n\n/**\n * Archivable statuses — sessions can only be archived from todo or doing.\n */\nexport type ArchivableStatus = Exclude<SessionStatus, \"archive\">;\n\nconst ARCHIVABLE_DIR_KEYS = {\n TODO: \"todoDir\",\n DOING: \"doingDir\",\n} as const;\n\ntype ArchivableDirKey = (typeof ARCHIVABLE_DIR_KEYS)[keyof typeof ARCHIVABLE_DIR_KEYS];\n\n/**\n * Result of finding a session for archiving.\n */\nexport interface SessionLocation {\n /** Status/directory where session was found */\n status: ArchivableStatus;\n /** Full path to the session file */\n path: string;\n}\n\n/**\n * Builds source and target paths for archiving a session.\n *\n * This is a pure function that computes paths based on session ID,\n * current status, and directory configuration.\n *\n * @param sessionId - Session ID (timestamp format)\n * @param currentStatus - Current status/directory of the session\n * @param config - Directory configuration\n * @returns Source and target paths for the archive operation\n *\n * @example\n * ```typescript\n * const paths = buildArchivePaths(\"2026-01-13_08-01-05\", \"todo\", {\n * todoDir: \".spx/sessions/todo\",\n * archiveDir: \".spx/sessions/archive\",\n * });\n * // paths.source === \".spx/sessions/todo/2026-01-13_08-01-05.md\"\n * // paths.target === \".spx/sessions/archive/2026-01-13_08-01-05.md\"\n * ```\n */\n/**\n * Maps archivable status to the corresponding config directory key.\n */\nconst ARCHIVABLE_DIR_KEY: Record<ArchivableStatus, ArchivableDirKey> = {\n todo: ARCHIVABLE_DIR_KEYS.TODO,\n doing: ARCHIVABLE_DIR_KEYS.DOING,\n};\n\nexport function buildArchivePaths(\n sessionId: string,\n currentStatus: ArchivableStatus,\n config: ArchivePathConfig,\n): ArchivePaths {\n const filename = `${sessionId}${SESSION_FILE_EXTENSION}`;\n const dirKey = ARCHIVABLE_DIR_KEY[currentStatus];\n const sourceDir = config[dirKey];\n\n return {\n source: `${sourceDir}/${filename}`,\n target: `${config.archiveDir}/${filename}`,\n };\n}\n\n/**\n * Finds a session's location for archiving.\n *\n * This is a pure function that determines the session's location based\n * on a map of existing paths. Returns null if the session is already\n * archived or not found.\n *\n * @param existingPaths - Map of paths where session might exist\n * @returns Session location if found in todo or doing, null otherwise\n *\n * @example\n * ```typescript\n * // Session in todo\n * const location = findSessionForArchive({\n * todo: \".spx/sessions/todo/test.md\",\n * doing: null,\n * archive: null,\n * });\n * // location === { status: \"todo\", path: \".spx/sessions/todo/test.md\" }\n *\n * // Session already archived\n * const location = findSessionForArchive({\n * todo: null,\n * doing: null,\n * archive: \".spx/sessions/archive/test.md\",\n * });\n * // location === null\n * ```\n */\n/**\n * Statuses to check when looking for a session to archive, in priority order.\n */\nconst ARCHIVE_SEARCH_ORDER: readonly ArchivableStatus[] = [\"todo\", \"doing\"] as const;\n\nexport function findSessionForArchive(\n existingPaths: ExistingPathsMap,\n): SessionLocation | null {\n // If session is already in archive, return null\n if (existingPaths.archive !== null) {\n return null;\n }\n\n // Check archivable directories in priority order\n for (const status of ARCHIVE_SEARCH_ORDER) {\n if (existingPaths[status] !== null) {\n return { status, path: existingPaths[status] };\n }\n }\n\n // Session not found anywhere\n return null;\n}\n","/**\n * Batch processing utilities for session commands.\n *\n * Provides a shared pattern for processing multiple session IDs:\n * run a handler per ID, collect results, report per-ID outcomes,\n * throw if any failed.\n *\n * @module session/batch\n */\n\n/**\n * Result of processing a single session ID within a batch.\n */\nexport interface BatchItemResult {\n /** The session ID that was processed. */\n id: string;\n /** Whether the operation succeeded. */\n ok: boolean;\n /** Output message on success, error message on failure. */\n message: string;\n}\n\n/**\n * Error thrown when a batch operation has partial or total failures.\n * Contains per-ID results so the caller knows which succeeded and which failed.\n */\nexport class BatchError extends Error {\n readonly results: readonly BatchItemResult[];\n\n constructor(results: readonly BatchItemResult[]) {\n const failures = results.filter((r) => !r.ok);\n const successes = results.filter((r) => r.ok);\n super(\n `${failures.length} of ${results.length} operations failed. `\n + `${successes.length} succeeded.`,\n );\n this.name = \"BatchError\";\n this.results = results;\n }\n}\n\n/**\n * Processes multiple session IDs through a handler function.\n *\n * IDs are processed sequentially in argument order (left-to-right).\n * All IDs are processed regardless of individual failures.\n * Throws BatchError if any ID fails.\n *\n * @param ids - Session IDs to process\n * @param handler - Async function that processes a single ID and returns output\n * @returns Combined output string with per-ID results\n * @throws {BatchError} When one or more IDs fail\n */\nexport async function processBatch(\n ids: readonly string[],\n handler: (id: string) => Promise<string>,\n): Promise<string> {\n const results: BatchItemResult[] = [];\n\n for (const id of ids) {\n try {\n const output = await handler(id);\n results.push({ id, ok: true, message: output });\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n results.push({ id, ok: false, message });\n }\n }\n\n const output = results\n .map((r) => r.ok ? r.message : `Error (${r.id}): ${r.message}`)\n .join(\"\\n\\n\");\n\n const hasFailures = results.some((r) => !r.ok);\n if (hasFailures) {\n const err = new BatchError(results);\n err.message = `${err.message}\\n\\n${output}`;\n throw err;\n }\n\n return output;\n}\n","/**\n * Session-specific error types.\n *\n * @module session/errors\n */\n\n/**\n * Base class for session errors.\n */\nexport class SessionError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"SessionError\";\n }\n}\n\n/**\n * Error thrown when a session cannot be found.\n */\nexport class SessionNotFoundError extends SessionError {\n /** The session ID that was not found */\n readonly sessionId: string;\n\n constructor(sessionId: string) {\n super(`Session not found: ${sessionId}. Check the session ID and try again.`);\n this.name = \"SessionNotFoundError\";\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown when a session is not available for claiming (already claimed).\n */\nexport class SessionNotAvailableError extends SessionError {\n /** The session ID that is not available */\n readonly sessionId: string;\n\n constructor(sessionId: string) {\n super(`Session not available: ${sessionId}. It may have been claimed by another agent.`);\n this.name = \"SessionNotAvailableError\";\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown when session content is invalid.\n */\nexport class SessionInvalidContentError extends SessionError {\n constructor(reason: string) {\n super(`Invalid session content: ${reason}`);\n this.name = \"SessionInvalidContentError\";\n }\n}\n\n/**\n * Error thrown when trying to release a session that is not currently claimed.\n */\nexport class SessionNotClaimedError extends SessionError {\n /** The session ID that is not claimed */\n readonly sessionId: string;\n\n constructor(sessionId: string) {\n super(`Session not claimed: ${sessionId}. The session is not in the doing directory.`);\n this.name = \"SessionNotClaimedError\";\n this.sessionId = sessionId;\n }\n}\n\n/**\n * Error thrown when no sessions are available for auto-pickup.\n */\nexport class NoSessionsAvailableError extends SessionError {\n constructor() {\n super(\"No sessions available. The todo directory is empty.\");\n this.name = \"NoSessionsAvailableError\";\n }\n}\n","/**\n * Git repository root detection utilities.\n *\n * Provides git root detection with dependency injection for testability.\n * Sessions should be created at the git repository root, not relative to cwd.\n *\n * @module git/root\n */\n\nimport { execa } from \"execa\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\n\nimport { SessionDirectoryConfig } from \"@/domains/session/show\";\nimport { DEFAULT_CONFIG } from \"../config/defaults\";\nimport { withoutGitEnvironment } from \"./environment\";\n\n/**\n * Result from git root detection.\n */\nexport interface GitRootResult {\n /** Absolute path to git root (or cwd if not in git repo) */\n root: string;\n /** Whether the directory is inside a git repository */\n isGitRepo: boolean;\n /** Warning message when not in a git repo (undefined if in repo) */\n warning?: string;\n}\n\n/**\n * Minimal result type for command execution.\n * Captures only the fields git root detection depends on.\n */\nexport interface ExecResult {\n /** Process exit code */\n exitCode: number;\n /** Standard output */\n stdout: string;\n /** Standard error */\n stderr: string;\n}\n\n/**\n * Dependencies for git operations (injectable for testing).\n */\nexport interface GitDependencies {\n /**\n * Execute a command.\n *\n * @param command - Command to execute\n * @param args - Command arguments\n * @param options - Execution options\n * @returns Promise resolving to command result\n */\n execa: (\n command: string,\n args: string[],\n options?: { cwd?: string; reject?: boolean },\n ) => Promise<ExecResult>;\n}\n\n/**\n * Default dependencies using real execa.\n */\nconst defaultDeps: GitDependencies = {\n execa: async (command, args, options) => {\n const result = await execa(command, args, {\n ...options,\n env: withoutGitEnvironment(process.env),\n extendEnv: false,\n });\n return {\n exitCode: result.exitCode ?? 0,\n stdout: typeof result.stdout === \"string\" ? result.stdout : String(result.stdout),\n stderr: typeof result.stderr === \"string\" ? result.stderr : String(result.stderr),\n };\n },\n};\n\nconst NOT_GIT_REPO_WARNING =\n \"Warning: Not in a git repository. Sessions will be created relative to current directory.\";\n\n/**\n * Detects the git repository root directory.\n *\n * Uses `git rev-parse --show-toplevel` to find the repository root.\n * If not in a git repository, returns the current working directory with a warning.\n *\n * @param cwd - Current working directory (defaults to process.cwd())\n * @param deps - Injectable dependencies for testing\n * @returns GitRootResult with root path, git status, and optional warning\n *\n * @example\n * ```typescript\n * // In a git repo subdirectory\n * const result = await detectGitRoot('/repo/src/components');\n * // => { root: '/repo', isGitRepo: true }\n *\n * // Not in a git repo\n * const result = await detectGitRoot('/tmp/random');\n * // => { root: '/tmp/random', isGitRepo: false, warning: '...' }\n * ```\n */\nexport async function detectGitRoot(\n cwd: string = process.cwd(),\n deps: GitDependencies = defaultDeps,\n): Promise<GitRootResult> {\n try {\n const result = await deps.execa(\n \"git\",\n [\"rev-parse\", \"--show-toplevel\"],\n { cwd, reject: false },\n );\n\n // Git command succeeded - we're in a repo\n if (result.exitCode === 0 && result.stdout) {\n return {\n root: extractStdout(result.stdout),\n isGitRepo: true,\n };\n }\n\n // Git command failed - not in a repo\n return {\n root: cwd,\n isGitRepo: false,\n warning: NOT_GIT_REPO_WARNING,\n };\n } catch {\n // Command execution failed (git not installed, permission error, etc.)\n return {\n root: cwd,\n isGitRepo: false,\n warning: NOT_GIT_REPO_WARNING,\n };\n }\n}\n\n/**\n * Extracts a trimmed string from execa stdout, handling all possible output types.\n */\nfunction extractStdout(stdout: unknown): string {\n if (!stdout) return \"\";\n const str = typeof stdout === \"string\" ? stdout : String(stdout);\n return str.trim().replace(/\\/+$/, \"\");\n}\n\n/**\n * Detects the main repository root, resolving through git worktrees.\n *\n * Uses `git rev-parse --git-common-dir` to find the shared `.git` directory,\n * then returns its parent as the main repository root. In a non-worktree\n * repository, this returns the same path as `detectGitRoot`.\n *\n * This function supports `.spx/` operations where state must be shared across\n * all worktrees.\n *\n * @param cwd - Current working directory (defaults to process.cwd())\n * @param deps - Injectable dependencies for testing\n * @returns GitRootResult with main repo root path\n */\nexport async function detectMainRepoRoot(\n cwd: string = process.cwd(),\n deps: GitDependencies = defaultDeps,\n): Promise<GitRootResult> {\n try {\n // Step 1: Get the worktree/repo root via --show-toplevel\n const toplevelResult = await deps.execa(\n \"git\",\n [\"rev-parse\", \"--show-toplevel\"],\n { cwd, reject: false },\n );\n\n if (toplevelResult.exitCode !== 0 || !toplevelResult.stdout) {\n return {\n root: cwd,\n isGitRepo: false,\n warning: NOT_GIT_REPO_WARNING,\n };\n }\n\n const toplevel = extractStdout(toplevelResult.stdout);\n\n // Step 2: Get the common git directory via --git-common-dir\n const commonDirResult = await deps.execa(\n \"git\",\n [\"rev-parse\", \"--git-common-dir\"],\n { cwd, reject: false },\n );\n\n if (commonDirResult.exitCode !== 0 || !commonDirResult.stdout) {\n // Fallback: if --git-common-dir fails, use toplevel\n return {\n root: toplevel,\n isGitRepo: true,\n };\n }\n\n const commonDir = extractStdout(commonDirResult.stdout);\n\n // Step 3: Resolve the common dir to an absolute path\n // --git-common-dir may return a relative path (e.g., \".git\" or \"../../../.git\")\n const absoluteCommonDir = isAbsolute(commonDir)\n ? commonDir\n : resolve(toplevel, commonDir);\n\n // Step 4: The main repo root is the parent of the common .git directory\n const mainRepoRoot = dirname(absoluteCommonDir);\n\n return {\n root: mainRepoRoot,\n isGitRepo: true,\n };\n } catch {\n return {\n root: cwd,\n isGitRepo: false,\n warning: NOT_GIT_REPO_WARNING,\n };\n }\n}\n\n/**\n * Options for resolving session directory configuration.\n */\nexport interface ResolveSessionConfigOptions {\n /** Explicit sessions directory (overrides auto-detection) */\n sessionsDir?: string;\n /** Current working directory for git detection */\n cwd?: string;\n /** Injectable dependencies for testing */\n deps?: GitDependencies;\n}\n\n/**\n * Result of session config resolution.\n */\nexport interface ResolveSessionConfigResult {\n /** Resolved session directory configuration with absolute paths */\n config: SessionDirectoryConfig;\n /** Warning message if not in a git repository */\n warning?: string;\n}\n\n/**\n * Resolves session directory configuration with worktree-aware root detection.\n *\n * If `sessionsDir` is provided, uses it directly. Otherwise, detects the main\n * repository root via `detectMainRepoRoot` and builds absolute paths from\n * `DEFAULT_CONFIG`.\n *\n * Session operations resolve against the main repository root so that\n * `.spx/sessions/` is shared across all worktrees.\n *\n * @param options - Resolution options\n * @returns Resolved config with absolute paths and optional warning\n */\nexport async function resolveSessionConfig(\n options: ResolveSessionConfigOptions = {},\n): Promise<ResolveSessionConfigResult> {\n const { sessionsDir, cwd, deps } = options;\n const { statusDirs } = DEFAULT_CONFIG.sessions;\n\n // Explicit directory provided — use as-is\n if (sessionsDir) {\n return {\n config: {\n todoDir: join(sessionsDir, statusDirs.todo),\n doingDir: join(sessionsDir, statusDirs.doing),\n archiveDir: join(sessionsDir, statusDirs.archive),\n },\n };\n }\n\n // Auto-detect main repo root for .spx/ operations\n const gitResult = await detectMainRepoRoot(cwd, deps);\n const baseDir = join(gitResult.root, DEFAULT_CONFIG.sessions.dir);\n\n return {\n config: {\n todoDir: join(baseDir, statusDirs.todo),\n doingDir: join(baseDir, statusDirs.doing),\n archiveDir: join(baseDir, statusDirs.archive),\n },\n warning: gitResult.warning,\n };\n}\n\n/**\n * Builds an absolute session file path from git root and session ID.\n *\n * Pure function that constructs the path without I/O.\n * All path components come from the config parameter (single source of truth).\n *\n * @param gitRoot - Absolute path to git repository root\n * @param sessionId - Session timestamp ID (e.g., \"2026-01-13_08-01-05\")\n * @param config - Session directory configuration\n * @returns Absolute path to session file in todo directory\n *\n * @example\n * ```typescript\n * const path = buildSessionPathFromRoot(\n * '/Users/dev/myproject',\n * '2026-01-13_08-01-05',\n * DEFAULT_SESSION_CONFIG,\n * );\n * // => '/Users/dev/myproject/.spx/sessions/todo/2026-01-13_08-01-05.md'\n * ```\n */\nexport function buildSessionPathFromRoot(\n gitRoot: string,\n sessionId: string,\n config: SessionDirectoryConfig,\n): string {\n const filename = `${sessionId}.md`;\n\n // Build absolute path: git root + todo dir + filename\n // All components come from config (no hardcoded strings)\n return join(gitRoot, config.todoDir, filename);\n}\n","/**\n * Default configuration for spx CLI\n *\n * This module defines the default directory structure and configuration\n * constants used throughout the spx CLI. All directory paths should reference\n * this configuration instead of using hardcoded strings.\n *\n * @module config/defaults\n */\n\n/**\n * Configuration schema for spx CLI directory structure\n */\nexport interface SpxConfig {\n /**\n * Specifications directory configuration\n */\n specs: {\n /**\n * Base directory for all specification files\n * @default \"specs\"\n */\n root: string;\n\n /**\n * Work items organization\n */\n work: {\n /**\n * Container directory for all work items\n * @default \"work\"\n */\n dir: string;\n\n /**\n * Status-based subdirectories for work items\n */\n statusDirs: {\n /**\n * Active work directory\n * @default \"doing\"\n */\n doing: string;\n\n /**\n * Future work directory\n * @default \"backlog\"\n */\n backlog: string;\n\n /**\n * Completed work directory\n * @default \"archive\"\n */\n done: string;\n };\n };\n\n /**\n * Product-level architecture decision records directory\n * @default \"decisions\"\n */\n decisions: string;\n\n /**\n * Templates directory (optional)\n * @default \"templates\"\n */\n templates?: string;\n };\n\n /**\n * Session handoff files configuration\n */\n sessions: {\n /**\n * Directory for session handoff files\n * @default \".spx/sessions\"\n */\n dir: string;\n\n /**\n * Status-based subdirectories for sessions\n */\n statusDirs: {\n /**\n * Available sessions directory\n * @default \"todo\"\n */\n todo: string;\n\n /**\n * Claimed sessions directory\n * @default \"doing\"\n */\n doing: string;\n\n /**\n * Archived sessions directory\n * @default \"archive\"\n */\n archive: string;\n };\n };\n}\n\n/**\n * Default configuration constant\n *\n * This is the embedded default configuration that spx uses when no\n * .spx/config.json file exists in the product.\n *\n * DO NOT modify this constant at runtime - it should remain immutable.\n */\nexport const DEFAULT_CONFIG = {\n specs: {\n root: \"specs\",\n work: {\n dir: \"work\",\n statusDirs: {\n doing: \"doing\",\n backlog: \"backlog\",\n done: \"archive\",\n },\n },\n decisions: \"decisions\",\n templates: \"templates\",\n },\n sessions: {\n dir: \".spx/sessions\",\n statusDirs: {\n todo: \"todo\",\n doing: \"doing\",\n archive: \"archive\",\n },\n },\n} as const satisfies SpxConfig;\n","/**\n * Removes Git context and identity variables for read-only commands that must\n * resolve from their own cwd instead of an inherited hook/worktree context.\n * Commit and tag callers need an identity-preserving environment instead.\n */\nexport function withoutGitEnvironment(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {\n const cleaned = { ...env };\n for (const key of Object.keys(cleaned)) {\n if (key.startsWith(\"GIT_\")) {\n delete cleaned[key];\n }\n }\n return cleaned;\n}\n","/**\n * Session delete CLI command handler.\n *\n * @module commands/session/delete\n */\n\nimport { stat, unlink } from \"node:fs/promises\";\n\nimport { processBatch } from \"@/domains/session/batch\";\nimport { resolveDeletePath } from \"@/domains/session/delete\";\nimport { resolveSessionPaths, SessionDirectoryConfig } from \"@/domains/session/show\";\nimport { resolveSessionConfig } from \"@/git/root\";\n\nexport const SESSION_DELETE_OUTPUT = {\n DELETED: \"Deleted session\",\n} as const;\n\n/**\n * Options for the delete command.\n */\nexport interface DeleteOptions {\n /** Session ID(s) to delete */\n sessionIds: string[];\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Checks which paths exist.\n */\nasync function findExistingPaths(paths: string[]): Promise<string[]> {\n const existing: string[] = [];\n\n for (const path of paths) {\n try {\n const stats = await stat(path);\n if (stats.isFile()) {\n existing.push(path);\n }\n } catch {\n // File doesn't exist, skip\n }\n }\n\n return existing;\n}\n\n/**\n * Executes the delete command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {SessionNotFoundError} When session not found\n */\n/**\n * Deletes a single session by ID.\n */\nasync function deleteSingle(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<string> {\n const paths = resolveSessionPaths(sessionId, config);\n const existingPaths = await findExistingPaths(paths);\n const pathToDelete = resolveDeletePath(sessionId, existingPaths);\n await unlink(pathToDelete);\n return `${SESSION_DELETE_OUTPUT.DELETED}: ${sessionId}`;\n}\n\n/**\n * Executes the delete command for one or more session IDs.\n *\n * @param options - Command options with one or more session IDs\n * @returns Formatted output for display\n * @throws {BatchError} When one or more IDs fail\n * @throws {SessionNotFoundError} When session not found (single ID)\n */\nexport async function deleteCommand(options: DeleteOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n return processBatch(options.sessionIds, (id) => deleteSingle(id, config));\n}\n","/**\n * Session deletion utilities.\n *\n * @module session/delete\n */\n\nimport { SessionNotFoundError } from \"./errors\";\n\n/**\n * Resolves the path to delete for a session ID.\n *\n * Given a session ID and a list of existing paths (checked by caller),\n * returns the first path that contains the session ID.\n *\n * @param sessionId - Session ID to find\n * @param existingPaths - Paths that were found to exist\n * @returns The path to the session file\n * @throws {SessionNotFoundError} When session is not found in any directory\n *\n * @example\n * ```typescript\n * // Caller checks which paths exist, passes only existing ones\n * const existingPaths = ['.spx/sessions/doing/2026-01-13_08-01-05.md'];\n * const path = resolveDeletePath('2026-01-13_08-01-05', existingPaths);\n * // => '.spx/sessions/doing/2026-01-13_08-01-05.md'\n * ```\n */\nexport function resolveDeletePath(\n sessionId: string,\n existingPaths: string[],\n): string {\n // Find the first existing path that matches the session ID\n const matchingPath = existingPaths.find((path) => path.includes(sessionId));\n\n if (!matchingPath) {\n throw new SessionNotFoundError(sessionId);\n }\n\n return matchingPath;\n}\n","/**\n * Session display utilities for showing session content without claiming.\n *\n * @module session/show\n */\n\nimport { join } from \"node:path\";\n\nimport { DEFAULT_CONFIG } from \"@/config/defaults\";\nimport { parseSessionMetadata } from \"./list\";\nimport { SESSION_STATUSES, type SessionStatus } from \"./types\";\n\nexport const SESSION_SHOW_LABEL = {\n ID: \"ID\",\n STATUS: \"Status\",\n PRIORITY: \"Priority\",\n BRANCH: \"Branch\",\n TAGS: \"Tags\",\n CREATED: \"Created\",\n} as const;\n\nexport const SESSION_SHOW_SEPARATOR_CHAR = \"─\";\nexport const SESSION_SHOW_SEPARATOR_WIDTH = 40;\n\n/**\n * Configuration for session directory paths.\n */\nexport interface SessionDirectoryConfig {\n /** Path to todo directory */\n todoDir: string;\n /** Path to doing directory */\n doingDir: string;\n /** Path to archive directory */\n archiveDir: string;\n}\n\n/**\n * Default session directory configuration.\n *\n * Derived from DEFAULT_CONFIG to ensure single source of truth for all path components.\n * NEVER hardcode path strings like \".spx\", \"sessions\", \"todo\" - always derive from config.\n */\nconst { dir: sessionsBaseDir, statusDirs } = DEFAULT_CONFIG.sessions;\n\nexport const DEFAULT_SESSION_CONFIG: SessionDirectoryConfig = {\n todoDir: join(sessionsBaseDir, statusDirs.todo),\n doingDir: join(sessionsBaseDir, statusDirs.doing),\n archiveDir: join(sessionsBaseDir, statusDirs.archive),\n};\n\n/**\n * Order to search directories (matches priority: todo first, then doing, then archive).\n * Derived from SESSION_STATUSES to maintain a single source of truth.\n */\nexport const SEARCH_ORDER: SessionStatus[] = [...SESSION_STATUSES];\n\n/**\n * Options for formatting show output.\n */\nexport interface ShowOutputOptions {\n /** Current status of the session */\n status: SessionStatus;\n}\n\n/**\n * Resolves possible file paths for a session ID across all status directories.\n *\n * @param id - Session ID (timestamp format)\n * @param config - Directory configuration\n * @returns Array of possible file paths in search order\n *\n * @example\n * ```typescript\n * const paths = resolveSessionPaths('2026-01-13_08-01-05', {\n * todoDir: '.spx/sessions/todo',\n * doingDir: '.spx/sessions/doing',\n * archiveDir: '.spx/sessions/archive',\n * });\n * // => [\n * // '.spx/sessions/todo/2026-01-13_08-01-05.md',\n * // '.spx/sessions/doing/2026-01-13_08-01-05.md',\n * // '.spx/sessions/archive/2026-01-13_08-01-05.md',\n * // ]\n * ```\n */\nexport function resolveSessionPaths(\n id: string,\n config: SessionDirectoryConfig = DEFAULT_SESSION_CONFIG,\n): string[] {\n const filename = `${id}.md`;\n\n return [\n `${config.todoDir}/${filename}`,\n `${config.doingDir}/${filename}`,\n `${config.archiveDir}/${filename}`,\n ];\n}\n\n/**\n * Formats session content for display with metadata header.\n *\n * @param content - Raw session file content\n * @param options - Display options including status\n * @returns Formatted output string with metadata header\n *\n * @example\n * ```typescript\n * const output = formatShowOutput(sessionContent, { status: 'todo' });\n * // => \"Status: todo\\nPriority: high\\n---\\n# Session Content...\"\n * ```\n */\nexport function formatShowOutput(\n content: string,\n options: ShowOutputOptions,\n): string {\n const metadata = parseSessionMetadata(content);\n\n // Build header with extracted metadata\n const headerLines: string[] = [\n `${SESSION_SHOW_LABEL.STATUS}: ${options.status}`,\n `${SESSION_SHOW_LABEL.PRIORITY}: ${metadata.priority}`,\n ];\n\n // Add optional metadata if present\n if (metadata.id) {\n headerLines.unshift(`${SESSION_SHOW_LABEL.ID}: ${metadata.id}`);\n }\n if (metadata.branch) {\n headerLines.push(`${SESSION_SHOW_LABEL.BRANCH}: ${metadata.branch}`);\n }\n if (metadata.tags.length > 0) {\n headerLines.push(`${SESSION_SHOW_LABEL.TAGS}: ${metadata.tags.join(\", \")}`);\n }\n if (metadata.createdAt) {\n headerLines.push(`${SESSION_SHOW_LABEL.CREATED}: ${metadata.createdAt}`);\n }\n\n // Combine header with separator and original content\n const header = headerLines.join(\"\\n\");\n const separator = \"\\n\" + SESSION_SHOW_SEPARATOR_CHAR.repeat(SESSION_SHOW_SEPARATOR_WIDTH) + \"\\n\\n\";\n\n return header + separator + content;\n}\n","/**\n * Session listing and sorting utilities.\n *\n * @module session/list\n */\n\nimport { parse as parseYaml } from \"yaml\";\n\nimport { parseSessionId } from \"./timestamp\";\nimport {\n DEFAULT_PRIORITY,\n PRIORITY_ORDER,\n type Session,\n SESSION_FRONT_MATTER,\n SESSION_PRIORITY,\n type SessionMetadata,\n type SessionPriority,\n} from \"./types\";\n\n/**\n * Regular expression to match YAML front matter.\n * Matches content between opening `---` and closing `---` or `...`\n */\nconst FRONT_MATTER_PATTERN = /^---\\r?\\n([\\s\\S]*?)\\r?\\n(?:---|\\.\\.\\.)\\r?\\n?/;\nconst SESSION_PRIORITY_VALUES = Object.values(SESSION_PRIORITY);\n\n/**\n * Validates if a value is a valid priority.\n */\nfunction isValidPriority(value: unknown): value is SessionPriority {\n return typeof value === \"string\" && SESSION_PRIORITY_VALUES.some((priority) => priority === value);\n}\n\n/**\n * Parses YAML front matter from session content to extract metadata.\n *\n * @param content - Full session file content\n * @returns Extracted metadata with defaults for missing fields\n *\n * @example\n * ```typescript\n * const metadata = parseSessionMetadata(`---\n * priority: high\n * tags: [bug, urgent]\n * ---\n * # Session content`);\n * // => { priority: 'high', tags: ['bug', 'urgent'] }\n * ```\n */\nexport function parseSessionMetadata(content: string): SessionMetadata {\n const match = FRONT_MATTER_PATTERN.exec(content);\n\n if (!match) {\n return {\n priority: DEFAULT_PRIORITY,\n tags: [],\n };\n }\n\n try {\n const parsed = parseYaml(match[1]) as Record<string, unknown>;\n\n if (!parsed || typeof parsed !== \"object\") {\n return {\n priority: DEFAULT_PRIORITY,\n tags: [],\n };\n }\n\n const rawPriority = parsed[SESSION_FRONT_MATTER.PRIORITY];\n const priority = isValidPriority(rawPriority) ? rawPriority : DEFAULT_PRIORITY;\n\n const rawTags = parsed[SESSION_FRONT_MATTER.TAGS];\n const tags: string[] = Array.isArray(rawTags)\n ? rawTags.filter((t): t is string => typeof t === \"string\")\n : [];\n\n const metadata: SessionMetadata = { priority, tags };\n\n const id = parsed[SESSION_FRONT_MATTER.ID];\n if (typeof id === \"string\") metadata.id = id;\n\n const branch = parsed[SESSION_FRONT_MATTER.BRANCH];\n if (typeof branch === \"string\") metadata.branch = branch;\n\n const createdAt = parsed[SESSION_FRONT_MATTER.CREATED_AT];\n if (typeof createdAt === \"string\") metadata.createdAt = createdAt;\n\n const agentSessionId = parsed[SESSION_FRONT_MATTER.AGENT_SESSION_ID];\n if (typeof agentSessionId === \"string\") metadata.agentSessionId = agentSessionId;\n\n const workingDirectory = parsed[SESSION_FRONT_MATTER.WORKING_DIRECTORY];\n if (typeof workingDirectory === \"string\") metadata.workingDirectory = workingDirectory;\n\n const specs = parsed[SESSION_FRONT_MATTER.SPECS];\n if (Array.isArray(specs)) {\n metadata.specs = specs.filter((s): s is string => typeof s === \"string\");\n }\n\n const files = parsed[SESSION_FRONT_MATTER.FILES];\n if (Array.isArray(files)) {\n metadata.files = files.filter((f): f is string => typeof f === \"string\");\n }\n\n return metadata;\n } catch {\n // Malformed YAML, return defaults\n return {\n priority: DEFAULT_PRIORITY,\n tags: [],\n };\n }\n}\n\n/**\n * Sorts sessions by priority (high first) then by timestamp (newest first).\n *\n * @param sessions - Array of sessions to sort\n * @returns New sorted array (does not mutate input)\n *\n * @example\n * ```typescript\n * const sorted = sortSessions([\n * { id: 'a', metadata: { priority: 'low' } },\n * { id: 'b', metadata: { priority: 'high' } },\n * ]);\n * // => [{ id: 'b', ... }, { id: 'a', ... }]\n * ```\n */\nexport function sortSessions(sessions: Session[]): Session[] {\n return [...sessions].sort((a, b) => {\n // First: sort by priority (high = 0, medium = 1, low = 2)\n const priorityA = PRIORITY_ORDER[a.metadata.priority];\n const priorityB = PRIORITY_ORDER[b.metadata.priority];\n\n if (priorityA !== priorityB) {\n return priorityA - priorityB;\n }\n\n // Second: sort by timestamp (newest first = descending)\n const dateA = parseSessionId(a.id);\n const dateB = parseSessionId(b.id);\n\n // Handle invalid session IDs by treating them as oldest\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1; // a goes after b\n if (!dateB) return -1; // b goes after a\n\n return dateB.getTime() - dateA.getTime();\n });\n}\n","/**\n * Session timestamp utilities for generating and parsing session IDs.\n *\n * Session IDs use the format YYYY-MM-DD_HH-mm-ss.\n *\n * @module session/timestamp\n */\n\n/**\n * Regular expression pattern for validating session IDs.\n * Format: YYYY-MM-DD_HH-mm-ss (all components zero-padded)\n *\n * Exported for use in validation and testing.\n */\nexport const SESSION_ID_PATTERN = /^(\\d{4})-(\\d{2})-(\\d{2})_(\\d{2})-(\\d{2})-(\\d{2})$/;\n\n/**\n * Separator between date and time components in session IDs.\n */\nexport const SESSION_ID_SEPARATOR = \"_\";\n\n/**\n * Options for generating session IDs.\n */\nexport interface GenerateSessionIdOptions {\n /**\n * Function that returns the current time.\n * Defaults to `() => new Date()` for production use.\n * Injectable for deterministic testing.\n */\n now?: () => Date;\n}\n\n/**\n * Generates a session ID from the current (or injected) time.\n *\n * @param options - Optional configuration including time source\n * @returns Session ID in format YYYY-MM-DD_HH-mm-ss\n *\n * @example\n * ```typescript\n * // Production usage\n * const id = generateSessionId();\n * // => \"2026-01-13_08-01-05\"\n *\n * // Testing with injected time\n * const id = generateSessionId({ now: () => new Date('2026-01-13T08:01:05') });\n * // => \"2026-01-13_08-01-05\"\n * ```\n */\nexport function generateSessionId(options: GenerateSessionIdOptions = {}): string {\n const now = options.now ?? (() => new Date());\n const date = now();\n\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n const hours = String(date.getHours()).padStart(2, \"0\");\n const minutes = String(date.getMinutes()).padStart(2, \"0\");\n const seconds = String(date.getSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day}${SESSION_ID_SEPARATOR}${hours}-${minutes}-${seconds}`;\n}\n\n/**\n * Parses a session ID string back into a Date object.\n *\n * @param id - Session ID string to parse\n * @returns Date object if valid, null if invalid format\n *\n * @example\n * ```typescript\n * const date = parseSessionId('2026-01-13_08-01-05');\n * // => Date representing 2026-01-13T08:01:05 (local time)\n *\n * const invalid = parseSessionId('invalid-format');\n * // => null\n * ```\n */\nexport function parseSessionId(id: string): Date | null {\n const match = SESSION_ID_PATTERN.exec(id);\n\n if (!match) {\n return null;\n }\n\n const [, yearStr, monthStr, dayStr, hoursStr, minutesStr, secondsStr] = match;\n\n const year = parseInt(yearStr, 10);\n const month = parseInt(monthStr, 10) - 1; // Date months are 0-indexed\n const day = parseInt(dayStr, 10);\n const hours = parseInt(hoursStr, 10);\n const minutes = parseInt(minutesStr, 10);\n const seconds = parseInt(secondsStr, 10);\n\n // Validate component ranges\n if (month < 0 || month > 11) return null;\n if (day < 1 || day > 31) return null;\n if (hours < 0 || hours > 23) return null;\n if (minutes < 0 || minutes > 59) return null;\n if (seconds < 0 || seconds > 59) return null;\n\n return new Date(year, month, day, hours, minutes, seconds);\n}\n","/**\n * Session type definitions for the session management domain.\n *\n * @module session/types\n */\n\n/**\n * Priority levels for session ordering.\n * Sessions are sorted: high → medium → low\n */\nexport const SESSION_PRIORITY = {\n HIGH: \"high\",\n MEDIUM: \"medium\",\n LOW: \"low\",\n} as const;\n\nexport type SessionPriority = (typeof SESSION_PRIORITY)[keyof typeof SESSION_PRIORITY];\n\n/**\n * All valid session statuses, derived from directory structure.\n * This is the single source of truth — SessionStatus type derives from it.\n */\nexport const SESSION_STATUSES = [\"todo\", \"doing\", \"archive\"] as const;\n\n/**\n * Status derived from directory location.\n */\nexport type SessionStatus = (typeof SESSION_STATUSES)[number];\n\n/**\n * Default statuses shown by `spx session list` when no --status filter is provided.\n * Excludes archive — use `--status archive` to see archived sessions.\n */\nexport const DEFAULT_LIST_STATUSES: readonly SessionStatus[] = [\"doing\", \"todo\"] as const;\n\n/**\n * Priority sort order (lower number = higher priority).\n */\nexport const PRIORITY_ORDER: Record<SessionPriority, number> = {\n [SESSION_PRIORITY.HIGH]: 0,\n [SESSION_PRIORITY.MEDIUM]: 1,\n [SESSION_PRIORITY.LOW]: 2,\n} as const;\n\n/**\n * Default priority when not specified in YAML front matter.\n */\nexport const DEFAULT_PRIORITY: SessionPriority = SESSION_PRIORITY.MEDIUM;\n\n/**\n * YAML front matter keys for session files.\n * Single source of truth for the serialized session schema.\n */\nexport const SESSION_FRONT_MATTER = {\n PRIORITY: \"priority\",\n TAGS: \"tags\",\n ID: \"id\",\n BRANCH: \"branch\",\n CREATED_AT: \"created_at\",\n AGENT_SESSION_ID: \"agent_session_id\",\n WORKING_DIRECTORY: \"working_directory\",\n SPECS: \"specs\",\n FILES: \"files\",\n} as const;\n\n/**\n * Metadata extracted from session YAML front matter.\n */\nexport interface SessionMetadata {\n /** Session ID (from filename or YAML) */\n id?: string;\n /** Priority level for sorting */\n priority: SessionPriority;\n /** Free-form tags for filtering */\n tags: string[];\n /** Git branch associated with session */\n branch?: string;\n /** Spec files to auto-inject on pickup */\n specs?: string[];\n /** Code files to auto-inject on pickup */\n files?: string[];\n /** ISO 8601 timestamp when session was created */\n createdAt?: string;\n /** Agent session ID from CLAUDE_SESSION_ID or CODEX_THREAD_ID at handoff time */\n agentSessionId?: string;\n /** Working directory path */\n workingDirectory?: string;\n}\n\n/**\n * Complete session information including status and metadata.\n */\nexport interface Session {\n /** Session ID (timestamp format: YYYY-MM-DD_HH-mm-ss) */\n id: string;\n /** Status derived from directory location */\n status: SessionStatus;\n /** Metadata from YAML front matter */\n metadata: SessionMetadata;\n /** Full path to session file */\n path: string;\n}\n","/**\n * Session handoff CLI command handler.\n *\n * Creates a new session for handoff to another agent context.\n * Metadata (priority, tags) should be included in the content as YAML frontmatter.\n *\n * @module commands/session/handoff\n */\n\nimport { mkdir, writeFile } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\nimport {\n buildSessionFrontMatterContent,\n preFillSessionContent,\n validateSessionContent,\n} from \"@/domains/session/create\";\nimport { SessionInvalidContentError } from \"@/domains/session/errors\";\nimport { generateSessionId } from \"@/domains/session/timestamp\";\nimport { DEFAULT_PRIORITY, SESSION_FRONT_MATTER } from \"@/domains/session/types\";\nimport { resolveSessionConfig } from \"@/git/root\";\n\n/**\n * Regex to detect YAML frontmatter presence.\n * Matches opening `---` at start of content.\n */\nconst FRONT_MATTER_START = /^---\\r?\\n/;\n\n/**\n * Options for the handoff command.\n */\nexport interface HandoffOptions {\n /** Session content (from stdin). Should include YAML frontmatter with priority/tags. */\n content?: string;\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Checks if content has YAML frontmatter.\n *\n * @param content - Raw session content\n * @returns True if content starts with frontmatter delimiter\n */\nexport function hasFrontmatter(content: string): boolean {\n return FRONT_MATTER_START.test(content);\n}\n\n/**\n * Builds session content, adding default frontmatter only if not present.\n *\n * If content already has frontmatter, returns as-is (preserves agent-provided metadata).\n * If content lacks frontmatter, adds default frontmatter with medium priority.\n *\n * @param content - Raw content from stdin\n * @returns Content ready to be written to session file\n */\nexport function buildSessionContent(content: string | undefined): string {\n // Default content if none provided\n if (!content || content.trim().length === 0) {\n return buildSessionFrontMatterContent(\n [`${SESSION_FRONT_MATTER.PRIORITY}: ${DEFAULT_PRIORITY}`],\n \"\\n# New Session\\n\\nDescribe your task here.\",\n );\n }\n\n // If content already has frontmatter, preserve it as-is\n if (hasFrontmatter(content)) {\n return content;\n }\n\n // Add default frontmatter to content without it\n return buildSessionFrontMatterContent([`${SESSION_FRONT_MATTER.PRIORITY}: ${DEFAULT_PRIORITY}`], `\\n${content}`);\n}\n\n/**\n * Executes the handoff command.\n *\n * Creates a new session in the todo directory for pickup by another context.\n * Output includes `<HANDOFF_ID>` tag for easy parsing by automation tools.\n *\n * When no --sessions-dir is provided, sessions are created at the git repository root\n * (if in a git repo) to ensure consistent location across subdirectories.\n *\n * Metadata (priority, tags) should be included in the content as YAML frontmatter:\n * ```\n * ---\n * priority: high\n * tags: [feature, api]\n * ---\n * # Session content...\n * ```\n *\n * @param options - Command options\n * @returns Formatted output for display with parseable session ID\n * @throws {SessionInvalidContentError} When content validation fails\n */\nexport async function handoffCommand(options: HandoffOptions): Promise<string> {\n const { config, warning } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n // Generate session ID\n const sessionId = generateSessionId();\n\n const baseContent = buildSessionContent(options.content);\n const agentSessionId = process.env.CLAUDE_SESSION_ID ?? process.env.CODEX_THREAD_ID;\n const fullContent = preFillSessionContent(baseContent, {\n createdAt: new Date(),\n agentSessionId,\n });\n\n const validation = validateSessionContent(fullContent);\n if (!validation.valid) {\n throw new SessionInvalidContentError(validation.error ?? \"Unknown validation error\");\n }\n\n // Build path to session file\n const filename = `${sessionId}.md`;\n const sessionPath = join(config.todoDir, filename);\n const absolutePath = resolve(sessionPath);\n\n // Ensure directory exists\n await mkdir(config.todoDir, { recursive: true });\n\n // Write file\n await writeFile(sessionPath, fullContent, \"utf-8\");\n\n // Emit warning to stderr if not in git repo\n if (warning) {\n process.stderr.write(`${warning}\\n`);\n }\n\n return `Created handoff session <HANDOFF_ID>${sessionId}</HANDOFF_ID>\\n<SESSION_FILE>${absolutePath}</SESSION_FILE>`;\n}\n","/**\n * Session creation utilities.\n *\n * @module session/create\n */\n\nimport { SESSION_FRONT_MATTER } from \"./types\";\n\nexport const MIN_CONTENT_LENGTH = 1;\nexport const SESSION_CONTENT_ERROR = {\n EMPTY: \"Session content cannot be empty\",\n} as const;\nexport const SESSION_FRONT_MATTER_DELIMITER = \"---\";\nexport const SESSION_FRONT_MATTER_DOCUMENT_END = \"...\";\nexport const SESSION_FRONT_MATTER_OPEN = `${SESSION_FRONT_MATTER_DELIMITER}\\n`;\nexport const SESSION_FRONT_MATTER_CLOSE = `\\n${SESSION_FRONT_MATTER_DELIMITER}\\n`;\n\nconst FRONT_MATTER_OPEN = /^---\\r?\\n/;\n\nexport interface PreFillParams {\n createdAt: Date;\n agentSessionId?: string;\n}\n\n/**\n * Result of session content validation.\n */\nexport interface ValidationResult {\n /** Whether the content is valid */\n valid: boolean;\n /** Error message if invalid */\n error?: string;\n}\n\nexport function preFillSessionContent(content: string, params: PreFillParams): string {\n const match = FRONT_MATTER_OPEN.exec(content);\n if (!match) return content;\n const lines = [`${SESSION_FRONT_MATTER.CREATED_AT}: \"${params.createdAt.toISOString()}\"`];\n if (params.agentSessionId !== undefined) {\n lines.push(`${SESSION_FRONT_MATTER.AGENT_SESSION_ID}: \"${params.agentSessionId}\"`);\n }\n return match[0] + lines.join(\"\\n\") + \"\\n\" + content.slice(match[0].length);\n}\n\nexport function buildSessionFrontMatterContent(\n frontMatterLines: readonly string[],\n body: string,\n closeDelimiter: string = SESSION_FRONT_MATTER_DELIMITER,\n): string {\n return `${SESSION_FRONT_MATTER_OPEN}${frontMatterLines.join(\"\\n\")}\\n${closeDelimiter}\\n${body}`;\n}\n\nexport function validateSessionContent(content: string): ValidationResult {\n if (!content || content.trim().length < MIN_CONTENT_LENGTH) {\n return {\n valid: false,\n error: SESSION_CONTENT_ERROR.EMPTY,\n };\n }\n\n return { valid: true };\n}\n","/**\n * Session list CLI command handler.\n *\n * @module commands/session/list\n */\n\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parseSessionMetadata, sortSessions } from \"@/domains/session/list\";\nimport { SessionDirectoryConfig } from \"@/domains/session/show\";\nimport {\n DEFAULT_LIST_STATUSES,\n DEFAULT_PRIORITY,\n Session,\n SESSION_STATUSES,\n SessionStatus,\n} from \"@/domains/session/types\";\nimport { resolveSessionConfig } from \"@/git/root\";\n\nexport const SESSION_LIST_FORMAT = {\n TEXT: \"text\",\n JSON: \"json\",\n} as const;\n\nexport type SessionListFormat = (typeof SESSION_LIST_FORMAT)[keyof typeof SESSION_LIST_FORMAT];\n\nexport const SESSION_LIST_EMPTY_TEXT = \"(no sessions)\";\n\n/**\n * Options for the list command.\n * Note: status is string (not SessionStatus) because it comes from user input via Commander.js.\n * Validation happens inside listCommand before status is used.\n */\nexport interface ListOptions {\n /** Filter by status (validated against SESSION_STATUSES) */\n status?: string;\n /** Custom sessions directory */\n sessionsDir?: string;\n /** Output format */\n format?: SessionListFormat;\n}\n\n/**\n * Loads sessions from a specific directory.\n */\nasync function loadSessionsFromDir(\n dir: string,\n status: SessionStatus,\n): Promise<Session[]> {\n try {\n const files = await readdir(dir);\n const sessions: Session[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".md\")) continue;\n\n const id = file.replace(\".md\", \"\");\n const filePath = join(dir, file);\n const content = await readFile(filePath, \"utf-8\");\n const metadata = parseSessionMetadata(content);\n\n sessions.push({\n id,\n status,\n path: filePath,\n metadata,\n });\n }\n\n return sessions;\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Maps a session status to its directory path in the config.\n */\nconst STATUS_DIR_KEY: Record<SessionStatus, keyof SessionDirectoryConfig> = {\n todo: \"todoDir\",\n doing: \"doingDir\",\n archive: \"archiveDir\",\n};\n\n/**\n * Formats sessions for text output.\n */\nfunction formatTextOutput(sessions: Session[]): string {\n if (sessions.length === 0) {\n return ` ${SESSION_LIST_EMPTY_TEXT}`;\n }\n\n return sessions\n .map((s) => {\n const priority = s.metadata.priority !== DEFAULT_PRIORITY ? ` [${s.metadata.priority}]` : \"\";\n const tags = s.metadata.tags.length > 0 ? ` (${s.metadata.tags.join(\", \")})` : \"\";\n return ` ${s.id}${priority}${tags}`;\n })\n .join(\"\\n\");\n}\n\n/**\n * Executes the list command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n */\n/**\n * Validates a user-supplied status string against SESSION_STATUSES.\n * Returns the validated SessionStatus or throws with valid values listed.\n */\nfunction validateStatus(input: string): SessionStatus {\n if (SESSION_STATUSES.includes(input as SessionStatus)) {\n return input as SessionStatus;\n }\n throw new Error(\n `Invalid status: \"${input}\". Valid values: ${SESSION_STATUSES.join(\", \")}`,\n );\n}\n\nexport async function listCommand(options: ListOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n // Validate and resolve statuses before use.\n const statuses: readonly SessionStatus[] = options.status !== undefined\n ? [validateStatus(options.status)]\n : DEFAULT_LIST_STATUSES;\n\n const sessionsByStatus: Partial<Record<SessionStatus, Session[]>> = {};\n\n for (const status of statuses) {\n const dirKey = STATUS_DIR_KEY[status];\n const sessions = await loadSessionsFromDir(config[dirKey], status);\n sessionsByStatus[status] = sortSessions(sessions);\n }\n\n // Format output\n if (options.format === SESSION_LIST_FORMAT.JSON) {\n return JSON.stringify(sessionsByStatus, null, 2);\n }\n\n // Text format\n const lines: string[] = [];\n\n for (const status of statuses) {\n lines.push(`${status.toUpperCase()}:`);\n lines.push(formatTextOutput(sessionsByStatus[status] ?? []));\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\").trim();\n}\n","/**\n * Session pickup CLI command handler.\n *\n * @module commands/session/pickup\n */\n\nimport { mkdir, readdir, readFile, rename } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { NoSessionsAvailableError } from \"@/domains/session/errors\";\nimport { parseSessionMetadata } from \"@/domains/session/list\";\nimport { buildClaimPaths, classifyClaimError, selectBestSession } from \"@/domains/session/pickup\";\nimport { formatShowOutput, SessionDirectoryConfig } from \"@/domains/session/show\";\nimport { Session, SESSION_STATUSES, SessionStatus } from \"@/domains/session/types\";\nimport { resolveSessionConfig } from \"@/git/root\";\n\n/** Status of sessions available for pickup. */\nconst PICKUP_SOURCE_STATUS: SessionStatus = SESSION_STATUSES[0]; // todo\n/** Status of sessions after being claimed. */\nconst PICKUP_TARGET_STATUS: SessionStatus = SESSION_STATUSES[1]; // doing\n\n/**\n * Options for the pickup command.\n */\nexport interface PickupOptions {\n /** Session ID to pickup (mutually exclusive with auto) */\n sessionId?: string;\n /** Auto-select highest priority session */\n auto?: boolean;\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Loads sessions from the todo directory.\n */\nasync function loadTodoSessions(config: SessionDirectoryConfig): Promise<Session[]> {\n try {\n const files = await readdir(config.todoDir);\n const sessions: Session[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".md\")) continue;\n\n const id = file.replace(\".md\", \"\");\n const filePath = join(config.todoDir, file);\n const content = await readFile(filePath, \"utf-8\");\n const metadata = parseSessionMetadata(content);\n\n sessions.push({\n id,\n status: PICKUP_SOURCE_STATUS,\n path: filePath,\n metadata,\n });\n }\n\n return sessions;\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Executes the pickup command.\n *\n * Claims a session from the todo queue and moves it to doing.\n * Output includes `<PICKUP_ID>` tag for easy parsing by automation tools.\n *\n * @param options - Command options\n * @returns Formatted output for display with parseable session ID\n * @throws {NoSessionsAvailableError} When no sessions in todo for auto mode\n * @throws {SessionNotAvailableError} When session already claimed\n */\nexport async function pickupCommand(options: PickupOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n let sessionId: string;\n\n if (options.auto) {\n // Auto mode: select best session\n const sessions = await loadTodoSessions(config);\n const selected = selectBestSession(sessions);\n\n if (!selected) {\n throw new NoSessionsAvailableError();\n }\n\n sessionId = selected.id;\n } else if (options.sessionId) {\n sessionId = options.sessionId;\n } else {\n throw new Error(\"Either session ID or --auto flag is required\");\n }\n\n // Build paths and ensure doing directory exists\n const paths = buildClaimPaths(sessionId, config);\n await mkdir(config.doingDir, { recursive: true });\n\n // Perform atomic claim\n try {\n await rename(paths.source, paths.target);\n } catch (error) {\n throw classifyClaimError(error, sessionId);\n }\n\n // Read and format content\n const content = await readFile(paths.target, \"utf-8\");\n const output = formatShowOutput(content, { status: PICKUP_TARGET_STATUS });\n\n // Output with parseable PICKUP_ID tag\n return `Claimed session <PICKUP_ID>${sessionId}</PICKUP_ID>\\n\\n${output}`;\n}\n","/**\n * Session pickup/claiming utilities.\n *\n * This module provides pure functions for atomic session claiming:\n * - Path construction for claim operations\n * - Error classification for claim failures\n * - Session selection for auto-pickup\n *\n * @module session/pickup\n */\n\nimport { SessionNotAvailableError } from \"./errors\";\nimport { parseSessionId } from \"./timestamp\";\nimport { PRIORITY_ORDER, type Session } from \"./types\";\n\n/**\n * Configuration for session claim paths.\n */\nexport interface ClaimPathConfig {\n /** Directory containing sessions to be claimed */\n todoDir: string;\n /** Directory for claimed sessions */\n doingDir: string;\n}\n\n/**\n * Result of building claim paths.\n */\nexport interface ClaimPaths {\n /** Source path (session in todo) */\n source: string;\n /** Target path (session in doing) */\n target: string;\n}\n\n/**\n * Builds source and target paths for claiming a session.\n *\n * @param sessionId - The session ID (timestamp format)\n * @param config - Directory configuration\n * @returns Source and target paths for the claim operation\n *\n * @example\n * ```typescript\n * const paths = buildClaimPaths(\"2026-01-13_08-01-05\", {\n * todoDir: \".spx/sessions/todo\",\n * doingDir: \".spx/sessions/doing\",\n * });\n * // => { source: \".spx/sessions/todo/2026-01-13_08-01-05.md\", target: \".spx/sessions/doing/2026-01-13_08-01-05.md\" }\n * ```\n */\nexport function buildClaimPaths(sessionId: string, config: ClaimPathConfig): ClaimPaths {\n return {\n source: `${config.todoDir}/${sessionId}.md`,\n target: `${config.doingDir}/${sessionId}.md`,\n };\n}\n\n/**\n * Classifies a filesystem error that occurred during claiming.\n *\n * When a claim operation fails, this function maps the raw filesystem\n * error to an appropriate domain error:\n * - ENOENT: Session was claimed by another agent (SessionNotAvailable)\n * - Other errors: Rethrown as-is\n *\n * @param error - The error from the claim operation\n * @param sessionId - The session ID being claimed\n * @returns A SessionNotAvailableError if ENOENT\n * @throws The original error if not ENOENT\n *\n * @example\n * ```typescript\n * const err = Object.assign(new Error(\"ENOENT\"), { code: \"ENOENT\" });\n * const classified = classifyClaimError(err, \"test-id\");\n * // => SessionNotAvailableError\n * ```\n */\nexport function classifyClaimError(error: unknown, sessionId: string): SessionNotAvailableError {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return new SessionNotAvailableError(sessionId);\n }\n throw error;\n}\n\n/**\n * Selects the best session for auto-pickup based on priority and timestamp.\n *\n * Selection criteria:\n * 1. Highest priority (high > medium > low)\n * 2. Oldest timestamp (FIFO) for sessions with equal priority\n *\n * @param sessions - Available sessions to choose from\n * @returns The best session to claim, or null if no sessions available\n *\n * @example\n * ```typescript\n * const sessions = [\n * { id: \"low-1\", metadata: { priority: \"low\" } },\n * { id: \"high-1\", metadata: { priority: \"high\" } },\n * ];\n * const best = selectBestSession(sessions);\n * // => { id: \"high-1\", ... }\n * ```\n */\nexport function selectBestSession(sessions: Session[]): Session | null {\n if (sessions.length === 0) {\n return null;\n }\n\n // Sort by priority (high first) then by timestamp (oldest first for FIFO)\n const sorted = [...sessions].sort((a, b) => {\n // First: sort by priority (high = 0, medium = 1, low = 2)\n const priorityA = PRIORITY_ORDER[a.metadata.priority];\n const priorityB = PRIORITY_ORDER[b.metadata.priority];\n\n if (priorityA !== priorityB) {\n return priorityA - priorityB;\n }\n\n // Second: sort by timestamp (oldest first = FIFO = ascending)\n const dateA = parseSessionId(a.id);\n const dateB = parseSessionId(b.id);\n\n // Handle invalid session IDs by treating them as newest (go last)\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1; // a goes after b\n if (!dateB) return -1; // b goes after a\n\n return dateA.getTime() - dateB.getTime();\n });\n\n return sorted[0];\n}\n","/**\n * Session prune CLI command handler.\n *\n * @module commands/session/prune\n */\n\nimport { readdir, readFile, unlink } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { parseSessionMetadata } from \"@/domains/session/list\";\nimport { DEFAULT_KEEP_COUNT, selectSessionsToDelete } from \"@/domains/session/prune\";\nimport { SessionDirectoryConfig } from \"@/domains/session/show\";\nimport { Session, SESSION_STATUSES, SessionStatus } from \"@/domains/session/types\";\nimport { resolveSessionConfig } from \"@/git/root\";\n\nexport { DEFAULT_KEEP_COUNT };\n\n/** Prune operates only on archived sessions. */\nconst PRUNE_STATUS: SessionStatus = SESSION_STATUSES[2]; // archive\n\nexport const SESSION_PRUNE_OUTPUT = {\n DELETED: \"Deleted\",\n WOULD_DELETE: \"Would delete\",\n} as const;\n\n/**\n * Options for the prune command.\n */\nexport interface PruneOptions {\n /** Number of sessions to keep (default: 5) */\n keep?: number;\n /** Show what would be deleted without actually deleting */\n dryRun?: boolean;\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Error thrown when prune options are invalid.\n */\nexport class PruneValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PruneValidationError\";\n }\n}\n\n/**\n * Validates prune options.\n *\n * @param options - Options to validate\n * @throws {PruneValidationError} When options are invalid\n */\nexport function validatePruneOptions(options: PruneOptions): void {\n if (options.keep !== undefined) {\n if (!Number.isInteger(options.keep) || options.keep < 1) {\n throw new PruneValidationError(\n `Invalid --keep value: ${options.keep}. Must be a positive integer.`,\n );\n }\n }\n}\n\n/**\n * Loads sessions from the archive directory.\n */\nasync function loadArchiveSessions(config: SessionDirectoryConfig): Promise<Session[]> {\n try {\n const files = await readdir(config.archiveDir);\n const sessions: Session[] = [];\n\n for (const file of files) {\n if (!file.endsWith(\".md\")) continue;\n\n const id = file.replace(\".md\", \"\");\n const filePath = join(config.archiveDir, file);\n const content = await readFile(filePath, \"utf-8\");\n const metadata = parseSessionMetadata(content);\n\n sessions.push({\n id,\n status: PRUNE_STATUS,\n path: filePath,\n metadata,\n });\n }\n\n return sessions;\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Executes the prune command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {PruneValidationError} When options are invalid\n */\nexport async function pruneCommand(options: PruneOptions): Promise<string> {\n // Validate options\n validatePruneOptions(options);\n\n const keep = options.keep ?? DEFAULT_KEEP_COUNT;\n const dryRun = options.dryRun ?? false;\n\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n // Load and sort sessions\n const sessions = await loadArchiveSessions(config);\n const toPrune = selectSessionsToDelete(sessions, { keep });\n\n if (toPrune.length === 0) {\n return `No sessions to prune. ${sessions.length} sessions kept.`;\n }\n\n // Dry run mode\n if (dryRun) {\n const lines = [\n `${SESSION_PRUNE_OUTPUT.WOULD_DELETE} ${toPrune.length} sessions:`,\n ...toPrune.map((s) => ` - ${s.id}`),\n \"\",\n `${sessions.length - toPrune.length} sessions would be kept.`,\n ];\n return lines.join(\"\\n\");\n }\n\n // Delete sessions\n for (const session of toPrune) {\n await unlink(session.path);\n }\n\n const lines = [\n `${SESSION_PRUNE_OUTPUT.DELETED} ${toPrune.length} sessions:`,\n ...toPrune.map((s) => ` - ${s.id}`),\n \"\",\n `${sessions.length - toPrune.length} sessions kept.`,\n ];\n return lines.join(\"\\n\");\n}\n","/**\n * Session pruning utilities for cleaning up old sessions.\n *\n * @module session/prune\n */\n\nimport { parseSessionId } from \"./timestamp\";\nimport type { Session } from \"./types\";\n\n/**\n * Default number of sessions to keep when pruning.\n */\nexport const DEFAULT_KEEP_COUNT = 5;\n\n/**\n * Options for selecting sessions to delete.\n */\nexport interface SelectSessionsOptions {\n /**\n * Number of most recent sessions to keep.\n * Defaults to DEFAULT_KEEP_COUNT (5).\n */\n keep?: number;\n}\n\n/**\n * Selects sessions to delete based on keep count.\n *\n * Sessions are sorted by timestamp (oldest first), and the oldest sessions\n * beyond the keep count are selected for deletion.\n *\n * @param sessions - Array of sessions to consider\n * @param options - Selection options including keep count\n * @returns Array of sessions to delete (oldest sessions beyond keep count)\n *\n * @example\n * ```typescript\n * // Given 10 sessions, keep 5 newest\n * const toDelete = selectSessionsToDelete(sessions, { keep: 5 });\n * // Returns the 5 oldest sessions\n *\n * // Using default keep count (5)\n * const toDelete = selectSessionsToDelete(sessions);\n * ```\n */\nexport function selectSessionsToDelete(\n sessions: Session[],\n options: SelectSessionsOptions = {},\n): Session[] {\n const keep = options.keep ?? DEFAULT_KEEP_COUNT;\n\n // If we have fewer sessions than the keep count, delete nothing\n if (sessions.length <= keep) {\n return [];\n }\n\n // Sort sessions by timestamp (oldest first for deletion selection)\n const sorted = [...sessions].sort((a, b) => {\n const dateA = parseSessionId(a.id);\n const dateB = parseSessionId(b.id);\n\n // Handle invalid session IDs by treating them as oldest (delete first)\n if (!dateA && !dateB) return 0;\n if (!dateA) return -1; // a (invalid) goes before b (to be deleted first)\n if (!dateB) return 1; // b (invalid) goes before a\n\n return dateA.getTime() - dateB.getTime();\n });\n\n // Return the oldest sessions (those beyond the keep count)\n const deleteCount = sessions.length - keep;\n return sorted.slice(0, deleteCount);\n}\n","/**\n * Session release CLI command handler.\n *\n * @module commands/session/release\n */\n\nimport { readdir, rename } from \"node:fs/promises\";\n\nimport { processBatch } from \"@/domains/session/batch\";\nimport { SessionNotClaimedError } from \"@/domains/session/errors\";\nimport { buildReleasePaths, findCurrentSession } from \"@/domains/session/release\";\nimport { SessionDirectoryConfig } from \"@/domains/session/show\";\nimport { resolveSessionConfig } from \"@/git/root\";\n\nexport const SESSION_RELEASE_OUTPUT = {\n RELEASED: \"Released session\",\n RETURNED_TO_TODO: \"Session returned to todo directory.\",\n} as const;\n\n/**\n * Options for the release command.\n */\nexport interface ReleaseOptions {\n /** Session IDs to release. Empty array defaults to most recent in doing. */\n sessionIds: string[];\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Loads session refs from the doing directory.\n */\nasync function loadDoingSessions(config: SessionDirectoryConfig): Promise<Array<{ id: string }>> {\n try {\n const files = await readdir(config.doingDir);\n return files\n .filter((file) => file.endsWith(\".md\"))\n .map((file) => ({ id: file.replace(\".md\", \"\") }));\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Releases a single claimed session by ID.\n */\nasync function releaseSingle(sessionId: string, config: SessionDirectoryConfig): Promise<string> {\n const paths = buildReleasePaths(sessionId, config);\n\n try {\n await rename(paths.source, paths.target);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n throw new SessionNotClaimedError(sessionId);\n }\n throw error;\n }\n\n return `${SESSION_RELEASE_OUTPUT.RELEASED}: ${sessionId}\\n${SESSION_RELEASE_OUTPUT.RETURNED_TO_TODO}`;\n}\n\n/**\n * Executes the release command for zero or more session IDs.\n *\n * When `sessionIds` is empty, the most recently claimed session in doing is released.\n * When one or more IDs are provided, all are processed in argument order.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {BatchError} When one or more IDs fail\n * @throws {SessionNotClaimedError} When no session is claimed (empty IDs) or session not in doing (single ID)\n */\nexport async function releaseCommand(options: ReleaseOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n let ids = options.sessionIds;\n\n if (ids.length === 0) {\n const sessions = await loadDoingSessions(config);\n const current = findCurrentSession(sessions);\n\n if (!current) {\n throw new SessionNotClaimedError(\"(none)\");\n }\n\n ids = [current.id];\n }\n\n return processBatch(ids, (id) => releaseSingle(id, config));\n}\n","/**\n * Session release utilities.\n *\n * This module provides pure functions for releasing claimed sessions:\n * - Path construction for release operations\n * - Finding the current session in doing directory\n *\n * @module session/release\n */\n\nimport { parseSessionId } from \"./timestamp\";\n\n/**\n * Configuration for session release paths.\n */\nexport interface ReleasePathConfig {\n /** Directory containing claimed sessions */\n doingDir: string;\n /** Directory for released sessions */\n todoDir: string;\n}\n\n/**\n * Result of building release paths.\n */\nexport interface ReleasePaths {\n /** Source path (session in doing) */\n source: string;\n /** Target path (session in todo) */\n target: string;\n}\n\n/**\n * Session reference with minimal required fields.\n */\nexport interface SessionRef {\n id: string;\n}\n\n/**\n * Builds source and target paths for releasing a session.\n *\n * @param sessionId - The session ID (timestamp format)\n * @param config - Directory configuration\n * @returns Source and target paths for the release operation\n *\n * @example\n * ```typescript\n * const paths = buildReleasePaths(\"2026-01-13_08-01-05\", {\n * doingDir: \".spx/sessions/doing\",\n * todoDir: \".spx/sessions/todo\",\n * });\n * // => { source: \".spx/sessions/doing/2026-01-13_08-01-05.md\", target: \".spx/sessions/todo/2026-01-13_08-01-05.md\" }\n * ```\n */\nexport function buildReleasePaths(sessionId: string, config: ReleasePathConfig): ReleasePaths {\n return {\n source: `${config.doingDir}/${sessionId}.md`,\n target: `${config.todoDir}/${sessionId}.md`,\n };\n}\n\n/**\n * Finds the most recent session in the doing directory.\n *\n * When no session ID is provided to release, this function\n * selects the most recently claimed session (newest timestamp).\n *\n * @param doingSessions - Sessions currently in doing directory\n * @returns The most recent session, or null if empty\n *\n * @example\n * ```typescript\n * const sessions = [\n * { id: \"2026-01-10_08-00-00\" },\n * { id: \"2026-01-13_08-00-00\" },\n * ];\n * const current = findCurrentSession(sessions);\n * // => { id: \"2026-01-13_08-00-00\" }\n * ```\n */\nexport function findCurrentSession(doingSessions: SessionRef[]): SessionRef | null {\n if (doingSessions.length === 0) {\n return null;\n }\n\n // Sort by timestamp descending (newest first)\n const sorted = [...doingSessions].sort((a, b) => {\n const dateA = parseSessionId(a.id);\n const dateB = parseSessionId(b.id);\n\n // Handle invalid session IDs by treating them as oldest\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1; // a goes after b\n if (!dateB) return -1; // b goes after a\n\n return dateB.getTime() - dateA.getTime();\n });\n\n return sorted[0];\n}\n","/**\n * Session show CLI command handler.\n *\n * @module commands/session/show\n */\n\nimport { readFile, stat } from \"node:fs/promises\";\n\nimport { processBatch } from \"@/domains/session/batch\";\nimport { SessionNotFoundError } from \"@/domains/session/errors\";\nimport { formatShowOutput, resolveSessionPaths, SEARCH_ORDER, SessionDirectoryConfig } from \"@/domains/session/show\";\nimport { SessionStatus } from \"@/domains/session/types\";\nimport { resolveSessionConfig } from \"@/git/root\";\n\n/**\n * Options for the show command.\n */\nexport interface ShowOptions {\n /** Session ID(s) to show */\n sessionIds: string[];\n /** Custom sessions directory */\n sessionsDir?: string;\n}\n\n/**\n * Finds the first existing path and its status.\n */\nasync function findExistingPath(\n paths: string[],\n _config: SessionDirectoryConfig,\n): Promise<{ path: string; status: SessionStatus } | null> {\n for (let i = 0; i < paths.length; i++) {\n const filePath = paths[i];\n try {\n const stats = await stat(filePath);\n if (stats.isFile()) {\n return { path: filePath, status: SEARCH_ORDER[i] };\n }\n } catch {\n // File doesn't exist, continue\n }\n }\n return null;\n}\n\n/**\n * Executes the show command.\n *\n * @param options - Command options\n * @returns Formatted output for display\n * @throws {SessionNotFoundError} When session not found\n */\n/**\n * Shows a single session by ID.\n */\nasync function showSingle(\n sessionId: string,\n config: SessionDirectoryConfig,\n): Promise<string> {\n const paths = resolveSessionPaths(sessionId, config);\n const found = await findExistingPath(paths, config);\n\n if (!found) {\n throw new SessionNotFoundError(sessionId);\n }\n\n const content = await readFile(found.path, \"utf-8\");\n return formatShowOutput(content, { status: found.status });\n}\n\n/**\n * Executes the show command for one or more session IDs.\n *\n * @param options - Command options with one or more session IDs\n * @returns Formatted output for display\n * @throws {BatchError} When one or more IDs fail\n * @throws {SessionNotFoundError} When session not found (single ID)\n */\nexport async function showCommand(options: ShowOptions): Promise<string> {\n const { config } = await resolveSessionConfig({ sessionsDir: options.sessionsDir });\n\n return processBatch(options.sessionIds, (id) => showSingle(id, config));\n}\n","/**\n * Shared help text for session commands.\n *\n * Centralizes help text to ensure consistency across subcommands.\n *\n * @module domains/session/help\n */\n\n/**\n * Session file format description for the main session help.\n */\nexport const SESSION_FORMAT_HELP = `\nSession File Format:\n Sessions are markdown files with YAML frontmatter for metadata.\n\n ---\n priority: high | medium | low\n tags: [tag1, tag2]\n ---\n # Session Title\n\n Session content...\n\nWorkflow:\n 1. handoff - Create session (todo)\n 2. pickup - Claim session (todo -> doing)\n 3. release - Return session (doing -> todo)\n 4. archive - Move session to archive\n 5. delete - Remove session permanently\n`;\n\n/**\n * Frontmatter details for handoff command.\n */\nexport const HANDOFF_FRONTMATTER_HELP = `\nUsage:\n Option 1: Pipe content with frontmatter via stdin\n Option 2: Run without stdin, then edit the created file directly\n\nFrontmatter Format:\n ---\n priority: high # high | medium | low (default: medium)\n tags: [feat, api] # optional labels for categorization\n ---\n # Your session content here...\n\nOutput Tags (for automation):\n <HANDOFF_ID>session-id</HANDOFF_ID> - Session identifier\n <SESSION_FILE>/path/to/file</SESSION_FILE> - Absolute path to edit\n\nExamples:\n # With stdin content:\n echo '---\n priority: high\n ---\n # Fix login' | spx session handoff\n\n # Without stdin (creates empty session, edit file directly):\n spx session handoff\n`;\n\n/**\n * Selection logic for pickup command.\n */\nexport const PICKUP_SELECTION_HELP = `\nSelection Logic (--auto):\n Sessions are selected by priority, then age (FIFO):\n 1. high priority first\n 2. medium priority second\n 3. low priority last\n 4. Within same priority: oldest session first\n\nOutput:\n <PICKUP_ID>session-id</PICKUP_ID> tag for automation parsing\n`;\n","/**\n * Session domain - Manage session workflow\n */\nimport type { Command } from \"commander\";\n\nimport {\n archiveCommand,\n deleteCommand,\n handoffCommand,\n listCommand,\n pickupCommand,\n pruneCommand,\n PruneValidationError,\n releaseCommand,\n SessionAlreadyArchivedError,\n showCommand,\n} from \"@/commands/session/index\";\nimport type { Domain } from \"../types\";\nimport { HANDOFF_FRONTMATTER_HELP, PICKUP_SELECTION_HELP, SESSION_FORMAT_HELP } from \"./help\";\nimport { SESSION_STATUSES } from \"./types\";\n\n/**\n * Reads content from stdin if available (piped input).\n * Returns undefined if stdin is a TTY (interactive terminal).\n */\nasync function readStdin(): Promise<string | undefined> {\n // Check if stdin is a TTY (interactive) - if so, don't wait for input\n if (process.stdin.isTTY) {\n return undefined;\n }\n\n return new Promise((resolve) => {\n let data = \"\";\n process.stdin.setEncoding(\"utf-8\");\n process.stdin.on(\"data\", (chunk) => {\n data += chunk;\n });\n process.stdin.on(\"end\", () => {\n resolve(data.trim() || undefined);\n });\n // Handle case where stdin closes without data\n process.stdin.on(\"error\", () => {\n resolve(undefined);\n });\n });\n}\n\n/**\n * Handles command errors with consistent formatting.\n */\nfunction handleError(error: unknown): never {\n console.error(\"Error:\", error instanceof Error ? error.message : String(error));\n process.exit(1);\n}\n\n/**\n * Register session domain commands\n *\n * @param sessionCmd - Commander.js session domain command\n */\nfunction registerSessionCommands(sessionCmd: Command): void {\n // list command\n sessionCmd\n .command(\"list\")\n .description(\"List active sessions (doing + todo by default)\")\n .option(\"--status <status>\", \"Filter by status (todo|doing|archive); defaults to doing + todo\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (options: { status?: string; json?: boolean; sessionsDir?: string }) => {\n try {\n const output = await listCommand({\n status: options.status,\n format: options.json ? \"json\" : \"text\",\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // todo command (convenience alias for list --status todo)\n sessionCmd\n .command(\"todo\")\n .description(\"List todo sessions\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (options: { json?: boolean; sessionsDir?: string }) => {\n try {\n const output = await listCommand({\n status: SESSION_STATUSES[0],\n format: options.json ? \"json\" : \"text\",\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // show command\n sessionCmd\n .command(\"show <id...>\")\n .description(\"Show session content\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (ids: string[], options: { sessionsDir?: string }) => {\n try {\n const output = await showCommand({\n sessionIds: ids,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // pickup command\n sessionCmd\n .command(\"pickup [id]\")\n .description(\"Claim a session (move from todo to doing)\")\n .option(\"--auto\", \"Auto-select highest priority session\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .addHelpText(\"after\", PICKUP_SELECTION_HELP)\n .action(async (id: string | undefined, options: { auto?: boolean; sessionsDir?: string }) => {\n try {\n if (!id && !options.auto) {\n console.error(\"Error: Either session ID or --auto flag is required\");\n process.exit(1);\n }\n const output = await pickupCommand({\n sessionId: id,\n auto: options.auto,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // release command\n sessionCmd\n .command(\"release [ids...]\")\n .description(\"Release one or more sessions (move from doing to todo)\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (ids: string[], options: { sessionsDir?: string }) => {\n try {\n const output = await releaseCommand({\n sessionIds: ids,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // handoff command\n // Note: --priority and --tags removed. Metadata should be in content frontmatter.\n // This makes the command deterministic for Claude Code permission pre-approval.\n sessionCmd\n .command(\"handoff\")\n .description(\"Create a handoff session (reads content with frontmatter from stdin)\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .addHelpText(\"after\", HANDOFF_FRONTMATTER_HELP)\n .action(async (options: { sessionsDir?: string }) => {\n try {\n // Read content from stdin if available\n const content = await readStdin();\n\n const output = await handoffCommand({\n content,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // delete command\n sessionCmd\n .command(\"delete <id...>\")\n .description(\"Delete one or more sessions\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (ids: string[], options: { sessionsDir?: string }) => {\n try {\n const output = await deleteCommand({\n sessionIds: ids,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n handleError(error);\n }\n });\n\n // prune command\n sessionCmd\n .command(\"prune\")\n .description(\"Remove old todo sessions, keeping the most recent N\")\n .option(\"--keep <count>\", \"Number of sessions to keep (default: 5)\", \"5\")\n .option(\"--dry-run\", \"Show what would be deleted without deleting\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (options: { keep?: string; dryRun?: boolean; sessionsDir?: string }) => {\n try {\n const keep = options.keep ? Number.parseInt(options.keep, 10) : undefined;\n const output = await pruneCommand({\n keep,\n dryRun: options.dryRun,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n if (error instanceof PruneValidationError) {\n console.error(\"Error:\", error.message);\n process.exit(1);\n }\n handleError(error);\n }\n });\n\n // archive command\n sessionCmd\n .command(\"archive <id...>\")\n .description(\"Move one or more sessions to the archive directory\")\n .option(\"--sessions-dir <path>\", \"Custom sessions directory\")\n .action(async (ids: string[], options: { sessionsDir?: string }) => {\n try {\n const output = await archiveCommand({\n sessionIds: ids,\n sessionsDir: options.sessionsDir,\n });\n console.log(output);\n } catch (error) {\n if (error instanceof SessionAlreadyArchivedError) {\n console.error(\"Error:\", error.message);\n process.exit(1);\n }\n handleError(error);\n }\n });\n}\n\n/**\n * Session domain - Manage session workflow\n */\nexport const sessionDomain: Domain = {\n name: \"session\",\n description: \"Manage session workflow\",\n register: (program: Command) => {\n const sessionCmd = program\n .command(\"session\")\n .description(\"Manage session workflow\")\n .addHelpText(\"after\", SESSION_FORMAT_HELP);\n\n registerSessionCommands(sessionCmd);\n },\n};\n","/**\n * Spec domain - Manage spec workflow\n */\nimport { access, readFile, writeFile } from \"node:fs/promises\";\n\nimport type { Command } from \"commander\";\n\nimport { nextCommand } from \"@/commands/spec/next\";\nimport { type OutputFormat, statusCommand } from \"@/commands/spec/status\";\nimport { APPLY_HELP } from \"@/domains/spec/apply/exclude/help\";\nimport { applyExcludeCommand } from \"@/domains/spec/apply/exclude/index\";\nimport type { Domain } from \"../types\";\n\nconst VALID_STATUS_FORMATS: readonly OutputFormat[] = [\n \"text\",\n \"json\",\n \"markdown\",\n \"table\",\n];\n\nfunction handleCommandError(error: unknown): never {\n console.error(\"Error:\", error instanceof Error ? error.message : String(error));\n process.exit(1);\n}\n\nfunction resolveStatusFormat(options: { json?: boolean; format?: string }): OutputFormat {\n if (options.json === true) {\n return \"json\";\n }\n\n if (options.format === undefined) {\n return \"text\";\n }\n\n if (VALID_STATUS_FORMATS.includes(options.format as OutputFormat)) {\n return options.format as OutputFormat;\n }\n\n throw new Error(\n `Invalid format \"${options.format}\". Must be one of: ${VALID_STATUS_FORMATS.join(\", \")}`,\n );\n}\n\nfunction registerSpecCommands(specCmd: Command): void {\n specCmd\n .command(\"status\")\n .description(\"Get project status\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"--format <format>\", \"Output format (text|json|markdown|table)\")\n .action(async (options: { json?: boolean; format?: string }) => {\n try {\n const output = await statusCommand({\n cwd: process.cwd(),\n format: resolveStatusFormat(options),\n });\n console.log(output);\n } catch (error) {\n handleCommandError(error);\n }\n });\n\n specCmd\n .command(\"next\")\n .description(\"Find next work item to work on\")\n .action(async () => {\n try {\n const output = await nextCommand({ cwd: process.cwd() });\n console.log(output);\n } catch (error) {\n handleCommandError(error);\n }\n });\n\n specCmd\n .command(\"apply\")\n .description(\"Apply spec-tree state to project configuration\")\n .addHelpText(\"after\", APPLY_HELP)\n .action(async () => {\n try {\n const result = await applyExcludeCommand({\n cwd: process.cwd(),\n deps: {\n readFile: (path: string) => readFile(path, \"utf-8\"),\n writeFile: (path: string, content: string) => writeFile(path, content, \"utf-8\"),\n fileExists: async (path: string) => {\n try {\n await access(path);\n return true;\n } catch {\n return false;\n }\n },\n },\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n } catch (error) {\n handleCommandError(error);\n }\n });\n}\n\n/**\n * Spec domain - Manage spec workflow\n */\nexport const specDomain: Domain = {\n name: \"spec\",\n description: \"Manage spec workflow\",\n register: (program: Command) => {\n const specCmd = program\n .command(\"spec\")\n .description(\"Manage spec workflow\");\n\n registerSpecCommands(specCmd);\n },\n};\n","/**\n * Scanner class for discovering work items in a project\n *\n * Encapsulates directory walking, filtering, and work item building with\n * configurable paths via dependency injection.\n *\n * @module scanner/scanner\n */\nimport type { SpxConfig } from \"@/config/defaults\";\nimport path from \"node:path\";\nimport type { WorkItem } from \"../types\";\nimport { buildWorkItemList, filterWorkItemDirectories, walkDirectory } from \"./walk\";\n\n/**\n * Scanner for discovering work items in a project\n *\n * Uses dependency injection for configuration, eliminating hardcoded paths.\n * All directory paths are derived from the injected SpxConfig.\n *\n * @example\n * ```typescript\n * import { DEFAULT_CONFIG } from \"@/config/defaults\";\n *\n * const scanner = new Scanner(\"/path/to/project\", DEFAULT_CONFIG);\n * const workItems = await scanner.scan();\n * ```\n */\nexport class Scanner {\n /**\n * Create a new Scanner instance\n *\n * @param projectRoot - Absolute path to the project root directory\n * @param config - Configuration object defining directory structure\n */\n constructor(\n private readonly projectRoot: string,\n private readonly config: SpxConfig,\n ) {}\n\n /**\n * Scan the project for work items in the \"doing\" status directory\n *\n * Walks the configured specs/work/doing directory, filters for valid\n * work item directories, and returns structured work item data.\n *\n * @returns Array of work items found in the doing directory\n * @throws Error if the directory doesn't exist or is inaccessible\n */\n async scan(): Promise<WorkItem[]> {\n const doingPath = this.getDoingPath();\n\n // Walk directory to find all subdirectories\n const allEntries = await walkDirectory(doingPath);\n\n // Filter to only valid work item directories\n const workItemEntries = filterWorkItemDirectories(allEntries);\n\n // Build work item list with metadata\n return buildWorkItemList(workItemEntries);\n }\n\n /**\n * Get the full path to the \"doing\" status directory\n *\n * Constructs path from config: {projectRoot}/{specs.root}/{work.dir}/{statusDirs.doing}\n *\n * @returns Absolute path to the doing directory\n */\n getDoingPath(): string {\n return path.join(\n this.projectRoot,\n this.config.specs.root,\n this.config.specs.work.dir,\n this.config.specs.work.statusDirs.doing,\n );\n }\n\n /**\n * Get the full path to the \"backlog\" status directory\n *\n * @returns Absolute path to the backlog directory\n */\n getBacklogPath(): string {\n return path.join(\n this.projectRoot,\n this.config.specs.root,\n this.config.specs.work.dir,\n this.config.specs.work.statusDirs.backlog,\n );\n }\n\n /**\n * Get the full path to the \"done\" status directory\n *\n * @returns Absolute path to the done/archive directory\n */\n getDonePath(): string {\n return path.join(\n this.projectRoot,\n this.config.specs.root,\n this.config.specs.work.dir,\n this.config.specs.work.statusDirs.done,\n );\n }\n\n /**\n * Get the full path to the specs root directory\n *\n * @returns Absolute path to the specs root\n */\n getSpecsRootPath(): string {\n return path.join(this.projectRoot, this.config.specs.root);\n }\n\n /**\n * Get the full path to the work directory\n *\n * @returns Absolute path to the work directory\n */\n getWorkPath(): string {\n return path.join(\n this.projectRoot,\n this.config.specs.root,\n this.config.specs.work.dir,\n );\n }\n}\n","/**\n * Directory walking and filesystem traversal\n */\nimport fs from \"fs/promises\";\nimport path from \"path\";\nimport type { DirectoryEntry, WorkItem } from \"../types\";\nimport { parseWorkItemName } from \"./patterns\";\n\n/**\n * Recursively walk a directory tree and return all subdirectories\n *\n * @param root - Root directory path to start walking from\n * @param visited - Set of visited paths to avoid symlink loops (internal use)\n * @returns Promise resolving to array of directory entries\n * @throws Error if root directory doesn't exist or permission denied\n *\n * @example\n * ```typescript\n * const entries = await walkDirectory(\"/path/to/specs\");\n * // Returns: [{ name: \"capability-21_test\", path: \"/path/to/specs/capability-21_test\", isDirectory: true }, ...]\n * ```\n */\nexport async function walkDirectory(\n root: string,\n visited: Set<string> = new Set(),\n): Promise<DirectoryEntry[]> {\n // Normalize and resolve path to handle symlinks\n const normalizedRoot = path.resolve(root);\n\n // Check for symlink loops\n if (visited.has(normalizedRoot)) {\n return []; // Skip already visited directories\n }\n visited.add(normalizedRoot);\n\n try {\n // Read directory contents\n const entries = await fs.readdir(normalizedRoot, { withFileTypes: true });\n const results: DirectoryEntry[] = [];\n\n for (const entry of entries) {\n const fullPath = path.join(normalizedRoot, entry.name);\n\n // Only process directories\n if (entry.isDirectory()) {\n // Add current directory\n results.push({\n name: entry.name,\n path: fullPath,\n isDirectory: true,\n });\n\n // Recursively walk subdirectories\n const subEntries = await walkDirectory(fullPath, visited);\n results.push(...subEntries);\n }\n }\n\n return results;\n } catch (error) {\n // Re-throw with more context\n if (error instanceof Error) {\n throw new Error(\n `Failed to walk directory \"${normalizedRoot}\": ${error.message}`,\n );\n }\n throw error;\n }\n}\n\n/**\n * Filter directory entries to include only work item directories\n *\n * Uses parseWorkItemName() to validate directory names match work item patterns.\n * Excludes directories that don't match capability/feature/story patterns.\n *\n * @param entries - Array of directory entries to filter\n * @returns Filtered array containing only valid work item directories\n *\n * @example\n * ```typescript\n * const entries = [\n * { name: \"capability-21_test\", path: \"/specs/capability-21_test\", isDirectory: true },\n * { name: \"node_modules\", path: \"/specs/node_modules\", isDirectory: true },\n * ];\n * const filtered = filterWorkItemDirectories(entries);\n * // Returns: [{ name: \"capability-21_test\", ... }]\n * ```\n */\nexport function filterWorkItemDirectories(\n entries: DirectoryEntry[],\n): DirectoryEntry[] {\n return entries.filter((entry) => {\n try {\n // Try to parse the directory name as a work item\n parseWorkItemName(entry.name);\n return true; // Valid work item pattern\n } catch {\n return false; // Not a work item pattern\n }\n });\n}\n\n/**\n * Convert directory entries to WorkItem objects\n *\n * Parses each directory entry name to extract work item metadata (kind, number, slug)\n * and combines it with the full filesystem path.\n *\n * @param entries - Filtered directory entries (work items only)\n * @returns Array of WorkItem objects with full metadata\n * @throws Error if any entry has invalid work item pattern\n *\n * @example\n * ```typescript\n * const entries = [\n * { name: \"capability-21_core-cli\", path: \"/specs/capability-21_core-cli\", isDirectory: true },\n * ];\n * const workItems = buildWorkItemList(entries);\n * // Returns: [{ kind: \"capability\", number: 20, slug: \"core-cli\", path: \"/specs/capability-21_core-cli\" }]\n * ```\n */\nexport function buildWorkItemList(entries: DirectoryEntry[]): WorkItem[] {\n return entries.map((entry) => ({\n ...parseWorkItemName(entry.name),\n path: entry.path,\n }));\n}\n","/**\n * Validation functions for BSP (Behavior, Structure, Property) numbers\n */\n\n/**\n * BSP number range constants\n */\nexport const MIN_BSP_NUMBER = 10;\nexport const MAX_BSP_NUMBER = 99;\n\n/**\n * Check if a number is a valid BSP number\n *\n * @param n - Number to validate\n * @returns true if n is in range [10, 99], false otherwise\n *\n * @example\n * ```typescript\n * isValidBSPNumber(20) // true\n * isValidBSPNumber(9) // false\n * isValidBSPNumber(100) // false\n * ```\n */\nexport function isValidBSPNumber(n: number): boolean {\n return n >= MIN_BSP_NUMBER && n <= MAX_BSP_NUMBER;\n}\n\n/**\n * Validate a BSP number and throw if invalid\n *\n * @param n - Number to validate\n * @returns The validated number\n * @throws Error if the number is outside the valid range [10, 99]\n *\n * @example\n * ```typescript\n * validateBSPNumber(20) // returns 20\n * validateBSPNumber(5) // throws Error: \"BSP number must be between 10 and 99, got 5\"\n * ```\n */\nexport function validateBSPNumber(n: number): number {\n if (!isValidBSPNumber(n)) {\n throw new Error(\n `BSP number must be between ${MIN_BSP_NUMBER} and ${MAX_BSP_NUMBER}, got ${n}`,\n );\n }\n return n;\n}\n","/**\n * Pattern matching for work item directory names\n */\nimport type { WorkItem, WorkItemKind } from \"../types\";\nimport { validateBSPNumber } from \"./validation\";\n\n/**\n * Regex pattern for work item directory names\n * Format: {kind}-{number}_{slug}\n * - kind: capability, feature, or story\n * - number: BSP number (10-99)\n * - slug: kebab-case identifier (lowercase, hyphens only)\n */\nconst WORK_ITEM_PATTERN = /^(capability|feature|story)-(\\d+)_([a-z][a-z0-9-]*)$/;\n\n/**\n * Parse a work item directory name into structured data\n *\n * @param dirName - Directory name to parse\n * @returns Parsed work item with kind, number, and slug (path not included)\n * @throws Error if the directory name doesn't match the pattern or BSP number is invalid\n *\n * @example\n * ```typescript\n * parseWorkItemName(\"capability-21_core-cli\")\n * // Returns: { kind: \"capability\", number: 20, slug: \"core-cli\" }\n *\n * parseWorkItemName(\"feature-21_pattern-matching\")\n * // Returns: { kind: \"feature\", number: 21, slug: \"pattern-matching\" }\n * ```\n */\nexport function parseWorkItemName(dirName: string): Omit<WorkItem, \"path\"> {\n const match = WORK_ITEM_PATTERN.exec(dirName);\n\n if (!match) {\n throw new Error(\n `Invalid work item name: \"${dirName}\". Expected format: {kind}-{number}_{slug} `\n + `(e.g., \"capability-21_core-cli\", \"feature-21_pattern-matching\")`,\n );\n }\n\n const kind = match[1] as WorkItemKind;\n const bspNumber = parseInt(match[2], 10);\n const slug = match[3];\n\n // Validate BSP number range using validation module\n validateBSPNumber(bspNumber);\n\n // Capabilities use 0-indexed numbers (directory number - 1)\n // Features and stories use directory number as-is\n const number = kind === \"capability\" ? bspNumber - 1 : bspNumber;\n\n return {\n kind,\n number,\n slug,\n };\n}\n","/**\n * Status determination state machine for work items\n */\nimport { access, readdir, stat } from \"fs/promises\";\nimport path from \"path\";\nimport { WorkItemStatus } from \"../types\";\n\n/**\n * Input flags for status determination\n */\nexport interface StatusFlags {\n /** Whether tests/ directory exists */\n hasTestsDir: boolean;\n /** Whether tests/DONE.md exists */\n hasDoneMd: boolean;\n /** Whether tests/ directory is empty (excluding DONE.md) */\n testsIsEmpty: boolean;\n}\n\n/**\n * Determines work item status based on tests/ directory state\n *\n * Truth Table:\n * | hasTestsDir | testsIsEmpty | hasDoneMd | Status |\n * |-------------|--------------|-----------|-------------|\n * | false | N/A | N/A | OPEN |\n * | true | true | false | OPEN |\n * | true | true | true | DONE |\n * | true | false | false | IN_PROGRESS |\n * | true | false | true | DONE |\n *\n * @param flags - Status determination flags\n * @returns Work item status as OPEN, IN_PROGRESS, or DONE\n *\n * @example\n * ```typescript\n * // No tests directory\n * determineStatus({ hasTestsDir: false, hasDoneMd: false, testsIsEmpty: true })\n * // => \"OPEN\"\n *\n * // Tests directory with files, no DONE.md\n * determineStatus({ hasTestsDir: true, hasDoneMd: false, testsIsEmpty: false })\n * // => \"IN_PROGRESS\"\n *\n * // Tests directory with DONE.md\n * determineStatus({ hasTestsDir: true, hasDoneMd: true, testsIsEmpty: false })\n * // => \"DONE\"\n * ```\n */\nexport function determineStatus(flags: StatusFlags): WorkItemStatus {\n // No tests directory → OPEN\n if (!flags.hasTestsDir) {\n return \"OPEN\";\n }\n\n // Has DONE.md → DONE (regardless of other files)\n if (flags.hasDoneMd) {\n return \"DONE\";\n }\n\n // Has tests directory but empty → OPEN\n if (flags.testsIsEmpty) {\n return \"OPEN\";\n }\n\n // Has tests directory with files, no DONE.md → IN_PROGRESS\n return \"IN_PROGRESS\";\n}\n\n/**\n * Checks if a work item has a tests/ directory\n *\n * @param workItemPath - Absolute path to the work item directory\n * @returns Promise resolving to true if tests/ exists, false otherwise\n *\n * @example\n * ```typescript\n * const hasTests = await hasTestsDirectory('/path/to/story-21');\n * // => true if /path/to/story-21/tests exists\n * ```\n */\nexport async function hasTestsDirectory(\n workItemPath: string,\n): Promise<boolean> {\n try {\n const testsPath = path.join(workItemPath, \"tests\");\n await access(testsPath);\n return true;\n } catch (error) {\n // ENOENT means directory doesn't exist → return false\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return false;\n }\n // Re-throw permission errors and other failures\n throw error;\n }\n}\n\n/**\n * Checks if a tests/ directory is empty (has no test files)\n *\n * A directory is considered empty if it contains no files, or only contains:\n * - DONE.md (completion marker, not a test)\n * - Dotfiles like .gitkeep (version control artifacts, not tests)\n *\n * @param testsPath - Absolute path to the tests/ directory\n * @returns Promise resolving to true if empty, false if has test files\n *\n * @example\n * ```typescript\n * // Directory with only DONE.md\n * await isTestsDirectoryEmpty('/path/to/tests');\n * // => true (DONE.md doesn't count as a test)\n *\n * // Directory with test files\n * await isTestsDirectoryEmpty('/path/to/tests');\n * // => false\n * ```\n */\nexport async function isTestsDirectoryEmpty(\n testsPath: string,\n): Promise<boolean> {\n try {\n const entries = await readdir(testsPath);\n\n // Filter out DONE.md and dotfiles\n const testFiles = entries.filter((entry) => {\n // Exclude DONE.md\n if (entry === \"DONE.md\") {\n return false;\n }\n // Exclude dotfiles (.gitkeep, .DS_Store, etc.)\n if (entry.startsWith(\".\")) {\n return false;\n }\n return true;\n });\n\n // Empty if no test files remain after filtering\n return testFiles.length === 0;\n } catch (error) {\n // ENOENT means directory doesn't exist → treat as empty\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return true;\n }\n // Re-throw permission errors and other failures\n throw error;\n }\n}\n\n/**\n * Checks if a tests/ directory contains a DONE.md file\n *\n * Verifies that DONE.md exists and is a regular file (not a directory).\n * The check is case-sensitive: only \"DONE.md\" is accepted.\n *\n * @param testsPath - Absolute path to the tests/ directory\n * @returns Promise resolving to true if DONE.md exists, false otherwise\n *\n * @example\n * ```typescript\n * // Tests directory with DONE.md\n * await hasDoneMd('/path/to/tests');\n * // => true\n *\n * // Tests directory without DONE.md\n * await hasDoneMd('/path/to/tests');\n * // => false\n * ```\n */\nexport async function hasDoneMd(testsPath: string): Promise<boolean> {\n try {\n // Case-sensitive check: read directory and verify exact filename\n const entries = await readdir(testsPath);\n\n // Check if \"DONE.md\" exists in the directory listing (case-sensitive)\n if (!entries.includes(\"DONE.md\")) {\n return false;\n }\n\n // Verify it's a regular file, not a directory\n const donePath = path.join(testsPath, \"DONE.md\");\n const stats = await stat(donePath);\n return stats.isFile();\n } catch (error) {\n // ENOENT means directory doesn't exist → return false\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return false;\n }\n // Re-throw permission errors and other failures\n throw error;\n }\n}\n\n/**\n * Custom error for status determination failures\n */\nexport class StatusDeterminationError extends Error {\n constructor(\n public readonly workItemPath: string,\n public readonly cause: unknown,\n ) {\n const errorMessage = cause instanceof Error ? cause.message : String(cause);\n super(`Failed to determine status for ${workItemPath}: ${errorMessage}`);\n this.name = \"StatusDeterminationError\";\n }\n}\n\n/**\n * Determines the status of a work item by checking its tests/ directory\n *\n * This is the main orchestration function that combines all status checks:\n * 1. Checks if tests/ directory exists\n * 2. Checks if tests/ has DONE.md\n * 3. Checks if tests/ is empty (excluding DONE.md)\n * 4. Determines final status based on these flags\n *\n * Performance: Uses caching strategy to minimize filesystem calls.\n * All checks for a single work item are performed in one pass.\n *\n * @param workItemPath - Absolute path to the work item directory\n * @returns Promise resolving to OPEN, IN_PROGRESS, or DONE\n * @throws {StatusDeterminationError} If work item doesn't exist or has permission errors\n *\n * @example\n * ```typescript\n * // Work item with no tests directory\n * await getWorkItemStatus('/path/to/story-21');\n * // => \"OPEN\"\n *\n * // Work item with tests but no DONE.md\n * await getWorkItemStatus('/path/to/story-32');\n * // => \"IN_PROGRESS\"\n *\n * // Work item with DONE.md\n * await getWorkItemStatus('/path/to/story-43');\n * // => \"DONE\"\n * ```\n */\nexport async function getWorkItemStatus(\n workItemPath: string,\n): Promise<WorkItemStatus> {\n try {\n const testsPath = path.join(workItemPath, \"tests\");\n let entries: string[];\n\n try {\n // Read tests/ once and reuse the listing for all subsequent checks.\n entries = await readdir(testsPath);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n try {\n await access(workItemPath);\n } catch (workItemError) {\n if ((workItemError as NodeJS.ErrnoException).code === \"ENOENT\") {\n throw new Error(`Work item not found: ${workItemPath}`);\n }\n\n throw workItemError;\n }\n\n return determineStatus({\n hasTestsDir: false,\n hasDoneMd: false,\n testsIsEmpty: true,\n });\n }\n\n throw error;\n }\n\n // Check for DONE.md from the cached entries before any extra stat call.\n const hasDone = entries.includes(\"DONE.md\");\n if (hasDone) {\n // Verify it's a file, not a directory\n const donePath = path.join(testsPath, \"DONE.md\");\n const stats = await stat(donePath);\n if (!stats.isFile()) {\n // DONE.md is a directory, treat as no DONE.md\n return determineStatus({\n hasTestsDir: true,\n hasDoneMd: false,\n testsIsEmpty: isEmptyFromEntries(entries),\n });\n }\n }\n\n // Check if empty from the same cached entries.\n const isEmpty = isEmptyFromEntries(entries);\n\n return determineStatus({\n hasTestsDir: true,\n hasDoneMd: hasDone,\n testsIsEmpty: isEmpty,\n });\n } catch (error) {\n // Wrap all errors with work item context\n throw new StatusDeterminationError(workItemPath, error);\n }\n}\n\n/**\n * Helper: Check if directory is empty from readdir entries\n * @param entries - Directory entries from readdir\n * @returns true if no test files (excluding DONE.md and dotfiles)\n */\nfunction isEmptyFromEntries(entries: string[]): boolean {\n const testFiles = entries.filter((entry) => {\n // Exclude DONE.md\n if (entry === \"DONE.md\") {\n return false;\n }\n // Exclude dotfiles (.gitkeep, .DS_Store, etc.)\n if (entry.startsWith(\".\")) {\n return false;\n }\n return true;\n });\n return testFiles.length === 0;\n}\n","/**\n * Tree building functions for converting flat work item lists to hierarchical trees\n */\nimport { getWorkItemStatus } from \"../status/state\";\nimport type { WorkItem, WorkItemStatus } from \"../types\";\nimport type { TreeNode, WorkItemTree } from \"./types\";\n\n/**\n * Dependencies for tree building (for testing)\n */\nexport interface TreeBuildDeps {\n getStatus?: (path: string) => Promise<string>;\n}\n\n/**\n * Build hierarchical tree from flat list of work items\n *\n * Creates parent-child relationships based on directory paths.\n * Children are BSP-sorted and status is rolled up from children.\n *\n * @param workItems - Flat list of work items from scanner\n * @param deps - Optional dependencies (for testing)\n * @returns Hierarchical tree structure\n * @throws Error if orphan work items detected (items without valid parents)\n *\n * @example\n * ```typescript\n * const workItems = await walkSpecs(\"/specs\");\n * const tree = await buildTree(workItems);\n * // tree.nodes contains top-level capabilities with nested children\n * ```\n */\nexport async function buildTree(\n workItems: WorkItem[],\n deps: TreeBuildDeps = {},\n): Promise<WorkItemTree> {\n const getStatus = deps.getStatus || getWorkItemStatus;\n\n // Step 1: Determine status for each work item\n const itemsWithStatus = await Promise.all(\n workItems.map(async (item) => ({\n ...item,\n status: await getStatus(item.path),\n })),\n );\n\n // Step 2: Separate work items by kind\n const capabilities = itemsWithStatus.filter(\n (item) => item.kind === \"capability\",\n );\n const features = itemsWithStatus.filter((item) => item.kind === \"feature\");\n const stories = itemsWithStatus.filter((item) => item.kind === \"story\");\n\n // Step 3: Build tree nodes for each level (with BSP sorting)\n const storyNodes = stories.map((item) => createTreeNode(item, []));\n const featureNodes = features.map((item) => {\n const children = storyNodes\n .filter((story) => isChildOf(story.path, item.path))\n .sort((a, b) => a.number - b.number); // Sort by BSP number\n return createTreeNode(item, children);\n });\n const capabilityNodes = capabilities.map((item) => {\n const children = featureNodes\n .filter((feature) => isChildOf(feature.path, item.path))\n .sort((a, b) => a.number - b.number); // Sort by BSP number\n return createTreeNode(item, children);\n });\n\n // Step 4: Detect orphans\n detectOrphans(stories, featureNodes);\n detectOrphans(features, capabilityNodes);\n\n // Step 5: Sort top-level capabilities by BSP number\n const sortedCapabilities = capabilityNodes.sort((a, b) => a.number - b.number);\n\n // Step 6: Roll up status from children to parents\n rollupStatus(sortedCapabilities);\n\n return {\n nodes: sortedCapabilities,\n };\n}\n\n/**\n * Create a TreeNode from a work item with status and children\n */\nfunction createTreeNode(\n item: WorkItem & { status: string },\n children: TreeNode[],\n): TreeNode {\n return {\n kind: item.kind,\n number: item.number,\n slug: item.slug,\n path: item.path,\n status: item.status as WorkItemStatus,\n children,\n };\n}\n\n/**\n * Check if childPath is a direct child of parentPath\n *\n * A path is a child if it starts with the parent path followed by a separator.\n *\n * @param childPath - Potential child path\n * @param parentPath - Potential parent path\n * @returns true if childPath is a direct child of parentPath\n */\nfunction isChildOf(childPath: string, parentPath: string): boolean {\n // Normalize paths to ensure consistent comparison\n const normalizedChild = childPath.replace(/\\/$/, \"\");\n const normalizedParent = parentPath.replace(/\\/$/, \"\");\n\n // Check if child starts with parent followed by path separator\n if (!normalizedChild.startsWith(normalizedParent + \"/\")) {\n return false;\n }\n\n // Ensure it's a direct child (not a grandchild)\n const relativePath = normalizedChild.slice(normalizedParent.length + 1);\n return !relativePath.includes(\"/\");\n}\n\n/**\n * Detect orphan work items (items without valid parents)\n *\n * @param items - Work items to check\n * @param potentialParents - Potential parent nodes\n * @throws Error if orphans detected\n */\nfunction detectOrphans(\n items: (WorkItem & { status: string })[],\n potentialParents: TreeNode[],\n): void {\n for (const item of items) {\n const hasParent = potentialParents.some((parent) => isChildOf(item.path, parent.path));\n\n if (!hasParent) {\n throw new Error(\n `Orphan work item detected: ${item.kind} \"${item.slug}\" at ${item.path} has no valid parent`,\n );\n }\n }\n}\n\n/**\n * Roll up status from children to parents\n *\n * Recursively aggregates status from child nodes to parent nodes.\n * Parent status requires BOTH own tests/DONE.md AND all children complete.\n *\n * Rollup rules (ownStatus = status from parent's own tests/DONE.md):\n * - DONE: ownStatus is DONE AND all children are DONE\n * - OPEN: ownStatus is OPEN AND all children are OPEN\n * - IN_PROGRESS: everything else (any mismatch between own and child status)\n *\n * @param nodes - Tree nodes to process (modified in place)\n */\nfunction rollupStatus(nodes: TreeNode[]): void {\n for (const node of nodes) {\n if (node.children.length > 0) {\n // First, recursively roll up status for children\n rollupStatus(node.children);\n\n // Capture node's own status (from its tests/DONE.md)\n const ownStatus = node.status;\n\n // Then, aggregate status from children\n const childStatuses = node.children.map((child) => child.status);\n const allChildrenDone = childStatuses.every(\n (status) => status === \"DONE\",\n );\n const allChildrenOpen = childStatuses.every(\n (status) => status === \"OPEN\",\n );\n\n // DONE: own status is DONE AND all children are DONE\n if (ownStatus === \"DONE\" && allChildrenDone) {\n node.status = \"DONE\";\n } // OPEN: own status is OPEN AND all children are OPEN\n else if (ownStatus === \"OPEN\" && allChildrenOpen) {\n node.status = \"OPEN\";\n } // IN_PROGRESS: everything else\n else {\n node.status = \"IN_PROGRESS\";\n }\n }\n // Leaf nodes (stories) keep their original status\n }\n}\n","/**\n * Core type definitions for spx\n */\n\n/**\n * Work item types in the spec hierarchy\n */\nexport const WORK_ITEM_KIND = {\n CAPABILITY: \"capability\",\n FEATURE: \"feature\",\n STORY: \"story\",\n} as const;\n\nexport type WorkItemKind = (typeof WORK_ITEM_KIND)[keyof typeof WORK_ITEM_KIND];\n\n/**\n * Ordered hierarchy of work item kinds (root to leaf)\n *\n * Used by both production code and tests to derive hierarchy structure.\n * Derive work item kind names from this constant.\n */\nexport const WORK_ITEM_KINDS: readonly WorkItemKind[] = [\n WORK_ITEM_KIND.CAPABILITY,\n WORK_ITEM_KIND.FEATURE,\n WORK_ITEM_KIND.STORY,\n] as const;\n\n/**\n * The leaf kind (actionable work items)\n *\n * Derived from WORK_ITEM_KINDS to ensure consistency if hierarchy changes.\n */\nexport const LEAF_KIND: WorkItemKind = WORK_ITEM_KINDS.at(-1)!;\n\n/**\n * Parsed work item structure\n */\nexport interface WorkItem {\n /** The type of work item */\n kind: WorkItemKind;\n /** BSP number (0-indexed for capabilities, as-is for features/stories) */\n number: number;\n /** URL-safe slug identifier */\n slug: string;\n /** Full filesystem path to work item directory */\n path: string;\n}\n\n/**\n * Directory entry from filesystem traversal\n */\nexport interface DirectoryEntry {\n /** Directory name (basename) */\n name: string;\n /** Full absolute path */\n path: string;\n /** Whether this is a directory */\n isDirectory: boolean;\n}\n\n/**\n * Work item status\n */\nexport const WORK_ITEM_STATUS = {\n OPEN: \"OPEN\",\n IN_PROGRESS: \"IN_PROGRESS\",\n DONE: \"DONE\",\n} as const;\n\nexport type WorkItemStatus = (typeof WORK_ITEM_STATUS)[keyof typeof WORK_ITEM_STATUS];\n\n/**\n * Ordered list of work item statuses\n *\n * Used by both production code and tests to derive status values.\n * Derive work item status names from this constant.\n */\nexport const WORK_ITEM_STATUSES: readonly WorkItemStatus[] = [\n WORK_ITEM_STATUS.OPEN,\n WORK_ITEM_STATUS.IN_PROGRESS,\n WORK_ITEM_STATUS.DONE,\n] as const;\n","import { DEFAULT_CONFIG } from \"@/config/defaults\";\nimport { Scanner } from \"@/lib/spec-legacy/scanner/scanner\";\nimport { buildTree } from \"@/lib/spec-legacy/tree/build\";\nimport { TreeNode, WorkItemTree } from \"@/lib/spec-legacy/tree/types\";\nimport { LEAF_KIND } from \"@/lib/spec-legacy/types\";\n\nconst EMPTY_WORK_ITEMS_MESSAGE = \"No work items found in specs/work/doing\";\nconst ALL_COMPLETE_MESSAGE = \"All work items are complete! 🎉\";\nconst NEXT_WORK_ITEM_HEADING = \"Next work item:\";\nconst STATUS_LABEL = \"Status\";\nconst PATH_LABEL = \"Path\";\nconst INDENT = \" \";\nconst BLANK_LINE = \"\";\nconst PATH_SEPARATOR = \" > \";\n\nexport interface NextOptions {\n cwd?: string;\n}\n\nexport function findNextWorkItem(tree: WorkItemTree): TreeNode | null {\n return findFirstNonDoneLeaf(tree.nodes);\n}\n\nfunction findFirstNonDoneLeaf(nodes: TreeNode[]): TreeNode | null {\n for (const node of nodes) {\n if (node.kind === LEAF_KIND) {\n if (node.status !== \"DONE\") {\n return node;\n }\n\n continue;\n }\n\n const found = findFirstNonDoneLeaf(node.children);\n if (found !== null) {\n return found;\n }\n }\n\n return null;\n}\n\nfunction formatWorkItemName(node: TreeNode): string {\n const displayNumber = node.kind === \"capability\" ? node.number + 1 : node.number;\n return `${node.kind}-${displayNumber}_${node.slug}`;\n}\n\nfunction findParents(\n nodes: TreeNode[],\n target: TreeNode,\n): { capability?: TreeNode; feature?: TreeNode } {\n for (const capability of nodes) {\n for (const feature of capability.children) {\n for (const story of feature.children) {\n if (story.path === target.path) {\n return { capability, feature };\n }\n }\n }\n }\n\n return {};\n}\n\nexport async function nextCommand(options: NextOptions = {}): Promise<string> {\n const cwd = options.cwd ?? process.cwd();\n const scanner = new Scanner(cwd, DEFAULT_CONFIG);\n const workItems = await scanner.scan();\n\n if (workItems.length === 0) {\n return EMPTY_WORK_ITEMS_MESSAGE;\n }\n\n const tree = await buildTree(workItems);\n const next = findNextWorkItem(tree);\n\n if (next === null) {\n return ALL_COMPLETE_MESSAGE;\n }\n\n const parents = findParents(tree.nodes, next);\n const pathLine = parents.capability !== undefined && parents.feature !== undefined\n ? `${INDENT}${formatWorkItemName(parents.capability)}${PATH_SEPARATOR}${\n formatWorkItemName(parents.feature)\n }${PATH_SEPARATOR}${formatWorkItemName(next)}`\n : `${INDENT}${formatWorkItemName(next)}`;\n\n return [\n NEXT_WORK_ITEM_HEADING,\n BLANK_LINE,\n pathLine,\n BLANK_LINE,\n `${INDENT}${STATUS_LABEL}: ${next.status}`,\n `${INDENT}${PATH_LABEL}: ${next.path}`,\n ].join(\"\\n\");\n}\n","/**\n * JSON formatter for work item trees\n *\n * Produces structured JSON with summary statistics and full tree data.\n */\nimport type { SpxConfig } from \"@/config/defaults\";\nimport { TreeNode, WorkItemTree } from \"../tree/types\";\n\n/** JSON indentation width. */\nconst JSON_INDENT = 2;\n\n/**\n * Summary counts for capabilities and features only (NOT stories)\n */\ninterface Summary {\n done: number;\n inProgress: number;\n open: number;\n}\n\n/**\n * JSON output structure\n */\ninterface JSONOutput {\n config: {\n specs: SpxConfig[\"specs\"];\n sessions: SpxConfig[\"sessions\"];\n };\n summary: Summary;\n capabilities: unknown[];\n}\n\n/**\n * Format tree as JSON with summary statistics\n *\n * Summary counts capabilities + features only (per user requirement).\n * Display numbers:\n * - Capabilities: internal + 1\n * - Features/Stories: as-is\n *\n * @param tree - Work item tree to format\n * @param config - SpxConfig used for path resolution\n * @returns JSON string with 2-space indentation\n */\nexport function formatJSON(tree: WorkItemTree, config: SpxConfig): string {\n const capabilities = tree.nodes.map((node) => nodeToJSON(node));\n const summary = calculateSummary(tree);\n\n const output: JSONOutput = {\n config: {\n specs: config.specs,\n sessions: config.sessions,\n },\n summary,\n capabilities,\n };\n\n return JSON.stringify(output, null, JSON_INDENT);\n}\n\n/**\n * Convert tree node to JSON structure with display numbers\n *\n * @param node - Tree node to convert\n * @returns JSON-serializable object\n */\nfunction nodeToJSON(node: TreeNode): unknown {\n const displayNumber = getDisplayNumber(node);\n\n const base = {\n kind: node.kind,\n number: displayNumber,\n slug: node.slug,\n status: node.status,\n };\n\n // Add children based on kind\n if (node.kind === \"capability\") {\n return {\n ...base,\n features: node.children.map((child) => nodeToJSON(child)),\n };\n } else if (node.kind === \"feature\") {\n return {\n ...base,\n stories: node.children.map((child) => nodeToJSON(child)),\n };\n } else {\n // Stories have no children\n return base;\n }\n}\n\n/**\n * Calculate summary statistics\n *\n * Counts capabilities + features only (NOT stories per user requirement)\n *\n * @param tree - Work item tree\n * @returns Summary counts\n */\nfunction calculateSummary(tree: WorkItemTree): Summary {\n const summary: Summary = {\n done: 0,\n inProgress: 0,\n open: 0,\n };\n\n for (const capability of tree.nodes) {\n // Count capability\n countNode(capability, summary);\n\n // Count features (but NOT stories)\n for (const feature of capability.children) {\n countNode(feature, summary);\n }\n }\n\n return summary;\n}\n\n/**\n * Count a single node in summary\n *\n * @param node - Node to count\n * @param summary - Summary object to update\n */\nfunction countNode(node: TreeNode, summary: Summary): void {\n switch (node.status) {\n case \"DONE\":\n summary.done++;\n break;\n case \"IN_PROGRESS\":\n summary.inProgress++;\n break;\n case \"OPEN\":\n summary.open++;\n break;\n }\n}\n\n/**\n * Get display number for a work item\n *\n * Display numbers:\n * - Capabilities: internal + 1 (dir capability-21 has internal 20)\n * - Features/Stories: as-is\n */\nfunction getDisplayNumber(node: TreeNode): number {\n return node.kind === \"capability\" ? node.number + 1 : node.number;\n}\n","/**\n * Markdown formatter for work item trees\n *\n * Renders trees with heading hierarchy and status lines.\n */\nimport type { TreeNode, WorkItemTree } from \"../tree/types\";\n\n/**\n * Format tree as markdown with heading hierarchy\n *\n * Heading levels:\n * - Capabilities: #\n * - Features: ##\n * - Stories: ###\n *\n * Display numbers:\n * - Capabilities: internal + 1\n * - Features/Stories: as-is\n *\n * @param tree - Work item tree to format\n * @returns Formatted markdown\n *\n * @example\n * ```typescript\n * const tree = buildTreeWithStories();\n * const output = formatMarkdown(tree);\n * // => \"# capability-21_test\\n\\nStatus: DONE\\n\\n## feature-21_test\\n...\"\n * ```\n */\nexport function formatMarkdown(tree: WorkItemTree): string {\n const sections: string[] = [];\n\n for (const node of tree.nodes) {\n formatNode(node, 1, sections);\n }\n\n return sections.join(\"\\n\\n\");\n}\n\n/**\n * Recursively format a tree node as markdown\n *\n * @param node - Current node to format\n * @param level - Heading level (1 = #, 2 = ##, 3 = ###)\n * @param sections - Output sections array\n */\nfunction formatNode(\n node: TreeNode,\n level: number,\n sections: string[],\n): void {\n const displayNumber = getDisplayNumber(node);\n const name = `${node.kind}-${displayNumber}_${node.slug}`;\n const heading = \"#\".repeat(level);\n\n sections.push(`${heading} ${name}`);\n sections.push(`Status: ${node.status}`);\n\n // Recurse for children\n for (const child of node.children) {\n formatNode(child, level + 1, sections);\n }\n}\n\n/**\n * Get display number for a work item\n *\n * Display numbers:\n * - Capabilities: internal + 1 (dir capability-21 has internal 20)\n * - Features/Stories: as-is\n */\nfunction getDisplayNumber(node: TreeNode): number {\n return node.kind === \"capability\" ? node.number + 1 : node.number;\n}\n","/**\n * Table formatter for work item trees\n *\n * Renders trees as aligned tables with dynamic column widths.\n */\nimport type { TreeNode, WorkItemTree } from \"../tree/types\";\n\n/**\n * Table row data\n */\ninterface TableRow {\n level: string;\n number: string;\n name: string;\n status: string;\n}\n\n/**\n * Format tree as aligned table with dynamic column widths\n *\n * Columns: Level | Number | Name | Status\n * Level shows indented hierarchy:\n * - \"Capability\" (no indent)\n * - \" Feature\" (2-space indent)\n * - \" Story\" (4-space indent)\n *\n * Display numbers:\n * - Capabilities: internal + 1\n * - Features/Stories: as-is\n *\n * @param tree - Work item tree to format\n * @returns Formatted table with aligned columns\n */\nexport function formatTable(tree: WorkItemTree): string {\n const rows: TableRow[] = [];\n\n // Collect all rows\n for (const node of tree.nodes) {\n collectRows(node, 0, rows);\n }\n\n // Calculate column widths\n const widths = calculateColumnWidths(rows);\n\n // Format table\n const lines: string[] = [];\n\n // Header row\n lines.push(\n formatRow(\n {\n level: \"Level\",\n number: \"Number\",\n name: \"Name\",\n status: \"Status\",\n },\n widths,\n ),\n );\n\n // Separator row\n lines.push(\n `|${\"-\".repeat(widths.level + 2)}|${\"-\".repeat(widths.number + 2)}|${\"-\".repeat(widths.name + 2)}|${\n \"-\".repeat(widths.status + 2)\n }|`,\n );\n\n // Data rows\n for (const row of rows) {\n lines.push(formatRow(row, widths));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Recursively collect table rows from tree\n *\n * @param node - Current node\n * @param depth - Current depth (0 = capability, 1 = feature, 2 = story)\n * @param rows - Output rows array\n */\nfunction collectRows(node: TreeNode, depth: number, rows: TableRow[]): void {\n const indent = \" \".repeat(depth);\n const levelName = getLevelName(node.kind);\n const displayNumber = getDisplayNumber(node);\n\n rows.push({\n level: `${indent}${levelName}`,\n number: String(displayNumber),\n name: node.slug,\n status: node.status,\n });\n\n // Recurse for children\n for (const child of node.children) {\n collectRows(child, depth + 1, rows);\n }\n}\n\n/**\n * Get level name with proper capitalization\n *\n * @param kind - Work item kind\n * @returns Capitalized level name\n */\nfunction getLevelName(kind: string): string {\n return kind.charAt(0).toUpperCase() + kind.slice(1);\n}\n\n/**\n * Get display number for a work item\n *\n * Display numbers:\n * - Capabilities: internal + 1 (dir capability-21 has internal 20)\n * - Features/Stories: as-is\n */\nfunction getDisplayNumber(node: TreeNode): number {\n return node.kind === \"capability\" ? node.number + 1 : node.number;\n}\n\n/**\n * Calculate maximum width for each column\n *\n * @param rows - All table rows including header\n * @returns Column widths\n */\nfunction calculateColumnWidths(rows: TableRow[]): {\n level: number;\n number: number;\n name: number;\n status: number;\n} {\n const widths = {\n level: \"Level\".length,\n number: \"Number\".length,\n name: \"Name\".length,\n status: \"Status\".length,\n };\n\n for (const row of rows) {\n widths.level = Math.max(widths.level, row.level.length);\n widths.number = Math.max(widths.number, row.number.length);\n widths.name = Math.max(widths.name, row.name.length);\n widths.status = Math.max(widths.status, row.status.length);\n }\n\n return widths;\n}\n\n/**\n * Format a single table row with proper padding\n *\n * @param row - Row data\n * @param widths - Column widths\n * @returns Formatted row with | delimiters\n */\nfunction formatRow(\n row: TableRow,\n widths: { level: number; number: number; name: number; status: number },\n): string {\n return `| ${row.level.padEnd(widths.level)} | ${row.number.padEnd(widths.number)} | ${\n row.name.padEnd(widths.name)\n } | ${row.status.padEnd(widths.status)} |`;\n}\n","/**\n * Text formatter for work item trees\n *\n * Renders hierarchical tree with indentation and colored status indicators.\n * Output format:\n * capability-21_name [STATUS] (colored)\n * feature-32_name [STATUS] (colored)\n * story-21_name [STATUS] (colored)\n */\nimport chalk from \"chalk\";\nimport type { TreeNode, WorkItemTree } from \"../tree/types\";\nimport type { WorkItemKind } from \"../types\";\n\n/**\n * Format work item tree as text with hierarchical indentation\n *\n * @param tree - Work item tree to format\n * @returns Formatted text output with indentation and status\n *\n * @example\n * ```typescript\n * const tree = buildTreeWithStories();\n * const output = formatText(tree);\n * // => \"capability-21_test [DONE]\\n feature-21_test [DONE]\\n story-21_test [DONE]\"\n * ```\n */\nexport function formatText(tree: WorkItemTree): string {\n const lines: string[] = [];\n\n for (const node of tree.nodes) {\n lines.push(formatNode(node, 0));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format a single tree node with indentation and colored status\n *\n * @param node - Tree node to format\n * @param indent - Indentation level (0 = no indent, 2 = feature, 4 = story)\n * @returns Formatted node and all children\n */\nfunction formatNode(node: TreeNode, indent: number): string {\n const lines: string[] = [];\n\n // Format current node\n const name = formatWorkItemName(node.kind, node.number, node.slug);\n const prefix = \" \".repeat(indent);\n const status = formatStatus(node.status);\n const line = `${prefix}${name} ${status}`;\n lines.push(line);\n\n // Recursively format children with increased indentation\n for (const child of node.children) {\n lines.push(formatNode(child, indent + 2));\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Format work item name for display\n *\n * Converts internal number to display number for capabilities.\n *\n * @param kind - Work item type\n * @param number - Internal BSP number\n * @param slug - URL-safe identifier\n * @returns Formatted name (e.g., \"capability-21_core-cli\")\n */\nfunction formatWorkItemName(\n kind: WorkItemKind,\n number: number,\n slug: string,\n): string {\n // Capabilities: display = internal + 1\n // Features/Stories: display = internal\n const displayNumber = kind === \"capability\" ? number + 1 : number;\n return `${kind}-${displayNumber}_${slug}`;\n}\n\n/**\n * Format status with color\n *\n * Colors:\n * - DONE: green\n * - IN_PROGRESS: yellow\n * - OPEN: gray\n *\n * @param status - Work item status\n * @returns Colored status string with brackets\n */\nfunction formatStatus(status: string): string {\n switch (status) {\n case \"DONE\":\n return chalk.green(`[${status}]`);\n case \"IN_PROGRESS\":\n return chalk.yellow(`[${status}]`);\n case \"OPEN\":\n return chalk.gray(`[${status}]`);\n default:\n return `[${status}]`;\n }\n}\n","import { DEFAULT_CONFIG } from \"@/config/defaults\";\nimport { formatJSON } from \"@/lib/spec-legacy/reporter/json\";\nimport { formatMarkdown } from \"@/lib/spec-legacy/reporter/markdown\";\nimport { formatTable } from \"@/lib/spec-legacy/reporter/table\";\nimport { formatText } from \"@/lib/spec-legacy/reporter/text\";\nimport { Scanner } from \"@/lib/spec-legacy/scanner/scanner\";\nimport { buildTree } from \"@/lib/spec-legacy/tree/build\";\n\nexport const OUTPUT_FORMAT = {\n TEXT: \"text\",\n JSON: \"json\",\n MARKDOWN: \"markdown\",\n TABLE: \"table\",\n} as const;\n\nconst DEFAULT_FORMAT: OutputFormat = OUTPUT_FORMAT.TEXT;\n\nexport type OutputFormat = (typeof OUTPUT_FORMAT)[keyof typeof OUTPUT_FORMAT];\n\nexport interface StatusOptions {\n cwd?: string;\n format?: OutputFormat;\n}\n\nfunction buildMissingDirectoryMessage(): string {\n const {\n root,\n work: {\n dir,\n statusDirs: { doing },\n },\n } = DEFAULT_CONFIG.specs;\n\n return `Directory ${root}/${dir}/${doing} not found.`;\n}\n\nexport async function statusCommand(\n options: StatusOptions = {},\n): Promise<string> {\n const cwd = options.cwd ?? process.cwd();\n const format = options.format ?? DEFAULT_FORMAT;\n const scanner = new Scanner(cwd, DEFAULT_CONFIG);\n\n let workItems;\n try {\n workItems = await scanner.scan();\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"ENOENT\")) {\n throw new Error(buildMissingDirectoryMessage());\n }\n\n throw error;\n }\n\n if (workItems.length === 0) {\n return \"No work items found in specs/work/doing\";\n }\n\n const tree = await buildTree(workItems);\n\n switch (format) {\n case OUTPUT_FORMAT.JSON:\n return formatJSON(tree, DEFAULT_CONFIG);\n case OUTPUT_FORMAT.MARKDOWN:\n return formatMarkdown(tree);\n case OUTPUT_FORMAT.TABLE:\n return formatTable(tree);\n case OUTPUT_FORMAT.TEXT:\n return formatText(tree);\n }\n}\n","/**\n * Language detection for apply-exclude.\n *\n * Checks which config files exist in the project to determine the language\n * and return the appropriate adapter.\n */\nimport { join } from \"node:path\";\n\nimport type { ApplyExcludeDeps } from \"../types\";\nimport { pythonAdapter } from \"./python\";\nimport type { LanguageAdapter } from \"./types\";\n\n/** All registered language adapters, checked in order */\nexport const ADAPTERS: readonly LanguageAdapter[] = [pythonAdapter] as const;\n\n/**\n * Detect the project language by checking for config files.\n *\n * @param projectRoot - Absolute path to the project root\n * @param deps - Injected file system dependencies\n * @returns The first matching adapter, or null if no config file is found\n */\nexport async function detectLanguage(\n projectRoot: string,\n deps: Pick<ApplyExcludeDeps, \"fileExists\">,\n): Promise<LanguageAdapter | null> {\n for (const adapter of ADAPTERS) {\n const configPath = join(projectRoot, adapter.configFile);\n const exists = await deps.fileExists(configPath);\n if (exists) {\n return adapter;\n }\n }\n return null;\n}\n","/**\n * Constants for apply-exclude operations.\n */\nimport { NODE_SUFFIXES as SPEC_TREE_NODE_SUFFIXES, SPEC_TREE_CONFIG } from \"@/lib/spec-tree/config\";\n\n/** Prefix for all spec-tree paths in config files */\nexport const SPX_PREFIX = `${SPEC_TREE_CONFIG.ROOT_DIRECTORY}/`;\n\n/** Node type suffixes that identify spec-tree directories */\nexport const NODE_SUFFIXES: readonly string[] = SPEC_TREE_NODE_SUFFIXES.map((suffix) => `${suffix}/`);\n\n/** Comment character in EXCLUDE files */\nexport const COMMENT_CHAR = \"#\";\n\n/** Default name of the EXCLUDE file within spx/ */\nexport const EXCLUDE_FILENAME = \"EXCLUDE\";\n","/**\n * Node path to tool-specific config entry mappings.\n */\nimport { NODE_SUFFIXES, SPX_PREFIX } from \"./constants\";\n\n/**\n * Convert a node path to a pytest --ignore flag.\n *\n * @example toPytestIgnore(\"57-subsystems.outcome\") => \"--ignore=spx/57-subsystems.outcome/\"\n */\nexport function toPytestIgnore(node: string): string {\n return `--ignore=${SPX_PREFIX}${node}/`;\n}\n\n/**\n * Escape a string for use in a regular expression.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\-]/g, \"\\\\$&\");\n}\n\n/**\n * Convert a node path to a mypy exclude regex.\n *\n * @example toMypyRegex(\"57-subsystems.outcome\") => \"^spx/57\\\\-subsystems\\\\.outcome/\"\n */\nexport function toMypyRegex(node: string): string {\n const escaped = escapeRegex(`${SPX_PREFIX}${node}/`);\n return `^${escaped}`;\n}\n\n/**\n * Convert a node path to a pyright exclude path.\n *\n * @example toPyrightPath(\"57-subsystems.outcome\") => \"spx/57-subsystems.outcome/\"\n */\nexport function toPyrightPath(node: string): string {\n return `${SPX_PREFIX}${node}/`;\n}\n\n/**\n * Check if a config value was generated from an excluded spec-tree node.\n *\n * Detects entries by value pattern (contains a node-type suffix and spx/ prefix),\n * not by marker comments.\n */\nexport function isExcludedEntry(val: string): boolean {\n const hasPrefix = val.includes(SPX_PREFIX);\n const hasSuffix = NODE_SUFFIXES.some((suffix) => val.includes(suffix));\n return hasPrefix && hasSuffix;\n}\n","/**\n * Python language adapter for apply-exclude.\n *\n * Applies spec-tree exclusions to pyproject.toml using string-based editing.\n * Preserves comments and formatting by only modifying the specific values\n * for pytest addopts, mypy exclude, and pyright exclude — everything else\n * is left untouched.\n */\nimport { isExcludedEntry, toMypyRegex, toPyrightPath, toPytestIgnore } from \"../mappings\";\nimport type { ApplyResult } from \"../types\";\nimport type { LanguageAdapter } from \"./types\";\n\n/** Config file name for Python projects */\nexport const PYTHON_CONFIG_FILE = \"pyproject.toml\";\n\n/** TOML section header for pytest configuration */\nexport const PYTEST_SECTION = \"tool.pytest.ini_options\";\n\n/** TOML section header for mypy configuration */\nexport const MYPY_SECTION = \"tool.mypy\";\n\n/** TOML section header for pyright configuration */\nexport const PYRIGHT_SECTION = \"tool.pyright\";\n\n/** Indentation used for new array entries */\nconst ARRAY_INDENT = \" \";\n\n/**\n * Update pytest addopts string value within pyproject.toml content.\n *\n * Finds `addopts = \"...\"` in `[tool.pytest.ini_options]`, filters out\n * old excluded entries, and appends new ones.\n */\nfunction updatePytestAddopts(content: string, nodes: string[]): string {\n const sectionPattern = new RegExp(`^\\\\[${PYTEST_SECTION.replace(/\\./g, \"\\\\.\")}\\\\]`, \"m\");\n const sectionMatch = sectionPattern.exec(content);\n if (!sectionMatch) return content;\n\n // Find addopts = \"...\" after the section header\n const afterSection = content.slice(sectionMatch.index);\n const addoptsPattern = /^([ \\t]*addopts\\s*=\\s*\")((?:[^\"\\\\]|\\\\.)*)(\")/m;\n const addoptsMatch = addoptsPattern.exec(afterSection);\n if (!addoptsMatch) return content;\n\n const prefix = addoptsMatch[1];\n const currentValue = addoptsMatch[2];\n const suffix = addoptsMatch[3];\n\n // Split by whitespace, filter old excluded entries, add new ones\n const parts = currentValue.split(/\\s+/).filter((p) => p.length > 0);\n const kept = parts.filter((p) => !isExcludedEntry(p));\n const newIgnores = nodes.map(toPytestIgnore);\n const updatedValue = [...kept, ...newIgnores].join(\" \");\n\n const absoluteStart = sectionMatch.index + addoptsMatch.index;\n const absoluteEnd = absoluteStart + addoptsMatch[0].length;\n\n return content.slice(0, absoluteStart) + prefix + updatedValue + suffix + content.slice(absoluteEnd);\n}\n\n/**\n * Find the boundaries of a TOML array value within a specific section.\n */\nfunction findTomlArray(\n content: string,\n sectionHeader: string,\n key: string,\n): { arrayStart: number; arrayEnd: number } | null {\n const sectionPattern = new RegExp(`^\\\\[${sectionHeader.replace(/\\./g, \"\\\\.\")}\\\\]`, \"m\");\n const sectionMatch = sectionPattern.exec(content);\n if (!sectionMatch) return null;\n\n // Find key = [ after section header, before next section\n const afterSection = content.slice(sectionMatch.index);\n const nextSectionMatch = /^\\[(?!.*\\].*=)/m.exec(afterSection.slice(sectionMatch[0].length));\n const sectionEnd = nextSectionMatch\n ? sectionMatch.index + sectionMatch[0].length + nextSectionMatch.index\n : content.length;\n\n const keyPattern = new RegExp(`^([ \\\\t]*${key}\\\\s*=\\\\s*)\\\\[`, \"m\");\n const regionToSearch = content.slice(sectionMatch.index, sectionEnd);\n const keyMatch = keyPattern.exec(regionToSearch);\n if (!keyMatch) return null;\n\n const arrayStart = sectionMatch.index + keyMatch.index + keyMatch[1].length;\n\n // Find the matching closing bracket\n let depth = 0;\n let arrayEnd = arrayStart;\n for (let i = arrayStart; i < content.length; i++) {\n if (content[i] === \"[\") depth++;\n if (content[i] === \"]\") {\n depth--;\n if (depth === 0) {\n arrayEnd = i + 1;\n break;\n }\n }\n }\n\n return { arrayStart, arrayEnd };\n}\n\n/**\n * Update a TOML array in a specific section by filtering out excluded entries\n * and appending new ones.\n *\n * Preserves comments and indentation of non-excluded entries.\n */\nfunction updateTomlArray(content: string, sectionHeader: string, key: string, newEntries: string[]): string {\n const info = findTomlArray(content, sectionHeader, key);\n if (!info) return content;\n\n // Parse the array content line by line to preserve formatting\n const arrayContent = content.slice(info.arrayStart + 1, info.arrayEnd - 1);\n const lines = arrayContent.split(\"\\n\");\n\n // Keep lines that are comments, blank, or contain non-excluded entries\n const keptLines: string[] = [];\n for (const line of lines) {\n const trimmed = line.trim();\n // Keep blank lines and comments\n if (trimmed === \"\" || trimmed.startsWith(\"#\")) {\n keptLines.push(line);\n continue;\n }\n // Check if this line contains a string entry that should be excluded\n const stringMatch = /\"((?:[^\"\\\\]|\\\\.)*)\"/.exec(trimmed);\n if (stringMatch && isExcludedEntry(stringMatch[1])) {\n continue; // Remove this line\n }\n keptLines.push(line);\n }\n\n // Append new entries with trailing commas\n const newLines = newEntries.map((entry) => `${ARRAY_INDENT}\"${entry}\",`);\n\n // Reconstruct the array content\n // Remove trailing empty lines from kept lines before appending\n while (keptLines.length > 0 && keptLines[keptLines.length - 1].trim() === \"\") {\n keptLines.pop();\n }\n\n const reconstructed = [...keptLines, ...newLines, \"\"].join(\"\\n\");\n\n return content.slice(0, info.arrayStart + 1) + reconstructed + content.slice(info.arrayEnd - 1);\n}\n\n/**\n * Python language adapter for apply-exclude.\n *\n * Updates pyproject.toml to exclude specified nodes from pytest, mypy,\n * and pyright. Ruff is never excluded — style is checked regardless of\n * implementation existence.\n */\nexport const pythonAdapter: LanguageAdapter = {\n language: \"Python\",\n configFile: PYTHON_CONFIG_FILE,\n tools: [\"pytest\", \"mypy\", \"pyright\"],\n excluded: [\"ruff (style checked regardless of implementation existence)\"],\n\n applyExclusions(content: string, nodes: string[]): ApplyResult {\n let result = content;\n\n // 1. Update pytest addopts\n result = updatePytestAddopts(result, nodes);\n\n // 2. Update mypy exclude\n const mypyEntries = nodes.map(toMypyRegex);\n result = updateTomlArray(result, MYPY_SECTION, \"exclude\", mypyEntries);\n\n // 3. Update pyright exclude\n const pyrightEntries = nodes.map(toPyrightPath);\n result = updateTomlArray(result, PYRIGHT_SECTION, \"exclude\", pyrightEntries);\n\n return {\n changed: result !== content,\n content: result,\n };\n },\n};\n","/**\n * Dynamic help text for spx spec apply, built from constants and adapter registry.\n */\nimport { ADAPTERS } from \"./adapters/index\";\nimport { EXCLUDE_FILENAME, SPX_PREFIX } from \"./constants\";\n\n/**\n * Build the help text for spx spec apply.\n *\n * Generates language support table and tool details from the adapter registry,\n * so the help stays in sync with the implementation.\n */\nfunction buildApplyHelp(): string {\n const excludePath = `${SPX_PREFIX}${EXCLUDE_FILENAME}`;\n\n const languageLines = ADAPTERS.map((adapter) => {\n const tools = adapter.tools.join(\", \");\n const excluded = adapter.excluded.length > 0 ? `\\n NOT configured: ${adapter.excluded.join(\", \")}` : \"\";\n return ` ${adapter.language} (${adapter.configFile})\\n Configures: ${tools}${excluded}`;\n });\n\n return `\nReads ${excludePath} and applies exclusions to the project's tool configuration.\nEach excluded node is translated into the appropriate format for the detected\nlanguage's test runner, type checker, and other quality gate tools.\n\nSource:\n ${excludePath}\n One node path per line. Comments (#) and blank lines are ignored.\n Path traversal (..) and absolute paths are rejected.\n\nSupported languages:\n${languageLines.join(\"\\n\\n\")}\n\nDetection:\n The language is auto-detected by checking for config files in order.\n The first match wins.\n\nExamples:\n spx spec apply # Apply exclusions to detected config file\n`;\n}\n\n/** Extended help text appended after the command description */\nexport const APPLY_HELP = buildApplyHelp();\n","/**\n * Parse spx/EXCLUDE files into node paths with validation.\n */\nimport { COMMENT_CHAR } from \"./constants\";\n\n/** Characters that are unsafe in TOML string values */\nconst TOML_UNSAFE_PATTERN = /[\"\\\\\\n\\r\\t]/;\n\n/** Path traversal sequences */\nconst PATH_TRAVERSAL_PATTERN = /(?:^|\\/)\\.\\.(?:\\/|$)/;\n\n/**\n * Validate that a node path is safe for use in config file generation.\n *\n * Rejects:\n * - Path traversal (`..` segments)\n * - Absolute paths (starting with `/`)\n * - TOML-unsafe characters (`\"`, `\\`, newlines, tabs)\n *\n * @returns Error message if invalid, null if valid\n */\nexport function validateNodePath(path: string): string | null {\n if (path.startsWith(\"/\")) {\n return `absolute path rejected: ${path}`;\n }\n if (PATH_TRAVERSAL_PATTERN.test(path)) {\n return `path traversal rejected: ${path}`;\n }\n if (TOML_UNSAFE_PATTERN.test(path)) {\n return `TOML-unsafe characters rejected: ${path}`;\n }\n return null;\n}\n\n/**\n * Read node paths from EXCLUDE file content, stripping comments and blanks.\n * Invalid paths are silently filtered out.\n *\n * @param content - Raw content of the EXCLUDE file\n * @returns Array of valid node paths (trimmed, non-empty, non-comment, safe)\n */\nexport function readExcludedNodes(content: string): string[] {\n return content\n .split(\"\\n\")\n .map((line) => line.trim())\n .filter((line) => line.length > 0 && !line.startsWith(COMMENT_CHAR))\n .filter((line) => validateNodePath(line) === null);\n}\n","/**\n * Command handler for spx spec apply.\n *\n * Reads spx/EXCLUDE and applies exclusions to the project's language-specific\n * config file using the detected language adapter.\n */\nimport { join } from \"node:path\";\n\nimport { detectLanguage } from \"./adapters/index\";\nimport { EXCLUDE_FILENAME, SPX_PREFIX } from \"./constants\";\nimport { readExcludedNodes } from \"./exclude-file\";\nimport type { ApplyExcludeOptions, ApplyExcludeResult } from \"./types\";\n\n/**\n * Run the apply-exclude command.\n *\n * @param options - Command options with injected dependencies\n * @returns Command result with exit code and output message\n */\nexport async function applyExcludeCommand(options: ApplyExcludeOptions): Promise<ApplyExcludeResult> {\n const { cwd, deps } = options;\n const excludePath = join(cwd, SPX_PREFIX, EXCLUDE_FILENAME);\n\n // Check spx/EXCLUDE exists\n const excludeExists = await deps.fileExists(excludePath);\n if (!excludeExists) {\n return { exitCode: 1, output: `error: ${excludePath} not found` };\n }\n\n // Detect project language\n const adapter = await detectLanguage(cwd, deps);\n if (!adapter) {\n return { exitCode: 1, output: \"error: no supported config file found (checked: pyproject.toml)\" };\n }\n\n const configPath = join(cwd, adapter.configFile);\n\n // Read both files\n const excludeContent = await deps.readFile(excludePath);\n const configContent = await deps.readFile(configPath);\n\n // Parse excluded nodes\n const nodes = readExcludedNodes(excludeContent);\n if (nodes.length === 0) {\n return { exitCode: 0, output: \"spx/EXCLUDE is empty — no excluded nodes to apply.\" };\n }\n\n // Apply exclusions\n const result = adapter.applyExclusions(configContent, nodes);\n\n if (result.changed) {\n await deps.writeFile(configPath, result.content);\n return {\n exitCode: 0,\n output: `Updated ${adapter.configFile} from spx/EXCLUDE (${nodes.length} nodes).`,\n };\n }\n\n return { exitCode: 0, output: `${adapter.configFile} is already in sync with spx/EXCLUDE.` };\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport function createScanner(text, ignoreTrivia = false) {\n const len = text.length;\n let pos = 0, value = '', tokenOffset = 0, token = 16 /* SyntaxKind.Unknown */, lineNumber = 0, lineStartOffset = 0, tokenLineStartOffset = 0, prevTokenLineStartOffset = 0, scanError = 0 /* ScanError.None */;\n function scanHexDigits(count, exact) {\n let digits = 0;\n let value = 0;\n while (digits < count || !exact) {\n let ch = text.charCodeAt(pos);\n if (ch >= 48 /* CharacterCodes._0 */ && ch <= 57 /* CharacterCodes._9 */) {\n value = value * 16 + ch - 48 /* CharacterCodes._0 */;\n }\n else if (ch >= 65 /* CharacterCodes.A */ && ch <= 70 /* CharacterCodes.F */) {\n value = value * 16 + ch - 65 /* CharacterCodes.A */ + 10;\n }\n else if (ch >= 97 /* CharacterCodes.a */ && ch <= 102 /* CharacterCodes.f */) {\n value = value * 16 + ch - 97 /* CharacterCodes.a */ + 10;\n }\n else {\n break;\n }\n pos++;\n digits++;\n }\n if (digits < count) {\n value = -1;\n }\n return value;\n }\n function setPosition(newPosition) {\n pos = newPosition;\n value = '';\n tokenOffset = 0;\n token = 16 /* SyntaxKind.Unknown */;\n scanError = 0 /* ScanError.None */;\n }\n function scanNumber() {\n let start = pos;\n if (text.charCodeAt(pos) === 48 /* CharacterCodes._0 */) {\n pos++;\n }\n else {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n }\n if (pos < text.length && text.charCodeAt(pos) === 46 /* CharacterCodes.dot */) {\n pos++;\n if (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n }\n else {\n scanError = 3 /* ScanError.UnexpectedEndOfNumber */;\n return text.substring(start, pos);\n }\n }\n let end = pos;\n if (pos < text.length && (text.charCodeAt(pos) === 69 /* CharacterCodes.E */ || text.charCodeAt(pos) === 101 /* CharacterCodes.e */)) {\n pos++;\n if (pos < text.length && text.charCodeAt(pos) === 43 /* CharacterCodes.plus */ || text.charCodeAt(pos) === 45 /* CharacterCodes.minus */) {\n pos++;\n }\n if (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n while (pos < text.length && isDigit(text.charCodeAt(pos))) {\n pos++;\n }\n end = pos;\n }\n else {\n scanError = 3 /* ScanError.UnexpectedEndOfNumber */;\n }\n }\n return text.substring(start, end);\n }\n function scanString() {\n let result = '', start = pos;\n while (true) {\n if (pos >= len) {\n result += text.substring(start, pos);\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n const ch = text.charCodeAt(pos);\n if (ch === 34 /* CharacterCodes.doubleQuote */) {\n result += text.substring(start, pos);\n pos++;\n break;\n }\n if (ch === 92 /* CharacterCodes.backslash */) {\n result += text.substring(start, pos);\n pos++;\n if (pos >= len) {\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n const ch2 = text.charCodeAt(pos++);\n switch (ch2) {\n case 34 /* CharacterCodes.doubleQuote */:\n result += '\\\"';\n break;\n case 92 /* CharacterCodes.backslash */:\n result += '\\\\';\n break;\n case 47 /* CharacterCodes.slash */:\n result += '/';\n break;\n case 98 /* CharacterCodes.b */:\n result += '\\b';\n break;\n case 102 /* CharacterCodes.f */:\n result += '\\f';\n break;\n case 110 /* CharacterCodes.n */:\n result += '\\n';\n break;\n case 114 /* CharacterCodes.r */:\n result += '\\r';\n break;\n case 116 /* CharacterCodes.t */:\n result += '\\t';\n break;\n case 117 /* CharacterCodes.u */:\n const ch3 = scanHexDigits(4, true);\n if (ch3 >= 0) {\n result += String.fromCharCode(ch3);\n }\n else {\n scanError = 4 /* ScanError.InvalidUnicode */;\n }\n break;\n default:\n scanError = 5 /* ScanError.InvalidEscapeCharacter */;\n }\n start = pos;\n continue;\n }\n if (ch >= 0 && ch <= 0x1f) {\n if (isLineBreak(ch)) {\n result += text.substring(start, pos);\n scanError = 2 /* ScanError.UnexpectedEndOfString */;\n break;\n }\n else {\n scanError = 6 /* ScanError.InvalidCharacter */;\n // mark as error but continue with string\n }\n }\n pos++;\n }\n return result;\n }\n function scanNext() {\n value = '';\n scanError = 0 /* ScanError.None */;\n tokenOffset = pos;\n lineStartOffset = lineNumber;\n prevTokenLineStartOffset = tokenLineStartOffset;\n if (pos >= len) {\n // at the end\n tokenOffset = len;\n return token = 17 /* SyntaxKind.EOF */;\n }\n let code = text.charCodeAt(pos);\n // trivia: whitespace\n if (isWhiteSpace(code)) {\n do {\n pos++;\n value += String.fromCharCode(code);\n code = text.charCodeAt(pos);\n } while (isWhiteSpace(code));\n return token = 15 /* SyntaxKind.Trivia */;\n }\n // trivia: newlines\n if (isLineBreak(code)) {\n pos++;\n value += String.fromCharCode(code);\n if (code === 13 /* CharacterCodes.carriageReturn */ && text.charCodeAt(pos) === 10 /* CharacterCodes.lineFeed */) {\n pos++;\n value += '\\n';\n }\n lineNumber++;\n tokenLineStartOffset = pos;\n return token = 14 /* SyntaxKind.LineBreakTrivia */;\n }\n switch (code) {\n // tokens: []{}:,\n case 123 /* CharacterCodes.openBrace */:\n pos++;\n return token = 1 /* SyntaxKind.OpenBraceToken */;\n case 125 /* CharacterCodes.closeBrace */:\n pos++;\n return token = 2 /* SyntaxKind.CloseBraceToken */;\n case 91 /* CharacterCodes.openBracket */:\n pos++;\n return token = 3 /* SyntaxKind.OpenBracketToken */;\n case 93 /* CharacterCodes.closeBracket */:\n pos++;\n return token = 4 /* SyntaxKind.CloseBracketToken */;\n case 58 /* CharacterCodes.colon */:\n pos++;\n return token = 6 /* SyntaxKind.ColonToken */;\n case 44 /* CharacterCodes.comma */:\n pos++;\n return token = 5 /* SyntaxKind.CommaToken */;\n // strings\n case 34 /* CharacterCodes.doubleQuote */:\n pos++;\n value = scanString();\n return token = 10 /* SyntaxKind.StringLiteral */;\n // comments\n case 47 /* CharacterCodes.slash */:\n const start = pos - 1;\n // Single-line comment\n if (text.charCodeAt(pos + 1) === 47 /* CharacterCodes.slash */) {\n pos += 2;\n while (pos < len) {\n if (isLineBreak(text.charCodeAt(pos))) {\n break;\n }\n pos++;\n }\n value = text.substring(start, pos);\n return token = 12 /* SyntaxKind.LineCommentTrivia */;\n }\n // Multi-line comment\n if (text.charCodeAt(pos + 1) === 42 /* CharacterCodes.asterisk */) {\n pos += 2;\n const safeLength = len - 1; // For lookahead.\n let commentClosed = false;\n while (pos < safeLength) {\n const ch = text.charCodeAt(pos);\n if (ch === 42 /* CharacterCodes.asterisk */ && text.charCodeAt(pos + 1) === 47 /* CharacterCodes.slash */) {\n pos += 2;\n commentClosed = true;\n break;\n }\n pos++;\n if (isLineBreak(ch)) {\n if (ch === 13 /* CharacterCodes.carriageReturn */ && text.charCodeAt(pos) === 10 /* CharacterCodes.lineFeed */) {\n pos++;\n }\n lineNumber++;\n tokenLineStartOffset = pos;\n }\n }\n if (!commentClosed) {\n pos++;\n scanError = 1 /* ScanError.UnexpectedEndOfComment */;\n }\n value = text.substring(start, pos);\n return token = 13 /* SyntaxKind.BlockCommentTrivia */;\n }\n // just a single slash\n value += String.fromCharCode(code);\n pos++;\n return token = 16 /* SyntaxKind.Unknown */;\n // numbers\n case 45 /* CharacterCodes.minus */:\n value += String.fromCharCode(code);\n pos++;\n if (pos === len || !isDigit(text.charCodeAt(pos))) {\n return token = 16 /* SyntaxKind.Unknown */;\n }\n // found a minus, followed by a number so\n // we fall through to proceed with scanning\n // numbers\n case 48 /* CharacterCodes._0 */:\n case 49 /* CharacterCodes._1 */:\n case 50 /* CharacterCodes._2 */:\n case 51 /* CharacterCodes._3 */:\n case 52 /* CharacterCodes._4 */:\n case 53 /* CharacterCodes._5 */:\n case 54 /* CharacterCodes._6 */:\n case 55 /* CharacterCodes._7 */:\n case 56 /* CharacterCodes._8 */:\n case 57 /* CharacterCodes._9 */:\n value += scanNumber();\n return token = 11 /* SyntaxKind.NumericLiteral */;\n // literals and unknown symbols\n default:\n // is a literal? Read the full word.\n while (pos < len && isUnknownContentCharacter(code)) {\n pos++;\n code = text.charCodeAt(pos);\n }\n if (tokenOffset !== pos) {\n value = text.substring(tokenOffset, pos);\n // keywords: true, false, null\n switch (value) {\n case 'true': return token = 8 /* SyntaxKind.TrueKeyword */;\n case 'false': return token = 9 /* SyntaxKind.FalseKeyword */;\n case 'null': return token = 7 /* SyntaxKind.NullKeyword */;\n }\n return token = 16 /* SyntaxKind.Unknown */;\n }\n // some\n value += String.fromCharCode(code);\n pos++;\n return token = 16 /* SyntaxKind.Unknown */;\n }\n }\n function isUnknownContentCharacter(code) {\n if (isWhiteSpace(code) || isLineBreak(code)) {\n return false;\n }\n switch (code) {\n case 125 /* CharacterCodes.closeBrace */:\n case 93 /* CharacterCodes.closeBracket */:\n case 123 /* CharacterCodes.openBrace */:\n case 91 /* CharacterCodes.openBracket */:\n case 34 /* CharacterCodes.doubleQuote */:\n case 58 /* CharacterCodes.colon */:\n case 44 /* CharacterCodes.comma */:\n case 47 /* CharacterCodes.slash */:\n return false;\n }\n return true;\n }\n function scanNextNonTrivia() {\n let result;\n do {\n result = scanNext();\n } while (result >= 12 /* SyntaxKind.LineCommentTrivia */ && result <= 15 /* SyntaxKind.Trivia */);\n return result;\n }\n return {\n setPosition: setPosition,\n getPosition: () => pos,\n scan: ignoreTrivia ? scanNextNonTrivia : scanNext,\n getToken: () => token,\n getTokenValue: () => value,\n getTokenOffset: () => tokenOffset,\n getTokenLength: () => pos - tokenOffset,\n getTokenStartLine: () => lineStartOffset,\n getTokenStartCharacter: () => tokenOffset - prevTokenLineStartOffset,\n getTokenError: () => scanError,\n };\n}\nfunction isWhiteSpace(ch) {\n return ch === 32 /* CharacterCodes.space */ || ch === 9 /* CharacterCodes.tab */;\n}\nfunction isLineBreak(ch) {\n return ch === 10 /* CharacterCodes.lineFeed */ || ch === 13 /* CharacterCodes.carriageReturn */;\n}\nfunction isDigit(ch) {\n return ch >= 48 /* CharacterCodes._0 */ && ch <= 57 /* CharacterCodes._9 */;\n}\nvar CharacterCodes;\n(function (CharacterCodes) {\n CharacterCodes[CharacterCodes[\"lineFeed\"] = 10] = \"lineFeed\";\n CharacterCodes[CharacterCodes[\"carriageReturn\"] = 13] = \"carriageReturn\";\n CharacterCodes[CharacterCodes[\"space\"] = 32] = \"space\";\n CharacterCodes[CharacterCodes[\"_0\"] = 48] = \"_0\";\n CharacterCodes[CharacterCodes[\"_1\"] = 49] = \"_1\";\n CharacterCodes[CharacterCodes[\"_2\"] = 50] = \"_2\";\n CharacterCodes[CharacterCodes[\"_3\"] = 51] = \"_3\";\n CharacterCodes[CharacterCodes[\"_4\"] = 52] = \"_4\";\n CharacterCodes[CharacterCodes[\"_5\"] = 53] = \"_5\";\n CharacterCodes[CharacterCodes[\"_6\"] = 54] = \"_6\";\n CharacterCodes[CharacterCodes[\"_7\"] = 55] = \"_7\";\n CharacterCodes[CharacterCodes[\"_8\"] = 56] = \"_8\";\n CharacterCodes[CharacterCodes[\"_9\"] = 57] = \"_9\";\n CharacterCodes[CharacterCodes[\"a\"] = 97] = \"a\";\n CharacterCodes[CharacterCodes[\"b\"] = 98] = \"b\";\n CharacterCodes[CharacterCodes[\"c\"] = 99] = \"c\";\n CharacterCodes[CharacterCodes[\"d\"] = 100] = \"d\";\n CharacterCodes[CharacterCodes[\"e\"] = 101] = \"e\";\n CharacterCodes[CharacterCodes[\"f\"] = 102] = \"f\";\n CharacterCodes[CharacterCodes[\"g\"] = 103] = \"g\";\n CharacterCodes[CharacterCodes[\"h\"] = 104] = \"h\";\n CharacterCodes[CharacterCodes[\"i\"] = 105] = \"i\";\n CharacterCodes[CharacterCodes[\"j\"] = 106] = \"j\";\n CharacterCodes[CharacterCodes[\"k\"] = 107] = \"k\";\n CharacterCodes[CharacterCodes[\"l\"] = 108] = \"l\";\n CharacterCodes[CharacterCodes[\"m\"] = 109] = \"m\";\n CharacterCodes[CharacterCodes[\"n\"] = 110] = \"n\";\n CharacterCodes[CharacterCodes[\"o\"] = 111] = \"o\";\n CharacterCodes[CharacterCodes[\"p\"] = 112] = \"p\";\n CharacterCodes[CharacterCodes[\"q\"] = 113] = \"q\";\n CharacterCodes[CharacterCodes[\"r\"] = 114] = \"r\";\n CharacterCodes[CharacterCodes[\"s\"] = 115] = \"s\";\n CharacterCodes[CharacterCodes[\"t\"] = 116] = \"t\";\n CharacterCodes[CharacterCodes[\"u\"] = 117] = \"u\";\n CharacterCodes[CharacterCodes[\"v\"] = 118] = \"v\";\n CharacterCodes[CharacterCodes[\"w\"] = 119] = \"w\";\n CharacterCodes[CharacterCodes[\"x\"] = 120] = \"x\";\n CharacterCodes[CharacterCodes[\"y\"] = 121] = \"y\";\n CharacterCodes[CharacterCodes[\"z\"] = 122] = \"z\";\n CharacterCodes[CharacterCodes[\"A\"] = 65] = \"A\";\n CharacterCodes[CharacterCodes[\"B\"] = 66] = \"B\";\n CharacterCodes[CharacterCodes[\"C\"] = 67] = \"C\";\n CharacterCodes[CharacterCodes[\"D\"] = 68] = \"D\";\n CharacterCodes[CharacterCodes[\"E\"] = 69] = \"E\";\n CharacterCodes[CharacterCodes[\"F\"] = 70] = \"F\";\n CharacterCodes[CharacterCodes[\"G\"] = 71] = \"G\";\n CharacterCodes[CharacterCodes[\"H\"] = 72] = \"H\";\n CharacterCodes[CharacterCodes[\"I\"] = 73] = \"I\";\n CharacterCodes[CharacterCodes[\"J\"] = 74] = \"J\";\n CharacterCodes[CharacterCodes[\"K\"] = 75] = \"K\";\n CharacterCodes[CharacterCodes[\"L\"] = 76] = \"L\";\n CharacterCodes[CharacterCodes[\"M\"] = 77] = \"M\";\n CharacterCodes[CharacterCodes[\"N\"] = 78] = \"N\";\n CharacterCodes[CharacterCodes[\"O\"] = 79] = \"O\";\n CharacterCodes[CharacterCodes[\"P\"] = 80] = \"P\";\n CharacterCodes[CharacterCodes[\"Q\"] = 81] = \"Q\";\n CharacterCodes[CharacterCodes[\"R\"] = 82] = \"R\";\n CharacterCodes[CharacterCodes[\"S\"] = 83] = \"S\";\n CharacterCodes[CharacterCodes[\"T\"] = 84] = \"T\";\n CharacterCodes[CharacterCodes[\"U\"] = 85] = \"U\";\n CharacterCodes[CharacterCodes[\"V\"] = 86] = \"V\";\n CharacterCodes[CharacterCodes[\"W\"] = 87] = \"W\";\n CharacterCodes[CharacterCodes[\"X\"] = 88] = \"X\";\n CharacterCodes[CharacterCodes[\"Y\"] = 89] = \"Y\";\n CharacterCodes[CharacterCodes[\"Z\"] = 90] = \"Z\";\n CharacterCodes[CharacterCodes[\"asterisk\"] = 42] = \"asterisk\";\n CharacterCodes[CharacterCodes[\"backslash\"] = 92] = \"backslash\";\n CharacterCodes[CharacterCodes[\"closeBrace\"] = 125] = \"closeBrace\";\n CharacterCodes[CharacterCodes[\"closeBracket\"] = 93] = \"closeBracket\";\n CharacterCodes[CharacterCodes[\"colon\"] = 58] = \"colon\";\n CharacterCodes[CharacterCodes[\"comma\"] = 44] = \"comma\";\n CharacterCodes[CharacterCodes[\"dot\"] = 46] = \"dot\";\n CharacterCodes[CharacterCodes[\"doubleQuote\"] = 34] = \"doubleQuote\";\n CharacterCodes[CharacterCodes[\"minus\"] = 45] = \"minus\";\n CharacterCodes[CharacterCodes[\"openBrace\"] = 123] = \"openBrace\";\n CharacterCodes[CharacterCodes[\"openBracket\"] = 91] = \"openBracket\";\n CharacterCodes[CharacterCodes[\"plus\"] = 43] = \"plus\";\n CharacterCodes[CharacterCodes[\"slash\"] = 47] = \"slash\";\n CharacterCodes[CharacterCodes[\"formFeed\"] = 12] = \"formFeed\";\n CharacterCodes[CharacterCodes[\"tab\"] = 9] = \"tab\";\n})(CharacterCodes || (CharacterCodes = {}));\n","export const cachedSpaces = new Array(20).fill(0).map((_, index) => {\n return ' '.repeat(index);\n});\nconst maxCachedValues = 200;\nexport const cachedBreakLinesWithSpaces = {\n ' ': {\n '\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\n' + ' '.repeat(index);\n }),\n '\\r': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r' + ' '.repeat(index);\n }),\n '\\r\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r\\n' + ' '.repeat(index);\n }),\n },\n '\\t': {\n '\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\n' + '\\t'.repeat(index);\n }),\n '\\r': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r' + '\\t'.repeat(index);\n }),\n '\\r\\n': new Array(maxCachedValues).fill(0).map((_, index) => {\n return '\\r\\n' + '\\t'.repeat(index);\n }),\n }\n};\nexport const supportedEols = ['\\n', '\\r', '\\r\\n'];\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nimport { createScanner } from './scanner';\nvar ParseOptions;\n(function (ParseOptions) {\n ParseOptions.DEFAULT = {\n allowTrailingComma: false\n };\n})(ParseOptions || (ParseOptions = {}));\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport function getLocation(text, position) {\n const segments = []; // strings or numbers\n const earlyReturnException = new Object();\n let previousNode = undefined;\n const previousNodeInst = {\n value: {},\n offset: 0,\n length: 0,\n type: 'object',\n parent: undefined\n };\n let isAtPropertyKey = false;\n function setPreviousNode(value, offset, length, type) {\n previousNodeInst.value = value;\n previousNodeInst.offset = offset;\n previousNodeInst.length = length;\n previousNodeInst.type = type;\n previousNodeInst.colonOffset = undefined;\n previousNode = previousNodeInst;\n }\n try {\n visit(text, {\n onObjectBegin: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n isAtPropertyKey = position > offset;\n segments.push(''); // push a placeholder (will be replaced)\n },\n onObjectProperty: (name, offset, length) => {\n if (position < offset) {\n throw earlyReturnException;\n }\n setPreviousNode(name, offset, length, 'property');\n segments[segments.length - 1] = name;\n if (position <= offset + length) {\n throw earlyReturnException;\n }\n },\n onObjectEnd: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.pop();\n },\n onArrayBegin: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.push(0);\n },\n onArrayEnd: (offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n previousNode = undefined;\n segments.pop();\n },\n onLiteralValue: (value, offset, length) => {\n if (position < offset) {\n throw earlyReturnException;\n }\n setPreviousNode(value, offset, length, getNodeType(value));\n if (position <= offset + length) {\n throw earlyReturnException;\n }\n },\n onSeparator: (sep, offset, length) => {\n if (position <= offset) {\n throw earlyReturnException;\n }\n if (sep === ':' && previousNode && previousNode.type === 'property') {\n previousNode.colonOffset = offset;\n isAtPropertyKey = false;\n previousNode = undefined;\n }\n else if (sep === ',') {\n const last = segments[segments.length - 1];\n if (typeof last === 'number') {\n segments[segments.length - 1] = last + 1;\n }\n else {\n isAtPropertyKey = true;\n segments[segments.length - 1] = '';\n }\n previousNode = undefined;\n }\n }\n });\n }\n catch (e) {\n if (e !== earlyReturnException) {\n throw e;\n }\n }\n return {\n path: segments,\n previousNode,\n isAtPropertyKey,\n matches: (pattern) => {\n let k = 0;\n for (let i = 0; k < pattern.length && i < segments.length; i++) {\n if (pattern[k] === segments[i] || pattern[k] === '*') {\n k++;\n }\n else if (pattern[k] !== '**') {\n return false;\n }\n }\n return k === pattern.length;\n }\n };\n}\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore always check the errors list to find out if the input was valid.\n */\nexport function parse(text, errors = [], options = ParseOptions.DEFAULT) {\n let currentProperty = null;\n let currentParent = [];\n const previousParents = [];\n function onValue(value) {\n if (Array.isArray(currentParent)) {\n currentParent.push(value);\n }\n else if (currentProperty !== null) {\n currentParent[currentProperty] = value;\n }\n }\n const visitor = {\n onObjectBegin: () => {\n const object = {};\n onValue(object);\n previousParents.push(currentParent);\n currentParent = object;\n currentProperty = null;\n },\n onObjectProperty: (name) => {\n currentProperty = name;\n },\n onObjectEnd: () => {\n currentParent = previousParents.pop();\n },\n onArrayBegin: () => {\n const array = [];\n onValue(array);\n previousParents.push(currentParent);\n currentParent = array;\n currentProperty = null;\n },\n onArrayEnd: () => {\n currentParent = previousParents.pop();\n },\n onLiteralValue: onValue,\n onError: (error, offset, length) => {\n errors.push({ error, offset, length });\n }\n };\n visit(text, visitor, options);\n return currentParent[0];\n}\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport function parseTree(text, errors = [], options = ParseOptions.DEFAULT) {\n let currentParent = { type: 'array', offset: -1, length: -1, children: [], parent: undefined }; // artificial root\n function ensurePropertyComplete(endOffset) {\n if (currentParent.type === 'property') {\n currentParent.length = endOffset - currentParent.offset;\n currentParent = currentParent.parent;\n }\n }\n function onValue(valueNode) {\n currentParent.children.push(valueNode);\n return valueNode;\n }\n const visitor = {\n onObjectBegin: (offset) => {\n currentParent = onValue({ type: 'object', offset, length: -1, parent: currentParent, children: [] });\n },\n onObjectProperty: (name, offset, length) => {\n currentParent = onValue({ type: 'property', offset, length: -1, parent: currentParent, children: [] });\n currentParent.children.push({ type: 'string', value: name, offset, length, parent: currentParent });\n },\n onObjectEnd: (offset, length) => {\n ensurePropertyComplete(offset + length); // in case of a missing value for a property: make sure property is complete\n currentParent.length = offset + length - currentParent.offset;\n currentParent = currentParent.parent;\n ensurePropertyComplete(offset + length);\n },\n onArrayBegin: (offset, length) => {\n currentParent = onValue({ type: 'array', offset, length: -1, parent: currentParent, children: [] });\n },\n onArrayEnd: (offset, length) => {\n currentParent.length = offset + length - currentParent.offset;\n currentParent = currentParent.parent;\n ensurePropertyComplete(offset + length);\n },\n onLiteralValue: (value, offset, length) => {\n onValue({ type: getNodeType(value), offset, length, parent: currentParent, value });\n ensurePropertyComplete(offset + length);\n },\n onSeparator: (sep, offset, length) => {\n if (currentParent.type === 'property') {\n if (sep === ':') {\n currentParent.colonOffset = offset;\n }\n else if (sep === ',') {\n ensurePropertyComplete(offset);\n }\n }\n },\n onError: (error, offset, length) => {\n errors.push({ error, offset, length });\n }\n };\n visit(text, visitor, options);\n const result = currentParent.children[0];\n if (result) {\n delete result.parent;\n }\n return result;\n}\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport function findNodeAtLocation(root, path) {\n if (!root) {\n return undefined;\n }\n let node = root;\n for (let segment of path) {\n if (typeof segment === 'string') {\n if (node.type !== 'object' || !Array.isArray(node.children)) {\n return undefined;\n }\n let found = false;\n for (const propertyNode of node.children) {\n if (Array.isArray(propertyNode.children) && propertyNode.children[0].value === segment && propertyNode.children.length === 2) {\n node = propertyNode.children[1];\n found = true;\n break;\n }\n }\n if (!found) {\n return undefined;\n }\n }\n else {\n const index = segment;\n if (node.type !== 'array' || index < 0 || !Array.isArray(node.children) || index >= node.children.length) {\n return undefined;\n }\n node = node.children[index];\n }\n }\n return node;\n}\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport function getNodePath(node) {\n if (!node.parent || !node.parent.children) {\n return [];\n }\n const path = getNodePath(node.parent);\n if (node.parent.type === 'property') {\n const key = node.parent.children[0].value;\n path.push(key);\n }\n else if (node.parent.type === 'array') {\n const index = node.parent.children.indexOf(node);\n if (index !== -1) {\n path.push(index);\n }\n }\n return path;\n}\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport function getNodeValue(node) {\n switch (node.type) {\n case 'array':\n return node.children.map(getNodeValue);\n case 'object':\n const obj = Object.create(null);\n for (let prop of node.children) {\n const valueNode = prop.children[1];\n if (valueNode) {\n obj[prop.children[0].value] = getNodeValue(valueNode);\n }\n }\n return obj;\n case 'null':\n case 'string':\n case 'number':\n case 'boolean':\n return node.value;\n default:\n return undefined;\n }\n}\nexport function contains(node, offset, includeRightBound = false) {\n return (offset >= node.offset && offset < (node.offset + node.length)) || includeRightBound && (offset === (node.offset + node.length));\n}\n/**\n * Finds the most inner node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport function findNodeAtOffset(node, offset, includeRightBound = false) {\n if (contains(node, offset, includeRightBound)) {\n const children = node.children;\n if (Array.isArray(children)) {\n for (let i = 0; i < children.length && children[i].offset <= offset; i++) {\n const item = findNodeAtOffset(children[i], offset, includeRightBound);\n if (item) {\n return item;\n }\n }\n }\n return node;\n }\n return undefined;\n}\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport function visit(text, visitor, options = ParseOptions.DEFAULT) {\n const _scanner = createScanner(text, false);\n // Important: Only pass copies of this to visitor functions to prevent accidental modification, and\n // to not affect visitor functions which stored a reference to a previous JSONPath\n const _jsonPath = [];\n // Depth of onXXXBegin() callbacks suppressed. onXXXEnd() decrements this if it isn't 0 already.\n // Callbacks are only called when this value is 0.\n let suppressedCallbacks = 0;\n function toNoArgVisit(visitFunction) {\n return visitFunction ? () => suppressedCallbacks === 0 && visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;\n }\n function toOneArgVisit(visitFunction) {\n return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter()) : () => true;\n }\n function toOneArgVisitWithPath(visitFunction) {\n return visitFunction ? (arg) => suppressedCallbacks === 0 && visitFunction(arg, _scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice()) : () => true;\n }\n function toBeginVisit(visitFunction) {\n return visitFunction ?\n () => {\n if (suppressedCallbacks > 0) {\n suppressedCallbacks++;\n }\n else {\n let cbReturn = visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter(), () => _jsonPath.slice());\n if (cbReturn === false) {\n suppressedCallbacks = 1;\n }\n }\n }\n : () => true;\n }\n function toEndVisit(visitFunction) {\n return visitFunction ?\n () => {\n if (suppressedCallbacks > 0) {\n suppressedCallbacks--;\n }\n if (suppressedCallbacks === 0) {\n visitFunction(_scanner.getTokenOffset(), _scanner.getTokenLength(), _scanner.getTokenStartLine(), _scanner.getTokenStartCharacter());\n }\n }\n : () => true;\n }\n const onObjectBegin = toBeginVisit(visitor.onObjectBegin), onObjectProperty = toOneArgVisitWithPath(visitor.onObjectProperty), onObjectEnd = toEndVisit(visitor.onObjectEnd), onArrayBegin = toBeginVisit(visitor.onArrayBegin), onArrayEnd = toEndVisit(visitor.onArrayEnd), onLiteralValue = toOneArgVisitWithPath(visitor.onLiteralValue), onSeparator = toOneArgVisit(visitor.onSeparator), onComment = toNoArgVisit(visitor.onComment), onError = toOneArgVisit(visitor.onError);\n const disallowComments = options && options.disallowComments;\n const allowTrailingComma = options && options.allowTrailingComma;\n function scanNext() {\n while (true) {\n const token = _scanner.scan();\n switch (_scanner.getTokenError()) {\n case 4 /* ScanError.InvalidUnicode */:\n handleError(14 /* ParseErrorCode.InvalidUnicode */);\n break;\n case 5 /* ScanError.InvalidEscapeCharacter */:\n handleError(15 /* ParseErrorCode.InvalidEscapeCharacter */);\n break;\n case 3 /* ScanError.UnexpectedEndOfNumber */:\n handleError(13 /* ParseErrorCode.UnexpectedEndOfNumber */);\n break;\n case 1 /* ScanError.UnexpectedEndOfComment */:\n if (!disallowComments) {\n handleError(11 /* ParseErrorCode.UnexpectedEndOfComment */);\n }\n break;\n case 2 /* ScanError.UnexpectedEndOfString */:\n handleError(12 /* ParseErrorCode.UnexpectedEndOfString */);\n break;\n case 6 /* ScanError.InvalidCharacter */:\n handleError(16 /* ParseErrorCode.InvalidCharacter */);\n break;\n }\n switch (token) {\n case 12 /* SyntaxKind.LineCommentTrivia */:\n case 13 /* SyntaxKind.BlockCommentTrivia */:\n if (disallowComments) {\n handleError(10 /* ParseErrorCode.InvalidCommentToken */);\n }\n else {\n onComment();\n }\n break;\n case 16 /* SyntaxKind.Unknown */:\n handleError(1 /* ParseErrorCode.InvalidSymbol */);\n break;\n case 15 /* SyntaxKind.Trivia */:\n case 14 /* SyntaxKind.LineBreakTrivia */:\n break;\n default:\n return token;\n }\n }\n }\n function handleError(error, skipUntilAfter = [], skipUntil = []) {\n onError(error);\n if (skipUntilAfter.length + skipUntil.length > 0) {\n let token = _scanner.getToken();\n while (token !== 17 /* SyntaxKind.EOF */) {\n if (skipUntilAfter.indexOf(token) !== -1) {\n scanNext();\n break;\n }\n else if (skipUntil.indexOf(token) !== -1) {\n break;\n }\n token = scanNext();\n }\n }\n }\n function parseString(isValue) {\n const value = _scanner.getTokenValue();\n if (isValue) {\n onLiteralValue(value);\n }\n else {\n onObjectProperty(value);\n // add property name afterwards\n _jsonPath.push(value);\n }\n scanNext();\n return true;\n }\n function parseLiteral() {\n switch (_scanner.getToken()) {\n case 11 /* SyntaxKind.NumericLiteral */:\n const tokenValue = _scanner.getTokenValue();\n let value = Number(tokenValue);\n if (isNaN(value)) {\n handleError(2 /* ParseErrorCode.InvalidNumberFormat */);\n value = 0;\n }\n onLiteralValue(value);\n break;\n case 7 /* SyntaxKind.NullKeyword */:\n onLiteralValue(null);\n break;\n case 8 /* SyntaxKind.TrueKeyword */:\n onLiteralValue(true);\n break;\n case 9 /* SyntaxKind.FalseKeyword */:\n onLiteralValue(false);\n break;\n default:\n return false;\n }\n scanNext();\n return true;\n }\n function parseProperty() {\n if (_scanner.getToken() !== 10 /* SyntaxKind.StringLiteral */) {\n handleError(3 /* ParseErrorCode.PropertyNameExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n return false;\n }\n parseString(false);\n if (_scanner.getToken() === 6 /* SyntaxKind.ColonToken */) {\n onSeparator(':');\n scanNext(); // consume colon\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n }\n else {\n handleError(5 /* ParseErrorCode.ColonExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n _jsonPath.pop(); // remove processed property name\n return true;\n }\n function parseObject() {\n onObjectBegin();\n scanNext(); // consume open brace\n let needsComma = false;\n while (_scanner.getToken() !== 2 /* SyntaxKind.CloseBraceToken */ && _scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n if (_scanner.getToken() === 5 /* SyntaxKind.CommaToken */) {\n if (!needsComma) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n }\n onSeparator(',');\n scanNext(); // consume comma\n if (_scanner.getToken() === 2 /* SyntaxKind.CloseBraceToken */ && allowTrailingComma) {\n break;\n }\n }\n else if (needsComma) {\n handleError(6 /* ParseErrorCode.CommaExpected */, [], []);\n }\n if (!parseProperty()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [2 /* SyntaxKind.CloseBraceToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n needsComma = true;\n }\n onObjectEnd();\n if (_scanner.getToken() !== 2 /* SyntaxKind.CloseBraceToken */) {\n handleError(7 /* ParseErrorCode.CloseBraceExpected */, [2 /* SyntaxKind.CloseBraceToken */], []);\n }\n else {\n scanNext(); // consume close brace\n }\n return true;\n }\n function parseArray() {\n onArrayBegin();\n scanNext(); // consume open bracket\n let isFirstElement = true;\n let needsComma = false;\n while (_scanner.getToken() !== 4 /* SyntaxKind.CloseBracketToken */ && _scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n if (_scanner.getToken() === 5 /* SyntaxKind.CommaToken */) {\n if (!needsComma) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n }\n onSeparator(',');\n scanNext(); // consume comma\n if (_scanner.getToken() === 4 /* SyntaxKind.CloseBracketToken */ && allowTrailingComma) {\n break;\n }\n }\n else if (needsComma) {\n handleError(6 /* ParseErrorCode.CommaExpected */, [], []);\n }\n if (isFirstElement) {\n _jsonPath.push(0);\n isFirstElement = false;\n }\n else {\n _jsonPath[_jsonPath.length - 1]++;\n }\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], [4 /* SyntaxKind.CloseBracketToken */, 5 /* SyntaxKind.CommaToken */]);\n }\n needsComma = true;\n }\n onArrayEnd();\n if (!isFirstElement) {\n _jsonPath.pop(); // remove array index\n }\n if (_scanner.getToken() !== 4 /* SyntaxKind.CloseBracketToken */) {\n handleError(8 /* ParseErrorCode.CloseBracketExpected */, [4 /* SyntaxKind.CloseBracketToken */], []);\n }\n else {\n scanNext(); // consume close bracket\n }\n return true;\n }\n function parseValue() {\n switch (_scanner.getToken()) {\n case 3 /* SyntaxKind.OpenBracketToken */:\n return parseArray();\n case 1 /* SyntaxKind.OpenBraceToken */:\n return parseObject();\n case 10 /* SyntaxKind.StringLiteral */:\n return parseString(true);\n default:\n return parseLiteral();\n }\n }\n scanNext();\n if (_scanner.getToken() === 17 /* SyntaxKind.EOF */) {\n if (options.allowEmptyContent) {\n return true;\n }\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n return false;\n }\n if (!parseValue()) {\n handleError(4 /* ParseErrorCode.ValueExpected */, [], []);\n return false;\n }\n if (_scanner.getToken() !== 17 /* SyntaxKind.EOF */) {\n handleError(9 /* ParseErrorCode.EndOfFileExpected */, [], []);\n }\n return true;\n}\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport function stripComments(text, replaceCh) {\n let _scanner = createScanner(text), parts = [], kind, offset = 0, pos;\n do {\n pos = _scanner.getPosition();\n kind = _scanner.scan();\n switch (kind) {\n case 12 /* SyntaxKind.LineCommentTrivia */:\n case 13 /* SyntaxKind.BlockCommentTrivia */:\n case 17 /* SyntaxKind.EOF */:\n if (offset !== pos) {\n parts.push(text.substring(offset, pos));\n }\n if (replaceCh !== undefined) {\n parts.push(_scanner.getTokenValue().replace(/[^\\r\\n]/g, replaceCh));\n }\n offset = _scanner.getPosition();\n break;\n }\n } while (kind !== 17 /* SyntaxKind.EOF */);\n return parts.join('');\n}\nexport function getNodeType(value) {\n switch (typeof value) {\n case 'boolean': return 'boolean';\n case 'number': return 'number';\n case 'string': return 'string';\n case 'object': {\n if (!value) {\n return 'null';\n }\n else if (Array.isArray(value)) {\n return 'array';\n }\n return 'object';\n }\n default: return 'null';\n }\n}\n","/*---------------------------------------------------------------------------------------------\n * Copyright (c) Microsoft Corporation. All rights reserved.\n * Licensed under the MIT License. See License.txt in the project root for license information.\n *--------------------------------------------------------------------------------------------*/\n'use strict';\nimport * as formatter from './impl/format';\nimport * as edit from './impl/edit';\nimport * as scanner from './impl/scanner';\nimport * as parser from './impl/parser';\n/**\n * Creates a JSON scanner on the given text.\n * If ignoreTrivia is set, whitespaces or comments are ignored.\n */\nexport const createScanner = scanner.createScanner;\nexport var ScanError;\n(function (ScanError) {\n ScanError[ScanError[\"None\"] = 0] = \"None\";\n ScanError[ScanError[\"UnexpectedEndOfComment\"] = 1] = \"UnexpectedEndOfComment\";\n ScanError[ScanError[\"UnexpectedEndOfString\"] = 2] = \"UnexpectedEndOfString\";\n ScanError[ScanError[\"UnexpectedEndOfNumber\"] = 3] = \"UnexpectedEndOfNumber\";\n ScanError[ScanError[\"InvalidUnicode\"] = 4] = \"InvalidUnicode\";\n ScanError[ScanError[\"InvalidEscapeCharacter\"] = 5] = \"InvalidEscapeCharacter\";\n ScanError[ScanError[\"InvalidCharacter\"] = 6] = \"InvalidCharacter\";\n})(ScanError || (ScanError = {}));\nexport var SyntaxKind;\n(function (SyntaxKind) {\n SyntaxKind[SyntaxKind[\"OpenBraceToken\"] = 1] = \"OpenBraceToken\";\n SyntaxKind[SyntaxKind[\"CloseBraceToken\"] = 2] = \"CloseBraceToken\";\n SyntaxKind[SyntaxKind[\"OpenBracketToken\"] = 3] = \"OpenBracketToken\";\n SyntaxKind[SyntaxKind[\"CloseBracketToken\"] = 4] = \"CloseBracketToken\";\n SyntaxKind[SyntaxKind[\"CommaToken\"] = 5] = \"CommaToken\";\n SyntaxKind[SyntaxKind[\"ColonToken\"] = 6] = \"ColonToken\";\n SyntaxKind[SyntaxKind[\"NullKeyword\"] = 7] = \"NullKeyword\";\n SyntaxKind[SyntaxKind[\"TrueKeyword\"] = 8] = \"TrueKeyword\";\n SyntaxKind[SyntaxKind[\"FalseKeyword\"] = 9] = \"FalseKeyword\";\n SyntaxKind[SyntaxKind[\"StringLiteral\"] = 10] = \"StringLiteral\";\n SyntaxKind[SyntaxKind[\"NumericLiteral\"] = 11] = \"NumericLiteral\";\n SyntaxKind[SyntaxKind[\"LineCommentTrivia\"] = 12] = \"LineCommentTrivia\";\n SyntaxKind[SyntaxKind[\"BlockCommentTrivia\"] = 13] = \"BlockCommentTrivia\";\n SyntaxKind[SyntaxKind[\"LineBreakTrivia\"] = 14] = \"LineBreakTrivia\";\n SyntaxKind[SyntaxKind[\"Trivia\"] = 15] = \"Trivia\";\n SyntaxKind[SyntaxKind[\"Unknown\"] = 16] = \"Unknown\";\n SyntaxKind[SyntaxKind[\"EOF\"] = 17] = \"EOF\";\n})(SyntaxKind || (SyntaxKind = {}));\n/**\n * For a given offset, evaluate the location in the JSON document. Each segment in the location path is either a property name or an array index.\n */\nexport const getLocation = parser.getLocation;\n/**\n * Parses the given text and returns the object the JSON content represents. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n * Therefore, always check the errors list to find out if the input was valid.\n */\nexport const parse = parser.parse;\n/**\n * Parses the given text and returns a tree representation the JSON content. On invalid input, the parser tries to be as fault tolerant as possible, but still return a result.\n */\nexport const parseTree = parser.parseTree;\n/**\n * Finds the node at the given path in a JSON DOM.\n */\nexport const findNodeAtLocation = parser.findNodeAtLocation;\n/**\n * Finds the innermost node at the given offset. If includeRightBound is set, also finds nodes that end at the given offset.\n */\nexport const findNodeAtOffset = parser.findNodeAtOffset;\n/**\n * Gets the JSON path of the given JSON DOM node\n */\nexport const getNodePath = parser.getNodePath;\n/**\n * Evaluates the JavaScript object of the given JSON DOM node\n */\nexport const getNodeValue = parser.getNodeValue;\n/**\n * Parses the given text and invokes the visitor functions for each object, array and literal reached.\n */\nexport const visit = parser.visit;\n/**\n * Takes JSON with JavaScript-style comments and remove\n * them. Optionally replaces every none-newline character\n * of comments with a replaceCharacter\n */\nexport const stripComments = parser.stripComments;\nexport var ParseErrorCode;\n(function (ParseErrorCode) {\n ParseErrorCode[ParseErrorCode[\"InvalidSymbol\"] = 1] = \"InvalidSymbol\";\n ParseErrorCode[ParseErrorCode[\"InvalidNumberFormat\"] = 2] = \"InvalidNumberFormat\";\n ParseErrorCode[ParseErrorCode[\"PropertyNameExpected\"] = 3] = \"PropertyNameExpected\";\n ParseErrorCode[ParseErrorCode[\"ValueExpected\"] = 4] = \"ValueExpected\";\n ParseErrorCode[ParseErrorCode[\"ColonExpected\"] = 5] = \"ColonExpected\";\n ParseErrorCode[ParseErrorCode[\"CommaExpected\"] = 6] = \"CommaExpected\";\n ParseErrorCode[ParseErrorCode[\"CloseBraceExpected\"] = 7] = \"CloseBraceExpected\";\n ParseErrorCode[ParseErrorCode[\"CloseBracketExpected\"] = 8] = \"CloseBracketExpected\";\n ParseErrorCode[ParseErrorCode[\"EndOfFileExpected\"] = 9] = \"EndOfFileExpected\";\n ParseErrorCode[ParseErrorCode[\"InvalidCommentToken\"] = 10] = \"InvalidCommentToken\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfComment\"] = 11] = \"UnexpectedEndOfComment\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfString\"] = 12] = \"UnexpectedEndOfString\";\n ParseErrorCode[ParseErrorCode[\"UnexpectedEndOfNumber\"] = 13] = \"UnexpectedEndOfNumber\";\n ParseErrorCode[ParseErrorCode[\"InvalidUnicode\"] = 14] = \"InvalidUnicode\";\n ParseErrorCode[ParseErrorCode[\"InvalidEscapeCharacter\"] = 15] = \"InvalidEscapeCharacter\";\n ParseErrorCode[ParseErrorCode[\"InvalidCharacter\"] = 16] = \"InvalidCharacter\";\n})(ParseErrorCode || (ParseErrorCode = {}));\nexport function printParseErrorCode(code) {\n switch (code) {\n case 1 /* ParseErrorCode.InvalidSymbol */: return 'InvalidSymbol';\n case 2 /* ParseErrorCode.InvalidNumberFormat */: return 'InvalidNumberFormat';\n case 3 /* ParseErrorCode.PropertyNameExpected */: return 'PropertyNameExpected';\n case 4 /* ParseErrorCode.ValueExpected */: return 'ValueExpected';\n case 5 /* ParseErrorCode.ColonExpected */: return 'ColonExpected';\n case 6 /* ParseErrorCode.CommaExpected */: return 'CommaExpected';\n case 7 /* ParseErrorCode.CloseBraceExpected */: return 'CloseBraceExpected';\n case 8 /* ParseErrorCode.CloseBracketExpected */: return 'CloseBracketExpected';\n case 9 /* ParseErrorCode.EndOfFileExpected */: return 'EndOfFileExpected';\n case 10 /* ParseErrorCode.InvalidCommentToken */: return 'InvalidCommentToken';\n case 11 /* ParseErrorCode.UnexpectedEndOfComment */: return 'UnexpectedEndOfComment';\n case 12 /* ParseErrorCode.UnexpectedEndOfString */: return 'UnexpectedEndOfString';\n case 13 /* ParseErrorCode.UnexpectedEndOfNumber */: return 'UnexpectedEndOfNumber';\n case 14 /* ParseErrorCode.InvalidUnicode */: return 'InvalidUnicode';\n case 15 /* ParseErrorCode.InvalidEscapeCharacter */: return 'InvalidEscapeCharacter';\n case 16 /* ParseErrorCode.InvalidCharacter */: return 'InvalidCharacter';\n }\n return '<unknown ParseErrorCode>';\n}\n/**\n * Computes the edit operations needed to format a JSON document.\n *\n * @param documentText The input text\n * @param range The range to format or `undefined` to format the full content\n * @param options The formatting options\n * @returns The edit operations describing the formatting changes to the original document following the format described in {@linkcode EditResult}.\n * To apply the edit operations to the input, use {@linkcode applyEdits}.\n */\nexport function format(documentText, range, options) {\n return formatter.format(documentText, range, options);\n}\n/**\n * Computes the edit operations needed to modify a value in the JSON document.\n *\n * @param documentText The input text\n * @param path The path of the value to change. The path represents either to the document root, a property or an array item.\n * If the path points to an non-existing property or item, it will be created.\n * @param value The new value for the specified property or item. If the value is undefined,\n * the property or item will be removed.\n * @param options Options\n * @returns The edit operations describing the changes to the original document, following the format described in {@linkcode EditResult}.\n * To apply the edit operations to the input, use {@linkcode applyEdits}.\n */\nexport function modify(text, path, value, options) {\n return edit.setProperty(text, path, value, options);\n}\n/**\n * Applies edits to an input string.\n * @param text The input text\n * @param edits Edit operations following the format described in {@linkcode EditResult}.\n * @returns The text with the applied edits.\n * @throws An error if the edit operations are not well-formed as described in {@linkcode EditResult}.\n */\nexport function applyEdits(text, edits) {\n let sortedEdits = edits.slice(0).sort((a, b) => {\n const diff = a.offset - b.offset;\n if (diff === 0) {\n return a.length - b.length;\n }\n return diff;\n });\n let lastModifiedOffset = text.length;\n for (let i = sortedEdits.length - 1; i >= 0; i--) {\n let e = sortedEdits[i];\n if (e.offset + e.length <= lastModifiedOffset) {\n text = edit.applyEdit(text, e);\n }\n else {\n throw new Error('Overlapping edit');\n }\n lastModifiedOffset = e.offset;\n }\n return text;\n}\n","/**\n * TypeScript scope resolution for validation.\n *\n * Provides functions to determine which directories should be validated\n * based on tsconfig.json settings, ensuring alignment between TypeScript\n * and ESLint validation.\n *\n * @module validation/config/scope\n */\n\nimport * as JSONC from \"jsonc-parser\";\nimport { existsSync, readdirSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport type { ScopeConfig, ValidationScope } from \"../types\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/**\n * TSConfig file paths for each validation scope.\n */\nexport const TSCONFIG_FILES = {\n full: \"tsconfig.json\",\n production: \"tsconfig.production.json\",\n} as const;\n\n// =============================================================================\n// DEPENDENCY INJECTION INTERFACES\n// =============================================================================\n\n/**\n * Dependencies for scope resolution.\n *\n * Enables dependency injection for testing without mocking.\n */\nexport interface ScopeDeps {\n readFileSync: typeof readFileSync;\n existsSync: typeof existsSync;\n readdirSync: typeof readdirSync;\n}\n\n/**\n * Default production dependencies.\n */\nexport const defaultScopeDeps: ScopeDeps = {\n readFileSync,\n existsSync,\n readdirSync,\n};\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\ninterface TypeScriptConfig {\n include?: string[];\n exclude?: string[];\n extends?: string;\n}\n\n// =============================================================================\n// INTERNAL FUNCTIONS\n// =============================================================================\n\n/**\n * Parse TypeScript configuration using proper JSONC parser.\n *\n * @param configPath - Path to tsconfig file\n * @param deps - Injectable dependencies\n * @returns Parsed TypeScript configuration\n */\nexport function parseTypeScriptConfig(\n configPath: string,\n deps: ScopeDeps = defaultScopeDeps,\n): TypeScriptConfig {\n try {\n const configContent = deps.readFileSync(configPath, \"utf-8\");\n const parsed = JSONC.parse(configContent) as TypeScriptConfig;\n return parsed;\n } catch {\n // Fallback: return minimal config and let directory detection work\n return {\n include: [\"**/*.ts\", \"**/*.tsx\"],\n exclude: [\"node_modules/**\", \".pnpm-store/**\", \"dist/**\"],\n };\n }\n}\n\n/**\n * Resolve complete TypeScript configuration including extends.\n *\n * @param scope - Validation scope\n * @param deps - Injectable dependencies\n * @returns Resolved TypeScript configuration\n */\nexport function resolveTypeScriptConfig(\n scope: ValidationScope,\n deps: ScopeDeps = defaultScopeDeps,\n): TypeScriptConfig {\n const configFile = TSCONFIG_FILES[scope];\n const config = parseTypeScriptConfig(configFile, deps);\n\n if (config.extends) {\n const baseConfig = parseTypeScriptConfig(config.extends, deps);\n return {\n include: config.include ?? baseConfig.include ?? [],\n exclude: [...(baseConfig.exclude ?? []), ...(config.exclude ?? [])],\n };\n }\n\n return {\n include: config.include ?? [],\n exclude: config.exclude ?? [],\n };\n}\n\n/**\n * Check if a directory contains TypeScript files recursively.\n *\n * @param dirPath - Directory to check\n * @param maxDepth - Maximum recursion depth\n * @param deps - Injectable dependencies\n * @returns True if directory contains TypeScript files\n */\nexport function hasTypeScriptFilesRecursive(\n dirPath: string,\n maxDepth: number = 2,\n deps: ScopeDeps = defaultScopeDeps,\n): boolean {\n if (maxDepth <= 0) return false;\n\n try {\n const items = deps.readdirSync(dirPath, { withFileTypes: true });\n\n // Check for TypeScript files in current directory\n const hasDirectTsFiles = items.some(\n (item) => item.isFile() && (item.name.endsWith(\".ts\") || item.name.endsWith(\".tsx\")),\n );\n\n if (hasDirectTsFiles) return true;\n\n // Check subdirectories (limited depth to avoid performance issues)\n const subdirs = items.filter((item) => item.isDirectory() && !item.name.startsWith(\".\"));\n for (const subdir of subdirs.slice(0, 5)) {\n // Limit to first 5 subdirs\n if (hasTypeScriptFilesRecursive(join(dirPath, subdir.name), maxDepth - 1, deps)) {\n return true;\n }\n }\n\n return false;\n } catch {\n return false;\n }\n}\n\n/**\n * Get top-level directories containing TypeScript files.\n *\n * @param config - TypeScript configuration\n * @param deps - Injectable dependencies\n * @returns Array of directory names\n */\nexport function getTopLevelDirectoriesWithTypeScript(\n config: TypeScriptConfig,\n deps: ScopeDeps = defaultScopeDeps,\n): string[] {\n const allTopLevelItems = deps.readdirSync(\".\", { withFileTypes: true });\n const directories = new Set<string>();\n\n // Find all top-level directories\n const topLevelDirs = allTopLevelItems\n .filter((item) => item.isDirectory())\n .map((item) => item.name)\n .filter((name) => !name.startsWith(\".\"));\n\n // Check if each directory should be included based on tsconfig include/exclude patterns\n for (const dir of topLevelDirs) {\n // Check if directory is explicitly excluded\n const isExcluded = config.exclude?.some((pattern) => {\n // Handle patterns like \"specs/**/*\", \"docs/**/*\"\n if (pattern.includes(\"/**\")) {\n const dirPattern = pattern.split(\"/**\")[0];\n return dirPattern === dir;\n }\n // Handle exact matches and directory patterns\n return pattern === dir || pattern.startsWith(dir + \"/\") || pattern === dir + \"/**\";\n });\n\n if (!isExcluded) {\n // Check if directory has TypeScript files\n try {\n const hasTypeScriptFiles = hasTypeScriptFilesRecursive(dir, 2, deps);\n if (hasTypeScriptFiles) {\n directories.add(dir);\n }\n } catch {\n // Directory access error, skip\n continue;\n }\n }\n }\n\n // Also add explicitly mentioned directories from include patterns\n if (config.include) {\n for (const pattern of config.include) {\n // Extract directory from patterns like \"scripts/**/*.ts\", \"tests/**/*.tsx\"\n if (pattern.includes(\"/\")) {\n const topLevelDir = pattern.split(\"/\")[0];\n if (topLevelDir && !topLevelDir.includes(\"*\") && !topLevelDir.startsWith(\".\")) {\n directories.add(topLevelDir);\n }\n }\n }\n }\n\n return Array.from(directories).sort();\n}\n\n/**\n * Get validation directories based on tsconfig files.\n *\n * @param scope - Validation scope\n * @param deps - Injectable dependencies\n * @returns Array of directory names to validate\n */\nexport function getValidationDirectories(\n scope: ValidationScope,\n deps: ScopeDeps = defaultScopeDeps,\n): string[] {\n // Get TypeScript configuration for the specified mode\n const config = resolveTypeScriptConfig(scope, deps);\n\n // Get directories that contain TypeScript files and respect tsconfig exclude patterns\n const configDirectories = getTopLevelDirectoriesWithTypeScript(config, deps);\n\n // Only include directories that actually exist\n const existingDirectories = configDirectories.filter((dir) => deps.existsSync(dir));\n\n return existingDirectories;\n}\n\n/**\n * Get authoritative validation scope configuration.\n *\n * This is the main entry point for scope resolution. Returns a ScopeConfig\n * object that can be used to configure validation tools.\n *\n * @param scope - Validation scope\n * @param deps - Injectable dependencies\n * @returns Scope configuration\n *\n * @example\n * ```typescript\n * const scopeConfig = getTypeScriptScope(\"full\");\n * console.log(scopeConfig.directories); // [\"src\", \"tests\", \"scripts\"]\n * ```\n */\nexport function getTypeScriptScope(\n scope: ValidationScope,\n deps: ScopeDeps = defaultScopeDeps,\n): ScopeConfig {\n // Use validation-focused directory selection\n const directories = getValidationDirectories(scope, deps);\n\n // Read TypeScript config for patterns\n const config = resolveTypeScriptConfig(scope, deps);\n\n return {\n directories,\n filePatterns: config.include ?? [],\n excludePatterns: config.exclude ?? [],\n };\n}\n","/**\n * Tool discovery for validation infrastructure.\n *\n * Discovers validation tools (eslint, tsc, madge, etc.) using a three-tier\n * priority system: bundled → project → global.\n *\n * @module validation/discovery/tool-finder\n */\n\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\n\nimport { TOOL_DISCOVERY, type ToolSource } from \"./constants\";\n\n/**\n * Information about a found tool.\n */\nexport interface ToolLocation {\n /** The tool name */\n tool: string;\n /** Absolute path to the tool executable or package */\n path: string;\n /** Where the tool was found */\n source: ToolSource;\n}\n\n/**\n * Information about a tool that was not found.\n */\nexport interface ToolNotFound {\n /** The tool name that was searched for */\n tool: string;\n /** Human-readable reason why the tool was not found */\n reason: string;\n}\n\n/**\n * Result of tool discovery - either found with location or not found with reason.\n */\nexport type ToolDiscoveryResult =\n | { found: true; location: ToolLocation }\n | { found: false; notFound: ToolNotFound };\n\n/**\n * Dependencies for tool discovery.\n * Enables testing without mocking by accepting controlled implementations.\n */\nexport interface ToolDiscoveryDeps {\n /**\n * Resolve a module path, returns the resolved path or null if not found.\n * @param modulePath - The module path to resolve (e.g., \"eslint/package.json\")\n */\n resolveModule: (modulePath: string) => string | null;\n\n /**\n * Check if a file exists at the given path.\n * @param filePath - The path to check\n */\n existsSync: (filePath: string) => boolean;\n\n /**\n * Find an executable in the system PATH.\n * @param tool - The tool name to find\n * @returns The absolute path to the tool, or null if not found\n */\n whichSync: (tool: string) => string | null;\n}\n\n/**\n * Create a require function for resolving modules.\n * Uses import.meta.url to create a require that resolves from this package.\n */\nconst require = createRequire(import.meta.url);\n\n/**\n * Default production dependencies for tool discovery.\n */\nexport const defaultToolDiscoveryDeps: ToolDiscoveryDeps = {\n resolveModule: (modulePath: string): string | null => {\n try {\n return require.resolve(modulePath);\n } catch {\n return null;\n }\n },\n\n existsSync: fs.existsSync,\n\n whichSync: (tool: string): string | null => {\n try {\n const result = execSync(`which ${tool}`, {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n return result.trim() || null;\n } catch {\n return null;\n }\n },\n};\n\n/**\n * Options for tool discovery.\n */\nexport interface DiscoverToolOptions {\n /**\n * Project root directory for checking project-local node_modules.\n * Defaults to current working directory.\n */\n projectRoot?: string;\n\n /**\n * Dependencies for tool discovery.\n * Defaults to production dependencies.\n */\n deps?: ToolDiscoveryDeps;\n}\n\n/**\n * Discover a validation tool using three-tier priority.\n *\n * Discovery order:\n * 1. **Bundled**: Check if the tool is bundled with spx-cli via require.resolve\n * 2. **Project**: Check project's node_modules/.bin directory\n * 3. **Global**: Check system PATH via `which` command\n *\n * @param tool - The tool name to discover (e.g., \"eslint\", \"typescript\", \"madge\")\n * @param options - Discovery options including projectRoot and dependencies\n * @returns Discovery result with found location or not found reason\n *\n * @example\n * ```typescript\n * const result = await discoverTool(\"eslint\");\n * if (result.found) {\n * console.log(`Found ${result.location.tool} at ${result.location.path}`);\n * console.log(`Source: ${result.location.source}`);\n * } else {\n * console.log(`Not found: ${result.notFound.reason}`);\n * }\n * ```\n */\nexport async function discoverTool(\n tool: string,\n options: DiscoverToolOptions = {},\n): Promise<ToolDiscoveryResult> {\n const { projectRoot = process.cwd(), deps = defaultToolDiscoveryDeps } = options;\n\n // Tier 1: Check if bundled with spx-cli\n const bundledPath = deps.resolveModule(`${tool}/package.json`);\n if (bundledPath) {\n return {\n found: true,\n location: {\n tool,\n path: path.dirname(bundledPath),\n source: TOOL_DISCOVERY.SOURCES.BUNDLED,\n },\n };\n }\n\n // Tier 2: Check project's node_modules/.bin\n const projectBinPath = path.join(projectRoot, \"node_modules\", \".bin\", tool);\n if (deps.existsSync(projectBinPath)) {\n return {\n found: true,\n location: {\n tool,\n path: projectBinPath,\n source: TOOL_DISCOVERY.SOURCES.PROJECT,\n },\n };\n }\n\n // Tier 3: Check system PATH\n const globalPath = deps.whichSync(tool);\n if (globalPath) {\n return {\n found: true,\n location: {\n tool,\n path: globalPath,\n source: TOOL_DISCOVERY.SOURCES.GLOBAL,\n },\n };\n }\n\n // Not found anywhere\n return {\n found: false,\n notFound: {\n tool,\n reason: TOOL_DISCOVERY.MESSAGES.NOT_FOUND_REASON(tool),\n },\n };\n}\n\n/**\n * Format a graceful skip message for when a tool is not found.\n *\n * @param stepName - The name of the validation step being skipped\n * @param result - The tool discovery result\n * @returns Formatted skip message, or empty string if tool was found\n *\n * @example\n * ```typescript\n * const result = await discoverTool(\"madge\");\n * const message = formatSkipMessage(\"Circular dependency check\", result);\n * // \"⏭ Skipping Circular dependency check (madge not available)\"\n * ```\n */\nexport function formatSkipMessage(\n stepName: string,\n result: ToolDiscoveryResult,\n): string {\n if (result.found) {\n return \"\";\n }\n return TOOL_DISCOVERY.MESSAGES.SKIP_FORMAT(stepName, result.notFound.tool);\n}\n","/**\n * Constants for tool discovery.\n * @module validation/discovery/constants\n */\n\n/**\n * Tool discovery constants.\n * Using constants ensures DRY principle and makes tests verify behavior via constants.\n */\nexport const TOOL_DISCOVERY = {\n /** Tool source identifiers */\n SOURCES: {\n /** Tool bundled with spx-cli */\n BUNDLED: \"bundled\",\n /** Tool in project's node_modules */\n PROJECT: \"project\",\n /** Tool in system PATH */\n GLOBAL: \"global\",\n } as const,\n\n /** Message templates */\n MESSAGES: {\n /** Prefix for skip messages */\n SKIP_PREFIX: \"\\u23ED\", // ⏭ emoji\n /**\n * Format not found reason message.\n * @param tool - The tool name that was not found\n */\n NOT_FOUND_REASON: (tool: string): string =>\n `${tool} not found in bundled deps, project node_modules, or system PATH`,\n /**\n * Format skip message for graceful degradation.\n * @param step - The validation step name\n * @param tool - The tool that was not found\n */\n SKIP_FORMAT: (step: string, tool: string): string =>\n `${TOOL_DISCOVERY.MESSAGES.SKIP_PREFIX} Skipping ${step} (${tool} not available)`,\n },\n} as const;\n\n/** Type for tool source */\nexport type ToolSource = (typeof TOOL_DISCOVERY.SOURCES)[keyof typeof TOOL_DISCOVERY.SOURCES];\n","/**\n * Language detection for validation infrastructure.\n *\n * Detects which programming languages a project uses based on configuration\n * file presence. Language-specific validation tools (ESLint, tsc, mypy) consult\n * detection results to determine whether to run.\n *\n * @module validation/discovery/language-finder\n */\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/**\n * Marker file for TypeScript projects, checked in the project root.\n */\nexport const TYPESCRIPT_MARKER = \"tsconfig.json\";\n\n/**\n * Marker file for Python projects, checked in the project root.\n */\nexport const PYTHON_MARKER = \"pyproject.toml\";\n\n/**\n * ESLint flat config file names, in priority order.\n *\n * ESLint 9+ uses flat config exclusively. When multiple config files exist in\n * the same directory, the highest-priority one wins.\n */\nexport const ESLINT_CONFIG_FILES = [\n \"eslint.config.ts\",\n \"eslint.config.js\",\n \"eslint.config.mjs\",\n \"eslint.config.cjs\",\n] as const;\n\n/**\n * Type of an ESLint config file name.\n */\nexport type EslintConfigFile = (typeof ESLINT_CONFIG_FILES)[number];\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\n/**\n * Result of TypeScript language detection.\n */\nexport interface TypeScriptDetection {\n /** Whether TypeScript is present in the project. */\n present: boolean;\n /** The ESLint flat config file name found, if any. Only set when `present` is true. */\n eslintConfigFile?: EslintConfigFile;\n}\n\n/**\n * Result of Python language detection.\n */\nexport interface PythonDetection {\n /** Whether Python is present in the project. */\n present: boolean;\n}\n\n/**\n * Result of full language detection.\n */\nexport interface LanguageDetection {\n typescript: TypeScriptDetection;\n python: PythonDetection;\n}\n\n/**\n * Dependencies for language detection.\n *\n * Enables type-safe dependency injection for testing without mocking.\n */\nexport interface LanguageDetectionDeps {\n /**\n * Check whether a file exists at the given absolute path.\n * @param filePath - Absolute path to check.\n */\n existsSync: (filePath: string) => boolean;\n}\n\n/**\n * Default production dependencies.\n */\nexport const defaultLanguageDetectionDeps: LanguageDetectionDeps = {\n existsSync: fs.existsSync,\n};\n\n// =============================================================================\n// DETECTION FUNCTIONS\n// =============================================================================\n\n/**\n * Detect whether a project uses TypeScript.\n *\n * TypeScript is present when `tsconfig.json` exists in the project root. When\n * present, the function also searches for an ESLint flat config file and\n * returns its name in priority order.\n *\n * @param projectRoot - Absolute path to the project root.\n * @param deps - Injectable filesystem dependencies.\n * @returns Detection result with presence flag and optional ESLint config path.\n */\nexport function detectTypeScript(\n projectRoot: string,\n deps: LanguageDetectionDeps = defaultLanguageDetectionDeps,\n): TypeScriptDetection {\n const present = deps.existsSync(path.join(projectRoot, TYPESCRIPT_MARKER));\n\n if (!present) {\n return { present: false };\n }\n\n const eslintConfigFile = ESLINT_CONFIG_FILES.find((configFile) =>\n deps.existsSync(path.join(projectRoot, configFile))\n );\n\n return eslintConfigFile === undefined\n ? { present: true }\n : { present: true, eslintConfigFile };\n}\n\n/**\n * Detect whether a project uses Python.\n *\n * Python is present when `pyproject.toml` exists in the project root.\n *\n * @param projectRoot - Absolute path to the project root.\n * @param deps - Injectable filesystem dependencies.\n * @returns Detection result with presence flag.\n */\nexport function detectPython(\n projectRoot: string,\n deps: LanguageDetectionDeps = defaultLanguageDetectionDeps,\n): PythonDetection {\n const present = deps.existsSync(path.join(projectRoot, PYTHON_MARKER));\n return { present };\n}\n\n/**\n * Detect all supported languages in a project.\n *\n * @param projectRoot - Absolute path to the project root.\n * @param deps - Injectable filesystem dependencies.\n * @returns Detection result for every supported language.\n */\nexport function detectLanguages(\n projectRoot: string,\n deps: LanguageDetectionDeps = defaultLanguageDetectionDeps,\n): LanguageDetection {\n return {\n typescript: detectTypeScript(projectRoot, deps),\n python: detectPython(projectRoot, deps),\n };\n}\n","/**\n * Circular dependency validation step.\n *\n * Uses madge to detect circular imports in the codebase.\n *\n * @module validation/steps/circular\n */\n\nimport madge from \"madge\";\n\nimport { TSCONFIG_FILES } from \"../config/scope\";\nimport type { CircularDependencyResult, ScopeConfig, ValidationScope } from \"../types\";\n\n// =============================================================================\n// DEPENDENCY INJECTION INTERFACES\n// =============================================================================\n\n/**\n * Dependencies for circular dependency validation.\n *\n * Enables dependency injection for testing.\n */\nexport interface CircularDeps {\n madge: typeof madge;\n}\n\n/**\n * Default production dependencies.\n */\nexport const defaultCircularDeps: CircularDeps = {\n madge,\n};\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate circular dependencies using TypeScript-derived scope.\n *\n * @param scope - Validation scope\n * @param typescriptScope - Scope configuration from tsconfig\n * @param deps - Injectable dependencies\n * @returns Result with success status and any circular dependencies found\n *\n * @example\n * ```typescript\n * const result = await validateCircularDependencies(\"full\", scopeConfig);\n * if (!result.success) {\n * console.error(\"Found circular dependencies:\", result.circularDependencies);\n * }\n * ```\n */\nexport async function validateCircularDependencies(\n scope: ValidationScope,\n typescriptScope: ScopeConfig,\n deps: CircularDeps = defaultCircularDeps,\n): Promise<CircularDependencyResult> {\n try {\n // Use TypeScript-derived directories for perfect scope alignment\n const analyzeDirectories = typescriptScope.directories;\n\n if (analyzeDirectories.length === 0) {\n return { success: true };\n }\n\n // Use the appropriate TypeScript config based on scope\n const tsConfigFile = TSCONFIG_FILES[scope];\n\n // Convert tsconfig exclude patterns to madge excludeRegExp\n const excludeRegExps = typescriptScope.excludePatterns.map((pattern) => {\n // Remove trailing /**/* or /* for cleaner matching\n const cleanPattern = pattern.replace(/\\/\\*\\*?\\/\\*$/, \"\");\n // Escape regex special chars and create regex\n const escaped = cleanPattern.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n return new RegExp(escaped);\n });\n\n const result = await deps.madge(analyzeDirectories, {\n fileExtensions: [\"ts\", \"tsx\"],\n tsConfig: tsConfigFile,\n excludeRegExp: excludeRegExps,\n });\n\n const circular = result.circular();\n\n if (circular.length === 0) {\n return { success: true };\n } else {\n return {\n success: false,\n error: `Found ${circular.length} circular dependency cycle(s)`,\n circularDependencies: circular,\n };\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { success: false, error: errorMessage };\n }\n}\n","/**\n * Circular dependency check command.\n *\n * Runs madge to detect circular dependencies.\n */\nimport { getTypeScriptScope } from \"@/validation/config/scope\";\nimport { detectTypeScript, discoverTool, formatSkipMessage } from \"@/validation/discovery/index\";\nimport { validateCircularDependencies } from \"@/validation/steps/circular\";\nimport type { CircularCommandOptions, ValidationCommandResult } from \"./types\";\n\nconst TYPESCRIPT_ABSENT_MESSAGE = \"⏭ Skipping Circular dependencies (TypeScript not detected in project)\";\nexport const CIRCULAR_DEPENDENCY_OUTPUT = {\n FOUND: \"Circular dependencies found\",\n} as const;\n\n/**\n * Check for circular dependencies.\n *\n * Gates madge execution on TypeScript language detection: madge walks the\n * TypeScript import graph and has nothing to examine in non-TypeScript\n * projects.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function circularCommand(options: CircularCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, quiet } = options;\n const startTime = Date.now();\n\n // Gate 1: language detection. No TypeScript = skip cleanly.\n const tsDetection = detectTypeScript(cwd);\n if (!tsDetection.present) {\n return {\n exitCode: 0,\n output: quiet ? \"\" : TYPESCRIPT_ABSENT_MESSAGE,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Gate 2: tool discovery.\n const toolResult = await discoverTool(\"madge\", { projectRoot: cwd });\n if (!toolResult.found) {\n const skipMessage = formatSkipMessage(\"circular dependency check\", toolResult);\n return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };\n }\n\n // Get scope configuration from tsconfig (circular always uses full scope)\n const scopeConfig = getTypeScriptScope(\"full\");\n\n // Run circular dependency validation\n const result = await validateCircularDependencies(\"full\", scopeConfig);\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : `Circular dependencies: ✓ None found`;\n return { exitCode: 0, output, durationMs };\n } else {\n // Format circular dependency output\n let output = result.error ?? CIRCULAR_DEPENDENCY_OUTPUT.FOUND;\n if (result.circularDependencies && result.circularDependencies.length > 0) {\n const cycles = result.circularDependencies\n .map((cycle) => ` ${cycle.join(\" → \")}`)\n .join(\"\\n\");\n output = `${CIRCULAR_DEPENDENCY_OUTPUT.FOUND}:\\n${cycles}`;\n }\n return { exitCode: 1, output, durationMs };\n }\n}\n","/**\n * Output formatting functions for validation commands.\n *\n * Pure functions that format validation results for CLI display.\n * These functions have no side effects and are fully testable.\n */\n\n/** Threshold in milliseconds for switching from ms to seconds display */\nexport const DURATION_THRESHOLD_MS = 1000;\n\n/** Symbols used in validation output */\nexport const VALIDATION_SYMBOLS = {\n SUCCESS: \"✓\",\n FAILURE: \"✗\",\n} as const;\n\nexport const VALIDATION_SUMMARY_STATUS = {\n PASSED: \"passed\",\n FAILED: \"failed\",\n} as const;\n\n/**\n * Format a duration in milliseconds for display.\n *\n * @param ms - Duration in milliseconds\n * @returns Formatted string (e.g., \"500ms\" or \"1.5s\")\n */\nexport function formatDuration(ms: number): string {\n if (ms < DURATION_THRESHOLD_MS) {\n return `${ms}ms`;\n }\n const seconds = ms / 1000;\n return `${seconds.toFixed(1)}s`;\n}\n\n/** Options for formatting a validation step output */\nexport interface FormatStepOptions {\n /** Current step number (1-indexed) */\n stepNumber: number;\n /** Total number of steps */\n totalSteps: number;\n /** Name of the validation step */\n name: string;\n /** Result message (e.g., \"✓ No errors found\") */\n result: string;\n /** Duration in milliseconds */\n durationMs: number;\n}\n\n/**\n * Format a validation step result for display.\n *\n * @param options - Step formatting options\n * @returns Formatted string (e.g., \"[1/4] ESLint: ✓ No errors found (0.8s)\")\n */\nexport function formatStepOutput(options: FormatStepOptions): string {\n const { stepNumber, totalSteps, name, result, durationMs } = options;\n const duration = formatDuration(durationMs);\n return `[${stepNumber}/${totalSteps}] ${name}: ${result} (${duration})`;\n}\n\n/** Options for formatting the validation summary */\nexport interface FormatSummaryOptions {\n /** Whether all required validations passed */\n success: boolean;\n /** Total duration in milliseconds */\n totalDurationMs: number;\n}\n\n/**\n * Format the final validation summary.\n *\n * @param options - Summary formatting options\n * @returns Formatted string (e.g., \"✓ Validation passed (2.7s total)\")\n */\nexport function formatSummary(options: FormatSummaryOptions): string {\n const { success, totalDurationMs } = options;\n const symbol = success ? VALIDATION_SYMBOLS.SUCCESS : VALIDATION_SYMBOLS.FAILURE;\n const status = success ? VALIDATION_SUMMARY_STATUS.PASSED : VALIDATION_SUMMARY_STATUS.FAILED;\n const duration = formatDuration(totalDurationMs);\n return `${symbol} Validation ${status} (${duration} total)`;\n}\n","/**\n * ESLint validation step.\n *\n * Validates code against ESLint rules with automatic TypeScript scope alignment.\n *\n * @module validation/steps/eslint\n */\n\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { lifecycleProcessRunner } from \"@/lib/process-lifecycle\";\nimport { validateLintPolicy } from \"@/validation/lint-policy\";\nimport type { ExecutionMode, ProcessRunner, ValidationContext } from \"../types\";\nimport { EXECUTION_MODES, VALIDATION_SCOPES } from \"../types\";\n\n// =============================================================================\n// DEFAULT DEPENDENCIES\n// =============================================================================\n\n/**\n * Default production process runner for ESLint.\n */\nexport const defaultEslintProcessRunner: ProcessRunner = lifecycleProcessRunner;\n\n// =============================================================================\n// PURE ARGUMENT BUILDER\n// =============================================================================\n\n/**\n * Default ESLint flat config file name, used when the caller does not supply\n * one. Callers should prefer passing the config file reported by language\n * detection.\n */\nexport const DEFAULT_ESLINT_CONFIG_FILE = \"eslint.config.ts\";\nexport const ESLINT_COMMAND_TOKENS = {\n COMMAND: \"eslint\",\n CONFIG_FLAG: \"--config\",\n CURRENT_DIRECTORY: \".\",\n FILE_SEPARATOR: \"--\",\n FIX_FLAG: \"--fix\",\n} as const;\n\n/**\n * Build ESLint CLI arguments based on validation context.\n *\n * Pure function for testability - can be verified at Level 1.\n *\n * @param context - Context for building arguments\n * @returns Array of ESLint CLI arguments\n *\n * @example\n * ```typescript\n * const args = buildEslintArgs({\n * validatedFiles: [\"src/index.ts\"],\n * mode: \"write\",\n * configFile: \"eslint.config.ts\",\n * });\n * // Returns: [\"eslint\", \"--config\", \"eslint.config.ts\", \"--\", \"src/index.ts\"]\n * ```\n */\nexport function buildEslintArgs(context: {\n validatedFiles?: string[];\n mode?: ExecutionMode;\n configFile?: string;\n}): string[] {\n const { validatedFiles, mode, configFile = DEFAULT_ESLINT_CONFIG_FILE } = context;\n const fixArg = mode === EXECUTION_MODES.WRITE ? [ESLINT_COMMAND_TOKENS.FIX_FLAG] : [];\n\n if (validatedFiles && validatedFiles.length > 0) {\n return [\n ESLINT_COMMAND_TOKENS.COMMAND,\n ESLINT_COMMAND_TOKENS.CONFIG_FLAG,\n configFile,\n ...fixArg,\n ESLINT_COMMAND_TOKENS.FILE_SEPARATOR,\n ...validatedFiles,\n ];\n }\n return [\n ESLINT_COMMAND_TOKENS.COMMAND,\n ESLINT_COMMAND_TOKENS.CURRENT_DIRECTORY,\n ESLINT_COMMAND_TOKENS.CONFIG_FLAG,\n configFile,\n ...fixArg,\n ];\n}\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate ESLint compliance using automatic TypeScript scope alignment.\n *\n * @param context - Validation context\n * @param runner - Injectable process runner\n * @returns Promise resolving to validation result\n *\n * @example\n * ```typescript\n * const result = await validateESLint(context);\n * if (!result.success) {\n * console.error(\"ESLint failed:\", result.error);\n * }\n * ```\n */\nexport async function validateESLint(\n context: ValidationContext,\n runner: ProcessRunner = defaultEslintProcessRunner,\n): Promise<{\n success: boolean;\n error?: string;\n}> {\n const { projectRoot, scope, validatedFiles, mode, eslintConfigFile } = context;\n const lintPolicy = validateLintPolicy(projectRoot);\n\n if (!lintPolicy.ok) {\n return { success: false, error: lintPolicy.error };\n }\n\n return new Promise((resolve) => {\n if (!validatedFiles || validatedFiles.length === 0) {\n if (scope === VALIDATION_SCOPES.PRODUCTION) {\n process.env.ESLINT_PRODUCTION_ONLY = \"1\";\n } else {\n delete process.env.ESLINT_PRODUCTION_ONLY;\n }\n }\n\n const eslintArgs = buildEslintArgs({\n validatedFiles,\n mode,\n configFile: eslintConfigFile,\n });\n\n const localBin = join(projectRoot, \"node_modules\", \".bin\", \"eslint\");\n const binary = existsSync(localBin) ? localBin : \"npx\";\n const spawnArgs = binary === \"npx\" ? eslintArgs : eslintArgs.slice(1);\n const eslintProcess = runner.spawn(binary, spawnArgs, {\n cwd: projectRoot,\n stdio: \"inherit\",\n });\n\n eslintProcess.on(\"close\", (code) => {\n if (code === 0) {\n resolve({ success: true });\n } else {\n resolve({ success: false, error: `ESLint exited with code ${code}` });\n }\n });\n\n eslintProcess.on(\"error\", (error) => {\n resolve({ success: false, error: error.message });\n });\n });\n}\n\n// =============================================================================\n// ENVIRONMENT CHECK\n// =============================================================================\n\n/**\n * Check if a validation type is enabled via environment variable.\n *\n * @param envVarKey - Validation key (TYPESCRIPT, ESLINT, KNIP)\n * @param defaults - Default enabled states\n * @returns True if the validation is enabled\n */\nexport function validationEnabled(\n envVarKey: string,\n defaults: Record<string, boolean> = {},\n): boolean {\n const envVar = `${envVarKey}_VALIDATION_ENABLED`;\n const explicitlyDisabled = process.env[envVar] === \"0\";\n const explicitlyEnabled = process.env[envVar] === \"1\";\n\n const defaultValue = defaults[envVarKey] ?? true;\n if (defaultValue) {\n return !explicitlyDisabled;\n }\n return explicitlyEnabled;\n}\n","/**\n * Conventional exit codes for CLI termination paths.\n *\n * The mapping follows POSIX convention: 128 + signal number for\n * signal-terminated processes, 0 for downstream-closed pipes (matches\n * `head`/`tee` behavior under `SIGPIPE`), 1 for genuine internal failures.\n *\n * @module lib/process-lifecycle/exit-codes\n */\n\nexport const SIGINT_EXIT_CODE = 130;\nexport const SIGTERM_EXIT_CODE = 143;\nexport const EPIPE_EXIT_CODE = 0;\nexport const UNCAUGHT_EXIT_CODE = 1;\n","/**\n * Lifecycle handler factory. Produces the four handler entry points that\n * fire on SIGINT, SIGTERM, EPIPE, and uncaught exceptions.\n *\n * Each handler is idempotent: a `cleanupOnce` flag plus per-child\n * `child.killed` checks ensure that repeated invocations kill each\n * registered child exactly once. This handles the race in which SIGINT\n * arrives mid-write to a closed pipe.\n *\n * @module lib/process-lifecycle/handlers\n */\n\nimport { EPIPE_EXIT_CODE, SIGINT_EXIT_CODE, SIGTERM_EXIT_CODE, UNCAUGHT_EXIT_CODE } from \"./exit-codes\";\nimport type { ChildHandle, LifecycleHandlerDeps, LifecycleHandlers } from \"./types\";\n\nexport const SIGINT_NAME: NodeJS.Signals = \"SIGINT\";\nexport const SIGTERM_NAME: NodeJS.Signals = \"SIGTERM\";\n\nexport function createHandlers(deps: LifecycleHandlerDeps): LifecycleHandlers {\n let cleanupOnce = false;\n\n function killEachChild(signal: NodeJS.Signals): void {\n deps.registry.forEach((child: ChildHandle) => {\n if (!child.killed) child.kill(signal);\n });\n }\n\n function exitOnce(code: number, killSignal?: NodeJS.Signals): void {\n if (cleanupOnce) {\n deps.exitController.exit(code);\n return;\n }\n cleanupOnce = true;\n if (killSignal !== undefined) killEachChild(killSignal);\n deps.exitController.exit(code);\n }\n\n return {\n onSigint(): void {\n exitOnce(SIGINT_EXIT_CODE, SIGINT_NAME);\n },\n onSigterm(): void {\n exitOnce(SIGTERM_EXIT_CODE, SIGTERM_NAME);\n },\n onEpipe(): void {\n exitOnce(EPIPE_EXIT_CODE, SIGTERM_NAME);\n },\n onUncaught(_error: unknown): void {\n exitOnce(UNCAUGHT_EXIT_CODE, SIGTERM_NAME);\n },\n };\n}\n","/**\n * CLI process-lifecycle installation. Wires real Node process events to the\n * lifecycle handlers and exposes the production `lifecycleProcessRunner`\n * that the validation steps consume.\n *\n * The module-scoped registry holds child handles; `installLifecycle()`\n * attaches handlers once. Calling `installLifecycle()` more than once is a\n * no-op so re-entry from accidental imports does not double-install.\n *\n * @module lib/process-lifecycle/install\n */\n\nimport { spawn } from \"node:child_process\";\n\nimport { createHandlers } from \"./handlers\";\nimport { createRegistry } from \"./registry\";\nimport { createLifecycleRunner } from \"./runner\";\nimport type { ChildRegistry, ExitController, LifecycleHandlers } from \"./types\";\n\nconst moduleRegistry: ChildRegistry = createRegistry();\nconst moduleExitController: ExitController = {\n exit(code: number): void {\n process.exit(code);\n },\n};\n\nlet installed = false;\n\nexport const lifecycleProcessRunner = createLifecycleRunner({\n registry: moduleRegistry,\n spawn,\n});\n\nexport const EPIPE_CODE = \"EPIPE\";\nexport const UNCAUGHT_EVENT_NAME = \"uncaughtException\";\nconst UNCAUGHT_PREFIX = \"Uncaught: \";\nconst NEWLINE = \"\\n\";\n\nfunction formatUncaught(error: unknown): string {\n if (error instanceof Error && error.stack !== undefined) {\n return UNCAUGHT_PREFIX + error.stack + NEWLINE;\n }\n return UNCAUGHT_PREFIX + String(error) + NEWLINE;\n}\n\nfunction logUncaughtToStderr(error: unknown): void {\n // Best-effort diagnostic write before the process exits. If stderr is\n // already closed, the write throws synchronously and we swallow it; the\n // exit path runs regardless so the operator at minimum sees a non-zero\n // exit code.\n try {\n process.stderr.write(formatUncaught(error));\n } catch {\n /* stderr unavailable; rely on exit code */\n }\n}\n\nexport function installLifecycle(): void {\n if (installed) return;\n installed = true;\n\n const handlers: LifecycleHandlers = createHandlers({\n registry: moduleRegistry,\n exitController: moduleExitController,\n });\n\n process.on(\"uncaughtException\", (error: unknown) => {\n logUncaughtToStderr(error);\n handlers.onUncaught(error);\n });\n process.on(\"unhandledRejection\", (reason: unknown) => {\n logUncaughtToStderr(reason);\n handlers.onUncaught(reason);\n });\n process.on(\"SIGTERM\", () => handlers.onSigterm());\n process.on(\"SIGINT\", () => handlers.onSigint());\n\n process.stdout.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (error.code === EPIPE_CODE) {\n handlers.onEpipe();\n return;\n }\n handlers.onUncaught(error);\n });\n process.stderr.on(\"error\", (error: NodeJS.ErrnoException) => {\n if (error.code === EPIPE_CODE) {\n handlers.onEpipe();\n return;\n }\n handlers.onUncaught(error);\n });\n}\n","/**\n * Child-process registry. Tracks asynchronously spawned children so that\n * lifecycle handlers can reach them when the parent receives a termination\n * signal.\n *\n * The registry is identity-based: callers pass the `ChildHandle` reference\n * returned by `spawn` to both `add` and `remove`.\n *\n * @module lib/process-lifecycle/registry\n */\n\nimport type { ChildHandle, ChildRegistry } from \"./types\";\n\nexport function createRegistry(): ChildRegistry {\n const tracked = new Set<ChildHandle>();\n\n return {\n add(child: ChildHandle): void {\n tracked.add(child);\n },\n remove(child: ChildHandle): void {\n tracked.delete(child);\n },\n forEach(fn: (child: ChildHandle) => void): void {\n for (const child of tracked) fn(child);\n },\n get size(): number {\n return tracked.size;\n },\n };\n}\n","/**\n * Lifecycle-aware process runner. Wraps a real `spawn` function so that\n * every child handle returned by `runner.spawn(...)` is registered in the\n * lifecycle registry and removed when the child exits.\n *\n * @module lib/process-lifecycle/runner\n */\n\nimport type { ProcessRunner } from \"@/validation/types\";\n\nimport type { ChildRegistry } from \"./types\";\n\nexport interface LifecycleRunnerDeps {\n readonly registry: ChildRegistry;\n readonly spawn: ProcessRunner[\"spawn\"];\n}\n\nexport type LifecycleSpawn = LifecycleRunnerDeps[\"spawn\"];\n\nexport function createLifecycleRunner(deps: LifecycleRunnerDeps): ProcessRunner {\n return {\n spawn(command, args, options) {\n const child = deps.spawn(command, args, options);\n deps.registry.add(child);\n child.on(\"exit\", () => deps.registry.remove(child));\n return child;\n },\n };\n}\n","import { execFileSync } from \"node:child_process\";\nimport { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { withoutGitEnvironment } from \"@/git/environment\";\nimport { LINT_POLICY_BASE_REFS, LINT_POLICY_MANIFESTS, parseLintPolicyManifest } from \"./lint-policy-constants\";\n\nconst LEGACY_SPEC_SUFFIX_NODE_MANIFEST_FILE = LINT_POLICY_MANIFESTS.LEGACY_SPEC_SUFFIX_NODES.file;\nconst LEGACY_SPEC_SUFFIX_NODE_MANIFEST_KEY = LINT_POLICY_MANIFESTS.LEGACY_SPEC_SUFFIX_NODES.key;\nconst TEST_LINT_DEBT_NODE_MANIFEST_FILE = LINT_POLICY_MANIFESTS.TEST_LINT_DEBT_NODES.file;\nconst TEST_LINT_DEBT_NODE_MANIFEST_KEY = LINT_POLICY_MANIFESTS.TEST_LINT_DEBT_NODES.key;\nconst TEST_OWNED_CONSTANT_DEBT_NODE_MANIFEST_FILE = LINT_POLICY_MANIFESTS.TEST_OWNED_CONSTANT_DEBT_NODES.file;\nconst TEST_OWNED_CONSTANT_DEBT_NODE_MANIFEST_KEY = LINT_POLICY_MANIFESTS.TEST_OWNED_CONSTANT_DEBT_NODES.key;\nconst SPEC_TREE_ROOT = \"spx\";\nconst SPEC_TREE_NODE_SUFFIX_PATTERN = /\\.(enabler|outcome|capability|feature|story)$/;\nconst LEGACY_SPEC_NODE_SUFFIX_PATTERN = /\\.(capability|feature|story)$/;\nconst BASE_BRANCH_REFS = [LINT_POLICY_BASE_REFS.REMOTE_MAIN, LINT_POLICY_BASE_REFS.LOCAL_MAIN] as const;\n\nexport type LintPolicyResult =\n | { readonly ok: true }\n | { readonly ok: false; readonly error: string };\n\nfunction readManifest(projectRoot: string, file: string, key: string): string[] {\n return parseLintPolicyManifest(\n readFileSync(join(projectRoot, file), \"utf-8\"),\n file,\n key,\n );\n}\n\nfunction manifestExists(projectRoot: string, file: string): boolean {\n return existsSync(join(projectRoot, file));\n}\n\nfunction listLegacySpecNodePaths(projectRoot: string): string[] {\n const legacySpecNodePaths: string[] = [];\n\n function visit(relativeDirectory: string): void {\n const absoluteDirectory = join(projectRoot, relativeDirectory);\n for (const entry of readdirSync(absoluteDirectory, { withFileTypes: true })) {\n if (!entry.isDirectory()) {\n continue;\n }\n\n const childPath = `${relativeDirectory}/${entry.name}`;\n\n if (LEGACY_SPEC_NODE_SUFFIX_PATTERN.test(entry.name)) {\n legacySpecNodePaths.push(childPath);\n }\n\n visit(childPath);\n }\n }\n\n const specTreeRootPath = join(projectRoot, SPEC_TREE_ROOT);\n if (!existsSync(specTreeRootPath)) {\n return [];\n }\n\n visit(SPEC_TREE_ROOT);\n return legacySpecNodePaths.sort();\n}\n\nfunction assertManifestEntries(\n projectRoot: string,\n file: string,\n entries: string[],\n suffixPattern: RegExp,\n suffixDescription: string,\n): void {\n const duplicates = entries.filter((entry, index) => entries.indexOf(entry) !== index);\n\n if (duplicates.length > 0) {\n throw new Error(\n `${file} contains duplicate entries: ${duplicates.join(\", \")}`,\n );\n }\n\n for (const entry of entries) {\n if (entry !== entry.trim()) {\n throw new Error(`${file} entry has surrounding whitespace: ${entry}`);\n }\n\n if (!entry.startsWith(`${SPEC_TREE_ROOT}/`)) {\n throw new Error(`${file} entry must be under ${SPEC_TREE_ROOT}/: ${entry}`);\n }\n\n if (entry.includes(\"..\")) {\n throw new Error(`${file} entry must not contain '..': ${entry}`);\n }\n\n if (!suffixPattern.test(entry)) {\n throw new Error(`${file} entry must ${suffixDescription}: ${entry}`);\n }\n\n const absoluteEntry = join(projectRoot, entry);\n if (!existsSync(absoluteEntry) || !statSync(absoluteEntry).isDirectory()) {\n throw new Error(`${file} entry does not exist as a directory: ${entry}`);\n }\n }\n}\n\nfunction readBaselineManifest(projectRoot: string, file: string, key: string): string[] | undefined {\n const baselineRef = readBaselineRef(projectRoot);\n if (baselineRef === undefined) {\n return undefined;\n }\n\n let content: string;\n try {\n content = execFileSync(\"git\", [\"show\", `${baselineRef}:${file}`], {\n cwd: projectRoot,\n encoding: \"utf-8\",\n env: withoutGitEnvironment(process.env),\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n } catch {\n return undefined;\n }\n\n return parseLintPolicyManifest(\n content,\n `${baselineRef}:${file}`,\n key,\n );\n}\n\nfunction readBaselineRef(projectRoot: string): string | undefined {\n const mergeCommitFirstParent = readMergeCommitFirstParent(projectRoot);\n if (mergeCommitFirstParent !== undefined) {\n return mergeCommitFirstParent;\n }\n\n for (const baseBranchRef of BASE_BRANCH_REFS) {\n const mergeBase = readMergeBase(projectRoot, baseBranchRef);\n if (mergeBase !== undefined) {\n return mergeBase;\n }\n }\n\n return undefined;\n}\n\nfunction readMergeCommitFirstParent(projectRoot: string): string | undefined {\n const secondParent = readGitRef(projectRoot, [\"rev-parse\", \"--verify\", \"HEAD^2\"]);\n if (secondParent === undefined) {\n return undefined;\n }\n return readGitRef(projectRoot, [\"rev-parse\", \"--verify\", \"HEAD^1\"]);\n}\n\nfunction readMergeBase(projectRoot: string, baseBranchRef: string): string | undefined {\n return readGitRef(projectRoot, [\"merge-base\", \"HEAD\", baseBranchRef]);\n}\n\nfunction readGitRef(projectRoot: string, args: readonly string[]): string | undefined {\n try {\n const output = execFileSync(\"git\", [...args], {\n cwd: projectRoot,\n encoding: \"utf-8\",\n env: withoutGitEnvironment(process.env),\n stdio: [\"ignore\", \"pipe\", \"ignore\"],\n });\n return output.trim() || undefined;\n } catch {\n return undefined;\n }\n}\n\nfunction assertManifestDoesNotGrow(\n projectRoot: string,\n file: string,\n key: string,\n entries: string[],\n): void {\n const baselineEntries = readBaselineManifest(projectRoot, file, key);\n\n if (baselineEntries === undefined) {\n return;\n }\n\n const baselineEntrySet = new Set(baselineEntries);\n const additions = entries.filter((entry) => !baselineEntrySet.has(entry));\n\n if (additions.length > 0) {\n throw new Error(\n `${file} is shrink-only. Remove the listed debt instead of adding entries: ${additions.join(\", \")}`,\n );\n }\n}\n\nfunction validateLegacySpecSuffixNodeManifest(projectRoot: string, entries: string[]): void {\n assertManifestEntries(\n projectRoot,\n LEGACY_SPEC_SUFFIX_NODE_MANIFEST_FILE,\n entries,\n LEGACY_SPEC_NODE_SUFFIX_PATTERN,\n \"end in .capability, .feature, or .story\",\n );\n assertManifestDoesNotGrow(\n projectRoot,\n LEGACY_SPEC_SUFFIX_NODE_MANIFEST_FILE,\n LEGACY_SPEC_SUFFIX_NODE_MANIFEST_KEY,\n entries,\n );\n\n const manifestEntrySet = new Set(entries);\n const legacySpecNodePaths = listLegacySpecNodePaths(projectRoot);\n const untrackedLegacySpecNodes = legacySpecNodePaths.filter((entry) => !manifestEntrySet.has(entry));\n\n if (untrackedLegacySpecNodes.length > 0) {\n throw new Error(\n `Legacy Spec Tree suffix paths must be listed in ${LEGACY_SPEC_SUFFIX_NODE_MANIFEST_FILE}: ${\n untrackedLegacySpecNodes.join(\", \")\n }`,\n );\n }\n}\n\nfunction validateTestLintDebtNodeManifest(projectRoot: string, entries: string[]): void {\n assertManifestEntries(\n projectRoot,\n TEST_LINT_DEBT_NODE_MANIFEST_FILE,\n entries,\n SPEC_TREE_NODE_SUFFIX_PATTERN,\n \"be a Spec Tree node path\",\n );\n assertManifestDoesNotGrow(\n projectRoot,\n TEST_LINT_DEBT_NODE_MANIFEST_FILE,\n TEST_LINT_DEBT_NODE_MANIFEST_KEY,\n entries,\n );\n}\n\nfunction validateTestOwnedConstantDebtNodeManifest(projectRoot: string, entries: string[]): void {\n assertManifestEntries(\n projectRoot,\n TEST_OWNED_CONSTANT_DEBT_NODE_MANIFEST_FILE,\n entries,\n SPEC_TREE_NODE_SUFFIX_PATTERN,\n \"be a Spec Tree node path\",\n );\n assertManifestDoesNotGrow(\n projectRoot,\n TEST_OWNED_CONSTANT_DEBT_NODE_MANIFEST_FILE,\n TEST_OWNED_CONSTANT_DEBT_NODE_MANIFEST_KEY,\n entries,\n );\n}\n\nexport function validateLintPolicy(projectRoot: string): LintPolicyResult {\n try {\n const manifestExistence = [\n manifestExists(projectRoot, LEGACY_SPEC_SUFFIX_NODE_MANIFEST_FILE),\n manifestExists(projectRoot, TEST_LINT_DEBT_NODE_MANIFEST_FILE),\n manifestExists(projectRoot, TEST_OWNED_CONSTANT_DEBT_NODE_MANIFEST_FILE),\n ];\n if (manifestExistence.every((exists) => !exists)) {\n return { ok: true };\n }\n if (!manifestExistence.every(Boolean)) {\n return {\n ok: false,\n error: \"lint policy manifests must be present together\",\n };\n }\n\n validateLegacySpecSuffixNodeManifest(\n projectRoot,\n readManifest(projectRoot, LEGACY_SPEC_SUFFIX_NODE_MANIFEST_FILE, LEGACY_SPEC_SUFFIX_NODE_MANIFEST_KEY),\n );\n validateTestLintDebtNodeManifest(\n projectRoot,\n readManifest(projectRoot, TEST_LINT_DEBT_NODE_MANIFEST_FILE, TEST_LINT_DEBT_NODE_MANIFEST_KEY),\n );\n validateTestOwnedConstantDebtNodeManifest(\n projectRoot,\n readManifest(\n projectRoot,\n TEST_OWNED_CONSTANT_DEBT_NODE_MANIFEST_FILE,\n TEST_OWNED_CONSTANT_DEBT_NODE_MANIFEST_KEY,\n ),\n );\n return { ok: true };\n } catch (error) {\n return { ok: false, error: error instanceof Error ? error.message : String(error) };\n }\n}\n","import * as JSONC from \"jsonc-parser\";\n\nexport const LINT_POLICY_MANIFESTS = {\n LEGACY_SPEC_SUFFIX_NODES: {\n file: \"eslint.legacy-spec-suffix-nodes.json\",\n key: \"legacySpecSuffixNodes\",\n },\n TEST_LINT_DEBT_NODES: {\n file: \"eslint.test-lint-debt-nodes.json\",\n key: \"testLintDebtNodes\",\n },\n TEST_OWNED_CONSTANT_DEBT_NODES: {\n file: \"eslint.test-owned-constant-debt-nodes.json\",\n key: \"testOwnedConstantDebtNodes\",\n },\n} as const;\n\nexport const LINT_POLICY_BASE_REFS = {\n REMOTE_MAIN: \"origin/main\",\n LOCAL_MAIN: \"main\",\n} as const;\n\ntype JsonObject = Record<string, unknown>;\n\nfunction isJsonObject(value: unknown): value is JsonObject {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function parseLintPolicyManifest(content: string, source: string, key: string): string[] {\n const parsed = JSONC.parse(content) as unknown;\n\n if (!isJsonObject(parsed)) {\n throw new Error(`${source} must contain a JSON object`);\n }\n\n const entries = parsed[key];\n\n if (!Array.isArray(entries)) {\n throw new Error(`${source} must contain a ${key} array`);\n }\n\n const invalidEntries = entries.filter((entry) => typeof entry !== \"string\");\n\n if (invalidEntries.length > 0) {\n throw new Error(`${source} ${key} entries must be strings`);\n }\n\n return entries as string[];\n}\n","/**\n * Shared types for the validation module.\n *\n * These types define the contracts for validation steps and their dependencies,\n * enabling dependency injection for testability.\n *\n * @module validation/types\n */\n\nimport type { ChildProcess, SpawnOptions } from \"node:child_process\";\n\n// =============================================================================\n// DEPENDENCY INJECTION INTERFACES\n// =============================================================================\n\n/**\n * Interface for subprocess execution.\n *\n * Enables dependency injection for testing - production code uses real spawn,\n * tests can provide controlled implementations.\n *\n * @example\n * ```typescript\n * // Production usage\n * const runner: ProcessRunner = { spawn };\n *\n * // Test usage with controlled implementation\n * const testRunner: ProcessRunner = {\n * spawn: (cmd, args, opts) => createMockProcess({ exitCode: 0 }),\n * };\n * ```\n */\nexport interface ProcessRunner {\n spawn(command: string, args: readonly string[], options?: SpawnOptions): ChildProcess;\n}\n\n// =============================================================================\n// VALIDATION SCOPE\n// =============================================================================\n\n/**\n * Validation scope constants.\n *\n * @example\n * ```typescript\n * import { VALIDATION_SCOPES } from \"./types.js\";\n * const scope = VALIDATION_SCOPES.FULL; // \"full\"\n * ```\n */\nexport const VALIDATION_SCOPES = {\n /** Validate entire codebase including tests and scripts */\n FULL: \"full\",\n /** Validate production files only */\n PRODUCTION: \"production\",\n} as const;\n\n/** Type for validation scope values */\nexport type ValidationScope = (typeof VALIDATION_SCOPES)[keyof typeof VALIDATION_SCOPES];\n\n/**\n * Configuration for validation scope.\n *\n * Derived from tsconfig.json settings to ensure alignment between\n * TypeScript and ESLint validation.\n */\nexport interface ScopeConfig {\n /** Directories to include in validation */\n directories: string[];\n /** File patterns to match (from tsconfig include) */\n filePatterns: string[];\n /** Patterns to exclude from validation */\n excludePatterns: string[];\n}\n\n// =============================================================================\n// EXECUTION MODE\n// =============================================================================\n\n/**\n * Execution mode constants.\n */\nexport const EXECUTION_MODES = {\n /** Read-only mode - report errors without fixing */\n READ: \"read\",\n /** Write mode - fix errors when possible (e.g., eslint --fix) */\n WRITE: \"write\",\n} as const;\n\n/** Type for execution mode values */\nexport type ExecutionMode = (typeof EXECUTION_MODES)[keyof typeof EXECUTION_MODES];\n\n// =============================================================================\n// VALIDATION CONTEXT\n// =============================================================================\n\n/**\n * Context object passed to validation steps.\n *\n * Contains all information needed to execute a validation step,\n * enabling pure functions that don't rely on global state.\n */\nexport interface ValidationContext {\n /** Root directory of the project being validated */\n projectRoot: string;\n /** Execution mode (read-only or write/fix) */\n mode?: ExecutionMode;\n /** Validation scope (full or production) */\n scope: ValidationScope;\n /** Scope configuration derived from tsconfig */\n scopeConfig: ScopeConfig;\n /** Which validations are enabled */\n enabledValidations: Partial<Record<string, boolean>>;\n /** Specific files to validate (if file-specific mode) */\n validatedFiles?: string[];\n /** Whether running in file-specific mode */\n isFileSpecificMode: boolean;\n /** ESLint flat config file name, determined by language detection */\n eslintConfigFile?: string;\n}\n\n// =============================================================================\n// VALIDATION RESULTS\n// =============================================================================\n\n/**\n * Result from a validation step.\n *\n * All validation steps return this structure to enable consistent\n * result handling and progress reporting.\n */\nexport interface ValidationStepResult {\n /** Whether the validation passed */\n success: boolean;\n /** Error message if validation failed */\n error?: string;\n /** Duration of the validation step in milliseconds */\n duration: number;\n /** Whether the step was skipped (e.g., tool not available) */\n skipped?: boolean;\n}\n\n/**\n * Result from circular dependency validation.\n *\n * Extends ValidationStepResult with circular dependency details.\n */\nexport interface CircularDependencyResult {\n /** Whether no circular dependencies were found */\n success: boolean;\n /** Error message if circular dependencies found */\n error?: string;\n /** The circular dependency cycles found */\n circularDependencies?: string[][];\n}\n\n// =============================================================================\n// VALIDATION STEP INTERFACE\n// =============================================================================\n\n/**\n * Definition of a validation step.\n *\n * Validation steps are pluggable units that can be enabled/disabled\n * and executed in sequence.\n */\nexport interface ValidationStep {\n /** Unique identifier for the step */\n id: string;\n /** Human-readable name for progress reporting */\n name: string;\n /** Description shown during execution */\n description: string;\n /** Function to determine if step should run */\n enabled: (context: ValidationContext) => boolean;\n /** Function to execute the validation */\n execute: (context: ValidationContext) => Promise<ValidationStepResult>;\n}\n","/**\n * Knip validation step.\n *\n * Detects unused exports, dependencies, and files using knip.\n *\n * @module validation/steps/knip\n */\n\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\nimport { lifecycleProcessRunner } from \"@/lib/process-lifecycle\";\nimport type { ProcessRunner, ScopeConfig } from \"../types\";\n\n// =============================================================================\n// DEFAULT DEPENDENCIES\n// =============================================================================\n\n/**\n * Default production process runner for Knip.\n */\nexport const defaultKnipProcessRunner: ProcessRunner = lifecycleProcessRunner;\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate unused code using knip with TypeScript-derived scope.\n *\n * @param scope - Validation scope\n * @param typescriptScope - Scope configuration from tsconfig\n * @param runner - Injectable process runner\n * @returns Promise resolving to validation result\n *\n * @example\n * ```typescript\n * const result = await validateKnip(\"full\", scopeConfig);\n * if (!result.success) {\n * console.error(\"Knip found issues:\", result.error);\n * }\n * ```\n */\nexport async function validateKnip(\n typescriptScope: ScopeConfig,\n runner: ProcessRunner = defaultKnipProcessRunner,\n): Promise<{\n success: boolean;\n error?: string;\n}> {\n try {\n // Use TypeScript-derived directories for perfect scope alignment\n const analyzeDirectories = typescriptScope.directories;\n\n if (analyzeDirectories.length === 0) {\n return { success: true };\n }\n\n return new Promise((resolve) => {\n const localBin = join(process.cwd(), \"node_modules\", \".bin\", \"knip\");\n const binary = existsSync(localBin) ? localBin : \"npx\";\n const knipProcess = runner.spawn(binary, binary === \"npx\" ? [\"knip\"] : [], {\n cwd: process.cwd(),\n stdio: \"pipe\",\n });\n\n let knipOutput = \"\";\n let knipError = \"\";\n\n knipProcess.stdout?.on(\"data\", (data: Buffer) => {\n knipOutput += data.toString();\n });\n\n knipProcess.stderr?.on(\"data\", (data: Buffer) => {\n knipError += data.toString();\n });\n\n knipProcess.on(\"close\", (code) => {\n if (code === 0) {\n resolve({ success: true });\n } else {\n const errorOutput = knipOutput || knipError || \"Unused code detected\";\n resolve({\n success: false,\n error: errorOutput,\n });\n }\n });\n\n knipProcess.on(\"error\", (error) => {\n resolve({ success: false, error: error.message });\n });\n });\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { success: false, error: errorMessage };\n }\n}\n","/**\n * Knip command for detecting unused code.\n *\n * Runs knip to find unused exports, dependencies, and files.\n * Disabled by default - enable with KNIP_VALIDATION_ENABLED=1.\n */\nimport { getTypeScriptScope } from \"@/validation/config/scope\";\nimport { discoverTool, formatSkipMessage } from \"@/validation/discovery/index\";\nimport { validationEnabled } from \"@/validation/steps/eslint\";\nimport { validateKnip } from \"@/validation/steps/knip\";\nimport type { KnipCommandOptions, ValidationCommandResult } from \"./types\";\n\n/**\n * Detect unused code with knip.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function knipCommand(options: KnipCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, quiet } = options;\n const startTime = Date.now();\n\n // Knip is disabled by default - check if explicitly enabled\n if (!validationEnabled(\"KNIP\", { KNIP: false })) {\n const output = quiet ? \"\" : \"Knip: skipped (disabled by default, set KNIP_VALIDATION_ENABLED=1 to enable)\";\n return { exitCode: 0, output, durationMs: Date.now() - startTime };\n }\n\n // Discover knip\n const toolResult = await discoverTool(\"knip\", { projectRoot: cwd });\n if (!toolResult.found) {\n const skipMessage = formatSkipMessage(\"unused code detection\", toolResult);\n return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };\n }\n\n // Get scope configuration from tsconfig (knip uses full scope)\n const scopeConfig = getTypeScriptScope(\"full\");\n\n // Run knip validation\n const result = await validateKnip(scopeConfig);\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : `Knip: ✓ No unused code found`;\n return { exitCode: 0, output, durationMs };\n } else {\n const output = result.error ?? \"Unused code found\";\n return { exitCode: 1, output, durationMs };\n }\n}\n","/**\n * ESLint validation command.\n *\n * Runs ESLint for code quality checks.\n */\nimport { getTypeScriptScope } from \"@/validation/config/scope\";\nimport { detectTypeScript, discoverTool, formatSkipMessage } from \"@/validation/discovery/index\";\nimport { validateESLint } from \"@/validation/steps/eslint\";\nimport type { ValidationContext } from \"@/validation/types\";\nimport type { LintCommandOptions, ValidationCommandResult } from \"./types\";\n\nconst TYPESCRIPT_ABSENT_MESSAGE = \"⏭ Skipping ESLint (TypeScript not detected in project)\";\nconst MISSING_CONFIG_MESSAGE =\n \"ESLint config not found: project has tsconfig.json but no eslint.config.{ts,js,mjs,cjs}\";\n\n/**\n * Run ESLint validation.\n *\n * Gates ESLint execution on TypeScript language detection. ESLint runs only\n * when `tsconfig.json` is present AND an ESLint flat config file exists. A\n * project with `tsconfig.json` but no ESLint config produces a non-zero exit\n * with a descriptive error; a project without `tsconfig.json` skips cleanly.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function lintCommand(options: LintCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, scope = \"full\", files, fix, quiet } = options;\n const startTime = Date.now();\n\n // Gate 1: language detection. No TypeScript = skip cleanly.\n const tsDetection = detectTypeScript(cwd);\n if (!tsDetection.present) {\n return {\n exitCode: 0,\n output: quiet ? \"\" : TYPESCRIPT_ABSENT_MESSAGE,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Gate 2: ESLint flat config must exist when TypeScript is present.\n if (tsDetection.eslintConfigFile === undefined) {\n return {\n exitCode: 1,\n output: MISSING_CONFIG_MESSAGE,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Gate 3: tool discovery — ensure ESLint itself is available somewhere.\n const toolResult = await discoverTool(\"eslint\", { projectRoot: cwd });\n if (!toolResult.found) {\n const skipMessage = formatSkipMessage(\"ESLint\", toolResult);\n return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };\n }\n\n // Get scope configuration from tsconfig\n const scopeConfig = getTypeScriptScope(scope);\n\n // Build validation context\n const context: ValidationContext = {\n projectRoot: cwd,\n scope,\n scopeConfig,\n mode: fix ? \"write\" : \"read\",\n enabledValidations: { ESLINT: true },\n validatedFiles: files,\n isFileSpecificMode: Boolean(files && files.length > 0),\n eslintConfigFile: tsDetection.eslintConfigFile,\n };\n\n // Run ESLint validation\n const result = await validateESLint(context);\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : `ESLint: ✓ No errors found`;\n return { exitCode: 0, output, durationMs };\n } else {\n const output = result.error ?? \"ESLint validation failed\";\n return { exitCode: 1, output, durationMs };\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { isAbsolute, relative, resolve } from \"node:path\";\n\nimport { DEFAULT_SCOPE_CONFIG } from \"@/lib/file-inclusion/config\";\nimport { EMPTY_IGNORE_READER } from \"@/lib/file-inclusion/ignore-source\";\nimport { artifactDirectoryLayer, hiddenPrefixLayer } from \"@/lib/file-inclusion/layer-sequence\";\nimport { runPipeline } from \"@/lib/file-inclusion/pipeline\";\nimport type { ScopeEntry } from \"@/lib/file-inclusion/types\";\nimport { type ValidationPathConfig } from \"@/validation/config/descriptor\";\n\nimport { type LiteralConfig, literalConfigDescriptor, resolveAllowlist } from \"./config\";\nimport {\n buildIndex,\n collectLiterals,\n defaultVisitorKeys,\n type DetectionResult,\n detectReuse,\n type LiteralOccurrence,\n} from \"./detector\";\nimport { isTestFile, isTypescriptSource } from \"./walker\";\n\nexport { literalConfigDescriptor, resolveAllowlist } from \"./config\";\nexport type { LiteralAllowlistConfig, LiteralConfig } from \"./config\";\nexport {\n buildIndex,\n collectLiterals,\n defaultVisitorKeys,\n detectReuse,\n FIXTURE_WRITER_CALLS,\n LITERAL_KIND,\n MODULE_NAMING_SKIP,\n parseLiteralReuseResult,\n REMEDIATION,\n} from \"./detector\";\nexport type {\n DetectionResult,\n DupeFinding,\n LiteralIndex,\n LiteralKind,\n LiteralLocation,\n LiteralOccurrence,\n Remediation,\n ReuseFinding,\n VisitorKeysMap,\n} from \"./detector\";\n\nexport interface ValidateLiteralReuseInput {\n readonly projectRoot: string;\n readonly files?: readonly string[];\n readonly config?: LiteralConfig;\n readonly pathConfig?: ValidationPathConfig;\n}\n\nexport interface ValidateLiteralReuseResult {\n readonly findings: DetectionResult;\n readonly indexedOccurrencesByFile: ReadonlyMap<string, readonly LiteralOccurrence[]>;\n}\n\nconst PATH_PREFIX_SEPARATOR = \"/\";\n\nfunction normalizePathPrefix(prefix: string): string {\n const posix = prefix.split(/[\\\\/]/g).join(PATH_PREFIX_SEPARATOR);\n return posix.endsWith(PATH_PREFIX_SEPARATOR) ? posix : `${posix}${PATH_PREFIX_SEPARATOR}`;\n}\n\nfunction applyPathFilter(\n entries: readonly ScopeEntry[],\n pathConfig: ValidationPathConfig | undefined,\n): readonly ScopeEntry[] {\n if (pathConfig === undefined) {\n return entries;\n }\n const includePrefixes = (pathConfig.include ?? []).map(normalizePathPrefix);\n const excludePrefixes = (pathConfig.exclude ?? []).map(normalizePathPrefix);\n return entries.filter((entry) => {\n if (\n includePrefixes.length > 0\n && !includePrefixes.some((p) => entry.path.startsWith(p))\n ) {\n return false;\n }\n if (excludePrefixes.some((p) => entry.path.startsWith(p))) {\n return false;\n }\n return true;\n });\n}\n\nexport async function validateLiteralReuse(\n input: ValidateLiteralReuseInput,\n): Promise<ValidateLiteralReuseResult> {\n const config = input.config ?? literalConfigDescriptor.defaults;\n\n const request = input.files\n ? {\n explicit: input.files.map((f) => {\n const abs = isAbsolute(f) ? f : resolve(input.projectRoot, f);\n return relative(input.projectRoot, abs).split(/[\\\\/]/g).join(\"/\");\n }),\n }\n : { walkRoot: input.projectRoot };\n\n const scope = await runPipeline(\n [artifactDirectoryLayer, hiddenPrefixLayer],\n input.projectRoot,\n request,\n DEFAULT_SCOPE_CONFIG,\n EMPTY_IGNORE_READER,\n );\n\n const filtered = applyPathFilter(scope.included, input.pathConfig);\n\n const candidateFiles = filtered\n .filter((entry) => isTypescriptSource(entry.path))\n .map((entry) => resolve(input.projectRoot, entry.path));\n\n const collectOptions = {\n visitorKeys: defaultVisitorKeys,\n minStringLength: config.minStringLength,\n minNumberDigits: config.minNumberDigits,\n };\n\n const srcOccurrences: LiteralOccurrence[] = [];\n const testOccurrencesByFile = new Map<string, readonly LiteralOccurrence[]>();\n const indexedOccurrencesByFile = new Map<string, readonly LiteralOccurrence[]>();\n\n for (const abs of candidateFiles) {\n const rel = relative(input.projectRoot, abs).split(/[\\\\/]/g).join(\"/\");\n\n const content = await readSafe(abs);\n if (content === null) continue;\n\n const occurrences = collectLiterals(content, rel, collectOptions);\n indexedOccurrencesByFile.set(rel, occurrences);\n if (isTestFile(rel)) {\n testOccurrencesByFile.set(rel, occurrences);\n } else {\n srcOccurrences.push(...occurrences);\n }\n }\n\n const srcIndex = buildIndex(srcOccurrences);\n const findings = detectReuse({\n srcIndex,\n testOccurrencesByFile,\n allowlist: resolveAllowlist(config.allowlist),\n });\n\n return { findings, indexedOccurrencesByFile };\n}\n\nasync function readSafe(path: string): Promise<string | null> {\n try {\n return await readFile(path, \"utf8\");\n } catch (err: unknown) {\n if (typeof err === \"object\" && err !== null && \"code\" in err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === \"ENOENT\" || code === \"EISDIR\") return null;\n }\n throw err;\n }\n}\n","import type { IgnoreSourcePredicateConfig, LayerDecision } from \"../types\";\n\nexport const IGNORE_SOURCE_LAYER = \"ignore-source\";\nconst LAYER = IGNORE_SOURCE_LAYER;\n\nexport function ignoreSourcePredicate(\n path: string,\n config: IgnoreSourcePredicateConfig,\n): LayerDecision {\n const entry = config.reader.matchedEntry(path);\n if (entry === undefined) {\n return { matched: false, layer: LAYER };\n }\n return { matched: true, layer: LAYER, detail: entry.segment };\n}\n","import { artifactDirectoryPredicate } from \"./predicates/artifact-directory\";\nimport { hiddenPrefixPredicate } from \"./predicates/hidden-prefix\";\nimport { ignoreSourcePredicate } from \"./predicates/ignore-source\";\nimport type { ArtifactDirectoryConfig, HiddenPrefixConfig, IgnoreSourcePredicateConfig } from \"./types\";\nimport type { LayerContext, LayerDecision, LayerEntry } from \"./types\";\n\nfunction makeLayer<C>(\n extractConfig: (ctx: LayerContext) => C,\n predicate: (path: string, config: C) => LayerDecision,\n): LayerEntry {\n return {\n extractConfig,\n predicate: (path, config) => predicate(path, config as C),\n };\n}\n\nexport const artifactDirectoryLayer: LayerEntry = makeLayer(\n (ctx): ArtifactDirectoryConfig => ({ artifactDirectories: ctx.config.artifactDirectories }),\n artifactDirectoryPredicate,\n);\n\nexport const hiddenPrefixLayer: LayerEntry = makeLayer(\n (ctx): HiddenPrefixConfig => ({ hiddenPrefix: ctx.config.hiddenPrefix }),\n hiddenPrefixPredicate,\n);\n\nexport const ignoreSourceLayer: LayerEntry = makeLayer(\n (ctx): IgnoreSourcePredicateConfig => ({ reader: ctx.ignoreReader }),\n ignoreSourcePredicate,\n);\n\nexport const LAYER_SEQUENCE: readonly LayerEntry[] = [\n artifactDirectoryLayer,\n hiddenPrefixLayer,\n ignoreSourceLayer,\n];\n","import type { Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join, relative, sep } from \"node:path\";\n\nimport { createIgnoreSourceReader } from \"./ignore-source\";\nimport type { IgnoreSourceReader } from \"./ignore-source\";\nimport { LAYER_SEQUENCE } from \"./layer-sequence\";\nimport type {\n LayerContext,\n LayerDecision,\n LayerEntry,\n ScopeEntry,\n ScopeRequest,\n ScopeResolverConfig,\n ScopeResult,\n} from \"./types\";\n\nexport { LayerEntry, ScopeEntry, ScopeRequest, ScopeResolverConfig, ScopeResult };\nexport type { LayerContext, LayerDecision };\n\nexport const EXPLICIT_OVERRIDE_LAYER = \"explicit-override\" as const;\n\nfunction isNodeError(err: unknown): err is NodeJS.ErrnoException {\n return err instanceof Error && \"code\" in err;\n}\n\nasync function collectPaths(\n absoluteDir: string,\n projectRoot: string,\n result: string[],\n artifactDirs: ReadonlySet<string>,\n): Promise<void> {\n let dirEntries: Dirent<string>[];\n try {\n dirEntries = await readdir(absoluteDir, { withFileTypes: true });\n } catch (err) {\n if (isNodeError(err) && (err.code === \"ENOENT\" || err.code === \"ENOTDIR\")) {\n return;\n }\n throw err;\n }\n for (const entry of dirEntries) {\n if (entry.isDirectory()) {\n if (artifactDirs.has(entry.name)) continue;\n const absolutePath = join(absoluteDir, entry.name);\n await collectPaths(absolutePath, projectRoot, result, artifactDirs);\n } else if (entry.isFile()) {\n const absolutePath = join(absoluteDir, entry.name);\n const rel = relative(projectRoot, absolutePath);\n result.push(sep === \"/\" ? rel : rel.split(sep).join(\"/\"));\n }\n }\n}\n\nexport async function resolveScope(\n projectRoot: string,\n request: ScopeRequest,\n config: ScopeResolverConfig,\n): Promise<ScopeResult> {\n const ignoreReader = createIgnoreSourceReader(projectRoot, {\n ignoreSourceFilename: config.ignoreSourceFilename,\n specTreeRootSegment: config.specTreeRootSegment,\n });\n return runPipeline(LAYER_SEQUENCE, projectRoot, request, config, ignoreReader);\n}\n\nexport async function runPipeline(\n sequence: readonly LayerEntry[],\n projectRoot: string,\n request: ScopeRequest,\n config: ScopeResolverConfig,\n ignoreReader: IgnoreSourceReader,\n): Promise<ScopeResult> {\n const layerCtx: LayerContext = { config, ignoreReader };\n const layerPairs = sequence.map((entry) => ({\n entry,\n layerConfig: entry.extractConfig(layerCtx),\n }));\n\n const included: ScopeEntry[] = [];\n const excluded: ScopeEntry[] = [];\n\n const explicitPaths = request.explicit ?? [];\n const explicitPathSet = new Set<string>(explicitPaths);\n\n for (const path of explicitPaths) {\n included.push({\n path,\n decisionTrail: [{ matched: true, layer: EXPLICIT_OVERRIDE_LAYER }],\n });\n }\n\n if (request.walkRoot !== undefined) {\n const artifactDirs = new Set(config.artifactDirectories);\n const allPaths: string[] = [];\n await collectPaths(request.walkRoot, projectRoot, allPaths, artifactDirs);\n\n for (const path of allPaths) {\n if (explicitPathSet.has(path)) continue;\n\n const trail: LayerDecision[] = [];\n for (const { entry, layerConfig } of layerPairs) {\n const decision = entry.predicate(path, layerConfig);\n if (decision.matched) {\n trail.push(decision);\n }\n }\n\n if (trail.length > 0) {\n excluded.push({ path, decisionTrail: trail });\n } else {\n included.push({ path, decisionTrail: [] });\n }\n }\n }\n\n return { included, excluded };\n}\n","import { parse as parseTypeScript } from \"@typescript-eslint/parser\";\nimport { visitorKeys as typescriptVisitorKeys } from \"@typescript-eslint/visitor-keys\";\n\nimport { SPEC_TREE_ENV_FIXTURE_WRITER_METHODS } from \"@/domains/spec/fixture-writer-methods\";\n\nexport const LITERAL_KIND = {\n STRING: \"string\",\n NUMBER: \"number\",\n} as const;\n\nexport type LiteralKind = (typeof LITERAL_KIND)[keyof typeof LITERAL_KIND];\n\nexport interface LiteralLocation {\n readonly file: string;\n readonly line: number;\n}\n\nexport interface LiteralOccurrence {\n readonly kind: LiteralKind;\n readonly value: string;\n readonly loc: LiteralLocation;\n}\n\nexport type LiteralIndex = ReadonlyMap<string, readonly LiteralLocation[]>;\n\nexport type VisitorKeysMap = Record<string, readonly string[] | undefined>;\n\nexport const REMEDIATION = {\n IMPORT_FROM_SOURCE: \"import-from-source\",\n REFACTOR_TO_SOURCE_OR_GENERATOR: \"refactor-to-source-or-generator\",\n} as const;\n\nexport type Remediation = (typeof REMEDIATION)[keyof typeof REMEDIATION];\n\nexport interface ReuseFinding {\n readonly test: LiteralLocation;\n readonly kind: LiteralKind;\n readonly value: string;\n readonly src: readonly LiteralLocation[];\n readonly remediation: typeof REMEDIATION.IMPORT_FROM_SOURCE;\n}\n\nexport interface DupeFinding {\n readonly test: LiteralLocation;\n readonly kind: LiteralKind;\n readonly value: string;\n readonly otherTests: readonly LiteralLocation[];\n readonly remediation: typeof REMEDIATION.REFACTOR_TO_SOURCE_OR_GENERATOR;\n}\n\nexport interface DetectionResult {\n readonly srcReuse: readonly ReuseFinding[];\n readonly testDupe: readonly DupeFinding[];\n}\n\nexport interface CollectLiteralsOptions {\n readonly visitorKeys: VisitorKeysMap;\n readonly minStringLength: number;\n readonly minNumberDigits: number;\n}\n\nexport interface DetectReuseInput {\n readonly srcIndex: LiteralIndex;\n readonly testOccurrencesByFile: ReadonlyMap<string, readonly LiteralOccurrence[]>;\n readonly allowlist: ReadonlySet<string>;\n}\n\nexport const defaultVisitorKeys: VisitorKeysMap = typescriptVisitorKeys;\n\nexport const MODULE_NAMING_SKIP: Record<string, ReadonlySet<string>> = {\n ImportDeclaration: new Set([\"source\"]),\n ExportNamedDeclaration: new Set([\"source\"]),\n ExportAllDeclaration: new Set([\"source\"]),\n ImportExpression: new Set([\"source\"]),\n TSImportType: new Set([\"source\", \"argument\"]),\n TSExternalModuleReference: new Set([\"expression\"]),\n};\n\nconst EMPTY_SKIP: ReadonlySet<string> = new Set();\nconst TEST_PATH_SEGMENT = \"/tests/\";\nconst WINDOWS_TEST_PATH_SEGMENT = \"\\\\tests\\\\\";\nconst TEST_FILE_MARKER = \".test.\";\nconst CALL_EXPRESSION_TYPE = \"CallExpression\";\nconst VARIABLE_DECLARATOR_TYPE = \"VariableDeclarator\";\nconst IDENTIFIER_TYPE = \"Identifier\";\nconst LITERAL_TYPE = \"Literal\";\nconst MEMBER_EXPRESSION_TYPE = \"MemberExpression\";\nconst TEMPLATE_ELEMENT_TYPE = \"TemplateElement\";\nconst FUNCTION_NODE_TYPES: ReadonlySet<string> = new Set([\n \"ArrowFunctionExpression\",\n \"FunctionDeclaration\",\n \"FunctionExpression\",\n]);\nexport const FIXTURE_WRITER_CALLS: ReadonlySet<string> = new Set(\n SPEC_TREE_ENV_FIXTURE_WRITER_METHODS,\n);\nconst FIXTURE_DATA_DIRECT_SEGMENTS: ReadonlySet<string> = new Set([\"fixture\", \"payload\"]);\nconst FIXTURE_DATA_ROLE_SEGMENTS: ReadonlySet<string> = new Set([\n \"verdict\",\n \"session\",\n \"frontmatter\",\n \"xml\",\n \"yaml\",\n \"json\",\n \"source\",\n]);\nconst FIXTURE_DATA_CONTEXT_SEGMENTS: ReadonlySet<string> = new Set([\"path\", \"tree\"]);\n// Used through String#match; match resets global regex state instead of reading lastIndex.\nconst IDENTIFIER_SEGMENT_PATTERN = /[A-Z]+(?=[A-Z][a-z]|$)|[A-Z]?[a-z]+|[0-9]+/g;\n\ninterface Node {\n readonly type: string;\n readonly loc?: { readonly start?: { readonly line?: number } };\n readonly value?: unknown;\n readonly raw?: unknown;\n readonly [key: string]: unknown;\n}\n\ninterface WalkAncestor {\n readonly node: Node;\n}\n\ninterface WalkContext {\n readonly filename: string;\n readonly isTestFixtureFile: boolean;\n}\n\nexport function collectLiterals(\n source: string,\n filename: string,\n options: CollectLiteralsOptions,\n): LiteralOccurrence[] {\n const ast = parseTypeScript(source, {\n loc: true,\n range: true,\n comment: false,\n jsx: true,\n ecmaVersion: \"latest\",\n sourceType: \"module\",\n }) as unknown as Node;\n const out: LiteralOccurrence[] = [];\n const ancestors: WalkAncestor[] = [];\n walk(ast, { filename, isTestFixtureFile: isTestLikeFile(filename) }, ancestors, options, out);\n return out;\n}\n\nfunction walk(\n node: Node,\n context: WalkContext,\n ancestors: WalkAncestor[],\n options: CollectLiteralsOptions,\n out: LiteralOccurrence[],\n): void {\n emitLiteral(node, context, ancestors, options, out);\n\n const keys = options.visitorKeys[node.type];\n if (!keys) {\n return;\n }\n const skip = MODULE_NAMING_SKIP[node.type] ?? EMPTY_SKIP;\n for (const key of keys) {\n if (skip.has(key)) continue;\n const child = node[key];\n if (Array.isArray(child)) {\n for (const item of child) {\n if (isNode(item)) walkChild(item, node, context, ancestors, options, out);\n }\n } else if (isNode(child)) {\n walkChild(child, node, context, ancestors, options, out);\n }\n }\n}\n\nfunction walkChild(\n node: Node,\n parent: Node,\n context: WalkContext,\n ancestors: WalkAncestor[],\n options: CollectLiteralsOptions,\n out: LiteralOccurrence[],\n): void {\n // Shared stack mutation relies on synchronous traversal.\n ancestors.push({ node: parent });\n try {\n walk(node, context, ancestors, options, out);\n } finally {\n ancestors.pop();\n }\n}\n\nfunction isNode(value: unknown): value is Node {\n return typeof value === \"object\" && value !== null && typeof (value as Node).type === \"string\";\n}\n\nfunction emitLiteral(\n node: Node,\n context: WalkContext,\n ancestors: readonly WalkAncestor[],\n options: CollectLiteralsOptions,\n out: LiteralOccurrence[],\n): void {\n if (node.type !== LITERAL_TYPE && node.type !== TEMPLATE_ELEMENT_TYPE) {\n return;\n }\n if (isFixtureDataLiteral(context, ancestors)) {\n return;\n }\n const line = node.loc?.start?.line ?? 0;\n\n if (node.type === LITERAL_TYPE) {\n if (typeof node.value === \"string\") {\n if (node.value.length >= options.minStringLength) {\n out.push({ kind: \"string\", value: node.value, loc: { file: context.filename, line } });\n }\n } else if (typeof node.value === \"number\") {\n const raw = typeof node.raw === \"string\" ? node.raw : String(node.value);\n if (isMeaningfulNumber(raw, options.minNumberDigits)) {\n out.push({ kind: \"number\", value: String(node.value), loc: { file: context.filename, line } });\n }\n }\n return;\n }\n\n if (node.type === TEMPLATE_ELEMENT_TYPE) {\n const value = node.value as { readonly cooked?: string } | undefined;\n const cooked = value?.cooked ?? \"\";\n if (cooked.length >= options.minStringLength) {\n out.push({ kind: \"string\", value: cooked, loc: { file: context.filename, line } });\n }\n }\n}\n\nfunction isTestLikeFile(filename: string): boolean {\n return filename.includes(TEST_PATH_SEGMENT)\n || filename.includes(WINDOWS_TEST_PATH_SEGMENT)\n || filename.includes(TEST_FILE_MARKER);\n}\n\nfunction isFixtureDataLiteral(\n context: WalkContext,\n ancestors: readonly WalkAncestor[],\n): boolean {\n if (!context.isTestFixtureFile) {\n return false;\n }\n return isInsideFixtureWriterArgument(ancestors) || isInsideFixtureDataVariable(ancestors);\n}\n\nfunction isInsideFixtureWriterArgument(ancestors: readonly WalkAncestor[]): boolean {\n // Scan every call ancestor so wrappers around fixture-writer calls do not hide direct writer arguments.\n // Payload helpers inside a fixture writer remain setup data unless a nested function boundary intervenes.\n for (let index = ancestors.length - 1; index >= 0; index -= 1) {\n const ancestor = ancestors[index];\n if (ancestor.node.type !== CALL_EXPRESSION_TYPE) {\n continue;\n }\n const callName = getCallName(ancestor.node);\n if (callName === undefined || !isFixtureWriterCall(callName)) {\n continue;\n }\n if (hasNestedFunctionBetween(ancestors, index)) {\n continue;\n }\n return true;\n }\n return false;\n}\n\nfunction isFixtureWriterCall(callName: string): boolean {\n return FIXTURE_WRITER_CALLS.has(callName);\n}\n\nfunction isInsideFixtureDataVariable(ancestors: readonly WalkAncestor[]): boolean {\n for (let index = ancestors.length - 1; index >= 0; index -= 1) {\n const ancestor = ancestors[index];\n if (ancestor.node.type !== VARIABLE_DECLARATOR_TYPE) {\n continue;\n }\n if (hasNestedFunctionBetween(ancestors, index)) {\n continue;\n }\n const variableName = getFixtureDataDeclaratorName(ancestor.node);\n if (variableName !== undefined && isFixtureDataVariableName(variableName)) {\n return true;\n }\n }\n return false;\n}\n\nfunction hasNestedFunctionBetween(\n ancestors: readonly WalkAncestor[],\n ancestorIndex: number,\n): boolean {\n // The current literal node is passed separately, so this range checks only ancestors between call and literal.\n for (let index = ancestorIndex + 1; index < ancestors.length; index += 1) {\n if (FUNCTION_NODE_TYPES.has(ancestors[index].node.type)) {\n return true;\n }\n }\n return false;\n}\n\nfunction getFixtureDataDeclaratorName(node: Node): string | undefined {\n const bindingName = getIdentifierName(node.id);\n if (bindingName !== undefined) {\n return bindingName;\n }\n // Destructuring defaults are classified by the fixture object they read from.\n // Opaque initializer expressions keep their literals in the occurrence index.\n return getIdentifierName(node.init);\n}\n\nfunction isFixtureDataVariableName(variableName: string): boolean {\n const segments = splitIdentifierName(variableName);\n if (segments.length === 0) {\n return false;\n }\n // Tier 1: explicit fixture markers always denote test-authored data.\n if (segments.some((segment) => FIXTURE_DATA_DIRECT_SEGMENTS.has(segment))) {\n return true;\n }\n // Tier 2 and Tier 3 require at least one fixture role word.\n if (!segments.some((segment) => FIXTURE_DATA_ROLE_SEGMENTS.has(segment))) {\n return false;\n }\n // Tier 2: single-role and compound-role names describe fixture payloads.\n if (segments.every((segment) => FIXTURE_DATA_ROLE_SEGMENTS.has(segment))) {\n return true;\n }\n // Tier 3: role/context compounds are fixtures only when the context word is final.\n const finalSegment = segments[segments.length - 1];\n return finalSegment !== undefined && FIXTURE_DATA_CONTEXT_SEGMENTS.has(finalSegment);\n}\n\nfunction splitIdentifierName(variableName: string): readonly string[] {\n return variableName\n .split(\"_\")\n .flatMap((part) => part.match(IDENTIFIER_SEGMENT_PATTERN) ?? [])\n .map((segment) => segment.toLowerCase());\n}\n\nfunction getCallName(node: Node): string | undefined {\n const callee = node.callee;\n if (!isNode(callee)) {\n return undefined;\n }\n if (callee.type === IDENTIFIER_TYPE) {\n return getIdentifierName(callee);\n }\n if (callee.type !== MEMBER_EXPRESSION_TYPE) {\n return undefined;\n }\n const property = callee.property;\n if (isNode(property)) {\n return property.type === IDENTIFIER_TYPE ? getIdentifierName(property) : getLiteralString(property);\n }\n return undefined;\n}\n\nfunction getIdentifierName(value: unknown): string | undefined {\n if (!isNode(value) || value.type !== IDENTIFIER_TYPE) {\n return undefined;\n }\n return typeof value.name === \"string\" ? value.name : undefined;\n}\n\nfunction getLiteralString(value: unknown): string | undefined {\n if (!isNode(value) || value.type !== LITERAL_TYPE) {\n return undefined;\n }\n return typeof value.value === \"string\" ? value.value : undefined;\n}\n\nfunction isMeaningfulNumber(raw: string, minDigits: number): boolean {\n const digits = raw.replace(/[^0-9]/g, \"\");\n return digits.length >= minDigits;\n}\n\nexport function buildIndex(\n occurrences: Iterable<LiteralOccurrence>,\n): LiteralIndex {\n const map = new Map<string, LiteralLocation[]>();\n for (const occ of occurrences) {\n const key = makeKey(occ.kind, occ.value);\n const existing = map.get(key);\n if (existing) {\n existing.push(occ.loc);\n } else {\n map.set(key, [occ.loc]);\n }\n }\n return map;\n}\n\nfunction makeKey(kind: LiteralKind, value: string): string {\n return `${kind}\\0${value}`;\n}\n\nfunction splitKey(key: string): { kind: LiteralKind; value: string } {\n const idx = key.indexOf(\"\\0\");\n return { kind: key.slice(0, idx) as LiteralKind, value: key.slice(idx + 1) };\n}\n\nexport function detectReuse(input: DetectReuseInput): DetectionResult {\n const srcReuse: ReuseFinding[] = [];\n const testDupe: DupeFinding[] = [];\n\n const testIndex = new Map<string, Map<string, LiteralLocation[]>>();\n for (const [file, occurrences] of input.testOccurrencesByFile) {\n for (const occ of occurrences) {\n if (input.allowlist.has(occ.value)) continue;\n const key = makeKey(occ.kind, occ.value);\n let byFile = testIndex.get(key);\n if (!byFile) {\n byFile = new Map<string, LiteralLocation[]>();\n testIndex.set(key, byFile);\n }\n const locsInFile = byFile.get(file);\n if (locsInFile) locsInFile.push(occ.loc);\n else byFile.set(file, [occ.loc]);\n }\n }\n\n for (const [key, byFile] of testIndex) {\n const { kind, value } = splitKey(key);\n const srcLocs = input.srcIndex.get(key);\n const allTestLocs: LiteralLocation[] = [];\n for (const locs of byFile.values()) allTestLocs.push(...locs);\n\n if (srcLocs && srcLocs.length > 0) {\n for (const testLoc of allTestLocs) {\n srcReuse.push({\n test: testLoc,\n kind,\n value,\n src: srcLocs,\n remediation: REMEDIATION.IMPORT_FROM_SOURCE,\n });\n }\n } else if (byFile.size >= 2) {\n for (let i = 0; i < allTestLocs.length; i += 1) {\n const otherTests = [...allTestLocs.slice(0, i), ...allTestLocs.slice(i + 1)];\n testDupe.push({\n test: allTestLocs[i],\n kind,\n value,\n otherTests,\n remediation: REMEDIATION.REFACTOR_TO_SOURCE_OR_GENERATOR,\n });\n }\n }\n }\n\n return { srcReuse, testDupe };\n}\n\nexport function parseLiteralReuseResult(value: unknown): DetectionResult {\n if (!isPlainObject(value)) {\n throw new Error(\"literal-reuse result must be an object\");\n }\n const obj = value as { srcReuse?: unknown; testDupe?: unknown };\n if (!Array.isArray(obj.srcReuse)) {\n throw new Error(\"literal-reuse result is missing srcReuse array\");\n }\n if (!Array.isArray(obj.testDupe)) {\n throw new Error(\"literal-reuse result is missing testDupe array\");\n }\n for (const f of obj.srcReuse) validateReuseFinding(f);\n for (const f of obj.testDupe) validateDupeFinding(f);\n return { srcReuse: obj.srcReuse as readonly ReuseFinding[], testDupe: obj.testDupe as readonly DupeFinding[] };\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction validateLiteralLocation(value: unknown, context: string): void {\n if (!isPlainObject(value)) throw new Error(`${context} must be an object`);\n if (typeof value[\"file\"] !== \"string\") throw new Error(`${context}.file must be a string`);\n if (typeof value[\"line\"] !== \"number\") throw new Error(`${context}.line must be a number`);\n}\n\nfunction validateKindValue(value: unknown, context: string): void {\n if (!isPlainObject(value)) throw new Error(`${context} must be an object`);\n if (value[\"kind\"] !== \"string\" && value[\"kind\"] !== \"number\") {\n throw new Error(`${context}.kind must be \"string\" or \"number\"`);\n }\n if (typeof value[\"value\"] !== \"string\") {\n throw new Error(`${context}.value must be a string`);\n }\n}\n\nfunction validateReuseFinding(value: unknown): void {\n validateKindValue(value, \"srcReuse finding\");\n const obj = value as Record<string, unknown>;\n validateLiteralLocation(obj[\"test\"], \"srcReuse finding.test\");\n if (!Array.isArray(obj[\"src\"])) throw new Error(\"srcReuse finding.src must be an array\");\n for (const loc of obj[\"src\"]) validateLiteralLocation(loc, \"srcReuse finding.src[i]\");\n if (obj[\"remediation\"] !== REMEDIATION.IMPORT_FROM_SOURCE) {\n throw new Error(`srcReuse finding.remediation must be \"${REMEDIATION.IMPORT_FROM_SOURCE}\"`);\n }\n}\n\nfunction validateDupeFinding(value: unknown): void {\n validateKindValue(value, \"testDupe finding\");\n const obj = value as Record<string, unknown>;\n validateLiteralLocation(obj[\"test\"], \"testDupe finding.test\");\n if (!Array.isArray(obj[\"otherTests\"])) {\n throw new Error(\"testDupe finding.otherTests must be an array\");\n }\n for (const loc of obj[\"otherTests\"]) validateLiteralLocation(loc, \"testDupe finding.otherTests[i]\");\n if (obj[\"remediation\"] !== REMEDIATION.REFACTOR_TO_SOURCE_OR_GENERATOR) {\n throw new Error(\n `testDupe finding.remediation must be \"${REMEDIATION.REFACTOR_TO_SOURCE_OR_GENERATOR}\"`,\n );\n }\n}\n","// Shared production metadata for spec-tree fixture writer methods.\n// Literal validation imports this registry to classify test-authored setup data.\nexport const SPEC_TREE_ENV_FIXTURE_WRITER_METHODS = [\n \"writeDecision\",\n \"writeNode\",\n \"writeRaw\",\n] as const satisfies readonly string[];\n\nexport type SpecTreeEnvFixtureWriterMethod = (typeof SPEC_TREE_ENV_FIXTURE_WRITER_METHODS)[number];\n","const TYPESCRIPT_EXTENSIONS: ReadonlySet<string> = new Set([\".ts\", \".tsx\"]);\nconst DECLARATION_SUFFIX = \".d.ts\";\n\nexport function isTypescriptSource(path: string): boolean {\n if (path.endsWith(DECLARATION_SUFFIX)) return false;\n const ext = extensionOf(path);\n return TYPESCRIPT_EXTENSIONS.has(ext);\n}\n\nfunction extensionOf(name: string): string {\n const idx = name.lastIndexOf(\".\");\n return idx === -1 ? \"\" : name.slice(idx);\n}\n\nexport function isTestFile(relPath: string): boolean {\n return /\\.test\\.tsx?$/.test(relPath);\n}\n","import { resolveConfig } from \"@/config/index\";\nimport {\n type ValidationConfig,\n validationConfigDescriptor,\n type ValidationPathConfig,\n} from \"@/validation/config/descriptor\";\nimport { detectTypeScript } from \"@/validation/discovery/index\";\nimport { type LiteralConfig } from \"@/validation/literal/config\";\nimport {\n type DetectionResult,\n type DupeFinding,\n type LiteralKind,\n type LiteralLocation,\n type ReuseFinding,\n validateLiteralReuse,\n} from \"@/validation/literal/index\";\nimport { validationEnabled } from \"@/validation/steps/eslint\";\n\nexport const LITERAL_PROBLEM_KIND = {\n REUSE: \"reuse\",\n DUPE: \"dupe\",\n} as const;\n\nexport type LiteralProblemKind = (typeof LITERAL_PROBLEM_KIND)[keyof typeof LITERAL_PROBLEM_KIND];\n\nexport const OUTPUT_MODE_NAMES = [\"text\", \"verbose\", \"filesWithProblems\", \"literals\", \"json\"] as const;\nexport type OutputModeName = (typeof OUTPUT_MODE_NAMES)[number];\n\nexport const VERBOSE_PROBLEM_LINE_PREFIX = \"line \";\n\nexport interface LiteralCommandOptions {\n readonly cwd: string;\n readonly files?: readonly string[];\n readonly kind?: LiteralProblemKind;\n readonly filesWithProblems?: boolean;\n readonly literals?: boolean;\n readonly verbose?: boolean;\n readonly json?: boolean;\n readonly quiet?: boolean;\n readonly config?: LiteralConfig;\n readonly pathConfig?: ValidationPathConfig;\n}\n\nexport interface ValidationCommandResult {\n readonly exitCode: number;\n readonly output: string;\n readonly durationMs: number;\n}\n\nconst EXIT_OK = 0;\nconst EXIT_FINDINGS = 1;\nconst EXIT_CONFIG_ERROR = 2;\nconst TYPESCRIPT_ABSENT_MESSAGE = \"⏭ Skipping Literal (TypeScript not detected in project)\";\nconst DISABLED_MESSAGE = \"⏭ Skipping Literal (LITERAL_VALIDATION_ENABLED=0)\";\nexport const NO_PROBLEMS_MESSAGE = \"Literal: ✓ No problems\";\n\nexport function formatNoProblemsOfKind(kind: LiteralProblemKind): string {\n return `Literal: No problems of type ${kind}`;\n}\n\ninterface LiteralProblem {\n readonly problemKind: LiteralProblemKind;\n readonly literalKind: LiteralKind;\n readonly value: string;\n readonly test: LiteralLocation;\n readonly related: readonly LiteralLocation[];\n}\n\nexport async function literalCommand(\n options: LiteralCommandOptions,\n): Promise<ValidationCommandResult> {\n const start = Date.now();\n\n const tsDetection = detectTypeScript(options.cwd);\n if (!tsDetection.present) {\n return {\n exitCode: EXIT_OK,\n output: options.quiet ? \"\" : TYPESCRIPT_ABSENT_MESSAGE,\n durationMs: Date.now() - start,\n };\n }\n\n if (!validationEnabled(\"LITERAL\")) {\n return {\n exitCode: EXIT_OK,\n output: options.quiet ? \"\" : DISABLED_MESSAGE,\n durationMs: Date.now() - start,\n };\n }\n\n let resolvedLiteralConfig: LiteralConfig;\n let resolvedPathConfig: ValidationPathConfig;\n if (options.config !== undefined) {\n resolvedLiteralConfig = options.config;\n resolvedPathConfig = options.pathConfig ?? validationConfigDescriptor.defaults.paths;\n } else {\n const loaded = await resolveConfig(options.cwd, [validationConfigDescriptor]);\n if (!loaded.ok) {\n return {\n exitCode: EXIT_CONFIG_ERROR,\n output: `Literal: ✗ config error — ${loaded.error}`,\n durationMs: Date.now() - start,\n };\n }\n const validationConfig = loaded.value[validationConfigDescriptor.section] as ValidationConfig;\n resolvedLiteralConfig = validationConfig.literal.values;\n resolvedPathConfig = validationConfig.paths;\n }\n\n const result = await validateLiteralReuse({\n projectRoot: options.cwd,\n files: options.files,\n config: resolvedLiteralConfig,\n pathConfig: resolvedPathConfig,\n });\n\n const filteredFindings = filterLiteralFindings(result.findings, options.kind);\n const totalProblems = countLiteralProblems(filteredFindings);\n const exitCode = totalProblems === 0 ? EXIT_OK : EXIT_FINDINGS;\n\n const output = options.json\n ? JSON.stringify(filteredFindings)\n : options.quiet\n ? \"\"\n : formatLiteralCommandOutput(filteredFindings, options);\n\n return { exitCode, output, durationMs: Date.now() - start };\n}\n\nexport function filterLiteralFindings(\n findings: DetectionResult,\n kind: LiteralProblemKind | undefined,\n): DetectionResult {\n return {\n srcReuse: kind === LITERAL_PROBLEM_KIND.DUPE ? [] : sortReuseFindings(findings.srcReuse),\n testDupe: kind === LITERAL_PROBLEM_KIND.REUSE ? [] : sortDupeFindings(findings.testDupe),\n };\n}\n\nexport function countLiteralProblems(findings: DetectionResult): number {\n return findings.srcReuse.length + findings.testDupe.length;\n}\n\nexport function formatDefaultLiteralProblems(findings: DetectionResult): string {\n return toLiteralProblems(findings)\n .map((problem) =>\n `[${problem.problemKind}] ${formatLiteralValue(problem.literalKind, problem.value)} ${formatLoc(problem.test)}`\n )\n .join(\"\\n\");\n}\n\nexport function formatVerboseLiteralProblems(findings: DetectionResult): string {\n const lines = [\n `Literal: ${\n countLiteralProblems(findings)\n } problems (reuse: ${findings.srcReuse.length}, dupe: ${findings.testDupe.length})`,\n ];\n\n appendVerboseSection(\n lines,\n \"REUSE\",\n findings.srcReuse.map((finding): LiteralProblem => ({\n problemKind: LITERAL_PROBLEM_KIND.REUSE,\n literalKind: finding.kind,\n value: finding.value,\n test: finding.test,\n related: finding.src,\n })),\n );\n appendVerboseSection(\n lines,\n \"DUPE\",\n findings.testDupe.map((finding): LiteralProblem => ({\n problemKind: LITERAL_PROBLEM_KIND.DUPE,\n literalKind: finding.kind,\n value: finding.value,\n test: finding.test,\n related: finding.otherTests,\n })),\n );\n\n return lines.join(\"\\n\");\n}\n\nexport function formatFilesWithProblems(findings: DetectionResult): string {\n return [...new Set(toLiteralProblems(findings).map((problem) => problem.test.file))]\n .sort()\n .join(\"\\n\");\n}\n\nexport function formatLiteralValues(findings: DetectionResult): string {\n const values = new Map<string, { readonly kind: LiteralKind; readonly value: string }>();\n for (const problem of toLiteralProblems(findings)) {\n values.set(`${problem.literalKind}\\0${problem.value}`, {\n kind: problem.literalKind,\n value: problem.value,\n });\n }\n return [...values.values()]\n .sort((left, right) => left.value.localeCompare(right.value) || left.kind.localeCompare(right.kind))\n .map((entry) => formatLiteralValue(entry.kind, entry.value))\n .join(\"\\n\");\n}\n\nfunction formatLiteralCommandOutput(\n findings: DetectionResult,\n options: LiteralCommandOptions,\n): string {\n const totalProblems = countLiteralProblems(findings);\n\n if (totalProblems === 0 && options.kind !== undefined) {\n return formatNoProblemsOfKind(options.kind);\n }\n\n if (totalProblems === 0) {\n return options.filesWithProblems || options.literals || options.verbose ? \"\" : NO_PROBLEMS_MESSAGE;\n }\n\n if (options.filesWithProblems) return formatFilesWithProblems(findings);\n if (options.literals) return formatLiteralValues(findings);\n if (options.verbose) return formatVerboseLiteralProblems(findings);\n return formatDefaultLiteralProblems(findings);\n}\n\nfunction toLiteralProblems(findings: DetectionResult): readonly LiteralProblem[] {\n return [\n ...sortReuseFindings(findings.srcReuse).map((finding): LiteralProblem => ({\n problemKind: LITERAL_PROBLEM_KIND.REUSE,\n literalKind: finding.kind,\n value: finding.value,\n test: finding.test,\n related: finding.src,\n })),\n ...sortDupeFindings(findings.testDupe).map((finding): LiteralProblem => ({\n problemKind: LITERAL_PROBLEM_KIND.DUPE,\n literalKind: finding.kind,\n value: finding.value,\n test: finding.test,\n related: finding.otherTests,\n })),\n ];\n}\n\nfunction appendVerboseSection(\n lines: string[],\n heading: string,\n problems: readonly LiteralProblem[],\n): void {\n const sortedProblems = [...problems].sort(compareLiteralProblems);\n if (sortedProblems.length === 0) return;\n\n lines.push(heading);\n let currentFile: string | undefined;\n for (const problem of sortedProblems) {\n if (problem.test.file !== currentFile) {\n lines.push(problem.test.file);\n currentFile = problem.test.file;\n }\n lines.push(\n ` line ${problem.test.line}: ${formatLiteralValue(problem.literalKind, problem.value)} also in ${\n problem.related.map(formatLoc).join(\", \")\n }`,\n );\n }\n}\n\nfunction sortReuseFindings(findings: readonly ReuseFinding[]): readonly ReuseFinding[] {\n return [...findings].sort(compareFindings);\n}\n\nfunction sortDupeFindings(findings: readonly DupeFinding[]): readonly DupeFinding[] {\n return [...findings].sort(compareFindings);\n}\n\nfunction compareFindings(\n left: { readonly kind: LiteralKind; readonly value: string; readonly test: LiteralLocation },\n right: { readonly kind: LiteralKind; readonly value: string; readonly test: LiteralLocation },\n): number {\n return (\n left.test.file.localeCompare(right.test.file)\n || left.test.line - right.test.line\n || left.kind.localeCompare(right.kind)\n || left.value.localeCompare(right.value)\n );\n}\n\nfunction compareLiteralProblems(left: LiteralProblem, right: LiteralProblem): number {\n return (\n left.test.file.localeCompare(right.test.file)\n || left.test.line - right.test.line\n || left.literalKind.localeCompare(right.literalKind)\n || left.value.localeCompare(right.value)\n );\n}\n\nfunction formatLiteralValue(kind: LiteralKind, value: string): string {\n return kind === \"string\" ? `\"${value}\"` : value;\n}\n\nfunction formatLoc(loc: LiteralLocation): string {\n return `${loc.file}:${loc.line}`;\n}\n","/**\n * Markdown validation step.\n *\n * Validates markdown files using markdownlint-cli2's programmatic API.\n * Configuration is built in code and passed via optionsOverride --\n * no config files are written to validated directories.\n *\n * @module validation/steps/markdown\n */\n\nimport { existsSync } from \"node:fs\";\nimport { basename, join } from \"node:path\";\n\nimport { createIgnoreSourceReader, IGNORE_SOURCE_FILENAME_DEFAULT } from \"@/lib/file-inclusion/ignore-source\";\nimport { SPEC_TREE_CONFIG } from \"@/lib/spec-tree/config\";\n\n// @ts-expect-error markdownlint-cli2 has no TypeScript type declarations\nimport { main as markdownlintMain } from \"markdownlint-cli2\";\nimport relativeLinksRule from \"markdownlint-rule-relative-links\";\n\n// =============================================================================\n// CONSTANTS\n// =============================================================================\n\n/** Default directories to validate when no --files are specified. */\nconst DEFAULT_DIRECTORY_NAMES = [\"spx\", \"docs\"] as const;\n\n/** Built-in markdownlint rules enabled for validation (MD024 excluded — configured per directory). */\nconst ENABLED_RULES = {\n MD001: true,\n MD003: true,\n MD009: true,\n MD010: true,\n MD025: true,\n MD047: true,\n} as const;\n\n/** Directories where MD024 is disabled entirely (generated/repetitive headings are normal). */\nconst MD024_DISABLED_DIRECTORIES = [\"docs\"] as const;\n\nexport const MARKDOWN_CUSTOM_RULE_NAMES = relativeLinksRule.names;\n\n/**\n * Pattern for parsing markdownlint-cli2 default formatter output.\n * Format: filename:line[:column] [severity] ruleName/ruleAlias description [detail] [context]\n */\nconst ERROR_LINE_PATTERN = /^(.+?):(\\d+)(?::\\d+)?\\s+(.+)$/;\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\n/** A structured error from markdown validation. */\nexport interface MarkdownError {\n /** Absolute path to the file containing the error. */\n file: string;\n /** Line number where the error occurs (1-based). */\n line: number;\n /** Description of the error including rule name and detail. */\n detail: string;\n}\n\n/** Result of markdown validation. */\nexport interface MarkdownValidationResult {\n /** Whether all files passed validation. */\n success: boolean;\n /** Structured errors found during validation. */\n errors: MarkdownError[];\n}\n\n/** A markdownlint custom rule object. */\ninterface MarkdownlintRule {\n names: string[];\n description: string;\n tags: string[];\n}\n\n/** Options for the validateMarkdown function. */\nexport interface ValidateMarkdownOptions {\n /** Directories to validate. */\n directories: string[];\n /** Project root for resolving project-absolute links. */\n projectRoot?: string;\n}\n\n// =============================================================================\n// CONFIGURATION\n// =============================================================================\n\n/**\n * Build the markdownlint configuration object.\n *\n * MD024 (no duplicate headings) is configured per directory:\n * - `spx/` and other spec directories: `siblings_only` — allows same heading\n * under different parents, flags true sibling duplicates\n * - `docs/`: disabled — generated/repetitive docs commonly reuse headings\n *\n * @param directoryName - Basename of the directory being validated (e.g. \"spx\", \"docs\")\n * @returns Configuration object for markdownlint-cli2's optionsOverride\n */\nexport function buildMarkdownlintConfig(directoryName: string): {\n default: boolean;\n MD001: boolean;\n MD003: boolean;\n MD009: boolean;\n MD010: boolean;\n MD024: boolean | { siblings_only: boolean };\n MD025: boolean;\n MD047: boolean;\n customRules: MarkdownlintRule[];\n} {\n const md024Disabled = MD024_DISABLED_DIRECTORIES.includes(\n directoryName as (typeof MD024_DISABLED_DIRECTORIES)[number],\n );\n\n return {\n default: false,\n ...ENABLED_RULES,\n MD024: md024Disabled ? false : { siblings_only: true },\n customRules: [relativeLinksRule],\n };\n}\n\n// =============================================================================\n// DEFAULT DIRECTORIES\n// =============================================================================\n\n/**\n * Get the default directories to validate.\n *\n * Returns absolute paths for spx/ and docs/ directories that exist\n * within the given project root. This is a pure function for testability.\n *\n * @param projectRoot - Absolute path to the project root\n * @returns Array of absolute paths to existing default directories\n */\nexport function getDefaultDirectories(projectRoot: string): string[] {\n return DEFAULT_DIRECTORY_NAMES\n .map((name) => join(projectRoot, name))\n .filter((dir) => existsSync(dir));\n}\n\n// =============================================================================\n// EXCLUDE SUPPORT\n// =============================================================================\n\n/**\n * Read node paths from spx/EXCLUDE and return them as ignore globs.\n *\n * Declared-state nodes have [test] links pointing to files that do not\n * exist yet. Listing them in spx/EXCLUDE tells markdown validation to\n * skip those directories so broken [test] links are not flagged.\n *\n * @param projectRoot - Absolute path to the project root\n * @returns Array of glob patterns to ignore (relative to the validated directory)\n */\nexport function getExcludeGlobs(projectRoot: string | undefined): string[] {\n if (projectRoot === undefined) return [];\n const reader = createIgnoreSourceReader(projectRoot, {\n ignoreSourceFilename: IGNORE_SOURCE_FILENAME_DEFAULT,\n specTreeRootSegment: SPEC_TREE_CONFIG.ROOT_DIRECTORY,\n });\n return reader.entries().map((entry) => `${entry.segment}/**`);\n}\n\n// =============================================================================\n// ERROR PARSING\n// =============================================================================\n\n/**\n * Pattern matching data URIs (data:image/..., data:text/..., etc.).\n * markdownlint-rule-relative-links does not handle data URIs natively\n * and reports them as broken relative links. Filter them out.\n */\nconst DATA_URI_PATTERN = /\\bdata:/;\n\n/**\n * Parse a line of markdownlint-cli2 default formatter output into a structured error.\n *\n * Filters out false positives from data URIs.\n *\n * @param line - A single line of error output\n * @returns Parsed MarkdownError, or null if the line is not a real error\n */\nfunction parseErrorLine(line: string): MarkdownError | null {\n if (DATA_URI_PATTERN.test(line)) {\n return null;\n }\n const match = ERROR_LINE_PATTERN.exec(line);\n if (!match) {\n return null;\n }\n const [, file, lineStr, detail] = match;\n return {\n file,\n line: parseInt(lineStr, 10),\n detail,\n };\n}\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate markdown files in the specified directories.\n *\n * Uses markdownlint-cli2's programmatic API with in-code configuration.\n * No config files are written to validated directories.\n *\n * @param options - Validation options including directories and project root\n * @returns Validation result with success status and structured errors\n *\n * @example\n * ```typescript\n * const result = await validateMarkdown({\n * directories: [\"/path/to/spx\", \"/path/to/docs\"],\n * projectRoot: \"/path/to/project\",\n * });\n * if (!result.success) {\n * for (const error of result.errors) {\n * console.error(`${error.file}:${error.line} ${error.detail}`);\n * }\n * }\n * ```\n */\nexport async function validateMarkdown(\n options: ValidateMarkdownOptions,\n): Promise<MarkdownValidationResult> {\n const { directories, projectRoot } = options;\n const errors: MarkdownError[] = [];\n const excludeGlobs = getExcludeGlobs(projectRoot);\n\n for (const directory of directories) {\n const dirName = basename(directory);\n const config = buildMarkdownlintConfig(dirName);\n const dirErrors = await validateDirectory(directory, config, projectRoot, excludeGlobs);\n errors.push(...dirErrors);\n }\n\n return {\n success: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Validate a single directory using markdownlint-cli2's programmatic API.\n *\n * @param directory - Absolute path to the directory to validate\n * @param config - Markdownlint configuration object\n * @param projectRoot - Optional project root for resolving project-absolute links\n * @returns Array of structured errors found in the directory\n */\nasync function validateDirectory(\n directory: string,\n config: ReturnType<typeof buildMarkdownlintConfig>,\n projectRoot?: string,\n ignoreGlobs: string[] = [],\n): Promise<MarkdownError[]> {\n const errors: MarkdownError[] = [];\n\n const { customRules, ...markdownlintConfig } = config;\n\n const optionsOverride: Record<string, unknown> = {\n config: {\n ...markdownlintConfig,\n \"relative-links\": projectRoot ? { root_path: projectRoot } : true,\n },\n customRules,\n noProgress: true,\n noBanner: true,\n ...(ignoreGlobs.length > 0 ? { ignores: ignoreGlobs } : {}),\n };\n\n await markdownlintMain({\n directory,\n argv: [\"**/*.md\"],\n optionsOverride,\n noImport: true,\n logMessage: () => {},\n logError: (message: string) => {\n const parsed = parseErrorLine(message);\n if (parsed) {\n errors.push({\n ...parsed,\n file: join(directory, parsed.file),\n });\n }\n },\n });\n\n return errors;\n}\n","/**\n * Markdown validation command.\n *\n * Runs markdownlint-cli2 for markdown link integrity and structural quality.\n * Unlike other validation commands, this does not use discoverTool() --\n * markdownlint-cli2 is a production dependency, always available.\n */\n\nimport { getDefaultDirectories, validateMarkdown } from \"@/validation/steps/markdown\";\nimport type { MarkdownCommandOptions, ValidationCommandResult } from \"./types\";\n\n/**\n * Run markdown validation.\n *\n * Validates markdown files in the specified directories (or defaults to\n * spx/ and docs/). Returns structured results with exit code and output.\n *\n * @param options - Command options including cwd and optional file scoping\n * @returns Command result with exit code and output\n *\n * @example\n * ```typescript\n * // Validate default directories\n * const result = await markdownCommand({ cwd: process.cwd() });\n *\n * // Validate specific directories\n * const result = await markdownCommand({\n * cwd: process.cwd(),\n * files: [\"/path/to/spx\"],\n * });\n * ```\n */\nconst MARKDOWN_EXTENSIONS = new Set([\".md\", \".markdown\"]);\nexport const MARKDOWN_COMMAND_OUTPUT = {\n ERROR_SUMMARY_SUFFIX: \"error(s) found\",\n NO_ISSUES: \"Markdown: No issues found\",\n} as const;\n\nfunction isMarkdownOrDirectory(path: string): boolean {\n const lastDot = path.lastIndexOf(\".\");\n if (lastDot < 0) return true;\n const ext = path.slice(lastDot).toLowerCase();\n return MARKDOWN_EXTENSIONS.has(ext);\n}\n\nexport async function markdownCommand(options: MarkdownCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, files, quiet } = options;\n const startTime = Date.now();\n\n const markdownScopedFiles = files?.filter(isMarkdownOrDirectory);\n\n const directories = markdownScopedFiles && markdownScopedFiles.length > 0\n ? markdownScopedFiles\n : files && files.length > 0\n ? []\n : getDefaultDirectories(cwd);\n\n if (directories.length === 0) {\n const reason = files && files.length > 0\n ? \"no markdown files in --files scope\"\n : \"no spx/ or docs/ directories found\";\n const output = quiet ? \"\" : `Markdown: skipped (${reason})`;\n return { exitCode: 0, output, durationMs: Date.now() - startTime };\n }\n\n // Run markdown validation\n const result = await validateMarkdown({\n directories,\n projectRoot: cwd,\n });\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : MARKDOWN_COMMAND_OUTPUT.NO_ISSUES;\n return { exitCode: 0, output, durationMs };\n } else {\n const errorLines = result.errors.map(\n (error) => ` ${error.file}:${error.line} ${error.detail}`,\n );\n const output = [`Markdown: ${result.errors.length} ${MARKDOWN_COMMAND_OUTPUT.ERROR_SUMMARY_SUFFIX}`, ...errorLines]\n .join(\"\\n\");\n return { exitCode: 1, output, durationMs };\n }\n}\n","/**\n * TypeScript validation step.\n *\n * Validates TypeScript code using the tsc compiler.\n *\n * @module validation/steps/typescript\n */\n\nimport { existsSync, mkdirSync, rmSync, writeFileSync } from \"node:fs\";\nimport { mkdtemp } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { isAbsolute, join } from \"node:path\";\n\nimport { lifecycleProcessRunner } from \"@/lib/process-lifecycle\";\nimport { TSCONFIG_FILES } from \"../config/scope\";\nimport type { ProcessRunner, ScopeConfig, ValidationScope } from \"../types\";\nimport { VALIDATION_SCOPES } from \"../types\";\n\n// =============================================================================\n// DEFAULT DEPENDENCIES\n// =============================================================================\n\n/**\n * Default production process runner for TypeScript.\n */\nexport const defaultTypeScriptProcessRunner: ProcessRunner = lifecycleProcessRunner;\n\n/**\n * Dependencies for file-specific TypeScript validation.\n */\nexport interface TypeScriptDeps {\n mkdtemp: typeof mkdtemp;\n writeFileSync: typeof writeFileSync;\n rmSync: typeof rmSync;\n existsSync: typeof existsSync;\n mkdirSync: typeof mkdirSync;\n}\n\n/**\n * Default production dependencies.\n */\nexport const defaultTypeScriptDeps: TypeScriptDeps = {\n mkdtemp,\n writeFileSync,\n rmSync,\n existsSync,\n mkdirSync,\n};\n\n// =============================================================================\n// PURE ARGUMENT BUILDER\n// =============================================================================\n\n/**\n * Build TypeScript CLI arguments based on validation scope.\n *\n * Pure function for testability - can be verified at Level 1.\n *\n * @param context - Context for building arguments\n * @returns Array of tsc CLI arguments\n *\n * @example\n * ```typescript\n * const args = buildTypeScriptArgs({ scope: \"full\", configFile: \"tsconfig.json\" });\n * // Returns: [\"tsc\", \"--noEmit\"]\n * ```\n */\nexport function buildTypeScriptArgs(context: { scope: ValidationScope; configFile: string }): string[] {\n const { scope, configFile } = context;\n return scope === VALIDATION_SCOPES.FULL ? [\"tsc\", \"--noEmit\"] : [\"tsc\", \"--project\", configFile];\n}\n\n// =============================================================================\n// FILE-SPECIFIC VALIDATION SUPPORT\n// =============================================================================\n\n/**\n * Create a temporary TypeScript configuration file for file-specific validation.\n *\n * @param scope - Validation scope\n * @param files - Files to validate\n * @param deps - Injectable dependencies\n * @returns Config path and cleanup function\n */\nexport async function createFileSpecificTsconfig(\n scope: ValidationScope,\n files: string[],\n deps: TypeScriptDeps = defaultTypeScriptDeps,\n): Promise<{ configPath: string; tempDir: string; cleanup: () => void }> {\n // Create temporary directory\n const tempDir = await deps.mkdtemp(join(tmpdir(), \"validate-ts-\"));\n const configPath = join(tempDir, \"tsconfig.json\");\n\n // Get base config file\n const baseConfigFile = TSCONFIG_FILES[scope];\n\n // Ensure all file paths are absolute\n const projectRoot = process.cwd();\n const absoluteFiles = files.map((file) => (isAbsolute(file) ? file : join(projectRoot, file)));\n\n // Create temporary tsconfig that extends the base config\n const tempConfig = {\n extends: join(projectRoot, baseConfigFile),\n files: absoluteFiles,\n include: [],\n exclude: [],\n compilerOptions: {\n noEmit: true,\n typeRoots: [join(projectRoot, \"node_modules\", \"@types\")],\n types: [\"node\"],\n },\n };\n\n // Write temporary config\n deps.writeFileSync(configPath, JSON.stringify(tempConfig, null, 2));\n\n // Return config path and cleanup function\n const cleanup = () => {\n try {\n deps.rmSync(tempDir, { recursive: true, force: true });\n } catch {\n // Cleanup error - don't fail validation\n }\n };\n\n return { configPath, tempDir, cleanup };\n}\n\n// =============================================================================\n// VALIDATION FUNCTION\n// =============================================================================\n\n/**\n * Validate TypeScript using authoritative configuration.\n *\n * @param scope - Validation scope\n * @param typescriptScope - Scope configuration from tsconfig\n * @param files - Optional specific files to validate\n * @param runner - Injectable process runner\n * @param deps - Injectable TypeScript dependencies\n * @returns Promise resolving to validation result\n *\n * @example\n * ```typescript\n * const result = await validateTypeScript(\"full\", scopeConfig);\n * if (!result.success) {\n * console.error(\"TypeScript failed:\", result.error);\n * }\n * ```\n */\nexport async function validateTypeScript(\n scope: ValidationScope,\n typescriptScope: ScopeConfig,\n files?: string[],\n runner: ProcessRunner = defaultTypeScriptProcessRunner,\n deps: TypeScriptDeps = defaultTypeScriptDeps,\n): Promise<{\n success: boolean;\n error?: string;\n skipped?: boolean;\n}> {\n const configFile = TSCONFIG_FILES[scope];\n\n // Determine tool and arguments based on whether specific files are provided\n let tool: string;\n let tscArgs: string[];\n\n if (files && files.length > 0) {\n // File-specific validation using custom temporary tsconfig\n const { configPath, cleanup } = await createFileSpecificTsconfig(scope, files, deps);\n\n try {\n return await new Promise((resolve) => {\n const tscBin = join(process.cwd(), \"node_modules\", \".bin\", \"tsc\");\n const tscBinary = existsSync(tscBin) ? tscBin : \"npx\";\n const tscArgs = tscBinary === \"npx\" ? [\"tsc\", \"--project\", configPath] : [\"--project\", configPath];\n const tscProcess = runner.spawn(tscBinary, tscArgs, {\n cwd: process.cwd(),\n stdio: \"inherit\",\n });\n\n tscProcess.on(\"close\", (code) => {\n cleanup();\n if (code === 0) {\n resolve({ success: true, skipped: false });\n } else {\n resolve({ success: false, error: `TypeScript exited with code ${code}` });\n }\n });\n\n tscProcess.on(\"error\", (error) => {\n cleanup();\n resolve({ success: false, error: error.message });\n });\n });\n } catch (error) {\n cleanup();\n const errorMessage = error instanceof Error ? error.message : String(error);\n return { success: false, error: `Failed to create temporary config: ${errorMessage}` };\n }\n } else {\n // Full validation using tsc\n const tscBin = join(process.cwd(), \"node_modules\", \".bin\", \"tsc\");\n tool = existsSync(tscBin) ? tscBin : \"npx\";\n const rawArgs = buildTypeScriptArgs({ scope, configFile });\n tscArgs = tool === \"npx\" ? rawArgs : rawArgs.slice(1);\n }\n\n return new Promise((resolve) => {\n const tscProcess = runner.spawn(tool, tscArgs, {\n cwd: process.cwd(),\n stdio: \"inherit\",\n });\n\n tscProcess.on(\"close\", (code) => {\n if (code === 0) {\n resolve({ success: true, skipped: false });\n } else {\n resolve({ success: false, error: `TypeScript exited with code ${code}` });\n }\n });\n\n tscProcess.on(\"error\", (error) => {\n resolve({ success: false, error: error.message });\n });\n });\n}\n","/**\n * TypeScript validation command.\n *\n * Runs TypeScript type checking using tsc.\n */\nimport { getTypeScriptScope } from \"@/validation/config/scope\";\nimport { detectTypeScript, discoverTool, formatSkipMessage } from \"@/validation/discovery/index\";\nimport { validateTypeScript } from \"@/validation/steps/typescript\";\nimport type { TypeScriptCommandOptions, ValidationCommandResult } from \"./types\";\n\nconst TYPESCRIPT_ABSENT_MESSAGE = \"⏭ Skipping TypeScript (TypeScript not detected in project)\";\n\n/**\n * Run TypeScript type checking.\n *\n * Gates tsc execution on language detection: without a `tsconfig.json` in the\n * project root there is nothing to type-check, and invoking tsc regardless\n * causes it to walk up and compile an ancestor project instead.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function typescriptCommand(options: TypeScriptCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, scope = \"full\", files, quiet } = options;\n const startTime = Date.now();\n\n // Gate 1: language detection. No TypeScript = skip cleanly.\n const tsDetection = detectTypeScript(cwd);\n if (!tsDetection.present) {\n return {\n exitCode: 0,\n output: quiet ? \"\" : TYPESCRIPT_ABSENT_MESSAGE,\n durationMs: Date.now() - startTime,\n };\n }\n\n // Gate 2: tool discovery — ensure tsc itself is available somewhere.\n const toolResult = await discoverTool(\"typescript\", { projectRoot: cwd });\n if (!toolResult.found) {\n const skipMessage = formatSkipMessage(\"TypeScript\", toolResult);\n return { exitCode: 0, output: skipMessage, durationMs: Date.now() - startTime };\n }\n\n // Get scope configuration from tsconfig\n const scopeConfig = getTypeScriptScope(scope);\n\n // Run TypeScript validation\n const result = await validateTypeScript(scope, scopeConfig, files);\n const durationMs = Date.now() - startTime;\n\n // Map result to command output\n if (result.success) {\n const output = quiet ? \"\" : `TypeScript: ✓ No type errors`;\n return { exitCode: 0, output, durationMs };\n } else {\n const output = result.error ?? \"TypeScript validation failed\";\n return { exitCode: 1, output, durationMs };\n }\n}\n","/**\n * Run all validations command.\n *\n * Executes all validation steps in sequence:\n * 1. Circular dependencies (fastest)\n * 2. Knip (optional)\n * 3. ESLint\n * 4. TypeScript\n * 5. Markdown\n * 6. Literal reuse\n */\nimport { circularCommand } from \"./circular\";\nimport { formatDuration, formatSummary } from \"./format\";\nimport { knipCommand } from \"./knip\";\nimport { lintCommand } from \"./lint\";\nimport { literalCommand } from \"./literal\";\nimport { markdownCommand } from \"./markdown\";\nimport type { AllCommandOptions, ValidationCommandResult } from \"./types\";\nimport { typescriptCommand } from \"./typescript\";\n\n/** Total number of validation steps */\nconst TOTAL_STEPS = 6;\nexport const LITERAL_SKIP_OUTPUT = \"Literal: skipped (--skip-literal)\";\nexport const LITERAL_SKIP_JSON_OUTPUT = JSON.stringify({\n skipped: true,\n reason: \"skip-literal\",\n});\n\n/**\n * Format step output with step number and timing.\n *\n * @param stepNumber - Current step number (1-indexed)\n * @param result - Validation result\n * @param quiet - Whether to suppress output\n * @returns Formatted output string\n */\nfunction formatStepWithTiming(\n stepNumber: number,\n result: ValidationCommandResult,\n quiet: boolean,\n): string {\n if (quiet || !result.output) return \"\";\n\n const timing = result.durationMs === undefined ? \"\" : ` (${formatDuration(result.durationMs)})`;\n return `[${stepNumber}/${TOTAL_STEPS}] ${result.output}${timing}`;\n}\n\n/**\n * Run all validation steps.\n *\n * @param options - Command options\n * @returns Command result with exit code and output\n */\nexport async function allCommand(options: AllCommandOptions): Promise<ValidationCommandResult> {\n const { cwd, scope, files, fix, quiet = false, json, skipLiteral = false } = options;\n const startTime = Date.now();\n const outputs: string[] = [];\n let hasFailure = false;\n\n // 1. Circular dependencies\n const circularResult = await circularCommand({ cwd, quiet, json });\n const circularOutput = formatStepWithTiming(1, circularResult, quiet);\n if (circularOutput) outputs.push(circularOutput);\n if (circularResult.exitCode !== 0) hasFailure = true;\n\n // 2. Knip (optional - skip on failure, it's informational)\n const knipResult = await knipCommand({ cwd, quiet, json });\n const knipOutput = formatStepWithTiming(2, knipResult, quiet);\n if (knipOutput) outputs.push(knipOutput);\n // Don't fail on knip - it's optional\n\n // 3. ESLint\n const lintResult = await lintCommand({ cwd, scope, files, fix, quiet, json });\n const lintOutput = formatStepWithTiming(3, lintResult, quiet);\n if (lintOutput) outputs.push(lintOutput);\n if (lintResult.exitCode !== 0) hasFailure = true;\n\n // 4. TypeScript\n const tsResult = await typescriptCommand({ cwd, scope, files, quiet, json });\n const tsOutput = formatStepWithTiming(4, tsResult, quiet);\n if (tsOutput) outputs.push(tsOutput);\n if (tsResult.exitCode !== 0) hasFailure = true;\n\n // 5. Markdown\n const markdownResult = await markdownCommand({ cwd, files, quiet });\n const markdownOutput = formatStepWithTiming(5, markdownResult, quiet);\n if (markdownOutput) outputs.push(markdownOutput);\n if (markdownResult.exitCode !== 0) hasFailure = true;\n\n // 6. Literal reuse\n const literalSkipOutput = json ? LITERAL_SKIP_JSON_OUTPUT : LITERAL_SKIP_OUTPUT;\n const literalResult = skipLiteral\n ? { exitCode: 0, output: quiet ? \"\" : literalSkipOutput }\n : await literalCommand({ cwd, files, quiet, json });\n const literalOutput = formatStepWithTiming(6, literalResult, quiet);\n if (literalOutput) outputs.push(literalOutput);\n if (literalResult.exitCode !== 0) hasFailure = true;\n\n // Calculate total duration\n const totalDurationMs = Date.now() - startTime;\n\n // Add summary line\n if (!quiet) {\n const summary = formatSummary({ success: !hasFailure, totalDurationMs });\n outputs.push(\"\", summary); // Empty line before summary\n }\n\n return {\n exitCode: hasFailure ? 1 : 0,\n output: outputs.join(\"\\n\"),\n durationMs: totalDurationMs,\n };\n}\n","export const MAX_CLI_ARGUMENT_DISPLAY_LENGTH = 120;\nexport const ELLIPSIS_TOKEN = \"...\";\n\nexport const SENTINEL_UNDEFINED = \"<undefined>\";\nexport const SENTINEL_NULL = \"<null>\";\nexport const SENTINEL_EMPTY = \"<empty>\";\n\nexport const CONTROL_CHAR_UPPER_BOUND = 0x1f;\nexport const DEL_CHAR_CODE = 0x7f;\nexport const FIRST_PRINTABLE_CHAR_CODE = 0x20;\n\nexport const HEX_RADIX = 16;\nexport const HEX_PAD = 2;\n\nexport function formatHexEscape(code: number): string {\n return `\\\\x${code.toString(HEX_RADIX).padStart(HEX_PAD, \"0\")}`;\n}\n\nexport function nonStringSentinel(type: string): string {\n return `<non-string:${type}>`;\n}\n\nexport function sanitizeCliArgument(input: unknown): string {\n if (input === undefined) return SENTINEL_UNDEFINED;\n if (input === null) return SENTINEL_NULL;\n if (typeof input !== \"string\") return nonStringSentinel(typeof input);\n if (input.length === 0) return SENTINEL_EMPTY;\n\n const escaped = escapeControlCharacters(input);\n return truncate(escaped);\n}\n\nfunction escapeControlCharacters(value: string): string {\n let out = \"\";\n for (const char of value) {\n const code = char.codePointAt(0);\n if (code === undefined) continue;\n if (code <= CONTROL_CHAR_UPPER_BOUND || code === DEL_CHAR_CODE) {\n out += formatHexEscape(code);\n } else {\n out += char;\n }\n }\n return out;\n}\n\nfunction truncate(value: string): string {\n if (value.length <= MAX_CLI_ARGUMENT_DISPLAY_LENGTH) return value;\n return value.slice(0, MAX_CLI_ARGUMENT_DISPLAY_LENGTH - ELLIPSIS_TOKEN.length) + ELLIPSIS_TOKEN;\n}\n","import { rename, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport {\n type ConfigFile,\n configFileForFormat,\n type ConfigFileReadResult,\n DEFAULT_CONFIG_FILE_FORMAT,\n formatConfigFileAmbiguityError,\n parseConfigFileSections,\n readProjectConfigFile,\n serializeConfigFileSectionsWithSetIn,\n} from \"@/config/index\";\nimport type { Result } from \"@/config/types\";\nimport {\n VALIDATION_LITERAL_SUBSECTION,\n VALIDATION_LITERAL_VALUES_SUBSECTION,\n VALIDATION_SECTION,\n} from \"@/validation/config/descriptor\";\n\nimport { type LiteralConfig, literalConfigDescriptor } from \"./config\";\nimport { validateLiteralReuse } from \"./index\";\n\nexport interface ConfigReader {\n read(projectRoot: string): Promise<Result<ConfigFileReadResult>>;\n}\n\nexport interface ConfigWriter {\n write(filePath: string, content: string): Promise<void>;\n}\n\nexport interface AllowlistExistingOptions {\n readonly projectRoot: string;\n readonly reader?: ConfigReader;\n readonly writer?: ConfigWriter;\n}\n\nexport interface AllowlistExistingResult {\n readonly exitCode: number;\n readonly output: string;\n}\n\nconst EXIT_OK = 0;\nconst EXIT_ERROR = 1;\nconst ALLOWLIST_FIELD = \"allowlist\";\nconst INCLUDE_FIELD = \"include\";\nconst ALLOWLIST_INCLUDE_PATH = [\n VALIDATION_SECTION,\n VALIDATION_LITERAL_SUBSECTION,\n VALIDATION_LITERAL_VALUES_SUBSECTION,\n ALLOWLIST_FIELD,\n INCLUDE_FIELD,\n] as const;\nconst TEMP_FILE_PREFIX = \".spx-allowlist-existing-\";\nconst TEMP_FILE_SUFFIX = \".tmp\";\nconst RANDOM_BASE = 36;\nconst RANDOM_PREFIX_SLICE = 2;\nconst RANDOM_TOKEN_LENGTH = 10;\n\nexport const productionReader: ConfigReader = {\n read: readProjectConfigFile,\n};\n\nexport const productionWriter: ConfigWriter = {\n async write(filePath: string, content: string): Promise<void> {\n const dir = dirname(filePath);\n const random = Math.random()\n .toString(RANDOM_BASE)\n .slice(RANDOM_PREFIX_SLICE, RANDOM_PREFIX_SLICE + RANDOM_TOKEN_LENGTH);\n const tmpPath = join(dir, `${TEMP_FILE_PREFIX}${random}${TEMP_FILE_SUFFIX}`);\n await writeFile(tmpPath, content, \"utf8\");\n await rename(tmpPath, filePath);\n },\n};\n\nexport async function allowlistExisting(\n options: AllowlistExistingOptions,\n): Promise<AllowlistExistingResult> {\n const reader = options.reader ?? productionReader;\n const writer = options.writer ?? productionWriter;\n\n const readResult = await reader.read(options.projectRoot);\n if (!readResult.ok) {\n return { exitCode: EXIT_ERROR, output: readResult.error };\n }\n\n const configRead = readResult.value;\n if (configRead.kind === \"ambiguous\") {\n return { exitCode: EXIT_ERROR, output: formatConfigFileAmbiguityError(configRead.detected) };\n }\n\n const currentLiteralConfig = readCurrentLiteralConfig(configRead);\n if (!currentLiteralConfig.ok) {\n return { exitCode: EXIT_ERROR, output: currentLiteralConfig.error };\n }\n\n const detection = await validateLiteralReuse({\n projectRoot: options.projectRoot,\n config: currentLiteralConfig.value,\n });\n\n const findingValues = collectFindingValues(detection.findings);\n const updatedInclude = computeUpdatedInclude(\n currentLiteralConfig.value.allowlist.include,\n findingValues,\n );\n\n const target: ConfigFile = configRead.kind === \"ok\"\n ? configRead.file\n : configFileForFormat(options.projectRoot, DEFAULT_CONFIG_FILE_FORMAT);\n\n const serialized = serializeWithUpdatedInclude(target, updatedInclude);\n if (!serialized.ok) {\n return { exitCode: EXIT_ERROR, output: serialized.error };\n }\n await writer.write(target.path, serialized.value);\n\n return { exitCode: EXIT_OK, output: \"\" };\n}\n\nfunction readCurrentLiteralConfig(read: ConfigFileReadResult): Result<LiteralConfig> {\n if (read.kind !== \"ok\") return { ok: true, value: literalConfigDescriptor.defaults };\n const sections = parseConfigFileSections(read.file);\n if (!sections.ok) return sections;\n const validationRaw = sections.value[VALIDATION_SECTION];\n if (typeof validationRaw !== \"object\" || validationRaw === null) {\n return { ok: true, value: literalConfigDescriptor.defaults };\n }\n const literalRaw = (validationRaw as Record<string, unknown>)[VALIDATION_LITERAL_SUBSECTION];\n if (typeof literalRaw !== \"object\" || literalRaw === null) {\n return { ok: true, value: literalConfigDescriptor.defaults };\n }\n const valuesRaw = (literalRaw as Record<string, unknown>)[VALIDATION_LITERAL_VALUES_SUBSECTION];\n if (valuesRaw === undefined) {\n return { ok: true, value: literalConfigDescriptor.defaults };\n }\n const validated = literalConfigDescriptor.validate(valuesRaw);\n return validated.ok ? validated : { ok: true, value: literalConfigDescriptor.defaults };\n}\n\nfunction collectFindingValues(\n findings: {\n readonly srcReuse: readonly { readonly value: string }[];\n readonly testDupe: readonly { readonly value: string }[];\n },\n): readonly string[] {\n const values = new Set<string>();\n for (const finding of findings.srcReuse) values.add(finding.value);\n for (const finding of findings.testDupe) values.add(finding.value);\n return [...values];\n}\n\nfunction computeUpdatedInclude(\n existing: readonly string[] | undefined,\n findingValues: readonly string[],\n): readonly string[] {\n const existingArr = existing ?? [];\n const existingSet = new Set(existingArr);\n const additions = findingValues.filter((value) => !existingSet.has(value)).sort();\n return [...existingArr, ...additions];\n}\n\nfunction serializeWithUpdatedInclude(target: ConfigFile, include: readonly string[]): Result<string> {\n return serializeConfigFileSectionsWithSetIn(target, ALLOWLIST_INCLUDE_PATH, [...include]);\n}\n","/**\n * Validation domain - Run code validation tools\n *\n * Provides CLI commands for running validation tools (TypeScript, ESLint, etc.)\n * as a globally-installed tool across TypeScript projects.\n */\nimport type { Command } from \"commander\";\n\nimport {\n allCommand,\n circularCommand,\n knipCommand,\n lintCommand,\n LITERAL_PROBLEM_KIND,\n literalCommand,\n type LiteralProblemKind,\n markdownCommand,\n typescriptCommand,\n} from \"@/commands/validation\";\nimport { sanitizeCliArgument } from \"@/interfaces/cli/sanitize\";\nimport { allowlistExisting } from \"@/validation/literal/allowlist-existing\";\nimport type { ValidationScope } from \"@/validation/types\";\nimport type { Domain } from \"../types\";\n\ninterface ValidationDomainCommandDefinition {\n readonly commandName: string;\n readonly alias: string;\n readonly description: string;\n}\n\ninterface ValidationSubcommandDefinition {\n readonly commandName: string;\n readonly alias?: string;\n readonly description: string;\n}\n\ninterface ValidationCliDefinition {\n readonly domain: ValidationDomainCommandDefinition;\n readonly subcommands: {\n readonly typescript: ValidationSubcommandDefinition;\n readonly lint: ValidationSubcommandDefinition;\n readonly circular: ValidationSubcommandDefinition;\n readonly knip: ValidationSubcommandDefinition;\n readonly literal: ValidationSubcommandDefinition;\n readonly markdown: ValidationSubcommandDefinition;\n readonly all: ValidationSubcommandDefinition;\n };\n readonly commanderHelpOperands: {\n readonly subcommand: string;\n readonly longFlag: string;\n readonly shortFlag: string;\n };\n readonly diagnostics: {\n readonly unknownSubcommand: {\n readonly messageLabel: string;\n readonly exitCode: number;\n };\n readonly unknownLiteralProblemKind: {\n readonly messageLabel: string;\n readonly exitCode: number;\n };\n };\n}\n\nexport const validationCliDefinition: ValidationCliDefinition = {\n domain: {\n commandName: \"validation\",\n alias: \"v\",\n description: \"Run code validation tools\",\n },\n subcommands: {\n typescript: {\n commandName: \"typescript\",\n alias: \"ts\",\n description: \"Run TypeScript type checking\",\n },\n lint: {\n commandName: \"lint\",\n description: \"Run ESLint\",\n },\n circular: {\n commandName: \"circular\",\n description: \"Check for circular dependencies\",\n },\n knip: {\n commandName: \"knip\",\n description: \"Detect unused code\",\n },\n literal: {\n commandName: \"literal\",\n description: \"Detect cross-file literal reuse between source and tests\",\n },\n markdown: {\n commandName: \"markdown\",\n alias: \"md\",\n description: \"Validate markdown link integrity and structure\",\n },\n all: {\n commandName: \"all\",\n description: \"Run all validations\",\n },\n },\n commanderHelpOperands: {\n subcommand: \"help\",\n longFlag: \"--help\",\n shortFlag: \"-h\",\n },\n diagnostics: {\n unknownSubcommand: {\n messageLabel: \"unknown subcommand\",\n exitCode: 1,\n },\n unknownLiteralProblemKind: {\n messageLabel: \"unknown problem kind\",\n exitCode: 1,\n },\n },\n} as const;\n\nexport const literalValidationCliOptions = {\n allowlistExisting: {\n flag: \"--allowlist-existing\",\n description: \"Append every current problem's value to literal.allowlist.include and exit\",\n },\n kind: {\n flag: \"--kind <kind>\",\n description: \"Only report one problem kind (reuse|dupe)\",\n },\n filesWithProblems: {\n flag: \"--files-with-problems\",\n description: \"Print each affected file path once\",\n },\n literals: {\n flag: \"--literals\",\n description: \"Print each affected literal value once\",\n },\n verbose: {\n flag: \"--verbose\",\n description: \"Print grouped problem details\",\n },\n} as const;\n\nexport const allValidationCliOptions = {\n skipLiteral: {\n flag: \"--skip-literal\",\n description: \"Skip literal reuse detection for this validation all run\",\n },\n} as const;\n\nconst validationSubcommandOperands = Object.values(validationCliDefinition.subcommands).flatMap(\n (subcommand) => {\n const operands = [subcommand.commandName];\n if (subcommand.alias !== undefined) operands.push(subcommand.alias);\n return operands;\n },\n);\n\nexport const validationKnownOperands: ReadonlySet<string> = new Set([\n ...validationSubcommandOperands,\n ...Object.values(validationCliDefinition.commanderHelpOperands),\n]);\nexport const validationOptionPrefix = validationCliDefinition.commanderHelpOperands.longFlag.slice(0, 1);\n\n/** Common options for all validation commands */\ninterface CommonOptions {\n scope?: ValidationScope;\n files?: string[];\n quiet?: boolean;\n json?: boolean;\n}\n\n/** Options for lint command */\ninterface LintOptions extends CommonOptions {\n fix?: boolean;\n}\n\ninterface LiteralOptions extends CommonOptions {\n allowlistExisting?: boolean;\n kind?: string;\n filesWithProblems?: boolean;\n literals?: boolean;\n verbose?: boolean;\n}\n\ninterface AllOptions extends CommonOptions {\n fix?: boolean;\n skipLiteral?: boolean;\n}\n\n/**\n * Add common options to a command\n */\nfunction addCommonOptions(cmd: Command): Command {\n return cmd\n .option(\"--scope <scope>\", \"Validation scope (full|production)\", \"full\")\n .option(\"--files <paths...>\", \"Specific files/directories to validate\")\n .option(\"--quiet\", \"Suppress progress output\")\n .option(\"--json\", \"Output results as JSON\");\n}\n\nfunction addValidationSubcommand(\n validationCmd: Command,\n definition: ValidationSubcommandDefinition,\n): Command {\n let subcommand = validationCmd\n .command(definition.commandName)\n .description(definition.description);\n\n if (definition.alias !== undefined) {\n subcommand = subcommand.alias(definition.alias);\n }\n\n return subcommand;\n}\n\n/**\n * Register validation domain commands\n */\nfunction registerValidationCommands(validationCmd: Command): void {\n const { subcommands } = validationCliDefinition;\n\n // typescript command\n const tsCmd = addValidationSubcommand(validationCmd, subcommands.typescript)\n .action(async (options: CommonOptions) => {\n const result = await typescriptCommand({\n cwd: process.cwd(),\n scope: options.scope,\n files: options.files,\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(tsCmd);\n\n // lint command\n const lintCmd = addValidationSubcommand(validationCmd, subcommands.lint)\n .option(\"--fix\", \"Auto-fix issues\")\n .action(async (options: LintOptions) => {\n const result = await lintCommand({\n cwd: process.cwd(),\n scope: options.scope,\n files: options.files,\n fix: options.fix,\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(lintCmd);\n\n // circular command\n const circularCmd = addValidationSubcommand(validationCmd, subcommands.circular)\n .action(async (options: CommonOptions) => {\n const result = await circularCommand({\n cwd: process.cwd(),\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(circularCmd);\n\n // knip command\n const knipCmd = addValidationSubcommand(validationCmd, subcommands.knip)\n .action(async (options: CommonOptions) => {\n const result = await knipCommand({\n cwd: process.cwd(),\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(knipCmd);\n\n // literal command (cross-file literal-reuse detector)\n const literalCmd = addValidationSubcommand(validationCmd, subcommands.literal)\n .option(\n literalValidationCliOptions.allowlistExisting.flag,\n literalValidationCliOptions.allowlistExisting.description,\n )\n .option(literalValidationCliOptions.kind.flag, literalValidationCliOptions.kind.description)\n .option(\n literalValidationCliOptions.filesWithProblems.flag,\n literalValidationCliOptions.filesWithProblems.description,\n )\n .option(literalValidationCliOptions.literals.flag, literalValidationCliOptions.literals.description)\n .option(literalValidationCliOptions.verbose.flag, literalValidationCliOptions.verbose.description)\n .addHelpText(\n \"after\",\n \"\\nEnabled for TypeScript projects by default. Set LITERAL_VALIDATION_ENABLED=0\\n\"\n + \"to skip (useful when migrating a project with many existing violations).\",\n )\n .action(async (options: LiteralOptions) => {\n if (options.allowlistExisting) {\n const result = await allowlistExisting({ projectRoot: process.cwd() });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n }\n let kind: LiteralProblemKind | undefined;\n if (options.kind !== undefined) {\n kind = parseLiteralProblemKind(options.kind);\n if (kind === undefined) {\n const { unknownLiteralProblemKind } = validationCliDefinition.diagnostics;\n process.stderr.write(\n `spx validation literal: ${unknownLiteralProblemKind.messageLabel}: ${sanitizeCliArgument(options.kind)}\\n`,\n );\n process.exit(unknownLiteralProblemKind.exitCode);\n }\n }\n const result = await literalCommand({\n cwd: process.cwd(),\n files: options.files,\n kind,\n filesWithProblems: options.filesWithProblems,\n literals: options.literals,\n verbose: options.verbose,\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(literalCmd);\n\n // markdown command\n const markdownCmd = addValidationSubcommand(validationCmd, subcommands.markdown)\n .addHelpText(\n \"after\",\n \"\\nValidates spx/ and docs/ by default. Nodes listed in spx/EXCLUDE are\\n\"\n + \"skipped — use this for declared-state nodes whose [test] links point\\n\"\n + \"to files that do not exist yet.\",\n )\n .action(async (options: CommonOptions) => {\n const result = await markdownCommand({\n cwd: process.cwd(),\n files: options.files,\n quiet: options.quiet,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(markdownCmd);\n\n // all command\n const allCmd = addValidationSubcommand(validationCmd, subcommands.all)\n .option(\"--fix\", \"Auto-fix ESLint issues\")\n .option(allValidationCliOptions.skipLiteral.flag, allValidationCliOptions.skipLiteral.description)\n .action(async (options: AllOptions) => {\n const result = await allCommand({\n cwd: process.cwd(),\n scope: options.scope,\n files: options.files,\n fix: options.fix,\n skipLiteral: options.skipLiteral,\n quiet: options.quiet,\n json: options.json,\n });\n if (result.output) console.log(result.output);\n process.exit(result.exitCode);\n });\n addCommonOptions(allCmd);\n}\n\nfunction parseLiteralProblemKind(value: string): LiteralProblemKind | undefined {\n if (value === LITERAL_PROBLEM_KIND.REUSE || value === LITERAL_PROBLEM_KIND.DUPE) {\n return value;\n }\n return undefined;\n}\n\n/**\n * Validation domain - Run code validation tools\n */\nfunction handleUnknownSubcommand(operands: readonly string[]): never {\n const [first] = operands;\n const sanitized = sanitizeCliArgument(first);\n const { domain, diagnostics } = validationCliDefinition;\n const { unknownSubcommand } = diagnostics;\n process.stderr.write(`spx ${domain.commandName}: ${unknownSubcommand.messageLabel}: ${sanitized}\\n`);\n process.exit(unknownSubcommand.exitCode);\n}\n\nexport const validationDomain: Domain = {\n name: validationCliDefinition.domain.commandName,\n description: validationCliDefinition.domain.description,\n register: (program: Command) => {\n const { domain } = validationCliDefinition;\n const validationCmd = program\n .command(domain.commandName)\n .alias(domain.alias)\n .description(domain.description);\n\n validationCmd.on(\"command:*\", (operands: readonly string[]) => {\n handleUnknownSubcommand(operands);\n });\n\n registerValidationCommands(validationCmd);\n },\n};\n"],"mappings":"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;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,IAAI,IAAI,EAAE,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,GAAG,IAAI;AAC5C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gBAAeA,gBAAe,GAAG,IAAI,EAAE,IAAI;AAC3C,EAAAA,gB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","names":["createRequire","program","fs","fs","fs","path","os","path","program","readFile","join","path","LAYER","path","basename","validate","validate","validate","defaults","validatePaths","validate","format","path","join","readFile","format","formatConfig","format","resolve","program","dirname","join","output","execa","join","resolve","execa","resolve","statusDirs","join","path","join","dirname","stat","path","join","parseYaml","parseYaml","join","path","stat","mkdir","join","resolve","join","resolve","mkdir","readFile","join","join","readFile","mkdir","readdir","readFile","rename","join","readdir","join","readFile","mkdir","rename","readdir","readFile","unlink","join","readdir","join","readFile","lines","unlink","readdir","rename","readdir","rename","readFile","stat","stat","readFile","showCommand","resolve","showCommand","program","access","readFile","writeFile","path","fs","path","path","fs","path","readdir","stat","path","path","readdir","stat","JSON_INDENT","getDisplayNumber","getDisplayNumber","formatNode","formatWorkItemName","format","join","NODE_SUFFIXES","NODE_SUFFIXES","join","path","join","join","path","readFile","writeFile","access","program","value","CharacterCodes","ParseOptions","handleError","ScanError","SyntaxKind","parse","ParseErrorCode","existsSync","readFileSync","join","parse","execSync","fs","path","require","fs","execSync","path","fs","path","fs","path","existsSync","join","existsSync","readdirSync","readFileSync","join","parse","readFileSync","join","existsSync","visit","readdirSync","resolve","join","existsSync","defaults","existsSync","join","resolve","join","existsSync","TYPESCRIPT_ABSENT_MESSAGE","readFile","isAbsolute","relative","resolve","LAYER","path","path","readdir","join","relative","isNodeError","readdir","join","relative","path","path","isAbsolute","resolve","relative","path","readFile","TYPESCRIPT_ABSENT_MESSAGE","existsSync","join","join","existsSync","path","existsSync","isAbsolute","join","existsSync","join","isAbsolute","resolve","tscArgs","TYPESCRIPT_ABSENT_MESSAGE","rename","writeFile","dirname","join","EXIT_OK","dirname","join","writeFile","rename","result","program","require","createRequire"]}