@ctxo/cli 0.13.1 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +16 -0
  2. package/dist/chunk-2Q76LH2H.js +186 -0
  3. package/dist/chunk-2Q76LH2H.js.map +1 -0
  4. package/dist/chunk-72CEQEQD.js +53 -0
  5. package/dist/chunk-72CEQEQD.js.map +1 -0
  6. package/dist/chunk-7HSA5JVP.js +1049 -0
  7. package/dist/chunk-7HSA5JVP.js.map +1 -0
  8. package/dist/chunk-G4BMKCKG.js +76 -0
  9. package/dist/chunk-G4BMKCKG.js.map +1 -0
  10. package/dist/chunk-L2CAUER6.js +508 -0
  11. package/dist/chunk-L2CAUER6.js.map +1 -0
  12. package/dist/chunk-LAX6VVBU.js +98 -0
  13. package/dist/chunk-LAX6VVBU.js.map +1 -0
  14. package/dist/chunk-SRQZDGFZ.js +128 -0
  15. package/dist/chunk-SRQZDGFZ.js.map +1 -0
  16. package/dist/{chunk-DT3ZH4AU.js → chunk-X4TVFJ4C.js} +6 -1
  17. package/dist/chunk-X4TVFJ4C.js.map +1 -0
  18. package/dist/{chunk-WB7WZKX4.js → chunk-ZL36YS2V.js} +766 -1614
  19. package/dist/chunk-ZL36YS2V.js.map +1 -0
  20. package/dist/{cli-router-DDHH4WQH.js → cli-router-AZCDNX5R.js} +980 -504
  21. package/dist/cli-router-AZCDNX5R.js.map +1 -0
  22. package/dist/index.js +13 -2874
  23. package/dist/index.js.map +1 -1
  24. package/dist/internal.d.ts +747 -0
  25. package/dist/internal.js +13 -0
  26. package/dist/{json-index-reader-OXTRTGE6.js → json-index-reader-DBW32TCN.js} +6 -4
  27. package/dist/json-index-reader-DBW32TCN.js.map +1 -0
  28. package/dist/mcp-server-6YG2QE6E.js +2604 -0
  29. package/dist/mcp-server-6YG2QE6E.js.map +1 -0
  30. package/dist/module-host-KNMKS62R.js +13 -0
  31. package/dist/module-host-KNMKS62R.js.map +1 -0
  32. package/dist/module-loader-B3LYF3W7.js +14 -0
  33. package/dist/module-loader-B3LYF3W7.js.map +1 -0
  34. package/dist/plugin-discovery-XRXI3IJF.js +13 -0
  35. package/dist/plugin-discovery-XRXI3IJF.js.map +1 -0
  36. package/llms-full.txt +54 -0
  37. package/llms.txt +11 -0
  38. package/package.json +13 -2
  39. package/dist/chunk-DT3ZH4AU.js.map +0 -1
  40. package/dist/chunk-WB7WZKX4.js.map +0 -1
  41. package/dist/cli-router-DDHH4WQH.js.map +0 -1
  42. /package/dist/{json-index-reader-OXTRTGE6.js.map → internal.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ discoverPlugins,
4
+ resolvePackageCandidates,
5
+ resolvePluginPackageJson
6
+ } from "./chunk-2Q76LH2H.js";
7
+ import "./chunk-5DSKZJNN.js";
8
+ export {
9
+ discoverPlugins,
10
+ resolvePackageCandidates,
11
+ resolvePluginPackageJson
12
+ };
13
+ //# sourceMappingURL=plugin-discovery-XRXI3IJF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/llms-full.txt CHANGED
@@ -13,6 +13,9 @@ ctxo index --check # CI gate: fail if index stale (writes nothing, re
13
13
  ctxo index --commit HEAD # Re-index the files one commit changed (what the post-commit hook runs)
14
14
  ctxo index --files a.ts b.ts # Re-index only these files (alias: --file <path>)
15
15
  ctxo # Start MCP server (stdio transport)
