@ctxo/cli 0.13.0 → 0.13.1
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/README.md +4 -4
- package/dist/{chunk-BYX3UFBJ.js → chunk-WB7WZKX4.js} +19 -10
- package/dist/chunk-WB7WZKX4.js.map +1 -0
- package/dist/{cli-router-RR4CM62C.js → cli-router-DDHH4WQH.js} +5 -5
- package/dist/cli-router-DDHH4WQH.js.map +1 -0
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/llms-full.txt +51 -1
- package/llms.txt +10 -1
- package/package.json +4 -4
- package/dist/chunk-BYX3UFBJ.js.map +0 -1
- package/dist/cli-router-RR4CM62C.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/cli-router.ts","../src/cli/index-command.ts","../src/core/staleness/content-hasher.ts","../src/adapters/language/language-adapter-registry.ts","../src/cli/plugin-loader.ts","../src/adapters/language/plugin-discovery.ts","../src/cli/install-command.ts","../src/core/detection/detect-languages.ts","../src/core/install/package-manager.ts","../src/core/install/run-package-manager.ts","../src/core/detection/detect-java-runtime.ts","../src/cli/read-source.ts","../src/cli/index-cochange.ts","../src/cli/index-contexts-view.ts","../src/adapters/storage/architecture-artifacts-writer.ts","../src/core/contexts-view/contexts-view-builder.ts","../src/core/contexts-view/candidate-groups.ts","../src/core/overlay/louvain.ts","../src/core/contexts-view/context-terms.ts","../src/core/contexts-view/data-coupling.ts","../src/core/contexts-view/file-graph.ts","../src/cli/index-facts.ts","../src/adapters/storage/json-index-writer.ts","../src/adapters/storage/schema-manager.ts","../src/core/history/change-log.ts","../src/core/history/intent-history.ts","../src/core/overlay/community-detector.ts","../src/core/overlay/community-labeler.ts","../src/cli/sync-command.ts","../src/cli/status-command.ts","../src/cli/verify-command.ts","../src/cli/init-command.ts","../src/cli/ai-rules.ts","../src/core/agent-rules/rules-block.ts","../src/cli/git-hooks.ts","../src/cli/init-parts.ts","../src/cli/watch-command.ts","../src/adapters/watcher/chokidar-watcher-adapter.ts","../src/cli/stats-command.ts","../src/cli/doctor-command.ts","../src/adapters/diagnostics/health-checker.ts","../src/adapters/diagnostics/doctor-reporter.ts","../src/adapters/diagnostics/checks/runtime-check.ts","../src/cli/version-command.ts","../src/adapters/diagnostics/checks/versions-check.ts","../src/adapters/diagnostics/checks/language-coverage-check.ts","../src/adapters/diagnostics/checks/java-tier-check.ts","../src/adapters/diagnostics/checks/csharp-tier-check.ts","../src/core/detection/detect-dotnet-sdk.ts","../src/adapters/diagnostics/checks/git-check.ts","../src/adapters/diagnostics/checks/agent-setup-check.ts","../src/adapters/diagnostics/checks/index-check.ts","../src/adapters/diagnostics/checks/storage-check.ts","../src/adapters/diagnostics/checks/config-check.ts","../src/adapters/diagnostics/checks/disk-check.ts","../src/cli/doctor-fix.ts","../src/cli/visualize-command.ts","../src/cli/graph-loader.ts","../src/cli/update-command.ts","../src/core/update/registry-client.ts","../src/core/update/update-plan.ts","../src/cli/blast-radius-command.ts","../src/cli/contexts-command.ts","../src/cli/gate-hook-command.ts","../src/core/gate/gate-config.ts","../src/core/gate/symbol-locator.ts","../src/core/gate/transcript-scan.ts","../src/adapters/gate/gate-session-store.ts","../src/core/gate/percentile.ts","../src/core/gate/gate-decision.ts","../src/cli/gate-command.ts"],"sourcesContent":["import { readFileSync, existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { IndexCommand } from './index-command.js';\nimport { SyncCommand } from './sync-command.js';\nimport { StatusCommand } from './status-command.js';\nimport { VerifyCommand } from './verify-command.js';\nimport { InitCommand } from './init-command.js';\nimport { INIT_PARTS, parseInitParts, type InitPart } from './init-parts.js';\nimport { WatchCommand } from './watch-command.js';\nimport { StatsCommand } from './stats-command.js';\nimport { DoctorCommand } from './doctor-command.js';\nimport { VisualizeCommand } from './visualize-command.js';\nimport { VersionCommand } from './version-command.js';\nimport { InstallCommand } from './install-command.js';\nimport { UpdateCommand } from './update-command.js';\nimport { BlastRadiusCommand } from './blast-radius-command.js';\nimport { ContextsCommand } from './contexts-command.js';\nimport { GateHookCommand } from './gate-hook-command.js';\nimport { GateCommand } from './gate-command.js';\nimport { parseCoChangeSince } from '../core/co-change/co-change-window.js';\n\n/** `value` as a positive integer, or undefined when it is anything else (no sign, decimals, exponent or unit). */\nfunction parsePositiveInteger(value: string | undefined): number | undefined {\n if (value === undefined || !/^\\d+$/.test(value)) return undefined;\n const parsed = Number(value);\n return Number.isSafeInteger(parsed) && parsed >= 1 ? parsed : undefined;\n}\n\ninterface InitPartsFlag {\n /** The flag appears on the line, with or without a usable value. */\n readonly present: boolean;\n readonly parts: InitPart[];\n /** The message to print before exiting 1, when the value is missing or names a part that does not exist. */\n readonly error?: string;\n}\n\n/**\n * Read `--only` or `--skip` from `ctxo init` arguments: `--only a,b`, `--only=a,b`, repeated as often as\n * the user likes (the parts are merged). The value must be present. In the two-token spelling a next\n * token that starts with `-` is a flag (`--dry-run`, `-y`), which ends the list before it began; in the\n * `=` spelling the value is taken as written, so `--only=-y` names an unknown part.\n */\nfunction readInitPartsFlag(args: readonly string[], flag: '--only' | '--skip'): InitPartsFlag {\n const validParts = INIT_PARTS.join(', ');\n const missing = `[ctxo] ${flag} requires a comma-separated list of parts: ${validParts}`;\n const values: string[] = [];\n let present = false;\n for (let i = 1; i < args.length; i++) {\n const arg = args[i]!;\n let value: string | undefined;\n let flagToken = false;\n if (arg === flag) {\n present = true;\n value = args[i + 1];\n flagToken = value?.startsWith('-') === true;\n i += 1;\n } else if (arg.startsWith(`${flag}=`)) {\n present = true;\n value = arg.slice(flag.length + 1);\n } else {\n continue;\n }\n if (!value || flagToken) return { present, parts: [], error: missing };\n values.push(value);\n }\n const { parts, unknown } = parseInitParts(values.join(','));\n if (unknown.length > 0) {\n return { present, parts, error: `[ctxo] Unknown init part: ${unknown[0]}. Valid parts: ${validParts}` };\n }\n return { present, parts };\n}\n\nexport function getVersion(): string {\n let dir = import.meta.dirname;\n for (let i = 0; i < 10; i++) {\n const pkg = join(dir, 'package.json');\n if (existsSync(pkg)) {\n try {\n const json = JSON.parse(readFileSync(pkg, 'utf-8'));\n return json.version ?? 'unknown';\n } catch { break; }\n }\n const parent = join(dir, '..');\n if (parent === dir) break;\n dir = parent;\n }\n return 'unknown';\n}\n\n/**\n * Walk up from `startDir` (capped at 12 levels) looking for a directory that\n * contains `.git`. First hit wins. Matches how git itself resolves the working\n * tree and keeps every subcommand consistent when the user runs ctxo from a\n * subdirectory or when pnpm --filter sets cwd to a monorepo package.\n */\nexport function locateGitRoot(startDir: string): string | null {\n let dir = startDir;\n for (let i = 0; i < 12; i++) {\n if (existsSync(join(dir, '.git'))) return dir;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nexport class CliRouter {\n private readonly projectRoot: string;\n\n constructor(projectRoot: string) {\n // If cwd is a subdirectory of a git repo (common in monorepos and when\n // users run ctxo from anywhere below the repo root), use the repo root so\n // every subcommand consistently operates on the same project.\n this.projectRoot = locateGitRoot(projectRoot) ?? projectRoot;\n }\n\n async route(args: string[]): Promise<void> {\n const command = args[0];\n\n // --help and -h win over everything else on the line, before any flag is parsed or any command is built:\n // `ctxo index --help` must print the help and never start an index run, and `ctxo init --help` never an init.\n // There is one help text for the whole CLI (each command has its own lines in it).\n if (!command || args.some((arg) => arg === '--help' || arg === '-h')) {\n this.printHelp();\n return;\n }\n\n if (command === '--version' || command === '-v' || command === '-V') {\n const verbose = args.includes('--verbose');\n const json = args.includes('--json');\n await new VersionCommand(this.projectRoot).run({ verbose, json });\n return;\n }\n\n if (command === 'version') {\n const json = args.includes('--json');\n const short = args.includes('--short');\n await new VersionCommand(this.projectRoot).run({\n verbose: !json && !short,\n json,\n });\n return;\n }\n\n switch (command) {\n case 'index': {\n // --files takes every value up to the next flag, --commit takes one revision, and --file is the\n // older spelling of --files with a single path. All of them can be repeated or combined.\n const filesArg: string[] = [];\n let commitArg: string | undefined;\n for (let i = 1; i < args.length; i++) {\n const arg = args[i];\n if (arg === '--file') {\n const value = args[i + 1];\n if (!value || value.startsWith('--')) {\n console.error('[ctxo] --file requires a path argument');\n process.exit(1);\n return;\n }\n filesArg.push(value);\n i += 1;\n } else if (arg === '--files') {\n const before = filesArg.length;\n while (i + 1 < args.length && !args[i + 1]!.startsWith('--')) {\n filesArg.push(args[i + 1]!);\n i += 1;\n }\n if (filesArg.length === before) {\n console.error('[ctxo] --files requires at least one path');\n process.exit(1);\n return;\n }\n } else if (arg === '--commit') {\n const value = args[i + 1];\n if (!value || value.startsWith('--')) {\n console.error('[ctxo] --commit requires a revision (for example HEAD)');\n process.exit(1);\n return;\n }\n commitArg = value;\n i += 1;\n }\n }\n const checkArg = args.includes('--check');\n const skipHistory = args.includes('--skip-history');\n const skipCommunity = args.includes('--skip-community');\n const installMissing = args.includes('--install-missing');\n const maxHistoryIdx = args.indexOf('--max-history');\n const maxHistoryArg = maxHistoryIdx !== -1 ? Number(args[maxHistoryIdx + 1]) : undefined;\n if (maxHistoryIdx !== -1 && (!maxHistoryArg || isNaN(maxHistoryArg) || maxHistoryArg < 1)) {\n console.error('[ctxo] --max-history requires a positive integer');\n process.exit(1);\n return;\n }\n // The co-change window flags are checked here because the config resolver skips an invalid\n // override silently, which would run a different window from the one the user asked for.\n const cochangeCommitsIdx = args.indexOf('--cochange-commits');\n const cochangeCommitsRaw = cochangeCommitsIdx !== -1 ? args[cochangeCommitsIdx + 1] : undefined;\n const cochangeCommitsArg = cochangeCommitsRaw === 'all' ? 'all' : parsePositiveInteger(cochangeCommitsRaw);\n if (cochangeCommitsIdx !== -1 && cochangeCommitsArg === undefined) {\n console.error('[ctxo] --cochange-commits requires a positive integer or \"all\"');\n process.exit(1);\n return;\n }\n const cochangeSinceIdx = args.indexOf('--cochange-since');\n const cochangeSinceArg = cochangeSinceIdx !== -1 ? args[cochangeSinceIdx + 1] : undefined;\n if (cochangeSinceIdx !== -1 && (cochangeSinceArg === undefined || parseCoChangeSince(cochangeSinceArg) === undefined)) {\n console.error('[ctxo] --cochange-since requires a duration such as 30d, 2w, 12m or 1y');\n process.exit(1);\n return;\n }\n await new IndexCommand(this.projectRoot).run({\n files: filesArg.length > 0 ? filesArg : undefined,\n commit: commitArg,\n check: checkArg,\n skipHistory,\n skipCommunity,\n maxHistory: maxHistoryArg,\n cochangeCommits: cochangeCommitsArg,\n cochangeSince: cochangeSinceArg,\n installMissing,\n });\n break;\n }\n\n case 'sync':\n await new SyncCommand(this.projectRoot).run();\n break;\n\n case 'watch':\n await new WatchCommand(this.projectRoot).run();\n break;\n\n case 'verify-index':\n await new VerifyCommand(this.projectRoot).run();\n break;\n\n case 'status':\n new StatusCommand(this.projectRoot).run();\n break;\n\n case 'init': {\n const toolsIdx = args.indexOf('--tools');\n const toolsArg = toolsIdx !== -1 ? args[toolsIdx + 1] : undefined;\n const yesArg = args.includes('--yes') || args.includes('-y');\n const rulesOnly = args.includes('--rules');\n const dryRun = args.includes('--dry-run');\n const noInstall = args.includes('--no-install');\n const noGuard = args.includes('--no-guard');\n const tools = toolsArg ? toolsArg.split(',').map(t => t.trim()) : undefined;\n // Everything is checked before InitCommand exists, so a bad flag never starts an init. --only is\n // exact, so it cannot be mixed with the narrowing flags (--skip, --rules); --no-guard combines with all.\n const only = readInitPartsFlag(args, '--only');\n const skip = readInitPartsFlag(args, '--skip');\n const partsError = only.error ?? skip.error\n ?? (only.present && (skip.present || rulesOnly) ? '[ctxo] --only cannot be combined with --skip or --rules' : undefined);\n if (partsError) {\n console.error(partsError);\n process.exit(1);\n return;\n }\n await new InitCommand(this.projectRoot).run({\n tools,\n yes: yesArg,\n rulesOnly,\n dryRun,\n noInstall,\n only: only.present ? only.parts : undefined,\n skip: skip.present ? skip.parts : undefined,\n noGuard,\n });\n break;\n }\n\n case 'stats': {\n const daysIdx = args.indexOf('--days');\n const daysArg = daysIdx !== -1 ? Number(args[daysIdx + 1]) : undefined;\n const jsonArg = args.includes('--json');\n const clearArg = args.includes('--clear');\n await new StatsCommand(this.projectRoot).run({ days: daysArg, json: jsonArg, clear: clearArg });\n break;\n }\n\n case 'doctor': {\n const jsonArg = args.includes('--json');\n const quietArg = args.includes('--quiet');\n const fixArg = args.includes('--fix');\n const dryRunArg = args.includes('--dry-run');\n const yesArg = args.includes('--yes') || args.includes('-y');\n await new DoctorCommand(this.projectRoot).run({\n json: jsonArg,\n quiet: quietArg,\n fix: fixArg,\n dryRun: dryRunArg,\n yes: yesArg,\n });\n break;\n }\n\n case 'install': {\n const languages: string[] = [];\n const flagValues: Record<string, string | boolean> = {};\n for (let i = 1; i < args.length; i++) {\n const a = args[i]!;\n if (a === '--yes' || a === '-y') flagValues['yes'] = true;\n else if (a === '--global' || a === '-g') flagValues['global'] = true;\n else if (a === '--dry-run') flagValues['dryRun'] = true;\n else if (a === '--force') flagValues['force'] = true;\n else if (a === '--full-tier') flagValues['fullTier'] = true;\n else if (a === '--syntax-only') flagValues['syntaxOnly'] = true;\n else if (a === '--pm') {\n const next = args[++i];\n if (!next) { console.error('[ctxo] --pm requires a value'); process.exit(1); return; }\n flagValues['pm'] = next;\n } else if (a === '--version') {\n const next = args[++i];\n if (!next) { console.error('[ctxo] --version requires a value'); process.exit(1); return; }\n flagValues['version'] = next;\n } else if (a.startsWith('--')) {\n console.error(`[ctxo] Unknown install flag: ${a}`);\n process.exit(1);\n return;\n } else {\n languages.push(a);\n }\n }\n await new InstallCommand(this.projectRoot).run({\n languages,\n yes: flagValues['yes'] === true,\n global: flagValues['global'] === true,\n dryRun: flagValues['dryRun'] === true,\n force: flagValues['force'] === true,\n fullTier: flagValues['fullTier'] === true,\n syntaxOnly: flagValues['syntaxOnly'] === true,\n pm: typeof flagValues['pm'] === 'string' ? flagValues['pm'] : undefined,\n version: typeof flagValues['version'] === 'string' ? flagValues['version'] : undefined,\n });\n break;\n }\n\n case 'update': {\n const flagValues: Record<string, string | boolean> = {};\n for (let i = 1; i < args.length; i++) {\n const a = args[i]!;\n if (a === '--check') flagValues['check'] = true;\n else if (a === '--print') flagValues['print'] = true;\n else if (a === '--global' || a === '-g') flagValues['global'] = true;\n else if (a === '--json') flagValues['json'] = true;\n else if (a === '--force') flagValues['force'] = true;\n else if (a === '--pm') {\n const next = args[++i];\n if (!next) { console.error('[ctxo] --pm requires a value'); process.exit(1); return; }\n flagValues['pm'] = next;\n } else {\n console.error(`[ctxo] Unknown update flag: ${a}`);\n process.exit(1);\n return;\n }\n }\n await new UpdateCommand(this.projectRoot, {\n setExitCode: (code: number) => { process.exitCode = code; },\n }).run({\n check: flagValues['check'] === true,\n print: flagValues['print'] === true,\n global: flagValues['global'] === true,\n json: flagValues['json'] === true,\n force: flagValues['force'] === true,\n pm: typeof flagValues['pm'] === 'string' ? flagValues['pm'] : undefined,\n });\n break;\n }\n\n case 'gate': {\n if (args.includes('--preview')) {\n new GateCommand(this.projectRoot).preview({ json: args.includes('--json') });\n } else {\n console.error('[ctxo] usage: ctxo gate --preview [--json]');\n process.exit(1);\n }\n break;\n }\n\n case 'gate-hook':\n await new GateHookCommand(this.projectRoot).run();\n break;\n\n case 'blast-radius': {\n const symbolId = args[1];\n if (!symbolId || symbolId.startsWith('--')) {\n console.error('[ctxo] usage: ctxo blast-radius <symbolId> [--json]');\n process.exit(1);\n return;\n }\n new BlastRadiusCommand(this.projectRoot).run({ symbolId, json: args.includes('--json') });\n break;\n }\n\n case 'contexts':\n new ContextsCommand(this.projectRoot).run({ json: args.includes('--json') });\n break;\n\n case 'visualize': {\n const outputIdx = args.indexOf('--output');\n const outputArg = outputIdx !== -1 ? args[outputIdx + 1] : undefined;\n const maxNodesIdx = args.indexOf('--max-nodes');\n const maxNodesArg = maxNodesIdx !== -1 ? Number(args[maxNodesIdx + 1]) : undefined;\n const noBrowser = args.includes('--no-browser');\n if (maxNodesIdx !== -1 && (!maxNodesArg || isNaN(maxNodesArg) || maxNodesArg < 1)) {\n console.error('[ctxo] --max-nodes requires a positive integer');\n process.exit(1);\n return;\n }\n await new VisualizeCommand(this.projectRoot).run({ output: outputArg, maxNodes: maxNodesArg, noBrowser });\n break;\n }\n\n default:\n console.error(`[ctxo] Unknown command: \"${command}\". Run \"ctxo --help\" for usage.`);\n process.exit(1);\n return;\n }\n }\n\n private printHelp(): void {\n const v = getVersion();\n console.error(`\nctxo v${v} — MCP server for dependency-aware codebase context\n\nUsage:\n ctxo Start MCP server (stdio transport)\n ctxo index Build full codebase index (--max-history N controls intent depth only, default 20)\n ctxo index --skip-community Skip community detection and the contexts view for faster indexing\n ctxo index --skip-history Skip git history (no intent or anti-patterns; co-changes.json is not refreshed)\n ctxo index --check Fail if the index is stale; writes nothing and records no snapshot\n ctxo index --cochange-commits <n|all> Co-change window in commits (default 2000, or \"all\")\n ctxo index --cochange-since <duration> Co-change window by age from HEAD (30d, 2w, 12m, 1y)\n ctxo index --files <path...> Re-index only these files (repo-relative); the rest of the index is kept\n ctxo index --file <path> Same as --files with one path\n ctxo index --commit <rev> Re-index the files changed by the commit just made (for example HEAD), drop the ones it deleted or renamed\n ctxo sync Rebuild SQLite cache from committed JSON index\n ctxo watch Start file watcher for incremental re-indexing\n ctxo verify-index CI gate: fail if index is stale\n ctxo status Show index manifest\n ctxo init Interactive setup (rules, skills, guard, MCP, git hooks, config); the post-commit hook runs ctxo index --commit HEAD\n ctxo init --tools a,b -y Non-interactive (claude-code,cursor,...); -y without --tools selects every tool\n ctxo init --only <parts> Install only these parts: rules,skills,guard,mcp,git-hooks,config\n ctxo init --skip <parts> Install everything except these parts\n ctxo init --no-guard Does not install the Claude Code safe-edit guard\n ctxo init --rules Deprecated: same as --skip git-hooks,guard\n ctxo init --dry-run List every file init would create or change\n ctxo stats Show usage statistics (--json, --days N, --clear)\n ctxo doctor Health check all subsystems (--json, --quiet)\n ctxo doctor --fix Apply fixes in dependency order: config, git hooks, skills, the safe-edit guard, rules blocks, plugins, index (--dry-run, --yes)\n ctxo visualize Generate interactive dependency graph HTML\n ctxo visualize --max-nodes N Limit to top N symbols by PageRank\n ctxo visualize --output PATH Write HTML to custom path\n ctxo visualize --no-browser Skip auto-opening browser\n ctxo install [<lang>...] Install language plugins (detects if omitted)\n ctxo install python -y Batch install, no prompt\n ctxo install ts --global Install globally\n ctxo install py --dry-run Show command without running\n ctxo install sql SQL plugin: .sql definitions, data edges from C#, TypeScript, Java and Go call sites\n ctxo update Check + apply updates for ctxo + plugins\n ctxo update --check Check only, no install\n ctxo update --print Print install command, never execute\n ctxo update --global Force a global install\n ctxo update --json Machine-readable output\n ctxo update --pm <pm> Override package manager (npm|pnpm|yarn|bun)\n ctxo update --force Bypass CI lockfile guard\n ctxo blast-radius <symbolId> Blast radius for one symbol (--json for machine output; name::kind for a SQL object)\n ctxo contexts Candidate contexts from dependency and co-change clusters (table)\n ctxo contexts --json Same, full contexts-view.json to stdout\n ctxo gate --preview Preview which symbols the safe-edit guard would block\n ctxo gate --preview --json Same, machine-readable output\n ctxo --version Print core version\n ctxo --version --verbose Print core + plugins + runtime\n ctxo --version --json Machine-readable version payload\n ctxo version Subcommand — verbose by default\n ctxo --help Show this help message (also ctxo <command> --help; nothing is run)\n`.trim());\n }\n}\n","import { execFileSync } from 'node:child_process';\nimport { readFileSync, writeFileSync, existsSync, statSync, readdirSync } from 'node:fs';\nimport { join, relative, extname, isAbsolute, resolve } from 'node:path';\nimport { createRequire } from 'node:module';\nimport { compareCodepoint } from '../core/compare-codepoint.js';\nimport { ContentHasher } from '../core/staleness/content-hasher.js';\nimport { LanguageAdapterRegistry } from '../adapters/language/language-adapter-registry.js';\nimport { loadPlugins } from './plugin-loader.js';\nimport { InstallCommand } from './install-command.js';\nimport { readSourceText } from './read-source.js';\nimport { changeLogSize, writeCoChangeMatrix } from './index-cochange.js';\nimport { computeAndWriteContextsView } from './index-contexts-view.js';\nimport { extractFileFacts } from './index-facts.js';\nimport {\n communityDetectorOptions,\n factsRequested,\n loadConfig,\n indexIgnorePatterns,\n indexIgnoreProjectPatterns,\n makeGlobMatcher,\n resolveCoChangeConfig,\n} from '../core/config/load-config.js';\nimport type { CtxoConfig } from '../core/config/config-schema.js';\nimport {\n detectLanguages,\n decideNeededLanguages,\n officialPluginFor,\n EXTENSION_LANGUAGE,\n type KnownLanguage,\n} from '../core/detection/detect-languages.js';\n\nconst requireCjs = createRequire(import.meta.url);\nimport { JsonIndexWriter } from '../adapters/storage/json-index-writer.js';\nimport { JsonIndexReader } from '../adapters/storage/json-index-reader.js';\nimport { SqliteStorageAdapter } from '../adapters/storage/sqlite-storage-adapter.js';\nimport { SchemaManager } from '../adapters/storage/schema-manager.js';\nimport { ArchitectureArtifactsWriter } from '../adapters/storage/architecture-artifacts-writer.js';\nimport { CommunitySnapshotWriter } from '../adapters/storage/community-snapshot-writer.js';\nimport { SimpleGitAdapter } from '../adapters/git/simple-git-adapter.js';\nimport { RevertDetector } from '../core/why-context/revert-detector.js';\nimport { canonicalizeChangeLog } from '../core/history/change-log.js';\nimport { buildIntentHistory } from '../core/history/intent-history.js';\nimport { CommunityDetector, type CommunityDetectorOptions } from '../core/overlay/community-detector.js';\nimport { DriftDetector } from '../core/overlay/drift-detector.js';\nimport { BoundaryViolationDetector } from '../core/overlay/boundary-violation-detector.js';\nimport { SymbolGraph } from '../core/graph/symbol-graph.js';\nimport { PageRankCalculator } from '../core/importance/pagerank-calculator.js';\nimport type {\n BoundaryViolationsArtifact,\n CommunitySnapshot,\n DriftEventsArtifact,\n EdgeQuality,\n FileChange,\n FileIndex,\n SymbolKind,\n} from '../core/types.js';\n\ninterface TsMorphLike {\n loadProjectSources(sources: Map<string, string>): void;\n clearProjectSources(): void;\n}\n\ninterface RoslynLike {\n isReady(): boolean;\n batchIndex(): Promise<void>;\n startKeepAlive(): Promise<boolean>;\n reindexFile(relativePath: string): Promise<{\n symbols: Array<{ symbolId: string; name: string; kind: string; startLine: number; endLine: number }>;\n edges: Array<{ from: string; to: string; kind: string }>;\n complexity: Array<{ symbolId: string; cyclomatic: number }>;\n } | null>;\n dispose(): Promise<void>;\n}\n\ninterface CSharpCompositeLike {\n getRoslynDelegate(): RoslynLike | null;\n /** Re-read after the Roslyn batch: a failed helper switches the composite to the syntax tier. */\n getTier(): 'full' | 'syntax' | 'unavailable';\n}\n\ninterface GoCompositeLike {\n getTier(): 'full' | 'syntax' | 'unavailable';\n}\n\ninterface JavaCompositeLike {\n getTier(): 'full' | 'syntax' | 'unavailable';\n}\n\nexport class IndexCommand {\n private readonly projectRoot: string;\n ctxoRoot: string;\n private supportedExtensions: Set<string>;\n\n constructor(projectRoot: string, ctxoRoot?: string) {\n this.projectRoot = projectRoot;\n this.ctxoRoot = ctxoRoot ?? join(projectRoot, '.ctxo');\n this.supportedExtensions = new Set(['.ts', '.tsx', '.js', '.jsx', '.go', '.cs']);\n }\n\n private loadIgnoreConfig(): {\n /** The whole loaded config, so the run reads `.ctxo/config.yaml` (and warns about it) once. */\n config: CtxoConfig;\n ignoreFile: (p: string) => boolean;\n ignoreProject: (p: string) => boolean;\n ignoreProjectPatterns: string[];\n } {\n const { config } = loadConfig(this.ctxoRoot);\n const filePatterns = indexIgnorePatterns(config);\n const projectPatterns = indexIgnoreProjectPatterns(config);\n if (filePatterns.length > 0) {\n console.error(`[ctxo] index.ignore: ${filePatterns.length} pattern(s) active`);\n }\n if (projectPatterns.length > 0) {\n console.error(`[ctxo] index.ignoreProjects: ${projectPatterns.length} pattern(s) active`);\n }\n return {\n config,\n ignoreFile: makeGlobMatcher(filePatterns),\n ignoreProject: makeGlobMatcher(projectPatterns),\n ignoreProjectPatterns: projectPatterns,\n };\n }\n\n async run(options: {\n /** One repo-relative path to re-index: the older spelling of `files: [file]` (`--file`). */\n file?: string;\n /**\n * Repo-relative paths to re-index (`--files`). An incremental run: the other files keep their\n * committed entries, and everything global (registry, co-change, communities, artifacts, SQLite)\n * is computed from the merged index, not from these files alone.\n */\n files?: string[];\n /**\n * Re-index the files changed by this commit and drop the ones it deleted or renamed away\n * (`--commit`). Meant for the commit just made, which is what the post-commit hook runs on. A merge\n * commit lists no files, so nothing is re-indexed, but the global products are still refreshed.\n */\n commit?: string;\n check?: boolean;\n skipSideEffects?: boolean;\n skipHistory?: boolean;\n skipCommunity?: boolean;\n /** Commits of history kept per file in `intent[]`. Does not affect the co-change window. */\n maxHistory?: number;\n /** Co-change window in commits (`--cochange-commits`); overrides `cochange.maxCommits`. */\n cochangeCommits?: number | 'all';\n /** Co-change window by age, counted back from HEAD (`--cochange-since`); overrides `cochange.since`. */\n cochangeSince?: string;\n installMissing?: boolean;\n } = {}): Promise<void> {\n if (options.check) {\n // Delegate to verify logic: hash-based freshness check\n return this.runCheck();\n }\n\n // Pre-index: detect missing plugins and optionally auto-install\n if (options.installMissing) {\n await this.autoInstallMissingPlugins();\n }\n\n const ignore = this.loadIgnoreConfig();\n const gitAdapter = new SimpleGitAdapter(this.projectRoot);\n\n // An incremental run is selected by paths (--files, --file), by a commit (--commit), or both.\n const incremental = options.files !== undefined || options.commit !== undefined || Boolean(options.file);\n // The commit is read before anything heavy starts, so a revision git cannot resolve fails at once,\n // without a plugin having been loaded.\n const commitChanges = options.commit !== undefined ? await readCommitChanges(gitAdapter, options.commit) : [];\n\n // Set up adapters via plugin discovery (TS, Go, C# all plugin-backed)\n const registry = new LanguageAdapterRegistry();\n const plugins = await this.registerDiscoveredPlugins(registry, ignore.ignoreProjectPatterns, factsRequested(ignore.config));\n const { tsMorphLike, roslynAdapter, csharpComposite, goTier, javaTier } = plugins;\n // The C# tier as loaded; re-read after the Roslyn batch, which can switch it to the syntax tier.\n const csharpTierAtLoad = plugins.csharpTier;\n let csharpTier = plugins.csharpTier;\n this.supportedExtensions = registry.getSupportedExtensions();\n\n // Emit a language-aware pre-scan so users see the plan before the work runs\n this.printLanguagePreview();\n\n const writer = new JsonIndexWriter(this.ctxoRoot);\n const schemaManager = new SchemaManager(this.ctxoRoot);\n const hasher = new ContentHasher();\n const revertDetector = new RevertDetector();\n\n // The committed JSON index, read at most once per run, and before this run writes anything. An\n // incremental run needs it for the entries it removes, the symbol registry and the merged index; a full\n // run for the co-change file set and for pruning the entries that went stale. Each entry keeps the path\n // of the JSON file it came from: removing an entry deletes that file, never one named by the entry's\n // own `file` field, which a corrupt or crafted file can point at an artifact.\n let committed: { indices: FileIndex[]; jsonPaths: Map<string, string[]> } | undefined;\n const readCommitted = (): { indices: FileIndex[]; jsonPaths: Map<string, string[]> } => {\n if (committed === undefined) {\n const entries = new JsonIndexReader(this.ctxoRoot).readEntries();\n const jsonPaths = new Map<string, string[]>();\n for (const { path, index } of entries) jsonPaths.set(index.file, [...(jsonPaths.get(index.file) ?? []), path]);\n committed = { indices: entries.map((entry) => entry.index), jsonPaths };\n }\n return committed;\n };\n const committedIndex = (): FileIndex[] => readCommitted().indices;\n\n // Monorepo workspaces: the folders a full run discovers files in, and the ones index.ignoreProjects\n // leaves out. A file that the project configuration excludes from the index matches index.ignore or\n // lies inside one of those ignored workspaces.\n const workspaces = this.discoverWorkspaces(ignore.ignoreProject);\n const isIgnored = (path: string): boolean =>\n ignore.ignoreFile(path) ||\n workspaces.ignored.some((workspace) => isInsideDirectory(workspace, join(this.projectRoot, path)));\n\n // Discover files (an explicit selection, monorepo workspaces, or the full project)\n let files: string[];\n // Files of the committed index that this run drops: deleted, renamed away, or gone from the working tree.\n let removedPaths: ReadonlySet<string> = new Set();\n if (incremental) {\n const selection = await this.selectIncrementalFiles(\n [...(options.files ?? []), ...(options.file ? [options.file] : [])],\n commitChanges,\n registry,\n ignore.ignoreFile,\n workspaces.kept,\n new Set(committedIndex().map((idx) => idx.file)),\n gitAdapter,\n );\n files = selection.changed.map((path) => join(this.projectRoot, path));\n removedPaths = new Set(selection.removed);\n console.error(\n `[ctxo] Incremental re-index: ${selection.changed.length} file(s) to index, ${selection.removed.length} to remove` +\n (options.commit !== undefined ? ` (commit ${options.commit})` : ''),\n );\n } else {\n // Discover files across all workspace roots (the project root itself outside a monorepo)\n files = [];\n for (const ws of workspaces.kept) {\n const wsFiles = this.discoverFilesIn(ws, ignore.ignoreFile);\n files.push(...wsFiles);\n }\n console.error(`[ctxo] Building codebase index... Found ${files.length} source files`);\n }\n\n // Pre-Phase 0: sweep orphan .<pid>.tmp files from a previous interrupted write.\n try {\n const { sweepStaleTmpFiles } = await import('../adapters/storage/atomic-write.js');\n const swept = sweepStaleTmpFiles(join(this.ctxoRoot, 'index'));\n if (swept > 0) {\n console.error(`[ctxo] Cleaned ${swept} orphan .tmp file(s) from previous interrupted run`);\n }\n } catch {\n /* non-fatal */\n }\n\n // Phase 0: Roslyn batch index (if available, pre-caches all C# results). Full and incremental\n // (--files, --commit) runs all come through here.\n if (roslynAdapter?.isReady()) {\n const hasCsFiles = files.some(f => f.endsWith('.cs'));\n if (hasCsFiles) {\n await roslynAdapter.batchIndex();\n }\n }\n // When the helper failed (restore, build, timeout), the C# plugin now runs on tree-sitter: the edge\n // quality and the summary must say so.\n if (csharpComposite) csharpTier = csharpComposite.getTier();\n\n // Phase 1a: Extract symbols (CPU-bound, builds symbol registry for edge resolution)\n const symbolRegistry = new Map<string, SymbolKind>();\n const pendingIndices: Array<{\n relativePath: string;\n source: string;\n fileIndex: FileIndex;\n }> = [];\n let processed = 0;\n\n for (const filePath of files) {\n const adapter = registry.getAdapter(filePath);\n if (!adapter) continue;\n\n const relativePath = relative(this.projectRoot, filePath).replace(/\\\\/g, '/');\n\n try {\n const source = readSourceText(filePath);\n const lastModified = Math.floor(Date.now() / 1000);\n\n const symbols = await adapter.extractSymbols(relativePath, source);\n const complexity = await adapter.extractComplexity(relativePath, source);\n\n // Build symbol registry for accurate edge resolution\n for (const sym of symbols) {\n symbolRegistry.set(sym.symbolId, sym.kind);\n }\n\n pendingIndices.push({\n relativePath,\n source,\n fileIndex: {\n file: relativePath,\n lastModified,\n contentHash: hasher.hash(source),\n symbols,\n edges: [],\n complexity,\n intent: [],\n antiPatterns: [],\n },\n });\n\n processed++;\n if (processed % 50 === 0) {\n console.error(`[ctxo] Processed ${processed}/${files.length} files (symbols)`);\n }\n } catch (err) {\n console.error(`[ctxo] Skipped ${relativePath}: ${(err as Error).message}`);\n }\n }\n\n // An incremental run extracts edges for a few files, but those files refer to symbols defined in all\n // the others. Their kinds come from the committed index, minus the entries this run replaces or\n // removes, so a reference resolves to the same kind as in a full run.\n if (incremental) {\n const replaced = new Set<string>(removedPaths);\n for (const { relativePath } of pendingIndices) replaced.add(relativePath);\n for (const idx of committedIndex()) {\n if (replaced.has(idx.file)) continue;\n for (const symbol of idx.symbols) symbolRegistry.set(symbol.symbolId, symbol.kind);\n }\n }\n\n // Pre-load all sources into ts-morph for cross-file resolution\n const allSources = new Map<string, string>();\n for (const entry of pendingIndices) {\n allSources.set(entry.relativePath, entry.source);\n }\n tsMorphLike?.loadProjectSources(allSources);\n\n // Phase 1b: Extract edges (uses symbol registry for correct kind resolution)\n for (const entry of pendingIndices) {\n const adapter = registry.getAdapter(entry.relativePath);\n if (!adapter) continue;\n\n try {\n adapter.setSymbolRegistry?.(symbolRegistry);\n entry.fileIndex.edges = await adapter.extractEdges(entry.relativePath, entry.source);\n } catch (err) {\n console.error(`[ctxo] Edge extraction failed for ${entry.relativePath}: ${(err as Error).message}`);\n }\n }\n\n // Phase 1c: facts, only when requested (index.facts: true). They go into the JSON index, never SQLite.\n if (factsRequested(ignore.config)) {\n for (const entry of pendingIndices) {\n const adapter = registry.getAdapter(entry.relativePath);\n if (!adapter) continue;\n const facts = await extractFileFacts(adapter, entry.relativePath, entry.source);\n if (facts) entry.fileIndex.facts = facts;\n }\n }\n\n // Clean up pre-loaded sources\n tsMorphLike?.clearProjectSources();\n\n // The index that the co-change file set, community detection, the architecture artifacts and the SQLite\n // cache are all built from, assembled at most once per run. A full run indexed every file it discovers,\n // so those files are the project; an incremental run re-indexed a few, so the rest comes from the\n // committed index (minus the removed files).\n let graphInputIndices: FileIndex[] | undefined;\n const graphInput = (): FileIndex[] =>\n (graphInputIndices ??= this.buildGraphInputIndices(\n pendingIndices,\n incremental ? { committed: committedIndex(), removedPaths } : undefined,\n ));\n\n // The files the co-change matrix is computed for. The matrix is committed and shared, so it must not\n // depend on which language plugins this machine has loaded: it covers the files indexed in this run and\n // every file the committed index already holds that the project configuration does not exclude (the\n // co-change step drops the ones whose source is gone). A file that only a missing plugin keeps this\n // machine from indexing therefore still takes part. An incremental run follows the same rule, minus the\n // files it removes, so its matrix equals the one a full run writes for the same HEAD.\n const coChangeFiles = (): string[] => {\n const files = new Set(pendingIndices.map(({ fileIndex }) => fileIndex.file));\n for (const { file } of committedIndex()) {\n if (!removedPaths.has(file) && !isIgnored(file)) files.add(file);\n }\n return [...files];\n };\n\n // A full run also prunes the index entries that went stale: the source file is gone from the working\n // tree, or index.ignore / index.ignoreProjects now excludes it. Left in place they would come back into\n // the merged index of the next incremental run. An entry of a file that exists and is not excluded is\n // never pruned, even when no plugin loaded here handles it: another machine may have indexed it. Nor is\n // the entry of a path that git tracks but marks skip-worktree (a sparse checkout).\n const stalePaths = incremental\n ? []\n : await this.withoutSkipWorktree(\n this.findStaleEntries(committedIndex(), new Set(pendingIndices.map(({ fileIndex }) => fileIndex.file)), isIgnored),\n gitAdapter,\n );\n\n // The committed entries that are still there once the stale ones are pruned (an incremental run prunes none).\n const survivingEntries = new Set(committedIndex().map((idx) => idx.file)).size - new Set(stalePaths).size;\n\n // The snapshot and the architecture artifacts are rebuilt whenever the run changed the index. A --commit\n // run rebuilds them even when it re-indexed no file: a merge commit lists none, and a commit that only\n // touched documents still moves HEAD, which the snapshot records. A --files run that selected nothing\n // has nothing to rebuild. A full run that only pruned rebuilds them only when no entry survives, because\n // then the project really is empty: with entries left, a run that discovered nothing (no language plugin\n // loaded here, say right after a clone) would replace the committed snapshot with an empty one.\n // A full run on an empty index also rebuilds them when cochange.include names files: no language plugin\n // indexes them, but their co-change makes a contexts view, and with no committed entry there is no\n // snapshot of indexed files to protect.\n const emptyIndex = !incremental && survivingEntries === 0;\n const coChangeIncludesFiles = resolveCoChangeConfig(ignore.config).include.length > 0;\n const refreshProducts =\n pendingIndices.length > 0 ||\n removedPaths.size > 0 ||\n options.commit !== undefined ||\n (emptyIndex && (stalePaths.length > 0 || coChangeIncludesFiles));\n\n // Co-change is built from git history and the committed entries, not from what this run discovered, so\n // it also follows a run that only pruned.\n const refreshCoChange = refreshProducts || stalePaths.length > 0;\n\n if (!incremental && pendingIndices.length === 0 && survivingEntries > 0) {\n console.error(\n registry.getSupportedExtensions().size === 0\n ? '[ctxo] No language plugin is loaded, so no file was indexed. Run `ctxo install` (or `ctxo index --install-missing`). ' +\n 'communities.json, its history and the architecture artifacts were left as they are'\n : '[ctxo] No source file was indexed. communities.json, its history and the architecture artifacts were left as they are',\n );\n }\n\n // Phases 2 and 2b: one git pass (the change log) feeds both the per-file intent[] and the\n // co-change matrix of the whole repository. The co-change window comes from `cochange.*` in\n // config.yaml and `--cochange-*`; `--max-history` only sets how much history each file keeps.\n // Non-fatal like phases 2c and 2d: an unexpected failure here must not stop the index from\n // being written, and co-changes.json is only ever replaced by a complete matrix.\n if (!options.skipHistory && refreshCoChange) {\n try {\n const coChange = resolveCoChangeConfig(ignore.config, {\n maxCommits: options.cochangeCommits,\n since: options.cochangeSince,\n });\n const maxHistory = options.maxHistory ?? 20;\n const changeLog = await gitAdapter.getChangeLog(changeLogSize(coChange.maxCommits, maxHistory));\n\n if (changeLog === undefined) {\n // git failed, is missing, or the repository has no commit yet. intent[] stays empty, as it\n // did when the old batch read failed, and co-changes.json is left alone: a failing git call\n // must never replace a good matrix with an empty one.\n console.error('[ctxo] Git history unavailable: intent[] left empty and co-changes.json not updated');\n } else {\n // Renames are resolved once; intent[] and the co-change matrix share the result.\n const commits = canonicalizeChangeLog(changeLog.commits);\n\n // Phase 2: intent[] and antiPatterns of the files indexed in this run\n const history = buildIntentHistory(commits, maxHistory);\n for (const { relativePath, fileIndex } of pendingIndices) {\n const fileCommits = history.get(relativePath) ?? [];\n fileIndex.intent = fileCommits.map((c) => ({\n hash: c.hash,\n message: c.message,\n date: c.date,\n kind: 'commit' as const,\n }));\n fileIndex.antiPatterns = revertDetector.detect(fileCommits);\n }\n\n // Phase 2b: the co-change matrix of the whole repository, whichever files this run re-indexes.\n writeCoChangeMatrix({\n writer,\n projectRoot: this.projectRoot,\n commits,\n head: changeLog.head,\n headCommittedAt: changeLog.headCommittedAt,\n coChange,\n indexedFiles: coChangeFiles(),\n });\n }\n } catch (err) {\n console.error(`[ctxo] History and co-change skipped: ${(err as Error).message}`);\n }\n }\n\n // Phase 2c: Community detection + snapshot\n //\n // Full indexing: run Louvain over the files this run indexed (all of the project).\n // Incremental (--files, --commit): the merged index, so Louvain sees the *complete* graph:\n // the just-updated fileIndex(es) spliced into the rest of the committed JSON\n // index, minus the removed files. Running it over the few updated files alone\n // would produce a meaningless N-singleton snapshot (modularity 0).\n // Opt-out (--skip-community): skip entirely. Warn if a stale snapshot exists on disk.\n let communitySnapshot: CommunitySnapshot | undefined;\n let symbolPageRank: ReadonlyMap<string, number> | undefined;\n\n if (options.skipCommunity && refreshProducts) {\n if (existsSync(join(this.ctxoRoot, 'index', 'communities.json'))) {\n console.error(\n `[ctxo] WARN stale communities.json present — --skip-community preserved existing snapshot. Run \\`ctxo index\\` (full) to refresh.`,\n );\n }\n } else if (refreshProducts) {\n try {\n const graphIndices = graphInput();\n const built = await this.buildCommunitySnapshot(\n graphIndices,\n {\n csharpTier,\n goTier,\n javaTier,\n tsCount: graphIndices.filter((idx) => /\\.(ts|tsx|js|jsx)$/.test(idx.file)).length,\n },\n gitAdapter,\n communityDetectorOptions(ignore.config),\n );\n communitySnapshot = built.snapshot;\n symbolPageRank = built.pagerank;\n const scope = incremental ? ' (incremental, full-graph recompute)' : '';\n console.error(\n `[ctxo] Community detection${scope}: ${countCommunities(communitySnapshot)} clusters (modularity ${communitySnapshot.modularity.toFixed(3)})`,\n );\n } catch (err) {\n console.error(`[ctxo] Community detection skipped: ${(err as Error).message}`);\n }\n }\n\n // Phase 3: Write all indices\n // What the index holds after this run is assembled first: both an incremental run and a full run read the\n // committed JSON as it was before this run wrote anything.\n const indexed = graphInput();\n\n // Removed and stale files leave the index before the new entries are written. On a case-insensitive file\n // system a case-only rename names one JSON file twice, so deleting afterwards would take the entry just\n // written for the new name. The JSON file deleted is the one the entry was read from. A file that cannot\n // be deleted is reported and the run goes on, since the index this run builds its products from already\n // leaves it out. Returns true only when a file was really deleted.\n const deleteEntry = (file: string): boolean => {\n let deleted = false;\n for (const jsonPath of readCommitted().jsonPaths.get(file) ?? []) {\n try {\n if (writer.deleteEntryFile(jsonPath)) deleted = true;\n } catch (err) {\n console.error(`[ctxo] Could not remove ${file} from the index: ${(err as Error).message}`);\n }\n }\n return deleted;\n };\n for (const file of removedPaths) deleteEntry(file);\n const pruned = [...new Set(stalePaths)].filter(deleteEntry).length;\n if (pruned > 0) {\n console.error(\n `[ctxo] Pruned ${pruned} stale index ${pruned === 1 ? 'entry' : 'entries'} (source file deleted, or excluded by index.ignore / index.ignoreProjects)`,\n );\n }\n for (const { fileIndex } of pendingIndices) writer.write(fileIndex);\n\n // Write schema version\n schemaManager.writeVersion();\n\n // Populate SQLite cache (skip rebuildFromJson since we just wrote the JSON). It holds what the snapshot\n // and the artifacts are built from: the files of this run after a full run, and after an incremental\n // run the merged index, not just the few files it re-indexed. initEmpty() clears the tables, which\n // init() would not (it re-inserts rows and duplicates edges).\n const storage = new SqliteStorageAdapter(this.ctxoRoot, { allowProductionPath: true });\n try {\n await storage.initEmpty();\n storage.bulkWrite(indexed);\n if (communitySnapshot) {\n storage.writeCommunities(communitySnapshot);\n }\n } finally {\n storage.close();\n }\n\n // Phase 2d: Persist derived architectural artifacts (drift events + boundary\n // violations). These are computed AFTER `writeCommunities` so that history\n // already holds the previous commit's snapshot (see writeArchitectureArtifacts).\n // Consumers:\n // - pages/ctxo-visualizer.html Architecture tab reads these directly.\n // - Future MCP tools can surface the same data without recomputing.\n if (communitySnapshot) {\n // The full graph, like the snapshot it is compared with: after an incremental run the edges of a few\n // files alone would hide every violation that starts in a file this run did not re-index.\n this.writeArchitectureArtifacts(indexed, communitySnapshot);\n\n // The contexts view reads the same merged index, so an incremental run writes what a full run would.\n // Non-fatal like the artifacts above.\n if (symbolPageRank) {\n try {\n computeAndWriteContextsView({\n projectRoot: this.projectRoot,\n ctxoRoot: this.ctxoRoot,\n config: ignore.config,\n indices: indexed,\n snapshot: communitySnapshot,\n symbolPageRank,\n });\n } catch (err) {\n console.error(`[ctxo] Contexts view skipped: ${(err as Error).message}`);\n }\n }\n }\n\n // Ensure .ctxo/.cache/ is in .gitignore (skip during verify runs)\n if (!options.skipSideEffects) {\n this.ensureGitignore();\n }\n\n // Tier summary\n const csCount = pendingIndices.filter(e => e.relativePath.endsWith('.cs')).length;\n const tsCount = pendingIndices.filter(e => /\\.(ts|tsx|js|jsx)$/.test(e.relativePath)).length;\n const goCount = pendingIndices.filter(e => e.relativePath.endsWith('.go')).length;\n const javaCount = pendingIndices.filter(e => e.relativePath.endsWith('.java')).length;\n const sqlCount = pendingIndices.filter(e => e.relativePath.toLowerCase().endsWith('.sql')).length;\n console.error(\n `[ctxo] Index complete: ${processed} files indexed${removedPaths.size > 0 ? `, ${removedPaths.size} removed` : ''}`,\n );\n if (tsCount > 0) console.error(`[ctxo] TypeScript/JS: ${tsCount} files (full tier)`);\n if (csCount > 0) console.error(`[ctxo] C#: ${csCount} files (${csharpTier} tier${csharpTierNote(csharpTierAtLoad, csharpTier)})`);\n if (goCount > 0) console.error(`[ctxo] Go: ${goCount} files (${goTier} tier${goTier === 'syntax' ? ' - Go 1.22+ for full analysis' : ''})`);\n if (javaCount > 0) console.error(`[ctxo] Java: ${javaCount} files (${javaTier} tier${javaTier === 'syntax' ? ' - JRE 11+ & \"ctxo install java --full-tier\" for full analysis' : ''})`);\n if (sqlCount > 0) console.error(`[ctxo] SQL: ${sqlCount} files (syntax tier)`);\n\n // Dispose Roslyn adapter\n if (roslynAdapter) await roslynAdapter.dispose();\n }\n\n private async autoInstallMissingPlugins(): Promise<void> {\n const detection = detectLanguages(this.projectRoot);\n const needed = decideNeededLanguages(detection);\n const missing: KnownLanguage[] = [];\n for (const lang of needed) {\n try {\n requireCjs.resolve(`${officialPluginFor(lang)}/package.json`);\n } catch {\n missing.push(lang);\n }\n }\n if (missing.length === 0) return;\n console.error(`[ctxo] --install-missing: installing ${missing.join(', ')}`);\n await new InstallCommand(this.projectRoot).run({ languages: missing, yes: true });\n }\n\n private printLanguagePreview(): void {\n const detection = detectLanguages(this.projectRoot);\n const lines: string[] = [];\n for (const [lang, count] of Object.entries(detection.byExtension)) {\n const hasPlugin = this.supportedExtensions.size > 0 && Object.entries(EXTENSION_LANGUAGE)\n .some(([ext, id]) => id === lang && this.supportedExtensions.has(ext));\n const status = hasPlugin ? 'plugin available' : 'no plugin — skipped';\n lines.push(` ${lang.padEnd(10)} ${String(count).padStart(5)} files (${status})`);\n }\n if (lines.length === 0) return;\n console.error('[ctxo] Language scan:');\n for (const line of lines) console.error(line);\n }\n\n private async registerDiscoveredPlugins(\n registry: LanguageAdapterRegistry,\n ignoreProjectPatterns: string[] = [],\n facts = false,\n ): Promise<{\n tsMorphLike: TsMorphLike | undefined;\n roslynAdapter: RoslynLike | null;\n csharpComposite: CSharpCompositeLike | null;\n csharpTier: string;\n goTier: string;\n javaTier: string;\n }> {\n const loaded = await loadPlugins(this.projectRoot, { ignoreProjects: ignoreProjectPatterns, facts });\n let tsMorphLike: TsMorphLike | undefined;\n let roslynAdapter: RoslynLike | null = null;\n let csharpComposite: CSharpCompositeLike | null = null;\n let csharpTier = 'unavailable';\n let goTier = 'unavailable';\n let javaTier = 'unavailable';\n\n for (const { plugin, adapter } of loaded) {\n // Plugins that expose an initialize() lifecycle need it called before register\n if (typeof adapter.initialize === 'function') {\n try {\n await adapter.initialize(this.projectRoot);\n } catch (err) {\n console.error(`[ctxo] Plugin ${plugin.id} initialize failed: ${(err as Error).message}`);\n continue;\n }\n }\n\n registry.register(plugin.extensions, adapter);\n\n // Duck-type: TsMorphAdapter exposes project-wide preload hooks\n const tsCandidate = adapter as unknown as Partial<TsMorphLike>;\n if (\n typeof tsCandidate.loadProjectSources === 'function' &&\n typeof tsCandidate.clearProjectSources === 'function'\n ) {\n tsMorphLike = tsCandidate as TsMorphLike;\n }\n\n // Duck-type: CSharpCompositeAdapter exposes Roslyn delegate + tier info\n const csCandidate = adapter as unknown as Partial<CSharpCompositeLike>;\n if (\n plugin.id === 'csharp' &&\n typeof csCandidate.getRoslynDelegate === 'function' &&\n typeof csCandidate.getTier === 'function'\n ) {\n csharpComposite = csCandidate as CSharpCompositeLike;\n csharpTier = csCandidate.getTier();\n roslynAdapter = csCandidate.getRoslynDelegate() ?? null;\n }\n\n // Duck-type: GoCompositeAdapter exposes tier info\n const goCandidate = adapter as unknown as Partial<GoCompositeLike>;\n if (plugin.id === 'go' && typeof goCandidate.getTier === 'function') {\n goTier = goCandidate.getTier();\n }\n\n // Duck-type: JavaCompositeAdapter exposes tier info\n const javaCandidate = adapter as unknown as Partial<JavaCompositeLike>;\n if (plugin.id === 'java' && typeof javaCandidate.getTier === 'function') {\n javaTier = javaCandidate.getTier();\n }\n\n const activeTier =\n plugin.id === 'csharp' ? csharpTier :\n plugin.id === 'go' ? goTier :\n plugin.id === 'java' ? javaTier :\n plugin.tier;\n const tierSuffix = activeTier !== plugin.tier ? ` (active: ${activeTier})` : '';\n console.error(`[ctxo] Plugin ${plugin.id}@${plugin.version} (${plugin.tier} tier${tierSuffix}) — ${plugin.extensions.join(', ')}`);\n }\n\n return { tsMorphLike, roslynAdapter, csharpComposite, csharpTier, goTier, javaTier };\n }\n\n private discoverFilesIn(root: string, ignoreFile: (p: string) => boolean = () => false): string[] {\n try {\n // -z: NUL-separated, unquoted names. Without it git prints a non-ASCII path in quotes with octal\n // escapes (\"src/\\303\\266d\\303\\274n\\303\\247.ts\") under the default core.quotePath, and the extension check drops it.\n const output = execFileSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard'], {\n cwd: root,\n encoding: 'utf-8',\n maxBuffer: 10 * 1024 * 1024,\n });\n\n return output\n .split('\\0')\n .filter((line) => line.length > 0)\n .filter((line) => this.isSupportedExtension(line))\n .map((line) => join(root, line))\n .filter((abs) => {\n const rel = relative(this.projectRoot, abs).replace(/\\\\/g, '/');\n return !ignoreFile(rel);\n })\n // `git ls-files --cached` still lists files that have been deleted in\n // the working tree but whose removal isn't staged yet. Filter those out\n // so we don't spam ENOENT errors from readFileSync on stale entries.\n .filter((abs) => existsSync(abs));\n } catch {\n console.error(`[ctxo] git ls-files failed for ${root}`);\n return [];\n }\n }\n\n /**\n * The folders a full run discovers files in (`kept`), and the workspace folders that\n * `index.ignoreProjects` leaves out (`ignored`). Outside a monorepo, `kept` is the project root.\n */\n private discoverWorkspaces(\n ignoreProject: (p: string) => boolean = () => false,\n ): { kept: string[]; ignored: string[] } {\n const pkgPath = join(this.projectRoot, 'package.json');\n if (!existsSync(pkgPath)) return { kept: [this.projectRoot], ignored: [] };\n\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n const workspaces: string[] | undefined = Array.isArray(pkg.workspaces)\n ? pkg.workspaces\n : pkg.workspaces?.packages;\n\n if (!workspaces || workspaces.length === 0) return { kept: [this.projectRoot], ignored: [] };\n\n // Resolve workspace patterns (supports simple globs like packages/*)\n const resolved: string[] = [];\n for (const ws of workspaces) {\n if (ws.endsWith('/*') || ws.endsWith('\\\\*')) {\n // Glob: packages/* → list subdirectories of packages/\n const parentDir = join(this.projectRoot, ws.slice(0, -2));\n if (existsSync(parentDir)) {\n for (const entry of readdirSync(parentDir, { withFileTypes: true })) {\n if (entry.isDirectory()) {\n resolved.push(join(parentDir, entry.name));\n }\n }\n }\n } else {\n // Literal path\n const wsPath = join(this.projectRoot, ws);\n if (existsSync(wsPath)) {\n resolved.push(wsPath);\n }\n }\n }\n\n if (resolved.length === 0) return { kept: [this.projectRoot], ignored: [] };\n\n const ignored: string[] = [];\n const filtered = resolved.filter((wsAbs) => {\n const rel = relative(this.projectRoot, wsAbs).replace(/\\\\/g, '/');\n if (ignoreProject(rel)) {\n console.error(`[ctxo] index.ignoreProjects: skipping ${rel}`);\n ignored.push(wsAbs);\n return false;\n }\n return true;\n });\n\n if (filtered.length === 0) return { kept: [this.projectRoot], ignored };\n\n console.error(`[ctxo] Monorepo detected: ${filtered.length} workspace(s)`);\n return { kept: filtered, ignored };\n } catch {\n return { kept: [this.projectRoot], ignored: [] };\n }\n }\n\n private isSupportedExtension(filePath: string): boolean {\n const ext = extname(filePath).toLowerCase();\n return this.supportedExtensions.has(ext);\n }\n\n private async runCheck(): Promise<void> {\n console.error('[ctxo] Checking index freshness...');\n\n // Register adapters so supportedExtensions includes discovered extensions\n const registry = new LanguageAdapterRegistry();\n const { roslynAdapter: _roslyn } = await this.registerDiscoveredPlugins(registry);\n this.supportedExtensions = registry.getSupportedExtensions();\n if (_roslyn) await _roslyn.dispose();\n\n const hasher = new ContentHasher();\n const files = this.discoverFilesIn(this.projectRoot);\n const reader = new (await import('../adapters/storage/json-index-reader.js')).JsonIndexReader(this.ctxoRoot);\n const indices = reader.readAll();\n const indexedMap = new Map(indices.map((i) => [i.file, i]));\n\n let staleCount = 0;\n\n for (const filePath of files) {\n if (!this.isSupportedExtension(filePath)) continue;\n\n const relativePath = relative(this.projectRoot, filePath).replace(/\\\\/g, '/');\n const indexed = indexedMap.get(relativePath);\n\n if (!indexed) {\n console.error(`[ctxo] NOT INDEXED: ${relativePath}`);\n staleCount++;\n continue;\n }\n\n // Guard: file may be deleted from disk but still tracked by git\n if (!existsSync(filePath)) {\n console.error(`[ctxo] DELETED: ${relativePath}`);\n staleCount++;\n continue;\n }\n\n // Fast path: mtime check (skip hash if mtime hasn't changed)\n const mtime = Math.floor(statSync(filePath).mtimeMs / 1000);\n if (mtime <= indexed.lastModified) continue;\n\n // Slow path: hash-based verification (handles git checkout, cp -p, CI)\n if (indexed.contentHash) {\n const source = readSourceText(filePath);\n const currentHash = hasher.hash(source);\n if (currentHash === indexed.contentHash) continue;\n console.error(`[ctxo] STALE: ${relativePath} (content hash differs)`);\n } else {\n // Legacy index: contentHash wasn't populated yet. We cannot tell whether\n // the mtime bump reflects real content change — fail closed, but tell the user why.\n console.error(\n `[ctxo] STALE: ${relativePath} (index predates contentHash — run \\`ctxo index\\` once to enable mtime-tolerant checks)`,\n );\n }\n staleCount++;\n }\n\n if (staleCount > 0) {\n console.error(`[ctxo] ${staleCount} file(s) need re-indexing. Run \"ctxo index\"`);\n process.exit(1);\n }\n\n console.error('[ctxo] Index is up to date');\n }\n\n private ensureGitignore(): void {\n const gitignorePath = join(this.projectRoot, '.gitignore');\n const cachePattern = '.ctxo/.cache/';\n const suffix = `\\n# Ctxo local cache (never committed)\\n${cachePattern}\\n`;\n\n // Read-modify-write atomically to avoid TOCTOU race\n const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf-8') : '';\n if (existing.includes(cachePattern)) return;\n\n writeFileSync(gitignorePath, existing + suffix, 'utf-8');\n console.error('[ctxo] Added .ctxo/.cache/ to .gitignore');\n }\n\n /**\n * Which files an incremental run re-indexes, and which entries of the committed index it drops.\n *\n * The candidates are the paths asked for plus the files the commit added, modified or renamed to. Only\n * a file that a full run would index is kept: a language plugin handles it, `index.ignore` does not\n * match it, it lies inside a workspace that `index.ignoreProjects` leaves in, and (for a path listed by\n * name) git does not ignore it through .gitignore. A candidate that is\n * gone from the working tree is dropped from the index instead of being re-indexed, unless git tracks\n * it as skip-worktree (a sparse checkout): then it is merely not checked out and its entry stays.\n *\n * What the commit deleted, and the old path of what it renamed, are dropped without looking at the\n * working tree: on a case-insensitive file system a case-only rename leaves the old name \"existing\".\n * Only paths that have an entry in the committed index are reported as removed.\n */\n private async selectIncrementalFiles(\n paths: readonly string[],\n commitChanges: readonly FileChange[],\n registry: LanguageAdapterRegistry,\n ignoreFile: (path: string) => boolean,\n workspaces: readonly string[],\n indexedFiles: ReadonlySet<string>,\n gitAdapter: SimpleGitAdapter,\n ): Promise<{ changed: string[]; removed: string[] }> {\n const candidates = new Set<string>();\n const listed = new Set<string>();\n const dropped = new Set<string>();\n\n for (const raw of paths) {\n const path = toRepoPath(this.projectRoot, raw);\n if (path === undefined) {\n console.error(`[ctxo] Skipped ${raw}: not a path inside the project`);\n continue;\n }\n candidates.add(path);\n listed.add(path);\n }\n for (const change of commitChanges) {\n if (change.status === 'D') {\n dropped.add(change.path);\n continue;\n }\n candidates.add(change.path);\n if (change.status === 'R' && change.oldPath !== undefined) dropped.add(change.oldPath);\n }\n\n const isIndexable = (path: string): boolean =>\n registry.getAdapter(path) !== undefined &&\n !ignoreFile(path) &&\n workspaces.some((workspace) => isInsideDirectory(workspace, join(this.projectRoot, path)));\n\n let changed: string[] = [];\n const missing: string[] = [];\n let skippedListed = 0;\n for (const path of [...candidates].sort(compareCodepoint)) {\n if (!isIndexable(path)) {\n // A commit changes plenty of files nothing indexes (docs, JSON); only a file asked for by name is worth a word.\n if (listed.has(path)) skippedListed += 1;\n } else if (existsSync(join(this.projectRoot, path))) {\n changed.push(path);\n } else {\n missing.push(path);\n }\n }\n // A candidate that is missing from the working tree is dropped from the index, unless git tracks it\n // as skip-worktree: then it is merely not checked out, and its entry stays.\n for (const path of await this.withoutSkipWorktree(missing, gitAdapter)) dropped.add(path);\n\n // A full run leaves out what .gitignore covers (it lists files with --exclude-standard), so a path\n // listed by name is left out too. The files of a commit are tracked, which git never calls ignored, so\n // only the listed ones are asked about. If git cannot say, they are indexed as before.\n const toCheck = changed.filter((path) => listed.has(path));\n if (toCheck.length > 0) {\n const ignoredByGit = await gitAdapter.getIgnoredPaths(toCheck);\n if (ignoredByGit === undefined) {\n console.error('[ctxo] Could not ask git which listed files .gitignore excludes: indexing them anyway');\n } else {\n skippedListed += changed.filter((path) => ignoredByGit.has(path)).length;\n changed = changed.filter((path) => !ignoredByGit.has(path));\n }\n }\n if (skippedListed > 0) {\n console.error(\n `[ctxo] Skipped ${skippedListed} listed file(s) that a full run would not index (no language plugin, index.ignore, .gitignore, or outside the workspaces)`,\n );\n }\n\n const reindexed = new Set(changed);\n const removed = [...dropped]\n .filter((path) => indexedFiles.has(path) && !reindexed.has(path))\n .sort(compareCodepoint);\n return { changed, removed };\n }\n\n /**\n * Keeps the candidates whose index entry may be deleted. A path that git tracks but marks skip-worktree\n * (a sparse checkout) is absent from the working tree on purpose, so a missing source says nothing about\n * it, and its entry is committed data that other machines rely on. One git call lists those paths, made\n * only when there is a candidate and kept in memory. If git cannot answer, nothing is deleted this run\n * (fail safe).\n */\n private async withoutSkipWorktree(candidates: readonly string[], gitAdapter: SimpleGitAdapter): Promise<string[]> {\n if (candidates.length === 0) return [];\n const skipWorktree = await gitAdapter.getSkipWorktreePaths();\n if (skipWorktree === undefined) {\n console.error(\n '[ctxo] Could not tell which paths git marks skip-worktree (sparse checkout): no stale index entry was removed',\n );\n return [];\n }\n return candidates.filter((path) => !skipWorktree.has(path));\n }\n\n /**\n * The committed index entries a full run drops, as source paths. An entry is stale when its source file\n * is gone from the working tree, or when `index.ignore` / `index.ignoreProjects` now excludes it, and\n * this run did not just re-index it.\n *\n * It is never stale merely because no plugin loaded on this machine handles the file: that entry may\n * have been committed by a machine that has the plugin, and the file is still there.\n */\n private findStaleEntries(\n committed: readonly FileIndex[],\n reindexed: ReadonlySet<string>,\n isIgnored: (path: string) => boolean,\n ): string[] {\n return committed\n .map((idx) => idx.file)\n .filter((file) => !reindexed.has(file) && (!existsSync(join(this.projectRoot, file)) || isIgnored(file)))\n .sort(compareCodepoint);\n }\n\n /**\n * Produce the FileIndex list used as input to community detection, the architecture artifacts and the\n * SQLite cache (the co-change phase has its own file set, `coChangeFiles` in `run`).\n *\n * The list is sorted by file name in code point order, whichever run builds it. The graph, the\n * community detection and the PageRank that follow depend on the order they are fed in, and a full\n * run (discovery order) and an incremental run (directory order of the committed JSON, new files\n * appended) would otherwise feed them differently, and could write different snapshots for one HEAD.\n *\n * Full index run (`base` undefined): returns the indices of this run, sorted by file. A full run indexes\n * every file it discovers, so they are the whole project. The committed JSON of a file this machine\n * cannot index (no plugin loaded here) stays in the index, because a full run prunes only entries that\n * went stale, but it is not part of these local graph products.\n * Incremental run (`--files`, `--commit`, `base` given): pendingIndices holds only the just-updated\n * files. The committed JSON index is spliced in around them, a fresh index replacing the committed\n * entry of the same file and the entries of `base.removedPaths` left out, so Louvain sees the COMPLETE\n * project graph. Without this, Louvain would run on a few-file subgraph and emit a meaningless\n * modularity-0 snapshot. `removedPaths` is applied here, and not by reading the index again after the\n * JSON is deleted, because this runs in Phase 2b, before Phase 3 deletes anything.\n */\n private buildGraphInputIndices(\n pendingIndices: ReadonlyArray<{ relativePath: string; fileIndex: FileIndex }>,\n base?: { committed: readonly FileIndex[]; removedPaths: ReadonlySet<string> },\n ): FileIndex[] {\n if (base === undefined) return sortByFile(pendingIndices.map(({ fileIndex }) => fileIndex));\n\n const { committed, removedPaths } = base;\n const pendingByPath = new Map<string, FileIndex>();\n for (const { fileIndex } of pendingIndices) {\n pendingByPath.set(fileIndex.file, fileIndex);\n }\n\n const merged: FileIndex[] = [];\n for (const idx of committed) {\n if (removedPaths.has(idx.file)) continue;\n const override = pendingByPath.get(idx.file);\n if (override) {\n merged.push(override);\n pendingByPath.delete(idx.file);\n } else {\n merged.push(idx);\n }\n }\n // Newly indexed files (no prior committed entry) get appended.\n for (const remaining of pendingByPath.values()) merged.push(remaining);\n return sortByFile(merged);\n }\n\n private async buildCommunitySnapshot(\n indices: readonly FileIndex[],\n tiers: { csharpTier: string; goTier: string; javaTier: string; tsCount: number },\n gitAdapter: SimpleGitAdapter,\n detectorOptions: CommunityDetectorOptions,\n ): Promise<{ snapshot: CommunitySnapshot; pagerank: ReadonlyMap<string, number> }> {\n const graph = new SymbolGraph();\n for (const fileIndex of indices) {\n for (const symbol of fileIndex.symbols) graph.addNode(symbol);\n }\n for (const fileIndex of indices) {\n for (const edge of fileIndex.edges) graph.addEdge(edge);\n }\n\n const pagerank = new PageRankCalculator().calculate(graph, { limit: graph.nodeCount });\n const pagerankMap = new Map<string, number>();\n for (const entry of pagerank.rankings) pagerankMap.set(entry.symbolId, entry.score);\n\n const detector = new CommunityDetector(detectorOptions);\n const edgeQuality = pickEdgeQuality(tiers);\n const detectResult = detector.detect(graph, pagerankMap, edgeQuality);\n\n const snapshot: CommunitySnapshot = {\n version: 1,\n computedAt: new Date().toISOString(),\n commitSha: await safeHeadSha(gitAdapter, this.projectRoot),\n modularity: detectResult.modularity,\n communities: detectResult.communities,\n godNodes: detectResult.godNodes,\n edgeQuality: detectResult.edgeQuality,\n crossClusterEdges: detectResult.crossClusterEdges,\n };\n return { snapshot, pagerank: pagerankMap };\n }\n\n /**\n * Writes drift-events.json and boundary-violations.json next to\n * communities.json. Must be called AFTER storage.writeCommunities, which\n * archives the previous current snapshot into communities.history/ when HEAD\n * has moved since the last run. On a rerun at the same HEAD nothing is\n * archived (history holds one snapshot per commit), so history[0] is then the\n * snapshot of the last different commit. The detectors compare only with\n * earlier commits and count distinct commits, whatever else the history holds.\n */\n private writeArchitectureArtifacts(\n indices: readonly FileIndex[],\n snapshot: CommunitySnapshot,\n ): void {\n try {\n const snapshotWriter = new CommunitySnapshotWriter(this.ctxoRoot, {\n allowProductionPath: true,\n });\n const history = snapshotWriter.listHistory();\n\n const graph = new SymbolGraph();\n for (const fileIndex of indices) {\n for (const symbol of fileIndex.symbols) graph.addNode(symbol);\n }\n for (const fileIndex of indices) {\n for (const edge of fileIndex.edges) graph.addEdge(edge);\n }\n\n const driftResult = new DriftDetector().detect(snapshot, history);\n const violationsResult = new BoundaryViolationDetector().detect(\n graph,\n snapshot,\n history,\n );\n\n const computedAt = new Date().toISOString();\n const driftArtifact: DriftEventsArtifact = {\n version: 1,\n computedAt,\n commitSha: snapshot.commitSha,\n confidence: driftResult.confidence,\n snapshotsAvailable: driftResult.snapshotsAvailable,\n distinctCommits: driftResult.distinctCommits,\n ...(driftResult.hint ? { hint: driftResult.hint } : {}),\n events: driftResult.events,\n };\n const violationsArtifact: BoundaryViolationsArtifact = {\n version: 1,\n computedAt,\n commitSha: snapshot.commitSha,\n confidence: violationsResult.confidence,\n snapshotsAvailable: violationsResult.snapshotsAvailable,\n distinctCommits: violationsResult.distinctCommits,\n ...(violationsResult.hint ? { hint: violationsResult.hint } : {}),\n violations: violationsResult.violations,\n };\n\n const writer = new ArchitectureArtifactsWriter(this.ctxoRoot, {\n allowProductionPath: true,\n });\n writer.writeDriftEvents(driftArtifact);\n writer.writeBoundaryViolations(violationsArtifact);\n\n console.error(\n `[ctxo] Architecture artifacts: ${driftResult.events.length} drift events, ` +\n `${violationsResult.violations.length} boundary violations ` +\n `(confidence: drift=${driftResult.confidence}, violations=${violationsResult.confidence})`,\n );\n } catch (err) {\n // Non-fatal: detectors failing must not break the core index.\n console.error(\n `[ctxo] Architecture artifacts skipped: ${(err as Error).message}`,\n );\n }\n }\n}\n\n/**\n * The hint after the C# tier in the index summary. A plugin that loaded at the full tier and is at the\n * syntax tier after the Roslyn batch lost its helper (restore or build failure): `ctxo doctor` says why.\n */\nfunction csharpTierNote(tierAtLoad: string, tier: string): string {\n if (tier !== 'syntax') return '';\n return tierAtLoad === 'full' ? ' - the Roslyn helper failed, run \"ctxo doctor\"' : ' - .NET SDK 8+ for full analysis';\n}\n\nfunction pickEdgeQuality(tiers: {\n csharpTier: string;\n goTier: string;\n javaTier: string;\n tsCount: number;\n}): EdgeQuality {\n const hasSyntaxOnly = tiers.csharpTier === 'syntax' || tiers.goTier === 'syntax' || tiers.javaTier === 'syntax';\n const hasFull =\n tiers.tsCount > 0 || tiers.csharpTier === 'full' || tiers.goTier === 'full' || tiers.javaTier === 'full';\n if (hasSyntaxOnly && hasFull) return 'mixed';\n if (hasSyntaxOnly) return 'syntax-only';\n return 'full';\n}\n\n/** The indices ordered by file name in code point order (never by locale), leaving the input alone. */\nfunction sortByFile(indices: readonly FileIndex[]): FileIndex[] {\n return [...indices].sort((a, b) => compareCodepoint(a.file, b.file));\n}\n\n/**\n * The short SHA of HEAD as git prints it, or 'nocommit' when there is none. It is not cut to a fixed\n * length: the snapshot staleness check compares it with `getHeadSha()`, which is whatever\n * `git rev-parse --short HEAD` gives for this repository.\n */\nasync function safeHeadSha(gitAdapter: SimpleGitAdapter, projectRoot: string): Promise<string> {\n try {\n const sha = await gitAdapter.getHeadSha();\n if (sha) return sha;\n } catch {\n /* fall through */\n }\n try {\n // cwd matters: without it git answers for whichever repository the process happens to run in.\n const out = execFileSync('git', ['rev-parse', '--short', 'HEAD'], {\n cwd: projectRoot,\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n return out.trim() || 'nocommit';\n } catch {\n return 'nocommit';\n }\n}\n\n/**\n * The files one commit changed, for `--commit`. Throws when git cannot say (unknown revision, or git\n * failed), because a run that cannot tell what to re-index must not pretend it did.\n */\nasync function readCommitChanges(gitAdapter: SimpleGitAdapter, rev: string): Promise<FileChange[]> {\n const changes = await gitAdapter.getCommitFileChanges(rev);\n if (changes === undefined) {\n throw new Error(`--commit ${rev}: cannot read the files this commit changed (unknown revision, or git failed)`);\n }\n return changes;\n}\n\n/**\n * `input` as a repo-relative path with forward slashes, or undefined when it is empty or points outside\n * the project. Accepts backslashes, a leading `./`, and an absolute path inside the project.\n */\nfunction toRepoPath(projectRoot: string, input: string): string | undefined {\n const trimmed = input.trim().replace(/\\\\/g, '/');\n if (trimmed === '') return undefined;\n const relativePath = relative(projectRoot, resolve(projectRoot, trimmed));\n if (relativePath === '' || isAbsolute(relativePath) || relativePath.split(/[\\\\/]/)[0] === '..') return undefined;\n return relativePath.replace(/\\\\/g, '/');\n}\n\n/** True when `absolute` lies inside `directory` (and is not the directory itself). */\nfunction isInsideDirectory(directory: string, absolute: string): boolean {\n const relativePath = relative(directory, absolute);\n return relativePath !== '' && !isAbsolute(relativePath) && relativePath.split(/[\\\\/]/)[0] !== '..';\n}\n\nfunction countCommunities(snapshot: CommunitySnapshot): number {\n const ids = new Set<number>();\n for (const entry of snapshot.communities) ids.add(entry.communityId);\n return ids.size;\n}\n","import { createHash } from 'node:crypto';\n\nexport class ContentHasher {\n hash(content: string): string {\n return createHash('sha256').update(content, 'utf-8').digest('hex');\n }\n}\n","import { extname } from 'node:path';\nimport type { ILanguageAdapter } from '@ctxo/plugin-api';\n\nexport class LanguageAdapterRegistry {\n private readonly adaptersByExtension = new Map<string, ILanguageAdapter>();\n\n register(extensions: readonly string[], adapter: ILanguageAdapter): void {\n for (const ext of extensions) {\n this.adaptersByExtension.set(ext.toLowerCase(), adapter);\n }\n }\n\n getSupportedExtensions(): Set<string> {\n return new Set(this.adaptersByExtension.keys());\n }\n\n getAdapter(filePath: string): ILanguageAdapter | undefined {\n if (!filePath) return undefined;\n\n const ext = extname(filePath).toLowerCase();\n if (!ext) return undefined;\n\n return this.adaptersByExtension.get(ext);\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport type { CtxoLanguagePlugin, PluginCapabilities, PluginContext, ILanguageAdapter, IWorkspace } from '@ctxo/plugin-api';\nimport { discoverPlugins, type DiscoveredPlugin } from '../adapters/language/plugin-discovery.js';\nimport { detectWorkspace } from '../adapters/workspace/single-package-workspace.js';\nimport { createLogger } from '../core/logger.js';\nimport { makeGlobMatcher } from '../core/config/load-config.js';\n\nconst log = createLogger('ctxo:plugin-loader');\n\nexport interface LoadedPlugin {\n readonly plugin: CtxoLanguagePlugin;\n readonly adapter: ILanguageAdapter;\n readonly specifier: string;\n}\n\nfunction manifestHasPlugins(path: string): boolean {\n try {\n const raw = JSON.parse(readFileSync(path, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n };\n const all = { ...raw.dependencies, ...raw.devDependencies, ...raw.peerDependencies };\n return Object.keys(all).some((n) => n.startsWith('@ctxo/lang-') || n.startsWith('ctxo-lang-'));\n } catch {\n return false;\n }\n}\n\n/**\n * Resolve the package.json that should be scanned for plugin deps.\n * Preference order:\n * 1. projectRoot/package.json (user's project)\n * 2. cli install location (walk up from __dirname until package.json)\n */\nexport function loadManifestPath(projectRoot: string): string | null {\n return resolveManifestPath(projectRoot);\n}\n\nfunction resolveManifestPath(projectRoot: string): string | null {\n const projectManifest = join(projectRoot, 'package.json');\n if (existsSync(projectManifest) && manifestHasPlugins(projectManifest)) {\n return projectManifest;\n }\n\n let dir = import.meta.dirname;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'package.json');\n if (existsSync(candidate) && manifestHasPlugins(candidate)) return candidate;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n // Last resort: return projectManifest even if empty so discovery reports absence.\n return existsSync(projectManifest) ? projectManifest : null;\n}\n\nfunction buildContext(\n projectRoot: string,\n workspace: IWorkspace,\n pluginId: string,\n capabilities: PluginCapabilities,\n): PluginContext {\n const pluginLog = createLogger(`ctxo:plugin:${pluginId}`);\n return {\n logger: {\n debug: (msg, ...args) => pluginLog.info(String(msg), ...args),\n info: (msg, ...args) => pluginLog.info(String(msg), ...args),\n warn: (msg, ...args) => pluginLog.warn(String(msg), ...args),\n error: (msg, ...args) => pluginLog.error(String(msg), ...args),\n },\n projectRoot,\n workspace,\n config: {},\n capabilities,\n };\n}\n\nexport interface LoadPluginsOptions {\n /**\n * Glob patterns (matched against workspace paths relative to projectRoot)\n * for workspaces whose plugin deps should be ignored during discovery.\n * Sourced from `.ctxo/config.yaml#index.ignoreProjects`.\n */\n readonly ignoreProjects?: readonly string[];\n /** Facts extraction requested (`index.facts: true`); handed to every plugin as a capability. */\n readonly facts?: boolean;\n}\n\n/**\n * Capabilities the host offers every plugin. Computed once from all discovered\n * plugins, so a host-language plugin learns that a `.sql` plugin is present.\n */\nexport function hostCapabilities(\n plugins: readonly CtxoLanguagePlugin[],\n options: { readonly facts: boolean },\n): PluginCapabilities {\n return {\n facts: options.facts,\n sqlCallSites: plugins.some((p) => p.extensions.some((e) => e.toLowerCase() === '.sql')),\n };\n}\n\nexport async function loadPlugins(\n projectRoot: string,\n options: LoadPluginsOptions = {},\n): Promise<LoadedPlugin[]> {\n const manifestPath = resolveManifestPath(projectRoot);\n if (!manifestPath) {\n log.info('No package.json found for plugin discovery');\n return [];\n }\n\n const workspace = detectWorkspace(projectRoot);\n const ignoreProjectPatterns = options.ignoreProjects ?? [];\n const shouldSkipSpecifier = ignoreProjectPatterns.length === 0\n ? undefined\n : makeGlobMatcher(ignoreProjectPatterns.slice());\n const result = await discoverPlugins({ manifestPath, shouldSkipSpecifier });\n\n // Computed once, from every discovered plugin, before any createAdapter call.\n const capabilities = hostCapabilities(\n result.plugins.map((p) => p.plugin),\n { facts: options.facts ?? false },\n );\n\n const loaded: LoadedPlugin[] = [];\n for (const { plugin, specifier } of result.plugins as readonly DiscoveredPlugin[]) {\n try {\n const ctx = buildContext(projectRoot, workspace, plugin.id, capabilities);\n const adapter = plugin.createAdapter(ctx);\n loaded.push({ plugin, adapter, specifier });\n } catch (err) {\n log.warn(`Plugin ${plugin.id} createAdapter failed: ${(err as Error).message}`);\n }\n }\n return loaded;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, isAbsolute, resolve } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { CtxoLanguagePlugin } from '@ctxo/plugin-api';\nimport { SUPPORTED_API_VERSIONS } from '@ctxo/plugin-api';\nimport { createLogger } from '../../core/logger.js';\n\nconst log = createLogger('ctxo:plugin-discovery');\n\nconst OFFICIAL_PREFIX = '@ctxo/lang-';\nconst COMMUNITY_PREFIX = 'ctxo-lang-';\n\nexport interface DiscoverOptions {\n /** Absolute path to the package.json used for dependency scanning. */\n readonly manifestPath: string;\n /**\n * Explicit plugin list. When provided, suppresses auto-discovery and loads\n * only these packages/paths. Strings starting with '.' or '/' are treated\n * as local paths resolved against the manifest directory.\n */\n readonly explicit?: readonly string[];\n /**\n * Predicate that returns true for plugin specifiers that should be skipped\n * entirely (never imported). Used by the CLI to short-circuit loading of\n * plugins whose backing workspace was excluded via\n * `.ctxo/config.yaml#index.ignoreProjects`.\n */\n readonly shouldSkipSpecifier?: (specifier: string) => boolean;\n}\n\nexport interface DiscoveredPlugin {\n readonly plugin: CtxoLanguagePlugin;\n readonly specifier: string;\n}\n\nexport interface PluginLoadFailure {\n readonly specifier: string;\n readonly reason: string;\n}\n\nexport interface DiscoveryResult {\n readonly plugins: readonly DiscoveredPlugin[];\n readonly failures: readonly PluginLoadFailure[];\n}\n\nfunction readManifestDeps(manifestPath: string): string[] {\n try {\n const raw = readFileSync(manifestPath, 'utf-8');\n const manifest = JSON.parse(raw) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n };\n const all = {\n ...manifest.dependencies,\n ...manifest.devDependencies,\n ...manifest.peerDependencies,\n };\n return Object.keys(all).filter(\n (name) => name.startsWith(OFFICIAL_PREFIX) || name.startsWith(COMMUNITY_PREFIX),\n );\n } catch (err) {\n log.warn(`Failed to read manifest ${manifestPath}: ${(err as Error).message}`);\n return [];\n }\n}\n\nfunction isLocalSpecifier(spec: string): boolean {\n return spec.startsWith('.') || spec.startsWith('/') || isAbsolute(spec);\n}\n\ntype ExportsEntry = string | { [condition: string]: ExportsEntry } | null | undefined;\n\nfunction pickEsmEntry(exportsField: unknown): string | undefined {\n if (!exportsField) return undefined;\n if (typeof exportsField === 'string') return exportsField;\n if (typeof exportsField !== 'object') return undefined;\n const table = exportsField as Record<string, ExportsEntry>;\n const dot = '.' in table ? table['.'] : (exportsField as ExportsEntry);\n if (typeof dot === 'string') return dot;\n if (!dot || typeof dot !== 'object') return undefined;\n for (const key of ['import', 'node', 'default'] as const) {\n const nested = (dot as Record<string, ExportsEntry>)[key];\n if (typeof nested === 'string') return nested;\n if (nested && typeof nested === 'object') {\n for (const inner of ['default', 'import', 'node'] as const) {\n const v = (nested as Record<string, ExportsEntry>)[inner];\n if (typeof v === 'string') return v;\n }\n }\n }\n return undefined;\n}\n\nconst cliFallbackRequire = createRequire(import.meta.url);\n\n/**\n * Absolute path of `${specifier}/package.json`, found the way the plugin loader\n * finds a plugin: through `projectRequire` (the consumer project) first, then\n * from the CLI's own location. The CLI fallback matters for a global install\n * run in a repository without a package.json, and for dev/test flows (where the\n * CLI source lives inside the plugin's monorepo) that resolve without a\n * populated node_modules. Throws the project lookup's error when neither finds it.\n *\n * Anchored on `${specifier}/package.json` because `require.resolve(spec)` fails\n * for ESM-only packages whose \"exports\" map has no \"require\" condition.\n */\nexport function resolvePluginPackageJson(specifier: string, projectRequire: NodeJS.Require): string {\n try {\n return projectRequire.resolve(`${specifier}/package.json`);\n } catch (primary) {\n try {\n return cliFallbackRequire.resolve(`${specifier}/package.json`);\n } catch {\n throw primary;\n }\n }\n}\n\nfunction resolvePluginEntryUrl(\n specifier: string,\n manifestRequire: NodeJS.Require,\n): string {\n // Resolve bare specifiers against the consumer project's node_modules first,\n // not the CLI bundle location. Matters when `ctxo` runs via npx, where plain\n // import() would look in ~/.npm/_npx/<hash>/node_modules.\n const pkgJsonPath = resolvePluginPackageJson(specifier, manifestRequire);\n const pkgDir = dirname(pkgJsonPath);\n const pkgJson = JSON.parse(readFileSync(pkgJsonPath, 'utf-8')) as {\n main?: string;\n module?: string;\n exports?: unknown;\n };\n const entry = pickEsmEntry(pkgJson.exports) ?? pkgJson.module ?? pkgJson.main ?? 'index.js';\n return pathToFileURL(resolve(pkgDir, entry)).href;\n}\n\nasync function tryLoad(\n specifier: string,\n baseDir: string,\n manifestRequire: NodeJS.Require,\n): Promise<CtxoLanguagePlugin | PluginLoadFailure> {\n try {\n const target = isLocalSpecifier(specifier)\n ? pathToFileURL(resolve(baseDir, specifier)).href\n : resolvePluginEntryUrl(specifier, manifestRequire);\n\n const mod = (await import(target)) as {\n default?: unknown;\n plugin?: unknown;\n };\n const candidate = (mod.default ?? mod.plugin ?? mod) as Partial<CtxoLanguagePlugin>;\n\n if (!candidate || typeof candidate !== 'object') {\n return { specifier, reason: 'module export is not an object' };\n }\n if (!(SUPPORTED_API_VERSIONS as readonly unknown[]).includes(candidate.apiVersion)) {\n return {\n specifier,\n reason: `unsupported apiVersion ${String(candidate.apiVersion)} (supported: ${SUPPORTED_API_VERSIONS.join(', ')})`,\n };\n }\n if (typeof candidate.createAdapter !== 'function') {\n return { specifier, reason: 'missing createAdapter()' };\n }\n if (typeof candidate.id !== 'string' || candidate.id.length === 0) {\n return { specifier, reason: 'missing or empty id' };\n }\n if (!Array.isArray(candidate.extensions)) {\n return { specifier, reason: 'extensions must be an array' };\n }\n if (candidate.tier !== 'syntax' && candidate.tier !== 'full') {\n return { specifier, reason: `invalid tier ${String(candidate.tier)}` };\n }\n\n return candidate as CtxoLanguagePlugin;\n } catch (err) {\n return { specifier, reason: (err as Error).message };\n }\n}\n\nexport async function discoverPlugins(options: DiscoverOptions): Promise<DiscoveryResult> {\n const { manifestPath } = options;\n if (!existsSync(manifestPath)) {\n log.info(`Manifest not found at ${manifestPath} — no plugins discovered`);\n return { plugins: [], failures: [] };\n }\n\n const baseDir = dirname(manifestPath);\n const specifiers = options.explicit ?? readManifestDeps(manifestPath);\n const manifestRequire = createRequire(pathToFileURL(manifestPath).href);\n\n const plugins: DiscoveredPlugin[] = [];\n const failures: PluginLoadFailure[] = [];\n\n for (const spec of specifiers) {\n if (options.shouldSkipSpecifier?.(spec)) {\n log.info(`Skipping plugin ${spec} (matched ignoreProjects)`);\n continue;\n }\n const result = await tryLoad(spec, baseDir, manifestRequire);\n if ('apiVersion' in result) {\n plugins.push({ plugin: result, specifier: spec });\n } else {\n failures.push(result);\n log.warn(`Skipped plugin ${spec}: ${result.reason}`);\n }\n }\n\n return { plugins, failures };\n}\n","import { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport {\n KNOWN_LANGUAGES,\n officialPluginFor,\n detectLanguages,\n decideNeededLanguages,\n type KnownLanguage,\n} from '../core/detection/detect-languages.js';\nimport {\n resolvePackageManager,\n buildInstallCommand,\n isPackageManager,\n isWorkspaceRoot,\n PACKAGE_MANAGERS,\n type PackageManager,\n type Resolution,\n} from '../core/install/package-manager.js';\nimport { runPackageManager } from '../core/install/run-package-manager.js';\nimport { javaRuntimeAvailable } from '../core/detection/detect-java-runtime.js';\n\nexport interface InstallOptions {\n readonly languages?: readonly string[];\n readonly yes?: boolean;\n readonly global?: boolean;\n readonly dryRun?: boolean;\n readonly pm?: string;\n readonly version?: string;\n readonly force?: boolean;\n readonly fullTier?: boolean;\n readonly syntaxOnly?: boolean;\n}\n\n/** Decide the java package set from JRE availability + flags. Pure + unit-testable. */\nexport function resolveJavaPackages(opts: { jreAvailable: boolean; fullTier?: boolean; syntaxOnly?: boolean }): string[] {\n if (opts.fullTier && opts.syntaxOnly) throw new Error('Cannot combine --full-tier with --syntax-only.');\n const base = ['@ctxo/lang-java'];\n if (opts.syntaxOnly) return base;\n if (opts.fullTier || opts.jreAvailable) return [...base, '@ctxo/lang-java-analyzer'];\n return base;\n}\n\n/**\n * Build the deduped list of npm specifiers to install for the given languages.\n *\n * Resolves each language to its official plugin package (java expands to its tier\n * packages via {@link resolveJavaPackages}; javascript folds into @ctxo/lang-typescript),\n * pins to `version` when supplied, and removes duplicates so a project that surfaces\n * both typescript and javascript does not request @ctxo/lang-typescript twice.\n * Pure + unit-testable.\n */\nexport function buildPluginSpecifiers(\n languages: readonly KnownLanguage[],\n opts: { jreAvailable: boolean; fullTier?: boolean; syntaxOnly?: boolean; version?: string },\n): string[] {\n const out: string[] = [];\n const seen = new Set<string>();\n const add = (pkg: string): void => {\n const spec = opts.version ? `${pkg}@${opts.version}` : pkg;\n if (seen.has(spec)) return;\n seen.add(spec);\n out.push(spec);\n };\n\n for (const lang of languages) {\n if (lang === 'java') {\n for (const pkg of resolveJavaPackages(opts)) add(pkg);\n } else {\n add(officialPluginFor(lang));\n }\n }\n\n return out;\n}\n\nexport interface InstallPlan {\n readonly languages: readonly KnownLanguage[];\n readonly packages: readonly string[];\n readonly manager: PackageManager;\n readonly managerSource: Resolution['source'];\n readonly global: boolean;\n readonly command: string;\n readonly args: readonly string[];\n}\n\nexport class InstallCommand {\n constructor(private readonly projectRoot: string) {}\n\n async run(options: InstallOptions = {}): Promise<void> {\n const resolvedLangs = this.resolveLanguages(options);\n if (resolvedLangs.length === 0) {\n console.error('[ctxo] Nothing to install. Specify a language (e.g. \"ctxo install python\") or add one to your project.');\n process.exitCode = 0;\n return;\n }\n\n let resolution: Resolution;\n try {\n resolution = resolvePackageManager({\n flag: options.pm,\n projectRoot: this.projectRoot,\n });\n } catch (err) {\n console.error(`[ctxo] ${(err as Error).message}`);\n process.exitCode = 1;\n return;\n }\n\n if (!options.global && !existsSync(join(this.projectRoot, 'package.json'))) {\n console.error('[ctxo] No package.json in the current project. Re-run with --global or create a package.json first.');\n process.exitCode = 1;\n return;\n }\n\n if (!options.force && !options.global && isLockedCI(process.env)) {\n console.error('[ctxo] CI environment detected with a frozen lockfile. Refusing to mutate dependencies. Use --force or switch to --global.');\n process.exitCode = 1;\n return;\n }\n\n const jreAvailable = resolvedLangs.includes('java') ? javaRuntimeAvailable() : false;\n if (resolvedLangs.includes('java') && !jreAvailable && !options.fullTier && !options.syntaxOnly) {\n console.error('[ctxo] JRE 11+ not found; installing Java syntax tier. Install a JRE (11–16 or 17+) then run \"ctxo install java --full-tier\" for resolved call/use edges.');\n }\n\n let specifiers: string[];\n try {\n specifiers = buildPluginSpecifiers(resolvedLangs, {\n jreAvailable,\n fullTier: options.fullTier,\n syntaxOnly: options.syntaxOnly,\n version: options.version,\n });\n } catch (err) {\n console.error(`[ctxo] ${(err as Error).message}`);\n process.exitCode = 1;\n return;\n }\n\n const invocation = buildInstallCommand(resolution.manager, specifiers, {\n global: options.global,\n workspaceRoot: !options.global && isWorkspaceRoot(this.projectRoot),\n });\n\n const plan: InstallPlan = {\n languages: resolvedLangs,\n packages: specifiers,\n manager: resolution.manager,\n managerSource: resolution.source,\n global: options.global ?? false,\n command: invocation.command,\n args: [...invocation.args],\n };\n\n console.error(`[ctxo] Plan: install ${plan.packages.join(', ')}`);\n console.error(`[ctxo] Using ${plan.manager} (${plan.managerSource}${resolution.detail ? `: ${resolution.detail}` : ''})${plan.global ? ', global' : ''}`);\n console.error(`[ctxo] Command: ${plan.command} ${plan.args.join(' ')}`);\n\n if (options.dryRun) {\n console.error('[ctxo] --dry-run set; not executing.');\n return;\n }\n\n const code = await runPackageManager(plan.command, plan.args, this.projectRoot);\n if (code !== 0) {\n console.error(`[ctxo] ${plan.command} exited with code ${code}`);\n process.exitCode = code;\n return;\n }\n\n console.error(`[ctxo] Installed ${plan.packages.join(', ')}`);\n }\n\n private resolveLanguages(options: InstallOptions): KnownLanguage[] {\n const requested = options.languages ?? [];\n if (requested.length > 0) {\n const out: KnownLanguage[] = [];\n for (const raw of requested) {\n const lang = normalizeLanguage(raw);\n if (!lang) {\n console.error(\n `[ctxo] Unknown language \"${raw}\". Known: ${KNOWN_LANGUAGES.join(', ')}. Community plugins: see the ctxo-lang-template scaffolding guide.`,\n );\n process.exitCode = 1;\n return [];\n }\n if (!out.includes(lang)) out.push(lang);\n }\n return out;\n }\n\n // No explicit languages — detect missing.\n const detection = detectLanguages(this.projectRoot);\n const needed = decideNeededLanguages(detection);\n if (needed.length === 0) return [];\n const missing = needed.filter((lang) => !isPluginInstalled(lang));\n if (missing.length === 0) {\n console.error('[ctxo] All detected languages already have plugins installed.');\n return [];\n }\n console.error(`[ctxo] Detected missing plugins for: ${missing.join(', ')}`);\n return missing;\n }\n}\n\nfunction normalizeLanguage(input: string): KnownLanguage | null {\n const lowered = input.toLowerCase();\n if ((KNOWN_LANGUAGES as readonly string[]).includes(lowered)) {\n return lowered as KnownLanguage;\n }\n // Accept common aliases.\n const aliases: Record<string, KnownLanguage> = {\n ts: 'typescript',\n js: 'javascript',\n py: 'python',\n 'c#': 'csharp',\n 'cs': 'csharp',\n 'net': 'csharp',\n golang: 'go',\n kt: 'kotlin',\n rb: 'ruby',\n rs: 'rust',\n tsql: 'sql',\n };\n return aliases[lowered] ?? null;\n}\n\nconst installRequire = createRequire(import.meta.url);\n\nfunction isPluginInstalled(lang: KnownLanguage): boolean {\n try {\n installRequire.resolve(`${officialPluginFor(lang)}/package.json`);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isLockedCI(env: NodeJS.ProcessEnv): boolean {\n if (env['CI'] !== 'true' && env['CI'] !== '1') return false;\n // npm ci / pnpm --frozen-lockfile / yarn install --frozen-lockfile run in CI and must not mutate.\n return true;\n}\n\nexport { isPackageManager, PACKAGE_MANAGERS };\n","import { execFileSync } from 'node:child_process';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { extname, join } from 'node:path';\n\n/**\n * Canonical short language ids. Plugins use these same ids (e.g. `@ctxo/lang-typescript`\n * declares id: 'typescript'). Keep in sync with plugin id fields.\n */\nexport const KNOWN_LANGUAGES = [\n 'typescript',\n 'javascript',\n 'go',\n 'csharp',\n 'python',\n 'java',\n 'rust',\n 'ruby',\n 'kotlin',\n 'sql',\n] as const;\n\nexport type KnownLanguage = (typeof KNOWN_LANGUAGES)[number];\n\n/**\n * Extension → canonical language id. Multiple extensions may map to the same\n * language (e.g. .ts + .tsx → typescript).\n */\nexport const EXTENSION_LANGUAGE: Readonly<Record<string, KnownLanguage>> = {\n '.ts': 'typescript',\n '.tsx': 'typescript',\n '.js': 'javascript',\n '.jsx': 'javascript',\n '.go': 'go',\n '.cs': 'csharp',\n '.py': 'python',\n '.pyi': 'python',\n '.java': 'java',\n '.kt': 'kotlin',\n '.kts': 'kotlin',\n '.rs': 'rust',\n '.rb': 'ruby',\n '.sql': 'sql',\n};\n\nexport interface DetectionResult {\n /** Language id → manifest filename that surfaced it. */\n byManifest: Record<string, string>;\n /** Language id → source file count (from git ls-files). */\n byExtension: Record<string, number>;\n /** Total source files counted (sum of byExtension). */\n totalFiles: number;\n /** Extensions seen that don't map to a known language id. */\n unknownExtensions: Record<string, number>;\n}\n\ninterface ManifestProbe {\n readonly id: KnownLanguage;\n readonly check: (root: string) => string | null;\n}\n\nconst MANIFEST_PROBES: readonly ManifestProbe[] = [\n {\n id: 'typescript',\n check: (root) => (existsSync(join(root, 'tsconfig.json')) ? 'tsconfig.json' : null),\n },\n {\n id: 'python',\n check: (root) => {\n if (existsSync(join(root, 'pyproject.toml'))) return 'pyproject.toml';\n if (existsSync(join(root, 'setup.py'))) return 'setup.py';\n if (existsSync(join(root, 'requirements.txt'))) return 'requirements.txt';\n return null;\n },\n },\n {\n id: 'java',\n check: (root) => {\n if (existsSync(join(root, 'pom.xml'))) return 'pom.xml';\n if (existsSync(join(root, 'build.gradle'))) return 'build.gradle';\n if (existsSync(join(root, 'build.gradle.kts'))) return 'build.gradle.kts';\n return null;\n },\n },\n {\n id: 'go',\n check: (root) => (existsSync(join(root, 'go.mod')) ? 'go.mod' : null),\n },\n {\n id: 'csharp',\n check: (root) => {\n try {\n for (const entry of readdirSync(root, { withFileTypes: true })) {\n if (entry.isFile() && (entry.name.endsWith('.csproj') || entry.name.endsWith('.sln'))) {\n return entry.name;\n }\n }\n } catch {\n // ignore\n }\n return null;\n },\n },\n {\n id: 'rust',\n check: (root) => (existsSync(join(root, 'Cargo.toml')) ? 'Cargo.toml' : null),\n },\n {\n id: 'ruby',\n check: (root) => (existsSync(join(root, 'Gemfile')) ? 'Gemfile' : null),\n },\n];\n\nfunction listGitFiles(root: string): string[] {\n try {\n const out = execFileSync(\n 'git',\n // -z: NUL-separated, unquoted names (git quotes non-ASCII paths otherwise).\n ['ls-files', '-z', '--cached', '--others', '--exclude-standard'],\n { cwd: root, encoding: 'utf-8', maxBuffer: 64 * 1024 * 1024 },\n );\n return out.split('\\0').filter(Boolean);\n } catch {\n return [];\n }\n}\n\n/**\n * Detect languages present in a project root.\n *\n * - Manifest signals: presence of language-specific build files (pyproject.toml, pom.xml, go.mod, ...)\n * - Extension counts: derived from `git ls-files` (falls back to empty when not a git repo)\n *\n * Pure I/O: no network, bounded by git output. Safe to call repeatedly.\n */\nexport function detectLanguages(root: string): DetectionResult {\n const byManifest: Record<string, string> = {};\n for (const probe of MANIFEST_PROBES) {\n const manifest = probe.check(root);\n if (manifest) byManifest[probe.id] = manifest;\n }\n\n const byExtension: Record<string, number> = {};\n const unknownExtensions: Record<string, number> = {};\n let totalFiles = 0;\n\n for (const file of listGitFiles(root)) {\n const ext = extname(file).toLowerCase();\n if (!ext) continue;\n totalFiles += 1;\n const lang = EXTENSION_LANGUAGE[ext];\n if (lang) {\n byExtension[lang] = (byExtension[lang] ?? 0) + 1;\n } else {\n unknownExtensions[ext] = (unknownExtensions[ext] ?? 0) + 1;\n }\n }\n\n return { byManifest, byExtension, totalFiles, unknownExtensions };\n}\n\nexport interface LanguageNeedsOptions {\n /** Minimum source files needed to flag an extension-only language. Default 5. */\n minFiles?: number;\n /** Minimum ratio (0..1) of total files needed for extension-only detection. Default 0.02. */\n minRatio?: number;\n}\n\n/**\n * Decide which languages the project needs plugins for.\n *\n * Rules (from PRD §4.6):\n * - Manifest-backed language → always in `needed`\n * - Extension-only language → needed if count >= minFiles AND ratio >= minRatio\n */\nexport function decideNeededLanguages(\n result: DetectionResult,\n options: LanguageNeedsOptions = {},\n): KnownLanguage[] {\n const minFiles = options.minFiles ?? 5;\n const minRatio = options.minRatio ?? 0.02;\n const needed = new Set<KnownLanguage>();\n\n for (const id of Object.keys(result.byManifest)) {\n needed.add(id as KnownLanguage);\n }\n\n for (const [id, count] of Object.entries(result.byExtension)) {\n if (result.byManifest[id]) continue;\n const ratio = result.totalFiles > 0 ? count / result.totalFiles : 0;\n if (count >= minFiles && ratio >= minRatio) {\n needed.add(id as KnownLanguage);\n }\n }\n\n return [...needed];\n}\n\n/** Map a language id to its canonical official npm plugin package name. */\nexport function officialPluginFor(language: KnownLanguage): string {\n // .js/.jsx files are handled by the TypeScript plugin (ts-morph); there is no\n // standalone @ctxo/lang-javascript package, so javascript resolves to it.\n const pkgLang = language === 'javascript' ? 'typescript' : language;\n return `@ctxo/lang-${pkgLang}`;\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nexport type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';\n\nexport const PACKAGE_MANAGERS: readonly PackageManager[] = ['npm', 'pnpm', 'yarn', 'bun'];\n\nexport function isPackageManager(value: string): value is PackageManager {\n return (PACKAGE_MANAGERS as readonly string[]).includes(value);\n}\n\nexport interface ResolveOptions {\n /** CLI flag value (highest priority). */\n readonly flag?: string;\n /** process.env lookup (can inject for tests). */\n readonly env?: NodeJS.ProcessEnv;\n /** Project root where package.json, lockfiles, and .ctxo live. */\n readonly projectRoot: string;\n}\n\nexport interface Resolution {\n readonly manager: PackageManager;\n readonly source: 'flag' | 'env' | 'config' | 'lockfile' | 'default';\n readonly detail?: string;\n}\n\n/**\n * Resolve the package manager to use for install operations.\n *\n * Order (PRD §5.4 D3.6):\n * 1. `--pm` flag\n * 2. `CTXO_PM` env var\n * 3. `.ctxo/config.yaml` packageManager field\n * 4. Lockfile detection: bun.lockb > pnpm-lock.yaml > yarn.lock > package-lock.json\n * 5. Default: npm\n */\nexport function resolvePackageManager(options: ResolveOptions): Resolution {\n const env = options.env ?? process.env;\n\n if (options.flag) {\n if (!isPackageManager(options.flag)) {\n throw new Error(\n `Unknown --pm value \"${options.flag}\". Supported: ${PACKAGE_MANAGERS.join(', ')}`,\n );\n }\n return { manager: options.flag, source: 'flag' };\n }\n\n const envValue = env['CTXO_PM'];\n if (envValue) {\n if (!isPackageManager(envValue)) {\n throw new Error(\n `CTXO_PM=\"${envValue}\" is not a supported package manager. Expected one of: ${PACKAGE_MANAGERS.join(', ')}`,\n );\n }\n return { manager: envValue, source: 'env' };\n }\n\n const configured = readConfigPackageManager(options.projectRoot);\n if (configured) return { manager: configured, source: 'config' };\n\n const corepack = readPackageManagerField(options.projectRoot);\n if (corepack) return { manager: corepack.manager, source: 'config', detail: corepack.detail };\n\n const lockHit = detectFromLockfileWalkUp(options.projectRoot);\n if (lockHit) return { manager: lockHit.manager, source: 'lockfile', detail: lockHit.detail };\n\n return { manager: 'npm', source: 'default' };\n}\n\n/**\n * Honor the corepack `packageManager` field in the nearest package.json walking\n * up from projectRoot. Format: \"pnpm@10.9.0\" | \"yarn@4.0.0\" | \"npm@10.0.0\".\n */\nfunction readPackageManagerField(startDir: string): LockHit | null {\n let dir = startDir;\n for (let i = 0; i < 12; i++) {\n const pkg = join(dir, 'package.json');\n if (existsSync(pkg)) {\n try {\n const parsed = JSON.parse(readFileSync(pkg, 'utf-8')) as { packageManager?: string };\n const value = parsed.packageManager;\n if (typeof value === 'string') {\n const [nameRaw] = value.split('@');\n const name = (nameRaw ?? '').trim();\n if (isPackageManager(name)) {\n return { manager: name, detail: `packageManager: ${value}` };\n }\n }\n } catch {\n // ignore malformed manifests; try parent\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nfunction readConfigPackageManager(projectRoot: string): PackageManager | null {\n const path = join(projectRoot, '.ctxo', 'config.yaml');\n if (!existsSync(path)) return null;\n try {\n const raw = readFileSync(path, 'utf-8');\n // Minimal parse — single top-level `packageManager: <value>` line.\n const match = raw.match(/^packageManager:\\s*(\\S+)\\s*$/m);\n if (!match) return null;\n const value = match[1]!;\n return isPackageManager(value) ? value : null;\n } catch {\n return null;\n }\n}\n\ninterface LockHit {\n manager: PackageManager;\n detail: string;\n}\n\n/**\n * Look for a lockfile at `projectRoot` or any ancestor (monorepo-aware).\n * pnpm-workspace.yaml is also a strong pnpm signal even when the lockfile\n * lives only at the workspace root.\n */\nfunction detectFromLockfileWalkUp(startDir: string): LockHit | null {\n const probes: Array<{ file: string; manager: PackageManager }> = [\n { file: 'bun.lockb', manager: 'bun' },\n { file: 'pnpm-lock.yaml', manager: 'pnpm' },\n { file: 'pnpm-workspace.yaml', manager: 'pnpm' },\n { file: 'yarn.lock', manager: 'yarn' },\n { file: 'package-lock.json', manager: 'npm' },\n ];\n let dir = startDir;\n for (let i = 0; i < 12; i++) {\n for (const probe of probes) {\n const path = join(dir, probe.file);\n if (existsSync(path)) {\n return { manager: probe.manager, detail: probe.file };\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\nexport interface InstallInvocation {\n readonly command: string;\n readonly args: readonly string[];\n}\n\n/**\n * Read every dependency in `projectRoot`'s `package.json` whose version spec\n * starts with `workspace:` (pnpm / yarn workspaces convention, e.g.\n * `workspace:*`, `workspace:^`, `workspace:~`). Returns a Set of package names.\n *\n * Used by `ctxo update` to skip these packages: their source is local, so\n * \"upgrading\" them to a registry version would unlink the workspace and\n * silently downgrade you to whatever npm has published.\n */\nexport function readWorkspaceLinks(projectRoot: string): Set<string> {\n const links = new Set<string>();\n const pkgPath = join(projectRoot, 'package.json');\n if (!existsSync(pkgPath)) return links;\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n peerDependencies?: Record<string, string>;\n optionalDependencies?: Record<string, string>;\n };\n for (const group of [pkg.dependencies, pkg.devDependencies, pkg.peerDependencies, pkg.optionalDependencies]) {\n if (!group) continue;\n for (const [name, spec] of Object.entries(group)) {\n if (typeof spec === 'string' && spec.startsWith('workspace:')) {\n links.add(name);\n }\n }\n }\n return links;\n } catch {\n return links;\n }\n}\n\n/**\n * True when `projectRoot` is the root of a pnpm workspace. Detects either\n * `pnpm-workspace.yaml` (the explicit pnpm marker) or a `package.json` whose\n * `workspaces` field declares sub-packages. Required so `buildInstallCommand`\n * can append `-w` to pnpm add; pnpm 8+ refuses to install at the workspace\n * root without it (`ERR_PNPM_ADDING_TO_ROOT`).\n */\nexport function isWorkspaceRoot(projectRoot: string): boolean {\n if (existsSync(join(projectRoot, 'pnpm-workspace.yaml'))) return true;\n const pkgPath = join(projectRoot, 'package.json');\n if (!existsSync(pkgPath)) return false;\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { workspaces?: unknown };\n const ws = pkg.workspaces;\n if (Array.isArray(ws) && ws.length > 0) return true;\n if (ws && typeof ws === 'object' && Array.isArray((ws as { packages?: unknown }).packages)) return true;\n return false;\n } catch {\n return false;\n }\n}\n\nexport interface BuildInstallOptions {\n readonly global?: boolean;\n /**\n * True when the install is targeting the root of a pnpm/npm/yarn/bun\n * workspace. Adds `-w` for pnpm (required) and is a no-op for the others\n * (their CLIs do not error in the same way).\n */\n readonly workspaceRoot?: boolean;\n}\n\n/**\n * Build the install invocation for a chosen package manager. `global` produces\n * a globally-scoped install; otherwise the install targets devDependencies.\n * Pass `workspaceRoot: true` when running at the root of a pnpm workspace —\n * pnpm refuses to add to the root without `-w` (ERR_PNPM_ADDING_TO_ROOT).\n */\nexport function buildInstallCommand(\n manager: PackageManager,\n packages: readonly string[],\n options: BuildInstallOptions = {},\n): InstallInvocation {\n if (packages.length === 0) {\n throw new Error('buildInstallCommand requires at least one package');\n }\n switch (manager) {\n case 'npm':\n return {\n command: 'npm',\n args: options.global ? ['install', '-g', ...packages] : ['install', '-D', ...packages],\n };\n case 'pnpm':\n if (options.global) {\n return { command: 'pnpm', args: ['add', '-g', ...packages] };\n }\n if (options.workspaceRoot) {\n return { command: 'pnpm', args: ['add', '-D', '-w', ...packages] };\n }\n return { command: 'pnpm', args: ['add', '-D', ...packages] };\n case 'yarn':\n return {\n command: 'yarn',\n args: options.global\n ? ['global', 'add', ...packages]\n : ['add', '--dev', ...packages],\n };\n case 'bun':\n return {\n command: 'bun',\n args: options.global ? ['add', '-g', ...packages] : ['add', '-d', ...packages],\n };\n }\n}\n","import { spawn } from 'node:child_process';\n\n/**\n * Spawn a package manager (npm / pnpm / yarn / bun) with the given args.\n *\n * Windows note: npm / pnpm / yarn ship as `.cmd` shim files. Since the\n * CVE-2024-27980 fix (Node >=18.20.2 / >=20.12.2 / all 21+), Node refuses to\n * spawn a `.cmd` / `.bat` file unless `shell: true` is set, otherwise it throws\n * `EINVAL`. But passing an argv ARRAY together with `shell: true` triggers the\n * DEP0190 deprecation (Node 22) because the args are concatenated unescaped.\n *\n * To satisfy both constraints on Windows we build a single command STRING and\n * let the shell resolve the shim (cmd.exe applies PATHEXT, so plain `npm`\n * resolves to `npm.cmd` and `bun` to `bun.exe`). The pieces come from\n * `buildInstallCommand` — package-manager subcommands and version specifiers\n * validated by `isSafeVersionSpecifier`, which rejects shell metacharacters and\n * whitespace — so no interpolated user input ever reaches the shell.\n *\n * On POSIX the binary is a normal executable on PATH, so we spawn it directly\n * with an argv array and `shell: false`.\n */\nexport function runPackageManager(command: string, args: readonly string[], cwd: string): Promise<number> {\n return new Promise((resolve, reject) => {\n const child =\n process.platform === 'win32'\n ? spawn([command, ...args].join(' '), { cwd, stdio: 'inherit', shell: true })\n : spawn(command, [...args], { cwd, stdio: 'inherit', shell: false });\n child.on('exit', (code) => resolve(code ?? 0));\n child.on('error', (err) => reject(err));\n });\n}\n","import { spawnSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/** Parse `java -version` text → major (handles 1.8 legacy). Pure/uncached. */\nexport function parseJavaMajor(output: string): number | undefined {\n const m = output.match(/version \"([^\"]+)\"/);\n if (!m) return undefined;\n const parts = m[1]!.split('.');\n const major = parts[0] === '1' && parts[1] ? parseInt(parts[1]!, 10) : parseInt(parts[0]!, 10);\n return Number.isNaN(major) ? undefined : major;\n}\n\n/** Module-level memo: undefined = not yet computed; null = computed as absent */\nlet _javaMajorCache: number | null | undefined = undefined;\n\n/**\n * Spawn `java -version` once (CTXO_JAVA_HOME → JAVA_HOME → PATH), return the\n * parsed major version. Returns undefined when java is not found or the\n * version string cannot be parsed. Always respects a 10 s timeout so\n * a hanging JVM on a broken JAVA_HOME / network mount cannot stall the CLI.\n *\n * Result is memoized at module scope after the first spawn — repeated calls\n * within the same process are free.\n */\nexport function detectJavaMajor(): number | undefined {\n if (_javaMajorCache !== undefined) {\n // null sentinel means \"computed, result was undefined\"\n return _javaMajorCache === null ? undefined : _javaMajorCache;\n }\n\n const home = process.env['CTXO_JAVA_HOME'] || process.env['JAVA_HOME'];\n const bin = home\n ? join(home, 'bin', process.platform === 'win32' ? 'java.exe' : 'java')\n : 'java';\n if (home && !existsSync(bin)) {\n _javaMajorCache = null;\n return undefined;\n }\n const r = spawnSync(bin, ['-version'], {\n encoding: 'utf-8',\n timeout: 10_000,\n windowsHide: true,\n });\n if (r.error || r.status === null) {\n _javaMajorCache = null;\n return undefined;\n }\n // java writes version to stderr; stdout may also carry it in some JVMs\n const major = parseJavaMajor(`${r.stderr ?? ''}${r.stdout ?? ''}`);\n _javaMajorCache = major ?? null;\n return major;\n}\n\n/**\n * Reset the memoized java major cache. Intended for tests only — allows\n * successive test cases to exercise different java-not-found / version\n * scenarios without cross-test contamination.\n */\nexport function resetJavaRuntimeCacheForTests(): void {\n _javaMajorCache = undefined;\n}\n\n/** True if a JRE >= 11 is reachable (CTXO_JAVA_HOME -> JAVA_HOME -> PATH). */\nexport function javaRuntimeAvailable(): boolean {\n return (detectJavaMajor() ?? 0) >= 11;\n}\n","import { readFileSync } from 'node:fs';\n\n/**\n * Reads a source file the way indexing, `--check` and watch must all read it: one decoder, so the text\n * that is parsed and the text that is hashed never differ between those paths.\n *\n * A UTF-16 file with a BOM (`FF FE` little endian, `FE FF` big endian) is decoded and its BOM dropped.\n * SSMS saves SQL scripts that way, and read as UTF-8 they would be unreadable to the plugin. Every other\n * file is read exactly as `readFileSync(path, 'utf-8')` does, so a UTF-8 BOM stays in the text and the\n * content hash of a file indexed earlier does not change.\n *\n * UTF-16 without a BOM is not detected: guessing would misread UTF-8 files.\n */\nexport function readSourceText(absolutePath: string): string {\n const bytes = readFileSync(absolutePath);\n if (bytes.length >= 2) {\n const first = bytes[0];\n const second = bytes[1];\n if (first === 0xff && second === 0xfe) return decodeUtf16(bytes, false);\n if (first === 0xfe && second === 0xff) return decodeUtf16(bytes, true);\n }\n return bytes.toString('utf-8');\n}\n\nconst UTF16_BOM_LENGTH = 2;\n\n/** Decodes the code units after a 2-byte BOM. A trailing odd byte cannot form a code unit and is ignored. */\nfunction decodeUtf16(bytes: Buffer, bigEndian: boolean): string {\n const textLength = bytes.length - UTF16_BOM_LENGTH;\n const wholeUnitsLength = textLength - (textLength % 2);\n // Copy: swap16 works in place and `subarray` would reach back into `bytes`.\n const units = Buffer.from(bytes.subarray(UTF16_BOM_LENGTH, UTF16_BOM_LENGTH + wholeUnitsLength));\n return (bigEndian ? units.swap16() : units).toString('utf16le');\n}\n","import { execFileSync } from 'node:child_process';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { makeGlobMatcher, type ResolvedCoChangeConfig } from '../core/config/load-config.js';\nimport { buildCoChangeMatrix } from '../core/co-change/co-change-analyzer.js';\nimport { parseCoChangeSince, selectWindow, sinceCutoff } from '../core/co-change/co-change-window.js';\nimport type { CanonicalCommit } from '../core/history/change-log.js';\nimport type { JsonIndexWriter } from '../adapters/storage/json-index-writer.js';\n\n/**\n * How many commits to read from git. The co-change window needs `windowCommits` of them; `intent[]`\n * needs enough to find `maxHistory` commits for every file, which the old batch read approximated as\n * `maxHistory * 50`. The larger of the two serves both, and an unbounded window reads everything.\n */\nexport function changeLogSize(windowCommits: number | 'all', maxHistory: number): number | 'all' {\n return windowCommits === 'all' ? 'all' : Math.max(windowCommits, maxHistory * 50);\n}\n\nexport interface WriteCoChangeMatrixOptions {\n readonly writer: JsonIndexWriter;\n readonly projectRoot: string;\n /** The whole canonical change log, newest first. The window is cut from it here. */\n readonly commits: readonly CanonicalCommit[];\n /** Short SHA of HEAD and its committer date in unix seconds, as the change log reports them. */\n readonly head: string;\n readonly headCommittedAt: number;\n readonly coChange: ResolvedCoChangeConfig;\n /**\n * The files that take part: those indexed in this run plus every file the committed index holds that\n * the project configuration does not exclude, so the matrix does not depend on which language plugins\n * this machine has loaded. One that is gone from the working tree drops out here: the committed index\n * can still hold the entry of a file deleted since.\n */\n readonly indexedFiles: readonly string[];\n}\n\n/**\n * Phase 2b. Builds the co-change matrix from the commits of the change log and writes\n * `co-changes.json`.\n *\n * The window is cut from `commits` with the same `coChange` object that is recorded in the matrix,\n * so the stored window always equals the applied one. The cutoff for `since` is counted back from\n * HEAD's committer date, never from the clock.\n *\n * Nothing is written when the tracked files that `cochange.include` asks for cannot be listed: a\n * matrix built without them would replace a good file with a poorer one.\n */\nexport function writeCoChangeMatrix(options: WriteCoChangeMatrixOptions): void {\n const { writer, projectRoot, commits, head, headCommittedAt, coChange, indexedFiles } = options;\n\n const isIncluded = coChangeFileFilter(projectRoot, indexedFiles, coChange);\n if (isIncluded === undefined) return;\n\n const since = coChange.since !== undefined ? parseCoChangeSince(coChange.since) : undefined;\n const cutoff = since !== undefined ? sinceCutoff(headCommittedAt, since) : undefined;\n const windowed = selectWindow(commits, coChange.maxCommits, cutoff);\n\n const matrix = buildCoChangeMatrix(windowed, {\n isIncluded,\n maxCommits: coChange.maxCommits,\n since: coChange.since,\n head,\n maxFilesPerCommit: coChange.maxFilesPerCommit,\n minShared: coChange.minShared,\n timestamp: Math.floor(Date.now() / 1000),\n });\n writer.writeCoChanges(matrix);\n\n if (matrix.window) {\n console.error(\n `[ctxo] Co-change: ${matrix.entries.length} pairs from ${matrix.window.commitsUsed} commits ` +\n `(${matrix.window.massSkipped} mass commits skipped, window ${describeCoChangeWindow(coChange, matrix.window.commitsScanned)})`,\n );\n }\n}\n\n/**\n * The files that take part in the co-change matrix: the indexed files and the tracked files that\n * match `cochange.include` (files no language plugin indexes, such as SQL scripts), minus the files\n * that match `cochange.exclude`. Exclusion wins, so it can also remove a file that `include` added.\n *\n * A file takes part only while its source is still in the working tree. This is the one place that\n * rule lives, for indexed and for included files alike.\n *\n * Returns `undefined` when `cochange.include` is set but git cannot list the tracked files.\n */\nfunction coChangeFileFilter(\n projectRoot: string,\n indexedFiles: readonly string[],\n coChange: ResolvedCoChangeConfig,\n): ((path: string) => boolean) | undefined {\n const candidates = new Set<string>(indexedFiles);\n\n if (coChange.include.length > 0) {\n const tracked = listTrackedFiles(projectRoot);\n if (tracked === undefined) return undefined;\n const matchesInclude = makeGlobMatcher([...coChange.include]);\n for (const path of tracked) {\n if (matchesInclude(path)) candidates.add(path);\n }\n }\n\n const isExcluded = makeGlobMatcher([...coChange.exclude]);\n const present = new Set<string>();\n for (const path of candidates) {\n if (!isExcluded(path) && existsSync(join(projectRoot, path))) present.add(path);\n }\n return (path) => present.has(path);\n}\n\n/**\n * Every file git tracks, repo-relative with forward slashes (`-z` keeps unusual names verbatim).\n * Returns `undefined` after saying why when git fails, so the caller can skip the write.\n */\nfunction listTrackedFiles(projectRoot: string): string[] | undefined {\n try {\n const output = execFileSync('git', ['ls-files', '-z'], {\n cwd: projectRoot,\n encoding: 'utf-8',\n maxBuffer: 64 * 1024 * 1024,\n // stderr is captured: a failure reports git's message once, in the error below.\n stdio: ['ignore', 'pipe', 'pipe'],\n });\n return output.split('\\0').filter((path) => path.length > 0);\n } catch (err) {\n // A failed child process reports \"Command failed: ...\" and git's own message on separate lines.\n const reason = (err as Error).message.replace(/\\s+/g, ' ').trim();\n console.error(`[ctxo] git ls-files failed: ${reason}; co-changes.json not updated`);\n return undefined;\n }\n}\n\n/** The configured window in words, for the log line: \"last 2000 commits within 12m of HEAD, 87 scanned\". */\nfunction describeCoChangeWindow(coChange: ResolvedCoChangeConfig, commitsScanned: number): string {\n const size = coChange.maxCommits === 'all' ? 'all commits' : `last ${coChange.maxCommits} commits`;\n const age = coChange.since !== undefined ? ` within ${coChange.since} of HEAD` : '';\n return `${size}${age}, ${commitsScanned} scanned`;\n}\n","import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { ArchitectureArtifactsWriter } from '../adapters/storage/architecture-artifacts-writer.js';\nimport { CoChangeReader } from '../adapters/storage/co-change-reader.js';\nimport type { CtxoConfig } from '../core/config/config-schema.js';\nimport {\n indexIgnorePatterns,\n indexTestPatterns,\n makeGlobMatcher,\n resolveContextsViewConfig,\n} from '../core/config/load-config.js';\nimport { buildContextsView, type ContextsView } from '../core/contexts-view/contexts-view-builder.js';\nimport { createTestFileClassifier, filesWithTestAnnotations } from '../core/test-files/test-file-classifier.js';\nimport type { CommunitySnapshot, FileIndex } from '../core/types.js';\n\nexport interface ContextsViewStepOptions {\n readonly projectRoot: string;\n readonly ctxoRoot: string;\n readonly config: CtxoConfig;\n /** The merged full index. */\n readonly indices: readonly FileIndex[];\n /** This run's snapshot: god nodes and commitSha. */\n readonly snapshot: CommunitySnapshot;\n readonly symbolPageRank: ReadonlyMap<string, number>;\n /** Whether an absolute path exists in the working tree; `existsSync` unless a test counts the checks. */\n readonly exists?: (path: string) => boolean;\n}\n\n/** The file part of a symbol ID (`<file>::<name>::<kind>`). */\nfunction fileOfSymbol(symbolId: string): string {\n const cut = symbolId.indexOf('::');\n return cut === -1 ? symbolId : symbolId.slice(0, cut);\n}\n\n/**\n * Whether any `.cs` index entry carries an annotation on any symbol. That is the evidence that the v2 C#\n * plugin ran, so a `.cs` file without a test annotation really has none.\n */\nfunction hasCSharpAnnotations(indices: readonly FileIndex[]): boolean {\n return indices.some(\n (index) =>\n index.file.endsWith('.cs') && index.symbols.some((symbol) => symbol.annotations && symbol.annotations.length > 0),\n );\n}\n\n/**\n * Builds the contexts view from the merged full index and writes `contexts-view.json` (only when its content\n * changed). A node is a file that is not a test file, not matched by `index.ignore` or `contextsView.exclude`,\n * and still present in the working tree: the committed JSON of a deleted or skip-worktree file must not\n * make it a node. A file is a test file when a test glob matches or a test-framework annotation marks it; once\n * `.cs` annotations exist, the name-only globs (`*Test.cs`, `*Tests.cs`) alone no longer decide. Throws on\n * failure; the caller reports it and carries on.\n */\nexport function computeAndWriteContextsView(options: ContextsViewStepOptions): ContextsView {\n const { projectRoot, ctxoRoot, config, indices, snapshot, symbolPageRank } = options;\n const exists = options.exists ?? existsSync;\n\n const settings = resolveContextsViewConfig(config);\n const isTest = createTestFileClassifier(indexTestPatterns(config), filesWithTestAnnotations(indices), {\n annotationAware: hasCSharpAnnotations(indices),\n });\n const isIgnored = makeGlobMatcher(indexIgnorePatterns(config));\n const isExcluded = makeGlobMatcher([...settings.exclude]);\n // The file graph asks about each file once per index entry and up to four times per co-change pair, and\n // every answer costs a stat and a dozen glob matches, so each file is decided once.\n const nodeDecisions = new Map<string, boolean>();\n const isNode = (file: string): boolean => {\n let decision = nodeDecisions.get(file);\n if (decision === undefined) {\n decision = !isTest(file) && !isIgnored(file) && !isExcluded(file) && exists(join(projectRoot, file));\n nodeDecisions.set(file, decision);\n }\n return decision;\n };\n\n const godNodeFiles = new Set(snapshot.godNodes.map((god) => fileOfSymbol(god.symbolId)));\n const filePageRank = new Map<string, number>();\n for (const index of indices) {\n let sum = filePageRank.get(index.file) ?? 0;\n for (const symbol of index.symbols) sum += symbolPageRank.get(symbol.symbolId) ?? 0;\n filePageRank.set(index.file, sum);\n }\n\n const coChangeMap = new CoChangeReader(ctxoRoot).readCoChangeMap();\n const view = buildContextsView({\n indices,\n isNode,\n ...(coChangeMap ? { coChangeMap } : {}),\n godNodeFiles,\n filePageRank,\n settings,\n commitSha: snapshot.commitSha,\n });\n\n new ArchitectureArtifactsWriter(ctxoRoot, { allowProductionPath: true }).writeContextsView(view);\n\n const { coverage } = view;\n // A shared table is a resource of two or more candidates, as `ctxo contexts` counts it.\n const sharedTables = view.dataResources.filter((resource) => resource.accesses.length >= 2).length;\n console.error(\n `[ctxo] Contexts view: ${view.candidates.length} candidates cover ${coverage.covered}/${coverage.files} files ` +\n `(${Math.round(coverage.ratio * 100)}%), ${view.hubs.length} hubs, ${view.unclustered.count} unclustered` +\n (sharedTables > 0 ? `, ${sharedTables} shared tables` : ''),\n );\n return view;\n}\n","import { existsSync, mkdirSync, readFileSync } from 'node:fs';\nimport { join, resolve } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { createLogger } from '../../core/logger.js';\nimport type {\n BoundaryViolationsArtifact,\n DriftEventsArtifact,\n} from '../../core/types.js';\nimport type { ContextsView } from '../../core/contexts-view/contexts-view-builder.js';\nimport { atomicWrite } from './atomic-write.js';\n\nconst log = createLogger('ctxo:architecture-artifacts');\n\nconst DRIFT_FILE_NAME = 'drift-events.json';\nconst VIOLATIONS_FILE_NAME = 'boundary-violations.json';\nconst CONTEXTS_VIEW_FILE_NAME = 'contexts-view.json';\n\nexport interface ArchitectureArtifactsWriterOptions {\n /**\n * Acknowledge writes to a production `.ctxo/` root. Mirrors the guard in\n * CommunitySnapshotWriter so tests can't accidentally poison a real project.\n */\n readonly allowProductionPath?: boolean;\n}\n\n/**\n * Persists derived architectural-intelligence artifacts next to the\n * community snapshot. These files exist so the static HTML visualizer\n * (pages/ctxo-visualizer.html) can render the Architecture views without\n * re-running the detectors in the browser.\n *\n * Contracts:\n * - `drift-events.json` is overwritten on every index run.\n * - `boundary-violations.json` is overwritten on every index run.\n * - Both are derived — no history rotation needed (history lives in\n * communities.history/ and the detectors recompute from there).\n */\nexport class ArchitectureArtifactsWriter {\n private readonly indexDir: string;\n\n constructor(ctxoRoot: string, options: ArchitectureArtifactsWriterOptions = {}) {\n this.indexDir = join(ctxoRoot, 'index');\n assertSafeWritePath(ctxoRoot, options.allowProductionPath ?? false);\n }\n\n writeDriftEvents(artifact: DriftEventsArtifact): void {\n mkdirSync(this.indexDir, { recursive: true });\n atomicWrite(join(this.indexDir, DRIFT_FILE_NAME), JSON.stringify(artifact, null, 2));\n }\n\n writeBoundaryViolations(artifact: BoundaryViolationsArtifact): void {\n mkdirSync(this.indexDir, { recursive: true });\n atomicWrite(join(this.indexDir, VIOLATIONS_FILE_NAME), JSON.stringify(artifact, null, 2));\n }\n\n /**\n * Writes `contexts-view.json` only when its content changed, so a rerun on the same commit leaves the file\n * (and its mtime) alone. A file that differs in any way, a merge conflict included, is replaced.\n * Returns true when the file was written.\n */\n writeContextsView(view: ContextsView): boolean {\n const path = join(this.indexDir, CONTEXTS_VIEW_FILE_NAME);\n const content = JSON.stringify(view, null, 2);\n try {\n if (readFileSync(path, 'utf-8') === content) return false;\n } catch {\n /* missing or unreadable: write it */\n }\n mkdirSync(this.indexDir, { recursive: true });\n atomicWrite(path, content);\n return true;\n }\n\n readDriftEvents(): DriftEventsArtifact | undefined {\n const path = join(this.indexDir, DRIFT_FILE_NAME);\n if (!existsSync(path)) return undefined;\n try {\n return JSON.parse(readFileSync(path, 'utf-8')) as DriftEventsArtifact;\n } catch (err) {\n log.warn(`failed to parse ${DRIFT_FILE_NAME}: ${(err as Error).message}`);\n return undefined;\n }\n }\n\n readBoundaryViolations(): BoundaryViolationsArtifact | undefined {\n const path = join(this.indexDir, VIOLATIONS_FILE_NAME);\n if (!existsSync(path)) return undefined;\n try {\n return JSON.parse(readFileSync(path, 'utf-8')) as BoundaryViolationsArtifact;\n } catch (err) {\n log.warn(`failed to parse ${VIOLATIONS_FILE_NAME}: ${(err as Error).message}`);\n return undefined;\n }\n }\n}\n\nfunction assertSafeWritePath(ctxoRoot: string, allowProductionPath: boolean): void {\n const resolvedRoot = resolve(ctxoRoot);\n const resolvedTmp = resolve(tmpdir());\n if (resolvedRoot.startsWith(resolvedTmp)) return;\n if (allowProductionPath) return;\n throw new Error(\n `ArchitectureArtifactsWriter: refusing to write to non-tmp path ${resolvedRoot}. ` +\n `Pass { allowProductionPath: true } for production CLI writes, ` +\n `or target a tmpdir-based path in tests.`,\n );\n}\n","import { createHash } from 'node:crypto';\n\nimport { compareCodepoint } from '../compare-codepoint.js';\nimport type { ResolvedContextsViewConfig } from '../config/load-config.js';\nimport type { CoChangeEntry, EdgeKind, FileIndex, SymbolNode } from '../types.js';\nimport { clusterFiles, foldSmallGroups, type WeightLookup } from './candidate-groups.js';\nimport { findTermCollisions, harvestTopTerms, type ContextTerm, type TermCollision } from './context-terms.js';\nimport { computeDataCoupling, type CandidateSharedTable, type DataResourceUsage } from './data-coupling.js';\nimport {\n applyHubDamping,\n buildFileGraph,\n buildIndexGraph,\n detectHubs,\n type FilePair,\n type HubReason,\n} from './file-graph.js';\n\nexport interface CandidateCrossEdges {\n readonly candidate: number;\n readonly total: number;\n readonly byKind: Readonly<Partial<Record<EdgeKind, number>>>;\n}\n\nexport interface CandidateCoChangePair {\n readonly file: string;\n readonly otherFile: string;\n readonly otherCandidate: number;\n readonly frequency: number;\n readonly sharedCommits: number;\n}\n\nexport interface ContextCandidate {\n readonly id: number;\n readonly label: string;\n readonly fingerprint: string;\n readonly fileCount: number;\n readonly files: readonly string[];\n readonly cohesion: number;\n readonly topTerms: readonly ContextTerm[];\n readonly crossEdges: readonly CandidateCrossEdges[];\n readonly coChangePairs: readonly CandidateCoChangePair[];\n /** Tables and views that this candidate and at least one other read or write, by name. */\n readonly sharedTables: readonly CandidateSharedTable[];\n}\n\nexport interface ContextHub {\n readonly file: string;\n readonly reasons: readonly HubReason[];\n readonly dependents: number;\n readonly damping: number;\n readonly candidate?: number;\n}\n\nexport interface ContextsView {\n readonly version: 1;\n readonly commitSha: string;\n readonly settings: ResolvedContextsViewConfig;\n readonly coverage: { readonly files: number; readonly covered: number; readonly ratio: number };\n readonly candidates: readonly ContextCandidate[];\n readonly hubs: readonly ContextHub[];\n readonly unclustered: { readonly count: number; readonly files: readonly string[] };\n readonly collisions: readonly TermCollision[];\n /** Every table or view that a candidate file (members and assigned hubs) reads or writes, by name. */\n readonly dataResources: readonly DataResourceUsage[];\n}\n\nexport interface ContextsViewInput {\n readonly indices: readonly FileIndex[];\n readonly isNode: (file: string) => boolean;\n readonly coChangeMap?: ReadonlyMap<string, readonly CoChangeEntry[]>;\n readonly godNodeFiles: ReadonlySet<string>;\n readonly filePageRank: ReadonlyMap<string, number>;\n readonly settings: ResolvedContextsViewConfig;\n readonly commitSha: string;\n}\n\n/** Crossing co-change pairs kept per candidate (Designer call 7). */\nconst CO_CHANGE_PAIR_LIMIT = 10;\n\nfunction round3(value: number): number {\n return Math.round(value * 1000) / 1000;\n}\n\n/** A fresh copy with a fixed key order, so the artifact's bytes never depend on how the caller built it. */\nfunction copySettings(settings: ResolvedContextsViewConfig): ResolvedContextsViewConfig {\n return {\n weights: {\n dependency: settings.weights.dependency,\n coChange: settings.weights.coChange,\n data: settings.weights.data,\n },\n exclude: [...settings.exclude],\n hubs: {\n auto: settings.hubs.auto,\n topPercent: settings.hubs.topPercent,\n minDependents: settings.hubs.minDependents,\n paths: [...settings.hubs.paths],\n },\n resolution: settings.resolution,\n minCandidateFiles: settings.minCandidateFiles,\n technicalTerms: [...settings.technicalTerms],\n };\n}\n\n/** Each file's symbols, deduplicated and sorted by id, so term harvest never sees the input order. */\nfunction symbolsByFileOf(indices: readonly FileIndex[]): Map<string, SymbolNode[]> {\n const byFile = new Map<string, Map<string, SymbolNode>>();\n for (const index of indices) {\n const symbols = byFile.get(index.file) ?? new Map<string, SymbolNode>();\n for (const symbol of index.symbols) if (!symbols.has(symbol.symbolId)) symbols.set(symbol.symbolId, symbol);\n byFile.set(index.file, symbols);\n }\n const result = new Map<string, SymbolNode[]>();\n for (const [file, symbols] of byFile) {\n result.set(file, [...symbols.values()].sort((x, y) => compareCodepoint(x.symbolId, y.symbolId)));\n }\n return result;\n}\n\nfunction adjacencyOf(pairs: readonly FilePair[]): WeightLookup {\n const adjacency = new Map<string, Map<string, number>>();\n const link = (from: string, to: string, weight: number): void => {\n const row = adjacency.get(from);\n if (row) row.set(to, weight);\n else adjacency.set(from, new Map([[to, weight]]));\n };\n for (const pair of pairs) {\n link(pair.a, pair.b, pair.weight);\n link(pair.b, pair.a, pair.weight);\n }\n return adjacency;\n}\n\n/** Directory segments of a path, split on `/` and `\\`; a root file has none. */\nfunction directorySegments(file: string): string[] {\n const parts = file.split(/[\\\\/]/);\n parts.pop();\n return parts;\n}\n\n/** The longest common directory segments of the given files; empty when they share none. */\nfunction commonDirectory(files: readonly string[]): string[] {\n if (files.length === 0) return [];\n let common = directorySegments(files[0]!);\n for (const file of files.slice(1)) {\n const segments = directorySegments(file);\n let length = 0;\n while (length < common.length && length < segments.length && common[length] === segments[length]) length++;\n common = common.slice(0, length);\n }\n return common;\n}\n\n/** Directory segments joined with `/`, the repo root as `.`. The segments keep their spelling (spaces, non-ASCII, case). */\nfunction directoryLabel(segments: readonly string[]): string {\n return segments.length === 0 ? '.' : segments.join('/');\n}\n\n/** The directory of the member with the highest file-level PageRank (ties: first member). */\nfunction topMemberDirectory(files: readonly string[], pageRank: ReadonlyMap<string, number>): string {\n let top = files[0]!;\n for (const file of files) {\n if ((pageRank.get(file) ?? 0) > (pageRank.get(top) ?? 0)) top = file;\n }\n return directoryLabel(directorySegments(top));\n}\n\n/**\n * The labels of the groups (K34): the longest common directory of the members or, when that is the repo\n * root, the directory of the top-PageRank member. Then every label that two or more groups share is\n * replaced, for each of them, by the directory of its own top-PageRank member. One pass: labels may still\n * repeat. Independent of the group order.\n */\nfunction labelsOf(groups: readonly (readonly string[])[], pageRank: ReadonlyMap<string, number>): string[] {\n const base = groups.map((files) => {\n const common = commonDirectory(files);\n return common.length > 0 ? directoryLabel(common) : topMemberDirectory(files, pageRank);\n });\n const uses = new Map<string, number>();\n for (const label of base) uses.set(label, (uses.get(label) ?? 0) + 1);\n return base.map((label, index) =>\n (uses.get(label) ?? 0) > 1 ? topMemberDirectory(groups[index]!, pageRank) : label,\n );\n}\n\nfunction fingerprintOf(files: readonly string[]): string {\n return createHash('sha256').update(files.join('\\n')).digest('hex').slice(0, 16);\n}\n\n/** One entry per unordered pair of distinct files, the highest frequency (then shared commits) winning. */\nfunction distinctCoChanges(coChangeMap: ReadonlyMap<string, readonly CoChangeEntry[]> | undefined): CoChangeEntry[] {\n const byPair = new Map<string, CoChangeEntry>();\n for (const entries of coChangeMap?.values() ?? []) {\n for (const entry of entries) {\n if (entry.file1 === entry.file2) continue;\n const [file1, file2] =\n compareCodepoint(entry.file1, entry.file2) < 0 ? [entry.file1, entry.file2] : [entry.file2, entry.file1];\n const key = `${file1}\\n${file2}`;\n const known = byPair.get(key);\n if (\n !known ||\n entry.frequency > known.frequency ||\n (entry.frequency === known.frequency && entry.sharedCommits > known.sharedCommits)\n ) {\n byPair.set(key, { file1, file2, sharedCommits: entry.sharedCommits, frequency: entry.frequency });\n }\n }\n }\n return [...byPair.values()];\n}\n\n/**\n * Builds the contexts view (spec 7.2 and 7.3): file graph, hubs, damping, Louvain groups, folding, hub\n * assignment, IDs and labels, per-candidate fields, collisions and coverage. Pure and deterministic: the\n * same input in any order gives a byte-identical `JSON.stringify`.\n *\n * `cohesion` and the folding use the final weights without hub endpoints: hubs belong to no candidate,\n * and their edges, damped on purpose, do not count against a candidate's cohesion. `crossEdges` and\n * `coChangePairs` likewise only connect candidate members. Data coupling (`sharedTables`, `dataResources`)\n * counts members and assigned hubs for their candidate; unclustered files are left out.\n */\nexport function buildContextsView(input: ContextsViewInput): ContextsView {\n const settings = copySettings(input.settings);\n\n const indexGraph = buildIndexGraph(input.indices);\n const graph = buildFileGraph({\n indices: input.indices,\n isNode: input.isNode,\n ...(input.coChangeMap ? { coChangeMap: input.coChangeMap } : {}),\n weights: settings.weights,\n graph: indexGraph,\n });\n const hubDecisions = detectHubs(graph, { hubs: settings.hubs, godNodeFiles: input.godNodeFiles });\n const pairs = applyHubDamping(graph.pairs, hubDecisions);\n const hubFiles = new Set(hubDecisions.map((hub) => hub.file));\n\n const clusters = clusterFiles(graph.files, pairs, hubFiles, settings.resolution);\n const memberPairs = pairs.filter((pair) => !hubFiles.has(pair.a) && !hubFiles.has(pair.b));\n const folded = foldSmallGroups(clusters, adjacencyOf(memberPairs), settings.minCandidateFiles);\n\n // Hub assignment: the strongest neighbour that sits in a group (ties: neighbour path).\n const groupIndex = new Map<string, number>();\n folded.groups.forEach((files, index) => {\n for (const file of files) groupIndex.set(file, index);\n });\n const hubNeighbour = new Map<string, { file: string; weight: number }>();\n for (const pair of pairs) {\n for (const [hub, other] of [\n [pair.a, pair.b],\n [pair.b, pair.a],\n ] as const) {\n if (!hubFiles.has(hub) || !groupIndex.has(other)) continue;\n const best = hubNeighbour.get(hub);\n if (!best || pair.weight > best.weight || (pair.weight === best.weight && compareCodepoint(other, best.file) < 0)) {\n hubNeighbour.set(hub, { file: other, weight: pair.weight });\n }\n }\n }\n\n // Labels first, then IDs: size desc, then final label, then first member; IDs start at 1.\n const labels = labelsOf(folded.groups, input.filePageRank);\n const ordered = folded.groups\n .map((files, index) => ({ files, label: labels[index]! }))\n .sort(\n (x, y) =>\n y.files.length - x.files.length || compareCodepoint(x.label, y.label) || compareCodepoint(x.files[0]!, y.files[0]!),\n );\n const candidateOf = new Map<string, number>();\n ordered.forEach(({ files }, index) => {\n for (const file of files) candidateOf.set(file, index + 1);\n });\n\n const hubs: ContextHub[] = hubDecisions.map((hub) => {\n const neighbour = hubNeighbour.get(hub.file);\n const candidate = neighbour ? candidateOf.get(neighbour.file) : undefined;\n return {\n file: hub.file,\n reasons: [...hub.reasons],\n dependents: hub.dependents,\n damping: hub.damping,\n ...(candidate !== undefined ? { candidate } : {}),\n };\n });\n\n // Data coupling: members and assigned hubs count for their candidate.\n const fileCandidate = new Map(candidateOf);\n for (const hub of hubs) if (hub.candidate !== undefined) fileCandidate.set(hub.file, hub.candidate);\n const dataCoupling = computeDataCoupling({ graph: indexGraph, fileCandidate });\n\n // Cohesion: internal weight over internal plus boundary weight, hub endpoints left out.\n const internal = new Map<number, number>();\n const boundary = new Map<number, number>();\n for (const pair of memberPairs) {\n const ca = candidateOf.get(pair.a);\n const cb = candidateOf.get(pair.b);\n if (ca !== undefined && ca === cb) {\n internal.set(ca, (internal.get(ca) ?? 0) + pair.weight);\n continue;\n }\n if (ca !== undefined) boundary.set(ca, (boundary.get(ca) ?? 0) + pair.weight);\n if (cb !== undefined) boundary.set(cb, (boundary.get(cb) ?? 0) + pair.weight);\n }\n\n // Cross edges: outgoing distinct symbol edges into another candidate, by kind.\n const crossCounts = new Map<number, Map<number, Map<EdgeKind, number>>>();\n for (const edge of graph.edgeCounts) {\n const from = candidateOf.get(edge.from);\n const to = candidateOf.get(edge.to);\n if (from === undefined || to === undefined || from === to) continue;\n const byTarget = crossCounts.get(from) ?? new Map<number, Map<EdgeKind, number>>();\n const byKind = byTarget.get(to) ?? new Map<EdgeKind, number>();\n byKind.set(edge.kind, (byKind.get(edge.kind) ?? 0) + edge.count);\n byTarget.set(to, byKind);\n crossCounts.set(from, byTarget);\n }\n\n // Co-change pairs crossing candidates, listed from both sides.\n const coPairs = new Map<number, CandidateCoChangePair[]>();\n const addCoPair = (candidate: number, pair: CandidateCoChangePair): void => {\n const list = coPairs.get(candidate);\n if (list) list.push(pair);\n else coPairs.set(candidate, [pair]);\n };\n for (const entry of distinctCoChanges(input.coChangeMap)) {\n const c1 = candidateOf.get(entry.file1);\n const c2 = candidateOf.get(entry.file2);\n if (c1 === undefined || c2 === undefined || c1 === c2) continue;\n const { frequency, sharedCommits } = entry;\n addCoPair(c1, { file: entry.file1, otherFile: entry.file2, otherCandidate: c2, frequency, sharedCommits });\n addCoPair(c2, { file: entry.file2, otherFile: entry.file1, otherCandidate: c1, frequency, sharedCommits });\n }\n\n const symbolsByFile = symbolsByFileOf(input.indices);\n const candidates: ContextCandidate[] = ordered.map(({ files, label }, index) => {\n const id = index + 1;\n const inside = internal.get(id) ?? 0;\n const total = inside + (boundary.get(id) ?? 0);\n const crossEdges = [...(crossCounts.get(id) ?? new Map<number, Map<EdgeKind, number>>()).entries()]\n .sort(([x], [y]) => x - y)\n .map(([candidate, kinds]): CandidateCrossEdges => {\n const sortedKinds = [...kinds.entries()].sort(([x], [y]) => compareCodepoint(x, y));\n return {\n candidate,\n total: sortedKinds.reduce((sum, [, count]) => sum + count, 0),\n byKind: Object.fromEntries(sortedKinds) as Partial<Record<EdgeKind, number>>,\n };\n });\n const coChangePairs = (coPairs.get(id) ?? [])\n .sort(\n (x, y) =>\n y.frequency - x.frequency ||\n y.sharedCommits - x.sharedCommits ||\n compareCodepoint(x.file, y.file) ||\n compareCodepoint(x.otherFile, y.otherFile),\n )\n .slice(0, CO_CHANGE_PAIR_LIMIT);\n return {\n id,\n label,\n fingerprint: fingerprintOf(files),\n fileCount: files.length,\n files,\n cohesion: total > 0 ? round3(inside / total) : 0,\n topTerms: harvestTopTerms(files, symbolsByFile, settings.technicalTerms),\n crossEdges,\n coChangePairs,\n sharedTables: dataCoupling.sharedTables.get(id) ?? [],\n };\n });\n\n const collisions = findTermCollisions(\n candidates.map((candidate) => ({ id: candidate.id, files: candidate.files })),\n symbolsByFile,\n );\n\n const covered =\n candidates.reduce((sum, candidate) => sum + candidate.fileCount, 0) +\n hubs.filter((hub) => hub.candidate !== undefined).length;\n const fileCount = graph.files.length;\n\n return {\n version: 1,\n commitSha: input.commitSha,\n settings,\n coverage: { files: fileCount, covered, ratio: fileCount > 0 ? round3(covered / fileCount) : 0 },\n candidates,\n hubs,\n unclustered: { count: folded.unclustered.length, files: folded.unclustered },\n collisions,\n dataResources: dataCoupling.resources,\n };\n}\n","import { UndirectedGraph } from 'graphology';\n\nimport { compareCodepoint } from '../compare-codepoint.js';\nimport { runLouvain, splitDisconnectedCommunities } from '../overlay/louvain.js';\nimport type { FilePair } from './file-graph.js';\n\n/** Symmetric adjacency of final pair weights: `adjacency.get(x).get(y) === adjacency.get(y).get(x)`. */\nexport type WeightLookup = ReadonlyMap<string, ReadonlyMap<string, number>>;\n\nfunction round6(value: number): number {\n return Math.round(value * 1e6) / 1e6;\n}\n\n/** Sorts each group's members, then the groups by their first member. Empty groups are dropped. */\nfunction sortGroups(groups: readonly (readonly string[])[]): string[][] {\n return groups\n .filter((group) => group.length > 0)\n .map((group) => [...group].sort(compareCodepoint))\n .sort((x, y) => compareCodepoint(x[0]!, y[0]!));\n}\n\n/**\n * Clusters files with Louvain (no random walk, sorted node and pair insertion). Hubs take part in Louvain,\n * so their damped edges count, then leave their group before each group is split into its connected\n * parts. Returns the groups sorted (members by code point, groups by first member). Without any edge,\n * every non-hub file is its own group and Louvain does not run.\n */\nexport function clusterFiles(\n files: readonly string[],\n pairs: readonly FilePair[],\n hubFiles: ReadonlySet<string>,\n resolution: number,\n): string[][] {\n const nodes = [...new Set(files)].sort(compareCodepoint);\n const graph = new UndirectedGraph();\n for (const file of nodes) graph.addNode(file);\n\n const sortedPairs = [...pairs].sort((x, y) => compareCodepoint(x.a, y.a) || compareCodepoint(x.b, y.b));\n for (const pair of sortedPairs) {\n if (pair.a === pair.b || !(pair.weight > 0)) continue;\n if (!graph.hasNode(pair.a) || !graph.hasNode(pair.b) || graph.hasEdge(pair.a, pair.b)) continue;\n graph.addEdge(pair.a, pair.b, { weight: pair.weight });\n }\n\n const kept = nodes.filter((file) => !hubFiles.has(file));\n if (graph.size === 0) return kept.map((file) => [file]);\n\n const { communities } = runLouvain(graph, resolution);\n // A null prototype keeps a file literally named `__proto__` an ordinary key.\n const assignments = Object.create(null) as Record<string, number>;\n for (const file of kept) assignments[file] = communities[file]!;\n const split = splitDisconnectedCommunities(graph, assignments);\n\n const byId = new Map<number, string[]>();\n for (const file of kept) {\n const id = split.get(file)!;\n const group = byId.get(id);\n if (group) group.push(file);\n else byId.set(id, [file]);\n }\n return sortGroups([...byId.values()]);\n}\n\n/**\n * Folds groups smaller than `minFiles` into a neighbouring group (Designer call 4): the smallest small\n * group first (ties: first member) joins the group it has the largest total weight to (totals compared at\n * 6 decimals; ties: the larger group, then the first member). Repeats until no small group has a\n * neighbour; the small groups left over go to `unclustered`. Files absent from every group (hubs) are\n * not neighbours.\n */\nexport function foldSmallGroups(\n groups: readonly (readonly string[])[],\n adjacency: WeightLookup,\n minFiles: number,\n): { readonly groups: string[][]; readonly unclustered: string[] } {\n const live = new Map<number, string[]>();\n const groupOf = new Map<string, number>();\n sortGroups(groups).forEach((members, id) => {\n live.set(id, members);\n for (const file of members) groupOf.set(file, id);\n });\n\n const isBetter = (candidate: number, best: number): boolean => {\n const x = live.get(candidate)!;\n const y = live.get(best)!;\n return x.length !== y.length ? x.length > y.length : compareCodepoint(x[0]!, y[0]!) < 0;\n };\n\n const strongestNeighbour = (id: number, members: readonly string[]): number | undefined => {\n const totals = new Map<number, number>();\n for (const file of members) {\n for (const [other, weight] of adjacency.get(file) ?? []) {\n const neighbour = groupOf.get(other);\n if (neighbour === undefined || neighbour === id || !(weight > 0)) continue;\n totals.set(neighbour, (totals.get(neighbour) ?? 0) + weight);\n }\n }\n let best: number | undefined;\n let bestTotal = 0;\n for (const [neighbour, raw] of totals) {\n const total = round6(raw);\n if (!(total > 0)) continue;\n if (best === undefined || total > bestTotal || (total === bestTotal && isBetter(neighbour, best))) {\n best = neighbour;\n bestTotal = total;\n }\n }\n return best;\n };\n\n // With a symmetric adjacency a group without a neighbour never gains one, so it is not rescanned.\n const stranded = new Set<number>();\n for (;;) {\n const small = [...live.entries()]\n .filter(([id, members]) => members.length < minFiles && !stranded.has(id))\n .sort(([, x], [, y]) => x.length - y.length || compareCodepoint(x[0]!, y[0]!));\n let merged = false;\n for (const [id, members] of small) {\n const target = strongestNeighbour(id, members);\n if (target === undefined) {\n stranded.add(id);\n continue;\n }\n const combined = [...live.get(target)!, ...members].sort(compareCodepoint);\n live.set(target, combined);\n live.delete(id);\n stranded.delete(target);\n for (const file of members) groupOf.set(file, target);\n merged = true;\n break;\n }\n if (!merged) break;\n }\n\n const kept: string[][] = [];\n const unclustered: string[] = [];\n for (const members of live.values()) {\n if (members.length < minFiles) unclustered.push(...members);\n else kept.push(members);\n }\n return { groups: sortGroups(kept), unclustered: unclustered.sort(compareCodepoint) };\n}\n","import type { UndirectedGraph } from 'graphology';\nimport type { DetailedLouvainOutput, LouvainOptions } from 'graphology-communities-louvain';\nimport louvainModule from 'graphology-communities-louvain';\n\ninterface LouvainRunner {\n detailed(graph: UndirectedGraph, options?: LouvainOptions): DetailedLouvainOutput;\n}\n\n// graphology-communities-louvain is a CJS module exposed via default export; under\n// Node16 module resolution the TS type is the module namespace, so we normalize here.\nconst louvain: LouvainRunner =\n ((louvainModule as unknown) as { default?: LouvainRunner }).default ??\n (louvainModule as unknown as LouvainRunner);\n\n/**\n * Deterministic Louvain over an undirected graph whose edges carry a `weight` attribute: no random walk,\n * so the same graph built in the same node and edge order always gives the same assignment. Callers add\n * nodes and edges in sorted order.\n */\nexport function runLouvain(\n graph: UndirectedGraph,\n resolution: number,\n): { readonly communities: Record<string, number>; readonly modularity: number } {\n const result = louvain.detailed(graph, {\n resolution,\n randomWalk: false,\n fastLocalMoves: true,\n getEdgeWeight: 'weight',\n });\n return { communities: result.communities as Record<string, number>, modularity: result.modularity };\n}\n\n/**\n * Splits every community into its connected parts (Louvain can return a community whose members only\n * connect through other communities). New ids are given in ascending order of the original id, then of\n * each part's smallest member.\n */\nexport function splitDisconnectedCommunities(\n gph: UndirectedGraph,\n assignments: Readonly<Record<string, number>>,\n): Map<string, number> {\n const result = new Map<string, number>();\n const membersByCommunity = new Map<number, string[]>();\n for (const [node, communityId] of Object.entries(assignments)) {\n const list = membersByCommunity.get(communityId) ?? [];\n list.push(node);\n membersByCommunity.set(communityId, list);\n }\n\n let nextCommunityId = 0;\n const sortedCommunities = [...membersByCommunity.entries()].sort(([a], [b]) => a - b);\n\n for (const [, members] of sortedCommunities) {\n const visited = new Set<string>();\n for (const start of [...members].sort()) {\n if (visited.has(start)) continue;\n const componentId = nextCommunityId++;\n const queue = [start];\n visited.add(start);\n while (queue.length > 0) {\n const node = queue.shift()!;\n result.set(node, componentId);\n for (const neighbor of gph.neighbors(node)) {\n if (visited.has(neighbor)) continue;\n if (!members.includes(neighbor)) continue;\n visited.add(neighbor);\n queue.push(neighbor);\n }\n }\n }\n }\n\n return result;\n}\n","import { compareCodepoint } from '../compare-codepoint.js';\nimport { isDataResourceKind } from '../data-coupling/data-kinds.js';\nimport { SymbolTokenizer } from '../search/symbol-tokenizer.js';\nimport type { SymbolNode } from '../types.js';\n\nexport interface ContextTerm {\n readonly term: string;\n readonly files: number;\n}\n\nexport interface TermOccurrence {\n readonly candidate: number;\n readonly file: string;\n readonly symbolId: string;\n readonly members: readonly string[];\n}\n\nexport interface TermCollision {\n readonly name: string;\n readonly minJaccard: number;\n readonly occurrences: readonly TermOccurrence[];\n}\n\nexport interface TermSource {\n readonly id: number;\n readonly files: readonly string[];\n}\n\nconst DEFAULT_TERM_LIMIT = 10;\nconst COLLISION_JACCARD_THRESHOLD = 0.5;\n\nfunction isTypeSymbol(symbol: SymbolNode): boolean {\n return symbol.kind === 'class' || symbol.kind === 'interface' || symbol.kind === 'type';\n}\n\n/** C# names are namespace-qualified and SQL names schema-qualified, so the short name is the last `.` segment. */\nfunction shortName(name: string): string {\n const dot = name.lastIndexOf('.');\n return dot === -1 ? name : name.slice(dot + 1);\n}\n\n/**\n * The comparison form of a type, table or member name in collisions: ASCII A-Z lowercased (no locale or\n * Unicode folding, as lang-sql folds column names) and `_` removed, so `LoanItems` meets `loan_items`.\n */\nexport function normalizeTermName(name: string): string {\n return name.replace(/[A-Z]/g, (c) => String.fromCharCode(c.charCodeAt(0) + 32)).replace(/_/g, '');\n}\n\n/** The `columns` annotation of a table symbol (lang-sql), sorted and unique; [] without one. */\nfunction columnNames(symbol: SymbolNode): string[] {\n const columns = new Set<string>();\n for (const annotation of symbol.annotations ?? []) {\n if (annotation.name !== 'columns') continue;\n for (const column of annotation.args ?? []) if (column.length > 0) columns.add(column);\n }\n return [...columns].sort(compareCodepoint);\n}\n\n/** Names of the symbols one level below `typeName` in the same file (`<typeName>.<member>`). */\nfunction memberNames(typeName: string, symbols: readonly SymbolNode[]): string[] {\n const prefix = `${typeName}.`;\n const members = new Set<string>();\n for (const symbol of symbols) {\n if (!symbol.name.startsWith(prefix)) continue;\n const rest = symbol.name.slice(prefix.length);\n if (rest.includes('.')) continue;\n // The C# tree-sitter fallback suffixes methods with their arity, `Borrow(2)`; overloads collapse.\n const member = rest.replace(/\\(\\d+\\)$/, '');\n if (member.length > 0) members.add(member);\n }\n return [...members].sort(compareCodepoint);\n}\n\n/** Enum members: `variable` symbols named `<type>.<member>` directly under a `type` symbol. */\nfunction enumMemberNames(typeName: string, symbols: readonly SymbolNode[]): string[] {\n const prefix = `${typeName}.`;\n const members: string[] = [];\n for (const symbol of symbols) {\n if (symbol.kind !== 'variable' || !symbol.name.startsWith(prefix)) continue;\n const rest = symbol.name.slice(prefix.length);\n if (rest.length > 0 && !rest.includes('.')) members.push(rest);\n }\n return members;\n}\n\n/**\n * Top type-name terms of a candidate (spec 7.3, Designer call 8): type names, enum members, and the short\n * names and columns of tables and views, tokenized with SymbolTokenizer, minus stop words, technical words\n * and tokens shorter than 2 characters or all digits, ranked by number of files, ties by code point order.\n */\nexport function harvestTopTerms(\n files: readonly string[],\n symbolsByFile: ReadonlyMap<string, readonly SymbolNode[]>,\n technicalTerms: readonly string[],\n limit: number = DEFAULT_TERM_LIMIT,\n): ContextTerm[] {\n const technical = new Set(technicalTerms.map((term) => term.toLowerCase()));\n const fileCounts = new Map<string, number>();\n\n for (const file of new Set(files)) {\n const symbols = symbolsByFile.get(file) ?? [];\n const names: string[] = [];\n for (const symbol of symbols) {\n if (isDataResourceKind(symbol.kind)) {\n names.push(shortName(symbol.name), ...columnNames(symbol));\n continue;\n }\n if (!isTypeSymbol(symbol)) continue;\n names.push(shortName(symbol.name));\n if (symbol.kind === 'type') names.push(...enumMemberNames(symbol.name, symbols));\n }\n\n const terms = new Set<string>();\n for (const name of names) {\n for (const raw of SymbolTokenizer.splitName(name)) {\n const token = raw.toLowerCase();\n if (token.length < 2 || /^\\d+$/.test(token)) continue;\n if (SymbolTokenizer.isStopWord(token) || technical.has(token)) continue;\n terms.add(token);\n }\n }\n for (const term of terms) fileCounts.set(term, (fileCounts.get(term) ?? 0) + 1);\n }\n\n return [...fileCounts.entries()]\n .map(([term, count]) => ({ term, files: count }))\n .sort((a, b) => b.files - a.files || compareCodepoint(a.term, b.term))\n .slice(0, limit);\n}\n\nfunction jaccard(a: readonly string[], b: readonly string[]): number {\n if (a.length === 0 && b.length === 0) return 1;\n const left = new Set(a);\n let intersection = 0;\n for (const item of new Set(b)) if (left.has(item)) intersection++;\n const union = new Set([...a, ...b]).size;\n return intersection / union;\n}\n\n/**\n * Type and table names that appear in two or more candidates with member sets whose Jaccard similarity is\n * below 0.5 for at least one pair of occurrences in different candidates. A table's members are its\n * columns; views take no part. Names and members compare in `normalizeTermName` form (ASCII case and `_`\n * ignored): the collision is named by that form, and the occurrences keep the original member spellings.\n * `similarity` is Jaccard over the normalized members; a test can pass its own to count the comparisons.\n */\nexport function findTermCollisions(\n candidates: readonly TermSource[],\n symbolsByFile: ReadonlyMap<string, readonly SymbolNode[]>,\n similarity: (a: readonly string[], b: readonly string[]) => number = jaccard,\n): TermCollision[] {\n const byName = new Map<string, Array<{ readonly occurrence: TermOccurrence; readonly normalized: string[] }>>();\n\n for (const candidate of candidates) {\n for (const file of new Set(candidate.files)) {\n const symbols = symbolsByFile.get(file) ?? [];\n for (const symbol of symbols) {\n const isTable = symbol.kind === 'table';\n if (!isTable && !isTypeSymbol(symbol)) continue;\n const key = normalizeTermName(shortName(symbol.name));\n // Arity stripping (in memberNames) applies to class members only; columns are taken as they are.\n const members = isTable ? columnNames(symbol) : memberNames(symbol.name, symbols);\n const entry = {\n occurrence: { candidate: candidate.id, file, symbolId: symbol.symbolId, members },\n normalized: members.map(normalizeTermName),\n };\n const list = byName.get(key);\n if (list) list.push(entry);\n else byName.set(key, [entry]);\n }\n }\n }\n\n const collisions: TermCollision[] = [];\n for (const [name, entries] of byName) {\n let min = Infinity;\n // Jaccard is never below 0, so once a pair reaches it no later pair can lower the minimum.\n for (let i = 0; i < entries.length && min > 0; i++) {\n for (let j = i + 1; j < entries.length && min > 0; j++) {\n const a = entries[i]!;\n const b = entries[j]!;\n if (a.occurrence.candidate === b.occurrence.candidate) continue;\n min = Math.min(min, similarity(a.normalized, b.normalized));\n }\n }\n if (min === Infinity || min >= COLLISION_JACCARD_THRESHOLD) continue;\n collisions.push({\n name,\n minJaccard: Math.round(min * 1000) / 1000,\n occurrences: entries\n .map((entry) => entry.occurrence)\n .sort((a, b) => a.candidate - b.candidate || compareCodepoint(a.symbolId, b.symbolId)),\n });\n }\n\n return collisions.sort((a, b) => compareCodepoint(a.name, b.name));\n}\n","import type { DataResourceKind } from '@ctxo/plugin-api';\n\nimport { compareCodepoint } from '../compare-codepoint.js';\nimport { DATA_EDGE_KINDS, isDataResourceKind } from '../data-coupling/data-kinds.js';\nimport type { SymbolGraph } from '../graph/symbol-graph.js';\nimport type { SymbolNode } from '../types.js';\n\nexport type DataAccessMode = 'reads' | 'writes';\n\n/** How one candidate accesses a resource; `modes` lists `reads` before `writes`. */\nexport interface CandidateDataAccess {\n readonly candidate: number;\n readonly modes: readonly DataAccessMode[];\n}\n\n/** A table or view that at least one candidate reads or writes. */\nexport interface DataResourceUsage {\n /** Canonical `schema.name`. */\n readonly name: string;\n /** Absent when external. */\n readonly kind?: DataResourceKind;\n /** No indexed table or view defines it. */\n readonly external: boolean;\n /** By candidate id. */\n readonly accesses: readonly CandidateDataAccess[];\n /** Candidates that write it, by id; more than one means several writers. */\n readonly writers: readonly number[];\n /** The only writer. */\n readonly owner?: number;\n}\n\n/** A resource this candidate and at least one other candidate access. */\nexport interface CandidateSharedTable {\n readonly name: string;\n /** Absent when external. */\n readonly kind?: DataResourceKind;\n readonly external: boolean;\n readonly accesses: readonly CandidateDataAccess[];\n readonly owner?: number;\n}\n\nexport interface DataCouplingInput {\n /** The symbol graph of the index, from `buildIndexGraph`. */\n readonly graph: SymbolGraph;\n /** The candidate of each member file and of each assigned hub; other files are left out. */\n readonly fileCandidate: ReadonlyMap<string, number>;\n}\n\nexport interface DataCoupling {\n /** Every resource with at least one access, by name. */\n readonly resources: readonly DataResourceUsage[];\n /** Per candidate id (ascending), the resources of two or more candidates, by name; candidates without any are absent. */\n readonly sharedTables: ReadonlyMap<number, readonly CandidateSharedTable[]>;\n}\n\nconst MODES: readonly DataAccessMode[] = ['reads', 'writes'];\n\nfunction fileOf(symbolId: string): string {\n const at = symbolId.indexOf('::');\n return at < 0 ? symbolId : symbolId.slice(0, at);\n}\n\n/** The name part of `<file>::<name>::<kind>` or of a 2-part reference `<name>::<kind>`. */\nfunction nameOf(id: string): string | undefined {\n const parts = id.split('::');\n if (parts.length === 3) return parts[1];\n if (parts.length === 2) return parts[0];\n return undefined;\n}\n\nfunction kindOf(id: string): string {\n return id.slice(id.lastIndexOf('::') + 2);\n}\n\n/**\n * The seeds (vertices for which `isSeed` holds) that no seed outside their own strongly connected component\n * reaches, in the graph `successors` spans over `vertices`. Paths may run through vertices that are not\n * seeds. `successors` must only name vertices of `vertices`.\n *\n * One iterative Tarjan pass, which numbers the components in reverse topological order, then one pass over\n * the components in topological order that marks every component a seed reaches from another component.\n * Linear in vertices plus edges; the result does not depend on the order of `vertices`.\n */\nfunction unenteredSeeds(\n vertices: readonly string[],\n successors: (vertex: string) => readonly string[],\n isSeed: (vertex: string) => boolean,\n): Set<string> {\n const index = new Map<string, number>();\n const low = new Map<string, number>();\n const component = new Map<string, number>();\n const members: string[][] = [];\n const stack: string[] = [];\n const onStack = new Set<string>();\n let nextIndex = 0;\n\n for (const start of vertices) {\n if (index.has(start)) continue;\n const frames: Array<{ vertex: string; next: readonly string[]; at: number }> = [];\n const open = (vertex: string): void => {\n index.set(vertex, nextIndex);\n low.set(vertex, nextIndex);\n nextIndex++;\n stack.push(vertex);\n onStack.add(vertex);\n frames.push({ vertex, next: successors(vertex), at: 0 });\n };\n open(start);\n while (frames.length > 0) {\n const frame = frames[frames.length - 1]!;\n if (frame.at < frame.next.length) {\n const successor = frame.next[frame.at++]!;\n if (!index.has(successor)) open(successor);\n else if (onStack.has(successor)) low.set(frame.vertex, Math.min(low.get(frame.vertex)!, index.get(successor)!));\n continue;\n }\n frames.pop();\n if (low.get(frame.vertex) === index.get(frame.vertex)) {\n const id = members.length;\n const list: string[] = [];\n let member: string;\n do {\n member = stack.pop()!;\n onStack.delete(member);\n component.set(member, id);\n list.push(member);\n } while (member !== frame.vertex);\n members.push(list);\n }\n const parent = frames[frames.length - 1];\n if (parent) low.set(parent.vertex, Math.min(low.get(parent.vertex)!, low.get(frame.vertex)!));\n }\n }\n\n // An edge between two components always goes to a lower id, so the highest id comes first in\n // topological order, and a component is final once every higher id is done.\n const entered = members.map(() => false);\n for (let id = members.length - 1; id >= 0; id--) {\n if (!entered[id] && !members[id]!.some(isSeed)) continue;\n for (const vertex of members[id]!) {\n for (const successor of successors(vertex)) {\n const target = component.get(successor)!;\n if (target !== id) entered[target] = true;\n }\n }\n }\n return new Set(vertices.filter((vertex) => isSeed(vertex) && !entered[component.get(vertex)!]));\n}\n\n/**\n * Data coupling between candidates (spec 8.6): which candidate reads or writes which table or view.\n *\n * - A `reads` or `writes` edge from a symbol in a candidate file records that candidate and mode for its\n * target, unless the symbol is a procedure: procedure bodies count through `executes` instead, so the\n * candidate that holds a procedure script does not read and write every table its procedures touch.\n * - Procedures are executed by canonical name (`SymbolGraph.dataResourceIdentity`). An `executes` edge to a\n * resolved procedure points at the winning definition of the name, and executes the name's counted\n * definitions: every production copy (in neither a test file nor a documentation folder), or the winner\n * alone when no copy is production. The executing candidate takes on the reads and writes of their\n * bodies, following their further `executes` edges transitively; an unresolved procedure adds nothing.\n * A production copy that lost resolution is therefore executed whenever its name is, and the other docs\n * and test copies add nothing at all.\n * - A procedure name that no candidate-attributed symbol executes, directly or through a chain, credits the\n * candidate of each file that holds a counted definition of it, as if that candidate executed it. A name\n * that is executed never credits the candidates of the files that define it. Executors outside the view\n * (unclustered files, test files) do not count as executing. Among such names, one that another of them\n * with a counted definition in a candidate file reaches, from outside its own cycle, counts through that\n * chain instead; names that only execute each other, with nothing outside the cycle executing them, each\n * credit their own candidates. This is one strongly connected component pass, linear in procedures plus\n * executes edges.\n * - Reading a view does not expand to its tables.\n * - A target that no indexed table or view defines is external and has no kind. Resources are keyed by\n * canonical name; when several definitions share a name, the kind is that of the definition SymbolGraph\n * resolves the 2-part reference to.\n *\n * Pure and deterministic: the result does not depend on the order of the graph or the map.\n */\nexport function computeDataCoupling(input: DataCouplingInput): DataCoupling {\n const { graph, fileCandidate } = input;\n\n const nodes = new Map<string, SymbolNode>();\n for (const node of graph.allNodes()) nodes.set(node.symbolId, node);\n\n /** The kind of the definition a 2-part reference to `name` resolves to, or undefined when none defines it. */\n const definitionKind = (name: string): DataResourceKind | undefined => {\n const node = graph.getNode(`${name}::table`);\n return node && isDataResourceKind(node.kind) ? node.kind : undefined;\n };\n\n /** The resource name of an edge target, or undefined when the target is no table or view. */\n const resourceOf = (target: string): string | undefined => {\n const node = nodes.get(target);\n if (node) return isDataResourceKind(node.kind) ? nameOf(node.symbolId) : undefined;\n return isDataResourceKind(kindOf(target)) ? nameOf(target) : undefined;\n };\n const isProcedure = (target: string): boolean => nodes.get(target)?.kind === 'procedure';\n\n // Procedures by canonical name: each procedure node maps to its `name::procedure`, each name to its counted\n // definitions (tie-break order): every production copy, or the winner alone when no copy is production.\n const procedureName = new Map<string, string>();\n const countedOf = new Map<string, readonly string[]>();\n for (const node of nodes.values()) {\n if (node.kind !== 'procedure' || procedureName.has(node.symbolId)) continue;\n const identity = graph.dataResourceIdentity(node.symbolId);\n if (!identity) continue;\n for (const definition of identity.definitions) procedureName.set(definition.symbolId, identity.canonicalId);\n const counted = identity.production.length > 0 ? identity.production : [identity.winner];\n countedOf.set(identity.canonicalId, counted.map((definition) => definition.symbolId));\n }\n\n /** Per procedure name, the resolved procedure names the bodies of its counted definitions execute. */\n const executesNames = new Map<string, readonly string[]>();\n for (const [name, definitions] of countedOf) {\n const targets = new Set<string>();\n for (const definition of definitions) {\n for (const edge of graph.getForwardEdges(definition)) {\n const target = edge.kind === 'executes' ? procedureName.get(edge.to) : undefined;\n if (target !== undefined) targets.add(target);\n }\n }\n executesNames.set(name, [...targets]);\n }\n /** The procedure names reachable from `starts` through `executes` edges, `starts` included. */\n const closure = (starts: Iterable<string>): Set<string> => {\n const visited = new Set<string>();\n const stack = [...starts];\n while (stack.length > 0) {\n const name = stack.pop()!;\n if (visited.has(name)) continue;\n visited.add(name);\n for (const next of executesNames.get(name) ?? []) if (!visited.has(next)) stack.push(next);\n }\n return visited;\n };\n\n const usage = new Map<string, Map<number, Set<DataAccessMode>>>();\n const record = (candidate: number, target: string, mode: DataAccessMode): void => {\n const name = resourceOf(target);\n if (name === undefined) return;\n const byCandidate = usage.get(name) ?? new Map<number, Set<DataAccessMode>>();\n const modes = byCandidate.get(candidate) ?? new Set<DataAccessMode>();\n modes.add(mode);\n byCandidate.set(candidate, modes);\n usage.set(name, byCandidate);\n };\n\n /** Per candidate, the procedure names whose bodies it takes on (with everything they execute). */\n const executed = new Map<number, string[]>();\n const execute = (candidate: number, name: string): void => {\n const list = executed.get(candidate);\n if (list) list.push(name);\n else executed.set(candidate, [name]);\n };\n\n for (const edge of graph.allEdges()) {\n if (!DATA_EDGE_KINDS.has(edge.kind) || isProcedure(edge.from)) continue;\n const candidate = fileCandidate.get(fileOf(edge.from));\n if (candidate === undefined) continue;\n if (edge.kind === 'executes') {\n const name = procedureName.get(edge.to);\n if (name !== undefined) execute(candidate, name);\n continue;\n }\n record(candidate, edge.to, edge.kind === 'writes' ? 'writes' : 'reads');\n }\n\n // The procedure names that no non-procedure symbol of a candidate file reaches. A name that another of them\n // with a counted definition in a candidate file reaches, from outside its own cycle, counts through that\n // chain; the rest credit the candidate of each file that holds a counted definition of them. A cycle with\n // no way in from outside credits each member's candidates.\n const reached = closure([...executed.values()].flat());\n const unreached = [...countedOf.keys()].filter((name) => !reached.has(name));\n const inCandidateFile = (name: string): boolean => countedOf.get(name)!.some((definition) => fileCandidate.has(fileOf(definition)));\n const unreachedSet = new Set(unreached);\n const executesUnreached = (from: string): string[] => executesNames.get(from)!.filter((name) => unreachedSet.has(name));\n for (const name of unenteredSeeds(unreached, executesUnreached, inCandidateFile)) {\n for (const definition of countedOf.get(name)!) {\n const candidate = fileCandidate.get(fileOf(definition));\n if (candidate !== undefined) execute(candidate, name);\n }\n }\n\n // One walk per candidate over the procedure names it executes, directly or through other procedures, and\n // the body of every counted definition of each.\n for (const [candidate, starts] of executed) {\n for (const name of closure(starts)) {\n for (const definition of countedOf.get(name)!) {\n for (const edge of graph.getForwardEdges(definition)) {\n if (edge.kind === 'reads' || edge.kind === 'writes') record(candidate, edge.to, edge.kind);\n }\n }\n }\n }\n\n const resources = [...usage.entries()]\n .sort(([x], [y]) => compareCodepoint(x, y))\n .map(([name, byCandidate]): DataResourceUsage => {\n const accesses = [...byCandidate.entries()]\n .sort(([x], [y]) => x - y)\n .map(([candidate, modes]): CandidateDataAccess => ({ candidate, modes: MODES.filter((mode) => modes.has(mode)) }));\n const writers = accesses.filter((access) => access.modes.includes('writes')).map((access) => access.candidate);\n const kind = definitionKind(name);\n return {\n name,\n ...(kind !== undefined ? { kind } : {}),\n external: kind === undefined,\n accesses,\n writers,\n ...(writers.length === 1 ? { owner: writers[0]! } : {}),\n };\n });\n\n const shared = new Map<number, CandidateSharedTable[]>();\n for (const resource of resources) {\n if (resource.accesses.length < 2) continue;\n const entry: CandidateSharedTable = {\n name: resource.name,\n ...(resource.kind !== undefined ? { kind: resource.kind } : {}),\n external: resource.external,\n accesses: resource.accesses,\n ...(resource.owner !== undefined ? { owner: resource.owner } : {}),\n };\n for (const access of resource.accesses) {\n const list = shared.get(access.candidate);\n if (list) list.push(entry);\n else shared.set(access.candidate, [entry]);\n }\n }\n const sharedTables = new Map([...shared.entries()].sort(([x], [y]) => x - y));\n\n return { resources, sharedTables };\n}\n","import { compareCodepoint } from '../compare-codepoint.js';\nimport { makeGlobMatcher, type ResolvedContextsViewConfig } from '../config/load-config.js';\nimport { DATA_EDGE_KINDS } from '../data-coupling/data-kinds.js';\nimport { SymbolGraph } from '../graph/symbol-graph.js';\nimport type { CoChangeEntry, EdgeKind, FileIndex } from '../types.js';\n\n/** Weight of one distinct symbol edge by kind (spec 7.2). */\nexport const EDGE_KIND_WEIGHTS: Readonly<Record<EdgeKind, number>> = {\n calls: 1,\n extends: 1,\n implements: 1,\n uses: 1,\n imports: 0.5,\n reads: 0,\n writes: 0,\n executes: 0,\n};\n\nexport interface FileEdgeCount {\n readonly from: string;\n readonly to: string;\n readonly kind: EdgeKind;\n readonly count: number;\n}\n\n/** An undirected file pair (`a` < `b`) with its blended weight. */\nexport interface FilePair {\n readonly a: string;\n readonly b: string;\n readonly dependency: number;\n readonly coChange: number;\n /** Log-normalized count of distinct `reads`, `writes` and `executes` edges between the two files. */\n readonly data: number;\n readonly weight: number;\n}\n\nexport interface FileGraph {\n readonly files: readonly string[];\n readonly pairs: readonly FilePair[];\n readonly edgeCounts: readonly FileEdgeCount[];\n readonly dependents: ReadonlyMap<string, number>;\n}\n\nexport interface FileGraphInput {\n readonly indices: readonly FileIndex[];\n readonly isNode: (file: string) => boolean;\n readonly coChangeMap?: ReadonlyMap<string, readonly CoChangeEntry[]>;\n readonly weights: ResolvedContextsViewConfig['weights'];\n /** The symbol graph of `indices` from `buildIndexGraph`, when the caller already built it. */\n readonly graph?: SymbolGraph;\n}\n\nfunction round(value: number, digits: number): number {\n const factor = 10 ** digits;\n return Math.round(value * factor) / factor;\n}\n\nfunction fileOf(symbolId: string): string {\n const at = symbolId.indexOf('::');\n return at < 0 ? symbolId : symbolId.slice(0, at);\n}\n\nfunction pairKey(a: string, b: string): string {\n return `${a}\\n${b}`;\n}\n\nfunction orderedPair(x: string, y: string): [string, string] {\n return compareCodepoint(x, y) < 0 ? [x, y] : [y, x];\n}\n\n/**\n * The symbol graph of the indices, the one builder of the contexts view: files sorted by path, each file's\n * symbols sorted by id, all nodes first and then all edges. Deterministic: the same indices in any order,\n * with symbols in any order inside each file, resolve every edge to the same target.\n */\nexport function buildIndexGraph(indices: readonly FileIndex[]): SymbolGraph {\n const sorted = [...indices].sort((x, y) => compareCodepoint(x.file, y.file));\n const graph = new SymbolGraph();\n for (const index of sorted) {\n // SymbolGraph resolves a wrong-kind target through a last-wins file::name map, so the order symbols\n // are added in decides where such an edge lands. Adding them sorted by id makes that order fixed.\n const symbols = [...index.symbols].sort((x, y) => compareCodepoint(x.symbolId, y.symbolId));\n for (const symbol of symbols) graph.addNode(symbol);\n }\n for (const index of sorted) {\n for (const edge of index.edges) graph.addEdge(edge);\n }\n return graph;\n}\n\n/**\n * Builds the undirected file graph: distinct symbol edges between node files, weighted by kind and\n * log-scaled against the strongest pair, blended with the co-change frequency and the data component\n * (distinct `reads`, `writes` and `executes` edges per pair, log-scaled the same way). Data edges never\n * count in `edgeCounts` or `dependents`: data coupling is reported separately. Deterministic: the same\n * indices in any order, with symbols in any order inside each file, give a deep-equal result.\n * Rounding order: `weight` is computed from the unrounded components and rounded once to 6 decimals;\n * `dependency` and `data` are rounded to 6 decimals.\n */\nexport function buildFileGraph(input: FileGraphInput): FileGraph {\n const graph = input.graph ?? buildIndexGraph(input.indices);\n const sorted = [...input.indices].sort((x, y) => compareCodepoint(x.file, y.file));\n\n const nodes = new Set<string>();\n for (const index of sorted) {\n if (input.isNode(index.file)) nodes.add(index.file);\n }\n\n const coEntries = new Map<string, { a: string; b: string; frequency: number }>();\n for (const entries of input.coChangeMap?.values() ?? []) {\n for (const entry of entries) {\n if (entry.file1 === entry.file2) continue;\n // A co-change file accepted by isNode is a node even when all its partners are rejected.\n const ok1 = input.isNode(entry.file1);\n const ok2 = input.isNode(entry.file2);\n if (ok1) nodes.add(entry.file1);\n if (ok2) nodes.add(entry.file2);\n if (!ok1 || !ok2) continue;\n const [a, b] = orderedPair(entry.file1, entry.file2);\n const key = pairKey(a, b);\n const known = coEntries.get(key);\n if (!known || entry.frequency > known.frequency) coEntries.set(key, { a, b, frequency: entry.frequency });\n }\n }\n\n const symbolIds = new Set(graph.allNodes().map((node) => node.symbolId));\n const directed = new Map<string, FileEdgeCount>();\n const dependentSets = new Map<string, Set<string>>();\n const dataCounts = new Map<string, { a: string; b: string; count: number }>();\n for (const edge of graph.allEdges()) {\n if (!symbolIds.has(edge.to)) continue;\n const from = fileOf(edge.from);\n const to = fileOf(edge.to);\n if (from === to || !nodes.has(from) || !nodes.has(to)) continue;\n // Data coupling is reported separately: a data edge only feeds the data component of its pair.\n if (DATA_EDGE_KINDS.has(edge.kind)) {\n const [a, b] = orderedPair(from, to);\n const pair = pairKey(a, b);\n const known = dataCounts.get(pair);\n if (known) known.count++;\n else dataCounts.set(pair, { a, b, count: 1 });\n continue;\n }\n const key = `${from}\\n${to}\\n${edge.kind}`;\n const known = directed.get(key);\n directed.set(key, { from, to, kind: edge.kind, count: (known?.count ?? 0) + 1 });\n const set = dependentSets.get(to) ?? new Set<string>();\n set.add(from);\n dependentSets.set(to, set);\n }\n\n const edgeCounts = [...directed.values()].sort(\n (x, y) => compareCodepoint(x.from, y.from) || compareCodepoint(x.to, y.to) || compareCodepoint(x.kind, y.kind),\n );\n\n const rawDependency = new Map<string, { a: string; b: string; value: number }>();\n for (const entry of edgeCounts) {\n const [a, b] = orderedPair(entry.from, entry.to);\n const key = pairKey(a, b);\n const known = rawDependency.get(key) ?? { a, b, value: 0 };\n known.value += EDGE_KIND_WEIGHTS[entry.kind] * entry.count;\n rawDependency.set(key, known);\n }\n let maxValue = 0;\n for (const { value } of rawDependency.values()) maxValue = Math.max(maxValue, value);\n let maxDataCount = 0;\n for (const { count } of dataCounts.values()) maxDataCount = Math.max(maxDataCount, count);\n\n const keys = new Set<string>([...rawDependency.keys(), ...coEntries.keys(), ...dataCounts.keys()]);\n const pairs: FilePair[] = [];\n for (const key of keys) {\n const dep = rawDependency.get(key);\n const co = coEntries.get(key);\n const dataCount = dataCounts.get(key);\n const ends = (dep ?? co ?? dataCount)!;\n const dependency = dep && maxValue > 0 ? Math.log2(1 + dep.value) / Math.log2(1 + maxValue) : 0;\n const coChange = co?.frequency ?? 0;\n const data = dataCount ? Math.log2(1 + dataCount.count) / Math.log2(1 + maxDataCount) : 0;\n const weight = round(\n input.weights.dependency * dependency + input.weights.coChange * coChange + input.weights.data * data,\n 6,\n );\n if (!(weight > 0)) continue;\n pairs.push({ a: ends.a, b: ends.b, dependency: round(dependency, 6), coChange, data: round(data, 6), weight });\n }\n pairs.sort((x, y) => compareCodepoint(x.a, y.a) || compareCodepoint(x.b, y.b));\n\n const files = [...nodes].sort(compareCodepoint);\n const dependents = new Map<string, number>();\n for (const file of files) dependents.set(file, dependentSets.get(file)?.size ?? 0);\n\n return { files, pairs, edgeCounts, dependents };\n}\n\nexport type HubReason = 'configured' | 'fan-in' | 'god-node';\n\nexport interface HubDecision {\n readonly file: string;\n readonly reasons: readonly HubReason[];\n readonly dependents: number;\n readonly damping: number;\n}\n\n/**\n * Finds hub files: `hubs.paths` matches (damping 0), and with `hubs.auto` the files in the top\n * `topPercent` by dependents (every tie included, at least `minDependents`) and god-node files.\n * `damping` is `1 / log2(2 + dependents)` rounded to 3 decimals, a display value only:\n * `applyHubDamping` recomputes the exact factor. Sorted by file.\n */\nexport function detectHubs(\n graph: FileGraph,\n options: { readonly hubs: ResolvedContextsViewConfig['hubs']; readonly godNodeFiles: ReadonlySet<string> },\n): HubDecision[] {\n const { hubs } = options;\n const isConfigured = makeGlobMatcher([...hubs.paths]);\n let fanInCut = Number.POSITIVE_INFINITY;\n if (hubs.auto && graph.files.length > 0) {\n const k = Math.max(1, Math.ceil((graph.files.length * hubs.topPercent) / 100));\n const counts = graph.files.map((file) => graph.dependents.get(file) ?? 0).sort((x, y) => y - x);\n fanInCut = counts[Math.min(k, counts.length) - 1]!;\n }\n\n const decisions: HubDecision[] = [];\n for (const file of graph.files) {\n const dependents = graph.dependents.get(file) ?? 0;\n const reasons: HubReason[] = [];\n const configured = isConfigured(file);\n if (configured) reasons.push('configured');\n if (hubs.auto && dependents >= fanInCut && dependents >= hubs.minDependents) reasons.push('fan-in');\n if (hubs.auto && options.godNodeFiles.has(file)) reasons.push('god-node');\n if (reasons.length === 0) continue;\n decisions.push({\n file,\n reasons,\n dependents,\n damping: configured ? 0 : round(1 / Math.log2(2 + dependents), 3),\n });\n }\n return decisions;\n}\n\n/**\n * Multiplies each pair's weight by the exact factor of every hub endpoint (0 for a configured hub,\n * else `1 / log2(2 + dependents)`, not the rounded `damping`), then rounds the weight once to\n * 6 decimals. Zero weights are dropped.\n */\nexport function applyHubDamping(pairs: readonly FilePair[], hubs: readonly HubDecision[]): FilePair[] {\n const damping = new Map(\n hubs.map((hub) => [hub.file, hub.reasons.includes('configured') ? 0 : 1 / Math.log2(2 + hub.dependents)]),\n );\n const result: FilePair[] = [];\n for (const pair of pairs) {\n const weight = round(pair.weight * (damping.get(pair.a) ?? 1) * (damping.get(pair.b) ?? 1), 6);\n if (weight > 0) result.push({ ...pair, weight });\n }\n return result;\n}\n","import type { CodeFact, ILanguageAdapter } from '@ctxo/plugin-api';\n\n/**\n * The facts one adapter extracts from one file. `undefined` when the adapter has no `extractFacts`, when it\n * finds nothing, or when it throws (the failure is reported and indexing carries on without facts).\n */\nexport async function extractFileFacts(\n adapter: ILanguageAdapter,\n relativePath: string,\n source: string,\n): Promise<CodeFact[] | undefined> {\n if (typeof adapter.extractFacts !== 'function') return undefined;\n try {\n const facts = await adapter.extractFacts(relativePath, source);\n return facts.length > 0 ? facts : undefined;\n } catch (err) {\n console.error(`[ctxo] Fact extraction failed for ${relativePath}: ${(err as Error).message}`);\n return undefined;\n }\n}\n","import { mkdirSync, unlinkSync, existsSync, readFileSync } from 'node:fs';\nimport { dirname, join, relative, resolve, sep } from 'node:path';\nimport { isDeepStrictEqual } from 'node:util';\nimport type { FileIndex, CoChangeMatrix } from '../../core/types.js';\nimport { atomicWrite } from './atomic-write.js';\nimport { COMMUNITY_HISTORY_DIR, INDEX_ARTIFACT_FILES } from './json-index-reader.js';\n\nexport class JsonIndexWriter {\n private readonly indexDir: string;\n\n constructor(ctxoRoot: string) {\n this.indexDir = join(ctxoRoot, 'index');\n }\n\n write(fileIndex: FileIndex): void {\n if (!fileIndex.file) {\n throw new Error('FileIndex.file must not be empty');\n }\n\n const targetPath = this.resolveIndexPath(fileIndex.file);\n mkdirSync(dirname(targetPath), { recursive: true });\n\n const sorted = this.sortKeys(fileIndex);\n const json = JSON.stringify(sorted, null, 2);\n this.atomicWrite(targetPath, json);\n }\n\n /**\n * Writes `co-changes.json`. Returns false and leaves the file untouched when it already holds the\n * same `window` and `entries`: `timestamp` is metadata, so a run that found nothing new does not\n * show up as a change in git. Returns true when the file was (re)written.\n */\n writeCoChanges(matrix: CoChangeMatrix): boolean {\n mkdirSync(this.indexDir, { recursive: true });\n const targetPath = join(this.indexDir, 'co-changes.json');\n if (this.holdsSameCoChanges(targetPath, matrix)) return false;\n\n this.atomicWrite(targetPath, JSON.stringify(matrix, null, 2));\n return true;\n }\n\n /** True when the file at `targetPath` parses and has the same `window` and `entries` as `matrix`. */\n private holdsSameCoChanges(targetPath: string, matrix: CoChangeMatrix): boolean {\n if (!existsSync(targetPath)) return false;\n try {\n const existing: unknown = JSON.parse(readFileSync(targetPath, 'utf-8'));\n if (existing === null || typeof existing !== 'object') return false;\n const { window, entries } = existing as Partial<CoChangeMatrix>;\n return isDeepStrictEqual(window, matrix.window) && isDeepStrictEqual(entries, matrix.entries);\n } catch {\n // Unreadable or not JSON: treat it as different, so the write below replaces it.\n return false;\n }\n }\n\n private atomicWrite(targetPath: string, content: string): void {\n atomicWrite(targetPath, content);\n }\n\n delete(relativePath: string): void {\n const targetPath = this.resolveIndexPath(relativePath);\n if (existsSync(targetPath)) {\n unlinkSync(targetPath);\n }\n }\n\n /**\n * Deletes the JSON file of one index entry, given the path it was read from (see `JsonIndexReader.readEntries`)\n * rather than the source path it claims to be for, which a corrupt or crafted file can set to any name,\n * an artifact's included. Returns true when a file was deleted and false when there was none.\n *\n * Throws for a path outside the index folder, and for the artifacts that live there but are not entries\n * (the co-change matrix, the community snapshot and its history, the architecture artifacts).\n */\n deleteEntryFile(jsonPath: string): boolean {\n const resolved = resolve(jsonPath);\n const indexDir = resolve(this.indexDir);\n if (!resolved.startsWith(indexDir + sep)) {\n throw new Error(`Not inside the index folder: ${jsonPath}`);\n }\n const inIndex = relative(indexDir, resolved).replace(/\\\\/g, '/');\n if (INDEX_ARTIFACT_FILES.includes(inIndex) || inIndex.startsWith(`${COMMUNITY_HISTORY_DIR}/`)) {\n throw new Error(`Refusing to delete the index artifact ${inIndex}`);\n }\n if (!existsSync(resolved)) return false;\n unlinkSync(resolved);\n return true;\n }\n\n private resolveIndexPath(relativePath: string): string {\n const resolved = resolve(this.indexDir, `${relativePath}.json`);\n const normalizedDir = resolve(this.indexDir) + sep;\n if (!resolved.startsWith(normalizedDir)) {\n throw new Error(`Path traversal detected: ${relativePath}`);\n }\n return resolved;\n }\n\n private sortKeys(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortKeys(item));\n }\n if (obj !== null && typeof obj === 'object') {\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n return obj;\n }\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\n\nconst CURRENT_SCHEMA_VERSION = '1.0.0';\n\nexport class SchemaManager {\n private readonly versionFilePath: string;\n\n constructor(ctxoRoot: string) {\n this.versionFilePath = join(ctxoRoot, 'index', 'schema-version');\n }\n\n currentVersion(): string {\n return CURRENT_SCHEMA_VERSION;\n }\n\n readStoredVersion(): string | undefined {\n if (!existsSync(this.versionFilePath)) {\n return undefined;\n }\n return readFileSync(this.versionFilePath, 'utf-8').trim();\n }\n\n writeVersion(): void {\n mkdirSync(dirname(this.versionFilePath), { recursive: true });\n writeFileSync(this.versionFilePath, CURRENT_SCHEMA_VERSION, 'utf-8');\n }\n\n isCompatible(): boolean {\n const stored = this.readStoredVersion();\n if (!stored) return false;\n return stored === CURRENT_SCHEMA_VERSION;\n }\n}\n","import { compareCodepoint } from '../compare-codepoint.js';\nimport type { CommitChangeSet } from '../types.js';\n\n/** A non-merge commit with its changed paths mapped to the newest name of each file. */\nexport interface CanonicalCommit {\n readonly hash: string;\n readonly message: string;\n readonly date: string;\n readonly author: string;\n readonly committedAt: number;\n /** Canonical file names the commit touched: sorted by code point, no duplicates. */\n readonly files: readonly string[];\n}\n\n/**\n * Maps every path in a change log to the newest name of its file, so a file keeps one identity\n * across renames.\n *\n * `commits` must be newest first (the order `git log` returns). The log is walked in that order\n * with an alias map: on `R old -> new` it records `canon[old] = canon[new] ?? new`, and every\n * path maps to `canon[path] ?? path`. A rename therefore reaches only commits older than itself;\n * a newer commit that reuses the old name keeps it. The entries of one commit can be handled in\n * order because git (with `-M`) reports a rename only between a deleted and an added path, so no\n * path is both the source and the destination of a rename in the same commit.\n *\n * A copy (`C`) contributes its new path and creates no alias. A deleted file keeps the last name\n * it had, and callers drop the files that no longer exist. Every input commit yields one output\n * commit in the same order, including commits that changed no files.\n */\nexport function canonicalizeChangeLog(commits: readonly CommitChangeSet[]): CanonicalCommit[] {\n const canon = new Map<string, string>();\n const canonical: CanonicalCommit[] = [];\n\n for (const commit of commits) {\n const files = new Set<string>();\n for (const change of commit.changes) {\n const newest = canon.get(change.path) ?? change.path;\n if (change.status === 'R' && change.oldPath !== undefined) {\n canon.set(change.oldPath, newest);\n }\n files.add(newest);\n }\n canonical.push({\n hash: commit.hash,\n message: commit.message,\n date: commit.date,\n author: commit.author,\n committedAt: commit.committedAt,\n files: [...files].sort(compareCodepoint),\n });\n }\n\n return canonical;\n}\n","import type { CommitRecord } from '../types.js';\nimport type { CanonicalCommit } from './change-log.js';\n\n/**\n * Builds the per-file commit history behind `intent[]`: for each canonical file, its newest\n * `maxPerFile` commits, newest first.\n *\n * `commits` must be newest first, as `canonicalizeChangeLog` returns them. A commit is listed at\n * most once per file. Files that no longer exist are included; callers read only the files they\n * index. A `maxPerFile` below one (or `NaN`) keeps nothing, and a fractional value rounds down.\n */\nexport function buildIntentHistory(\n commits: readonly CanonicalCommit[],\n maxPerFile: number,\n): Map<string, CommitRecord[]> {\n const history = new Map<string, CommitRecord[]>();\n const limit = Math.floor(maxPerFile);\n if (!(limit >= 1)) return history;\n\n for (const commit of commits) {\n // One record per commit, shared by all of its files (records are read-only).\n let record: CommitRecord | undefined;\n for (const file of commit.files) {\n let records = history.get(file);\n if (records === undefined) {\n records = [];\n history.set(file, records);\n }\n if (records.length >= limit) continue;\n if (records.at(-1)?.hash === commit.hash) continue;\n record ??= { hash: commit.hash, message: commit.message, date: commit.date, author: commit.author };\n records.push(record);\n }\n }\n\n return history;\n}\n","import { UndirectedGraph } from 'graphology';\n\nimport { compareCodepoint } from '../compare-codepoint.js';\nimport { DATA_EDGE_KINDS } from '../data-coupling/data-kinds.js';\nimport type { SymbolGraph } from '../graph/symbol-graph.js';\nimport type { CommunityEntry, EdgeQuality, GodNode } from '../types.js';\nimport { labelCommunities } from './community-labeler.js';\nimport { runLouvain, splitDisconnectedCommunities } from './louvain.js';\n\nexport interface CommunityComputeResult {\n readonly communities: CommunityEntry[];\n readonly godNodes: GodNode[];\n readonly modularity: number;\n readonly crossClusterEdges: number;\n readonly edgeQuality: EdgeQuality;\n}\n\nexport interface CommunityDetectorOptions {\n readonly resolution?: number;\n readonly godNodeMinBridged?: number;\n readonly godNodeMaxResults?: number;\n}\n\nconst DEFAULT_RESOLUTION = 1.0;\nconst DEFAULT_GOD_NODE_MIN_BRIDGED = 3;\nconst DEFAULT_GOD_NODE_MAX_RESULTS = 25;\n\nexport class CommunityDetector {\n private readonly resolution: number;\n private readonly godNodeMinBridged: number;\n private readonly godNodeMaxResults: number;\n\n constructor(options: CommunityDetectorOptions = {}) {\n this.resolution = options.resolution ?? DEFAULT_RESOLUTION;\n this.godNodeMinBridged = options.godNodeMinBridged ?? DEFAULT_GOD_NODE_MIN_BRIDGED;\n this.godNodeMaxResults = options.godNodeMaxResults ?? DEFAULT_GOD_NODE_MAX_RESULTS;\n }\n\n detect(\n graph: SymbolGraph,\n pagerank: ReadonlyMap<string, number>,\n edgeQuality: EdgeQuality = 'full',\n ): CommunityComputeResult {\n const nodes = graph.allNodes();\n if (nodes.length === 0) {\n return {\n communities: [],\n godNodes: [],\n modularity: 0,\n crossClusterEdges: 0,\n edgeQuality,\n };\n }\n\n // Sort for determinism. Louvain result depends on node insertion order.\n // Use codepoint comparison (NOT localeCompare) — localeCompare is\n // locale-sensitive and can produce different orders on different machines\n // (e.g., Turkish locale treats dotted/dotless i specially), which would\n // poison snapshot drift comparisons across teammates or CI runners.\n const sortedNodes = [...nodes].sort((a, b) => compareCodepoint(a.symbolId, b.symbolId));\n\n const gph = new UndirectedGraph();\n for (const node of sortedNodes) {\n gph.addNode(node.symbolId);\n }\n\n // Collapse directed edges to undirected weights. A→B and B→A contribute to same undirected edge.\n const weightByPair = new Map<string, number>();\n for (const edge of graph.allEdges()) {\n if (edge.from === edge.to) continue;\n if (DATA_EDGE_KINDS.has(edge.kind)) continue;\n if (!gph.hasNode(edge.from) || !gph.hasNode(edge.to)) continue;\n const [a, b] = edge.from < edge.to ? [edge.from, edge.to] : [edge.to, edge.from];\n const key = `${a}|${b}`;\n weightByPair.set(key, (weightByPair.get(key) ?? 0) + 1);\n }\n\n for (const [key, weight] of weightByPair) {\n const [from, to] = key.split('|') as [string, string];\n gph.addEdge(from, to, { weight });\n }\n\n if (gph.size === 0) {\n return {\n communities: this.singletonCommunities(sortedNodes),\n godNodes: [],\n modularity: 0,\n crossClusterEdges: 0,\n edgeQuality,\n };\n }\n\n const result = runLouvain(gph, this.resolution);\n\n const rawAssignments = result.communities;\n const splitAssignments = splitDisconnectedCommunities(gph, rawAssignments);\n const normalizedAssignments = this.normalizeCommunityIds(splitAssignments, sortedNodes);\n\n const memberIndex = this.buildMemberIndex(normalizedAssignments);\n const labels = labelCommunities(memberIndex, pagerank);\n\n const communities: CommunityEntry[] = sortedNodes.map((node) => {\n const communityId = normalizedAssignments.get(node.symbolId) ?? 0;\n return {\n symbolId: node.symbolId,\n communityId,\n communityLabel: labels.get(communityId) ?? `community-${communityId}`,\n };\n });\n\n const crossClusterEdges = this.countCrossClusterEdges(graph, normalizedAssignments);\n const godNodes = this.detectGodNodes(graph, normalizedAssignments, pagerank);\n\n return {\n communities,\n godNodes,\n modularity: result.modularity,\n crossClusterEdges,\n edgeQuality,\n };\n }\n\n private singletonCommunities(nodes: ReadonlyArray<{ symbolId: string }>): CommunityEntry[] {\n return nodes.map((node, i) => ({\n symbolId: node.symbolId,\n communityId: i,\n communityLabel: `isolated-${i}`,\n }));\n }\n\n private normalizeCommunityIds(\n assignments: Map<string, number>,\n sortedNodes: ReadonlyArray<{ symbolId: string }>,\n ): Map<string, number> {\n const remap = new Map<number, number>();\n const result = new Map<string, number>();\n let nextId = 0;\n for (const node of sortedNodes) {\n const raw = assignments.get(node.symbolId);\n if (raw === undefined) {\n result.set(node.symbolId, nextId);\n remap.set(nextId, nextId);\n nextId++;\n continue;\n }\n let normalized = remap.get(raw);\n if (normalized === undefined) {\n normalized = nextId++;\n remap.set(raw, normalized);\n }\n result.set(node.symbolId, normalized);\n }\n return result;\n }\n\n private buildMemberIndex(assignments: Map<string, number>): Map<number, string[]> {\n const index = new Map<number, string[]>();\n for (const [symbolId, communityId] of assignments) {\n const list = index.get(communityId) ?? [];\n list.push(symbolId);\n index.set(communityId, list);\n }\n for (const list of index.values()) list.sort();\n return index;\n }\n\n private countCrossClusterEdges(\n graph: SymbolGraph,\n assignments: Map<string, number>,\n ): number {\n let count = 0;\n for (const edge of graph.allEdges()) {\n if (DATA_EDGE_KINDS.has(edge.kind)) continue;\n const from = assignments.get(edge.from);\n const to = assignments.get(edge.to);\n if (from === undefined || to === undefined) continue;\n if (from !== to) count++;\n }\n return count;\n }\n\n private detectGodNodes(\n graph: SymbolGraph,\n assignments: Map<string, number>,\n pagerank: ReadonlyMap<string, number>,\n ): GodNode[] {\n const candidates: GodNode[] = [];\n for (const node of graph.allNodes()) {\n const ownCommunity = assignments.get(node.symbolId);\n if (ownCommunity === undefined) continue;\n const bridged = new Set<number>();\n const forward = graph.getForwardEdges(node.symbolId);\n const reverse = graph.getReverseEdges(node.symbolId);\n for (const edge of forward) {\n if (DATA_EDGE_KINDS.has(edge.kind)) continue;\n const other = assignments.get(edge.to);\n if (other !== undefined && other !== ownCommunity) bridged.add(other);\n }\n for (const edge of reverse) {\n if (DATA_EDGE_KINDS.has(edge.kind)) continue;\n const other = assignments.get(edge.from);\n if (other !== undefined && other !== ownCommunity) bridged.add(other);\n }\n if (bridged.size >= this.godNodeMinBridged) {\n const pr = pagerank.get(node.symbolId) ?? 0;\n candidates.push({\n symbolId: node.symbolId,\n bridgedCommunities: [...bridged].sort((a, b) => a - b),\n centralityScore: bridged.size * (pr > 0 ? pr : 1 / graph.nodeCount),\n });\n }\n }\n\n candidates.sort((a, b) => {\n if (b.centralityScore !== a.centralityScore) {\n return b.centralityScore - a.centralityScore;\n }\n return compareCodepoint(a.symbolId, b.symbolId);\n });\n\n return candidates.slice(0, this.godNodeMaxResults);\n }\n}\n","const MIN_PREFIX_SEGMENTS = 1;\nconst PATH_SEPARATOR = '/';\n\nexport function labelCommunities(\n membersByCommunity: ReadonlyMap<number, readonly string[]>,\n pagerank: ReadonlyMap<string, number>,\n): Map<number, string> {\n const labels = new Map<number, string>();\n const used = new Set<string>();\n\n for (const [communityId, members] of membersByCommunity) {\n const label = pickLabel(members, pagerank, used);\n labels.set(communityId, label);\n used.add(label);\n }\n\n return labels;\n}\n\nfunction pickLabel(\n members: readonly string[],\n pagerank: ReadonlyMap<string, number>,\n used: ReadonlySet<string>,\n): string {\n const files = members.map(extractFilePath).filter((file): file is string => Boolean(file));\n const prefixLabel = longestCommonPathPrefix(files);\n\n if (prefixLabel && !used.has(prefixLabel)) {\n return prefixLabel;\n }\n\n const topSymbol = pickTopByPagerank(members, pagerank);\n if (topSymbol) {\n const name = extractSymbolName(topSymbol);\n if (name) {\n const candidate = `${name} area`;\n if (!used.has(candidate)) return candidate;\n }\n }\n\n if (prefixLabel) {\n return disambiguate(prefixLabel, used);\n }\n\n return disambiguate('cluster', used);\n}\n\nfunction extractFilePath(symbolId: string): string | undefined {\n const parts = symbolId.split('::');\n return parts.length === 3 ? parts[0] : undefined;\n}\n\nfunction extractSymbolName(symbolId: string): string | undefined {\n const parts = symbolId.split('::');\n return parts.length === 3 ? parts[1] : undefined;\n}\n\nfunction longestCommonPathPrefix(files: readonly string[]): string | undefined {\n if (files.length === 0) return undefined;\n const normalized = files.map((file) => file.replace(/\\\\/g, PATH_SEPARATOR));\n const segments = normalized.map((file) => file.split(PATH_SEPARATOR));\n const first = segments[0]!;\n\n let matchLength = first.length;\n for (let i = 1; i < segments.length; i++) {\n const current = segments[i]!;\n matchLength = Math.min(matchLength, current.length);\n for (let j = 0; j < matchLength; j++) {\n if (current[j] !== first[j]) {\n matchLength = j;\n break;\n }\n }\n if (matchLength === 0) break;\n }\n\n // Drop the filename if the common prefix includes it.\n const fullMatch = matchLength === first.length && files.length === 1;\n const keep = fullMatch ? matchLength - 1 : matchLength;\n if (keep < MIN_PREFIX_SEGMENTS) return undefined;\n\n const prefix = first.slice(0, keep).join(PATH_SEPARATOR);\n return prefix.length > 0 ? prefix : undefined;\n}\n\nfunction pickTopByPagerank(\n members: readonly string[],\n pagerank: ReadonlyMap<string, number>,\n): string | undefined {\n let best: string | undefined;\n let bestScore = -1;\n for (const symbolId of members) {\n const score = pagerank.get(symbolId) ?? 0;\n if (score > bestScore || (score === bestScore && best !== undefined && symbolId < best)) {\n bestScore = score;\n best = symbolId;\n }\n }\n return best ?? members[0];\n}\n\nfunction disambiguate(base: string, used: ReadonlySet<string>): string {\n if (!used.has(base)) return base;\n let suffix = 2;\n while (used.has(`${base} (${suffix})`)) suffix++;\n return `${base} (${suffix})`;\n}\n","import { join } from 'node:path';\nimport { SqliteStorageAdapter } from '../adapters/storage/sqlite-storage-adapter.js';\n\nexport class SyncCommand {\n private readonly ctxoRoot: string;\n\n constructor(projectRoot: string) {\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n async run(): Promise<void> {\n console.error('[ctxo] Rebuilding SQLite cache from committed JSON index...');\n\n const storage = new SqliteStorageAdapter(this.ctxoRoot, { allowProductionPath: true });\n try {\n await storage.init();\n } finally {\n storage.close();\n }\n\n console.error('[ctxo] Sync complete');\n }\n}\n","import { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { execFileSync } from 'node:child_process';\nimport { JsonIndexReader } from '../adapters/storage/json-index-reader.js';\nimport { SchemaManager } from '../adapters/storage/schema-manager.js';\n\nexport class StatusCommand {\n private readonly projectRoot: string;\n private readonly ctxoRoot: string;\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n run(): void {\n const indexDir = join(this.ctxoRoot, 'index');\n\n if (!existsSync(indexDir)) {\n console.error('[ctxo] No index found. Run \"ctxo index\" first.');\n return;\n }\n\n const schemaManager = new SchemaManager(this.ctxoRoot);\n const version = schemaManager.readStoredVersion() ?? 'unknown';\n\n const reader = new JsonIndexReader(this.ctxoRoot);\n const indices = reader.readAll();\n\n const totalSymbols = indices.reduce((sum, idx) => sum + idx.symbols.length, 0);\n const totalEdges = indices.reduce((sum, idx) => sum + idx.edges.length, 0);\n\n console.error(`[ctxo] Index Status`);\n console.error(` Schema version: ${version}`);\n console.error(` Indexed files: ${indices.length}`);\n console.error(` Total symbols: ${totalSymbols}`);\n console.error(` Total edges: ${totalEdges}`);\n\n const cacheExists = existsSync(join(this.ctxoRoot, '.cache', 'symbols.db'));\n console.error(` SQLite cache: ${cacheExists ? 'present' : 'missing (run ctxo sync)'}`);\n\n // Per-file listing with timestamps\n if (indices.length > 0) {\n console.error('');\n console.error(' Files:');\n\n // Get source files to detect orphans\n const sourceFiles = this.getSourceFiles();\n\n for (const idx of indices.sort((a, b) => a.file.localeCompare(b.file))) {\n const ts = new Date(idx.lastModified * 1000).toISOString();\n const isOrphaned = sourceFiles.size > 0 && !sourceFiles.has(idx.file);\n const badge = isOrphaned ? ' [orphaned]' : '';\n console.error(` ${idx.file} ${ts} (${idx.symbols.length} symbols, ${idx.edges.length} edges)${badge}`);\n }\n }\n }\n\n private getSourceFiles(): Set<string> {\n try {\n // -z: NUL-separated, unquoted names (git quotes non-ASCII paths otherwise).\n const output = execFileSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard'], {\n cwd: this.projectRoot,\n encoding: 'utf-8',\n });\n return new Set(output.split('\\0').filter((l) => l.length > 0));\n } catch {\n return new Set();\n }\n }\n}\n","import { mkdtempSync, rmSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { tmpdir } from 'node:os';\nimport { IndexCommand } from './index-command.js';\nimport { JsonIndexReader } from '../adapters/storage/json-index-reader.js';\n\nexport class VerifyCommand {\n private readonly projectRoot: string;\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n }\n\n async run(): Promise<void> {\n console.error('[ctxo] Verifying index freshness...');\n\n // Build index into a temp directory to avoid overwriting committed index\n const tempDir = mkdtempSync(join(tmpdir(), 'ctxo-verify-'));\n\n try {\n const tempCtxo = join(tempDir, '.ctxo');\n\n // Run index into temp .ctxo (does not touch committed index)\n const indexCmd = new IndexCommand(this.projectRoot, tempCtxo);\n await indexCmd.run({ skipSideEffects: true });\n\n // Compare temp index with committed index\n const committedReader = new JsonIndexReader(join(this.projectRoot, '.ctxo'));\n const freshReader = new JsonIndexReader(tempCtxo);\n\n const committedIndices = committedReader.readAll();\n const freshIndices = freshReader.readAll();\n\n // Compare full index: symbols + edges + intent + antiPatterns\n const serialize = (i: { symbols: unknown; edges: unknown; intent: unknown; antiPatterns: unknown }) =>\n JSON.stringify({ symbols: i.symbols, edges: i.edges, intent: i.intent, antiPatterns: i.antiPatterns });\n\n const committedMap = new Map(committedIndices.map((i) => [i.file, serialize(i)]));\n const freshMap = new Map(freshIndices.map((i) => [i.file, serialize(i)]));\n\n let stale = false;\n\n // Check for files that changed or were added\n for (const [file, freshData] of freshMap) {\n const committed = committedMap.get(file);\n if (committed !== freshData) {\n console.error(`[ctxo] STALE: ${file}`);\n stale = true;\n }\n }\n\n // Check for files that were removed\n for (const file of committedMap.keys()) {\n if (!freshMap.has(file)) {\n console.error(`[ctxo] REMOVED: ${file}`);\n stale = true;\n }\n }\n\n if (stale) {\n console.error('[ctxo] Index is STALE — run \"ctxo index\" and commit .ctxo/index/');\n process.exit(1);\n }\n\n console.error('[ctxo] Index is up to date');\n } finally {\n rmSync(tempDir, { recursive: true, force: true });\n }\n }\n}\n","import { isAbsolute, join, relative } from 'node:path';\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport {\n PLATFORMS,\n detectPlatforms,\n installRules,\n ensureGitignore,\n ensureConfig,\n ensureIndexDir,\n getMcpConfigTargets,\n ensureMcpConfig,\n installSkills,\n ensureClaudeHook,\n gateEnabled,\n linkedRulesPlatforms,\n planRules,\n resolveRulesTier,\n rulesFileHoldReasons,\n skillInstallWarnings,\n type InstallResult,\n type RulesHoldOptions,\n} from './ai-rules.js';\nimport type { RulesTier } from '../core/agent-rules/rules-block.js';\nimport {\n detectLanguages,\n decideNeededLanguages,\n officialPluginFor,\n type KnownLanguage,\n} from '../core/detection/detect-languages.js';\nimport { InstallCommand } from './install-command.js';\nimport {\n POST_COMMIT_CONTENT,\n POST_MERGE_CONTENT,\n resolveHooksDir,\n sharedHooksScope,\n sharedHooksWarning,\n upsertCtxoBlock,\n forwardSlashes,\n type SharedHooksScope,\n} from './git-hooks.js';\nimport { pluginStepEnabled, resolveInitParts, type InitPart } from './init-parts.js';\n\nconst requireCjs = createRequire(import.meta.url);\n\nfunction resolveInstalledPlugins(needed: readonly KnownLanguage[]): {\n installed: KnownLanguage[];\n missing: KnownLanguage[];\n} {\n const installed: KnownLanguage[] = [];\n const missing: KnownLanguage[] = [];\n for (const lang of needed) {\n try {\n requireCjs.resolve(`${officialPluginFor(lang)}/package.json`);\n installed.push(lang);\n } catch {\n missing.push(lang);\n }\n }\n return { installed, missing };\n}\n\n/* ------------------------------------------------------------------ */\n/* Options */\n/* ------------------------------------------------------------------ */\n\n/** Outcome of `InitCommand.installHooks`. Not installing into a shared hooks directory is a normal outcome, not an error. */\nexport interface HooksInstallResult {\n readonly installed: boolean;\n readonly hooksDir: string;\n /** Set when `core.hooksPath` comes from the global or system git config, so ctxo left it alone. */\n readonly sharedScope?: SharedHooksScope;\n /**\n * One row per hook (`post-commit`, then `post-merge`); empty for a shared hooks directory. Unlike\n * other rows, a hook row's `file` is absolute when the hooks directory is outside the project.\n */\n readonly results: InstallResult[];\n}\n\nexport interface InitOptions {\n /**\n * `--tools`: the AI tools to set up; a repeated id counts once. Without it, the interactive run asks,\n * and a `--yes` run and a dry run take every tool (D16; final review M2).\n */\n tools?: string[];\n yes?: boolean;\n /** `--rules`: deprecated alias for `skip: ['git-hooks', 'guard']`; it also skips the plugin step. */\n rulesOnly?: boolean;\n dryRun?: boolean;\n /** Skip language detection prompt + any install invocation. */\n noInstall?: boolean;\n /** `--only`: install exactly these parts. The router rejects it together with `skip` or `rulesOnly`. */\n only?: InitPart[];\n /** `--skip`: install everything except these parts. */\n skip?: InitPart[];\n /** `--no-guard`: does not install the safe-edit guard. */\n noGuard?: boolean;\n}\n\n/* ------------------------------------------------------------------ */\n/* Terminal UI helpers (zero dependency — picocolors only) */\n/* ------------------------------------------------------------------ */\n\nimport type picocolorsType from 'picocolors';\ntype PC = typeof picocolorsType;\n\nconst STRIP_ANSI = /\\u001b\\[[0-9;]*m/g;\nconst strip = (s: string) => s.replace(STRIP_ANSI, '');\n\nfunction box(lines: string[], opts: { title?: string; border?: (s: string) => string; width?: number }, pc: PC): string {\n const border = opts.border ?? pc.dim;\n const w = opts.width ?? Math.max(...lines.map(l => strip(l).length), strip(opts.title ?? '').length + 4, 48);\n const pad = (s: string) => s + ' '.repeat(Math.max(0, w - strip(s).length));\n\n const hr = '\\u2500'.repeat(w + 2);\n let top: string;\n if (opts.title) {\n const tLen = strip(opts.title).length;\n top = border('\\u256d\\u2500 ') + opts.title + border(` ${ '\\u2500'.repeat(Math.max(0, w - tLen - 2))}\\u256e`);\n } else {\n top = border(`\\u256d${hr}\\u256e`);\n }\n const bot = border(`\\u2570${hr}\\u256f`);\n const body = lines.map(l => `${border('\\u2502')} ${pad(l)} ${border('\\u2502')}`).join('\\n');\n return `${top}\\n${body}\\n${bot}`;\n}\n\nfunction stepHeader(step: number, total: number, title: string, desc: string, pc: PC): string {\n const stepLabel = pc.bold(pc.cyan(`${step}/${total}`));\n const titleStr = pc.bold(title);\n return box(\n [`${pc.dim(desc)}`],\n { title: `${stepLabel} ${titleStr}`, border: pc.cyan },\n pc,\n );\n}\n\n/* ------------------------------------------------------------------ */\n/* ASCII banner with faux gradient */\n/* ------------------------------------------------------------------ */\n\nfunction renderBanner(_version: string | undefined, pc: PC): string {\n const art = [\n ' \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2557\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2557\\u2588\\u2588\\u2557 \\u2588\\u2588\\u2557 \\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2557 ',\n ' \\u2588\\u2588\\u2554\\u2550\\u2550\\u2550\\u255d\\u255a\\u2550\\u2550\\u2588\\u2588\\u2554\\u2550\\u2550\\u255d\\u255a\\u2588\\u2588\\u2557\\u2588\\u2588\\u2554\\u255d\\u2588\\u2588\\u2554\\u2550\\u2550\\u2550\\u2588\\u2588\\u2557',\n ' \\u2588\\u2588\\u2551 \\u2588\\u2588\\u2551 \\u255a\\u2588\\u2588\\u2588\\u2554\\u255d \\u2588\\u2588\\u2551 \\u2588\\u2588\\u2551',\n ' \\u2588\\u2588\\u2551 \\u2588\\u2588\\u2551 \\u2588\\u2588\\u2554\\u2588\\u2588\\u2557 \\u2588\\u2588\\u2551 \\u2588\\u2588\\u2551',\n ' \\u255a\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2557 \\u2588\\u2588\\u2551 \\u2588\\u2588\\u2554\\u255d\\u255a\\u2588\\u2588\\u2557\\u255a\\u2588\\u2588\\u2588\\u2588\\u2588\\u2588\\u2554\\u255d',\n ' \\u255a\\u2550\\u2550\\u2550\\u2550\\u2550\\u255d \\u255a\\u2550\\u255d \\u255a\\u2550\\u255d \\u255a\\u2550\\u255d \\u255a\\u2550\\u2550\\u2550\\u2550\\u2550\\u255d ',\n ];\n\n // Faux vertical gradient: cyan → blueBright → magentaBright\n const colors = [pc.cyan, pc.cyan, pc.blueBright, pc.blueBright, pc.magentaBright, pc.magentaBright] as const;\n const coloredArt = art.map((line, i) => colors[i]!(line));\n\n const tagline1 = pc.bold(pc.white(' Code intelligence for AI agents.'));\n const tagline2 = pc.dim(' One call instead of hundreds.');\n\n const inner = [\n '',\n ...coloredArt,\n '',\n tagline1,\n tagline2,\n '',\n ];\n\n return box(inner, { border: pc.dim }, pc);\n}\n\n/* ------------------------------------------------------------------ */\n/* Init output */\n/* ------------------------------------------------------------------ */\n\nconst RULES_DEPRECATION_NOTICE =\n '[ctxo] --rules is deprecated and now means --skip git-hooks,guard. Use --only or --skip instead.';\nconst NOTHING_TO_INSTALL_NOTICE = '[ctxo] Nothing to install: every part is excluded.';\nconst SHARED_HOOKS_SKIPPED = 'git hooks skipped - shared hooks directory (see warning above)';\n\n/** The parts the AI Tools step serves: without any of them, no tool list is asked for. */\nconst TOOL_PARTS: readonly InitPart[] = ['rules', 'skills', 'guard', 'mcp'];\n\n/** One row of init output: a file and what happened to it. */\ninterface InitResult extends InstallResult {\n /** A rules file that `rulesHold` kept back: `skipped`, with `heldWarning` as its warning. */\n readonly held?: boolean;\n /** A git hook row from `installHooks`; the dry run prints its file as `<path> (git hook)`. */\n readonly gitHook?: boolean;\n}\n\n/**\n * The tool ids a run sets up: `--tools` with each id once, or every platform without it. The dry run\n * and a `--yes` run take the same default, so the dry run previews what `--yes` writes (final review M2).\n */\nfunction selectedTools(options: InitOptions): string[] {\n return options.tools ? [...new Set(options.tools)] : PLATFORMS.map((p) => p.id);\n}\n\n/** Why a held rules file was left unchanged, and the commands that let it be written. */\nfunction heldWarning(file: string): string {\n return `${file}: left unchanged until the guard and skills are installed; run \"ctxo init --only rules,skills,guard\" or \"ctxo doctor --fix\"`;\n}\n\n/** What these options decline in this run, for `rulesHold`: `--no-guard` and `--skip skills` (Review Focus 3). */\nfunction declinedBy(options: InitOptions): { noGuard: boolean; skipSkills: boolean } {\n return { noGuard: options.noGuard === true, skipSkills: options.skip?.includes('skills') === true };\n}\n\n/** `skipped` reads `unchanged` in init output (D16). */\nfunction actionLabel(action: InstallResult['action']): string {\n return action === 'skipped' ? 'unchanged' : action;\n}\n\n/** `[ctxo] ✓ <file> (<created|updated|unchanged>)`; a result with a warning prints only `[ctxo] ⚠ <warning>` (D16). */\nfunction formatResultLine(result: InstallResult): string {\n return result.warning !== undefined\n ? `[ctxo] \\u26a0 ${result.warning}`\n : `[ctxo] \\u2713 ${result.file} (${actionLabel(result.action)})`;\n}\n\n/** The same result as a row of the interactive summary box. */\nfunction summaryRow(result: InstallResult, pc: PC): string {\n return result.warning !== undefined\n ? `${pc.yellow('\\u26a0')} ${result.warning}`\n : `${pc.green('\\u2713')} ${pc.bold(result.file)} ${pc.dim(actionLabel(result.action))}`;\n}\n\nconst DRY_RUN_HEADER = '[ctxo] Dry run: nothing is written. Files init would touch:';\n\n/** A dry-run row's action word; `skipped` reads `unchanged` (D16). */\nconst PLAN_ACTION: Readonly<Record<InstallResult['action'], string>> = {\n created: 'would create',\n updated: 'would update',\n skipped: 'unchanged',\n};\n\n/**\n * One dry-run line: ` <file> <would create|would update|unchanged>`, the file padded to 44 columns,\n * or the warning sign and the text for a result with a warning. A git hook's file reads `<path> (git hook)`,\n * and a held rules file `unchanged (held)`.\n */\nfunction formatPlanLine(result: InitResult): string {\n if (result.held) return ` ${result.file.padEnd(44)} unchanged (held)`;\n if (result.warning !== undefined) return ` \\u26a0 ${result.warning}`;\n const file = result.gitHook ? `${result.file} (git hook)` : result.file;\n return ` ${file.padEnd(44)} ${PLAN_ACTION[result.action]}`;\n}\n\n/** Exits 1 on the first tool id that is not a platform, naming the valid ones. */\nfunction exitOnUnknownTools(toolIds: readonly string[]): void {\n for (const id of toolIds) {\n if (!PLATFORMS.find(p => p.id === id)) {\n console.error(`[ctxo] Unknown tool: \"${id}\". Valid: ${PLATFORMS.map(p => p.id).join(', ')}`);\n process.exit(1);\n }\n }\n}\n\n/** The git hooks init installs, in install order. */\nconst GIT_HOOKS = [\n { name: 'post-commit', content: POST_COMMIT_CONTENT },\n { name: 'post-merge', content: POST_MERGE_CONTENT },\n] as const;\n\n/** A path for human output: project-relative with forward slashes inside the project, absolute otherwise. */\nfunction displayPath(projectRoot: string, path: string): string {\n const rel = forwardSlashes(relative(projectRoot, path));\n return rel === '' || rel.startsWith('..') || isAbsolute(rel) ? forwardSlashes(path) : rel;\n}\n\n/* ------------------------------------------------------------------ */\n/* InitCommand */\n/* ------------------------------------------------------------------ */\n\nexport class InitCommand {\n private readonly projectRoot: string;\n\n constructor(projectRoot: string) {\n // Router now resolves this; kept as a defensive copy for direct construction.\n this.projectRoot = projectRoot;\n }\n\n /**\n * Installs (or upgrades in place) the post-commit and post-merge blocks in the hooks directory\n * git uses, one result row per hook. A `core.hooksPath` from the global or system git config points\n * at a directory shared by every repository on the machine: nothing is written there, a warning\n * with the blocks to add by hand goes to stderr, and the result has `installed: false` and no rows.\n * A local `core.hooksPath` is honoured. `dryRun` gives the same result and warning but writes\n * nothing: no directory, no hook file, no exec bit.\n */\n installHooks(options: { readonly dryRun?: boolean } = {}): HooksInstallResult {\n const dryRun = options.dryRun === true;\n const hooksDir = resolveHooksDir(this.projectRoot);\n const sharedScope = sharedHooksScope(this.projectRoot);\n if (sharedScope) {\n console.error(sharedHooksWarning(hooksDir, sharedScope));\n return { installed: false, hooksDir, sharedScope, results: [] };\n }\n\n if (!dryRun) mkdirSync(hooksDir, { recursive: true });\n const results = GIT_HOOKS.map(({ name, content }) => this.installHook(hooksDir, name, content, dryRun));\n return { installed: true, hooksDir, results };\n }\n\n /**\n * What init would do with these options, one row per file, writing nothing: the same pipeline as a\n * real run over the parts the flags select. Without `tools` it previews every platform (D16).\n */\n plan(options: InitOptions = {}): InitResult[] {\n return this.applyParts(resolveInitParts(options), selectedTools(options), true, declinedBy(options));\n }\n\n async run(options: InitOptions = {}): Promise<void> {\n if (!existsSync(join(this.projectRoot, '.git'))) {\n console.error('[ctxo] Not a git repository. Run \"git init\" first.');\n process.exit(1);\n }\n\n if (options.rulesOnly) console.error(RULES_DEPRECATION_NOTICE);\n\n // The plugin step is not a part (D9), so `--skip` of every part can still leave it; a dry run never installs plugins.\n const parts = resolveInitParts(options);\n if (parts.size === 0 && (options.dryRun || !pluginStepEnabled(options))) {\n console.error(NOTHING_TO_INSTALL_NOTICE);\n return;\n }\n\n if (options.dryRun) return this.dryRun(options);\n if (options.yes || options.tools) return await this.runNonInteractive(options, parts);\n return this.runInteractive(options, parts);\n }\n\n /* ---------------------------------------------------------------- */\n /* The parts pipeline */\n /* ---------------------------------------------------------------- */\n\n /**\n * Installs the selected parts in one fixed order: config, skills, guard, rules, MCP, git hooks.\n * Skills and the guard go first so each platform's rules tier is resolved from what is on disk after\n * them, and so `rulesHold` can see whether a block that expects them must wait (for a file under\n * any of its linked names, `rulesFileHoldReasons`). A part not in the\n * set adds no row. Bundled skills that cannot be read become a warning row, and the other parts\n * still run. `dryRun` gives the same rows and writes nothing; the rules tier and the hold then count\n * the skills and guard it would install as present. `declined` is what the user declined in this run.\n */\n private applyParts(\n parts: ReadonlySet<InitPart>,\n toolIds: readonly string[],\n dryRun: boolean,\n declined: Pick<RulesHoldOptions, 'noGuard' | 'skipSkills'>,\n ): InitResult[] {\n const root = this.projectRoot;\n const write = { dryRun };\n const results: InitResult[] = [];\n\n if (parts.has('config')) {\n results.push(ensureIndexDir(root, write), ensureConfig(root, write), ensureGitignore(root, write));\n }\n\n /**\n * The platforms whose skills step leaves every skill in place: no error, and no warning other than\n * a skill from a newer ctxo (a skill path that is a directory stays missing, so it does not count).\n */\n const skillsDone = new Set<string>();\n if (parts.has('skills')) {\n for (const id of toolIds) {\n try {\n const skillResults = installSkills(root, id, write);\n results.push(...skillResults);\n if (skillInstallWarnings(root, id, skillResults).problems.length === 0) skillsDone.add(id);\n } catch (err) {\n // Only the warning is printed; the platform id stands in for the skill files it names.\n results.push({ file: id, action: 'skipped', warning: `skills for ${id} not installed: ${(err as Error).message}` });\n }\n }\n }\n\n let guard = false;\n if (parts.has('guard') && toolIds.includes('claude-code')) {\n const result = ensureClaudeHook(root, write);\n results.push(result);\n guard = result.warning === undefined;\n }\n\n if (parts.has('rules')) {\n // Read once per run, so an invalid config warns once, not once per platform.\n const gate = gateEnabled(root);\n // A real run reads the tier from disk after the skills and guard steps; a dry run counts what it would install.\n const planned = dryRun ? { guard, skills: skillsDone.has('claude-code') } : {};\n const holdOptions = (platformId: string): RulesHoldOptions => ({\n ...declined,\n gateEnabled: gate,\n ...(dryRun ? { planned: { guard, skills: skillsDone.has(platformId) } } : {}),\n });\n /** Dry run only: the content each planned rules file would have, so a linked name is planned against it. */\n const plannedContent = new Map<string, string>();\n for (const id of toolIds) {\n // A file linked to a held one (an AGENTS.md that is CLAUDE.md) is held too: a write would go through the link.\n if (rulesFileHoldReasons(root, id, holdOptions) !== undefined) {\n results.push(...this.heldRows(id));\n continue;\n }\n const tier = this.rulesTier(id, planned, gate);\n if (!dryRun) {\n results.push(installRules(root, id, { tier }));\n continue;\n }\n // The real run reads a linked name after the earlier name's write landed; plan it against that content.\n const sibling = linkedRulesPlatforms(root, id).find((other) => plannedContent.has(other));\n const existing = sibling !== undefined ? plannedContent.get(sibling) : undefined;\n const plan = planRules(root, id, { tier, ...(existing !== undefined ? { existing } : {}) });\n if (plan.content !== undefined) plannedContent.set(id, plan.content);\n results.push(plan.result);\n }\n }\n\n if (parts.has('mcp')) {\n for (const target of getMcpConfigTargets([...toolIds])) results.push(ensureMcpConfig(root, target, write));\n }\n\n if (parts.has('git-hooks')) {\n const hooks = this.installHooks(write);\n results.push(...hooks.results.map((result): InitResult => ({ ...result, gitHook: true })));\n if (!hooks.installed) {\n // installHooks printed the full warning; this row keeps the skip in the summary.\n results.push({ file: displayPath(root, hooks.hooksDir), action: 'skipped', warning: SHARED_HOOKS_SKIPPED });\n }\n }\n\n return results;\n }\n\n /**\n * The rows for a rules file that `rulesHold` keeps back: the held row, then the warning a write\n * would have given (a damaged block or one from a newer ctxo, read by a dry run that writes nothing).\n */\n private heldRows(platformId: string): InitResult[] {\n const file = PLATFORMS.find((p) => p.id === platformId)?.file ?? platformId;\n const probe = installRules(this.projectRoot, platformId, { dryRun: true });\n const held: InitResult = { file, action: 'skipped', warning: heldWarning(file), held: true };\n return probe.warning !== undefined ? [held, probe] : [held];\n }\n\n /** The platform's rules tier; `full` when it cannot be resolved (the bundled skills cannot be read). */\n private rulesTier(\n platformId: string,\n planned: { readonly guard?: boolean; readonly skills?: boolean },\n gate: boolean,\n ): RulesTier {\n try {\n return resolveRulesTier(this.projectRoot, platformId, planned, { gateEnabled: gate });\n } catch {\n return 'full';\n }\n }\n\n /** Detected languages whose official plugin is not installed. */\n private missingPlugins(): KnownLanguage[] {\n return resolveInstalledPlugins(decideNeededLanguages(detectLanguages(this.projectRoot))).missing;\n }\n\n /* ---------------------------------------------------------------- */\n /* Interactive flow */\n /* ---------------------------------------------------------------- */\n\n private async runInteractive(options: InitOptions, selected: ReadonlySet<InitPart>): Promise<void> {\n const clack = await import('@clack/prompts');\n const pc = (await import('picocolors')).default;\n\n const version = await this.getVersion();\n const parts = new Set(selected);\n\n // A step is shown only for a selected part, and the counter counts only the steps shown. The\n // plugin lookup runs up front so its step can be counted.\n const missingPlugins = pluginStepEnabled(options) ? this.missingPlugins() : [];\n const showIndex = parts.has('config');\n const showTools = TOOL_PARTS.some((part) => parts.has(part));\n const showPlugins = missingPlugins.length > 0;\n const showHooks = parts.has('git-hooks');\n const totalSteps = [showIndex, showTools, showPlugins, showHooks].filter(Boolean).length;\n let stepNum = 0;\n\n // ── Banner ──\n console.error('');\n console.error(renderBanner(version, pc));\n console.error('');\n\n // ── Index directory (config) ──\n if (showIndex) {\n stepNum++;\n console.error(stepHeader(stepNum, totalSteps, 'Index Directory', 'Where ctxo stores the symbol graph and metadata.', pc));\n console.error('');\n console.error(` ${pc.bold('.ctxo/index/')} ${pc.dim('fixed location')}`);\n console.error('');\n }\n\n // ── AI tool selection (rules, skills, guard, mcp) ──\n let toolIds: string[] = [];\n if (showTools) {\n stepNum++;\n const detected = detectPlatforms(this.projectRoot);\n const detectedCount = detected.size;\n const detectedHint = detectedCount > 0 ? pc.green(` ${detectedCount} detected`) : '';\n\n console.error(stepHeader(stepNum, totalSteps, `AI Tools${detectedHint}`, 'Select your tools. Generates MCP usage rules for each.', pc));\n console.error('');\n\n const toolChoices = PLATFORMS.map(p => {\n const isDetected = detected.has(p.id);\n const star = p.starred ? pc.yellow(' \\u2605') : '';\n const detect = isDetected ? pc.green(' (detected)') : '';\n return {\n value: p.id,\n label: `${p.name}${star}${detect}`,\n hint: isDetected ? undefined : pc.dim(p.file),\n };\n });\n\n const selectedTools = await clack.multiselect({\n message: pc.cyan('Select tools'),\n options: toolChoices,\n initialValues: [...detected],\n required: false,\n });\n\n if (clack.isCancel(selectedTools)) { clack.cancel('Setup cancelled.'); process.exit(0); }\n toolIds = selectedTools as string[];\n console.error('');\n }\n\n // ── Language plugins (not a part; skipped by --only, --rules and --no-install) ──\n let pluginsToInstall: KnownLanguage[] = [];\n if (showPlugins) {\n stepNum++;\n console.error(stepHeader(\n stepNum,\n totalSteps,\n `Language Plugins ${pc.yellow('missing')}`,\n `Detected: ${missingPlugins.join(', ')}; ctxo needs a plugin per language to index it.`,\n pc,\n ));\n console.error('');\n const confirm = await clack.confirm({\n message: pc.cyan(`Install ${[...new Set(missingPlugins.map(officialPluginFor))].join(' ')}?`),\n initialValue: true,\n });\n if (clack.isCancel(confirm)) { clack.cancel('Setup cancelled.'); process.exit(0); }\n if (confirm) pluginsToInstall = missingPlugins;\n console.error('');\n }\n\n // ── Git hooks ──\n if (showHooks) {\n stepNum++;\n console.error(stepHeader(\n stepNum,\n totalSteps,\n `Git Hooks ${pc.yellow('recommended')}`,\n 'Auto-updates index and community snapshots on every commit and pull.\\n Without hooks, architectural drift & boundary violation signals stay empty\\n until you re-run `ctxo index` manually (or start `ctxo watch`).',\n pc,\n ));\n console.error('');\n\n const hooks = await clack.confirm({\n message: pc.cyan('Install hooks?'),\n initialValue: true,\n });\n\n if (clack.isCancel(hooks)) { clack.cancel('Setup cancelled.'); process.exit(0); }\n\n if (!hooks) {\n parts.delete('git-hooks');\n console.error('');\n console.error(pc.yellow(' ⚠ Drift & boundary-violation signals depend on repeated snapshots.'));\n console.error(pc.dim(' Options without hooks:'));\n console.error(pc.dim(' • run `ctxo watch` during development'));\n console.error(pc.dim(' • run `ctxo index --commit HEAD` after each commit (`ctxo index --check` only verifies staleness and records no snapshot)'));\n console.error(pc.dim(' • run `ctxo init` again to install hooks later'));\n }\n console.error('');\n }\n\n // ── Guard question (Claude Code only); answering no declines the guard, as --no-guard does ──\n const declined = declinedBy(options);\n if (parts.has('guard') && toolIds.includes('claude-code') && !options.noGuard) {\n const guard = await clack.confirm({\n message: pc.cyan('Install the safe-edit guard? Blocks edits to high-impact symbols until blast radius is checked.'),\n initialValue: true,\n });\n if (clack.isCancel(guard)) { clack.cancel('Setup cancelled.'); process.exit(0); }\n if (!guard) {\n parts.delete('guard');\n declined.noGuard = true;\n }\n }\n\n // ── Execute with spinner ──\n const s = clack.spinner();\n s.start(pc.dim('Configuring...'));\n\n const rows = this.applyParts(parts, toolIds, false, declined).map((result) => summaryRow(result, pc));\n\n if (pluginsToInstall.length > 0) {\n s.stop(pc.dim('Installing language plugins...'));\n const installer = new InstallCommand(this.projectRoot);\n await installer.run({ languages: pluginsToInstall, yes: true });\n rows.push(`${pc.green('\\u2713')} ${pc.bold([...new Set(pluginsToInstall.map(officialPluginFor))].join(', '))} ${pc.dim('language plugins installed')}`);\n s.start(pc.dim('Finalizing...'));\n }\n\n s.stop(pc.green('Done!'));\n\n // ── Summary box ──\n if (rows.length > 0) {\n console.error('');\n console.error(box(rows, { title: pc.green('\\u2713 Summary'), border: pc.green }, pc));\n }\n\n // ── Next steps box ──\n const hasWork = toolIds.length > 0 || parts.has('git-hooks');\n if (hasWork) {\n const steps = [\n `${pc.cyan('\\u25b6')} ctxo index ${pc.dim('\\u2500 build codebase index')}`,\n `${pc.cyan('\\u25b6')} ctxo doctor ${pc.dim('\\u2500 verify everything works')}`,\n ];\n console.error('');\n console.error(box(steps, { title: pc.cyan('\\u2192 Next steps'), border: pc.cyan }, pc));\n }\n\n console.error('');\n console.error(` ${pc.dim('Happy coding!')} ${pc.magentaBright('\\u2764')}`);\n console.error('');\n }\n\n /* ---------------------------------------------------------------- */\n /* Non-interactive flow */\n /* ---------------------------------------------------------------- */\n\n private async runNonInteractive(options: InitOptions, parts: ReadonlySet<InitPart>): Promise<void> {\n const toolIds = selectedTools(options);\n exitOnUnknownTools(toolIds);\n\n for (const result of this.applyParts(parts, toolIds, false, declinedBy(options))) console.error(formatResultLine(result));\n\n // Language detection + plugin install (not a part: skipped by --only, --rules and --no-install)\n if (pluginStepEnabled(options)) {\n const missing = this.missingPlugins();\n if (missing.length > 0) {\n if (options.yes) {\n console.error(`[ctxo] Installing missing plugins: ${missing.join(', ')}`);\n await new InstallCommand(this.projectRoot).run({ languages: missing, yes: true });\n } else {\n console.error(\n `[ctxo] Detected missing plugins: ${missing.join(', ')}. Run \"ctxo install ${missing.join(' ')}\" to install.`,\n );\n }\n }\n }\n }\n\n /* ---------------------------------------------------------------- */\n /* Dry run */\n /* ---------------------------------------------------------------- */\n\n /**\n * Prints `plan(options)`: the header, then one row per file and one line per warning. A shared\n * hooks directory prints installHooks' warning and no hook rows, as a real run does. The hook rows\n * come marked from the pipeline, so the hooks directory is looked up only when git-hooks is selected.\n */\n private dryRun(options: InitOptions): void {\n exitOnUnknownTools(selectedTools(options));\n\n console.error(DRY_RUN_HEADER);\n for (const result of this.plan(options)) console.error(formatPlanLine(result));\n }\n\n /* ---------------------------------------------------------------- */\n /* Helpers */\n /* ---------------------------------------------------------------- */\n\n private async getVersion(): Promise<string | undefined> {\n try {\n const pkgPath = join(this.projectRoot, 'node_modules', '@ctxo', 'cli', 'package.json');\n if (existsSync(pkgPath)) {\n return JSON.parse(readFileSync(pkgPath, 'utf-8')).version;\n }\n const { createRequire } = await import('node:module');\n const require = createRequire(import.meta.url);\n return require('../../package.json').version;\n } catch {\n return undefined;\n }\n }\n\n /**\n * Upserts one hook's ctxo block. The action compares the old and the new text: a missing file is\n * `created`, a changed one `updated`, an equal one `skipped` and not rewritten. `dryRun` computes\n * the same action and touches nothing, not even the exec bit.\n *\n * The hook is read once, with no existence check before it (a check followed by a read is a race\n * on the same path): `ENOENT` means there is no hook yet, and any other read error (a directory,\n * no permission) is thrown to the caller.\n */\n private installHook(hooksDir: string, hookName: string, hookContent: string, dryRun: boolean): InstallResult {\n const hookPath = join(hooksDir, hookName);\n const file = displayPath(this.projectRoot, hookPath);\n\n let existing = '#!/bin/sh\\n';\n let hookExists = true;\n try {\n existing = readFileSync(hookPath, 'utf-8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n hookExists = false;\n }\n const updated = upsertCtxoBlock(existing, hookContent);\n\n if (!hookExists || updated !== existing) {\n if (!dryRun) {\n writeFileSync(hookPath, updated, 'utf-8');\n chmodSync(hookPath, 0o755);\n }\n return { file, action: hookExists ? 'updated' : 'created' };\n }\n\n // Content is already current. A hook that lost its exec bit (copied, restored from a backup)\n // would silently stop firing, so restore it; failing init over a file we cannot chmod would not help.\n if (!dryRun) {\n try {\n chmodSync(hookPath, 0o755);\n } catch {\n // best effort\n }\n }\n return { file, action: 'skipped' };\n }\n}\n","/**\n * Platform configurations and MCP tool usage rule generator.\n *\n * Each platform entry defines where the AI coding assistant reads its\n * project-level instructions; ctxo upserts one marked rules block into that file.\n */\n\nimport { existsSync, readFileSync, realpathSync, writeFileSync, mkdirSync, statSync } from 'node:fs';\nimport { join, dirname, relative, sep } from 'node:path';\nimport {\n LEGACY_CURSOR_FRONTMATTER,\n SKILLS_TEMPLATE_VERSION,\n compareTemplateVersions,\n expectedRulesTier,\n comparableMarkdown,\n guardAndSkillsExpected,\n renderRulesBlock,\n scanRulesBlocks,\n skillTemplateVersion,\n textShape,\n upsertRulesBlock,\n type RulesBlockSpan,\n type RulesScan,\n type RulesTier,\n type TextShape,\n} from '../core/agent-rules/rules-block.js';\nimport { loadConfig } from '../core/config/load-config.js';\n\n/* ------------------------------------------------------------------ */\n/* Claude Code safe-edit gate hook */\n/* ------------------------------------------------------------------ */\n\nconst CTXO_HOOK_COMMAND = 'ctxo gate-hook';\nconst CLAUDE_SETTINGS_FILE = '.claude/settings.json';\nconst UNREADABLE_SETTINGS_WARNING =\n `${CLAUDE_SETTINGS_FILE} is not valid JSON or not a settings object; left unchanged. Fix it, then run \"ctxo init --only rules,skills,guard\".`;\n\n/** Whether the safe-edit guard is registered: `unreadable` means `.claude/settings.json` cannot be read safely. */\nexport type ClaudeGuardState = 'present' | 'absent' | 'unreadable';\n\ntype SettingsRead =\n | { readonly kind: 'missing' }\n | { readonly kind: 'unreadable' }\n | { readonly kind: 'ok'; readonly json: Record<string, unknown>; readonly hasHook: boolean; readonly shape: TextShape };\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\n/**\n * Reads a Claude Code settings file; a leading UTF-8 BOM and CRLF line endings are kept in `shape`, so\n * a rewrite restores them (D2). `unreadable` covers text that fails `JSON.parse` (JSONC comments\n * included) and JSON that is not a plain object, has a `hooks` that is not a plain object, a\n * `hooks.PreToolUse` that is not an array, or a `PreToolUse` entry that is not a plain object with a\n * `hooks` array. The guard counts wherever its own entry is well formed: a file that registers it is\n * `ok` with `hasHook` even next to a malformed entry, because ctxo never writes a file with the guard.\n */\nfunction readSettings(path: string): SettingsRead {\n if (!existsSync(path)) return { kind: 'missing' };\n let json: unknown;\n let shape: TextShape;\n try {\n shape = textShape(readFileSync(path, 'utf-8'));\n json = JSON.parse(shape.text);\n } catch {\n return { kind: 'unreadable' };\n }\n if (!isPlainObject(json)) return { kind: 'unreadable' };\n if (json.hooks === undefined) return { kind: 'ok', json, hasHook: false, shape };\n if (!isPlainObject(json.hooks)) return { kind: 'unreadable' };\n const pre = json.hooks.PreToolUse;\n if (pre === undefined) return { kind: 'ok', json, hasHook: false, shape };\n if (!Array.isArray(pre)) return { kind: 'unreadable' };\n const wellFormed = (pre as unknown[]).filter(\n (entry): entry is { hooks: unknown[] } => isPlainObject(entry) && Array.isArray(entry.hooks),\n );\n const hasHook = wellFormed.some((entry) => entry.hooks.some((h) => isPlainObject(h) && h.command === CTXO_HOOK_COMMAND));\n if (!hasHook && wellFormed.length !== pre.length) return { kind: 'unreadable' };\n return { kind: 'ok', json, hasHook, shape };\n}\n\n/** The shared settings file and whether the guard is registered there or in the local one (read only, D11). */\nfunction guardRegistration(projectRoot: string): { readonly shared: SettingsRead; readonly state: ClaudeGuardState } {\n const shared = readSettings(join(projectRoot, '.claude', 'settings.json'));\n const local = readSettings(join(projectRoot, '.claude', 'settings.local.json'));\n if ((shared.kind === 'ok' && shared.hasHook) || (local.kind === 'ok' && local.hasHook)) {\n return { shared, state: 'present' };\n }\n return { shared, state: shared.kind === 'unreadable' ? 'unreadable' : 'absent' };\n}\n\n/**\n * Whether the safe-edit guard hook is registered in `.claude/settings.json` or\n * `.claude/settings.local.json`. `unreadable`: the shared file exists but cannot be read safely and\n * the local file does not register the guard.\n */\nexport function readClaudeGuardState(projectRoot: string): ClaudeGuardState {\n return guardRegistration(projectRoot).state;\n}\n\n/** A platform's rules file and the ctxo blocks found in it. */\nexport interface PlatformRulesState {\n readonly platformId: string;\n /** Project-relative, forward slashes */\n readonly file: string;\n readonly scan: RulesScan;\n}\n\n/**\n * The scan of one platform's rules file, or `undefined` when there is no such file: nothing at the\n * path (`ENOENT`) or a directory in its place (`EISDIR`). Any other read error is thrown. The file is\n * read once, with no check first, so the answer cannot go stale between a check and the read.\n */\nfunction platformRulesState(projectRoot: string, platform: Platform): PlatformRulesState | undefined {\n const path = join(projectRoot, platform.file);\n let text: string;\n try {\n text = readFileSync(path, 'utf-8');\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'ENOENT' || code === 'EISDIR') return undefined;\n throw err;\n }\n return { platformId: platform.id, file: platform.file, scan: scanRulesBlocks(text) };\n}\n\n/**\n * The scan of every platform whose rules file exists, in PLATFORMS order. Platforms whose rules files\n * are one file on disk (`linkedRulesPlatforms`) give one entry, under the first of them.\n */\nexport function readRulesStates(projectRoot: string): PlatformRulesState[] {\n const states: PlatformRulesState[] = [];\n const covered = new Set<string>();\n for (const platform of PLATFORMS) {\n if (covered.has(platform.id)) continue;\n const state = platformRulesState(projectRoot, platform);\n if (!state) continue;\n for (const id of linkedRulesPlatforms(projectRoot, platform.id)) covered.add(id);\n states.push(state);\n }\n return states;\n}\n\n/**\n * Whether two existing paths are one file on disk: the same real path (a symlink), or the same device\n * and inode (a hard link, which has a real path of its own). Both are checked.\n */\nfunction sameFileOnDisk(a: string, b: string): boolean {\n try {\n if (realpathSync(a) === realpathSync(b)) return true;\n const sa = statSync(a, { bigint: true });\n const sb = statSync(b, { bigint: true });\n return sa.ino !== 0n && sa.dev === sb.dev && sa.ino === sb.ino;\n } catch {\n return false;\n }\n}\n\n/**\n * The other platforms whose rules file is the same file on disk as this platform's, in PLATFORMS\n * order: for example an AGENTS.md or GEMINI.md linked to CLAUDE.md. `[]` when the file does not exist.\n * Such a file serves several clients, so the writer and doctor both give it the full tier.\n */\nexport function linkedRulesPlatforms(projectRoot: string, platformId: string): string[] {\n const platform = PLATFORMS.find((p) => p.id === platformId);\n const path = platform ? join(projectRoot, platform.file) : undefined;\n if (!path || !existsSync(path)) return [];\n return PLATFORMS.filter((other) => {\n if (other.id === platformId) return false;\n const otherPath = join(projectRoot, other.file);\n return existsSync(otherPath) && sameFileOnDisk(path, otherPath);\n }).map((other) => other.id);\n}\n\n/** The first ctxo block in a platform's rules file; undefined without the file or a block. */\nfunction firstRulesBlock(projectRoot: string, platformId: string): RulesBlockSpan | undefined {\n const platform = PLATFORMS.find((p) => p.id === platformId);\n return platform ? platformRulesState(projectRoot, platform)?.scan.blocks[0] : undefined;\n}\n\n/**\n * Whether the safe-edit guard should be registered: CLAUDE.md's first block is pre-tier or compact\n * (a versioned full block records an opt-out, D5) and `gate.enabled` is not false.\n */\nexport function guardExpected(projectRoot: string): boolean {\n return guardAndSkillsExpected(firstRulesBlock(projectRoot, 'claude-code')) && gateEnabled(projectRoot);\n}\n\n/**\n * Whether the platform's skills should all be installed: one ctxo skill is already there, or its rules\n * block is pre-tier or compact. Always false for a platform without skills. Throws like `skillStates`\n * when the bundled skills cannot be found.\n */\nexport function skillsExpected(projectRoot: string, platformId: string): boolean {\n if (!skillTarget(platformId)) return false;\n return (\n skillStates(projectRoot, platformId).some((s) => s.state !== 'missing') ||\n guardAndSkillsExpected(firstRulesBlock(projectRoot, platformId))\n );\n}\n\n/** What a run declined, for `rulesHold`. Config opt-outs (`gate.enabled: false`) are read from disk. */\nexport interface RulesHoldOptions {\n /** `--no-guard`, or the guard question answered no: the guard is not waited for. */\n readonly noGuard?: boolean;\n /** `--skip skills`: the skills are not waited for. */\n readonly skipSkills?: boolean;\n /** A dry run: the guard and this platform's skills that the run would install count as on disk. */\n readonly planned?: { readonly guard?: boolean; readonly skills?: boolean };\n /** `gate.enabled` as this run already read it; read from `.ctxo/config.yaml` when absent. */\n readonly gateEnabled?: boolean;\n}\n\n/** What a held rules file waits for; see `rulesHold`. */\nexport interface RulesHoldReasons {\n /** The guard is expected and not registered; `unreadable`: `.claude/settings.json` cannot be read safely. */\n readonly guard?: 'absent' | 'unreadable';\n /** The expected skills that are not on disk, or not readable as a file. */\n readonly missingSkills?: readonly string[];\n /** The expected skills on disk that differ from the bundled copy; like missing ones, they do not back the compact tier. */\n readonly outdatedSkills?: readonly string[];\n /** The bundled skills cannot be read, so the installed ones cannot be checked; they count as not on disk. */\n readonly skillsError?: string;\n}\n\n/** Whether a skill backs the compact tier: its file is readable and current (or from a newer ctxo). */\nfunction skillInPlace(state: SkillState): boolean {\n return state.state === 'current' || state.state === 'newer';\n}\n\n/**\n * Why a platform's rules block must be left unchanged, or undefined when it may be written; see\n * `rulesHold`. A rules file that cannot be read is never held: the writer then leaves it unchanged\n * with its `could not be read` warning, and the run goes on.\n */\nexport function rulesHoldReasons(\n projectRoot: string,\n platformId: string,\n options: RulesHoldOptions = {},\n): RulesHoldReasons | undefined {\n if (!(SKILL_PLATFORMS as readonly string[]).includes(platformId)) return undefined;\n let first: RulesBlockSpan | undefined;\n try {\n first = firstRulesBlock(projectRoot, platformId);\n } catch {\n return undefined;\n }\n if (!guardAndSkillsExpected(first)) return undefined;\n\n let guard: RulesHoldReasons['guard'];\n if (\n platformId === 'claude-code' &&\n !options.noGuard &&\n options.planned?.guard !== true &&\n (options.gateEnabled ?? gateEnabled(projectRoot))\n ) {\n const state = readClaudeGuardState(projectRoot);\n if (state !== 'present') guard = state;\n }\n let missingSkills: string[] | undefined;\n let outdatedSkills: string[] | undefined;\n let skillsError: string | undefined;\n if (!options.skipSkills && options.planned?.skills !== true) {\n try {\n const states = skillStates(projectRoot, platformId);\n const missing = states.filter((s) => s.state === 'missing').map((s) => s.skill);\n const outdated = states.filter((s) => s.state === 'outdated').map((s) => s.skill);\n if (missing.length > 0) missingSkills = missing;\n if (outdated.length > 0) outdatedSkills = outdated;\n } catch (err) {\n skillsError = (err as Error).message;\n }\n }\n\n if (guard === undefined && missingSkills === undefined && outdatedSkills === undefined && skillsError === undefined) {\n return undefined;\n }\n return {\n ...(guard !== undefined ? { guard } : {}),\n ...(missingSkills !== undefined ? { missingSkills } : {}),\n ...(outdatedSkills !== undefined ? { outdatedSkills } : {}),\n ...(skillsError !== undefined ? { skillsError } : {}),\n };\n}\n\n/**\n * The one rule against a silent opt-out (D5): whether the writers must leave this platform's rules\n * block unchanged. A versioned full block records that the user declined the guard and the skills,\n * so writing one where nobody declined them would hide the missing pieces for good. True for Claude\n * Code and Cursor (the platforms with skills) when all of these hold:\n *\n * 1. the rules file has a ctxo block that expects the guard and the skills: pre-tier (unversioned or\n * legacy) or compact;\n * 2. the user has not declined them: the guard counts unless `noGuard` or `gate.enabled: false`, the\n * skills unless `skipSkills` (Cursor has no guard);\n * 3. what counts is still not on disk, read after the run's skills and guard steps (`planned` stands\n * in for them in a dry run). An unreadable `.claude/settings.json` is not on disk, and neither are\n * skills that cannot be checked. A skill counts as on disk only when it is readable and current,\n * the same test `resolveRulesTier` applies, so a held block is never one the tier would turn full.\n *\n * A file without a ctxo block is never held. Used by init (the real run and the dry run, so also by\n * `--only rules` and `--rules`) and by `doctor --fix`.\n */\nexport function rulesHold(projectRoot: string, platformId: string, options: RulesHoldOptions = {}): boolean {\n return rulesHoldReasons(projectRoot, platformId, options) !== undefined;\n}\n\n/**\n * `rulesHoldReasons` for a rules file that may be several platforms' file (`linkedRulesPlatforms`):\n * the platform's own reasons, else those of the first platform linked to it that is held. A write\n * under any name of the file reaches the held block (an AGENTS.md linked to a held CLAUDE.md would\n * record the opt-out through the link), so every name waits. `optionsFor` gives each platform's\n * options, because a dry run plans the skills per platform. Init, the dry run and `doctor --fix` use it.\n */\nexport function rulesFileHoldReasons(\n projectRoot: string,\n platformId: string,\n optionsFor: (platformId: string) => RulesHoldOptions = () => ({}),\n): RulesHoldReasons | undefined {\n for (const id of [platformId, ...linkedRulesPlatforms(projectRoot, platformId)]) {\n const reasons = rulesHoldReasons(projectRoot, id, optionsFor(id));\n if (reasons) return reasons;\n }\n return undefined;\n}\n\n/**\n * Registers the safe-edit guard under `hooks.PreToolUse` in `.claude/settings.json`. A guard already\n * registered there or in `.claude/settings.local.json` is `skipped`. An unreadable settings file is\n * never overwritten: `skipped` with a warning. Every other setting and hook is kept, the entry goes\n * last, and the file's UTF-8 BOM and line endings are written back (D2). `dryRun` computes the same\n * action and writes nothing, not even a directory.\n */\nexport function ensureClaudeHook(projectRoot: string, options: { readonly dryRun?: boolean } = {}): InstallResult {\n const filePath = join(projectRoot, '.claude', 'settings.json');\n const ctxoEntry = { matcher: 'Edit', hooks: [{ type: 'command', command: CTXO_HOOK_COMMAND }] };\n const { shared, state } = guardRegistration(projectRoot);\n\n if (state === 'present') return { file: CLAUDE_SETTINGS_FILE, action: 'skipped' };\n if (shared.kind === 'unreadable') {\n return { file: CLAUDE_SETTINGS_FILE, action: 'skipped', warning: UNREADABLE_SETTINGS_WARNING };\n }\n\n if (shared.kind === 'missing') {\n if (!options.dryRun) {\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify({ hooks: { PreToolUse: [ctxoEntry] } }, null, 2) + '\\n', 'utf-8');\n }\n return { file: CLAUDE_SETTINGS_FILE, action: 'created' };\n }\n\n const hooks = isPlainObject(shared.json.hooks) ? shared.json.hooks : {};\n const pre = Array.isArray(hooks.PreToolUse) ? (hooks.PreToolUse as unknown[]) : [];\n const updated = { ...shared.json, hooks: { ...hooks, PreToolUse: [...pre, ctxoEntry] } };\n const body = JSON.stringify(updated, null, 2) + '\\n';\n if (!options.dryRun) writeFileSync(filePath, shared.shape.restore(body), 'utf-8');\n return { file: CLAUDE_SETTINGS_FILE, action: 'updated' };\n}\n\n/** `gate.enabled` from `.ctxo/config.yaml`; a missing or invalid config counts as enabled. */\nexport function gateEnabled(projectRoot: string): boolean {\n return loadConfig(join(projectRoot, '.ctxo')).config.gate?.enabled !== false;\n}\n\n/**\n * The rules tier for a platform from what is on disk. `planned` counts a guard or skills that a dry\n * run would install as present. A skill counts only when its file is readable and current (or from a\n * newer ctxo): a missing one, a path that is not a readable file and an outdated copy do not back the\n * compact tier. A rules file linked to another platform's (`linkedRulesPlatforms`) gets the full tier.\n * Only Claude Code can get the compact tier, so every other platform is `full` without a disk read.\n * `known.gateEnabled` is the `gate.enabled` value this run already read (read from config when absent).\n */\nexport function resolveRulesTier(\n projectRoot: string,\n platformId: string,\n planned: { readonly guard?: boolean; readonly skills?: boolean } = {},\n known: { readonly gateEnabled?: boolean } = {},\n): RulesTier {\n if (platformId !== 'claude-code') return 'full';\n const guardPresent = planned.guard === true || readClaudeGuardState(projectRoot) === 'present';\n const skillsComplete = planned.skills === true || skillStates(projectRoot, 'claude-code').every(skillInPlace);\n const sharedFile = linkedRulesPlatforms(projectRoot, platformId).length > 0;\n const gate = known.gateEnabled ?? gateEnabled(projectRoot);\n return expectedRulesTier(platformId, { guardPresent, skillsComplete, gateEnabled: gate, sharedFile });\n}\n\nexport interface Platform {\n id: string;\n name: string;\n /** The rules file, project-relative with forward slashes; ctxo upserts a marked block into it */\n file: string;\n /** Paths to check for auto-detection (relative to project root) */\n detectPaths: string[];\n /** Show a star next to this platform name */\n starred: boolean;\n}\n\nexport const PLATFORMS: Platform[] = [\n { id: 'claude-code', name: 'Claude Code', file: 'CLAUDE.md', detectPaths: ['CLAUDE.md', '.claude'], starred: true },\n { id: 'cursor', name: 'Cursor', file: '.cursor/rules/ctxo.mdc', detectPaths: ['.cursor', '.cursorrules'], starred: false },\n { id: 'github-copilot', name: 'GitHub Copilot', file: '.github/copilot-instructions.md', detectPaths: ['.github', '.vscode'], starred: false },\n { id: 'windsurf', name: 'Windsurf', file: '.windsurfrules', detectPaths: ['.windsurfrules', '.windsurf'], starred: false },\n { id: 'antigravity', name: 'Google Antigravity', file: 'AGENTS.md', detectPaths: ['AGENTS.md', 'GEMINI.md', '.gemini'], starred: false },\n { id: 'augment', name: 'Augment Code', file: 'augment-guidelines.md', detectPaths: ['augment-guidelines.md', '.augment'], starred: false },\n { id: 'amazonq', name: 'Amazon Q', file: '.amazonq/rules/ctxo.md', detectPaths: ['.amazonq'], starred: false },\n { id: 'gemini-cli', name: 'Gemini CLI', file: 'GEMINI.md', detectPaths: ['.gemini/settings.json', 'GEMINI.md'], starred: false },\n { id: 'continue', name: 'Continue', file: '.continue/rules/ctxo.md', detectPaths: ['.continue'], starred: false },\n];\n\nexport function detectPlatforms(projectRoot: string): Set<string> {\n const detected = new Set<string>();\n for (const p of PLATFORMS) {\n if (p.detectPaths.some(d => existsSync(join(projectRoot, d)))) {\n detected.add(p.id);\n }\n }\n return detected;\n}\n\n/* ------------------------------------------------------------------ */\n/* Rule content */\n/* ------------------------------------------------------------------ */\n\n/** The frontmatter of a new Cursor rules file; LEGACY_CURSOR_FRONTMATTER is the one it replaces. */\nconst CURSOR_FRONTMATTER = `---\ndescription: ctxo MCP tool usage rules, always applied\nglobs:\nalwaysApply: true\n---\n\n`;\n\n/** The content of a new rules file: the marked block (after the frontmatter for Cursor). */\nexport function generateRules(platformId: string, tier: RulesTier = 'full'): string {\n const block = renderRulesBlock(tier) + '\\n';\n return platformId === 'cursor' ? CURSOR_FRONTMATTER + block : block;\n}\n\n/**\n * Swaps a leading LEGACY_CURSOR_FRONTMATTER for CURSOR_FRONTMATTER. The swapped lines keep their\n * BOM and line endings; anything else is returned as it is.\n */\nfunction replaceLegacyCursorFrontmatter(content: string): string {\n const lineBreaks = LEGACY_CURSOR_FRONTMATTER.split('\\n').length - 1;\n let end = 0;\n for (let i = 0; i < lineBreaks; i++) {\n const next = content.indexOf('\\n', end);\n if (next < 0) return content;\n end = next + 1;\n }\n const head = textShape(content.slice(0, end));\n if (head.text !== LEGACY_CURSOR_FRONTMATTER) return content;\n return head.restore(CURSOR_FRONTMATTER) + content.slice(end);\n}\n\n/* ------------------------------------------------------------------ */\n/* File operations */\n/* ------------------------------------------------------------------ */\n\nexport interface InstallResult {\n /**\n * Project-relative, forward slashes. A git hook row from init is absolute when the hooks directory\n * is outside the project (a `core.hooksPath` elsewhere, a worktree's common git dir).\n */\n file: string;\n action: 'created' | 'updated' | 'skipped';\n /** Why a file was left unchanged although it needs attention */\n warning?: string;\n}\n\n/**\n * Upserts the ctxo rules block into a platform's rules file. A missing file gets\n * `generateRules`; an existing one keeps every byte outside the ctxo block. The action compares\n * the final content with the original: equal is `skipped`. `dryRun` computes the same action and\n * writes nothing, not even a directory. A file that is also another platform's rules file\n * (`linkedRulesPlatforms`) is written in the full tier, whatever `tier` says.\n *\n * Cursor's file also gets its frontmatter: a leading LEGACY_CURSOR_FRONTMATTER is swapped for the\n * current one (its BOM and line endings kept), and an empty or whitespace-only file is written as a\n * created one would be. Other frontmatter is left alone.\n *\n * A file that cannot be read (a directory, no permission), a damaged block (a start marker without an\n * end marker, an end marker without a start marker) and a block from a newer ctxo are `skipped` with\n * a warning and left unchanged, in a dry run too.\n */\nexport function installRules(\n projectRoot: string,\n platformId: string,\n options: { readonly tier?: RulesTier; readonly dryRun?: boolean } = {},\n): InstallResult {\n const { result, content } = planRules(projectRoot, platformId, { tier: options.tier });\n if (!options.dryRun && result.action !== 'skipped' && content !== undefined) {\n const filePath = join(projectRoot, result.file);\n if (result.action === 'created') mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, content, 'utf-8');\n }\n return result;\n}\n\n/** What `installRules` does to a rules file, and the file's content afterwards. */\nexport interface RulesPlan {\n readonly result: InstallResult;\n /** The content the file has after the write (the old content when `skipped`); absent when it is left alone with a warning. */\n readonly content?: string;\n}\n\n/**\n * `installRules` without the write: its result, and the content the file would have. `existing`\n * stands in for the file's content on disk, so a dry run that has already planned a write to the same\n * file under a linked name plans this one against what that write leaves, as a real run reads it.\n */\nexport function planRules(\n projectRoot: string,\n platformId: string,\n options: { readonly tier?: RulesTier; readonly existing?: string } = {},\n): RulesPlan {\n const platform = PLATFORMS.find(p => p.id === platformId);\n if (!platform) throw new Error(`Unknown platform: ${platformId}`);\n const file = platform.file;\n\n // A file another platform also reads gets the full tier whatever the caller asked (doctor agrees).\n const tier = linkedRulesPlatforms(projectRoot, platformId).length > 0 ? 'full' : (options.tier ?? 'full');\n const filePath = join(projectRoot, file);\n\n let existing = options.existing;\n if (existing === undefined) {\n if (!existsSync(filePath)) return { result: { file, action: 'created' }, content: generateRules(platformId, tier) };\n try {\n existing = readFileSync(filePath, 'utf-8');\n } catch (err) {\n return { result: { file, action: 'skipped', warning: unreadableWarning(file, err) } };\n }\n }\n const changed = (content: string): RulesPlan => ({\n result: { file, action: content === existing ? 'skipped' : 'updated' },\n content,\n });\n\n if (platformId === 'cursor' && textShape(existing).text.trim() === '') {\n // An empty Cursor file gets what a created one gets: the frontmatter, then the block.\n return changed(textShape(existing).restore(generateRules(platformId, tier)));\n }\n\n const upsert = upsertRulesBlock(existing, renderRulesBlock(tier));\n if (upsert.kind === 'unterminated') {\n return { result: { file, action: 'skipped', warning: `${file}: ctxo rules start marker has no end marker; left unchanged` } };\n }\n if (upsert.kind === 'orphan-end') {\n return { result: { file, action: 'skipped', warning: `${file}: ctxo rules end marker has no start marker; left unchanged` } };\n }\n if (upsert.kind === 'newer') {\n return {\n result: { file, action: 'skipped', warning: `${file}: rules block v${upsert.version} comes from a newer ctxo; left unchanged` },\n };\n }\n\n return changed(platformId === 'cursor' ? replaceLegacyCursorFrontmatter(upsert.content) : upsert.content);\n}\n\n/** The warning for a rules, skill or MCP config file ctxo could not read (a directory in its place, no permission). */\nfunction unreadableWarning(file: string, err: unknown): string {\n const code = (err as NodeJS.ErrnoException | undefined)?.code;\n const reason = code ?? (err instanceof Error ? err.message : String(err));\n return `${file}: could not be read (${reason}); left unchanged`;\n}\n\n/* ------------------------------------------------------------------ */\n/* Skills */\n/* ------------------------------------------------------------------ */\n\nexport const SKILLS = ['ctxo-understand', 'ctxo-safe-edit', 'ctxo-review-pr'] as const;\n\n/** Platforms with a markdown skill/rule directory we can drop skills into. */\nexport const SKILL_PLATFORMS = ['claude-code', 'cursor'] as const;\n\ntype SkillPlatform = (typeof SKILL_PLATFORMS)[number];\n\nconst SKILL_TARGET_DIR: Record<SkillPlatform, (root: string, skill: string) => string> = {\n 'claude-code': (root, skill) => join(root, '.claude', 'skills', skill, 'SKILL.md'),\n cursor: (root, skill) => join(root, '.cursor', 'rules', `${skill}.mdc`),\n};\n\nfunction skillTarget(platformId: string): ((root: string, skill: string) => string) | undefined {\n return (SKILL_PLATFORMS as readonly string[]).includes(platformId)\n ? SKILL_TARGET_DIR[platformId as SkillPlatform]\n : undefined;\n}\n\nfunction skillsSourceDir(): string {\n let dir = import.meta.dirname;\n for (let i = 0; i < 10; i++) {\n const candidate = join(dir, 'skills');\n if (existsSync(join(candidate, 'ctxo-safe-edit', 'SKILL.md'))) return candidate;\n const parent = join(dir, '..');\n if (parent === dir) break;\n dir = parent;\n }\n throw new Error('Could not locate ctxo skills/ directory.');\n}\n\nexport interface SkillState {\n readonly skill: (typeof SKILLS)[number];\n /** Project-relative, forward slashes */\n readonly file: string;\n /**\n * `current` also covers a copy that differs only in formatting: line endings, a UTF-8 BOM, trailing\n * whitespace, blank lines, table padding or line wrapping (`comparableMarkdown`). `newer`: the copy's\n * `<!-- ctxo-skill -->` marker is above SKILLS_TEMPLATE_VERSION (a newer ctxo wrote it); it is left\n * alone and is not outdated. A copy with no marker or an older one is `outdated`. `missing` also\n * covers a path that cannot be read as a file (such as a directory).\n */\n readonly state: 'current' | 'missing' | 'outdated' | 'newer';\n}\n\ninterface SkillPlanEntry extends SkillState {\n /** The bundled file's content and the absolute path the skill is installed at. */\n readonly bundled: string;\n readonly to: string;\n /** The installed copy's marker version; set for `newer`. */\n readonly version?: string;\n /** Set when something other than a readable file is at `to` (a directory, no permission): the warning. */\n readonly blocked?: string;\n}\n\nfunction skillPlan(projectRoot: string, platformId: string): SkillPlanEntry[] {\n const target = skillTarget(platformId);\n if (!target) return [];\n const src = skillsSourceDir();\n return SKILLS.map((skill) => {\n const bundled = readFileSync(join(src, skill, 'SKILL.md'), 'utf-8');\n const to = target(projectRoot, skill);\n const file = relative(projectRoot, to).split(sep).join('/');\n if (!existsSync(to)) return { skill, file, state: 'missing', bundled, to };\n let installed: string;\n try {\n installed = readFileSync(to, 'utf-8');\n } catch (err) {\n // Not a readable skill, so it counts as missing; installSkills warns instead of writing over it.\n return { skill, file, state: 'missing', bundled, to, blocked: unreadableWarning(file, err) };\n }\n const version = skillTemplateVersion(installed);\n if (version !== undefined && compareTemplateVersions(version, SKILLS_TEMPLATE_VERSION) > 0) {\n return { skill, file, state: 'newer', bundled, to, version };\n }\n // The bundled copy carries the current marker, so a copy without one or with an older one differs.\n const same = comparableMarkdown(installed) === comparableMarkdown(bundled);\n return { skill, file, state: same ? 'current' : 'outdated', bundled, to };\n });\n}\n\n/** Where each of the platform's skills stands against the bundled copy. `[]` for a platform without skills. */\nexport function skillStates(projectRoot: string, platformId: string): SkillState[] {\n return skillPlan(projectRoot, platformId).map(({ skill, file, state }) => ({ skill, file, state }));\n}\n\n/**\n * Copies the bundled skills into the platform's skill folder. A skill equal to the bundled one\n * (formatting ignored, see `SkillState`) is `skipped` and not rewritten; a missing one is `created`, a\n * different one `updated`. A skill from a newer ctxo, and a skill path that cannot be read (such as a\n * directory), are `skipped` with a warning and left unchanged. `dryRun` computes the same actions and\n * writes nothing, not even a directory.\n */\nexport function installSkills(\n projectRoot: string,\n platformId: string,\n options: { readonly dryRun?: boolean } = {},\n): InstallResult[] {\n return skillPlan(projectRoot, platformId).map(({ file, state, bundled, to, version, blocked }): InstallResult => {\n if (blocked !== undefined) return { file, action: 'skipped', warning: blocked };\n if (state === 'current') return { file, action: 'skipped' };\n if (state === 'newer') {\n return { file, action: 'skipped', warning: `${file}: skill v${version ?? ''} comes from a newer ctxo; left unchanged` };\n }\n if (!options.dryRun) {\n mkdirSync(dirname(to), { recursive: true });\n writeFileSync(to, bundled, 'utf-8');\n }\n return { file, action: state === 'missing' ? 'created' : 'updated' };\n });\n}\n\n/**\n * The warnings of one platform's `installSkills` run, split by what they leave on disk: a skill from\n * a newer ctxo stays in place and still backs the tier (`notices`); any other warning, such as a skill\n * path that is a directory, leaves the skill missing (`problems`). Init and `doctor --fix` read them\n * the same way, so init plans the tier only from skills that are in place.\n */\nexport function skillInstallWarnings(\n projectRoot: string,\n platformId: string,\n results: readonly InstallResult[],\n): { readonly problems: readonly string[]; readonly notices: readonly string[] } {\n const newer = new Set(skillStates(projectRoot, platformId).filter((s) => s.state === 'newer').map((s) => s.file));\n const problems: string[] = [];\n const notices: string[] = [];\n for (const result of results) {\n if (result.warning === undefined) continue;\n if (newer.has(result.file)) notices.push(result.warning);\n else problems.push(result.warning);\n }\n return { problems, notices };\n}\n\n/* ------------------------------------------------------------------ */\n/* Project scaffolding (automatic, not prompted) */\n/* ------------------------------------------------------------------ */\n\nconst GITIGNORE_ENTRY = '.ctxo/.cache/';\n\n/**\n * Creates `.ctxo/index/`, where `ctxo index` writes the committed index. An existing directory is\n * `skipped`. `dryRun` computes the same action and creates nothing.\n */\nexport function ensureIndexDir(projectRoot: string, options: { readonly dryRun?: boolean } = {}): InstallResult {\n const dir = join(projectRoot, '.ctxo', 'index');\n if (existsSync(dir)) return { file: '.ctxo/index/', action: 'skipped' };\n if (!options.dryRun) mkdirSync(dir, { recursive: true });\n return { file: '.ctxo/index/', action: 'created' };\n}\n\n/**\n * Adds the `.ctxo/.cache/` entry to `.gitignore`, creating the file when it is missing. A file that\n * already has the entry is `skipped`. `dryRun` computes the same action and writes nothing.\n * The file is read once, with no check first: `ENOENT` means it is missing, any other read error\n * (a directory in its place, no permission) is thrown.\n */\nexport function ensureGitignore(projectRoot: string, options: { readonly dryRun?: boolean } = {}): InstallResult {\n const filePath = join(projectRoot, '.gitignore');\n\n let existing: string;\n try {\n existing = readFileSync(filePath, 'utf-8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err;\n if (!options.dryRun) {\n writeFileSync(filePath, `# Ctxo local cache (auto-rebuilt, never committed)\\n${GITIGNORE_ENTRY}\\n`, 'utf-8');\n }\n return { file: '.gitignore', action: 'created' };\n }\n\n if (existing.includes(GITIGNORE_ENTRY)) {\n return { file: '.gitignore', action: 'skipped' };\n }\n\n const separator = existing.endsWith('\\n') ? '\\n' : '\\n\\n';\n const updated = existing + `${separator}# Ctxo local cache (auto-rebuilt, never committed)\\n${GITIGNORE_ENTRY}\\n`;\n if (!options.dryRun) writeFileSync(filePath, updated, 'utf-8');\n return { file: '.gitignore', action: 'updated' };\n}\n\nconst DEFAULT_CONFIG = `# ctxo project configuration\n# Docs: https://github.com/alperhankendi/Ctxo\nversion: \"1.0\"\n\n# Exclude files and workspaces from indexing.\n# Uncomment and edit to activate; both fields accept picomatch globs\n# (forward-slash paths relative to repo root).\nindex:\n # Per-file filter applied after \\`git ls-files\\`.\n ignore: []\n # - \"packages/**/fixtures/**\"\n # - \"tools/legacy-*/**\"\n\n # Workspace filter: matching workspaces are skipped entirely\n # (no plugin load, no file enumeration).\n ignoreProjects: []\n # - \"packages/experimental-*\"\n # - \"examples/*\"\n\ngate:\n enabled: true\n sensitivity: balanced # strict | balanced | lenient\n\n# Co-change analysis: which files change together (.ctxo/index/co-changes.json).\n# Every field is optional. Uncomment the block to edit it; the values shown are the defaults.\n# cochange:\n# maxCommits: 2000 # number or \"all\"\n# # since: 12m # optional age limit; d, w, m, y\n# maxFilesPerCommit: 30\n# minShared: 2\n# include: [] # extra tracked files no plugin indexes (picomatch globs)\n# exclude: [] # indexed files to leave out (picomatch globs)\n`;\n\n/**\n * Writes the default `.ctxo/config.yaml`; an existing config is `skipped` and never touched. `dryRun`\n * computes the same action and writes nothing, not even the `.ctxo/` directory.\n * The real write creates the file in one step (`wx`: fail when anything is already there) instead of\n * checking first, so an existing config cannot be overwritten between a check and the write.\n */\nexport function ensureConfig(projectRoot: string, options: { readonly dryRun?: boolean } = {}): InstallResult {\n const filePath = join(projectRoot, '.ctxo', 'config.yaml');\n const file = '.ctxo/config.yaml';\n\n if (options.dryRun) {\n return { file, action: existsSync(filePath) ? 'skipped' : 'created' };\n }\n\n mkdirSync(dirname(filePath), { recursive: true });\n try {\n writeFileSync(filePath, DEFAULT_CONFIG, { encoding: 'utf-8', flag: 'wx' });\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'EEXIST') return { file, action: 'skipped' };\n throw err;\n }\n return { file, action: 'created' };\n}\n\n/* ------------------------------------------------------------------ */\n/* MCP server registration */\n/* ------------------------------------------------------------------ */\n\nconst CTXO_MCP_ENTRY = { command: 'npx', args: ['-y', '@ctxo/cli'] };\n\ninterface McpConfigTarget {\n file: string;\n /** JSON key that holds server map */\n serverKey: 'mcpServers' | 'servers';\n /** Extra fields per server entry */\n extraFields?: Record<string, string>;\n}\n\n/**\n * Returns which MCP config files to create/update based on selected platforms.\n * Multiple platforms may map to the same config file (deduplicated).\n */\nexport function getMcpConfigTargets(selectedPlatformIds: string[]): McpConfigTarget[] {\n const targets = new Map<string, McpConfigTarget>();\n\n for (const id of selectedPlatformIds) {\n switch (id) {\n case 'claude-code':\n case 'cursor':\n case 'windsurf':\n case 'augment':\n case 'antigravity':\n // .mcp.json is the universal project-level MCP config\n targets.set('.mcp.json', { file: '.mcp.json', serverKey: 'mcpServers' });\n break;\n case 'github-copilot':\n targets.set('.vscode/mcp.json', { file: '.vscode/mcp.json', serverKey: 'servers', extraFields: { type: 'stdio' } });\n break;\n case 'amazonq':\n targets.set('.amazonq/mcp.json', { file: '.amazonq/mcp.json', serverKey: 'mcpServers' });\n break;\n case 'gemini-cli':\n // Gemini CLI reads MCP servers from .gemini/settings.json (project) or ~/.gemini/settings.json (user).\n targets.set('.gemini/settings.json', { file: '.gemini/settings.json', serverKey: 'mcpServers' });\n break;\n case 'continue':\n // Continue reads each MCP server from a standalone file under .continue/mcpServers/.\n targets.set('.continue/mcpServers/ctxo.json', { file: '.continue/mcpServers/ctxo.json', serverKey: 'mcpServers' });\n break;\n }\n }\n\n return [...targets.values()];\n}\n\n/**\n * Registers the ctxo server in one MCP config file: a missing file is `created`, an existing one gets\n * the entry merged in (`updated`, or `skipped` when ctxo is already there), and corrupt MCP JSON is\n * overwritten (`updated`, D12). Corrupt covers text that fails `JSON.parse`, a root that is not a plain\n * object (an array, a string, a number, `null`), and a server map that is neither absent, `null` nor a\n * plain object (such as a string `mcpServers`), so the call never throws on a file's content. A path\n * that cannot be read (a directory, no permission) is `skipped` with a warning and left alone. `dryRun`\n * computes the same action and writes nothing, not even a directory.\n */\nexport function ensureMcpConfig(\n projectRoot: string,\n target: McpConfigTarget,\n options: { readonly dryRun?: boolean } = {},\n): InstallResult {\n const filePath = join(projectRoot, target.file);\n const write = (config: Record<string, unknown>): void => {\n if (options.dryRun) return;\n mkdirSync(dirname(filePath), { recursive: true });\n writeFileSync(filePath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n };\n\n const entry = target.extraFields\n ? { ...target.extraFields, ...CTXO_MCP_ENTRY }\n : { ...CTXO_MCP_ENTRY };\n const fresh = (): Record<string, unknown> => ({ [target.serverKey]: { ctxo: entry } });\n\n if (!existsSync(filePath)) {\n write(fresh());\n return { file: target.file, action: 'created' };\n }\n\n let text: string;\n try {\n text = readFileSync(filePath, 'utf-8');\n } catch (err) {\n return { file: target.file, action: 'skipped', warning: unreadableWarning(target.file, err) };\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n parsed = undefined;\n }\n const servers = isPlainObject(parsed) ? (parsed[target.serverKey] ?? {}) : undefined;\n if (!isPlainObject(parsed) || !isPlainObject(servers)) {\n // Corrupt MCP JSON: overwrite (D12).\n write(fresh());\n return { file: target.file, action: 'updated' };\n }\n\n if (servers['ctxo']) {\n return { file: target.file, action: 'skipped' };\n }\n\n write({ ...parsed, [target.serverKey]: { ...servers, ctxo: entry } });\n return { file: target.file, action: 'updated' };\n}\n","/**\n * The ctxo rules block that `ctxo init` writes into an agent's instruction file (CLAUDE.md,\n * AGENTS.md, .cursor/rules/ctxo.mdc and the rest), and the parser that finds it again.\n *\n * Two tiers share one pair of versioned markers:\n * - compact: a few lines for Claude Code when the safe-edit guard, the skills and the gate back it up;\n * - full: the complete tool guide for every other client.\n *\n * The parser also recognises unversioned marked blocks and the pre-marker body that older ctxo\n * versions wrote, so an upgrade replaces them in place instead of appending a second block.\n *\n * Pure: no file system, no clock, no environment.\n */\n\nexport type RulesTier = 'compact' | 'full';\n\n/**\n * The CLI minor in which the template text last changed (hand-set, not read from package.json),\n * so a release that leaves the template alone does not mark every committed block outdated.\n */\nexport const RULES_TEMPLATE_VERSION: string = '0.13';\n\n/**\n * The CLI minor in which the bundled skills last changed (hand-set, like RULES_TEMPLATE_VERSION). Each\n * bundled SKILL.md ends with it as `<!-- ctxo-skill v<M.m> -->`, so an older ctxo leaves a skill\n * written by a newer one alone instead of downgrading it.\n */\nexport const SKILLS_TEMPLATE_VERSION: string = '0.13';\n\n/** Marker lines; they also match inside a fenced code block, so a fenced copy of a block counts as one. */\nconst START_MARKER_RE = /^<!-- ctxo-rules-start(?: v(\\S+))? -->[ \\t]*$/gm;\nconst END_MARKER_RE = /^<!-- ctxo-rules-end -->[ \\t]*$/gm;\nconst VERSION_RE = /^\\d+\\.\\d+$/;\nconst END_MARKER = '<!-- ctxo-rules-end -->';\nconst BOM = '\\uFEFF';\n\n/* ------------------------------------------------------------------ */\n/* Rule texts */\n/* ------------------------------------------------------------------ */\n\n/**\n * The body every ctxo version before the tiers wrote (`ruleBody()` in `cli/ai-rules.ts`), verbatim.\n * Used only to recognise old blocks; its em dashes stay as escapes.\n */\nexport const LEGACY_RULE_BODY = `## ctxo MCP Tool Usage (MANDATORY)\n\n**ALWAYS use ctxo MCP tools before reading source files or making code changes.** The ctxo index contains dependency graphs, git intent, anti-patterns, and change health that cannot be derived from reading files alone. Skipping these tools leads to blind edits and broken dependencies.\n\n### Before ANY Code Modification\n1. Call \\`get_blast_radius\\` for the symbol you are about to change \\u2014 understand what breaks\n2. Call \\`get_why_context\\` for the same symbol \\u2014 check for revert history or anti-patterns\n3. Only then read and edit source files\n\n### Before Starting a Task\n| Task Type | REQUIRED First Call |\n|---|---|\n| Fixing a bug | \\`get_context_for_task(taskType: \"fix\")\\` |\n| Adding/extending a feature | \\`get_context_for_task(taskType: \"extend\")\\` |\n| Refactoring | \\`get_context_for_task(taskType: \"refactor\")\\` |\n| Understanding code | \\`get_context_for_task(taskType: \"understand\")\\` |\n\n### Before Reviewing a PR or Diff\n- Call \\`get_pr_impact\\` \\u2014 single call gives full risk assessment with co-change analysis\n\n### When Exploring or Searching Code\n- Use \\`search_symbols\\` for name/regex lookup \\u2014 DO NOT grep source files for symbol discovery\n- Use \\`get_ranked_context\\` for natural language queries \\u2014 DO NOT manually browse directories\n\n### Orientation in Unfamiliar Areas\n- Call \\`get_architectural_overlay\\` to understand layer boundaries\n- Call \\`get_symbol_importance\\` to identify critical symbols\n\n### NEVER Do These\n- NEVER edit a function without first calling \\`get_blast_radius\\` on it\n- NEVER skip \\`get_why_context\\` \\u2014 reverted code and anti-patterns are invisible without it\n- NEVER grep source files to find symbols when \\`search_symbols\\` exists\n- NEVER manually trace imports when \\`find_importers\\` gives the full reverse dependency graph`;\n\n/**\n * The Cursor frontmatter every ctxo version before the tiers wrote (`cursorFrontmatter()` in\n * `cli/ai-rules.ts`), verbatim. Used only to recognise old files; its em dash stays as an escape.\n */\nexport const LEGACY_CURSOR_FRONTMATTER = `---\ndescription: ctxo MCP tool usage rules \\u2014 always applied\nglobs:\nalwaysApply: true\n---\n\n`;\n\n/*\n * Both bodies are written in the layout Prettier prints (a blank line after each heading, a padded\n * table), so a repo that formats its markdown leaves them byte-for-byte alone.\n *\n * The spec caps the compact tier at 8 lines including its heading. Prettier forces blank lines after\n * the start marker, after the heading and before the end marker, so the cap counts non-blank lines\n * only: the rendered compact block has 6 (both markers, the heading, three lines of text), 9 in all.\n */\n\nconst COMPACT_RULE_BODY = `## ctxo\n\nThis repo has a ctxo index: dependency graph, git intent, change health. For structural questions (who depends on X, what breaks if X changes, why X looks like this), use the ctxo MCP tools before grepping.\nA pre-edit guard blocks the first edit to a high-impact symbol until \\`get_blast_radius\\` has been called for it.\nSkills: \\`ctxo-understand\\` (orient at task start), \\`ctxo-safe-edit\\` (before changing a symbol), \\`ctxo-review-pr\\` (before reviewing a diff).`;\n\n/**\n * LEGACY_RULE_BODY with eight lines reworded (narrowed first sentence, no em dashes) and Prettier's\n * layout (blank lines after the headings, a padded table); same heading.\n */\nconst FULL_RULE_BODY = `## ctxo MCP Tool Usage (MANDATORY)\n\n**For structural questions (dependencies, impact, history), use ctxo tools first; reading a file to see its contents needs no index call.** The ctxo index contains dependency graphs, git intent, anti-patterns, and change health that cannot be derived from reading files alone. Skipping these tools leads to blind edits and broken dependencies.\n\n### Before ANY Code Modification\n\n1. Call \\`get_blast_radius\\` for the symbol you are about to change, to see what breaks\n2. Call \\`get_why_context\\` for the same symbol, to check for revert history or anti-patterns\n3. Only then edit the source\n\n### Before Starting a Task\n\n| Task Type | REQUIRED First Call |\n| -------------------------- | ---------------------------------------------- |\n| Fixing a bug | \\`get_context_for_task(taskType: \"fix\")\\` |\n| Adding/extending a feature | \\`get_context_for_task(taskType: \"extend\")\\` |\n| Refactoring | \\`get_context_for_task(taskType: \"refactor\")\\` |\n| Understanding code | \\`get_context_for_task(taskType: \"understand\")\\` |\n\n### Before Reviewing a PR or Diff\n\n- Call \\`get_pr_impact\\`: a single call gives a full risk assessment with co-change analysis\n\n### When Exploring or Searching Code\n\n- Use \\`search_symbols\\` for name/regex lookup; DO NOT grep source files for symbol discovery\n- Use \\`get_ranked_context\\` for natural language queries; DO NOT manually browse directories\n\n### Orientation in Unfamiliar Areas\n\n- Call \\`get_architectural_overlay\\` to understand layer boundaries\n- Call \\`get_symbol_importance\\` to identify critical symbols\n\n### NEVER Do These\n\n- NEVER edit a function without first calling \\`get_blast_radius\\` on it\n- NEVER skip \\`get_why_context\\`: reverted code and anti-patterns are invisible without it\n- NEVER grep source files to find symbols when \\`search_symbols\\` exists\n- NEVER manually trace imports when \\`find_importers\\` gives the full reverse dependency graph`;\n\n/** The rules body for a tier, without markers and without a trailing newline. */\nexport function ruleBody(options: { readonly tier: RulesTier }): string {\n return options.tier === 'compact' ? COMPACT_RULE_BODY : FULL_RULE_BODY;\n}\n\n/**\n * The body between a versioned start marker and the end marker, joined by '\\n', no trailing newline.\n * A blank line separates each marker from the body, as Prettier prints it.\n */\nexport function renderRulesBlock(tier: RulesTier): string {\n return [`<!-- ctxo-rules-start v${RULES_TEMPLATE_VERSION} -->`, '', ruleBody({ tier }), '', END_MARKER].join('\\n');\n}\n\n/* ------------------------------------------------------------------ */\n/* BOM and line endings */\n/* ------------------------------------------------------------------ */\n\nexport type LineEnding = '\\n' | '\\r\\n';\n\n/**\n * A text file's BOM and dominant line ending, with its normalised text. Every ctxo writer that\n * must keep a user's file bytes (rules files, skills) detects and restores them through this.\n */\nexport interface TextShape {\n /** The content started with a UTF-8 BOM (U+FEFF). */\n readonly bom: boolean;\n /** '\\r\\n' when CRLF line breaks outnumber LF ones; otherwise '\\n' (also on a tie or with none). */\n readonly eol: LineEnding;\n /** The content without the BOM and with every '\\r\\n' turned into '\\n'. */\n readonly text: string;\n /** Gives text this shape's line endings only: every line break becomes `eol`. For a part of a file. */\n withEol(normalised: string): string;\n /** Gives text this whole shape: `withEol`, plus the BOM prepended when `bom`. For a whole file. */\n restore(normalised: string): string;\n}\n\nexport function textShape(content: string): TextShape {\n const bom = content.startsWith(BOM);\n const raw = bom ? content.slice(BOM.length) : content;\n let crlf = 0;\n let lf = 0;\n for (let i = raw.indexOf('\\n'); i >= 0; i = raw.indexOf('\\n', i + 1)) {\n if (i > 0 && raw[i - 1] === '\\r') crlf++;\n else lf++;\n }\n const eol: LineEnding = crlf > lf ? '\\r\\n' : '\\n';\n const withEol = (normalised: string): string => normalised.replace(/\\r\\n/g, '\\n').replace(/\\n/g, eol);\n return {\n bom,\n eol,\n text: raw.replace(/\\r\\n/g, '\\n'),\n withEol,\n restore: (normalised) => (bom ? BOM : '') + withEol(normalised),\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Format-insensitive comparison */\n/* ------------------------------------------------------------------ */\n\n/**\n * One line in its comparison form: trailing whitespace removed, and a table row without the padding\n * around its cells (the dashes of a separator row collapse to one). Leading whitespace is kept.\n */\nfunction comparisonLine(line: string): string {\n const trimmed = line.trimEnd();\n if (!trimmed.trimStart().startsWith('|')) return trimmed;\n const row = trimmed.trim().replace(/[ \\t]*\\|[ \\t]*/g, '|');\n return /^\\|(?::?-+:?\\|)+$/.test(row) ? row.replace(/-+/g, '-') : row;\n}\n\n/**\n * The comparison form of markdown text, so what a formatter (Prettier, markdownlint --fix, an editor)\n * changes is not an edit: no BOM, '\\n' line endings, no trailing whitespace, no blank lines (every run\n * of blank lines collapses into the line break it sits in, so leading and trailing ones go too), and\n * table rows without cell padding. Blocks, legacy bodies and skills are all compared in this form.\n */\nexport function normaliseMarkdown(text: string): string {\n return textShape(text).text.split('\\n').map(comparisonLine).filter((line) => line !== '').join('\\n');\n}\n\n/**\n * The equality form of markdown text: `normaliseMarkdown`, then every whitespace run (line breaks\n * included) as one space, trimmed. Re-wrapped prose (Prettier's `proseWrap: always` or `never`),\n * indentation and padding then never count as edits. Used only to test equality (block\n * classification, the formatting-only `unchanged` upsert, the skill comparison); the tier and the\n * legacy body are still read line by line.\n */\nexport function comparableMarkdown(text: string): string {\n return normaliseMarkdown(text).replace(/\\s+/g, ' ').trim();\n}\n\n/* ------------------------------------------------------------------ */\n/* Scanning */\n/* ------------------------------------------------------------------ */\n\nexport interface RulesBlockSpan {\n /** [start, end) in the normalised text; end is right after the end marker (or the legacy body). */\n readonly start: number;\n readonly end: number;\n /** False: the legacy body found without markers. */\n readonly marked: boolean;\n /** 'M.m' from the start marker; absent when unversioned, malformed or legacy. */\n readonly version?: string;\n /** Text between the marker lines ('\\n' line breaks). */\n readonly body: string;\n}\n\nexport interface RulesScan {\n readonly blocks: readonly RulesBlockSpan[];\n /** A start marker has no end marker before the next start marker or the end of the text. */\n readonly unterminated: boolean;\n /** An end marker closes no block: no start marker before it, or its block was already closed. */\n readonly orphanEnd: boolean;\n}\n\n/** Finds every ctxo block in a file's content. Strips a leading BOM and normalises '\\r\\n' first. */\nexport function scanRulesBlocks(content: string): RulesScan {\n return scanNormalised(textShape(content).text);\n}\n\nfunction scanNormalised(text: string): RulesScan {\n const starts = [...text.matchAll(START_MARKER_RE)];\n const ends = [...text.matchAll(END_MARKER_RE)];\n const marked: RulesBlockSpan[] = [];\n let unterminated = false;\n\n starts.forEach((start, i) => {\n const startLineEnd = start.index + start[0].length;\n const end = ends.find((m) => m.index > startLineEnd);\n const next = starts[i + 1];\n if (!end || (next && next.index < end.index)) {\n unterminated = true;\n return;\n }\n const rawVersion = start[1];\n const version = rawVersion !== undefined && VERSION_RE.test(rawVersion) ? rawVersion : undefined;\n marked.push({\n start: start.index,\n end: end.index + end[0].length,\n marked: true,\n ...(version !== undefined ? { version } : {}),\n body: text.slice(startLineEnd + 1, end.index - 1),\n });\n });\n\n const closing = new Set(marked.map((b) => b.end));\n const orphanEnd = ends.some((m) => !closing.has(m.index + m[0].length));\n const blocks = [...marked, ...legacySpans(text, marked)].sort((a, b) => a.start - b.start);\n return { blocks, unterminated, orphanEnd };\n}\n\n/** LEGACY_RULE_BODY's lines in their comparison form, blank lines left out. */\nconst LEGACY_LINES: readonly string[] = normaliseMarkdown(LEGACY_RULE_BODY).split('\\n');\n\n/**\n * Occurrences of LEGACY_RULE_BODY on whole lines, outside every marked block, compared line by line\n * in the `normaliseMarkdown` form: a copy a formatter reshaped (blank lines added, a table padded,\n * trailing spaces) is still found. A span runs from its first line to the end of its last one.\n */\nfunction legacySpans(text: string, marked: readonly RulesBlockSpan[]): RulesBlockSpan[] {\n const lines: Array<{ readonly start: number; readonly end: number; readonly key: string }> = [];\n for (let start = 0; start <= text.length; ) {\n const lineBreak = text.indexOf('\\n', start);\n const end = lineBreak < 0 ? text.length : lineBreak;\n lines.push({ start, end, key: comparisonLine(text.slice(start, end)) });\n start = end + 1;\n }\n\n const spans: RulesBlockSpan[] = [];\n for (let i = 0; i < lines.length; i++) {\n const first = lines[i];\n if (first === undefined || first.key !== LEGACY_LINES[0]) continue;\n let matched = 1;\n let last = first;\n let j = i + 1;\n for (; j < lines.length && matched < LEGACY_LINES.length; j++) {\n const line = lines[j];\n if (line === undefined || line.key === '') continue;\n if (line.key !== LEGACY_LINES[matched]) break;\n matched += 1;\n last = line;\n }\n if (matched < LEGACY_LINES.length) continue;\n if (marked.some((b) => first.start < b.end && last.end > b.start)) continue;\n spans.push({ start: first.start, end: last.end, marked: false, body: text.slice(first.start, last.end) });\n i = j - 1;\n }\n return spans;\n}\n\n/* ------------------------------------------------------------------ */\n/* Upsert */\n/* ------------------------------------------------------------------ */\n\nexport type UpsertResult =\n | { readonly kind: 'inserted' | 'replaced' | 'unchanged'; readonly content: string }\n | { readonly kind: 'unterminated' }\n | { readonly kind: 'orphan-end' }\n | { readonly kind: 'newer'; readonly version: string };\n\n/**\n * Writes `block` into a file's content: replaces the first ctxo block in place (marked, unmarked or\n * legacy), removes any later ones, or appends when there is none.\n *\n * Leaves the content alone when a start marker is unterminated, when an end marker closes no block\n * (a deleted start line would otherwise leave the old body and a second block), or when a block comes\n * from a newer template (D8, D2). Every byte outside the ctxo blocks is kept, the BOM included; the new\n * block takes the dominant line ending of the text around it, so a mixed-ending file is never\n * rewritten wholesale.\n * A single block with the same marker version as `block` and a body that differs only in formatting,\n * line wrapping included (`comparableMarkdown`), is `unchanged`, so ctxo and a formatter never rewrite\n * each other's output.\n */\nexport function upsertRulesBlock(existing: string, block: string): UpsertResult {\n const shape = textShape(existing);\n const raw = shape.bom ? existing.slice(BOM.length) : existing;\n const bom = shape.bom ? BOM : '';\n const text = shape.text;\n const scan = scanNormalised(text);\n if (scan.unterminated) return { kind: 'unterminated' };\n if (scan.orphanEnd) return { kind: 'orphan-end' };\n\n for (const b of scan.blocks) {\n if (b.version !== undefined && compareTemplateVersions(b.version, RULES_TEMPLATE_VERSION) > 0) {\n return { kind: 'newer', version: b.version };\n }\n }\n\n const [first, ...later] = scan.blocks;\n if (!first) {\n const eolShape = textShape(raw);\n const gap = raw.length === 0 ? '' : raw.endsWith('\\n') ? eolShape.eol : eolShape.eol + eolShape.eol;\n return { kind: 'inserted', content: bom + raw + gap + eolShape.withEol(block) + eolShape.eol };\n }\n if (later.length === 0 && sameBlock(first, block)) return { kind: 'unchanged', content: existing };\n\n const toRaw = rawOffsetMapper(raw);\n const kept: string[] = [];\n let cursor = first.end;\n for (const span of later) {\n const blankBefore = text[span.start - 1] === '\\n' && text[span.start - 2] === '\\n';\n const from = Math.max(cursor, span.start - (blankBefore ? 1 : 0));\n const to = span.end + (text[span.end] === '\\n' ? 1 : 0);\n kept.push(raw.slice(toRaw(cursor), toRaw(from)));\n cursor = to;\n }\n kept.push(raw.slice(toRaw(cursor)));\n\n const prefix = raw.slice(0, toRaw(first.start));\n const suffix = kept.join('');\n const around = prefix + suffix;\n // The surrounding lines set the ending; a file that is nothing but the block keeps the block's own.\n const eolShape = textShape(around.length > 0 ? around : raw.slice(toRaw(first.start), toRaw(first.end)));\n const content = bom + prefix + eolShape.withEol(block) + suffix;\n if (content === existing) return { kind: 'unchanged', content: existing };\n return { kind: 'replaced', content };\n}\n\n/** Whether `found` is a marked block with `block`'s marker version and a body equal to its in `comparableMarkdown` form. */\nfunction sameBlock(found: RulesBlockSpan, block: string): boolean {\n const target = scanNormalised(textShape(block).text).blocks[0];\n return (\n target !== undefined &&\n found.marked &&\n target.marked &&\n found.version !== undefined &&\n found.version === target.version &&\n comparableMarkdown(found.body) === comparableMarkdown(target.body)\n );\n}\n\n/**\n * Maps an offset in the normalised text to the same place in the raw text (BOM already removed).\n * An offset that points at a normalised '\\n' maps to the '\\r' of its '\\r\\n'.\n */\nfunction rawOffsetMapper(raw: string): (normalisedOffset: number) => number {\n const crlfAt: number[] = [];\n for (let i = raw.indexOf('\\r\\n'); i >= 0; i = raw.indexOf('\\r\\n', i + 2)) {\n crlfAt.push(i - crlfAt.length);\n }\n return (offset) => {\n let lo = 0;\n let hi = crlfAt.length;\n while (lo < hi) {\n const mid = (lo + hi) >> 1;\n if ((crlfAt[mid] as number) < offset) lo = mid + 1;\n else hi = mid;\n }\n return offset + lo;\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Classification and tier policy */\n/* ------------------------------------------------------------------ */\n\n/** Compares two 'M.m' template versions: numeric major, then numeric minor. */\nexport function compareTemplateVersions(a: string, b: string): number {\n const [aMajor, aMinor] = versionParts(a);\n const [bMajor, bMinor] = versionParts(b);\n return aMajor - bMajor || aMinor - bMinor;\n}\n\nfunction versionParts(version: string): [number, number] {\n const [major = '', minor = ''] = version.split('.');\n return [Number(major) || 0, Number(minor) || 0];\n}\n\nconst SKILL_MARKER_RE = /^<!-- ctxo-skill v(\\d+\\.\\d+) -->[ \\t]*$/m;\n\n/** The 'M.m' version from a skill's own `<!-- ctxo-skill v<M.m> -->` line; undefined without one. */\nexport function skillTemplateVersion(content: string): string | undefined {\n return SKILL_MARKER_RE.exec(textShape(content).text)?.[1];\n}\n\n/**\n * The tier a body was written in, read from its first non-blank line: a formatter may put a blank\n * line after the start marker.\n */\nexport function blockTier(body: string): RulesTier | 'unknown' {\n const heading = body.split('\\n').map((line) => line.trimEnd()).find((line) => line !== '') ?? '';\n if (heading === '## ctxo') return 'compact';\n if (heading.startsWith('## ctxo MCP Tool Usage')) return 'full';\n return 'unknown';\n}\n\n/** Each tier's body in the `comparableMarkdown` form. */\nconst COMPARABLE_BODIES: Readonly<Record<RulesTier, string>> = {\n compact: comparableMarkdown(COMPACT_RULE_BODY),\n full: comparableMarkdown(FULL_RULE_BODY),\n};\n\nexport type BlockStatus =\n | { readonly state: 'current'; readonly tier: RulesTier }\n | { readonly state: 'outdated'; readonly reason: 'unversioned' | 'older' | 'edited'; readonly tier: RulesTier | 'unknown' }\n | { readonly state: 'newer'; readonly version: string; readonly tier: RulesTier | 'unknown' };\n\n/**\n * Outdated: no version, an older version, or the current version with an edited body. A body that\n * differs from the template only in formatting, line wrapping included (`comparableMarkdown`), is not\n * edited. A block from a newer template is never outdated.\n */\nexport function classifyRulesBlock(block: RulesBlockSpan): BlockStatus {\n const tier = blockTier(block.body);\n if (!block.marked || block.version === undefined) return { state: 'outdated', reason: 'unversioned', tier };\n const order = compareTemplateVersions(block.version, RULES_TEMPLATE_VERSION);\n if (order > 0) return { state: 'newer', version: block.version, tier };\n if (order < 0) return { state: 'outdated', reason: 'older', tier };\n if (tier !== 'unknown' && comparableMarkdown(block.body) === COMPARABLE_BODIES[tier]) return { state: 'current', tier };\n return { state: 'outdated', reason: 'edited', tier };\n}\n\nexport interface TierFacts {\n readonly guardPresent: boolean;\n readonly skillsComplete: boolean;\n readonly gateEnabled: boolean;\n /** The rules file is also another client's rules file (a linked AGENTS.md and CLAUDE.md); absent: not shared. */\n readonly sharedFile?: boolean;\n}\n\n/**\n * Compact only for Claude Code with the guard hook, every skill and an enabled gate, in a rules file\n * no other client reads; full otherwise. A shared file serves clients the guard and skills do not\n * back, so it gets the full tier.\n */\nexport function expectedRulesTier(platformId: string, facts: TierFacts): RulesTier {\n return platformId === 'claude-code' &&\n facts.guardPresent &&\n facts.skillsComplete &&\n facts.gateEnabled &&\n facts.sharedFile !== true\n ? 'compact'\n : 'full';\n}\n\n/**\n * Whether a file's block implies the guard and the skills should be installed: legacy, unversioned\n * and compact blocks do; a versioned full block records an opt-out, and no block expects nothing.\n */\nexport function guardAndSkillsExpected(block: RulesBlockSpan | undefined): boolean {\n if (!block) return false;\n return !block.marked || block.version === undefined || blockTier(block.body) === 'compact';\n}\n","import { execFileSync } from 'node:child_process';\nimport { join, resolve } from 'node:path';\n\n/* ------------------------------------------------------------------ */\n/* ctxo git hook blocks */\n/* */\n/* Pure helpers shared by `ctxo init`, `ctxo doctor --fix` and the */\n/* `git_hooks` doctor check. No prompt or install modules in here. */\n/* ------------------------------------------------------------------ */\n\nconst CTXO_START = '# ctxo-start';\nconst CTXO_END = '# ctxo-end';\n\n/**\n * Version of the post-commit block this build writes. The marker line carries it (`# ctxo-start v2`)\n * so a newer build can tell an outdated block from a current one and replace it in place.\n * Blocks written before versioning have a bare `# ctxo-start` and count as version 1.\n */\nexport const POST_COMMIT_HOOK_VERSION = 2;\n\n// The block text is LF-only whatever the line endings of this source file. Template literals\n// normalise CRLF as well; the explicit join just makes that obvious.\n//\n// Both blocks are guarded on a `.ctxo` directory: git runs hooks from the work-tree root, so the\n// relative test only passes in a repository that uses ctxo. That keeps a block pasted into a hooks\n// directory shared by many repositories harmless everywhere else.\nexport const POST_COMMIT_CONTENT = [\n `${CTXO_START} v${POST_COMMIT_HOOK_VERSION}`,\n '# Incremental re-index of the files changed by this commit (one run per commit)',\n 'if [ -d .ctxo ] && command -v ctxo >/dev/null 2>&1; then',\n ' ctxo index --commit HEAD >/dev/null 2>&1 || true',\n 'fi',\n CTXO_END,\n].join('\\n');\n\nexport const POST_MERGE_CONTENT = [\n CTXO_START,\n '# Rebuild SQLite cache after merge (index updated via git pull)',\n 'if [ -d .ctxo ] && command -v ctxo >/dev/null 2>&1; then',\n ' ctxo sync 2>/dev/null || true',\n 'fi',\n CTXO_END,\n].join('\\n');\n\n/**\n * One complete ctxo block: a `# ctxo-start` line (optionally `vN`) through the next `# ctxo-end`\n * line. The body may not contain another start line, so a dangling start marker without an end can\n * never swallow the user lines up to a later, complete block. Marker lines are matched whole\n * (`# ctxo-end-of-my-section` is not an end marker). Global, so `matchAll` finds every block.\n */\nconst START_LINE = `${CTXO_START}(?:[ \\\\t]+v\\\\d+)?[ \\\\t]*$`;\nconst CTXO_BLOCK_PATTERN = new RegExp(\n `^${START_LINE}\\\\r?\\\\n(?:(?!^${START_LINE})[\\\\s\\\\S])*?^${CTXO_END}[ \\\\t]*$`,\n 'gm',\n);\n\nconst CTXO_BLOCK_VERSION_PATTERN = new RegExp(`^${CTXO_START}(?:[ \\\\t]+v(\\\\d+))?`);\n\ninterface CtxoBlockSpan {\n readonly start: number;\n readonly end: number;\n readonly text: string;\n}\n\nfunction findCtxoBlocks(content: string): CtxoBlockSpan[] {\n return [...content.matchAll(CTXO_BLOCK_PATTERN)].map((match) => ({\n start: match.index,\n end: match.index + match[0].length,\n text: match[0],\n }));\n}\n\n/**\n * Versions of every complete ctxo block in a hook file, in file order: 1 for an unversioned\n * block, N for `# ctxo-start vN`. Empty when the file holds no complete block.\n */\nexport function readCtxoBlockVersions(hookContent: string): number[] {\n return findCtxoBlocks(hookContent).map((block) => {\n const versionMatch = CTXO_BLOCK_VERSION_PATTERN.exec(block.text);\n return versionMatch?.[1] ? Number(versionMatch[1]) : 1;\n });\n}\n\n/**\n * Puts `blockContent` into a hook file. The first existing ctxo block (unversioned v1 included) is\n * replaced where it stands, so the lines before and after it survive byte for byte. Any further\n * complete ctxo block is removed (with its line break): replacing each one by the new block would\n * leave the hook running ctxo once per copy. Without a block, the new one is appended.\n */\nexport function upsertCtxoBlock(existing: string, blockContent: string): string {\n const [first, ...duplicates] = findCtxoBlocks(existing);\n if (!first) {\n return existing.endsWith('\\n')\n ? existing + '\\n' + blockContent + '\\n'\n : existing + '\\n\\n' + blockContent + '\\n';\n }\n\n // Back to front: every offset is taken from `existing`, and removing a later block never moves an earlier one.\n let result = existing;\n for (const block of duplicates.reverse()) {\n const lineBreak = existing.startsWith('\\r\\n', block.end) ? 2 : existing.startsWith('\\n', block.end) ? 1 : 0;\n result = result.slice(0, block.start) + result.slice(block.end + lineBreak);\n }\n return result.slice(0, first.start) + blockContent + result.slice(first.end);\n}\n\n/* ------------------------------------------------------------------ */\n/* Hooks directory */\n/* ------------------------------------------------------------------ */\n\n/**\n * The directory git runs hooks from: `git rev-parse --git-path hooks`, so `core.hooksPath` and\n * linked worktrees resolve the way git itself resolves them. Git may answer relative to its cwd,\n * which is the project root, so a relative answer is resolved against it. Falls back to\n * `<projectRoot>/.git/hooks` whenever git cannot answer.\n */\nexport function resolveHooksDir(projectRoot: string): string {\n const fallback = join(projectRoot, '.git', 'hooks');\n try {\n const answer = execFileSync('git', ['rev-parse', '--git-path', 'hooks'], {\n cwd: projectRoot,\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n return answer ? resolve(projectRoot, answer) : fallback;\n } catch {\n return fallback;\n }\n}\n\n/** Where git config scopes sit relative to one repository: only these two are shared with other repositories. */\nexport type SharedHooksScope = 'global' | 'system';\n\n/**\n * Set when the effective `core.hooksPath` comes from the user's global or the system git config\n * (`git config --show-scope --get core.hooksPath`, run in the project root). Such a directory is\n * shared by every repository on the machine, so ctxo must not write into it. A local or worktree\n * `core.hooksPath` (or none at all) gives `undefined`, as does git being unable to answer.\n */\nexport function sharedHooksScope(projectRoot: string): SharedHooksScope | undefined {\n try {\n const answer = execFileSync('git', ['config', '--show-scope', '--get', 'core.hooksPath'], {\n cwd: projectRoot,\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n }).trim();\n const scope = answer.split('\\t')[0];\n return scope === 'global' || scope === 'system' ? scope : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** Forward slashes for messages, so a Windows path reads (and compares) the same as a POSIX one. */\nexport function forwardSlashes(path: string): string {\n return path.replace(/\\\\/g, '/');\n}\n\n/**\n * What `ctxo init` and `ctxo doctor --fix` print instead of installing into a shared hooks\n * directory: why, and the two blocks to add by hand.\n */\nexport function sharedHooksWarning(hooksDir: string, scope: SharedHooksScope): string {\n const dir = forwardSlashes(hooksDir);\n return [\n `[ctxo] Skipped git hooks: core.hooksPath in your ${scope} git config points at ${dir}.`,\n '[ctxo] That hooks directory is shared by every repository on this machine, so ctxo does not write into it.',\n `[ctxo] To keep the index current anyway, add these blocks by hand to ${dir}/post-commit and ${dir}/post-merge`,\n '[ctxo] (each one only acts in a repository that has a .ctxo directory), or give this repository its own',\n '[ctxo] hooks path with \"git config --local core.hooksPath <dir>\" and run \"ctxo init\" again.',\n '',\n `--- ${dir}/post-commit ---`,\n POST_COMMIT_CONTENT,\n '',\n `--- ${dir}/post-merge ---`,\n POST_MERGE_CONTENT,\n '',\n ].join('\\n');\n}\n","/**\n * The parts `ctxo init` can install, and how the `--only`, `--skip`, `--no-guard` and `--rules` flags\n * select them. Pure: no file system, no process state (the router prints errors, InitCommand acts).\n *\n * Part boundaries (D9): `config` covers `.ctxo/config.yaml`, the `.gitignore` entry and `.ctxo/index/`.\n * The language-plugin install is not a part: `--only` skips it, `--skip` keeps it (subject to\n * `--no-install`), and `--rules` keeps skipping it (see `pluginStepEnabled`).\n *\n * `domain` joins the list in PR 2B.\n */\n\n/** The order the help lists them in. The order init runs them in is InitCommand's, not this one. */\nexport const INIT_PARTS = ['rules', 'skills', 'guard', 'mcp', 'git-hooks', 'config'] as const;\n\nexport type InitPart = (typeof INIT_PARTS)[number];\n\nfunction isInitPart(value: string): value is InitPart {\n return (INIT_PARTS as readonly string[]).includes(value);\n}\n\n/**\n * Split a comma-separated `--only` / `--skip` value. Names are trimmed, empty items dropped and repeats\n * removed, keeping the input order. Names that are not parts come back in `unknown` (case is not folded).\n */\nexport function parseInitParts(raw: string): { readonly parts: InitPart[]; readonly unknown: string[] } {\n const parts: InitPart[] = [];\n const unknown: string[] = [];\n for (const item of raw.split(',')) {\n const name = item.trim();\n if (name === '') continue;\n if (isInitPart(name)) {\n if (!parts.includes(name)) parts.push(name);\n } else if (!unknown.includes(name)) {\n unknown.push(name);\n }\n }\n return { parts, unknown };\n}\n\nexport interface InitPartFlags {\n /** `--only`: install exactly these parts. The router rejects it together with `skip` or `rulesOnly`. */\n readonly only?: readonly InitPart[];\n /** `--skip`: install everything except these parts. */\n readonly skip?: readonly InitPart[];\n /** `--no-guard`: does not install the safe-edit guard, whatever else is selected. */\n readonly noGuard?: boolean;\n /** `--rules`, deprecated: the same as `--skip git-hooks,guard`. */\n readonly rulesOnly?: boolean;\n}\n\n/** What `--rules` leaves out. */\nconst RULES_ONLY_SKIPS: readonly InitPart[] = ['git-hooks', 'guard'];\n\n/**\n * The parts one init run installs, in `INIT_PARTS` order. `only` selects exactly those parts; otherwise\n * every part except `skip` and, for `rulesOnly`, `git-hooks` and `guard`. `noGuard` always removes `guard`.\n * An empty `only` selects nothing.\n */\nexport function resolveInitParts(flags: InitPartFlags): Set<InitPart> {\n const removed = new Set<InitPart>(flags.skip ?? []);\n if (flags.rulesOnly) for (const part of RULES_ONLY_SKIPS) removed.add(part);\n return new Set(\n INIT_PARTS.filter((part) => {\n if (flags.noGuard && part === 'guard') return false;\n return flags.only !== undefined ? flags.only.includes(part) : !removed.has(part);\n }),\n );\n}\n\n/**\n * Whether init offers to install language plugins. The plugin step is not a part: `--only` skips it,\n * `--skip` keeps it (subject to `--no-install`), and `--rules` has always skipped it.\n */\nexport function pluginStepEnabled(flags: {\n readonly only?: readonly InitPart[];\n readonly rulesOnly?: boolean;\n readonly noInstall?: boolean;\n}): boolean {\n return flags.only === undefined && !flags.rulesOnly && !flags.noInstall;\n}\n","import { join, extname, relative } from 'node:path';\nimport { readSourceText } from './read-source.js';\nimport { LanguageAdapterRegistry } from '../adapters/language/language-adapter-registry.js';\nimport { loadPlugins } from './plugin-loader.js';\nimport { JsonIndexWriter } from '../adapters/storage/json-index-writer.js';\nimport { SqliteStorageAdapter } from '../adapters/storage/sqlite-storage-adapter.js';\nimport { ChokidarWatcherAdapter } from '../adapters/watcher/chokidar-watcher-adapter.js';\nimport { execFileSync } from 'node:child_process';\nimport { ContentHasher } from '../core/staleness/content-hasher.js';\nimport { SimpleGitAdapter } from '../adapters/git/simple-git-adapter.js';\nimport { RevertDetector } from '../core/why-context/revert-detector.js';\nimport { SymbolGraph } from '../core/graph/symbol-graph.js';\nimport { PageRankCalculator } from '../core/importance/pagerank-calculator.js';\nimport { CommunityDetector, type CommunityDetectorOptions } from '../core/overlay/community-detector.js';\nimport { communityDetectorOptions, factsRequested, loadConfig, watchSnapshotMinFileChanges } from '../core/config/load-config.js';\nimport { extractFileFacts } from './index-facts.js';\nimport type {\n FileIndex, CommitIntent, AntiPattern, CommunitySnapshot, SymbolNode, GraphEdge, ComplexityMetrics,\n} from '../core/types.js';\nimport type { CodeFact, IIncrementalReindex, IncrementalReindexCapable } from '@ctxo/plugin-api';\n\nconst DEBOUNCE_MS = 300;\nconst COMMUNITY_SNAPSHOT_DEBOUNCE_MS = 5000;\n\nexport class WatchCommand {\n private readonly projectRoot: string;\n private readonly ctxoRoot: string;\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n async run(): Promise<void> {\n console.error('[ctxo] Starting file watcher...');\n\n const registry = new LanguageAdapterRegistry();\n\n // Config is read before the plugins load, so the facts capability reaches every createAdapter.\n const watchConfig = loadConfig(this.ctxoRoot).config;\n const watchFacts = factsRequested(watchConfig);\n\n // Plugins via discovery\n const keepAliveByExt = new Map<string, IIncrementalReindex>();\n for (const { plugin, adapter } of await loadPlugins(this.projectRoot, { facts: watchFacts })) {\n if (typeof adapter.initialize === 'function') {\n try {\n await adapter.initialize(this.projectRoot);\n } catch (err) {\n console.error(`[ctxo] Plugin ${plugin.id} initialize failed: ${(err as Error).message}`);\n continue;\n }\n }\n\n registry.register(plugin.extensions, adapter);\n\n // Generic feature detection: if the adapter exposes an incremental-reindex capability, use it\n const capable = adapter as unknown as Partial<IncrementalReindexCapable>;\n if (typeof capable.getIncrementalReindex === 'function') {\n const cap = capable.getIncrementalReindex();\n if (cap?.isReady() && (await cap.startKeepAlive())) {\n for (const ext of plugin.extensions) keepAliveByExt.set(ext.toLowerCase(), cap);\n console.error(`[ctxo] ${plugin.id} watch: keep-alive active (full tier, fast incremental re-index)`);\n }\n }\n\n console.error(`[ctxo] Plugin ${plugin.id}@${plugin.version} (${plugin.tier} tier)`);\n }\n\n const supportedExtensions = registry.getSupportedExtensions();\n const writer = new JsonIndexWriter(this.ctxoRoot);\n const storage = new SqliteStorageAdapter(this.ctxoRoot, { allowProductionPath: true });\n await storage.init();\n const hasher = new ContentHasher();\n\n const gitAdapter = new SimpleGitAdapter(this.projectRoot);\n const revertDetector = new RevertDetector();\n const watcher = new ChokidarWatcherAdapter(this.projectRoot);\n const pendingFiles = new Map<string, NodeJS.Timeout>();\n\n // Watch-time community snapshots cost ~1s of blocking CPU on 25K-symbol\n // monorepos (full PageRank + Louvain recompute). Only recompute once at\n // least `snapshotMinFileChanges` distinct files have been re-indexed\n // since the last snapshot, so rapid-fire saves don't stall the editor.\n const snapshotThreshold = watchSnapshotMinFileChanges(watchConfig);\n const detectorOptions = communityDetectorOptions(watchConfig);\n const pathsChangedSinceSnapshot = new Set<string>();\n\n const reindexFile = async (filePath: string) => {\n const adapter = registry.getAdapter(filePath);\n if (!adapter) return;\n\n const relativePath = relative(this.projectRoot, filePath).replace(/\\\\/g, '/');\n\n try {\n // Generic keep-alive path: use capability if registered for this file extension\n const cap = keepAliveByExt.get(extname(filePath).toLowerCase());\n if (cap?.isReady()) {\n const result = await cap.reindexFile(relativePath);\n if (result) {\n const commits = await gitAdapter.getCommitHistory(relativePath);\n const intent: CommitIntent[] = commits.map((c) => ({\n hash: c.hash, message: c.message, date: c.date, kind: 'commit' as const,\n }));\n const antiPatterns: AntiPattern[] = revertDetector.detect(commits);\n const source = readSourceText(filePath);\n\n const fileIndex = buildWatchFileIndex(relativePath, {\n lastModified: Math.floor(Date.now() / 1000),\n contentHash: hasher.hash(source),\n symbols: result.symbols,\n edges: result.edges,\n complexity: result.complexity,\n intent,\n antiPatterns,\n facts: watchFacts ? await extractFileFacts(adapter, relativePath, source) : undefined,\n });\n\n writer.write(fileIndex);\n storage.writeSymbolFile(fileIndex);\n console.error(`[ctxo] Re-indexed (keep-alive): ${relativePath}`);\n return;\n }\n }\n\n // Default path: use adapter from registry (tree-sitter or ts-morph)\n const source = readSourceText(filePath);\n const lastModified = Math.floor(Date.now() / 1000);\n\n const symbols = await adapter.extractSymbols(relativePath, source);\n const edges = await adapter.extractEdges(relativePath, source);\n const complexity = await adapter.extractComplexity(relativePath, source);\n\n const commits = await gitAdapter.getCommitHistory(relativePath);\n const intent: CommitIntent[] = commits.map((c) => ({\n hash: c.hash, message: c.message, date: c.date, kind: 'commit' as const,\n }));\n const antiPatterns: AntiPattern[] = revertDetector.detect(commits);\n\n const fileIndex = buildWatchFileIndex(relativePath, {\n lastModified,\n contentHash: hasher.hash(source),\n symbols,\n edges,\n complexity,\n intent,\n antiPatterns,\n facts: watchFacts ? await extractFileFacts(adapter, relativePath, source) : undefined,\n });\n\n writer.write(fileIndex);\n storage.writeSymbolFile(fileIndex);\n console.error(`[ctxo] Re-indexed: ${relativePath}`);\n } catch (err) {\n console.error(`[ctxo] Failed to re-index ${relativePath}: ${(err as Error).message}`);\n }\n };\n\n let communitySnapshotTimer: NodeJS.Timeout | undefined;\n const scheduleCommunitySnapshot = () => {\n // Threshold skip — don't even arm the debounce timer unless enough\n // distinct files changed since the last accepted snapshot.\n if (pathsChangedSinceSnapshot.size < snapshotThreshold) return;\n\n if (communitySnapshotTimer) clearTimeout(communitySnapshotTimer);\n communitySnapshotTimer = setTimeout(() => {\n communitySnapshotTimer = undefined;\n if (pathsChangedSinceSnapshot.size < snapshotThreshold) return;\n const changedCount = pathsChangedSinceSnapshot.size;\n pathsChangedSinceSnapshot.clear();\n try {\n const snapshot = buildWatchCommunitySnapshot(storage, detectorOptions);\n if (snapshot) {\n storage.writeCommunities(snapshot);\n console.error(\n `[ctxo] Community snapshot refreshed after ${changedCount} file change(s) (modularity ${snapshot.modularity.toFixed(3)})`,\n );\n }\n } catch (err) {\n console.error(`[ctxo] Community snapshot skipped: ${(err as Error).message}`);\n }\n }, COMMUNITY_SNAPSHOT_DEBOUNCE_MS);\n };\n\n const debouncedReindex = (filePath: string) => {\n const existing = pendingFiles.get(filePath);\n if (existing) clearTimeout(existing);\n\n pendingFiles.set(\n filePath,\n setTimeout(async () => {\n pendingFiles.delete(filePath);\n await reindexFile(filePath);\n pathsChangedSinceSnapshot.add(filePath);\n scheduleCommunitySnapshot();\n }, DEBOUNCE_MS),\n );\n };\n\n watcher.start((event, filePath) => {\n if (event === 'unlink') {\n const ext = extname(filePath).toLowerCase();\n if (!supportedExtensions.has(ext)) return;\n\n const relativePath = relative(this.projectRoot, filePath).replace(/\\\\/g, '/');\n writer.delete(relativePath);\n storage.deleteSymbolFile(relativePath);\n console.error(`[ctxo] Removed from index: ${relativePath}`);\n } else {\n debouncedReindex(filePath);\n }\n });\n\n console.error('[ctxo] Watching for file changes... (Ctrl+C to stop)');\n\n const cleanup = () => {\n console.error('\\n[ctxo] Stopping watcher...');\n for (const timeout of pendingFiles.values()) {\n clearTimeout(timeout);\n }\n if (communitySnapshotTimer) clearTimeout(communitySnapshotTimer);\n // Shutdown all keep-alive capabilities (dedup via Set over Map values)\n const uniques = new Set(keepAliveByExt.values());\n const shutdowns = Promise.all([...uniques].map((c) => c.dispose()));\n shutdowns.then(() => {\n watcher.stop().then(() => {\n storage.close();\n console.error('[ctxo] Watcher stopped');\n process.exit(0);\n });\n });\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n }\n\n}\n\n/** What a watch re-index gathers for one file, before it becomes a `FileIndex`. */\nexport interface WatchFileIndexParts {\n readonly lastModified: number;\n readonly contentHash: string;\n readonly symbols: readonly SymbolNode[];\n readonly edges: readonly GraphEdge[];\n readonly complexity: readonly ComplexityMetrics[];\n readonly intent: readonly CommitIntent[];\n readonly antiPatterns: readonly AntiPattern[];\n readonly facts?: readonly CodeFact[];\n}\n\n/**\n * The `FileIndex` a watch re-index writes. Symbols are kept whole, so annotations and offsets survive;\n * edges to `ns:` namespace placeholders are dropped; `facts` is set only when given.\n */\nexport function buildWatchFileIndex(file: string, parts: WatchFileIndexParts): FileIndex {\n const fileIndex: FileIndex = {\n file,\n lastModified: parts.lastModified,\n contentHash: parts.contentHash,\n symbols: [...parts.symbols],\n edges: parts.edges.filter((e) => !e.to.startsWith('ns:')),\n complexity: [...parts.complexity],\n intent: [...parts.intent],\n antiPatterns: [...parts.antiPatterns],\n };\n if (parts.facts) fileIndex.facts = [...parts.facts];\n return fileIndex;\n}\n\nexport function buildWatchCommunitySnapshot(\n storage: SqliteStorageAdapter,\n detectorOptions: CommunityDetectorOptions,\n): CommunitySnapshot | undefined {\n const symbols = storage.getAllSymbols();\n if (symbols.length === 0) return undefined;\n const edges = storage.getAllEdges();\n\n const graph = new SymbolGraph();\n for (const symbol of symbols) graph.addNode(symbol);\n for (const edge of edges) graph.addEdge(edge);\n\n const pagerank = new PageRankCalculator().calculate(graph, { limit: graph.nodeCount });\n const pagerankMap = new Map<string, number>();\n for (const entry of pagerank.rankings) pagerankMap.set(entry.symbolId, entry.score);\n\n const detector = new CommunityDetector(detectorOptions);\n const detectResult = detector.detect(graph, pagerankMap, 'full');\n\n return {\n version: 1,\n computedAt: new Date().toISOString(),\n commitSha: readHeadSha(),\n modularity: detectResult.modularity,\n communities: detectResult.communities,\n godNodes: detectResult.godNodes,\n edgeQuality: detectResult.edgeQuality,\n crossClusterEdges: detectResult.crossClusterEdges,\n };\n}\n\nfunction readHeadSha(): string {\n try {\n return execFileSync('git', ['rev-parse', '--short', 'HEAD'], { encoding: 'utf-8' }).trim();\n } catch {\n return 'nocommit';\n }\n}\n","import { watch, type FSWatcher } from 'chokidar';\nimport type { IWatcherPort, FileChangeHandler } from '../../ports/i-watcher-port.js';\n\nconst DEFAULT_IGNORED = [\n '**/node_modules/**',\n '**/.git/**',\n '**/.ctxo/**',\n '**/dist/**',\n '**/coverage/**',\n];\n\nexport class ChokidarWatcherAdapter implements IWatcherPort {\n private readonly projectRoot: string;\n private readonly ignored: string[];\n private watcher: FSWatcher | undefined;\n\n constructor(projectRoot: string, ignored?: string[]) {\n this.projectRoot = projectRoot;\n this.ignored = ignored ?? DEFAULT_IGNORED;\n }\n\n start(handler: FileChangeHandler): void {\n if (this.watcher) {\n throw new Error('Watcher already started. Call stop() before starting again.');\n }\n\n this.watcher = watch(this.projectRoot, {\n ignored: this.ignored,\n persistent: true,\n ignoreInitial: true,\n });\n\n this.watcher.on('add', (path) => handler('add', path));\n this.watcher.on('change', (path) => handler('change', path));\n this.watcher.on('unlink', (path) => handler('unlink', path));\n }\n\n async stop(): Promise<void> {\n if (this.watcher) {\n await this.watcher.close();\n this.watcher = undefined;\n }\n }\n}\n","import { join } from 'node:path';\nimport { existsSync, readFileSync } from 'node:fs';\nimport initSqlJs from 'sql.js';\nimport { SessionRecorderAdapter } from '../adapters/stats/session-recorder-adapter.js';\nimport type { AggregatedStats } from '../ports/i-session-recorder-port.js';\nimport type { StatsReport } from '../core/stats/stats-types.js';\n\nexport class StatsCommand {\n private readonly ctxoRoot: string;\n\n constructor(projectRoot: string) {\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n async run(options: { days?: number; json?: boolean; clear?: boolean }): Promise<void> {\n // Check if stats are enabled\n if (!this.isStatsEnabled()) {\n console.error('[ctxo] Stats collection is disabled in .ctxo/config.yaml');\n return;\n }\n\n const dbPath = join(this.ctxoRoot, '.cache', 'symbols.db');\n if (!existsSync(dbPath)) {\n if (options.json) {\n process.stdout.write(JSON.stringify(this.emptyReport(options.days)) + '\\n');\n } else {\n console.error('[ctxo] No usage data yet. Start using Ctxo MCP tools to collect stats.');\n }\n return;\n }\n\n // Open DB\n const SQL = await initSqlJs();\n const buffer = readFileSync(dbPath);\n const db = new SQL.Database(buffer);\n const recorder = new SessionRecorderAdapter(db);\n\n try {\n if (options.clear) {\n recorder.clear();\n // Persist cleared DB\n const data = db.export();\n const { writeFileSync } = await import('node:fs');\n writeFileSync(dbPath, Buffer.from(data));\n console.error('[ctxo] Session data cleared.');\n return;\n }\n\n // Validate --days\n if (options.days != null) {\n if (!Number.isInteger(options.days) || options.days <= 0) {\n console.error('[ctxo] --days must be a positive integer');\n process.exit(1);\n return;\n }\n }\n\n const stats = recorder.queryStats(options.days);\n\n if (stats.totalCalls === 0) {\n if (options.json) {\n process.stdout.write(JSON.stringify(this.emptyReport(options.days)) + '\\n');\n } else {\n console.error('[ctxo] No usage data yet. Start using Ctxo MCP tools to collect stats.');\n }\n return;\n }\n\n if (options.json) {\n process.stdout.write(JSON.stringify(this.buildReport(stats, options.days), null, 2) + '\\n');\n } else {\n this.printHumanReadable(stats, options.days);\n }\n } finally {\n db.close();\n }\n }\n\n private isStatsEnabled(): boolean {\n const configPath = join(this.ctxoRoot, 'config.yaml');\n if (!existsSync(configPath)) return true;\n\n try {\n const raw = readFileSync(configPath, 'utf-8');\n const match = raw.match(/stats:\\s*\\n\\s*enabled:\\s*(true|false)/);\n if (match) return match[1] !== 'false';\n return true;\n } catch {\n return true;\n }\n }\n\n private buildReport(stats: AggregatedStats, days?: number): StatsReport {\n const now = new Date().toISOString();\n const from = days != null\n ? new Date(Date.now() - days * 86400000).toISOString()\n : null;\n\n return {\n timeRange: { from, to: now, daysFilter: days ?? null },\n summary: {\n totalCalls: stats.totalCalls,\n totalTokensServed: stats.totalTokensServed,\n },\n topTools: stats.topTools,\n topSymbols: stats.topSymbols,\n detailLevelDistribution: stats.detailLevelDistribution.map((d) => ({\n level: d.level,\n count: d.count,\n percentage: d.percentage,\n })),\n };\n }\n\n private emptyReport(days?: number): StatsReport {\n return this.buildReport({\n totalCalls: 0,\n totalTokensServed: 0,\n topTools: [],\n topSymbols: [],\n detailLevelDistribution: [],\n }, days);\n }\n\n private printHumanReadable(stats: AggregatedStats, days?: number): void {\n const header = days != null ? `last ${days} days` : 'all time';\n\n console.error('');\n console.error(` Usage Summary (${header})`);\n console.error(' ────────────────────────────────────────');\n console.error(` Total tool calls: ${this.formatNumber(stats.totalCalls)}`);\n console.error(` Total tokens served: ${this.formatTokens(stats.totalTokensServed)}`);\n\n if (stats.topTools.length > 0) {\n console.error('');\n console.error(' Top Tools');\n console.error(' ────────────────────────────────────────');\n for (const t of stats.topTools) {\n const name = t.tool.padEnd(24);\n const calls = `${this.formatNumber(t.calls)} calls`.padEnd(14);\n console.error(` ${name}${calls}avg ${this.formatNumber(t.avgTokens)} tokens`);\n }\n }\n\n if (stats.topSymbols.length > 0) {\n console.error('');\n console.error(' Top Queried Symbols');\n console.error(' ────────────────────────────────────────');\n for (const s of stats.topSymbols) {\n const name = s.name.padEnd(32);\n console.error(` ${name}${this.formatNumber(s.queries)} queries`);\n }\n }\n\n if (stats.detailLevelDistribution.length > 0) {\n console.error('');\n console.error(' Detail Level Distribution');\n console.error(' ────────────────────────────────────────');\n for (const d of stats.detailLevelDistribution) {\n const bar = this.renderBar(d.percentage);\n const pct = `${d.percentage}%`.padStart(4);\n console.error(` ${d.level}: ${bar} ${pct}`);\n }\n }\n\n console.error('');\n }\n\n private renderBar(percentage: number): string {\n const filled = Math.round(percentage / 10);\n const empty = 10 - filled;\n return '█'.repeat(filled) + '░'.repeat(empty);\n }\n\n private formatNumber(n: number): string {\n return n.toLocaleString('en-US');\n }\n\n private formatTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return String(n);\n }\n}\n","import { join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport type { IHealthCheck } from '../core/diagnostics/types.js';\nimport { JsonIndexReader } from '../adapters/storage/json-index-reader.js';\nimport { HealthChecker } from '../adapters/diagnostics/health-checker.js';\nimport { DoctorReporter } from '../adapters/diagnostics/doctor-reporter.js';\nimport { NodeVersionCheck, TsMorphCheck, TreeSitterCheck } from '../adapters/diagnostics/checks/runtime-check.js';\nimport { VersionsCheck } from '../adapters/diagnostics/checks/versions-check.js';\nimport { LanguageCoverageCheck } from '../adapters/diagnostics/checks/language-coverage-check.js';\nimport { JavaTierCheck } from '../adapters/diagnostics/checks/java-tier-check.js';\nimport { CSharpTierCheck } from '../adapters/diagnostics/checks/csharp-tier-check.js';\nimport { GitBinaryCheck, GitRepoCheck, GitHooksCheck } from '../adapters/diagnostics/checks/git-check.js';\nimport { AiRulesCheck, SkillsCheck, ClaudeGuardHookCheck } from '../adapters/diagnostics/checks/agent-setup-check.js';\nimport {\n IndexDirectoryCheck,\n IndexFreshnessCheck,\n SymbolCountCheck,\n EdgeCountCheck,\n OrphanedFilesCheck,\n CoChangesCacheCheck,\n SchemaVersionCheck,\n} from '../adapters/diagnostics/checks/index-check.js';\nimport { SqliteCacheCheck } from '../adapters/diagnostics/checks/storage-check.js';\nimport { ConfigFileCheck } from '../adapters/diagnostics/checks/config-check.js';\nimport { DiskUsageCheck } from '../adapters/diagnostics/checks/disk-check.js';\nimport { applyFixes, formatFixReport } from './doctor-fix.js';\n\nexport interface DoctorOptions {\n json?: boolean;\n quiet?: boolean;\n fix?: boolean;\n dryRun?: boolean;\n yes?: boolean;\n}\n\nexport class DoctorCommand {\n private readonly projectRoot: string;\n private readonly ctxoRoot: string;\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n async run(options: DoctorOptions = {}): Promise<void> {\n const { getVersion } = await import('./cli-router.js');\n console.error(`ctxo v${getVersion()} — health check\\n`);\n\n const checks: IHealthCheck[] = [\n new VersionsCheck(),\n new NodeVersionCheck(),\n new GitBinaryCheck(),\n new GitRepoCheck(),\n new GitHooksCheck(),\n new AiRulesCheck(),\n new SkillsCheck(),\n new ClaudeGuardHookCheck(),\n new IndexDirectoryCheck(),\n new IndexFreshnessCheck(),\n new SqliteCacheCheck(),\n new ConfigFileCheck(),\n new TsMorphCheck(),\n new TreeSitterCheck(),\n new LanguageCoverageCheck(),\n new JavaTierCheck(),\n new CSharpTierCheck(),\n new DiskUsageCheck(),\n new SymbolCountCheck(),\n new EdgeCountCheck(),\n new OrphanedFilesCheck(),\n new CoChangesCacheCheck(),\n new SchemaVersionCheck(),\n ];\n\n // Pre-load index once — shared by all index-related checks (avoids 5x redundant readAll)\n const indexDir = join(this.ctxoRoot, 'index');\n const indices = existsSync(indexDir)\n ? new JsonIndexReader(this.ctxoRoot).readAll()\n : [];\n\n const checker = new HealthChecker(checks, { quiet: Boolean(options.quiet) });\n const report = await checker.runAll({\n projectRoot: this.projectRoot,\n ctxoRoot: this.ctxoRoot,\n indices,\n });\n\n const reporter = new DoctorReporter();\n let output: string;\n\n if (options.json) {\n output = reporter.formatJson(report);\n process.stdout.write(output + '\\n');\n } else if (options.quiet) {\n output = reporter.formatQuiet(report);\n console.error(output);\n } else {\n output = reporter.formatHuman(report);\n console.error(output);\n }\n\n if (options.fix) {\n console.error('');\n console.error(options.dryRun ? '[ctxo] --fix --dry-run: planned actions' : '[ctxo] --fix: applying remediation');\n const fixReport = await applyFixes(report, {\n projectRoot: this.projectRoot,\n ctxoRoot: this.ctxoRoot,\n yes: options.yes,\n dryRun: options.dryRun,\n });\n console.error(formatFixReport(fixReport));\n if (fixReport.halted) {\n process.exitCode = 2;\n }\n return;\n }\n\n if (report.exitCode !== 0) {\n process.exitCode = 1;\n }\n }\n}\n","import { createLogger } from '../../core/logger.js';\nimport type { IHealthCheck, CheckContext, CheckResult, DoctorReport } from '../../core/diagnostics/types.js';\n\nconst log = createLogger('ctxo:doctor');\n\nexport interface HealthCheckerOptions {\n /** Suppress all per-check logger lines. The reporter still prints WARN/FAIL lines, so operators see them without the duplicated `[ctxo:doctor] ...` logger stream. */\n readonly quiet?: boolean;\n}\n\nexport class HealthChecker {\n private readonly checks: IHealthCheck[];\n private readonly quiet: boolean;\n\n constructor(checks: IHealthCheck[], options: HealthCheckerOptions = {}) {\n this.checks = checks;\n this.quiet = options.quiet ?? false;\n }\n\n async runAll(ctx: CheckContext): Promise<DoctorReport> {\n const settled = await Promise.allSettled(\n this.checks.map(check => check.run(ctx)),\n );\n\n const results: CheckResult[] = settled.map((outcome, i) => {\n const check = this.checks[i]!;\n if (outcome.status === 'fulfilled') {\n const r = outcome.value;\n if (!this.quiet) {\n log.info(`${r.id}: ${r.status.toUpperCase()} (${r.message})`);\n }\n return r;\n }\n const message = (outcome.reason as Error)?.message ?? 'Unknown error';\n if (!this.quiet) log.error(`${check.id}: FAIL (${message})`);\n return {\n id: check.id,\n title: check.title,\n status: 'fail' as const,\n message: `Check crashed: ${message}`,\n };\n });\n\n const summary = {\n pass: results.filter(r => r.status === 'pass').length,\n warn: results.filter(r => r.status === 'warn').length,\n fail: results.filter(r => r.status === 'fail').length,\n };\n\n const exitCode = summary.fail > 0 ? 1 as const : 0 as const;\n\n return { checks: results, summary, exitCode };\n }\n}\n","import type { DoctorReport, CheckResult } from '../../core/diagnostics/types.js';\n\nconst ICONS: Record<string, string> = {\n pass: '✓',\n warn: '⚠',\n fail: '✗',\n};\n\nexport class DoctorReporter {\n formatHuman(report: DoctorReport): string {\n const lines: string[] = ['ctxo doctor — Health Check', ''];\n\n for (const check of report.checks) {\n lines.push(this.formatCheckLine(check));\n }\n\n lines.push('');\n lines.push(` Summary: ${report.summary.pass} passed, ${report.summary.warn} warnings, ${report.summary.fail} failures`);\n\n return lines.join('\\n');\n }\n\n formatQuiet(report: DoctorReport): string {\n const lines: string[] = [];\n\n for (const check of report.checks) {\n if (check.status === 'warn' || check.status === 'fail') {\n lines.push(this.formatCheckLine(check));\n }\n }\n\n if (lines.length > 0) lines.push('');\n lines.push(` Summary: ${report.summary.pass} passed, ${report.summary.warn} warnings, ${report.summary.fail} failures`);\n\n return lines.join('\\n');\n }\n\n formatJson(report: DoctorReport): string {\n return JSON.stringify({\n checks: report.checks.map(c => ({\n name: c.id,\n status: c.status,\n value: c.value ?? null,\n message: c.message,\n ...(c.fix ? { fix: c.fix } : {}),\n })),\n summary: report.summary,\n exitCode: report.exitCode,\n }, null, 2);\n }\n\n private formatCheckLine(check: CheckResult): string {\n const icon = ICONS[check.status] ?? '?';\n const title = check.title.padEnd(24);\n const suffix = check.fix ? ` (${check.fix})` : '';\n return ` ${icon} ${title} ${check.message}${suffix}`;\n }\n}\n","import { createRequire } from 'node:module';\nimport type { IHealthCheck, CheckResult, CheckContext } from '../../../core/diagnostics/types.js';\n\nconst require = createRequire(import.meta.url);\n\nfunction pass(id: string, title: string, message: string): CheckResult {\n return { id, title, status: 'pass', message };\n}\nfunction warn(id: string, title: string, message: string, fix: string): CheckResult {\n return { id, title, status: 'warn', message, fix };\n}\n\nexport function checkNodeVersion(version: string): CheckResult {\n const id = 'node_version';\n const title = 'Node.js version';\n const major = parseInt(version.slice(1).split('.')[0] ?? '0', 10);\n if (major >= 20) return { id, title, status: 'pass', message: `Node.js ${version} (required: ≥20)`, value: version };\n if (major >= 18) return { id, title, status: 'warn', message: `Node.js ${version} — v20+ recommended`, fix: 'Upgrade to Node.js 20 or later', value: version };\n return { id, title, status: 'fail', message: `Node.js ${version} — v20+ required`, fix: 'Upgrade to Node.js 20 or later', value: version };\n}\n\nexport class NodeVersionCheck implements IHealthCheck {\n readonly id = 'node_version';\n readonly title = 'Node.js version';\n\n async run(_ctx: CheckContext): Promise<CheckResult> {\n return checkNodeVersion(process.version);\n }\n}\n\nexport class TsMorphCheck implements IHealthCheck {\n readonly id = 'ts_morph';\n readonly title = 'TypeScript plugin (@ctxo/lang-typescript)';\n\n async run(_ctx: CheckContext): Promise<CheckResult> {\n if (tryResolve('@ctxo/lang-typescript')) {\n return pass(this.id, this.title, 'available');\n }\n return warn(\n this.id,\n this.title,\n '@ctxo/lang-typescript not installed — TypeScript/JavaScript indexing disabled',\n 'Run \"npm install @ctxo/lang-typescript\" (or \"ctxo install typescript\")',\n );\n }\n}\n\nexport class TreeSitterCheck implements IHealthCheck {\n readonly id = 'tree_sitter';\n readonly title = 'Go / C# plugins (@ctxo/lang-go, @ctxo/lang-csharp)';\n\n async run(_ctx: CheckContext): Promise<CheckResult> {\n const goOk = tryResolve('@ctxo/lang-go');\n const csOk = tryResolve('@ctxo/lang-csharp');\n if (goOk && csOk) return pass(this.id, this.title, 'both plugins available');\n if (goOk || csOk) {\n const missing = goOk ? '@ctxo/lang-csharp' : '@ctxo/lang-go';\n return warn(\n this.id,\n this.title,\n `${missing} not installed`,\n `Run \"npm install ${missing}\" (or \"ctxo install ${missing === '@ctxo/lang-go' ? 'go' : 'csharp'}\")`,\n );\n }\n return warn(\n this.id,\n this.title,\n 'No Go/C# plugin installed — extended language indexing disabled',\n 'Run \"npm install @ctxo/lang-go @ctxo/lang-csharp\"',\n );\n }\n}\n\nfunction tryResolve(packageName: string): boolean {\n try {\n // Resolve package.json instead of the entry so \"exports: import-only\"\n // packages (all @ctxo/lang-* plugins) still register as installed.\n require.resolve(`${packageName}/package.json`);\n return true;\n } catch {\n return false;\n }\n}\n","import { SUPPORTED_API_VERSIONS } from '@ctxo/plugin-api';\nimport type { CtxoLanguagePlugin } from '@ctxo/plugin-api';\nimport { getVersion } from './cli-router.js';\nimport { discoverPlugins, type DiscoveredPlugin } from '../adapters/language/plugin-discovery.js';\nimport { loadManifestPath } from './plugin-loader.js';\n\nconst NEWEST_API_VERSION: string = SUPPORTED_API_VERSIONS[SUPPORTED_API_VERSIONS.length - 1]!;\n\nexport interface PluginVersionInfo {\n /** npm package name, e.g. \"@ctxo/lang-typescript\" or community \"ctxo-lang-kotlin\" */\n name: string;\n /** Plugin id from the runtime declaration, e.g. \"typescript\" */\n id: string;\n /** Runtime-declared plugin version */\n version: string;\n /** Plugin protocol version declared by the plugin */\n apiVersion: string;\n /** True when apiVersion is one of the core's SUPPORTED_API_VERSIONS */\n compatible: boolean;\n}\n\nexport interface RuntimeInfo {\n node: string;\n platform: NodeJS.Platform;\n arch: string;\n}\n\nexport interface VersionInfo {\n ctxo: string;\n /** The newest protocol version the core supports. */\n pluginApiVersion: string;\n /** Every protocol version the core loads. */\n pluginApiVersions: readonly string[];\n plugins: PluginVersionInfo[];\n runtime: RuntimeInfo;\n}\n\n/**\n * Produce VersionInfo from already-discovered plugins. Pure function; safe to\n * call without I/O once plugins are in hand. Used by both CLI printers and tests.\n */\nexport function gatherVersionInfo(discovered: readonly DiscoveredPlugin[]): VersionInfo {\n const plugins: PluginVersionInfo[] = discovered.map(({ plugin, specifier }) => ({\n name: specifier,\n id: plugin.id,\n version: plugin.version,\n apiVersion: plugin.apiVersion,\n compatible: (SUPPORTED_API_VERSIONS as readonly string[]).includes(plugin.apiVersion),\n }));\n\n return {\n ctxo: getVersion(),\n pluginApiVersion: NEWEST_API_VERSION,\n pluginApiVersions: SUPPORTED_API_VERSIONS,\n plugins,\n runtime: {\n node: process.version,\n platform: process.platform,\n arch: process.arch,\n },\n };\n}\n\nexport function formatShort(info: VersionInfo): string {\n return `ctxo ${info.ctxo}`;\n}\n\nexport function formatVerbose(info: VersionInfo): string {\n const lines: string[] = [];\n lines.push(`ctxo ${info.ctxo}`);\n lines.push(`Plugin API: ${info.pluginApiVersions.join(', ')}`);\n lines.push(`Runtime: Node ${info.runtime.node} on ${info.runtime.platform}/${info.runtime.arch}`);\n lines.push('');\n if (info.plugins.length === 0) {\n lines.push('Plugins: (none installed)');\n lines.push('');\n lines.push('Install a language plugin, e.g. \"npm i -D @ctxo/lang-typescript\"');\n return lines.join('\\n');\n }\n\n const nameCol = Math.max(7, ...info.plugins.map((p) => p.name.length));\n const verCol = Math.max(7, ...info.plugins.map((p) => p.version.length));\n const apiCol = Math.max(3, ...info.plugins.map((p) => p.apiVersion.length));\n\n lines.push(`Plugins: ${info.plugins.length} installed`);\n lines.push(\n ` ${'NAME'.padEnd(nameCol)} ${'VERSION'.padEnd(verCol)} ${'API'.padEnd(apiCol)} STATUS`,\n );\n for (const p of info.plugins) {\n const status = p.compatible ? 'OK' : `incompatible (core supports ${info.pluginApiVersions.join(', ')})`;\n lines.push(\n ` ${p.name.padEnd(nameCol)} ${p.version.padEnd(verCol)} ${p.apiVersion.padEnd(apiCol)} ${status}`,\n );\n }\n\n return lines.join('\\n');\n}\n\nexport function formatJson(info: VersionInfo): string {\n return JSON.stringify(info, null, 2);\n}\n\nexport interface VersionOptions {\n verbose?: boolean;\n json?: boolean;\n}\n\n/**\n * CLI entry. Keeps I/O scoped to plugin-discovery metadata reads; no adapter\n * instantiation, no network. Verbose and JSON modes target sub-200ms even with\n * several plugins installed because discovery only reads package.json plus a\n * single dynamic import() per plugin module (no createAdapter call).\n */\nexport class VersionCommand {\n constructor(private readonly projectRoot: string) {}\n\n async run(options: VersionOptions = {}): Promise<void> {\n const info = await this.collect();\n if (options.json) {\n process.stdout.write(formatJson(info) + '\\n');\n return;\n }\n if (options.verbose) {\n process.stdout.write(formatVerbose(info) + '\\n');\n return;\n }\n process.stdout.write(formatShort(info) + '\\n');\n }\n\n private async collect(): Promise<VersionInfo> {\n const manifestPath = loadManifestPath(this.projectRoot);\n if (!manifestPath) {\n return gatherVersionInfo([]);\n }\n const { plugins } = await discoverPlugins({ manifestPath });\n return gatherVersionInfo(plugins);\n }\n}\n\n/**\n * Treat a CtxoLanguagePlugin-shaped object directly (escape hatch for callers\n * that have plugins in memory, e.g. indexCommand after wiring the registry).\n */\nexport function gatherFromLivePlugins(\n live: ReadonlyArray<{ plugin: CtxoLanguagePlugin; specifier: string }>,\n): VersionInfo {\n return gatherVersionInfo(live);\n}\n","import type { IHealthCheck, CheckContext, CheckResult } from '../../../core/diagnostics/types.js';\nimport {\n gatherVersionInfo,\n formatVerbose,\n type VersionInfo,\n} from '../../../cli/version-command.js';\nimport { discoverPlugins } from '../../language/plugin-discovery.js';\nimport { loadManifestPath } from '../../../cli/plugin-loader.js';\n\n/**\n * Surfaces ctxo + plugin + runtime versions in `ctxo doctor` output. Warns when\n * a plugin declares an apiVersion the core does not support. Purely informational\n * in the pass-case; the doctor report summary already treats warn as non-zero.\n */\nexport class VersionsCheck implements IHealthCheck {\n readonly id = 'versions';\n readonly title = 'Versions';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const info = await collectInfo(ctx);\n\n const incompatible = info.plugins.filter((p) => !p.compatible);\n const message = buildSummary(info);\n\n if (incompatible.length > 0) {\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message,\n fix: `Upgrade or replace plugins whose apiVersion is not one of ${info.pluginApiVersions.join(', ')}: ${incompatible.map((p) => p.name).join(', ')}`,\n value: formatVerbose(info),\n };\n }\n\n return {\n id: this.id,\n title: this.title,\n status: 'pass',\n message,\n value: formatVerbose(info),\n };\n }\n}\n\nasync function collectInfo(ctx: CheckContext): Promise<VersionInfo> {\n const manifestPath = loadManifestPath(ctx.projectRoot);\n if (!manifestPath) return gatherVersionInfo([]);\n const { plugins } = await discoverPlugins({ manifestPath });\n return gatherVersionInfo(plugins);\n}\n\nfunction buildSummary(info: VersionInfo): string {\n const pluginCount = info.plugins.length;\n const pluginLabel = pluginCount === 0 ? 'no plugins' : `${pluginCount} plugin${pluginCount === 1 ? '' : 's'}`;\n return `ctxo ${info.ctxo} (API ${info.pluginApiVersions.join(', ')}) - ${pluginLabel}, Node ${info.runtime.node}`;\n}\n","import { createRequire } from 'node:module';\nimport type { IHealthCheck, CheckContext, CheckResult } from '../../../core/diagnostics/types.js';\nimport {\n decideNeededLanguages,\n detectLanguages,\n officialPluginFor,\n type KnownLanguage,\n} from '../../../core/detection/detect-languages.js';\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Reports which detected languages lack an installed plugin. Warns (never fails)\n * so mixed-language projects can still run ctxo for the subset with plugins.\n */\nexport class LanguageCoverageCheck implements IHealthCheck {\n readonly id = 'language_coverage';\n readonly title = 'Language coverage';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const detection = detectLanguages(ctx.projectRoot);\n const needed = decideNeededLanguages(detection);\n\n if (needed.length === 0) {\n return {\n id: this.id,\n title: this.title,\n status: 'pass',\n message: 'no source languages detected',\n };\n }\n\n const missing: KnownLanguage[] = [];\n for (const lang of needed) {\n if (!pluginResolves(officialPluginFor(lang))) {\n missing.push(lang);\n }\n }\n\n if (missing.length === 0) {\n const summary = needed.map((l) => `${l}`).join(', ');\n return {\n id: this.id,\n title: this.title,\n status: 'pass',\n message: `plugins installed for: ${summary}`,\n };\n }\n\n const packages = [...new Set(missing.map(officialPluginFor))].join(' ');\n const shortList = missing.join(', ');\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message: `missing plugins for: ${shortList}`,\n fix: `Run \"ctxo install ${missing.join(' ')}\" or \"npm install -D ${packages}\"`,\n };\n }\n}\n\nfunction pluginResolves(packageName: string): boolean {\n try {\n // Resolve package.json instead of the entry point so we don't trip over\n // ESM `exports` fields that refuse CJS require (our own plugins do this).\n require.resolve(`${packageName}/package.json`);\n return true;\n } catch {\n return false;\n }\n}\n","import { createRequire } from 'node:module';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport type { IHealthCheck, CheckContext, CheckResult } from '../../../core/diagnostics/types.js';\nimport { detectJavaMajor } from '../../../core/detection/detect-java-runtime.js';\n\nconst require = createRequire(import.meta.url);\n\nexport interface JavaTierInputs {\n hasJava: boolean;\n jreMajor: number | undefined;\n analyzerInstalled: boolean;\n}\n\n/** Pure decision: map (java-present, jre, analyzer) -> CheckResult. */\nexport function evaluateJavaTier(i: JavaTierInputs): CheckResult {\n const id = 'java_tier';\n const title = 'Java analysis tier';\n\n if (!i.hasJava) {\n return { id, title, status: 'pass', message: 'no Java sources detected' };\n }\n\n const jreOk = (i.jreMajor ?? 0) >= 11;\n const jarVariant = (i.jreMajor ?? 0) >= 17 ? 'java17' : 'java11';\n\n if (jreOk && i.analyzerInstalled) {\n return { id, title, status: 'pass', message: `full tier (JRE ${i.jreMajor}, ${jarVariant} analyzer installed)` };\n }\n\n if (jreOk && !i.analyzerInstalled) {\n return {\n id,\n title,\n status: 'warn',\n message: `syntax tier (JRE ${i.jreMajor} present, analyzer missing)`,\n fix: 'Run \"ctxo install java --full-tier\" for resolved call/use edges',\n };\n }\n\n if (!jreOk && i.analyzerInstalled) {\n return {\n id,\n title,\n status: 'warn',\n message: 'syntax tier (analyzer installed but no JRE 11+)',\n fix: 'Install a JRE 11+ and ensure it is on PATH (or set JAVA_HOME)',\n };\n }\n\n // No JRE >=11, no analyzer — syntax tier only, no nag\n return {\n id,\n title,\n status: 'pass',\n message: 'syntax tier (install JRE 11+ and run \"ctxo install java --full-tier\" for full tier)',\n };\n}\n\n/**\n * Returns true only when the @ctxo/lang-java-analyzer package is installed\n * AND its actual JAR file (`jar/ctxo-jdt-analyzer.jar`) exists on disk.\n * A package-only install without a built/extracted jar is not sufficient for\n * the full-tier indexer — doctor must reflect that accurately.\n */\nexport function analyzerJarPresent(): boolean {\n try {\n const pkgJson = require.resolve('@ctxo/lang-java-analyzer/package.json');\n const jarDir = join(dirname(pkgJson), 'jar');\n // Accept either variant — at least one must exist for the full tier to be usable\n return existsSync(join(jarDir, 'ctxo-jdt-analyzer-11.jar'))\n || existsSync(join(jarDir, 'ctxo-jdt-analyzer-17.jar'));\n } catch {\n return false;\n }\n}\n\n/** Directories that should never be descended into during a source scan (`obj` holds .NET build output). */\nconst SKIP_DIRS = new Set([\n 'node_modules', 'target', 'build', 'out', 'bin', 'obj',\n '.git', '.ctxo', 'dist', 'coverage',\n]);\n\n/**\n * Shallow-bounded recursive search for any `.java` file under `root`.\n * See findSourceFile for the bounds.\n */\nexport function findJavaFile(root: string, maxDepth: number): boolean {\n return findSourceFile(root, '.java', maxDepth);\n}\n\n/**\n * Shallow-bounded recursive search for any file ending in `extension` under `root`.\n * Descends at most `maxDepth` directory levels (root = depth 0), skipping\n * SKIP_DIRS at every level. Stops and returns true as soon as one file is\n * found to keep the work bounded.\n *\n * Uses Dirent entries — no extra stat calls. Symlinked entries (both files\n * and directories) are skipped entirely to avoid following loops.\n */\nexport function findSourceFile(root: string, extension: string, maxDepth: number): boolean {\n function walk(dir: string, depth: number): boolean {\n let entries: import('node:fs').Dirent[];\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return false;\n }\n for (const entry of entries) {\n if (entry.isSymbolicLink()) continue; // never follow symlinks\n if (entry.isFile() && entry.name.endsWith(extension)) return true;\n }\n if (depth >= maxDepth) return false;\n for (const entry of entries) {\n if (entry.isSymbolicLink()) continue;\n if (entry.isDirectory() && !SKIP_DIRS.has(entry.name)) {\n if (walk(join(dir, entry.name), depth + 1)) return true;\n }\n }\n return false;\n }\n return walk(root, 0);\n}\n\nfunction projectHasJava(root: string): boolean {\n for (const f of ['pom.xml', 'build.gradle', 'build.gradle.kts']) {\n if (existsSync(join(root, f))) return true;\n }\n return findJavaFile(root, 4);\n}\n\nexport class JavaTierCheck implements IHealthCheck {\n readonly id = 'java_tier';\n readonly title = 'Java analysis tier';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n return evaluateJavaTier({\n hasJava: projectHasJava(ctx.projectRoot),\n jreMajor: detectJavaMajor(),\n analyzerInstalled: analyzerJarPresent(),\n });\n }\n}\n","import { createRequire } from 'node:module';\nimport { spawnSync } from 'node:child_process';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { join, dirname } from 'node:path';\nimport type { IHealthCheck, CheckContext, CheckResult } from '../../../core/diagnostics/types.js';\nimport { detectDotnetSdkVersion, parseDotnetSdkMajor } from '../../../core/detection/detect-dotnet-sdk.js';\nimport { resolvePluginPackageJson } from '../../language/plugin-discovery.js';\nimport { findSourceFile } from './java-tier-check.js';\n\n/** Restoring the helper can download the Roslyn and ScriptDom packages on a cold cache. */\nconst RESTORE_TIMEOUT_MS = 120_000;\nconst MAX_MESSAGE_LENGTH = 200;\n\nexport interface CSharpTierInputs {\n hasCSharp: boolean;\n sdkVersion: string | undefined;\n /** Absolute path of ctxo-roslyn.csproj, or null. */\n helperProject: string | null;\n /** Null when not probed. */\n restore: { ok: boolean; message?: string } | null;\n}\n\n/** Pure decision: map (C#-present, SDK, helper, restore probe) -> CheckResult. */\nexport function evaluateCSharpTier(i: CSharpTierInputs): CheckResult {\n const id = 'csharp_tier';\n const title = 'C# analysis tier';\n\n if (!i.hasCSharp) {\n return { id, title, status: 'pass', message: 'no C# sources detected' };\n }\n\n // No .NET 8+ SDK: syntax tier only, no nag (like Java without a JRE)\n const sdkMajor = i.sdkVersion === undefined ? undefined : parseDotnetSdkMajor(i.sdkVersion);\n if ((sdkMajor ?? 0) < 8) {\n return { id, title, status: 'pass', message: 'syntax tier (install the .NET 8+ SDK for the full tier)' };\n }\n\n // language_coverage already warns about a missing plugin\n if (i.helperProject === null) {\n return { id, title, status: 'pass', message: 'syntax tier (@ctxo/lang-csharp not installed)' };\n }\n\n // Null means the restore was not probed, so the message claims no restore.\n if (i.restore === null) {\n return { id, title, status: 'pass', message: `full tier (.NET SDK ${i.sdkVersion})` };\n }\n if (i.restore.ok) {\n return { id, title, status: 'pass', message: `full tier (.NET SDK ${i.sdkVersion}, Roslyn helper restores)` };\n }\n\n return {\n id,\n title,\n status: 'warn',\n message: `syntax tier: the Roslyn helper could not restore (${i.restore.message ?? 'unknown error'})`,\n fix: 'Make Microsoft.SqlServer.TransactSql.ScriptDom and the Microsoft.CodeAnalysis packages reachable from your NuGet sources (nuget.org or a mirror), then run \"ctxo index\"',\n };\n}\n\n/** `path` written with backslashes and with forward slashes (MSBuild may print either). */\nfunction separatorVariants(path: string): string[] {\n return [...new Set([path, path.replace(/\\//g, '\\\\'), path.replace(/\\\\/g, '/')])];\n}\n\n/** A Windows path: a drive letter or a UNC prefix. Windows paths compare without case. */\nfunction isWindowsPath(path: string): boolean {\n return /^[A-Za-z]:[\\\\/]/.test(path) || path.startsWith('\\\\\\\\');\n}\n\n/** Every occurrence of `search` in `text` replaced by `replacement`; ignoring case when `ignoreCase` is set. */\nfunction replaceAll(text: string, search: string, replacement: string, ignoreCase: boolean): string {\n if (!ignoreCase) return text.split(search).join(replacement);\n const pattern = new RegExp(search.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n return text.replace(pattern, () => replacement);\n}\n\n/**\n * Replaces the helper project's absolute path with `ctxo-roslyn.csproj`, then\n * its directory with `ctxo-roslyn`, so the restore message keeps the error,\n * not a long node_modules path. A Windows path matches in any letter case,\n * since MSBuild may print the drive letter or a folder in another case.\n */\nfunction withoutHelperPath(text: string, helperProject: string): string {\n const ignoreCase = isWindowsPath(helperProject);\n let out = text;\n for (const variant of separatorVariants(helperProject)) out = replaceAll(out, variant, 'ctxo-roslyn.csproj', ignoreCase);\n const helperDir = helperProject.replace(/[\\\\/][^\\\\/]*$/, '');\n if (helperDir && helperDir !== helperProject) {\n for (const variant of separatorVariants(helperDir)) out = replaceAll(out, variant, 'ctxo-roslyn', ignoreCase);\n }\n return out;\n}\n\n/** An MSBuild or NuGet error line: an `error NU1101`-style code or ` : error `, matched with case. */\nconst ERROR_LINE = /\\berror [A-Z]+\\d+\\b| : error /;\n\n/**\n * Why `dotnet restore` failed, trimmed and capped at 200 characters: the first\n * output line (stdout, then stderr) with an MSBuild error shape (`error NU1101`,\n * ` : error `), else the first line that contains \"error\" in any case;\n * `exit code <n>` when no line does, and `timed out` on a timeout. A warning\n * such as `warning NU1900: Error occurred ...` is therefore never picked over a\n * real error. The helper's absolute path is dropped from the output first.\n */\nexport function restoreFailureMessage(r: {\n stdout: string;\n stderr: string;\n status: number | null;\n timedOut: boolean;\n /** Absolute path of the ctxo-roslyn.csproj that was restored. */\n helperProject?: string;\n}): string {\n if (r.timedOut) return 'timed out';\n const strip = (text: string): string => (r.helperProject ? withoutHelperPath(text, r.helperProject) : text);\n const lines = [...strip(r.stdout).split(/\\r?\\n/), ...strip(r.stderr).split(/\\r?\\n/)];\n const line = lines.find((l) => ERROR_LINE.test(l)) ?? lines.find((l) => /error/i.test(l));\n if (line !== undefined) return line.trim().slice(0, MAX_MESSAGE_LENGTH);\n return `exit code ${r.status}`;\n}\n\n/**\n * The ctxo-roslyn.csproj of the @ctxo/lang-csharp the plugin loader would load, or null.\n * Resolved the way the loader resolves a plugin: from the project first, then from the\n * CLI's own location (a global install in a repository without a package.json, a dev build).\n */\nexport function resolveHelperProject(projectRoot: string): string | null {\n try {\n const requireFromProject = createRequire(join(projectRoot, 'package.json'));\n const pkgJson = resolvePluginPackageJson('@ctxo/lang-csharp', requireFromProject);\n const csproj = join(dirname(pkgJson), 'tools', 'ctxo-roslyn', 'ctxo-roslyn.csproj');\n return existsSync(csproj) ? csproj : null;\n } catch {\n return null;\n }\n}\n\n/** A .sln or .csproj at the root, or a .cs file within depth 4 (same bounds as the Java scan). */\nexport function projectHasCSharp(root: string): boolean {\n try {\n if (readdirSync(root).some((name) => name.endsWith('.sln') || name.endsWith('.csproj'))) return true;\n } catch {\n return false;\n }\n return findSourceFile(root, '.cs', 4);\n}\n\n/** `dotnet restore` of the helper: the probe for a NuGet feed the helper's packages cannot come from. */\nfunction probeRestore(helperProject: string): { ok: boolean; message?: string } {\n const r = spawnSync('dotnet', ['restore', helperProject, '--nologo', '-v', 'q'], {\n encoding: 'utf-8',\n timeout: RESTORE_TIMEOUT_MS,\n windowsHide: true,\n });\n if (!r.error && r.status === 0) return { ok: true };\n const timedOut = (r.error as NodeJS.ErrnoException | undefined)?.code === 'ETIMEDOUT';\n return {\n ok: false,\n message: restoreFailureMessage({\n stdout: r.stdout ?? '',\n stderr: `${r.stderr ?? ''}${r.error && !timedOut ? `\\nerror: ${r.error.message}` : ''}`,\n status: r.status,\n timedOut,\n helperProject,\n }),\n };\n}\n\nexport class CSharpTierCheck implements IHealthCheck {\n readonly id = 'csharp_tier';\n readonly title = 'C# analysis tier';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const hasCSharp = projectHasCSharp(ctx.projectRoot);\n // No dotnet process at all for a project without C#\n const sdkVersion = hasCSharp ? detectDotnetSdkVersion() : undefined;\n const helperProject = hasCSharp ? resolveHelperProject(ctx.projectRoot) : null;\n // The restore probe runs only when outcomes 1-3 (no C#, no .NET 8+ SDK, no plugin) do not apply.\n const sdkReady = (parseDotnetSdkMajor(sdkVersion ?? '') ?? 0) >= 8;\n const restore = hasCSharp && sdkReady && helperProject !== null ? probeRestore(helperProject) : null;\n return evaluateCSharpTier({ hasCSharp, sdkVersion, helperProject, restore });\n }\n}\n","import { spawnSync } from 'node:child_process';\n\n/** Major version of a `dotnet --version` string (`8.0.404` -> 8, `10.0.100-rc.1` -> 10). Pure/uncached. */\nexport function parseDotnetSdkMajor(version: string): number | undefined {\n const m = /^\\s*(\\d+)\\./.exec(version);\n if (!m) return undefined;\n const major = parseInt(m[1]!, 10);\n return Number.isNaN(major) ? undefined : major;\n}\n\n/** Module-level memo: undefined = not yet computed; null = computed as absent */\nlet _sdkVersionCache: string | null | undefined = undefined;\n\n/**\n * Spawn `dotnet --version` once and return the SDK version it prints, trimmed.\n * Returns undefined when dotnet is not on PATH, has no SDK (a runtime-only\n * install exits non-zero) or prints nothing. Always respects a 10 s timeout so\n * a hanging dotnet cannot stall the CLI.\n *\n * Result is memoized at module scope after the first spawn, so repeated calls\n * within the same process are free.\n */\nexport function detectDotnetSdkVersion(): string | undefined {\n if (_sdkVersionCache !== undefined) {\n // null sentinel means \"computed, result was undefined\"\n return _sdkVersionCache === null ? undefined : _sdkVersionCache;\n }\n\n const r = spawnSync('dotnet', ['--version'], {\n encoding: 'utf-8',\n timeout: 10_000,\n windowsHide: true,\n });\n const version = r.error || r.status !== 0 ? '' : (r.stdout ?? '').trim();\n _sdkVersionCache = version || null;\n return version || undefined;\n}\n\n/**\n * Reset the memoized SDK version. Intended for tests only: it lets\n * successive test cases start from a fresh detection.\n */\nexport function resetDotnetSdkCacheForTests(): void {\n _sdkVersionCache = undefined;\n}\n","import { execFileSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { IHealthCheck, CheckResult, CheckContext } from '../../../core/diagnostics/types.js';\nimport {\n POST_COMMIT_HOOK_VERSION,\n forwardSlashes,\n readCtxoBlockVersions,\n resolveHooksDir,\n sharedHooksScope,\n} from '../../../cli/git-hooks.js';\n\nexport class GitBinaryCheck implements IHealthCheck {\n readonly id = 'git_binary';\n readonly title = 'Git available';\n\n async run(_ctx: CheckContext): Promise<CheckResult> {\n try {\n const version = execFileSync('git', ['--version'], { encoding: 'utf-8' }).trim();\n return { id: this.id, title: this.title, status: 'pass', message: version, value: version };\n } catch {\n return { id: this.id, title: this.title, status: 'fail', message: 'git not found in PATH', fix: 'Install git and ensure it is in your PATH' };\n }\n }\n}\n\nexport class GitRepoCheck implements IHealthCheck {\n readonly id = 'git_repo';\n readonly title = 'Git repository';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n if (existsSync(join(ctx.projectRoot, '.git'))) {\n return { id: this.id, title: this.title, status: 'pass', message: ctx.projectRoot, value: ctx.projectRoot };\n }\n return { id: this.id, title: this.title, status: 'fail', message: 'Not a git repository', fix: 'Run \"git init\" or clone a repository' };\n }\n}\n\n/**\n * Reports whether the post-commit hook carries exactly one, current ctxo block. A missing, older\n * (the unversioned v1 block re-indexed once per changed file) or duplicated block is a warn;\n * `ctxo doctor --fix` and `ctxo init` repair it in place. When `core.hooksPath` comes from the\n * global or system git config the directory is shared by every repository and ctxo never writes\n * there, so the warn explains that and the fix is manual; a current block added by hand passes.\n */\nexport class GitHooksCheck implements IHealthCheck {\n readonly id = 'git_hooks';\n readonly title = 'Git hooks';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n // Without a repository there is nothing to install into; git_repo already reports that as a fail.\n if (!existsSync(join(ctx.projectRoot, '.git'))) {\n return { id: this.id, title: this.title, status: 'pass', message: 'Not a git repository (hooks not applicable)' };\n }\n\n const hooksDir = resolveHooksDir(ctx.projectRoot);\n const hookPath = join(hooksDir, 'post-commit');\n let versions: number[];\n try {\n versions = readCtxoBlockVersions(readFileSync(hookPath, 'utf-8'));\n } catch {\n versions = []; // no hook file (or unreadable): same as no ctxo block\n }\n\n const version = versions[0];\n if (versions.length === 1 && version !== undefined && version >= POST_COMMIT_HOOK_VERSION) {\n return {\n id: this.id,\n title: this.title,\n status: 'pass',\n message: `ctxo post-commit hook v${version}`,\n value: `v${version}`,\n };\n }\n\n const sharedScope = sharedHooksScope(ctx.projectRoot);\n if (sharedScope) {\n const problem =\n versions.length > 1\n ? `${versions.length} ctxo blocks in post-commit (expected 1)`\n : version === undefined\n ? 'no ctxo block in post-commit'\n : `outdated ctxo block in post-commit (v${version}, current v${POST_COMMIT_HOOK_VERSION})`;\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message: `Shared hooks directory ${forwardSlashes(hooksDir)} (${sharedScope} core.hooksPath): ${problem}; ctxo does not write there`,\n fix: `Add the current ctxo post-commit block to ${forwardSlashes(hookPath)} by hand (run \"ctxo init\" to print it), or set a repo-local core.hooksPath`,\n ...(version !== undefined ? { value: `v${version}` } : {}),\n };\n }\n\n if (versions.length > 1) {\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message: `${versions.length} ctxo blocks in the post-commit hook (expected 1); the hook runs ctxo once per block`,\n fix: 'Run \"ctxo doctor --fix\" or \"ctxo init\" to collapse them into one block',\n };\n }\n if (version === undefined) {\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message: `No ctxo post-commit hook (${hookPath})`,\n fix: 'Run \"ctxo init\" or \"ctxo doctor --fix\" to install the post-commit hook',\n };\n }\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message: `Outdated ctxo post-commit hook (v${version}, current v${POST_COMMIT_HOOK_VERSION})`,\n fix: 'Run \"ctxo doctor --fix\" or \"ctxo init\" to upgrade the post-commit hook',\n value: `v${version}`,\n };\n }\n}\n","import type { IHealthCheck, CheckContext, CheckResult } from '../../../core/diagnostics/types.js';\nimport { RULES_TEMPLATE_VERSION, classifyRulesBlock, type BlockStatus } from '../../../core/agent-rules/rules-block.js';\nimport {\n PLATFORMS,\n SKILL_PLATFORMS,\n gateEnabled,\n guardExpected,\n readClaudeGuardState,\n readRulesStates,\n resolveRulesTier,\n skillStates,\n skillsExpected,\n type PlatformRulesState,\n} from '../../../cli/ai-rules.js';\n\n/*\n * Agent-setup checks: the ctxo rules blocks, the bundled skills and the Claude Code safe-edit guard.\n * Each reports drift as a warn and never fails or throws: an internal error (such as the bundled\n * skills not being found) becomes a warn that carries its message and CHECK_ERROR_FIX.\n */\n\nconst RULES_FIX = 'Run \"ctxo doctor --fix\" or \"ctxo init\" to re-render the ctxo rules blocks';\n// The rules part is named too, so the tier follows the pieces in one command (final review M3).\nconst SKILLS_FIX = 'Run \"ctxo doctor --fix\" or \"ctxo init --only rules,skills,guard\"';\nconst GUARD_FIX = 'Run \"ctxo doctor --fix\" or \"ctxo init --only rules,skills,guard\"';\nconst UNREADABLE_SETTINGS_FIX = 'Repair .claude/settings.json by hand; ctxo never overwrites it';\n/** Init and --fix leave a file with an unterminated block unchanged (D8), so the first step is by hand. */\nconst UNTERMINATED_FIX =\n 'Fix the file by hand (add the missing \"<!-- ctxo-rules-end -->\" line, or delete the start marker without one), then run \"ctxo doctor\"';\n/** The same for an end marker that closes no block (its start line was deleted): init and --fix leave it unchanged. */\nconst ORPHAN_END_FIX =\n 'Fix the file by hand (delete the \"<!-- ctxo-rules-end -->\" line that has no start marker, with the old ctxo rules text above it, or add the missing start marker), then run \"ctxo doctor\"';\n/** This ctxo leaves a file with a block from a newer ctxo unchanged (D2), so it cannot collapse the blocks. */\nconst NEWER_BLOCKS_FIX = 'Delete the older ctxo rules block by hand, or run \"ctxo doctor --fix\" with the newer ctxo';\nconst CHECK_ERROR_FIX =\n 'Fix the cause named in the message (a file ctxo cannot read, or a ctxo install without its bundled skills: reinstall @ctxo/cli), then run \"ctxo doctor\"';\n\n/** The ai_rules fixes, first step first: when several apply, the check names the one to take first. */\nconst RULES_FIX_ORDER = [CHECK_ERROR_FIX, UNTERMINATED_FIX, ORPHAN_END_FIX, NEWER_BLOCKS_FIX, RULES_FIX] as const;\n\ntype RulesFix = (typeof RULES_FIX_ORDER)[number];\n\ninterface RulesProblem {\n readonly text: string;\n readonly fix: RulesFix;\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n/** The warn an agent-setup check gives when it cannot run to the end. */\nfunction checkError(id: string, title: string, what: string, err: unknown): CheckResult {\n return { id, title, status: 'warn', message: `${what} could not be checked: ${errorMessage(err)}`, fix: CHECK_ERROR_FIX };\n}\n\nfunction platformName(platformId: string): string {\n return PLATFORMS.find((p) => p.id === platformId)?.name ?? platformId;\n}\n\n/**\n * Reports, per rules file, a block whose template is outdated (D2: a newer one is fine), a Claude\n * Code block that expects the guard while it is missing, a current block in the wrong tier, several\n * blocks in one file, a start marker without an end marker, and an end marker without a start\n * marker. The fix names the first step to take: by hand for a damaged block or for blocks next to a\n * newer one, which ctxo leaves alone.\n */\nexport class AiRulesCheck implements IHealthCheck {\n readonly id = 'ai_rules';\n readonly title = 'AI rules';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n try {\n return this.check(ctx.projectRoot);\n } catch (err) {\n return checkError(this.id, this.title, 'ctxo rules blocks', err);\n }\n }\n\n private check(projectRoot: string): CheckResult {\n const problems: RulesProblem[] = [];\n const summary: string[] = [];\n for (const state of readRulesStates(projectRoot)) {\n const first = state.scan.blocks[0];\n const status = first ? classifyRulesBlock(first) : undefined;\n problems.push(...fileProblems(projectRoot, state, status).map((p) => ({ ...p, text: `${state.file}: ${p.text}` })));\n if (status?.state === 'current') summary.push(`${state.file} v${RULES_TEMPLATE_VERSION} ${status.tier}`);\n if (status?.state === 'newer') summary.push(`${state.file} v${status.version} from a newer ctxo`);\n }\n\n if (problems.length > 0) {\n const fix = RULES_FIX_ORDER.find((candidate) => problems.some((p) => p.fix === candidate)) ?? RULES_FIX;\n return { id: this.id, title: this.title, status: 'warn', message: problems.map((p) => p.text).join('; '), fix };\n }\n return {\n id: this.id,\n title: this.title,\n status: 'pass',\n message: summary.length > 0 ? summary.join('; ') : 'no ctxo rules blocks',\n };\n }\n}\n\n/**\n * The problems in one rules file; `status` classifies its first block. A tier that cannot be resolved\n * (the bundled skills cannot be read) is a problem of this file only, so the other files keep theirs.\n */\nfunction fileProblems(projectRoot: string, state: PlatformRulesState, status: BlockStatus | undefined): RulesProblem[] {\n const problems: RulesProblem[] = [];\n const blocks = state.scan.blocks;\n const newer = blocks.length > 1 ? blocks.map(classifyRulesBlock).find((s) => s.state === 'newer') : undefined;\n\n if (newer?.state === 'newer') {\n // This ctxo leaves the whole file alone, so it reports the blocks once, with a step that clears them.\n problems.push({\n text: `${blocks.length} ctxo rules blocks, one from a newer ctxo (v${newer.version}); this ctxo leaves the file unchanged`,\n fix: NEWER_BLOCKS_FIX,\n });\n } else if (status?.state === 'outdated') {\n const found = status.reason === 'older' ? `v${blocks[0]?.version ?? ''}` : status.reason;\n problems.push({ text: `rules template outdated (${found} block, template v${RULES_TEMPLATE_VERSION})`, fix: RULES_FIX });\n }\n\n const guardMissing =\n state.platformId === 'claude-code' &&\n readClaudeGuardState(projectRoot) === 'absent' &&\n guardExpected(projectRoot);\n if (guardMissing) problems.push({ text: 'rules present, guard missing', fix: RULES_FIX });\n\n if (status?.state === 'current' && !guardMissing) {\n try {\n const expected = resolveRulesTier(projectRoot, state.platformId);\n if (status.tier !== expected) {\n problems.push({ text: `rules tier does not match the guard and skills (expected ${expected})`, fix: RULES_FIX });\n }\n } catch (err) {\n problems.push({ text: `rules tier could not be checked (${errorMessage(err)})`, fix: CHECK_ERROR_FIX });\n }\n }\n\n if (blocks.length > 1 && !newer) problems.push({ text: `${blocks.length} ctxo rules blocks`, fix: RULES_FIX });\n if (state.scan.unterminated) problems.push({ text: 'start marker without end marker', fix: UNTERMINATED_FIX });\n if (state.scan.orphanEnd) problems.push({ text: 'end marker without start marker', fix: ORPHAN_END_FIX });\n return problems;\n}\n\n/**\n * Reports missing and outdated skills for each skill platform that expects them: one ctxo skill is\n * installed, or its rules block is pre-tier or compact. A deliberate opt-out (a versioned full block\n * and no skills) passes.\n */\nexport class SkillsCheck implements IHealthCheck {\n readonly id = 'skills';\n readonly title = 'Agent skills';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n try {\n return this.check(ctx.projectRoot);\n } catch (err) {\n return checkError(this.id, this.title, 'ctxo skills', err);\n }\n }\n\n private check(projectRoot: string): CheckResult {\n const problems: string[] = [];\n const summary: string[] = [];\n for (const platformId of SKILL_PLATFORMS) {\n const name = platformName(platformId);\n if (!skillsExpected(projectRoot, platformId)) {\n summary.push(`${name}: not installed`);\n continue;\n }\n const states = skillStates(projectRoot, platformId);\n const missing = states.filter((s) => s.state === 'missing').map((s) => s.skill);\n const outdated = states.filter((s) => s.state === 'outdated').map((s) => s.skill);\n if (missing.length > 0) problems.push(`${name}: missing ${missing.join(', ')}`);\n if (outdated.length > 0) problems.push(`${name}: outdated ${outdated.join(', ')}`);\n if (missing.length === 0 && outdated.length === 0) summary.push(`${name}: current`);\n }\n\n if (problems.length > 0) {\n return { id: this.id, title: this.title, status: 'warn', message: problems.join('; '), fix: SKILLS_FIX };\n }\n return { id: this.id, title: this.title, status: 'pass', message: summary.join('; ') };\n }\n}\n\n/**\n * Reports an unreadable `.claude/settings.json`, and a missing guard when CLAUDE.md's block expects it\n * (pre-tier or compact) and the gate is enabled. A versioned full block or `gate.enabled: false`\n * records an opt-out and passes.\n */\nexport class ClaudeGuardHookCheck implements IHealthCheck {\n readonly id = 'claude_guard_hook';\n readonly title = 'Claude guard hook';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n try {\n return this.check(ctx.projectRoot);\n } catch (err) {\n return checkError(this.id, this.title, 'safe-edit guard', err);\n }\n }\n\n private check(projectRoot: string): CheckResult {\n const state = readClaudeGuardState(projectRoot);\n if (state === 'unreadable') {\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message: '.claude/settings.json is not valid JSON or not a settings object; the guard cannot be verified',\n fix: UNREADABLE_SETTINGS_FIX,\n };\n }\n if (state === 'absent' && guardExpected(projectRoot)) {\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message: 'safe-edit guard hook missing from .claude/settings.json',\n fix: GUARD_FIX,\n };\n }\n const message =\n state === 'absent'\n ? 'not installed'\n : gateEnabled(projectRoot)\n ? 'installed'\n : 'installed, disabled by gate.enabled: false';\n return { id: this.id, title: this.title, status: 'pass', message };\n }\n}\n","import { existsSync } from 'node:fs';\nimport { execFileSync } from 'node:child_process';\nimport { join } from 'node:path';\nimport type { IHealthCheck, CheckResult, CheckContext } from '../../../core/diagnostics/types.js';\nimport type { FileIndex } from '../../../core/types.js';\nimport { JsonIndexReader } from '../../storage/json-index-reader.js';\nimport { StalenessDetector } from '../../../core/staleness/staleness-detector.js';\nimport { SchemaManager } from '../../storage/schema-manager.js';\n\nfunction pass(id: string, title: string, message: string, value?: string): CheckResult {\n return { id, title, status: 'pass', message, value };\n}\nfunction warn(id: string, title: string, message: string, fix?: string, value?: string): CheckResult {\n return { id, title, status: 'warn', message, fix, value };\n}\nfunction fail(id: string, title: string, message: string, fix?: string, value?: string): CheckResult {\n return { id, title, status: 'fail', message, fix, value };\n}\n\n/** Use pre-loaded indices from context, or fall back to reading from disk */\nfunction getIndices(ctx: CheckContext): readonly FileIndex[] {\n return ctx.indices ?? new JsonIndexReader(ctx.ctxoRoot).readAll();\n}\n\nexport class IndexDirectoryCheck implements IHealthCheck {\n readonly id = 'index_directory';\n readonly title = 'Index directory';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const indexDir = join(ctx.ctxoRoot, 'index');\n if (!existsSync(indexDir)) {\n return fail(this.id, this.title, 'No index directory', 'Run \"ctxo index\"');\n }\n const indices = getIndices(ctx);\n if (indices.length === 0) {\n return fail(this.id, this.title, 'Index directory empty', 'Run \"ctxo index\"');\n }\n return pass(this.id, this.title, `${indices.length} files indexed`, String(indices.length));\n }\n}\n\nexport class IndexFreshnessCheck implements IHealthCheck {\n readonly id = 'index_freshness';\n readonly title = 'Index freshness';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const indices = getIndices(ctx);\n if (indices.length === 0) {\n return fail(this.id, this.title, 'No indexed files to check', 'Run \"ctxo index\"');\n }\n\n const indexedFiles = indices.map(idx => idx.file);\n const staleness = new StalenessDetector(ctx.projectRoot, ctx.ctxoRoot);\n const warning = staleness.check(indexedFiles);\n\n if (!warning) {\n return pass(this.id, this.title, `All ${indices.length} files fresh`, `0/${indices.length} stale`);\n }\n\n const staleCount = warning.staleFiles.length;\n const pct = staleCount / indices.length;\n const value = `${staleCount}/${indices.length} stale`;\n\n if (pct <= 0.1) {\n return warn(this.id, this.title, `${staleCount} of ${indices.length} files stale`, 'Run \"ctxo index\"', value);\n }\n return fail(this.id, this.title, `${staleCount} of ${indices.length} files stale (${Math.round(pct * 100)}%)`, 'Run \"ctxo index\"', value);\n }\n}\n\nexport class SymbolCountCheck implements IHealthCheck {\n readonly id = 'symbol_count';\n readonly title = 'Symbol count';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const indices = getIndices(ctx);\n const total = indices.reduce((sum, idx) => sum + idx.symbols.length, 0);\n if (total > 0) {\n return pass(this.id, this.title, `${total.toLocaleString()} symbols`, String(total));\n }\n return fail(this.id, this.title, '0 symbols (index empty)', 'Run \"ctxo index\"', '0');\n }\n}\n\nexport class EdgeCountCheck implements IHealthCheck {\n readonly id = 'edge_count';\n readonly title = 'Edge count';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const indices = getIndices(ctx);\n const total = indices.reduce((sum, idx) => sum + idx.edges.length, 0);\n if (total > 0) {\n return pass(this.id, this.title, `${total.toLocaleString()} edges`, String(total));\n }\n return warn(this.id, this.title, '0 edges (possible isolated files)', undefined, '0');\n }\n}\n\nexport class OrphanedFilesCheck implements IHealthCheck {\n readonly id = 'orphaned_files';\n readonly title = 'Orphaned index files';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const indices = getIndices(ctx);\n if (indices.length === 0) {\n return pass(this.id, this.title, 'no index files to check');\n }\n\n const sourceFiles = this.getSourceFiles(ctx.projectRoot);\n if (sourceFiles.size === 0) {\n return pass(this.id, this.title, 'none (git ls-files unavailable)');\n }\n\n const orphaned = indices.filter(idx => !sourceFiles.has(idx.file));\n if (orphaned.length === 0) {\n return pass(this.id, this.title, 'none', '0');\n }\n if (orphaned.length <= 5) {\n return warn(this.id, this.title, `${orphaned.length} orphaned index files`, 'Delete orphaned files from .ctxo/index/', String(orphaned.length));\n }\n return fail(this.id, this.title, `${orphaned.length} orphaned index files`, 'Delete orphaned files from .ctxo/index/', String(orphaned.length));\n }\n\n private getSourceFiles(projectRoot: string): Set<string> {\n try {\n // -z: NUL-separated, unquoted names (git quotes non-ASCII paths otherwise).\n const output = execFileSync('git', ['ls-files', '-z', '--cached', '--others', '--exclude-standard'], {\n cwd: projectRoot,\n encoding: 'utf-8',\n });\n return new Set(output.split('\\0').filter(l => l.length > 0));\n } catch {\n return new Set();\n }\n }\n}\n\nexport class CoChangesCacheCheck implements IHealthCheck {\n readonly id = 'co_changes_cache';\n readonly title = 'Co-changes cache';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const coChangesPath = join(ctx.ctxoRoot, 'index', 'co-changes.json');\n if (existsSync(coChangesPath)) {\n return pass(this.id, this.title, 'present');\n }\n return warn(this.id, this.title, 'missing (co-change analysis disabled)', 'Run \"ctxo index\" with git history');\n }\n}\n\nexport class SchemaVersionCheck implements IHealthCheck {\n readonly id = 'schema_version';\n readonly title = 'Schema version';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const manager = new SchemaManager(ctx.ctxoRoot);\n const stored = manager.readStoredVersion();\n const current = manager.currentVersion();\n\n if (!stored) {\n return fail(this.id, this.title, 'No schema version found', 'Run \"ctxo index\"');\n }\n if (manager.isCompatible()) {\n return pass(this.id, this.title, `${stored} (current)`, stored);\n }\n return fail(this.id, this.title, `${stored} (expected ${current})`, 'Run \"ctxo index\" to re-index with current schema', stored);\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { IHealthCheck, CheckResult, CheckContext } from '../../../core/diagnostics/types.js';\n\nexport class SqliteCacheCheck implements IHealthCheck {\n readonly id = 'sqlite_cache';\n readonly title = 'SQLite cache';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const dbPath = join(ctx.ctxoRoot, '.cache', 'symbols.db');\n if (!existsSync(dbPath)) {\n return { id: this.id, title: this.title, status: 'warn', message: 'SQLite cache missing', fix: 'Run \"ctxo sync\" to rebuild' };\n }\n\n try {\n const { default: initSqlJs } = await import('sql.js');\n const SQL = await initSqlJs();\n const buffer = readFileSync(dbPath);\n const db = new SQL.Database(new Uint8Array(buffer));\n const result = db.exec('PRAGMA integrity_check');\n db.close();\n\n const firstRow = result[0]?.values[0];\n if (firstRow && firstRow[0] === 'ok') {\n return { id: this.id, title: this.title, status: 'pass', message: 'integrity_check passed' };\n }\n return { id: this.id, title: this.title, status: 'fail', message: `SQLite corrupt: ${String(firstRow?.[0])}`, fix: 'Run \"ctxo sync\" to rebuild' };\n } catch (err) {\n return { id: this.id, title: this.title, status: 'fail', message: `SQLite unreadable: ${(err as Error).message}`, fix: 'Run \"ctxo sync\" to rebuild' };\n }\n }\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { IHealthCheck, CheckResult, CheckContext } from '../../../core/diagnostics/types.js';\nimport { loadConfig } from '../../../core/config/load-config.js';\n\nexport class ConfigFileCheck implements IHealthCheck {\n readonly id = 'config_file';\n readonly title = 'Config file';\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n const configPath = join(ctx.ctxoRoot, 'config.yaml');\n if (!existsSync(configPath)) {\n return { id: this.id, title: this.title, status: 'warn', message: 'No config.yaml (using defaults)' };\n }\n\n try {\n const content = readFileSync(configPath, 'utf-8');\n if (content.trim().length === 0) {\n return { id: this.id, title: this.title, status: 'warn', message: 'config.yaml is empty (using defaults)' };\n }\n // Basic YAML structure check — tabs are invalid in YAML\n if (content.includes('\\t')) {\n return { id: this.id, title: this.title, status: 'fail', message: 'Invalid config.yaml: tabs are not allowed in YAML', fix: 'Replace tabs with spaces in .ctxo/config.yaml' };\n }\n\n const loaded = loadConfig(ctx.ctxoRoot);\n if (loaded.errors.length > 0) {\n return {\n id: this.id,\n title: this.title,\n status: 'fail',\n message: `Invalid config.yaml: ${loaded.errors[0]}${loaded.errors.length > 1 ? ` (+${loaded.errors.length - 1} more)` : ''}`,\n fix: 'Fix schema violations in .ctxo/config.yaml (see docs for the full schema)',\n };\n }\n if (loaded.invalidGlobs.length > 0) {\n return {\n id: this.id,\n title: this.title,\n status: 'warn',\n message: `config.yaml has ${loaded.invalidGlobs.length} invalid glob pattern(s): ${loaded.invalidGlobs.join('; ')}`,\n fix: 'Fix the listed glob patterns under index.ignore / index.ignoreProjects / index.tests / cochange.include / cochange.exclude / contextsView.exclude / contextsView.hubs.paths',\n };\n }\n return { id: this.id, title: this.title, status: 'pass', message: '.ctxo/config.yaml valid' };\n } catch (err) {\n return { id: this.id, title: this.title, status: 'fail', message: `Cannot read config.yaml: ${(err as Error).message}`, fix: 'Check file permissions for .ctxo/config.yaml' };\n }\n }\n}\n","import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\nimport type { IHealthCheck, CheckResult, CheckContext } from '../../../core/diagnostics/types.js';\n\nexport interface DiskThresholds {\n readonly warnMb: number;\n readonly failMb: number;\n}\n\nconst DEFAULT_THRESHOLDS: DiskThresholds = { warnMb: 100, failMb: 500 };\n\nexport class DiskUsageCheck implements IHealthCheck {\n readonly id = 'disk_usage';\n readonly title = 'Disk usage';\n private readonly thresholds: DiskThresholds;\n\n constructor(thresholds: DiskThresholds = DEFAULT_THRESHOLDS) {\n this.thresholds = thresholds;\n }\n\n async run(ctx: CheckContext): Promise<CheckResult> {\n if (!existsSync(ctx.ctxoRoot)) {\n return { id: this.id, title: this.title, status: 'pass', message: 'no .ctxo/ directory', value: '0' };\n }\n\n const bytes = this.getDirSize(ctx.ctxoRoot);\n const mb = bytes / (1024 * 1024);\n const formatted = mb < 1 ? `${Math.round(bytes / 1024)} KB` : `${mb.toFixed(1)} MB`;\n\n if (mb < this.thresholds.warnMb) {\n return { id: this.id, title: this.title, status: 'pass', message: formatted, value: formatted };\n }\n if (mb < this.thresholds.failMb) {\n return { id: this.id, title: this.title, status: 'warn', message: `${formatted} — consider pruning orphaned index files`, value: formatted };\n }\n return { id: this.id, title: this.title, status: 'fail', message: `${formatted} — unusually large`, fix: 'Check for stale data in .ctxo/', value: formatted };\n }\n\n private getDirSize(dirPath: string): number {\n let total = 0;\n try {\n const entries = readdirSync(dirPath, { withFileTypes: true, recursive: true });\n for (const entry of entries) {\n if (entry.isFile()) {\n try {\n // parentPath available in Node 20.12+, path in earlier Node 20.x\n const parent = (entry as unknown as { parentPath?: string; path?: string }).parentPath\n ?? (entry as unknown as { path?: string }).path\n ?? dirPath;\n total += statSync(join(parent, entry.name)).size;\n } catch {\n // skip unreadable files\n }\n }\n }\n } catch {\n // skip unreadable directories\n }\n return total;\n }\n}\n","import { execFileSync } from 'node:child_process';\nimport { appendFileSync, existsSync, mkdirSync, rmSync, unlinkSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\nimport { JsonIndexReader } from '../adapters/storage/json-index-reader.js';\nimport type { DoctorReport } from '../core/diagnostics/types.js';\nimport {\n detectLanguages,\n decideNeededLanguages,\n officialPluginFor,\n type KnownLanguage,\n} from '../core/detection/detect-languages.js';\nimport { classifyRulesBlock } from '../core/agent-rules/rules-block.js';\nimport {\n SKILL_PLATFORMS,\n ensureClaudeHook,\n ensureConfig,\n guardExpected,\n installRules,\n installSkills,\n readClaudeGuardState,\n readRulesStates,\n resolveRulesTier,\n rulesFileHoldReasons,\n skillInstallWarnings,\n skillsExpected,\n type RulesHoldReasons,\n} from './ai-rules.js';\nimport { InstallCommand } from './install-command.js';\nimport { InitCommand } from './init-command.js';\nimport { IndexCommand } from './index-command.js';\nimport { SyncCommand } from './sync-command.js';\n\nexport interface FixOptions {\n readonly projectRoot: string;\n readonly ctxoRoot: string;\n readonly yes?: boolean;\n readonly dryRun?: boolean;\n}\n\nexport interface FixAttempt {\n readonly name: string;\n readonly action: string;\n readonly status: 'success' | 'skipped' | 'failed' | 'planned';\n readonly durationMs?: number;\n readonly error?: string;\n /** What a successful attempt left undone, such as a rules file it held back; one warning line each. */\n readonly warnings?: readonly string[];\n}\n\nexport interface FixReport {\n readonly attempts: readonly FixAttempt[];\n readonly halted: boolean;\n readonly reason?: string;\n}\n\n/**\n * Apply ordered fixes derived from a doctor report.\n *\n * Order (PRD §5.2 D4.4, with the agent-setup steps of PR 2A D13):\n * 1. Config (bootstraps defaults other steps may need)\n * 2. Git hooks (cheap; depends on .git existing)\n * 3. Skills (install missing or outdated ctxo skills where the setup expects them)\n * 4. Claude guard hook (register ctxo gate-hook in .claude/settings.json)\n * 5. AI rules (re-render the rules blocks; runs whenever any of the three agent checks\n * failed, after 3 and 4, so the tier follows the skills and guard fixed in this run)\n * 6. Language coverage (install missing plugins)\n * 7. Index (requires adapters, so it runs AFTER plugin install)\n * 8. SQLite cache (last; rebuild from index JSONs)\n *\n * Steps 3 to 5 never install what the user declined (D5): a versioned full block in CLAUDE.md is\n * an opt-out of the guard and the skills, and `gate.enabled: false` an opt-out of the guard only.\n * An unreadable `.claude/settings.json` is never written; when the guard is expected, its step fails\n * with the warning, otherwise it is skipped like any opt-out. Step 5\n * holds a rules file (CLAUDE.md, or Cursor's) while, after steps 3 and 4, its block still expects a\n * guard or skills that are not in place (whatever stopped them), by the same `rulesHold` rule as\n * `ctxo init`, and reports the hold as a warning.\n *\n * Error handling (D4.6 \"dependency-aware continue\"):\n * - Config failure -> skip all dependent steps\n * - Skills, Claude guard hook or AI rules failure -> reported; the next steps still run\n * - Plugin install failure -> skip index (can't rebuild adapters) but DO rebuild cache\n *\n * Never fixable here: runtime, git repo, disk. Those remain as CheckResult\n * output for the user to address manually.\n *\n * All attempts are appended to `.ctxo/doctor-fix.log` for forensics.\n */\nexport async function applyFixes(report: DoctorReport, options: FixOptions): Promise<FixReport> {\n if (isCI(process.env) && !options.yes && !options.dryRun) {\n return {\n attempts: [],\n halted: true,\n reason: 'CI environment detected; refuse to mutate without --yes',\n };\n }\n\n const attempts: FixAttempt[] = [];\n const fixableIds = new Set(report.checks.filter((c) => c.status !== 'pass').map((c) => c.id));\n\n let configOk = true;\n if (fixableIds.has('config_file')) {\n const attempt = await run(\n 'Config',\n 'create from template',\n () => fixConfig(options.projectRoot),\n options,\n );\n attempts.push(attempt);\n configOk = attempt.status === 'success' || attempt.status === 'skipped' || attempt.status === 'planned';\n }\n\n if (!configOk) {\n return finish(attempts, options, true, 'Config fix failed; halting before hooks/plugins/index');\n }\n\n if (fixableIds.has('git_hooks') || fixableIds.has('hooks')) {\n attempts.push(\n await run(\n 'Git hooks',\n 're-install ctxo git hooks',\n () => fixHooks(options.projectRoot),\n options,\n ),\n );\n }\n\n if (fixableIds.has('skills')) {\n attempts.push(\n await run(\n 'Skills',\n 'install missing or outdated ctxo skills',\n () => fixSkills(options.projectRoot),\n options,\n ),\n );\n }\n\n if (fixableIds.has('claude_guard_hook')) {\n attempts.push(\n await run(\n 'Claude guard hook',\n 'register ctxo gate-hook in .claude/settings.json',\n () => fixClaudeGuardHook(options.projectRoot),\n options,\n ),\n );\n }\n\n if (fixableIds.has('ai_rules') || fixableIds.has('skills') || fixableIds.has('claude_guard_hook')) {\n attempts.push(\n await run(\n 'AI rules',\n 're-render ctxo rules blocks',\n () => fixAiRules(options.projectRoot),\n options,\n ),\n );\n }\n\n let pluginsOk = true;\n if (fixableIds.has('language_coverage') || hasMissingPlugins(options.projectRoot)) {\n const attempt = await run(\n 'Language plugins',\n 'install missing @ctxo/lang-* packages',\n () => fixLanguageCoverage(options.projectRoot, options.dryRun ?? false),\n options,\n );\n attempts.push(attempt);\n pluginsOk = attempt.status === 'success' || attempt.status === 'skipped' || attempt.status === 'planned';\n }\n\n if (pluginsOk) {\n if (\n fixableIds.has('index_directory') ||\n fixableIds.has('index_freshness') ||\n fixableIds.has('symbol_count')\n ) {\n attempts.push(\n await run(\n 'Index',\n 'rebuild JSON index',\n () => fixIndex(options.projectRoot, options.dryRun ?? false),\n options,\n ),\n );\n }\n if (fixableIds.has('orphaned_files')) {\n attempts.push(\n await run(\n 'Orphaned index files',\n 'delete index entries without a matching source file',\n () => pruneOrphans(options.projectRoot, options.ctxoRoot, options.dryRun ?? false),\n options,\n ),\n );\n }\n } else {\n attempts.push({ name: 'Index', action: 'rebuild JSON index', status: 'skipped', error: 'plugin install failed' });\n }\n\n if (\n fixableIds.has('sqlite_cache') ||\n fixableIds.has('schema_version') ||\n fixableIds.has('co_changes_cache')\n ) {\n attempts.push(\n await run(\n 'SQLite cache',\n 'delete .ctxo/.cache and resync',\n () => fixSqliteCache(options.projectRoot, options.ctxoRoot, options.dryRun ?? false),\n options,\n ),\n );\n }\n\n return finish(attempts, options, false);\n}\n\nfunction finish(\n attempts: FixAttempt[],\n options: FixOptions,\n halted: boolean,\n reason?: string,\n): FixReport {\n writeLog(options.ctxoRoot, attempts, halted, reason);\n return reason ? { attempts, halted, reason } : { attempts, halted };\n}\n\n/** A fix body returns this when it deliberately did nothing (not a failure): the attempt is reported as skipped. */\ninterface FixSkipped {\n readonly skipped: string;\n}\n\n/** A fix body returns this when it did its work but left part of it undone: success with warning lines. */\ninterface FixWarned {\n readonly warnings: readonly string[];\n}\n\nasync function run(\n name: string,\n action: string,\n body: () => Promise<void | FixSkipped | FixWarned>,\n options: FixOptions,\n): Promise<FixAttempt> {\n if (options.dryRun) {\n return { name, action, status: 'planned' };\n }\n const start = Date.now();\n try {\n const outcome = await body();\n if (outcome && 'skipped' in outcome) {\n return { name, action, status: 'skipped', durationMs: Date.now() - start, error: outcome.skipped };\n }\n if (outcome) {\n return { name, action, status: 'success', durationMs: Date.now() - start, warnings: outcome.warnings };\n }\n return { name, action, status: 'success', durationMs: Date.now() - start };\n } catch (err) {\n return {\n name,\n action,\n status: 'failed',\n durationMs: Date.now() - start,\n error: (err as Error).message,\n };\n }\n}\n\nasync function fixConfig(projectRoot: string): Promise<void> {\n const result = ensureConfig(projectRoot);\n if (result.action === 'skipped') {\n // Already present — nothing to do\n return;\n }\n}\n\nasync function fixHooks(projectRoot: string): Promise<void | FixSkipped> {\n const result = new InitCommand(projectRoot).installHooks();\n if (!result.installed) {\n // installHooks already printed the warning with the blocks to add by hand.\n return { skipped: `shared hooks directory (${result.sharedScope} core.hooksPath); ctxo does not write there, add the blocks by hand` };\n }\n}\n\n/**\n * Installs the bundled skills on every skill platform that expects them: one ctxo skill is already\n * there, or the platform's rules block is pre-tier or compact. A deliberate opt-out expects none. A\n * platform that fails does not stop the next one.\n *\n * The `installSkills` warnings are reported, not dropped. A skill left in place because a newer ctxo\n * wrote it is fine, so its warning is a warning line under the success line. Any other warning (a skill\n * path that cannot be read, such as a directory) leaves the skill missing, so it fails the attempt, as\n * does an error, `<platform>: <error>`; the failure lists the warning lines too.\n */\nasync function fixSkills(projectRoot: string): Promise<void | FixSkipped | FixWarned> {\n const platforms = SKILL_PLATFORMS.filter((id) => skillsExpected(projectRoot, id));\n if (platforms.length === 0) return { skipped: 'no platform expects the ctxo skills' };\n const errors: string[] = [];\n const warnings: string[] = [];\n for (const id of platforms) {\n try {\n const { problems, notices } = skillInstallWarnings(projectRoot, id, installSkills(projectRoot, id));\n errors.push(...problems);\n warnings.push(...notices);\n } catch (err) {\n errors.push(`${id}: ${(err as Error).message}`);\n }\n }\n if (errors.length > 0) throw new Error([...errors, ...warnings].join('; '));\n if (warnings.length > 0) return { warnings };\n}\n\n/**\n * The failure for an unreadable `.claude/settings.json`. Unlike the `ensureClaudeHook` warning (shared\n * with init), it names one next step: the same `--fix` run that installs the guard renders the tier.\n */\nconst UNREADABLE_SETTINGS_FAILURE =\n '.claude/settings.json is not valid JSON or not a settings object; left unchanged. Fix it, then run \"ctxo doctor --fix\".';\n\n/**\n * Registers the safe-edit guard when CLAUDE.md expects it and the gate is enabled. An unreadable\n * `.claude/settings.json` is never written; it fails the attempt only when the guard is expected, since\n * a user who opted out expects nothing there (final review M4).\n */\nasync function fixClaudeGuardHook(projectRoot: string): Promise<void | FixSkipped> {\n const state = readClaudeGuardState(projectRoot);\n if (state === 'present') return { skipped: 'already registered' };\n if (!guardExpected(projectRoot)) {\n return { skipped: 'not expected: CLAUDE.md records an opt-out or has no ctxo block, or gate.enabled is false' };\n }\n if (state === 'unreadable') throw new Error(UNREADABLE_SETTINGS_FAILURE);\n const result = ensureClaudeHook(projectRoot);\n if (result.warning) throw new Error(result.warning);\n}\n\n/**\n * Re-renders each rules file's ctxo block in the tier the disk supports now, so it follows the skills\n * and guard installed earlier in the run. A block from a newer ctxo is left alone (D2). A damaged file\n * (a start marker without an end marker, or an end marker without a start marker) is passed on too,\n * so the writer's warning fails the attempt instead of being lost; the writer leaves it unchanged (D8).\n *\n * A file is held while `rulesFileHoldReasons` (the rule `ctxo init` uses too, under every linked name\n * of the file) finds a reason, and the hold is reported: as the skip reason when nothing else\n * rendered, otherwise as a warning line under the success line. A held file still reports a damaged\n * block (from a dry run, which writes nothing).\n */\nasync function fixAiRules(projectRoot: string): Promise<void | FixSkipped | FixWarned> {\n const warnings: string[] = [];\n const holds: string[] = [];\n let rendered = 0;\n for (const state of readRulesStates(projectRoot)) {\n const first = state.scan.blocks[0];\n const damaged = state.scan.unterminated || state.scan.orphanEnd;\n const renderable = first ? classifyRulesBlock(first).state !== 'newer' : damaged;\n if (!renderable) continue;\n const reasons = rulesFileHoldReasons(projectRoot, state.platformId);\n if (reasons) {\n holds.push(holdMessage(state.file, reasons));\n const probe = installRules(projectRoot, state.platformId, { dryRun: true });\n if (probe.warning) warnings.push(probe.warning);\n continue;\n }\n rendered += 1;\n const result = installRules(projectRoot, state.platformId, { tier: resolveRulesTier(projectRoot, state.platformId) });\n if (result.warning) warnings.push(result.warning);\n }\n if (warnings.length > 0) throw new Error([...warnings, ...holds].join('; '));\n if (rendered === 0) return { skipped: holds.length > 0 ? holds.join('; ') : 'no ctxo rules block to re-render' };\n if (holds.length > 0) return { warnings: holds };\n}\n\n/**\n * The hold line for a rules file `rulesHoldReasons` keeps back, read from disk after the Skills and\n * Claude guard hook steps, whatever stopped them (a failed write, a partial install, an error).\n */\nfunction holdMessage(file: string, reasons: RulesHoldReasons): string {\n const why: string[] = [];\n if (reasons.guard === 'unreadable') why.push('.claude/settings.json is unreadable');\n if (reasons.guard === 'absent') why.push('the safe-edit guard is not registered');\n if (reasons.missingSkills) why.push(`ctxo skills are missing (${reasons.missingSkills.join(', ')})`);\n if (reasons.outdatedSkills) why.push(`ctxo skills are outdated (${reasons.outdatedSkills.join(', ')})`);\n if (reasons.skillsError !== undefined) why.push(`the ctxo skills cannot be checked (${reasons.skillsError})`);\n return `${file} left unchanged while ${why.join(' and ')}`;\n}\n\nfunction hasMissingPlugins(projectRoot: string): boolean {\n const detection = detectLanguages(projectRoot);\n const needed = decideNeededLanguages(detection);\n for (const lang of needed) {\n if (!canResolvePlugin(lang)) return true;\n }\n return false;\n}\n\nasync function fixLanguageCoverage(projectRoot: string, dryRun: boolean): Promise<void> {\n const detection = detectLanguages(projectRoot);\n const needed = decideNeededLanguages(detection);\n const missing = needed.filter((lang) => !canResolvePlugin(lang));\n if (missing.length === 0) return;\n if (dryRun) return;\n await new InstallCommand(projectRoot).run({ languages: missing, yes: true });\n}\n\nasync function fixIndex(projectRoot: string, dryRun: boolean): Promise<void> {\n if (dryRun) return;\n await new IndexCommand(projectRoot).run({});\n}\n\nasync function pruneOrphans(projectRoot: string, ctxoRoot: string, dryRun: boolean): Promise<void> {\n if (dryRun) return;\n const indexDir = join(ctxoRoot, 'index');\n if (!existsSync(indexDir)) return;\n\n const sourceFiles = listGitFiles(projectRoot);\n if (sourceFiles.size === 0) return; // no signal; refuse to mass-delete\n\n const reader = new JsonIndexReader(ctxoRoot);\n const indices = reader.readAll();\n let removed = 0;\n for (const idx of indices) {\n if (sourceFiles.has(idx.file)) continue;\n const jsonPath = join(indexDir, `${idx.file}.json`);\n try {\n if (existsSync(jsonPath)) {\n unlinkSync(jsonPath);\n removed += 1;\n pruneEmptyParents(jsonPath, indexDir);\n }\n } catch {\n // best-effort; leave stragglers for next run\n }\n }\n if (removed === 0) return;\n}\n\nfunction pruneEmptyParents(filePath: string, stopAt: string): void {\n let dir = dirname(filePath);\n while (dir !== stopAt && dir.startsWith(stopAt)) {\n try {\n rmSync(dir, { recursive: false });\n } catch {\n return; // not empty or permission issue — stop climbing\n }\n dir = dirname(dir);\n }\n}\n\nfunction listGitFiles(projectRoot: string): Set<string> {\n try {\n const out = execFileSync(\n 'git',\n // -z: NUL-separated, unquoted names. Quoted ones would never match an index entry, and the\n // prune would delete the entries of every file with a non-ASCII name.\n ['ls-files', '-z', '--cached', '--others', '--exclude-standard'],\n { cwd: projectRoot, encoding: 'utf-8', maxBuffer: 64 * 1024 * 1024 },\n );\n return new Set(out.split('\\0').filter(Boolean));\n } catch {\n return new Set();\n }\n}\n\nasync function fixSqliteCache(projectRoot: string, ctxoRoot: string, dryRun: boolean): Promise<void> {\n const cacheDir = join(ctxoRoot, '.cache');\n if (dryRun) return;\n if (existsSync(cacheDir)) rmSync(cacheDir, { recursive: true, force: true });\n // Trigger a sync to rebuild from .ctxo/index/*.json (in-process; no npx round-trip)\n await new SyncCommand(projectRoot).run();\n}\n\nconst doctorRequire = createRequire(import.meta.url);\n\nfunction canResolvePlugin(lang: KnownLanguage): boolean {\n try {\n doctorRequire.resolve(`${officialPluginFor(lang)}/package.json`);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction isCI(env: NodeJS.ProcessEnv): boolean {\n return env['CI'] === 'true' || env['CI'] === '1';\n}\n\nfunction writeLog(\n ctxoRoot: string,\n attempts: readonly FixAttempt[],\n halted: boolean,\n reason?: string,\n): void {\n try {\n if (!existsSync(ctxoRoot)) mkdirSync(ctxoRoot, { recursive: true });\n const path = join(ctxoRoot, 'doctor-fix.log');\n const ts = new Date().toISOString();\n const lines: string[] = [`# ${ts} doctor --fix${halted ? ' (halted: ' + reason + ')' : ''}`];\n for (const a of attempts) {\n const dur = a.durationMs != null ? ` (${a.durationMs}ms)` : '';\n const err = a.error ? ` — ${a.error}` : '';\n lines.push(`- [${a.status}] ${a.name}: ${a.action}${dur}${err}`);\n for (const warning of a.warnings ?? []) lines.push(` - warning: ${warning}`);\n }\n lines.push('');\n appendFileSync(path, lines.join('\\n'));\n } catch {\n // best-effort logging; never fail the fix because of logging\n }\n}\n\n/** Consumer-friendly formatter for CLI output. */\nexport function formatFixReport(report: FixReport): string {\n const lines: string[] = [];\n for (const a of report.attempts) {\n const icon = a.status === 'success' ? '✓' : a.status === 'planned' ? '·' : a.status === 'skipped' ? '-' : '✗';\n const dur = a.durationMs != null ? ` (${a.durationMs}ms)` : '';\n const err = a.error ? ` — ${a.error}` : '';\n lines.push(` ${icon} ${a.name}: ${a.action}${dur}${err}`);\n for (const warning of a.warnings ?? []) lines.push(` ⚠ ${warning}`);\n }\n if (report.halted && report.reason) {\n lines.push(` ! halted: ${report.reason}`);\n }\n return lines.join('\\n');\n}\n","import { readFileSync, writeFileSync, existsSync } from 'node:fs';\nimport { join, basename } from 'node:path';\nimport { execFile } from 'node:child_process';\nimport { ArchitectureArtifactsWriter } from '../adapters/storage/architecture-artifacts-writer.js';\nimport { CommunitySnapshotWriter } from '../adapters/storage/community-snapshot-writer.js';\nimport { loadGraph } from './graph-loader.js';\nimport { PageRankCalculator } from '../core/importance/pagerank-calculator.js';\nimport { DeadCodeDetector } from '../core/dead-code/dead-code-detector.js';\nimport { ArchitecturalOverlay } from '../core/overlay/architectural-overlay.js';\nimport type {\n VisCommunityLegend,\n VisualizationPayload,\n VisNode,\n VisEdge,\n VisFileInfo,\n} from '../core/graph/visualization-payload.js';\nimport type { BoundaryViolation, CommunityEntry } from '../core/types.js';\n\nexport interface VisualizeOptions {\n output?: string;\n maxNodes?: number;\n noBrowser?: boolean;\n}\n\nexport class VisualizeCommand {\n private readonly ctxoRoot: string;\n\n constructor(private readonly projectRoot: string) {\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n async run(options: VisualizeOptions = {}): Promise<void> {\n // 1. Read index and build graph\n const { graph, indices } = loadGraph(this.ctxoRoot);\n\n if (indices.length === 0) {\n console.error('[ctxo] No index found. Run \"ctxo index\" first.');\n process.exit(1);\n return;\n }\n\n console.error(`[ctxo] Building graph from ${indices.length} files...`);\n\n console.error(`[ctxo] Graph: ${graph.nodeCount} symbols, ${graph.edgeCount} edges`);\n\n // 3. Compute PageRank\n const pageRank = new PageRankCalculator();\n const prResult = pageRank.calculate(graph, { limit: 100_000 });\n const prMap = new Map<string, number>();\n for (const entry of prResult.rankings) {\n prMap.set(entry.symbolId, entry.score);\n }\n\n // 4. Detect dead code\n const deadDetector = new DeadCodeDetector();\n const deadResult = deadDetector.detect(graph);\n const deadMap = new Map<string, { confidence: number; reason: string }>();\n for (const d of deadResult.deadSymbols) {\n deadMap.set(d.symbolId, { confidence: d.confidence, reason: d.reason });\n }\n\n // 4b. Build complexity map from index data\n const complexityMap = new Map<string, number>();\n for (const fileIndex of indices) {\n if (fileIndex.complexity) {\n for (const c of fileIndex.complexity) {\n complexityMap.set(c.symbolId, c.cyclomatic);\n }\n }\n }\n\n // 4c. Build anti-pattern set (files with anti-patterns)\n const antiPatternFiles = new Set<string>();\n for (const fileIndex of indices) {\n if (fileIndex.antiPatterns.length > 0) {\n antiPatternFiles.add(fileIndex.file);\n }\n }\n\n // 5. Classify architectural layers\n const filePaths = [...new Set(indices.map(i => i.file))];\n const overlay = new ArchitecturalOverlay();\n const overlayResult = overlay.classify(filePaths);\n\n // Build file -> layer lookup\n const fileLayerMap = new Map<string, string>();\n for (const [layer, files] of Object.entries(overlayResult.layers)) {\n for (const file of files) {\n fileLayerMap.set(file, layer);\n }\n }\n\n // 5b. Load community snapshot + boundary violations produced by `ctxo index`.\n // These are read-only here — the writer guards are opt-in.\n const communityWriter = new CommunitySnapshotWriter(this.ctxoRoot, {\n allowProductionPath: true,\n });\n const currentSnapshot = communityWriter.readCurrent();\n const communityByIdForSymbol = new Map<string, { id: number; label: string }>();\n if (currentSnapshot) {\n for (const entry of currentSnapshot.communities as readonly CommunityEntry[]) {\n communityByIdForSymbol.set(entry.symbolId, {\n id: entry.communityId,\n label: entry.communityLabel,\n });\n }\n }\n const architectureWriter = new ArchitectureArtifactsWriter(this.ctxoRoot, {\n allowProductionPath: true,\n });\n const violationsArtifact = architectureWriter.readBoundaryViolations();\n const violationEdgeSeverity = new Map<string, BoundaryViolation['severity']>();\n if (violationsArtifact) {\n for (const v of violationsArtifact.violations as readonly BoundaryViolation[]) {\n violationEdgeSeverity.set(\n `${v.from.symbolId}|${v.to.symbolId}`,\n v.severity,\n );\n }\n }\n\n // 6. Build payload\n const totalSymbols = graph.nodeCount;\n let nodes: VisNode[] = graph.allNodes().map(sym => {\n const file = sym.symbolId.split('::')[0] ?? '';\n const dead = deadMap.get(sym.symbolId);\n const community = communityByIdForSymbol.get(sym.symbolId);\n return {\n id: sym.symbolId,\n name: sym.name,\n kind: sym.kind,\n file,\n startLine: sym.startLine,\n layer: fileLayerMap.get(file) ?? 'Unknown',\n pageRank: prMap.get(sym.symbolId) ?? 0,\n isDead: dead !== undefined,\n ...(dead ? { deadConfidence: dead.confidence, deadReason: dead.reason } : {}),\n cyclomatic: complexityMap.get(sym.symbolId),\n hasAntiPattern: antiPatternFiles.has(file),\n inDegree: graph.getReverseEdges(sym.symbolId).length,\n outDegree: graph.getForwardEdges(sym.symbolId).length,\n communityId: community?.id ?? -1,\n communityLabel: community?.label ?? 'unassigned',\n };\n });\n\n // 7. Apply --max-nodes filtering\n if (options.maxNodes && nodes.length > options.maxNodes) {\n nodes.sort((a, b) => b.pageRank - a.pageRank);\n nodes = nodes.slice(0, options.maxNodes);\n }\n\n const nodeIds = new Set(nodes.map(n => n.id));\n const edges: VisEdge[] = graph.allEdges()\n .filter(e => nodeIds.has(e.from) && nodeIds.has(e.to))\n .map(e => {\n const severity = violationEdgeSeverity.get(`${e.from}|${e.to}`);\n return {\n source: e.from,\n target: e.to,\n kind: e.kind,\n ...(severity ? { violationSeverity: severity } : {}),\n };\n });\n\n // Build per-file info (intent + anti-patterns)\n const filesInfo: VisFileInfo[] = indices\n .filter(fi => nodeIds.has(fi.symbols[0]?.symbolId ?? '___') || fi.symbols.some(s => nodeIds.has(s.symbolId)))\n .map(fi => ({\n file: fi.file,\n intent: fi.intent.map(i => ({ hash: i.hash, message: i.message, date: i.date })),\n antiPatterns: fi.antiPatterns.map(a => ({ hash: a.hash, message: a.message, date: a.date })),\n }));\n\n // Build community legend restricted to communities with visible members.\n const legendCounts = new Map<number, { label: string; count: number }>();\n for (const node of nodes) {\n if (node.communityId < 0) continue;\n const entry = legendCounts.get(node.communityId);\n if (entry) {\n entry.count += 1;\n } else {\n legendCounts.set(node.communityId, { label: node.communityLabel, count: 1 });\n }\n }\n const communities: VisCommunityLegend[] = [...legendCounts.entries()]\n .map(([id, { label, count }]) => ({ id, label, memberCount: count }))\n .sort((a, b) => b.memberCount - a.memberCount);\n\n const payload: VisualizationPayload = {\n projectName: basename(this.projectRoot),\n generatedAt: new Date().toISOString().split('T')[0]!,\n totalSymbols,\n shownSymbols: nodes.length,\n nodes,\n edges,\n layers: overlayResult.layers,\n files: filesInfo,\n communities,\n modularity: currentSnapshot?.modularity ?? 0,\n violationCount: violationsArtifact?.violations.length ?? 0,\n };\n\n // 8. Inject into template\n const templatePath = this.getTemplatePath();\n const template = readFileSync(templatePath, 'utf-8');\n // A function replacer keeps `$&` and `$'` in names literal; `<` is escaped so a title cannot close the script block.\n const html = template.replace('/*__CTXO_DATA__*/null', () => JSON.stringify(payload).replace(/</g, '\\\\u003c'));\n\n // 9. Write output\n const outputPath = options.output ?? join(this.ctxoRoot, 'visualize.html');\n writeFileSync(outputPath, html, 'utf-8');\n console.error(`[ctxo] Wrote visualization to ${outputPath}`);\n console.error(`[ctxo] ${nodes.length} symbols, ${edges.length} edges, ${deadResult.deadSymbols.length} dead`);\n\n // 10. Open in browser\n if (!options.noBrowser) {\n this.openInBrowser(outputPath);\n }\n }\n\n private getTemplatePath(): string {\n let dir = import.meta.dirname;\n for (let i = 0; i < 10; i++) {\n const candidate = join(dir, 'pages', 'visualize-template.html');\n if (existsSync(candidate)) return candidate;\n const parent = join(dir, '..');\n if (parent === dir) break;\n dir = parent;\n }\n throw new Error('Could not find visualize-template.html. Ensure the pages/ directory exists.');\n }\n\n private openInBrowser(filePath: string): void {\n // Use execFile (not exec) for safety - no shell interpretation\n const onError = (err: Error | null) => {\n if (err) {\n console.error(`[ctxo] Could not open browser: ${err.message}`);\n console.error(`[ctxo] Open manually: ${filePath}`);\n }\n };\n\n if (process.platform === 'win32') {\n execFile('cmd.exe', ['/c', 'start', '', filePath], onError);\n } else if (process.platform === 'darwin') {\n execFile('open', [filePath], onError);\n } else {\n execFile('xdg-open', [filePath], onError);\n }\n }\n}\n","import { JsonIndexReader } from '../adapters/storage/json-index-reader.js';\nimport { SymbolGraph } from '../core/graph/symbol-graph.js';\nimport type { FileIndex } from '../core/types.js';\n\nexport interface LoadedGraph {\n readonly graph: SymbolGraph;\n readonly indices: FileIndex[];\n}\n\n/** Build a SymbolGraph from the committed JSON index under `ctxoRoot`. */\nexport function loadGraph(ctxoRoot: string): LoadedGraph {\n const indices = new JsonIndexReader(ctxoRoot).readAll();\n const graph = new SymbolGraph();\n for (const fi of indices) for (const sym of fi.symbols) graph.addNode(sym);\n for (const fi of indices) for (const edge of fi.edges) graph.addEdge(edge);\n return { graph, indices };\n}\n","import { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { getVersion } from './cli-router.js';\nimport { discoverPlugins } from '../adapters/language/plugin-discovery.js';\nimport { loadManifestPath } from './plugin-loader.js';\nimport { fetchDistTagsBatch, type HttpsFetcher } from '../core/update/registry-client.js';\nimport {\n computePackageStates,\n detectChannel,\n markWorkspaceLinks,\n selectInstallTargets,\n} from '../core/update/update-plan.js';\nimport {\n resolvePackageManager,\n buildInstallCommand,\n isPackageManager,\n isWorkspaceRoot,\n readWorkspaceLinks,\n} from '../core/install/package-manager.js';\nimport { runPackageManager } from '../core/install/run-package-manager.js';\nimport { createLogger } from '../core/logger.js';\nimport type { PackageManager, Resolution } from '../core/install/package-manager.js';\nimport type { PackageState, Channel } from '../core/update/update-plan.js';\n\nconst log = createLogger('ctxo:update');\nconst CTXO_CLI_PACKAGE = '@ctxo/cli';\n\nexport type UpdateStrategy = 'execute' | 'print' | 'none';\n\nexport interface UpdatePlanShape {\n readonly manager: PackageManager;\n readonly managerSource: Resolution['source'];\n readonly managerDetail?: string;\n readonly global: boolean;\n readonly command: string;\n readonly args: readonly string[];\n}\n\nexport interface UpdateReport {\n readonly ctxo: string;\n readonly channel: Channel;\n readonly packages: readonly PackageState[];\n readonly plan: UpdatePlanShape | null;\n readonly strategy: UpdateStrategy;\n readonly executed: boolean;\n readonly exitCode?: number;\n}\n\nexport function formatText(report: UpdateReport): string {\n const lines: string[] = [];\n lines.push('ctxo update — checking registry for updates...');\n lines.push('');\n\n const updatesExist = report.packages.some((p) => p.status === 'update');\n if (!updatesExist && report.strategy !== 'print') {\n const total = report.packages.length;\n lines.push(`All ${total} package${total === 1 ? '' : 's'} are up to date.`);\n return lines.join('\\n');\n }\n\n const latestCell = (p: PackageState): string => {\n if (p.status === 'workspace') return '(local)';\n return p.latest ?? '(not found)';\n };\n\n const nameCol = Math.max(7, ...report.packages.map((p) => p.name.length));\n const curCol = Math.max(7, ...report.packages.map((p) => p.current.length));\n const latestCol = Math.max(15, ...report.packages.map((p) => latestCell(p).length));\n\n lines.push(\n `${'PACKAGE'.padEnd(nameCol)} ${'CURRENT'.padEnd(curCol)} ${`LATEST (${report.channel})`.padEnd(latestCol)} STATUS`,\n );\n for (const pkg of report.packages) {\n const statusText = renderStatus(pkg, report.channel);\n lines.push(\n `${pkg.name.padEnd(nameCol)} ${pkg.current.padEnd(curCol)} ${latestCell(pkg).padEnd(latestCol)} ${statusText}`,\n );\n }\n\n if (report.plan && report.strategy === 'execute') {\n lines.push('');\n lines.push(`Plan: ${report.plan.command} ${report.plan.args.join(' ')}`);\n lines.push(`Using ${report.plan.manager} (${formatManagerSource(report.plan)})`);\n lines.push('');\n lines.push('Running...');\n } else if (report.plan && report.strategy === 'print') {\n lines.push('');\n lines.push('To update, run:');\n lines.push(` ${report.plan.command} ${report.plan.args.join(' ')}`);\n }\n\n return lines.join('\\n');\n}\n\nfunction renderStatus(pkg: PackageState, reportChannel: Channel): string {\n switch (pkg.status) {\n case 'current': return 'up to date';\n case 'ahead': return 'ahead of registry';\n case 'workspace': return 'workspace link';\n case 'unknown': return pkg.reason === 'registry-404' ? 'skipped' : `error${pkg.reason ? ` (${pkg.reason})` : ''}`;\n case 'update':\n return pkg.channel === reportChannel ? 'update' : `update (${pkg.channel})`;\n }\n}\n\nfunction formatManagerSource(plan: UpdatePlanShape): string {\n return plan.managerDetail ? `${plan.managerSource}: ${plan.managerDetail}` : plan.managerSource;\n}\n\nexport function formatJson(report: UpdateReport): string {\n return JSON.stringify(\n {\n ctxo: report.ctxo,\n channel: report.channel,\n packages: report.packages,\n plan: report.plan,\n executed: report.executed,\n ...(report.exitCode !== undefined ? { exitCode: report.exitCode } : {}),\n },\n null,\n 2,\n );\n}\n\nexport interface UpdateOptions {\n readonly check?: boolean;\n readonly print?: boolean;\n readonly global?: boolean;\n readonly json?: boolean;\n readonly pm?: string;\n readonly force?: boolean;\n}\n\nexport interface UpdateCommandDeps {\n readonly discoverInstalled?: (projectRoot: string) => Promise<ReadonlyArray<{ name: string; version: string }>>;\n readonly fetcher?: HttpsFetcher;\n readonly runner?: (command: string, args: readonly string[], cwd: string) => Promise<number>;\n readonly setExitCode?: (code: number) => void;\n readonly env?: NodeJS.ProcessEnv;\n}\n\nexport class UpdateCommand {\n constructor(\n private readonly projectRoot: string,\n private readonly deps: UpdateCommandDeps = {},\n ) {}\n\n async run(options: UpdateOptions = {}): Promise<void> {\n if (options.pm && !isPackageManager(options.pm)) {\n this.emitError(`Unknown --pm value \"${options.pm}\".`);\n this.deps.setExitCode?.(1);\n return;\n }\n\n const discover = this.deps.discoverInstalled ?? defaultDiscoverInstalled;\n const installed = await discover(this.projectRoot);\n if (installed.length === 0) {\n this.emit(options.json ? '{}\\n' : 'ctxo update — no @ctxo/* packages discovered.\\n');\n return;\n }\n\n const names = installed.map((p) => p.name);\n const results = await fetchDistTagsBatch(names, { fetcher: this.deps.fetcher });\n\n const allMissed = results.every((r) => !('distTags' in r));\n if (allMissed) {\n this.emitError('registry unreachable for every package; aborting.');\n this.deps.setExitCode?.(1);\n return;\n }\n\n const rawStates = computePackageStates(installed, results);\n // Drop workspace-linked packages from the install plan; they live in this\n // repo as `workspace:*` deps, not registry consumers. Keep them visible in\n // the report so users see why they were skipped.\n const states = markWorkspaceLinks(rawStates, readWorkspaceLinks(this.projectRoot));\n const targets = selectInstallTargets(states);\n\n const cliVersion = getVersion();\n const channel = detectChannel(cliVersion);\n const plan = targets.length === 0 ? null : this.buildPlan(targets, options);\n const strategy = this.pickStrategy(targets, options);\n\n const baseReport: UpdateReport = {\n ctxo: cliVersion,\n channel,\n packages: states,\n plan,\n strategy,\n executed: false,\n };\n\n if (options.check) {\n // --check never executes, so render with the print-style block so the user\n // sees the suggested command instead of a misleading \"Running...\" line.\n const checkStrategy: UpdateStrategy = plan ? 'print' : strategy;\n this.emitReport({ ...baseReport, strategy: checkStrategy }, options.json ?? false);\n return;\n }\n\n if (strategy === 'none' || strategy === 'print' || !plan) {\n this.emitReport(baseReport, options.json ?? false);\n return;\n }\n\n if (!options.force && !options.global && isLockedCI(this.deps.env ?? process.env)) {\n this.emitReport({ ...baseReport, strategy: 'print' }, options.json ?? false);\n this.emitError('CI environment with frozen lockfile detected. Refusing to mutate. Use --force or --global.');\n this.deps.setExitCode?.(1);\n return;\n }\n\n if (!options.json) this.emitReport(baseReport, false);\n const run = this.deps.runner ?? runPackageManager;\n const code = await run(plan.command, plan.args, this.projectRoot);\n const finalReport: UpdateReport = { ...baseReport, executed: true, exitCode: code };\n if (options.json) this.emit(formatJson(finalReport) + '\\n');\n if (code !== 0) this.deps.setExitCode?.(code);\n }\n\n private buildPlan(\n targets: ReadonlyArray<{ name: string; version: string }>,\n options: UpdateOptions,\n ): UpdatePlanShape {\n const resolution = resolvePackageManager({\n flag: options.pm,\n projectRoot: this.projectRoot,\n env: this.deps.env,\n });\n const specifiers = targets.map((t) => `${t.name}@${t.version}`);\n const useGlobal = options.global || !this.projectHasCtxoDep();\n const invocation = buildInstallCommand(resolution.manager, specifiers, {\n global: useGlobal,\n workspaceRoot: !useGlobal && isWorkspaceRoot(this.projectRoot),\n });\n return {\n manager: resolution.manager,\n managerSource: resolution.source,\n managerDetail: resolution.detail,\n global: useGlobal,\n command: invocation.command,\n args: invocation.args,\n };\n }\n\n private pickStrategy(\n targets: ReadonlyArray<{ name: string; version: string }>,\n options: UpdateOptions,\n ): UpdateStrategy {\n if (targets.length === 0) return 'none';\n if (options.print) return 'print';\n if (options.global) return 'execute';\n return this.projectHasCtxoDep() ? 'execute' : 'print';\n }\n\n private projectHasCtxoDep(): boolean {\n const pkg = join(this.projectRoot, 'package.json');\n if (!existsSync(pkg)) return false;\n try {\n const json = JSON.parse(readFileSync(pkg, 'utf-8')) as {\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n };\n const merged = { ...(json.dependencies ?? {}), ...(json.devDependencies ?? {}) };\n return Object.keys(merged).some(\n (name) => name === CTXO_CLI_PACKAGE || name.startsWith('@ctxo/lang-') || name.startsWith('ctxo-lang-'),\n );\n } catch (err) {\n log.error(`failed to read project package.json: ${(err as Error).message}`);\n return false;\n }\n }\n\n private emit(text: string): void { process.stdout.write(text); }\n private emitError(text: string): void { process.stderr.write(`[ctxo] ${text}\\n`); }\n\n private emitReport(report: UpdateReport, json: boolean): void {\n if (json) this.emit(formatJson(report) + '\\n');\n else this.emit(formatText(report) + '\\n');\n }\n}\n\nexport async function defaultDiscoverInstalled(projectRoot: string): Promise<ReadonlyArray<{ name: string; version: string }>> {\n const out: Array<{ name: string; version: string }> = [{ name: CTXO_CLI_PACKAGE, version: getVersion() }];\n const manifestPath = loadManifestPath(projectRoot);\n if (!manifestPath) return out;\n const { plugins } = await discoverPlugins({ manifestPath });\n for (const p of plugins) out.push({ name: p.specifier, version: p.plugin.version });\n return out;\n}\n\nfunction isLockedCI(env: NodeJS.ProcessEnv): boolean {\n return env['CI'] === 'true' || env['CI'] === '1';\n}\n","import { request } from 'node:https';\nimport { createLogger } from '../logger.js';\n\nconst log = createLogger('ctxo:update:registry');\n\nexport interface RegistryDistTags {\n readonly [tag: string]: string;\n}\n\nexport interface RegistryHit {\n readonly name: string;\n readonly distTags: RegistryDistTags;\n}\n\nexport interface RegistryMiss {\n readonly name: string;\n readonly reason: 'registry-404' | 'registry-error' | 'timeout' | 'network';\n readonly status?: number;\n readonly message?: string;\n}\n\nexport type RegistryResult = RegistryHit | RegistryMiss;\n\nexport interface FetchOptions {\n readonly timeoutMs?: number;\n readonly fetcher?: HttpsFetcher;\n}\n\nexport type HttpsFetcher = (url: string, timeoutMs: number) => Promise<{ status: number; body: string }>;\n\nconst DEFAULT_TIMEOUT_MS = 5_000;\n\nexport async function fetchDistTags(\n packageName: string,\n options: FetchOptions = {},\n): Promise<RegistryResult> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const fetcher = options.fetcher ?? defaultHttpsFetcher;\n const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}`;\n\n let response: { status: number; body: string };\n try {\n response = await fetcher(url, timeoutMs);\n } catch (err) {\n return classifyFetchError(packageName, err);\n }\n\n if (response.status === 404) {\n return { name: packageName, reason: 'registry-404', status: 404 };\n }\n if (response.status < 200 || response.status >= 300) {\n return { name: packageName, reason: 'registry-error', status: response.status };\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(response.body);\n } catch {\n return { name: packageName, reason: 'registry-error', status: response.status, message: 'invalid JSON' };\n }\n const distTags = (parsed as { 'dist-tags'?: unknown })['dist-tags'];\n if (!distTags || typeof distTags !== 'object') {\n return { name: packageName, reason: 'registry-error', status: response.status, message: 'missing dist-tags' };\n }\n return { name: packageName, distTags: distTags as RegistryDistTags };\n}\n\nexport async function fetchDistTagsBatch(\n packageNames: readonly string[],\n options: FetchOptions = {},\n): Promise<RegistryResult[]> {\n return Promise.all(packageNames.map((name) => fetchDistTags(name, options)));\n}\n\nfunction classifyFetchError(name: string, err: unknown): RegistryMiss {\n const code = (err as NodeJS.ErrnoException)?.code;\n const message = (err as Error)?.message ?? String(err);\n if (code === 'ETIMEDOUT' || /timeout/i.test(message)) {\n return { name, reason: 'timeout', message };\n }\n if (code === 'ECONNREFUSED' || code === 'ECONNRESET' || code === 'ENOTFOUND' || code === 'EAI_AGAIN') {\n return { name, reason: 'network', message };\n }\n log.error(`unexpected fetch error for ${name}: ${message}`);\n return { name, reason: 'network', message };\n}\n\nconst defaultHttpsFetcher: HttpsFetcher = (url, timeoutMs) => new Promise((resolve, reject) => {\n const req = request(url, { method: 'GET', headers: { 'user-agent': 'ctxo-update', accept: 'application/json' } }, (res) => {\n const chunks: Buffer[] = [];\n res.on('data', (chunk: Buffer) => chunks.push(chunk));\n res.on('end', () => resolve({ status: res.statusCode ?? 0, body: Buffer.concat(chunks).toString('utf-8') }));\n res.on('error', reject);\n });\n req.setTimeout(timeoutMs, () => {\n req.destroy(Object.assign(new Error(`timeout after ${timeoutMs}ms`), { code: 'ETIMEDOUT' }));\n });\n req.on('error', reject);\n req.end();\n});\n","import type { RegistryResult } from './registry-client.js';\n\nexport type Channel = 'latest' | 'alpha' | 'beta' | 'rc' | 'next' | string;\n\nconst SEMVER_RE = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+[0-9A-Za-z.-]+)?$/;\n\ninterface ParsedSemver {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[]; // empty array means release\n}\n\nfunction parseSemver(version: string): ParsedSemver | null {\n const match = SEMVER_RE.exec(version.trim());\n if (!match) return null;\n const prereleaseRaw = match[4] ?? '';\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: prereleaseRaw ? prereleaseRaw.split('.') : [],\n };\n}\n\nexport function detectChannel(version: string): Channel {\n const parsed = parseSemver(version);\n if (!parsed || parsed.prerelease.length === 0) return 'latest';\n const first = parsed.prerelease[0]!;\n if (/^\\d+$/.test(first)) return 'latest';\n return first;\n}\n\nexport function compareSemver(a: string, b: string): -1 | 0 | 1 {\n const pa = parseSemver(a);\n const pb = parseSemver(b);\n if (!pa && !pb) return 0;\n if (!pa) return -1;\n if (!pb) return 1;\n\n if (pa.major !== pb.major) return pa.major < pb.major ? -1 : 1;\n if (pa.minor !== pb.minor) return pa.minor < pb.minor ? -1 : 1;\n if (pa.patch !== pb.patch) return pa.patch < pb.patch ? -1 : 1;\n\n // Prerelease ordering per semver section 11.\n if (pa.prerelease.length === 0 && pb.prerelease.length === 0) return 0;\n if (pa.prerelease.length === 0) return 1; // release > prerelease\n if (pb.prerelease.length === 0) return -1;\n\n const len = Math.max(pa.prerelease.length, pb.prerelease.length);\n for (let i = 0; i < len; i++) {\n const ai = pa.prerelease[i];\n const bi = pb.prerelease[i];\n if (ai === undefined) return -1;\n if (bi === undefined) return 1;\n const aNum = /^\\d+$/.test(ai);\n const bNum = /^\\d+$/.test(bi);\n if (aNum && bNum) {\n const an = Number(ai);\n const bn = Number(bi);\n if (an !== bn) return an < bn ? -1 : 1;\n } else if (aNum && !bNum) {\n return -1; // numeric < non-numeric\n } else if (!aNum && bNum) {\n return 1;\n } else if (ai !== bi) {\n return ai < bi ? -1 : 1;\n }\n }\n return 0;\n}\n\nexport type PackageStatus = 'current' | 'update' | 'ahead' | 'unknown' | 'workspace';\n\nexport interface PackageState {\n readonly name: string;\n readonly current: string;\n readonly latest: string | null;\n readonly channel: Channel;\n readonly status: PackageStatus;\n readonly reason?: 'registry-404' | 'registry-error' | 'timeout' | 'network';\n}\n\nexport interface InstalledPackage {\n readonly name: string;\n readonly version: string;\n}\n\nexport function computePackageStates(\n installed: readonly InstalledPackage[],\n results: readonly RegistryResult[],\n): PackageState[] {\n const byName = new Map<string, RegistryResult>();\n for (const r of results) byName.set(r.name, r);\n\n return installed.map((pkg) => {\n const installedChannel = detectChannel(pkg.version);\n const result = byName.get(pkg.name);\n\n if (!result) {\n return { name: pkg.name, current: pkg.version, latest: null, channel: installedChannel, status: 'unknown' as const };\n }\n if (!('distTags' in result)) {\n return { name: pkg.name, current: pkg.version, latest: null, channel: installedChannel, status: 'unknown' as const, reason: result.reason };\n }\n\n // Pick the channel we actually have a version for. If the installed channel\n // is not published, fall back to \"latest\" so the row reports the real source.\n const hasInstalledChannel = typeof result.distTags[installedChannel] === 'string';\n const targetChannel: Channel = hasInstalledChannel ? installedChannel : 'latest';\n const target = result.distTags[targetChannel] ?? null;\n if (!target) {\n return { name: pkg.name, current: pkg.version, latest: null, channel: installedChannel, status: 'unknown' as const };\n }\n const cmp = compareSemver(pkg.version, target);\n const status: PackageStatus = cmp === 0 ? 'current' : cmp < 0 ? 'update' : 'ahead';\n return { name: pkg.name, current: pkg.version, latest: target, channel: targetChannel, status };\n });\n}\n\nexport function selectInstallTargets(states: readonly PackageState[]): ReadonlyArray<{ name: string; version: string }> {\n return states\n .filter((s): s is PackageState & { latest: string } => s.status === 'update' && typeof s.latest === 'string')\n .filter((s) => isSafeVersionSpecifier(s.latest))\n .map((s) => ({ name: s.name, version: s.latest }));\n}\n\n/**\n * Override the status of any package whose name appears in `workspaceLinkNames`\n * to `'workspace'`. Workspace-linked packages (pnpm `workspace:*` / yarn\n * `workspace:^`) are local source, not registry consumers — they must never\n * appear in the install plan or be \"upgraded\" to a registry version. They are\n * still shown in the report table so users see why a row is being skipped.\n */\nexport function markWorkspaceLinks(\n states: readonly PackageState[],\n workspaceLinkNames: ReadonlySet<string>,\n): PackageState[] {\n return states.map((s) =>\n workspaceLinkNames.has(s.name)\n ? { ...s, status: 'workspace' as const, latest: null }\n : s,\n );\n}\n\n// Strict semver-ish regex: digits, letters, dots, plus, minus only. Matches the\n// SEMVER_RE prefix without anchoring full structure (safe enough to feed to a\n// shell when shell:true is in effect on Windows).\nconst SAFE_SPECIFIER_RE = /^[0-9A-Za-z.+-]+$/;\n\nexport function isSafeVersionSpecifier(version: string): boolean {\n return SAFE_SPECIFIER_RE.test(version);\n}\n","import { join } from 'node:path';\nimport { loadGraph } from './graph-loader.js';\nimport { BlastRadiusCalculator } from '../core/blast-radius/blast-radius-calculator.js';\nimport { findCoChangedFilesForBlastRadius } from '../core/blast-radius/co-changed-files.js';\nimport { CoChangeReader } from '../adapters/storage/co-change-reader.js';\n\nexport interface BlastRadiusOptions {\n symbolId: string;\n json?: boolean;\n}\n\nexport class BlastRadiusCommand {\n private readonly ctxoRoot: string;\n constructor(projectRoot: string) {\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n run(options: BlastRadiusOptions): void {\n const { graph } = loadGraph(this.ctxoRoot);\n // Resolve the id once, as the get_blast_radius tool does: a 2-part data id names its winning definition.\n const root = graph.getNode(options.symbolId);\n if (!root) {\n process.stdout.write(JSON.stringify({ found: false, symbolId: options.symbolId }) + '\\n');\n return;\n }\n // Same tiering as the get_blast_radius tool: co-change upgrades a potential dependent to likely.\n const coChangeMap = new CoChangeReader(this.ctxoRoot).readCoChangeMap();\n const result = new BlastRadiusCalculator().calculate(graph, root.symbolId, coChangeMap);\n\n const coChangedFiles = findCoChangedFilesForBlastRadius(coChangeMap, root.symbolId, result.impactedSymbols);\n\n const payload = {\n found: true,\n symbolId: options.symbolId,\n directDependentsCount: result.directDependentsCount,\n confirmedCount: result.confirmedCount,\n likelyCount: result.likelyCount,\n potentialCount: result.potentialCount,\n overallRiskScore: result.overallRiskScore,\n impactedSymbols: result.impactedSymbols.map((s) => ({\n symbolId: s.symbolId, confidence: s.confidence, depth: s.depth,\n })),\n // Informational: files that change together with the symbol's file but have no dependency path to it.\n ...(coChangedFiles.length > 0 ? { coChangedFiles } : {}),\n };\n process.stdout.write(JSON.stringify(payload) + '\\n');\n }\n}\n","import { join } from 'node:path';\nimport { ContextsViewReader } from '../adapters/storage/contexts-view-reader.js';\n\nexport interface ContextsOptions {\n json?: boolean;\n}\n\nconst NO_VIEW_HINT = 'No contexts view. Run ctxo index (without --skip-community).';\n\nexport class ContextsCommand {\n private readonly ctxoRoot: string;\n\n constructor(projectRoot: string) {\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n run(options: ContextsOptions): void {\n const view = new ContextsViewReader(this.ctxoRoot).readContextsView();\n\n if (options.json) {\n process.stdout.write(\n view\n ? JSON.stringify(view, null, 2) + '\\n'\n : JSON.stringify({ found: false, hint: NO_VIEW_HINT }) + '\\n',\n );\n return;\n }\n\n if (!view) {\n console.error(NO_VIEW_HINT);\n return;\n }\n\n const { coverage, candidates, hubs, unclustered, collisions } = view;\n const shared = view.dataResources.filter((resource) => resource.accesses.length >= 2);\n const pct = Math.round(coverage.ratio * 100);\n const lines = [\n `[ctxo] Contexts view at ${view.commitSha}: ${candidates.length} candidates cover ${coverage.covered}/${coverage.files} files (${pct}%), ${hubs.length} hubs, ${unclustered.count} unclustered, ${collisions.length} collisions, ${shared.length} shared tables`,\n ];\n for (const c of candidates) {\n const terms = c.topTerms.slice(0, 3).map((t) => t.term).join(', ');\n const tables = c.sharedTables.length > 0 ? ` shared tables: ${c.sharedTables.length}` : '';\n lines.push(`#${c.id} ${c.fileCount} files cohesion ${c.cohesion} ${c.label} terms: ${terms}${tables}`);\n }\n for (const h of hubs) {\n const target = h.candidate === undefined ? 'unassigned' : `#${h.candidate}`;\n lines.push(`hub ${h.file} (${h.reasons.join(', ')}, ${h.dependents} dependents) -> ${target}`);\n }\n for (const r of shared) {\n const kind = r.external ? 'external' : (r.kind ?? 'table');\n const accesses = r.accesses.map((a) => `#${a.candidate} ${a.modes.join('+')}`).join(', ');\n const writers =\n r.owner !== undefined ? `owner #${r.owner}` : r.writers.length > 1 ? 'several writers' : 'read only';\n lines.push(`shared ${kind} ${r.name} ${accesses} ${writers}`);\n }\n console.error(lines.join('\\n'));\n }\n}\n","import { join, relative, sep } from 'node:path';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { loadConfig } from '../core/config/load-config.js';\nimport { resolveGateThresholds } from '../core/gate/gate-config.js';\nimport { loadGraph } from './graph-loader.js';\nimport { JsonIndexReader } from '../adapters/storage/json-index-reader.js';\nimport { lineOfSnippet, locateSymbolAtLine } from '../core/gate/symbol-locator.js';\nimport { transcriptHasBlastCheck } from '../core/gate/transcript-scan.js';\nimport { GateSessionStore } from '../adapters/gate/gate-session-store.js';\nimport { BlastRadiusCalculator } from '../core/blast-radius/blast-radius-calculator.js';\nimport { CoChangeReader } from '../adapters/storage/co-change-reader.js';\nimport { PageRankCalculator } from '../core/importance/pagerank-calculator.js';\nimport { percentileCutoff } from '../core/gate/percentile.js';\nimport { shouldBlock, formatBlockReason } from '../core/gate/gate-decision.js';\nimport { createLogger } from '../core/logger.js';\nimport { readSourceText } from './read-source.js';\n\nconst log = createLogger('ctxo:gate-hook');\n\nconst RANK_ALL = 100_000; // effectively unbounded: rank every node\n\nexport interface HookPayload {\n session_id: string;\n transcript_path: string;\n tool_name: string;\n tool_input: { file_path?: string; old_string?: string; new_string?: string };\n}\n\nexport interface HookDecision { block: boolean; reason?: string; }\n\nexport class GateHookCommand {\n private readonly ctxoRoot: string;\n private readonly cacheDir: string;\n constructor(private readonly projectRoot: string) {\n this.ctxoRoot = join(projectRoot, '.ctxo');\n this.cacheDir = join(this.ctxoRoot, '.cache');\n }\n\n /** Pure-ish decision: never throws (fail-open). */\n evaluate(payload: HookPayload): HookDecision {\n try {\n if (payload.tool_name !== 'Edit') return { block: false };\n const filePath = payload.tool_input?.file_path;\n const oldString = payload.tool_input?.old_string;\n if (!filePath || !oldString) return { block: false };\n\n // loadConfig takes ctxoRoot (.ctxo directory) and returns LoadedConfig wrapper\n const loaded = loadConfig(this.ctxoRoot);\n const thresholds = resolveGateThresholds(loaded.config.gate);\n if (!thresholds.enabled) return { block: false };\n\n const relPath = relative(this.projectRoot, filePath).split(sep).join('/');\n const indexFile = join(this.ctxoRoot, 'index', `${relPath}.json`);\n if (!existsSync(indexFile)) return { block: false };\n\n const fileIndex = new JsonIndexReader(this.ctxoRoot).readSingle(indexFile);\n if (!fileIndex) return { block: false };\n\n if (!existsSync(filePath)) return { block: false };\n // The same decoder the index uses, so a UTF-16 script (SSMS) gives the lines its symbols were indexed at.\n const source = readSourceText(filePath);\n const line = lineOfSnippet(source, oldString);\n if (line === null) return { block: false };\n\n const symbolId = locateSymbolAtLine(fileIndex, line);\n if (!symbolId) return { block: false };\n\n const store = new GateSessionStore(this.cacheDir);\n if (store.hasWarned(payload.session_id, symbolId)) return { block: false };\n if (payload.transcript_path && existsSync(payload.transcript_path)) {\n const lines = readFileSync(payload.transcript_path, 'utf-8').split('\\n').filter(Boolean);\n if (transcriptHasBlastCheck(lines, symbolId)) return { block: false };\n }\n\n const { graph } = loadGraph(this.ctxoRoot);\n const edited = graph.getNode(symbolId);\n if (!edited) return { block: false };\n // A copy of a table, view or procedure stands for the resource: the blast radius counts the resource's\n // dependents (the calculator resolves that), and its importance is the winning definition's PageRank,\n // because every data edge points at the winner.\n const importanceId = graph.dataResourceIdentity(edited.symbolId)?.winner.symbolId ?? edited.symbolId;\n // The guard counts confirmed + likely dependents, and co-change is what makes some of them likely.\n // One read per hook process, and only now that the edit is known to need a blast radius. The reader\n // never throws: a missing or invalid co-changes.json means the graph alone decides, as before.\n const coChangeMap = new CoChangeReader(this.ctxoRoot).readCoChangeMap();\n const blast = new BlastRadiusCalculator().calculate(graph, edited.symbolId, coChangeMap);\n const riskCount = blast.confirmedCount + blast.likelyCount;\n\n const pr = new PageRankCalculator().calculate(graph, { limit: RANK_ALL });\n const prMap = new Map(pr.rankings.map((r) => [r.symbolId, r.score]));\n const cutoff = percentileCutoff([...prMap.values()], thresholds.percentile);\n const importanceScore = prMap.get(importanceId) ?? 0;\n\n const block = shouldBlock({ riskCount, importanceScore, importanceCutoff: cutoff }, thresholds);\n if (!block) return { block: false };\n\n store.recordWarned(payload.session_id, symbolId);\n const name = symbolId.split('::')[1] ?? symbolId;\n const top = blast.impactedSymbols\n .filter((s) => s.confidence !== 'potential')\n .map((s) => s.symbolId);\n return { block: true, reason: formatBlockReason(name, riskCount, top) };\n } catch (err) {\n log.error(`${(err as Error).message}`);\n return { block: false };\n }\n }\n\n async run(): Promise<void> {\n try {\n const payload = await this.readStdin();\n if (payload) {\n const decision = this.evaluate(payload);\n if (decision.block) this.emitBlock(decision.reason ?? 'ctxo guard');\n }\n } catch (err) {\n log.error(`${(err as Error).message}`);\n }\n process.exit(0);\n }\n\n /** PreToolUse block contract (verified): exit 0 + stdout JSON deny. */\n private emitBlock(reason: string): void {\n process.stdout.write(JSON.stringify({\n hookSpecificOutput: {\n hookEventName: 'PreToolUse',\n permissionDecision: 'deny',\n permissionDecisionReason: reason,\n },\n }) + '\\n');\n process.exit(0);\n }\n\n private readStdin(): Promise<HookPayload | null> {\n return new Promise((resolve) => {\n let data = '';\n process.stdin.setEncoding('utf-8');\n process.stdin.on('data', (c) => { data += c; });\n process.stdin.on('end', () => {\n try { resolve(JSON.parse(data) as HookPayload); } catch { resolve(null); }\n });\n process.stdin.on('error', () => resolve(null));\n });\n }\n}\n","import type { GateConfig } from '../config/config-schema.js';\n\nexport interface ResolvedGate {\n readonly enabled: boolean;\n readonly percentile: number;\n readonly minDependents: number;\n}\n\nconst DIAL: Record<NonNullable<GateConfig['sensitivity']>, { percentile: number; minDependents: number }> = {\n strict: { percentile: 30, minDependents: 2 },\n balanced: { percentile: 15, minDependents: 3 },\n lenient: { percentile: 5, minDependents: 5 },\n};\n\nexport function resolveGateThresholds(gate: GateConfig | undefined): ResolvedGate {\n const dial = DIAL[gate?.sensitivity ?? 'balanced'];\n return {\n enabled: gate?.enabled ?? true,\n percentile: gate?.percentile ?? dial.percentile,\n minDependents: gate?.minDependents ?? dial.minDependents,\n };\n}\n","import type { FileIndex } from '../types.js';\n\n/**\n * 0-based line where `snippet` begins in `source`, or null if not found.\n * 0-based to match the ctxo index, whose `startLine`/`endLine` are stored as\n * `getStartLineNumber() - 1` by the language adapters (see ts-morph-adapter.ts).\n */\nexport function lineOfSnippet(source: string, snippet: string): number | null {\n const idx = source.indexOf(snippet);\n if (idx === -1) return null;\n let line = 0;\n for (let i = 0; i < idx; i++) {\n if (source.codePointAt(i) === 10 /* \\n */) line++;\n }\n return line;\n}\n\n/** symbolId of the innermost symbol whose [startLine,endLine] contains `line` (all 0-based). */\nexport function locateSymbolAtLine(fileIndex: FileIndex, line: number): string | null {\n let best: { id: string; span: number } | null = null;\n for (const s of fileIndex.symbols) {\n if (line >= s.startLine && line <= s.endLine) {\n const span = s.endLine - s.startLine;\n if (best === null || span < best.span) best = { id: s.symbolId, span };\n }\n }\n return best?.id ?? null;\n}\n","function fileAndName(symbolId: string): string {\n const [file, name] = symbolId.split('::');\n return `${file}::${name}`;\n}\n\n/**\n * True if any transcript line records a get_blast_radius tool call whose\n * symbolId argument matches `symbolId` by file::name (kind-insensitive).\n */\nexport function transcriptHasBlastCheck(lines: readonly string[], symbolId: string): boolean {\n const target = fileAndName(symbolId);\n for (const line of lines) {\n if (!line.includes('get_blast_radius')) continue;\n let entry: unknown;\n try { entry = JSON.parse(line); } catch { continue; }\n const content = (entry as { message?: { content?: unknown[] } })?.message?.content;\n if (!Array.isArray(content)) continue;\n for (const block of content) {\n const b = block as { type?: string; name?: string; input?: { symbolId?: string } };\n if (b?.type === 'tool_use' && typeof b.name === 'string' && b.name.includes('get_blast_radius')) {\n const id = b.input?.symbolId;\n if (typeof id === 'string' && fileAndName(id) === target) return true;\n }\n }\n }\n return false;\n}\n","import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { createLogger } from '../../core/logger.js';\n\nconst log = createLogger('ctxo:gate-store');\n\n/** Tracks which symbols the gate has already warned about, per session. */\nexport class GateSessionStore {\n constructor(private readonly cacheDir: string) {}\n\n private file(sessionId: string): string {\n const safe = sessionId.replace(/[^a-zA-Z0-9_-]/g, '_');\n return join(this.cacheDir, 'gate', `${safe}.json`);\n }\n\n private read(sessionId: string): Set<string> {\n const f = this.file(sessionId);\n if (!existsSync(f)) return new Set();\n try {\n return new Set(JSON.parse(readFileSync(f, 'utf-8')) as string[]);\n } catch (err) {\n log.error(`${(err as Error).message}`);\n return new Set();\n }\n }\n\n hasWarned(sessionId: string, symbolId: string): boolean {\n return this.read(sessionId).has(symbolId);\n }\n\n recordWarned(sessionId: string, symbolId: string): void {\n try {\n const set = this.read(sessionId);\n set.add(symbolId);\n const f = this.file(sessionId);\n mkdirSync(join(this.cacheDir, 'gate'), { recursive: true });\n writeFileSync(f, JSON.stringify([...set]), 'utf-8');\n } catch (err) {\n log.error(`${(err as Error).message}`);\n }\n }\n}\n","/**\n * The score value at the top-`topPercent`% boundary. A score >= the returned\n * cutoff is in the top `topPercent`% of the distribution. Empty input returns\n * Infinity so that \"in top P%\" is always false (nothing to gate on).\n */\nexport function percentileCutoff(scores: readonly number[], topPercent: number): number {\n if (scores.length === 0) return Infinity;\n const sorted = [...scores].sort((a, b) => a - b);\n const rank = Math.ceil(((100 - topPercent) / 100) * sorted.length);\n const idx = Math.min(Math.max(rank, 0), sorted.length - 1);\n return sorted[idx]!;\n}\n","import type { ResolvedGate } from './gate-config.js';\n\nconst MAX_TOP_DEPENDENTS = 8;\n\nexport interface GateInput {\n /** confirmed + likely dependents of the edited symbol (primary risk signal). */\n readonly riskCount: number;\n /** PageRank of the edited symbol. */\n readonly importanceScore: number;\n /** PageRank value at the top-percentile boundary for this repo. */\n readonly importanceCutoff: number;\n}\n\nexport function shouldBlock(input: GateInput, t: ResolvedGate): boolean {\n if (!t.enabled) return false;\n return input.riskCount >= t.minDependents && input.importanceScore >= input.importanceCutoff;\n}\n\n/** One-time guard message injected into the block reason. */\nexport function formatBlockReason(\n symbolName: string,\n riskCount: number,\n topDependents: readonly string[],\n): string {\n const list = topDependents.slice(0, MAX_TOP_DEPENDENTS).map((d) => ` - ${d}`).join('\\n');\n return [\n `⚠ ctxo guard: \"${symbolName}\" is a high-impact symbol - ${riskCount} confirmed/likely dependents may break.`,\n topDependents.length > 0 ? `Top dependents:\\n${list}` : '',\n `Call get_blast_radius / get_why_context before editing. This guard fires once per symbol per session - re-issue the edit to proceed.`,\n ].filter(Boolean).join('\\n');\n}\n","import { join } from 'node:path';\nimport { loadConfig } from '../core/config/load-config.js';\nimport { resolveGateThresholds } from '../core/gate/gate-config.js';\nimport { loadGraph } from './graph-loader.js';\nimport { BlastRadiusCalculator } from '../core/blast-radius/blast-radius-calculator.js';\nimport { CoChangeReader } from '../adapters/storage/co-change-reader.js';\nimport { PageRankCalculator } from '../core/importance/pagerank-calculator.js';\nimport { percentileCutoff } from '../core/gate/percentile.js';\nimport { shouldBlock } from '../core/gate/gate-decision.js';\n\nconst RANK_ALL = 100_000;\n\nexport interface GatePreviewOptions { json?: boolean; }\n\nexport class GateCommand {\n private readonly ctxoRoot: string;\n constructor(projectRoot: string) {\n this.ctxoRoot = join(projectRoot, '.ctxo');\n }\n\n preview(options: GatePreviewOptions = {}): void {\n const gate = loadConfig(this.ctxoRoot).config.gate;\n const thresholds = resolveGateThresholds(gate);\n const { graph } = loadGraph(this.ctxoRoot);\n const pr = new PageRankCalculator().calculate(graph, { limit: RANK_ALL });\n const prMap = new Map(pr.rankings.map((r) => [r.symbolId, r.score]));\n const cutoff = percentileCutoff([...prMap.values()], thresholds.percentile);\n\n // The guard counts confirmed + likely dependents and co-change makes some of them likely, so the\n // preview reads the matrix once and applies it to every symbol, as the hook does.\n const coChangeMap = new CoChangeReader(this.ctxoRoot).readCoChangeMap();\n const calc = new BlastRadiusCalculator();\n const firing: Array<{ symbolId: string; riskCount: number; importance: number }> = [];\n for (const symbolId of prMap.keys()) {\n // As the hook does: a copy of a table, view or procedure has the winning definition's importance.\n const importance = prMap.get(graph.dataResourceIdentity(symbolId)?.winner.symbolId ?? symbolId) ?? 0;\n if (importance < cutoff) continue;\n const blast = calc.calculate(graph, symbolId, coChangeMap);\n const riskCount = blast.confirmedCount + blast.likelyCount;\n if (shouldBlock({ riskCount, importanceScore: importance, importanceCutoff: cutoff }, thresholds)) {\n firing.push({ symbolId, riskCount, importance: Math.round(importance * 1e4) / 1e4 });\n }\n }\n firing.sort((a, b) => b.riskCount - a.riskCount);\n\n const payload = {\n sensitivity: gate?.sensitivity ?? 'balanced',\n thresholds,\n totalSymbols: graph.nodeCount,\n wouldFireCount: firing.length,\n symbols: firing.slice(0, 50),\n };\n if (options.json) { process.stdout.write(JSON.stringify(payload, null, 2) + '\\n'); return; }\n console.error(`[ctxo] gate preview (${payload.sensitivity}): ${firing.length}/${graph.nodeCount} symbols would gate.`);\n for (const f of firing.slice(0, 25)) console.error(` ${f.riskCount} dep ${f.symbolId}`);\n }\n}\n"],"mappings":"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","names":["readFileSync","existsSync","dirname","join","execFileSync","readFileSync","writeFileSync","existsSync","readdirSync","join","relative","extname","isAbsolute","resolve","createRequire","existsSync","readFileSync","dirname","log","readFileSync","existsSync","dirname","existsSync","createRequire","join","existsSync","extname","join","existsSync","readFileSync","dirname","join","resolve","existsSync","join","existsSync","join","createRequire","readFileSync","execFileSync","existsSync","join","existsSync","join","execFileSync","existsSync","join","existsSync","readFileSync","join","resolve","log","join","readFileSync","existsSync","resolve","createHash","fileOf","known","createHash","existsSync","join","mkdirSync","existsSync","readFileSync","dirname","join","resolve","join","mkdirSync","dirname","existsSync","readFileSync","resolve","readFileSync","existsSync","mkdirSync","join","dirname","UndirectedGraph","UndirectedGraph","createRequire","join","relative","files","existsSync","execFileSync","readFileSync","readdirSync","extname","writeFileSync","resolve","isAbsolute","join","join","join","existsSync","execFileSync","join","existsSync","execFileSync","join","tmpdir","join","tmpdir","isAbsolute","join","relative","existsSync","readFileSync","writeFileSync","mkdirSync","createRequire","existsSync","readFileSync","writeFileSync","mkdirSync","statSync","join","dirname","relative","sep","eolShape","existsSync","readFileSync","join","statSync","join","mkdirSync","dirname","writeFileSync","existsSync","readFileSync","relative","sep","execFileSync","join","resolve","requireCjs","createRequire","relative","isAbsolute","mkdirSync","existsSync","join","selectedTools","readFileSync","require","writeFileSync","join","extname","relative","execFileSync","join","relative","extname","commits","intent","antiPatterns","source","fileIndex","execFileSync","join","existsSync","readFileSync","join","existsSync","readFileSync","writeFileSync","join","existsSync","log","createRequire","require","SUPPORTED_API_VERSIONS","SUPPORTED_API_VERSIONS","createRequire","require","createRequire","createRequire","existsSync","readdirSync","join","dirname","require","createRequire","join","dirname","existsSync","readdirSync","createRequire","spawnSync","existsSync","readdirSync","join","dirname","spawnSync","strip","createRequire","join","dirname","existsSync","readdirSync","spawnSync","execFileSync","existsSync","readFileSync","join","execFileSync","existsSync","join","readFileSync","existsSync","execFileSync","join","pass","warn","join","existsSync","execFileSync","existsSync","readFileSync","join","initSqlJs","existsSync","readFileSync","join","join","existsSync","readFileSync","existsSync","readdirSync","statSync","join","execFileSync","existsSync","mkdirSync","rmSync","unlinkSync","createRequire","dirname","join","join","existsSync","listGitFiles","unlinkSync","dirname","rmSync","execFileSync","createRequire","mkdirSync","join","getVersion","existsSync","readFileSync","writeFileSync","existsSync","join","join","readFileSync","writeFileSync","existsSync","existsSync","readFileSync","join","log","resolve","log","formatJson","isLockedCI","run","join","existsSync","readFileSync","join","join","join","join","join","relative","sep","existsSync","readFileSync","existsSync","mkdirSync","readFileSync","writeFileSync","join","log","join","existsSync","readFileSync","mkdirSync","writeFileSync","log","join","relative","sep","existsSync","readFileSync","resolve","join","RANK_ALL","join","join","existsSync","readFileSync","dirname"]}
|