16
+ ctxo install domain # opt-in domain knowledge layer (@ctxo/domain)
17
+ ctxo init --domain # registry skeleton, fold guard hooks, skill, domain config
18
+ ctxo verify-domain --since origin/main # CI gate for contexts, cards, rule IDs, boundaries
16
19
  ```
17
20
 
18
21
  MCP client configuration:
@@ -494,6 +497,57 @@ Title path joined with ` > `; whitespace collapsed; runs of `:` collapsed and a
494
497
 
495
498
  ---
496
499
 
500
+ ## Domain Knowledge Layer: `@ctxo/domain` (unreleased, #156 PR 2B)
501
+
502
+ An opt-in package that lets a team name its bounded contexts and keep markdown cards in step with code. Ctxo supplies structure, linkage, verification and retrieval; it never writes domain text or fetches external documentation. Feature doc: docs/features/domain-knowledge.md ("Named contexts and the domain package", "Ctxo domain conventions v1"). Design record: docs/architecture/ADR/adr-018-domain-knowledge-layer.md.
503
+
504
+ ### Install and loading
505
+
506
+ - `ctxo install domain` installs `@ctxo/domain` at the CLI's version (globally when the project has no `package.json`; `npm i -g @ctxo/cli @ctxo/domain @ctxo/lang-sql` is the supported path for such repositories). `ctxo init --domain` also sets it up.
507
+ - The CLI loads the package from the project's `node_modules`, then from next to itself, through `@ctxo/cli/internal` (types only, plus `createModuleHost`). Only a copy at the same `major.minor` loads; `@ctxo/cli` and `@ctxo/domain` share one version.
508
+ - Without the package: no domain commands, fields or hooks. A known domain command name (`verify-domain`, `contexts-touched`, `domain`) prints an install hint and exits 1; `ctxo domain-guard-hook` exits 0 without output; `ctxo --help` ends with one install hint line. With the package and no registry: the commands print a hint and exit 0 and no `context` fields appear.
509
+
510
+ ### Registry and cards
511
+
512
+ - `docs/domain/contexts.yaml` (`domain.registry`): `version: 1`, `contexts[]` with `id` (kebab-case, permanent), `name`, `card` (optional only at rung fear), `paths` (globs), `rung` (fear, pinned, named, bounded, boring), `rulePrefix`, `contracts` (target context to allowed target files); `unowned.allow`, `glossary` (`docs/domain/glossary.md`), `contextMap` (`docs/domain/context-map.md`, a table with Context and Rung columns that must agree with the registry).
513
+ - A file belongs to at most one context. Unowned files warn by default (`domain.coverage.unowned: error` to fail).
514
+ - Card: five H2 headings in order (Language; Rules and invariants; Boundary contracts; Decisions; Open questions). Rules are `### <ID> <title>` under Rules and invariants, with optional `Tests:`, `Code:` and `Untested:` lines. A rule needs a test link, a `Tests:` line or an `Untested:` line.
515
+ - Rule IDs match `domain.rules.idPattern` (default `^[A-Z][A-Z0-9]*-\d+$`), are permanent and unique across cards, and use the context's `rulePrefix` when it has one. A test links to a rule through `[Trait("Rule", "LEND-03")]` (keys in `domain.tests.ruleTraitKeys`), `Category` / `TestCategory` / `Tag` values, `rule: LEND-03` comments, test titles that start with an ID, or the card's `Tests:` line. Tracker prefixes (`domain.rules.trackerPrefixes`) never link from plain text.
516
+
517
+ ### Commands
518
+
519
+ - `ctxo contexts-touched [--since <ref>] [--committed | --staged] [--json] [--check]`: contexts whose paths hold a changed non-test file, with status `card-changed`, `acknowledged` (a `Domain-Unchanged` trailer in the range), `unresolved` or `no-card`. `--check` exits 1 on unresolved; 2 on registry problems, a missing base (CI needs `fetch-depth: 0`) or git failure.
520
+ - `ctxo verify-domain [--since <ref>] [--boundaries by-rung|report] [--json]`: checks 1 registry and config, 2 cards present, 3 path globs match, 4a single owner, 4b unowned files, 5 card headings, 6 rule IDs and test links, 7 card links and anchors, 8 generated loader rules, 9 context map rungs, 10 boundaries, 11 fold since a ref (with `--since`). Exit 0 (warnings allowed), 1 errors, 2 missing index, git failure or internal error. `--json` writes `{ registry, checks, summary, exitCode }` to stdout; stdout is empty on exit 2 and with no registry.
521
+ - `ctxo domain rules --write | --check`: one pointer file per context with a card: `.claude/rules/ctxo-context-<id>.md` (front matter `paths`) and, when `.cursor/` exists, `.cursor/rules/ctxo-context-<id>.mdc`. Marker `<!-- generated by ctxo domain rules; do not edit -->`. `--check` exits 1 on missing, outdated, stale and blocked files (a hand-written file at a generated path; rename or delete it).
522
+ - `ctxo domain discover [--json] [--write]`: card rule prefixes, tracker-like keys in commit subjects and branch names (5 or more is proposed as a tracker prefix), test trait keys, uncovered test folders; `--write` merges the proposal into `.ctxo/config.yaml`.
523
+ - `ctxo init --domain [--boundaries <by-rung|report>]` or `--only domain`: config defaults, registry skeleton, discovery with confirmation, loader rules, guard hooks (SessionStart, Stop, TaskCompleted) and the `ctxo-domain-fold` skill (Claude Code and Cursor).
524
+
525
+ ### Fold guard and trailer
526
+
527
+ - `ctxo domain-guard-hook` judges only the commits of the current session (`startHead..HEAD`, recorded at SessionStart, intersected with the branch range from `domain.guard.base`, `origin/HEAD`, `main` or `master`; unpushed commits on the default branch). It blocks once per fingerprint (HEAD plus unresolved IDs): `Stop` prints `{"decision":"block","reason":...}` and exits 0, `TaskCompleted` prints to stderr and exits 2. `stop_hook_active` and every internal error allow.
528
+ - Trailer: `Domain-Unchanged: <id>[, <id>...] [(reason)]`, read with `git log --format=%(trailers:key=Domain-Unchanged,valueonly)` over the evaluated range only. A card change in the range also resolves a context. An empty commit with the trailer is fine.
529
+
530
+ ### Boundaries, drift and fields
531
+
532
+ - `ctxo index` writes `.ctxo/index/domain/contexts.json`, `boundaries.json` and `history/` (10 per-commit entries), each with a `ctxoArtifact` marker that the index reader skips.
533
+ - Edges between contexts are allowed when the target file matches the source context's `contracts.<target>`; otherwise a violation: an error for `blockingRungs` (default bounded, boring) in `by-rung` mode, else a warning (`report` mode: always a warning). Edges from test files and to unowned files are skipped.
534
+ - Additive fields: `context` (set when exactly one context owns the file) on search_symbols results, get_blast_radius impacted symbols, find_importers importers, get_logic_slice roots and get_pr_impact changed symbols; `contextBoundaryViolations` (capped at 50, with `contextBoundaryViolationsTotal`) on get_pr_impact; `contextDrift` (`crossShare`, `trend`, `movedFiles`, `distinctCommits`, `confidence`) on get_why_context.
535
+
536
+ ### Doctor and global installs
537
+
538
+ - `domain_registry`, `domain_agent_setup` and `domain_conventions` (all pass or warn; a repo with neither `.claude/` nor `.cursor/` is checked as Claude Code and carries a standing agent-setup warning until `ctxo init --only domain`).
539
+ - `install_copies` (every project): warns, never fails, when hooks call `ctxo` and none is on PATH, or an npx-pinned MCP entry differs from the global CLI the hooks run. `ctxo init` from a global install writes MCP entries that call the global `ctxo`.
540
+
541
+ ### Config
542
+
543
+ `domain:` keys and defaults: `registry: docs/domain/contexts.yaml`, `coverage.unowned: warn`, `boundaries.enforce: by-rung`, `boundaries.blockingRungs: [bounded, boring]`, `rules.idPattern: ^[A-Z][A-Z0-9]*-\d+$`, `rules.trackerPrefixes: []`, `tests.ruleTraitKeys: [Rule]`, `guard.enabled: true`, `guard.base` (unset), `guard.subagents: false`. An invalid key falls back to its default and verify-domain check 1 reports it.
544
+
545
+ ### Adoption ladder
546
+
547
+ level 0: install and index; 1: registry with paths; 2: cards; 3: rule IDs and test links, through card `Tests:` lines, test names or framework tags; 4: contracts and shadow-spec resolutions. No level requires code changes.
548
+
549
+ ---
550
+
497
551
  ## Safe-Edit Guard (v0.8+)
498
552
 
499
553
  The safe-edit guard closes the loop between MCP tool availability and agent compliance. An agent with access to get_blast_radius can still skip it. The guard makes skipping impossible for high-impact symbols on Claude Code.
package/llms.txt CHANGED
@@ -22,6 +22,7 @@ ctxo # Start MCP server (stdio)
22
22
  - `@ctxo/lang-csharp` - Roslyn plugin (attribute annotations; SQL edges at known call sites when `@ctxo/lang-sql` is installed)
23
23
  - `@ctxo/lang-java` - tree-sitter Java plugin (syntax tier built-in; full tier via `@ctxo/lang-java-analyzer` companion, requires JRE 11+)
24
24
  - `@ctxo/lang-sql` - T-SQL plugin for `.sql` files (protocol v2): tables, views, procedures, functions and their reads/writes/executes
25
+ - `@ctxo/domain` - opt-in domain knowledge layer (ADR-018): named contexts, cards, the fold guard and the `verify-domain` CI gate; loaded by the CLI through `@ctxo/cli/internal`, shares one version with `@ctxo/cli`
25
26
  - `@ctxo/sql-extract` - zero-dependency T-SQL tokenizer and recognizers (a library, not a plugin; the one dependency plugins may take besides `@ctxo/plugin-api`)
26
27
 
27
28
  Language adapters ship as separate npm packages and are discovered by scanning the project `package.json` for `@ctxo/lang-*` or `ctxo-lang-*` dependencies.
@@ -55,6 +56,16 @@ Language adapters ship as separate npm packages and are discovered by scanning t
55
56
  - Safe to delete? -> find_importers
56
57
  - Preparing a context map? -> get_architectural_overlay(mode: "contexts")
57
58
 
59
+ ## Unreleased: domain knowledge layer, `@ctxo/domain` (#156, PR 2B)
60
+
61
+ - Install: `ctxo install domain` (globally when the project has no `package.json`), then `ctxo init --domain`. Opt-in: without the package, no commands, fields or hooks, and a known domain command name prints an install hint and exits 1 (`ctxo domain-guard-hook` exits 0 without output). With the package but no registry, the domain commands print a hint and exit 0 and no `context` fields appear.
62
+ - Registry `docs/domain/contexts.yaml`: contexts with `id`, `name`, `card`, `paths`, `rung` (fear, pinned, named, bounded, boring), `rulePrefix`, `contracts`; `unowned.allow`, `glossary`, `contextMap`. A card has five H2 headings (Language; Rules and invariants; Boundary contracts; Decisions; Open questions) and rules as `### LEND-03 title` with optional `Tests:`, `Code:` and `Untested:` lines.
63
+ - Commands: `ctxo contexts-touched [--since <ref>] [--committed | --staged] [--json] [--check]`; `ctxo verify-domain [--since <ref>] [--boundaries by-rung|report] [--json]` (exit 0, 1 or 2; `--json` stdout is empty on exit 2 and with no registry); `ctxo domain rules --write | --check`; `ctxo domain discover [--json] [--write]`; `ctxo init --domain [--boundaries <mode>]` and `--only domain`.
64
+ - Fold guard (Claude Code): `ctxo domain-guard-hook` on SessionStart, Stop and TaskCompleted blocks once when the session's commits changed a context without a card change; resolve with a card commit or the trailer `Domain-Unchanged: <id>[, <id>] (reason)`.
65
+ - Config `domain:` in `.ctxo/config.yaml`: `registry`, `coverage.unowned` (warn | error), `boundaries.enforce` (by-rung | report) and `blockingRungs`, `rules.idPattern` and `trackerPrefixes`, `tests.ruleTraitKeys`, `guard.enabled`, `guard.base`, `guard.subagents`.
66
+ - Additive fields with `@ctxo/domain` and a registry: `context` on search_symbols, get_blast_radius, find_importers, get_logic_slice and get_pr_impact entries; `contextBoundaryViolations` on get_pr_impact; `contextDrift` on get_why_context. `ctxo index` writes `.ctxo/index/domain/`.
67
+ - Doctor: `domain_registry`, `domain_agent_setup`, `domain_conventions`, and `install_copies` (MCP entry and hooks start the same copy). Feature doc: docs/features/domain-knowledge.md ("Ctxo domain conventions v1").
68
+
58
69
  ## Unreleased: language parity for TypeScript, Java and Go (#156, PR 1C)
59
70
 
60
71
  - Capability matrix (annotations / test symbols / SQL at call sites, the last only with `@ctxo/lang-sql` installed): C# attributes / test methods / ADO.NET, Dapper, SqlBulkCopy, EF Core raw SQL (Roslyn tier); TypeScript decorators / test blocks / pg, mysql2, mssql, knex.raw, Prisma raw, TypeORM, Sequelize, better-sqlite3; Java annotations (JDT constant values, tree-sitter strings only) / test methods under src/test/java / JDBC, Spring JdbcTemplate, JPA native queries, native @Query, MyBatis (JDT full tier); Go struct tags (both tiers) / `_test.go` functions (full tier) / database/sql, sqlx, pgx, gorm raw (analyzer full tier).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctxo/cli",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "description": "MCP server delivering dependency-aware, history-enriched context for codebases",
5
5
  "type": "module",
6
6
  "engines": {
@@ -19,6 +19,17 @@
19
19
  ],
20
20
  "main": "dist/index.js",
21
21
  "types": "dist/index.d.ts",
22
+ "exports": {
23
+ ".": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ },
27
+ "./internal": {
28
+ "types": "./dist/internal.d.ts",
29
+ "import": "./dist/internal.js"
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
22
33
  "keywords": [
23
34
  "mcp",
24
35
  "context",
@@ -55,8 +66,8 @@
55
66
  "vitest": "^5.0.1",
56
67
  "@ctxo/lang-csharp": "0.9.0",
57
68
  "@ctxo/lang-go": "0.10.0",
58
- "@ctxo/lang-java": "0.11.0",
59
69
  "@ctxo/lang-sql": "0.1.0",
70
+ "@ctxo/lang-java": "0.11.0",
60
71
  "@ctxo/lang-typescript": "0.9.0"
61
72
  },
62
73
  "repository": {
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/adapters/storage/json-index-reader.ts","../src/core/types.ts"],"sourcesContent":["import { readFileSync, readdirSync, existsSync, realpathSync } from 'node:fs';\nimport { join, relative } from 'node:path';\nimport {\n FileIndexSchema,\n SymbolNodeSchema,\n GraphEdgeSchema,\n CommitIntentSchema,\n AntiPatternSchema,\n CodeFactSchema,\n type FileIndex,\n} from '../../core/types.js';\nimport { createLogger } from '../../core/logger.js';\n\nconst log = createLogger('ctxo:json-reader');\n\n/** JSON files next to the index entries that are products of Ctxo, not entries: the reader skips them. */\nexport const INDEX_ARTIFACT_FILES: readonly string[] = [\n 'co-changes.json',\n 'communities.json',\n 'drift-events.json',\n 'boundary-violations.json',\n 'contexts-view.json',\n];\n\n/** The folder of archived community snapshots inside the index folder: not entries either. */\nexport const COMMUNITY_HISTORY_DIR = 'communities.history';\n\n/** One index entry and the JSON file on disk it was read from. */\nexport interface IndexEntry {\n readonly path: string;\n readonly index: FileIndex;\n}\n\nexport class JsonIndexReader {\n private readonly indexDir: string;\n\n constructor(ctxoRoot: string) {\n this.indexDir = join(ctxoRoot, 'index');\n }\n\n readAll(): FileIndex[] {\n return this.readEntries().map((entry) => entry.index);\n }\n\n /**\n * Every valid index entry together with the path of the JSON file it came from. A caller that wants to\n * delete an entry must use this path: the `file` field inside the JSON says which source file the entry\n * is for, but a corrupt or crafted file can claim any name, such as an artifact's.\n */\n readEntries(): IndexEntry[] {\n if (!existsSync(this.indexDir)) {\n return [];\n }\n\n const jsonFiles = this.collectJsonFiles(this.indexDir);\n const results: IndexEntry[] = [];\n\n for (const filePath of jsonFiles) {\n const parsed = this.readSingle(filePath);\n if (parsed) {\n results.push({ path: filePath, index: parsed });\n }\n }\n\n return results;\n }\n\n readSingle(absolutePath: string): FileIndex | undefined {\n try {\n const raw = readFileSync(absolutePath, 'utf-8');\n const data: unknown = JSON.parse(raw);\n const result = FileIndexSchema.safeParse(data);\n\n if (result.success) {\n return result.data;\n }\n\n // Strict parse failed — attempt resilient recovery: keep valid items, drop invalid ones.\n const rel = relative(this.indexDir, absolutePath);\n const raw_data = data as Record<string, unknown>;\n\n // Must have at least a valid file name and lastModified to be recoverable.\n if (typeof raw_data['file'] !== 'string' || !raw_data['file'] ||\n typeof raw_data['lastModified'] !== 'number') {\n console.error(\n `[ctxo:json-reader] Invalid schema in ${rel}: ${result.error.message}`,\n );\n return undefined;\n }\n\n const rawSymbols = Array.isArray(raw_data['symbols']) ? raw_data['symbols'] : [];\n const rawEdges = Array.isArray(raw_data['edges']) ? raw_data['edges'] : [];\n const rawIntent = Array.isArray(raw_data['intent']) ? raw_data['intent'] : [];\n const rawAntiPatterns = Array.isArray(raw_data['antiPatterns']) ? raw_data['antiPatterns'] : [];\n\n // A symbol that fails only because of its annotations is kept without them: annotations are\n // optional metadata and must not cost the symbol.\n let droppedAnnotations = 0;\n const validSymbols: unknown[] = [];\n for (const sym of rawSymbols) {\n if (SymbolNodeSchema.safeParse(sym).success) {\n validSymbols.push(sym);\n continue;\n }\n if (sym !== null && typeof sym === 'object' && 'annotations' in sym) {\n const { annotations: _dropped, ...withoutAnnotations } = sym as Record<string, unknown>;\n if (SymbolNodeSchema.safeParse(withoutAnnotations).success) {\n validSymbols.push(withoutAnnotations);\n droppedAnnotations++;\n }\n }\n }\n // A facts value that is present but not an array is treated as absent: facts are optional metadata\n // and must not cost the file. It counts as one dropped fact list in the warning.\n const factsPresent = raw_data['facts'] !== undefined;\n const rawFacts = Array.isArray(raw_data['facts']) ? raw_data['facts'] : undefined;\n const validFacts = rawFacts?.filter((f) => CodeFactSchema.safeParse(f).success);\n const validEdges = rawEdges.filter((e) => GraphEdgeSchema.safeParse(e).success);\n const validIntent = rawIntent.filter((i) => CommitIntentSchema.safeParse(i).success);\n const validAntiPatterns = rawAntiPatterns.filter((a) => AntiPatternSchema.safeParse(a).success);\n\n const droppedSymbols = rawSymbols.length - validSymbols.length;\n const droppedFacts = rawFacts && validFacts\n ? rawFacts.length - validFacts.length\n : factsPresent ? 1 : 0;\n const droppedEdges = rawEdges.length - validEdges.length;\n const droppedIntent = rawIntent.length - validIntent.length;\n const droppedAntiPatterns = rawAntiPatterns.length - validAntiPatterns.length;\n\n if (droppedSymbols > 0 || droppedEdges > 0 || droppedIntent > 0 || droppedAntiPatterns > 0 ||\n droppedAnnotations > 0 || droppedFacts > 0) {\n log.warn(\n `${rel}: dropped ${droppedSymbols} invalid symbol(s), ${droppedEdges} invalid edge(s), ${droppedIntent} invalid intent(s), ${droppedAntiPatterns} invalid antiPattern(s), ${droppedAnnotations} invalid annotation list(s), ${droppedFacts} invalid fact(s); kept ${validSymbols.length} symbol(s), ${validEdges.length} edge(s), ${validIntent.length} intent(s), ${validAntiPatterns.length} antiPattern(s)`,\n );\n }\n\n // Re-parse with the filtered arrays to get a fully-typed FileIndex.\n const recovered = FileIndexSchema.safeParse({\n ...raw_data,\n symbols: validSymbols,\n edges: validEdges,\n intent: validIntent,\n antiPatterns: validAntiPatterns,\n facts: validFacts,\n });\n\n if (!recovered.success) {\n console.error(\n `[ctxo:json-reader] Invalid schema in ${rel}: ${result.error.message}`,\n );\n return undefined;\n }\n\n return recovered.data;\n } catch (err) {\n const rel = relative(this.indexDir, absolutePath);\n console.error(\n `[ctxo:json-reader] Failed to read ${rel}: ${(err as Error).message}`,\n );\n return undefined;\n }\n }\n\n private collectJsonFiles(dir: string, visited: Set<string> = new Set()): string[] {\n const realDir = realpathSync(dir);\n if (visited.has(realDir)) return []; // Guard against symlink loops\n visited.add(realDir);\n\n const files: string[] = [];\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n if (entry.isSymbolicLink()) continue; // Skip symlinks entirely\n\n const fullPath = join(dir, entry.name);\n if (entry.isDirectory()) {\n // Skip non-FileIndex directories under .ctxo/index/\n if (entry.name === COMMUNITY_HISTORY_DIR) continue;\n files.push(...this.collectJsonFiles(fullPath, visited));\n } else if (entry.name.endsWith('.json') && !INDEX_ARTIFACT_FILES.includes(entry.name)) {\n files.push(fullPath);\n }\n }\n\n return files;\n }\n}\n","import { z } from 'zod';\nimport { SYMBOL_KINDS, EDGE_KINDS, FACT_KINDS } from '@ctxo/plugin-api';\n\n// ── Symbol Kinds ────────────────────────────────────────────────\n\nexport { SYMBOL_KINDS };\n\nexport const SymbolKindSchema = z.enum(SYMBOL_KINDS);\nexport type SymbolKind = z.infer<typeof SymbolKindSchema>;\n\n// ── Edge Kinds ──────────────────────────────────────────────────\n\nexport { EDGE_KINDS };\n\nexport const EdgeKindSchema = z.enum(EDGE_KINDS);\nexport type EdgeKind = z.infer<typeof EdgeKindSchema>;\n\n// ── Detail Levels ───────────────────────────────────────────────\n\nexport const DETAIL_LEVELS = [1, 2, 3, 4] as const;\n\nexport const DetailLevelSchema = z.union([\n z.literal(1),\n z.literal(2),\n z.literal(3),\n z.literal(4),\n]);\nexport type DetailLevel = z.infer<typeof DetailLevelSchema>;\n\n// ── Symbol ID ───────────────────────────────────────────────────\n\n/**\n * Format: \"<relativeFile>::<name>::<kind>\"\n * Example: \"src/foo.ts::myFn::function\"\n */\nexport const SymbolIdSchema = z\n .string()\n .min(1)\n .refine(\n (value) => {\n const parts = value.split('::');\n if (parts.length !== 3) return false;\n const [file, name, kind] = parts;\n if (!file || !name || !kind) return false;\n return SymbolKindSchema.safeParse(kind).success;\n },\n { message: 'Symbol ID must match format \"<file>::<name>::<kind>\"' },\n );\nexport type SymbolId = z.infer<typeof SymbolIdSchema>;\n\n// ── Edge Target ─────────────────────────────────────────────────\n\n/**\n * An edge target: either a full 3-part symbol ID (\"<file>::<name>::<kind>\")\n * or a 2-part name-reference (\"<name>::<kind>\") for cross-file / unresolved\n * targets. The graph builder resolves name-references by name at query time.\n */\nexport const EdgeTargetSchema = z.string().refine(\n (s) => {\n const parts = s.split('::');\n if (parts.length !== 3 && parts.length !== 2) return false;\n if (parts.some((p) => p.length === 0)) return false;\n const kind = parts[parts.length - 1];\n return (SYMBOL_KINDS as readonly string[]).includes(kind as string);\n },\n { message: 'edge target must be <file>::<name>::<kind> or <name>::<kind>' },\n);\nexport type EdgeTarget = z.infer<typeof EdgeTargetSchema>;\n\n// ── Symbol Annotation ───────────────────────────────────────────\n\n/** Host-language attribute or decorator on a symbol (protocol v2). Shape only; plugins enforce caps. */\nexport const SymbolAnnotationSchema = z.object({\n name: z.string().min(1),\n args: z.array(z.string()).readonly().optional(),\n named: z.record(z.string(), z.string()).readonly().optional(),\n});\nexport type SymbolAnnotation = z.infer<typeof SymbolAnnotationSchema>;\n\n// ── Symbol Node ─────────────────────────────────────────────────\n\nexport const SymbolNodeSchema = z\n .object({\n symbolId: SymbolIdSchema,\n name: z.string().min(1),\n kind: SymbolKindSchema,\n startLine: z.number().int().nonnegative(),\n endLine: z.number().int().nonnegative(),\n startOffset: z.number().int().nonnegative().optional(),\n endOffset: z.number().int().nonnegative().optional(),\n annotations: z.array(SymbolAnnotationSchema).readonly().optional(),\n })\n .refine((node) => node.endLine >= node.startLine, {\n message: 'endLine must be >= startLine',\n });\nexport type SymbolNode = z.infer<typeof SymbolNodeSchema>;\n\n// ── Graph Edge ──────────────────────────────────────────────────\n\nexport const GraphEdgeSchema = z.object({\n from: SymbolIdSchema, // strict 3-part: from is always a local, resolved symbol\n to: EdgeTargetSchema, // 3-part OR 2-part name-ref for cross-file/unresolved targets\n kind: EdgeKindSchema,\n typeOnly: z.boolean().optional(),\n});\nexport type GraphEdge = z.infer<typeof GraphEdgeSchema>;\n\n// ── Commit Intent ───────────────────────────────────────────────\n\nexport const CommitIntentSchema = z.object({\n hash: z.string().min(1),\n message: z.string(),\n date: z.string().min(1),\n kind: z.literal('commit'),\n});\nexport type CommitIntent = z.infer<typeof CommitIntentSchema>;\n\n// ── Anti-Pattern ────────────────────────────────────────────────\n\nexport const AntiPatternSchema = z.object({\n hash: z.string().min(1),\n message: z.string(),\n date: z.string().min(1),\n});\nexport type AntiPattern = z.infer<typeof AntiPatternSchema>;\n\n// ── Code Fact ───────────────────────────────────────────────────\n\nexport const FactKindSchema = z.enum(FACT_KINDS);\nexport type FactKind = z.infer<typeof FactKindSchema>;\n\n/** A fact extracted from a symbol body (protocol v2). The line is 0-based, like a symbol's start line. */\nexport const CodeFactSchema = z.object({\n kind: FactKindSchema,\n symbolId: SymbolIdSchema,\n line: z.number().int().nonnegative(),\n text: z.string(),\n detail: z.record(z.string(), z.string()).readonly().optional(),\n});\nexport type CodeFact = z.infer<typeof CodeFactSchema>;\n\n// ── File Index ──────────────────────────────────────────────────\n\nexport const ComplexityMetricsSchema = z.object({\n symbolId: z.string().min(1),\n cyclomatic: z.number().nonnegative(),\n});\n\nexport const FileIndexSchema = z.object({\n file: z.string().min(1),\n lastModified: z.number().nonnegative(),\n contentHash: z.string().optional(),\n symbols: z.array(SymbolNodeSchema),\n edges: z.array(GraphEdgeSchema),\n complexity: z.array(ComplexityMetricsSchema).optional(),\n intent: z.array(CommitIntentSchema),\n antiPatterns: z.array(AntiPatternSchema),\n facts: z.array(CodeFactSchema).readonly().optional(),\n});\nexport type FileIndex = z.infer<typeof FileIndexSchema>;\n\n// ── Logic-Slice Result ──────────────────────────────────────────\n\nexport interface LogicSliceResult {\n readonly root: SymbolNode;\n readonly dependencies: readonly SymbolNode[];\n readonly edges: readonly GraphEdge[];\n}\n\n// ── Formatted Slice ─────────────────────────────────────────────\n\nexport interface TruncationInfo {\n readonly truncated: true;\n readonly reason: 'token_budget_exceeded';\n}\n\nexport interface FormattedSlice {\n readonly root: SymbolNode;\n readonly dependencies: readonly SymbolNode[];\n readonly edges: readonly GraphEdge[];\n readonly level: DetailLevel;\n readonly levelDescription?: string;\n readonly truncation?: TruncationInfo;\n}\n\n// ── Complexity & Churn ──────────────────────────────────────────\n\nexport interface ComplexityMetrics {\n readonly symbolId: string;\n readonly cyclomatic: number;\n}\n\nexport interface ChurnData {\n readonly filePath: string;\n readonly commitCount: number;\n}\n\nexport const SCORE_BANDS = ['low', 'medium', 'high'] as const;\nexport type ScoreBand = (typeof SCORE_BANDS)[number];\n\nexport interface ChangeIntelligenceScore {\n readonly symbolId: string;\n readonly complexity: number;\n readonly churn: number;\n readonly composite: number;\n readonly band: ScoreBand;\n}\n\n// ── Why-Context Result ──────────────────────────────────────────\n\nexport interface WhyContextResult {\n readonly commitHistory: readonly CommitIntent[];\n readonly antiPatternWarnings: readonly AntiPattern[];\n readonly changeIntelligence?: ChangeIntelligenceScore;\n}\n\n// ── Co-Change Analysis ─────────────────────────────────────────\n\nexport interface CoChangeEntry {\n readonly file1: string;\n readonly file2: string;\n readonly sharedCommits: number;\n readonly frequency: number;\n}\n\n/** The window a co-change matrix was built from and the filters that shaped it. */\nexport interface CoChangeWindowMeta {\n /** Configured commit limit: the last N non-merge commits from HEAD, or 'all'. */\n readonly maxCommits: number | 'all';\n /** Configured duration limit such as \"12m\", anchored to HEAD's committer date. */\n readonly since?: string;\n /** Short SHA of HEAD when the matrix was built. */\n readonly head: string;\n /** Commits inside the window. */\n readonly commitsScanned: number;\n /** Window commits that fed the counts. */\n readonly commitsUsed: number;\n /** Window commits skipped for touching more than `maxFilesPerCommit` included files. */\n readonly massSkipped: number;\n readonly maxFilesPerCommit: number;\n readonly minShared: number;\n}\n\nexport interface CoChangeMatrix {\n readonly version: 1;\n readonly timestamp: number;\n /** Absent in matrices written before the window was recorded. */\n readonly window?: CoChangeWindowMeta;\n readonly entries: readonly CoChangeEntry[];\n}\n\nconst CoChangeEntrySchema = z.object({\n file1: z.string().min(1),\n file2: z.string().min(1),\n sharedCommits: z.number().int().min(1),\n frequency: z.number().min(0).max(1),\n});\n\nconst CoChangeWindowMetaSchema = z.object({\n maxCommits: z.union([z.number().int().min(1), z.literal('all')]),\n since: z.string().optional(),\n head: z.string().min(1),\n commitsScanned: z.number().int().min(0),\n commitsUsed: z.number().int().min(0),\n massSkipped: z.number().int().min(0),\n maxFilesPerCommit: z.number().int().min(1),\n minShared: z.number().int().min(1),\n});\n\n/**\n * Validates `co-changes.json`. `entries` is required and `window` optional, so files written before\n * the window was recorded still load. Unknown keys are dropped rather than rejected, so a file from\n * a newer Ctxo stays readable.\n */\nexport const CoChangeMatrixSchema: z.ZodType<CoChangeMatrix> = z.object({\n version: z.literal(1),\n timestamp: z.number(),\n window: CoChangeWindowMetaSchema.optional(),\n entries: z.array(CoChangeEntrySchema),\n});\n\n// ── Commit Record (from git adapter) ────────────────────────────\n\nexport interface CommitRecord {\n readonly hash: string;\n readonly message: string;\n readonly date: string;\n readonly author: string;\n}\n\n// ── Change Log (from git adapter) ───────────────────────────────\n\n/** git name-status letters Ctxo keeps; A added, M modified, D deleted, R renamed, C copied, T type changed. */\nexport type FileChangeStatus = 'A' | 'M' | 'D' | 'R' | 'C' | 'T';\n\nexport interface FileChange {\n readonly status: FileChangeStatus;\n /** Path after the change: repo-relative, forward slashes. */\n readonly path: string;\n /** Path before the change; set only for renames (R) and copies (C). */\n readonly oldPath?: string;\n}\n\n/** One non-merge commit and the files it changed. */\nexport interface CommitChangeSet {\n /** Full commit SHA (git %H). */\n readonly hash: string;\n /** Subject line (git %s). */\n readonly message: string;\n /** Author date, strict ISO 8601 (git %aI). */\n readonly date: string;\n /** Author name (git %an). */\n readonly author: string;\n /** Committer date in unix seconds (git %ct). */\n readonly committedAt: number;\n readonly changes: readonly FileChange[];\n}\n\nexport interface ChangeLog {\n /** Short SHA of HEAD (git %h), which may itself be a merge commit. */\n readonly head: string;\n /** Committer date of HEAD in unix seconds (git %ct). */\n readonly headCommittedAt: number;\n /** Non-merge commits reachable from HEAD, newest first. */\n readonly commits: readonly CommitChangeSet[];\n}\n\n// ── Blame Line (from git adapter) ───────────────────────────────\n\nexport interface BlameLine {\n readonly hash: string;\n readonly lineNumber: number;\n readonly author: string;\n readonly date: string;\n}\n\n// ── Search Types ───────────────────────────────────────────────\n\nexport interface SearchResult {\n symbolId: string;\n name: string;\n kind: string;\n filePath: string;\n /** BM25 relevance score (higher = more relevant) */\n relevanceScore: number;\n /** PageRank importance score (0-1) */\n importanceScore: number;\n /** Final combined score after all boosts */\n combinedScore: number;\n}\n\nexport interface SearchMetrics {\n porterHits: number;\n trigramHits: number;\n phase2Activated: boolean;\n fuzzyApplied: boolean;\n latencyMs: number;\n}\n\nexport interface FuzzyCorrection {\n originalQuery: string;\n correctedQuery: string;\n corrections: Array<{\n original: string;\n corrected: string;\n distance: number;\n }>;\n}\n\nexport interface SearchResponse {\n query: string;\n results: SearchResult[];\n metrics: SearchMetrics;\n fuzzyCorrection?: FuzzyCorrection;\n}\n\n// ── Community Detection ────────────────────────────────────────\n\nexport interface CommunityEntry {\n readonly symbolId: string;\n readonly communityId: number;\n readonly communityLabel: string;\n}\n\nexport interface GodNode {\n readonly symbolId: string;\n readonly bridgedCommunities: readonly number[];\n readonly centralityScore: number;\n}\n\nexport const EDGE_QUALITY = ['full', 'syntax-only', 'mixed'] as const;\nexport type EdgeQuality = (typeof EDGE_QUALITY)[number];\n\nexport interface CommunitySnapshot {\n readonly version: 1;\n readonly computedAt: string;\n readonly commitSha: string;\n readonly modularity: number;\n readonly communities: readonly CommunityEntry[];\n readonly godNodes: readonly GodNode[];\n readonly edgeQuality: EdgeQuality;\n readonly crossClusterEdges: number;\n}\n\nexport interface DriftEvent {\n readonly symbolId: string;\n readonly movedFrom: { readonly id: number; readonly label: string };\n readonly movedTo: { readonly id: number; readonly label: string };\n readonly firstSeenInNewCluster: string;\n}\n\nexport interface BoundaryViolation {\n readonly from: {\n readonly symbolId: string;\n readonly communityId: number;\n readonly label: string;\n };\n readonly to: {\n readonly symbolId: string;\n readonly communityId: number;\n readonly label: string;\n };\n readonly edgeKind: EdgeKind;\n readonly historicalEdgesBetweenClusters: number;\n readonly severity: 'high' | 'medium';\n}\n\n// ── Persisted architectural artifacts ──────────────────────────\n// Written by `ctxo index` next to communities.json so the static\n// HTML visualizer can render Architecture views without re-running\n// detectors in the browser.\n\nexport type ConfidenceLevel = 'high' | 'medium' | 'low';\n\nexport interface DriftEventsArtifact {\n readonly version: 1;\n readonly computedAt: string;\n readonly commitSha: string;\n readonly confidence: ConfidenceLevel;\n /** The number of history entries passed to the detector (kept for compatibility; confidence is built on `distinctCommits`). */\n readonly snapshotsAvailable: number;\n /** Commits other than `commitSha` that the history covers; `confidence` is built on this. */\n readonly distinctCommits: number;\n readonly hint?: string;\n readonly events: readonly DriftEvent[];\n}\n\nexport interface BoundaryViolationsArtifact {\n readonly version: 1;\n readonly computedAt: string;\n readonly commitSha: string;\n readonly confidence: ConfidenceLevel;\n /** The number of history entries passed to the detector (kept for compatibility; confidence is built on `distinctCommits`). */\n readonly snapshotsAvailable: number;\n /** Commits other than `commitSha` that the history covers; `confidence` is built on this. */\n readonly distinctCommits: number;\n readonly hint?: string;\n readonly violations: readonly BoundaryViolation[];\n}\n"],"mappings":"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","names":[]}