@titan-design/code-read 0.1.9 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,24 +1,55 @@
1
1
  import {
2
2
  AGENT_COMMANDS,
3
+ AttentionSignal,
4
+ CHANGES_ROWS_MAX,
3
5
  CODE_READ_API_VERSION,
4
6
  COMMAND_NAMES,
5
7
  CONTRACT,
6
8
  Capabilities,
9
+ Centrality,
10
+ ChurnWindow,
11
+ CoChangePair,
12
+ CoupledPartners,
13
+ CrossEdge,
7
14
  EXCERPT_LINE_CAP,
15
+ ExportRow,
8
16
  FINDINGS_PAGE_MAX,
9
17
  Finding,
18
+ FindingChange,
19
+ FindingDelta,
10
20
  FindingStatus,
11
21
  HIERARCHY_ROW_CAP,
22
+ HOTSPOTS_PAGE_MAX,
23
+ Hotspot,
24
+ HotspotMark,
25
+ ImpactRollup,
26
+ LinkedTests,
27
+ LookFirstRow,
12
28
  MetricDescriptor,
13
29
  MissingReason,
30
+ NewFile,
14
31
  NodeKind,
32
+ NodeLens,
33
+ NodeLenses,
15
34
  NodeRef,
35
+ OVERVIEW_ROWS_MAX,
36
+ PACKAGES_MAX,
37
+ PATHS_IMPACT_MAX,
38
+ PackageLayer,
39
+ PackageStatsRow,
40
+ PathDelta,
41
+ PathHotspot,
42
+ PathImpact,
16
43
  Provenance,
17
44
  ProvenanceKind,
18
45
  QUERIES,
19
46
  RELATED_CAP,
20
47
  ReadError,
48
+ ReadingOrderRow,
49
+ Regression,
21
50
  RuleSummary,
51
+ ScoreBreakdown,
52
+ ScoreChange,
22
53
  Severity,
23
54
  SnapshotInfo,
24
55
  SnapshotRef,
@@ -26,22 +57,29 @@ import {
26
57
  Span,
27
58
  buildReadModel,
28
59
  createQueryResolver,
60
+ declaredTiers,
29
61
  describeApi,
30
62
  excessOf,
31
63
  findingNotFound,
64
+ getChanges,
32
65
  getFinding,
33
66
  getHierarchy,
34
67
  getNeighbors,
35
68
  getNode,
69
+ getOverview,
36
70
  invalidArgs,
37
71
  listFindings,
72
+ listHotspots,
38
73
  listSnapshots,
39
74
  nodeNotFound,
75
+ packagesStats,
76
+ pathsImpact,
77
+ repoRelative,
40
78
  resolveNode,
41
79
  resolveSnapshot,
42
80
  serializeContract,
43
81
  snapshotNotFound
44
- } from "./chunk-VXQFCVGB.js";
82
+ } from "./chunk-7FNTXO7C.js";
45
83
 
46
84
  // src/lru.ts
47
85
  var LruCache = class {
@@ -143,7 +181,11 @@ import { snapshotViolations, violationKey } from "@titan-design/code-graph";
143
181
  var IMPORT_KINDS = /* @__PURE__ */ new Set(["imports", "re-exports"]);
144
182
  var QUOTES = ['"', "'", "`"];
145
183
  function toModelRules(rules) {
146
- return rules.map((r) => ({ id: r.id, type: r.type, severity: r.severity ?? "error", text: describeRule(r) }));
184
+ return rules.map((r) => {
185
+ const rule = { id: r.id, type: r.type, severity: r.severity ?? "error", text: describeRule(r) };
186
+ if (r.type === "layered-deps") rule.layers = r.layers;
187
+ return rule;
188
+ });
147
189
  }
148
190
  var pairKey = (srcId, dstId) => `${srcId}
149
191
  ${dstId}`;
@@ -263,6 +305,7 @@ function createLiveSource(deps) {
263
305
  return models.getOrLoad(snapshotId, () => loadReadModel(openOnce(), snapshotId, { rules: current, read }));
264
306
  },
265
307
  ...read ? { readSource: read } : {},
308
+ repoRoot: root,
266
309
  cachedSnapshots: () => models.keys()
267
310
  };
268
311
  }
@@ -292,7 +335,9 @@ var CLI = {
292
335
  options: {
293
336
  snapshot: { long: "--snapshot", description: "Snapshot id or ref name (default: newest)" },
294
337
  baseline: { long: "--baseline", description: "Snapshot id or ref to compute deltas against" },
295
- metrics: { long: "--metric", description: "Metric to report; repeatable (default: every one that applies)" }
338
+ metrics: { long: "--metric", description: "Metric to report; repeatable (default: every one that applies)" },
339
+ lenses: { long: "--lens", description: "exports, score, centrality, coupling, or tests; repeatable" },
340
+ window: { long: "--window", description: "Churn window the score lens reads, such as 90d, or lifetime (default 30d)" }
296
341
  }
297
342
  },
298
343
  "node.resolve": {
@@ -330,6 +375,53 @@ var CLI = {
330
375
  context_lines: { long: "--context-lines", description: "Lines of context either side of the flagged range (default 5, max 20)" }
331
376
  }
332
377
  },
378
+ "hotspots.list": {
379
+ options: {
380
+ snapshot: { long: "--snapshot", description: "Snapshot id or ref name (default: newest)" },
381
+ baseline: { long: "--baseline", description: "Snapshot id or ref to mark rows new or worsened against" },
382
+ grain: { long: "--grain", description: "file (default) or symbol" },
383
+ window: { long: "--window", description: "Churn window such as 90d, or lifetime (default 30d)" },
384
+ cutoff: { long: "--cutoff", description: "Only rows scoring at least this" },
385
+ offset: { long: "--offset", description: "Rows to skip (default 0)" },
386
+ limit: { long: "--limit", description: "Rows to return (default 20, max 500; 0 for the total only)" }
387
+ }
388
+ },
389
+ "overview.get": {
390
+ options: {
391
+ snapshot: { long: "--snapshot", description: "Snapshot id or ref name (default: newest)" },
392
+ baseline: { long: "--baseline", description: "Snapshot id or ref to count findings new, carried over, or resolved against" },
393
+ window: { long: "--window", description: "Churn window such as 90d, or lifetime (default 30d)" },
394
+ cutoff: { long: "--cutoff", description: "Hotspot score a file is over the cutoff at (default 3000)" },
395
+ exclude_rules: { long: "--exclude-rule", description: "Leave this rule out of the findings signal; repeatable" },
396
+ combined: { long: "--combined", description: "Also return 100 minus every signal's penalty" },
397
+ reading_limit: { long: "--reading-limit", description: "Files in the reading order (default 6, max 50)" },
398
+ look_limit: { long: "--look-limit", description: "Look-first rows (default 8, max 50)" }
399
+ }
400
+ },
401
+ "changes.get": {
402
+ positional: ["baseline"],
403
+ options: {
404
+ snapshot: { long: "--snapshot", description: "Snapshot id or ref name (default: newest)" },
405
+ window: { long: "--window", description: "Churn window such as 90d, or lifetime (default 30d)" },
406
+ cutoff: { long: "--cutoff", description: "Hotspot score a file is over the cutoff at (default 3000)" },
407
+ limit: { long: "--limit", description: "Rows per list (default 20, max 500; 0 for counts only)" }
408
+ }
409
+ },
410
+ "paths.impact": {
411
+ options: {
412
+ paths: { long: "--path", description: "Repo-relative file path, or absolute under --root; repeatable" },
413
+ snapshot: { long: "--snapshot", description: "Snapshot id or ref name (default: newest)" },
414
+ baseline: { long: "--baseline", description: "Snapshot id or ref to compute score, complexity, and findings deltas against" },
415
+ root: { long: "--root", description: "Absolute checkout directory, so absolute paths under it are read as repo paths" },
416
+ window: { long: "--window", description: "Churn window such as 90d, or lifetime (default 30d)" }
417
+ }
418
+ },
419
+ "packages.stats": {
420
+ options: {
421
+ snapshot: { long: "--snapshot", description: "Snapshot id or ref name (default: newest)" },
422
+ packages: { long: "--package", description: "Package root such as packages/cli; repeatable (default: every package the tier config declares)" }
423
+ }
424
+ },
333
425
  "node.neighbors": {
334
426
  positional: ["id"],
335
427
  options: {
@@ -364,27 +456,58 @@ function registerCodeReadCommands(registry, deps) {
364
456
  }
365
457
  export {
366
458
  AGENT_COMMANDS,
459
+ AttentionSignal,
460
+ CHANGES_ROWS_MAX,
367
461
  CODE_READ_API_VERSION,
368
462
  COMMAND_NAMES,
369
463
  CONTRACT,
370
464
  Capabilities,
465
+ Centrality,
466
+ ChurnWindow,
467
+ CoChangePair,
468
+ CoupledPartners,
469
+ CrossEdge,
371
470
  DEFAULT_MODEL_CACHE_SIZE,
372
471
  EXCERPT_LINE_CAP,
472
+ ExportRow,
373
473
  FINDINGS_PAGE_MAX,
374
474
  Finding,
475
+ FindingChange,
476
+ FindingDelta,
375
477
  FindingStatus,
376
478
  HIERARCHY_ROW_CAP,
479
+ HOTSPOTS_PAGE_MAX,
480
+ Hotspot,
481
+ HotspotMark,
482
+ ImpactRollup,
483
+ LinkedTests,
484
+ LookFirstRow,
377
485
  LruCache,
378
486
  MetricDescriptor,
379
487
  MissingReason,
488
+ NewFile,
380
489
  NodeKind,
490
+ NodeLens,
491
+ NodeLenses,
381
492
  NodeRef,
493
+ OVERVIEW_ROWS_MAX,
494
+ PACKAGES_MAX,
495
+ PATHS_IMPACT_MAX,
496
+ PackageLayer,
497
+ PackageStatsRow,
498
+ PathDelta,
499
+ PathHotspot,
500
+ PathImpact,
382
501
  Provenance,
383
502
  ProvenanceKind,
384
503
  QUERIES,
385
504
  RELATED_CAP,
386
505
  ReadError,
506
+ ReadingOrderRow,
507
+ Regression,
387
508
  RuleSummary,
509
+ ScoreBreakdown,
510
+ ScoreChange,
388
511
  Severity,
389
512
  SnapshotInfo,
390
513
  SnapshotRef,
@@ -394,21 +517,28 @@ export {
394
517
  createLiveSource,
395
518
  createQueryResolver,
396
519
  createWorktreeReader,
520
+ declaredTiers,
397
521
  defineCodeReadCommands,
398
522
  describeApi,
399
523
  describeRule,
400
524
  excessOf,
401
525
  findingNotFound,
526
+ getChanges,
402
527
  getFinding,
403
528
  getHierarchy,
404
529
  getNeighbors,
405
530
  getNode,
531
+ getOverview,
406
532
  invalidArgs,
407
533
  listFindings,
534
+ listHotspots,
408
535
  listSnapshots,
409
536
  loadReadModel,
410
537
  nodeNotFound,
538
+ packagesStats,
539
+ pathsImpact,
411
540
  registerCodeReadCommands,
541
+ repoRelative,
412
542
  resolveNode,
413
543
  resolveSnapshot,
414
544
  serializeContract,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/lru.ts","../src/source-reader.ts","../src/rule-text.ts","../src/live-source.ts","../src/findings-live.ts","../src/register.ts"],"sourcesContent":["/** A least-recently-used cache; Map iteration order is insertion order, so the first key is the eldest. */\nexport class LruCache<K, V> {\n private readonly entries = new Map<K, V>();\n\n constructor(readonly capacity: number) {\n if (!Number.isInteger(capacity) || capacity < 1) throw new RangeError(`LRU capacity must be a positive integer, got ${capacity}`);\n }\n\n get size(): number {\n return this.entries.size;\n }\n\n has(key: K): boolean {\n return this.entries.has(key);\n }\n\n /** The cached value, refreshed to most recent; otherwise `load`'s value, evicting the eldest when full. */\n getOrLoad(key: K, load: () => V): V {\n if (this.entries.has(key)) {\n const value = this.entries.get(key)!;\n this.entries.delete(key);\n this.entries.set(key, value);\n return value;\n }\n const value = load();\n this.entries.set(key, value);\n if (this.entries.size > this.capacity) this.entries.delete(this.entries.keys().next().value!);\n return value;\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n keys(): K[] {\n return [...this.entries.keys()];\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { hashContent, type CodeGraphStore } from \"@titan-design/code-graph\";\nimport { LruCache } from \"./lru.js\";\nimport type { SourceRead } from \"./query/source.js\";\n\nexport type FingerprintStore = Pick<CodeGraphStore, \"listFingerprints\">;\nexport type SourceReader = (snapshotId: number, fileId: string) => SourceRead;\n\n/** Split into lines without inventing an empty last line for a trailing newline. */\nexport function splitLines(text: string): string[] {\n if (text === \"\") return [];\n const lines = text.split(/\\r?\\n/);\n if (lines.at(-1) === \"\") lines.pop();\n return lines;\n}\n\nfunction readText(file: string): string | null {\n try {\n return readFileSync(file, \"utf8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Reads files from the working tree and serves them only when their hash matches the snapshot's fingerprint,\n * so line numbers never disagree with the snapshot the finding came from.\n */\nexport function createWorktreeReader(store: FingerprintStore, repoRoot: string, cacheSize = 3): SourceReader {\n const hashes = new LruCache<number, Map<string, string>>(cacheSize);\n const expected = (snapshotId: number): Map<string, string> =>\n hashes.getOrLoad(snapshotId, () => new Map(store.listFingerprints(snapshotId).map((f) => [f.fileId, f.contentHash])));\n return (snapshotId, fileId) => {\n const want = expected(snapshotId).get(fileId);\n if (want === undefined) return { unavailable: \"not-a-source-file\" };\n const text = readText(path.join(repoRoot, fileId));\n if (text === null) return { unavailable: \"unreadable\" };\n const contentHash = hashContent(text);\n if (contentHash !== want) return { unavailable: \"changed-since-snapshot\" };\n const lines = splitLines(text);\n return { path: fileId, contentHash, origin: \"worktree\", startLine: 1, lines, lineCount: lines.length };\n };\n}\n","import type { CheckRule } from \"@titan-design/code-graph\";\n\nfunction scopeSuffix(kind: string | undefined, excludeRoles: readonly string[] | undefined): string {\n const on = kind ? ` on each ${kind}` : \"\";\n const except = excludeRoles && excludeRoles.length > 0 ? `, except ${excludeRoles.join(\" and \")} files` : \"\";\n return `${on}${except}`;\n}\n\n/** A plain-language statement of what a check rule demands, for a finding's `why`. */\nexport function describeRule(rule: CheckRule): string {\n switch (rule.type) {\n case \"metric-max\":\n return `${rule.metric} must be at most ${rule.max}${scopeSuffix(rule.kind, rule.excludeRoles)}.`;\n case \"metric-min\":\n return `${rule.metric} must be at least ${rule.min}${scopeSuffix(rule.kind, rule.excludeRoles)}.`;\n case \"metric-product-max\":\n return `The product ${rule.metrics.join(\" * \")} must be at most ${rule.max}${scopeSuffix(rule.kind, rule.excludeRoles)}.`;\n case \"metric-outlier\":\n return `${rule.metric} must not exceed its ${rule.percentile}th percentile over every ${rule.kind} in the snapshot.`;\n case \"forbid-import\":\n return `Files matching ${rule.from} must not import ${rule.to}.`;\n case \"layered-deps\":\n return `An import may point only to its own layer or a lower one, across ${rule.layers.length} layers.`;\n case \"no-internal-only-barrels\":\n return \"A barrel file must be imported from outside its own package, or it should not exist.\";\n }\n}\n","import { describeMetric, type CheckRule, type CodeGraphStore, type SnapshotRow } from \"@titan-design/code-graph\";\nimport { deriveFindings, toModelRules } from \"./findings-live.js\";\nimport { LruCache } from \"./lru.js\";\nimport { COMMAND_NAMES } from \"./query/contract.js\";\nimport { buildReadModel, type ModelNode, type ReadModel } from \"./query/model.js\";\nimport type { Capabilities, SnapshotInfo } from \"./query/schemas.js\";\nimport { snapshotNotFound, type ReadSource, type SourceFacts } from \"./query/source.js\";\nimport { createWorktreeReader, type SourceReader } from \"./source-reader.js\";\n\n/** The store reads the live source needs; structural, so any compatible code-graph release fits. */\nexport type SnapshotStore = Pick<\n CodeGraphStore,\n \"getSnapshot\" | \"listSnapshots\" | \"listNodes\" | \"listEdges\" | \"listMetrics\" | \"listAliases\" | \"listFingerprints\"\n>;\n\nexport interface CodeReadDeps {\n /** Called once, on first use; the source holds the store for its lifetime. */\n openStore: () => SnapshotStore;\n /**\n * The product's check rules: reported by `api.describe` and run on each snapshot to derive findings. Policy, so the\n * package has no default set. Return the same array while the rules are unchanged; a new array drops every cached model.\n */\n rules?: () => readonly CheckRule[];\n /** The git toplevel the snapshots were indexed from; excerpts are served only where the file still matches its snapshot. */\n repoRoot?: string | null;\n /** Snapshot models kept in memory; each holds a whole snapshot. Defaults to 3. */\n cacheSize?: number;\n}\n\nexport const DEFAULT_MODEL_CACHE_SIZE = 3;\n\n// Findings are derived from check rules; the stored findings, verdicts, themes, and feedback arrive with G11.\nfunction liveCapabilities(hasSource: boolean): Capabilities {\n return {\n findings: \"check-rules\",\n verdicts: false,\n themes: false,\n feedback: false,\n embeddings: null,\n cochange: false,\n sourceAtCommit: false,\n excerpts: hasSource ? \"any\" : \"none\",\n };\n}\n\n// Far above any real snapshot count; the store's own default of 50 would hide older snapshots.\nconst ALL_SNAPSHOTS = 1_000_000;\n\nexport function toSnapshotInfo(row: SnapshotRow): SnapshotInfo {\n return { id: row.id, ref: row.ref, commit: row.commitHash, takenAt: row.takenAt, indexVersion: row.indexVersion };\n}\n\nfunction toModelNode(node: ReturnType<SnapshotStore[\"listNodes\"]>[number]): ModelNode {\n const out: ModelNode = { id: node.id, kind: node.kind, name: node.name, parentId: node.parentId ?? null, attrs: node.attrs ?? {} };\n if (node.language !== undefined) out.language = node.language;\n if (node.role !== undefined) out.role = node.role;\n return out;\n}\n\n/** How a model derives its findings: the rules to run and, optionally, a reader that locates flagged lines. */\nexport interface FindingOptions {\n rules: readonly CheckRule[];\n read?: SourceReader;\n}\n\n/** Read one whole snapshot, symbols and reference edges included, into a `ReadModel`, with findings when rules are given. */\nexport function loadReadModel(store: SnapshotStore, snapshotId: number, findings?: FindingOptions): ReadModel {\n const row = store.getSnapshot(snapshotId);\n if (!row) throw snapshotNotFound(snapshotId);\n const edges = store.listEdges(snapshotId, { includeReferences: true }).map((e) => ({ ...e, attrs: e.attrs ?? {} }));\n const rules = findings?.rules ?? [];\n return buildReadModel({\n snapshot: toSnapshotInfo(row),\n nodes: store.listNodes(snapshotId, { includeSymbols: true }).map(toModelNode),\n edges,\n aliases: store.listAliases(snapshotId),\n metrics: store.listMetrics(snapshotId),\n describe: describeMetric,\n findings: deriveFindings(store, rules, { snapshotId, edges, read: findings?.read }),\n rules: toModelRules(rules),\n });\n}\n\nexport interface LiveSource extends ReadSource {\n /** Snapshot ids currently cached, eldest first. */\n cachedSnapshots(): number[];\n}\n\n/** A `ReadSource` over a code-graph store; snapshots are immutable, so models are cached by id alone. */\nconst NO_RULES: readonly CheckRule[] = [];\n\ninterface RuleTrackedModels {\n models: LruCache<number, ReadModel>;\n /** The product's current rules; a different array than last time empties the model cache. */\n rules(): readonly CheckRule[];\n}\n\nfunction ruleTrackedModels(deps: CodeReadDeps): RuleTrackedModels {\n const models = new LruCache<number, ReadModel>(deps.cacheSize ?? DEFAULT_MODEL_CACHE_SIZE);\n let seen = NO_RULES;\n const rules = (): readonly CheckRule[] => {\n const current = deps.rules?.() ?? NO_RULES;\n if (current !== seen) {\n models.clear();\n seen = current;\n }\n return current;\n };\n return { models, rules };\n}\n\n/** A `ReadSource` over a code-graph store; snapshots are immutable, so models are cached by id until the rules change. */\nexport function createLiveSource(deps: CodeReadDeps): LiveSource {\n let store: SnapshotStore | undefined;\n let reader: SourceReader | undefined;\n const openOnce = (): SnapshotStore => (store ??= deps.openStore());\n const root = deps.repoRoot ?? null;\n const read: SourceReader | undefined =\n root === null ? undefined : (id, file) => (reader ??= createWorktreeReader(openOnce(), root))(id, file);\n const { models, rules } = ruleTrackedModels(deps);\n const facts = (): SourceFacts => ({\n dataset: \"live\",\n commands: COMMAND_NAMES,\n capabilities: liveCapabilities(read !== undefined),\n rules: rules().map((r) => ({ id: r.id, type: r.type, severity: r.severity ?? \"error\" })),\n });\n return {\n facts,\n snapshots: () => openOnce().listSnapshots({ limit: ALL_SNAPSHOTS }).map(toSnapshotInfo),\n model: (snapshotId) => {\n const current = rules();\n return models.getOrLoad(snapshotId, () => loadReadModel(openOnce(), snapshotId, { rules: current, read }));\n },\n ...(read ? { readSource: read } : {}),\n cachedSnapshots: () => models.keys(),\n };\n}\n","import { snapshotViolations, violationKey, type CheckRule, type CheckViolation, type RuleStore } from \"@titan-design/code-graph\";\nimport type { ModelEdge, ModelFinding, ModelRule } from \"./query/model.js\";\nimport type { Span } from \"./query/schemas.js\";\nimport { describeRule } from \"./rule-text.js\";\nimport type { SourceReader } from \"./source-reader.js\";\n\nconst IMPORT_KINDS = new Set([\"imports\", \"re-exports\"]);\nconst QUOTES = ['\"', \"'\", \"`\"];\n\nexport function toModelRules(rules: readonly CheckRule[]): ModelRule[] {\n return rules.map((r) => ({ id: r.id, type: r.type, severity: r.severity ?? \"error\", text: describeRule(r) }));\n}\n\nconst pairKey = (srcId: string, dstId: string): string => `${srcId}\\n${dstId}`;\n\nfunction specifiersOf(edges: readonly ModelEdge[]): Map<string, string> {\n const out = new Map<string, string>();\n for (const e of edges) {\n if (IMPORT_KINDS.has(e.kind) && typeof e.attrs.specifier === \"string\") out.set(pairKey(e.srcId, e.dstId), e.attrs.specifier);\n }\n return out;\n}\n\n/** Lines naming the specifier in quotes: the import statement's last line, where `from \"x\"` sits. */\nexport function specifierLines(lines: readonly string[], specifier: string): Span[] {\n const quoted = QUOTES.map((q) => `${q}${specifier}${q}`);\n const out: Span[] = [];\n lines.forEach((line, i) => {\n if (quoted.some((q) => line.includes(q))) out.push({ startLine: i + 1, endLine: i + 1 });\n });\n return out;\n}\n\nexport interface FindingInputs {\n snapshotId: number;\n edges: readonly ModelEdge[];\n read?: SourceReader;\n}\n\ninterface Located extends FindingInputs {\n specifiers: ReadonlyMap<string, string>;\n}\n\n// Edges carry no line numbers, so an import finding's range comes from the source text, when it matches the snapshot.\nfunction importRanges(v: CheckViolation, inputs: Located): Span[] | undefined {\n if (!v.destinationId || !inputs.read) return undefined;\n const specifier = inputs.specifiers.get(pairKey(v.nodeId, v.destinationId));\n if (specifier === undefined) return undefined;\n const source = inputs.read(inputs.snapshotId, v.nodeId);\n if (\"unavailable\" in source) return undefined;\n const ranges = specifierLines(source.lines, specifier);\n return ranges.length > 0 ? ranges : undefined;\n}\n\nfunction toModelFinding(v: CheckViolation, inputs: Located): ModelFinding {\n const f: ModelFinding = { id: violationKey(v), rule: v.ruleId, severity: v.severity, nodeId: v.nodeId, message: v.message };\n if (v.destinationId !== undefined) f.destinationId = v.destinationId;\n if (v.metric !== undefined) f.metric = v.metric;\n if (v.value !== undefined) f.value = v.value;\n if (v.threshold !== undefined) f.threshold = v.threshold;\n const ranges = importRanges(v, inputs);\n if (ranges) f.ranges = ranges;\n return f;\n}\n\n/** The snapshot's check-rule violations as findings, computed by the same engine and keyed as the ratchet keys them. */\nexport function deriveFindings(store: RuleStore, rules: readonly CheckRule[], inputs: FindingInputs): ModelFinding[] {\n if (rules.length === 0) return [];\n const violations = snapshotViolations(store, inputs.snapshotId, rules);\n const located: Located = { ...inputs, specifiers: specifiersOf(inputs.edges) };\n return violations.map((v) => toModelFinding(v, located));\n}\n","import { defineCommand, type AnyCommand, type BaseContext, type CliMeta, type CommandRegistry } from \"@titan-design/registry\";\nimport { createLiveSource, type CodeReadDeps, type LiveSource } from \"./live-source.js\";\nimport { QUERIES, type QueryFn } from \"./query/commands.js\";\nimport { COMMAND_NAMES, CONTRACT, type CommandName } from \"./query/contract.js\";\nimport type { ReadSource } from \"./query/source.js\";\n\nconst CLI: Partial<Record<CommandName, CliMeta>> = {\n \"snapshot.list\": {\n options: {\n ref: { long: \"--ref\", description: \"Only snapshots of this ref\" },\n limit: { long: \"--limit\", description: \"Most snapshots to return (default 50, max 500)\" },\n },\n },\n \"hierarchy.get\": {\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n root: { long: \"--root\", description: \"Node id to start from; a directory id ends in / (default: the repo)\" },\n depth: { long: \"--depth\", description: \"Levels below the root (default 2, max 8)\" },\n metrics: { long: \"--metric\", description: \"Metric to report; repeatable (default loc)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to compute deltas against\" },\n include_symbols: { long: \"--include-symbols\", description: \"Descend into symbols below files\" },\n exclude_roles: { long: \"--exclude-role\", description: \"Leave out files with this role; repeatable\" },\n },\n },\n \"node.get\": {\n positional: [\"id\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to compute deltas against\" },\n metrics: { long: \"--metric\", description: \"Metric to report; repeatable (default: every one that applies)\" },\n },\n },\n \"node.resolve\": {\n positional: [\"query\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n path: { long: \"--path\", description: \"A file path instead of a query\" },\n line: { long: \"--line\", description: \"With --path: resolve to the innermost symbol containing this line\" },\n limit: { long: \"--limit\", description: \"Most candidates (default 10, max 50)\" },\n },\n },\n \"findings.list\": {\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to give each finding a status against\" },\n scope: { long: \"--scope\", description: \"Node id; only findings on it or under it\" },\n rule: { long: \"--rule\", description: \"Only this rule; repeatable\" },\n severity: { long: \"--severity\", description: \"Only this severity; repeatable\" },\n tool: { long: \"--tool\", description: \"Only this tool; repeatable\" },\n provenance: { long: \"--provenance\", description: \"Only measured, derived, or model findings; repeatable\" },\n kind: { long: \"--kind\", description: \"Only findings on nodes of this kind; repeatable\" },\n status: { long: \"--status\", description: \"With --baseline: new, carryover, resolved, worsened, or improved; repeatable\" },\n sort: { long: \"--sort\", description: \"severity (default), excess, value, path, or rule\" },\n order: { long: \"--order\", description: \"desc (default) or asc; flips the sort key only\" },\n offset: { long: \"--offset\", description: \"Rows to skip (default 0)\" },\n limit: { long: \"--limit\", description: \"Rows to return (default 20, max 500; 0 for counts only)\" },\n facets: { long: \"--facets\", description: \"Also count rows per rule, severity, tool, provenance, kind, and child\" },\n },\n },\n \"finding.get\": {\n positional: [\"id\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref for status and the baseline value\" },\n context_lines: { long: \"--context-lines\", description: \"Lines of context either side of the flagged range (default 5, max 20)\" },\n },\n },\n \"node.neighbors\": {\n positional: [\"id\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n direction: { long: \"--direction\", description: \"in, out, or both (default)\" },\n edge_kinds: { long: \"--edge-kind\", description: \"Only this edge kind; repeatable (default: all but references, except for a symbol)\" },\n metrics: { long: \"--metric\", description: \"Neighbour metric to report; repeatable (default loc and utilization)\" },\n offset: { long: \"--offset\", description: \"Edges to skip on each side (default 0)\" },\n limit: { long: \"--limit\", description: \"Edges per side (default 20, max 100)\" },\n },\n },\n};\n\nfunction defineOne<Ctx extends BaseContext>(source: ReadSource, name: CommandName): AnyCommand<Ctx> {\n const { description, args, result } = CONTRACT[name];\n const query = QUERIES[name] as QueryFn<CommandName>;\n return defineCommand<unknown, unknown, Ctx>({\n name,\n description,\n args,\n result,\n cli: CLI[name],\n run: (parsed) => Promise.resolve(query(source, parsed as never)),\n });\n}\n\n/**\n * One registry command per contract entry, answering from `source`. Exposed so a product can\n * register a subset on a second registry, for example an MCP-only one, until the registry filters surfaces.\n */\nexport function defineCodeReadCommands<Ctx extends BaseContext = BaseContext>(source: ReadSource): AnyCommand<Ctx>[] {\n return COMMAND_NAMES.map((name) => defineOne<Ctx>(source, name));\n}\n\n/** Register every read command on a product's registry over a live store; returns the source for inspection. */\nexport function registerCodeReadCommands<Ctx extends BaseContext>(\n registry: CommandRegistry<Ctx>,\n deps: CodeReadDeps,\n): LiveSource {\n const source = createLiveSource(deps);\n for (const cmd of defineCodeReadCommands<Ctx>(source)) registry.register(cmd);\n return source;\n}\n"],"mappings":"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","names":["value"]}
1
+ {"version":3,"sources":["../src/lru.ts","../src/source-reader.ts","../src/rule-text.ts","../src/live-source.ts","../src/findings-live.ts","../src/register.ts"],"sourcesContent":["/** A least-recently-used cache; Map iteration order is insertion order, so the first key is the eldest. */\nexport class LruCache<K, V> {\n private readonly entries = new Map<K, V>();\n\n constructor(readonly capacity: number) {\n if (!Number.isInteger(capacity) || capacity < 1) throw new RangeError(`LRU capacity must be a positive integer, got ${capacity}`);\n }\n\n get size(): number {\n return this.entries.size;\n }\n\n has(key: K): boolean {\n return this.entries.has(key);\n }\n\n /** The cached value, refreshed to most recent; otherwise `load`'s value, evicting the eldest when full. */\n getOrLoad(key: K, load: () => V): V {\n if (this.entries.has(key)) {\n const value = this.entries.get(key)!;\n this.entries.delete(key);\n this.entries.set(key, value);\n return value;\n }\n const value = load();\n this.entries.set(key, value);\n if (this.entries.size > this.capacity) this.entries.delete(this.entries.keys().next().value!);\n return value;\n }\n\n clear(): void {\n this.entries.clear();\n }\n\n keys(): K[] {\n return [...this.entries.keys()];\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { hashContent, type CodeGraphStore } from \"@titan-design/code-graph\";\nimport { LruCache } from \"./lru.js\";\nimport type { SourceRead } from \"./query/source.js\";\n\nexport type FingerprintStore = Pick<CodeGraphStore, \"listFingerprints\">;\nexport type SourceReader = (snapshotId: number, fileId: string) => SourceRead;\n\n/** Split into lines without inventing an empty last line for a trailing newline. */\nexport function splitLines(text: string): string[] {\n if (text === \"\") return [];\n const lines = text.split(/\\r?\\n/);\n if (lines.at(-1) === \"\") lines.pop();\n return lines;\n}\n\nfunction readText(file: string): string | null {\n try {\n return readFileSync(file, \"utf8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Reads files from the working tree and serves them only when their hash matches the snapshot's fingerprint,\n * so line numbers never disagree with the snapshot the finding came from.\n */\nexport function createWorktreeReader(store: FingerprintStore, repoRoot: string, cacheSize = 3): SourceReader {\n const hashes = new LruCache<number, Map<string, string>>(cacheSize);\n const expected = (snapshotId: number): Map<string, string> =>\n hashes.getOrLoad(snapshotId, () => new Map(store.listFingerprints(snapshotId).map((f) => [f.fileId, f.contentHash])));\n return (snapshotId, fileId) => {\n const want = expected(snapshotId).get(fileId);\n if (want === undefined) return { unavailable: \"not-a-source-file\" };\n const text = readText(path.join(repoRoot, fileId));\n if (text === null) return { unavailable: \"unreadable\" };\n const contentHash = hashContent(text);\n if (contentHash !== want) return { unavailable: \"changed-since-snapshot\" };\n const lines = splitLines(text);\n return { path: fileId, contentHash, origin: \"worktree\", startLine: 1, lines, lineCount: lines.length };\n };\n}\n","import type { CheckRule } from \"@titan-design/code-graph\";\n\nfunction scopeSuffix(kind: string | undefined, excludeRoles: readonly string[] | undefined): string {\n const on = kind ? ` on each ${kind}` : \"\";\n const except = excludeRoles && excludeRoles.length > 0 ? `, except ${excludeRoles.join(\" and \")} files` : \"\";\n return `${on}${except}`;\n}\n\n/** A plain-language statement of what a check rule demands, for a finding's `why`. */\nexport function describeRule(rule: CheckRule): string {\n switch (rule.type) {\n case \"metric-max\":\n return `${rule.metric} must be at most ${rule.max}${scopeSuffix(rule.kind, rule.excludeRoles)}.`;\n case \"metric-min\":\n return `${rule.metric} must be at least ${rule.min}${scopeSuffix(rule.kind, rule.excludeRoles)}.`;\n case \"metric-product-max\":\n return `The product ${rule.metrics.join(\" * \")} must be at most ${rule.max}${scopeSuffix(rule.kind, rule.excludeRoles)}.`;\n case \"metric-outlier\":\n return `${rule.metric} must not exceed its ${rule.percentile}th percentile over every ${rule.kind} in the snapshot.`;\n case \"forbid-import\":\n return `Files matching ${rule.from} must not import ${rule.to}.`;\n case \"layered-deps\":\n return `An import may point only to its own layer or a lower one, across ${rule.layers.length} layers.`;\n case \"no-internal-only-barrels\":\n return \"A barrel file must be imported from outside its own package, or it should not exist.\";\n }\n}\n","import { describeMetric, type CheckRule, type CodeGraphStore, type SnapshotRow } from \"@titan-design/code-graph\";\nimport { deriveFindings, toModelRules } from \"./findings-live.js\";\nimport { LruCache } from \"./lru.js\";\nimport { COMMAND_NAMES } from \"./query/contract.js\";\nimport { buildReadModel, type ModelNode, type ReadModel } from \"./query/model.js\";\nimport type { Capabilities, SnapshotInfo } from \"./query/schemas.js\";\nimport { snapshotNotFound, type ReadSource, type SourceFacts } from \"./query/source.js\";\nimport { createWorktreeReader, type SourceReader } from \"./source-reader.js\";\n\n/** The store reads the live source needs; structural, so any compatible code-graph release fits. */\nexport type SnapshotStore = Pick<\n CodeGraphStore,\n \"getSnapshot\" | \"listSnapshots\" | \"listNodes\" | \"listEdges\" | \"listMetrics\" | \"listAliases\" | \"listFingerprints\"\n>;\n\nexport interface CodeReadDeps {\n /** Called once, on first use; the source holds the store for its lifetime. */\n openStore: () => SnapshotStore;\n /**\n * The product's check rules: reported by `api.describe` and run on each snapshot to derive findings. Policy, so the\n * package has no default set. Return the same array while the rules are unchanged; a new array drops every cached model.\n */\n rules?: () => readonly CheckRule[];\n /** The git toplevel the snapshots were indexed from; excerpts are served only where the file still matches its snapshot. */\n repoRoot?: string | null;\n /** Snapshot models kept in memory; each holds a whole snapshot. Defaults to 3. */\n cacheSize?: number;\n}\n\nexport const DEFAULT_MODEL_CACHE_SIZE = 3;\n\n// Findings are derived from check rules; the stored findings, verdicts, themes, and feedback arrive with G11.\nfunction liveCapabilities(hasSource: boolean): Capabilities {\n return {\n findings: \"check-rules\",\n verdicts: false,\n themes: false,\n feedback: false,\n embeddings: null,\n cochange: false,\n sourceAtCommit: false,\n excerpts: hasSource ? \"any\" : \"none\",\n };\n}\n\n// Far above any real snapshot count; the store's own default of 50 would hide older snapshots.\nconst ALL_SNAPSHOTS = 1_000_000;\n\nexport function toSnapshotInfo(row: SnapshotRow): SnapshotInfo {\n return { id: row.id, ref: row.ref, commit: row.commitHash, takenAt: row.takenAt, indexVersion: row.indexVersion };\n}\n\nfunction toModelNode(node: ReturnType<SnapshotStore[\"listNodes\"]>[number]): ModelNode {\n const out: ModelNode = { id: node.id, kind: node.kind, name: node.name, parentId: node.parentId ?? null, attrs: node.attrs ?? {} };\n if (node.language !== undefined) out.language = node.language;\n if (node.role !== undefined) out.role = node.role;\n return out;\n}\n\n/** How a model derives its findings: the rules to run and, optionally, a reader that locates flagged lines. */\nexport interface FindingOptions {\n rules: readonly CheckRule[];\n read?: SourceReader;\n}\n\n/** Read one whole snapshot, symbols and reference edges included, into a `ReadModel`, with findings when rules are given. */\nexport function loadReadModel(store: SnapshotStore, snapshotId: number, findings?: FindingOptions): ReadModel {\n const row = store.getSnapshot(snapshotId);\n if (!row) throw snapshotNotFound(snapshotId);\n const edges = store.listEdges(snapshotId, { includeReferences: true }).map((e) => ({ ...e, attrs: e.attrs ?? {} }));\n const rules = findings?.rules ?? [];\n return buildReadModel({\n snapshot: toSnapshotInfo(row),\n nodes: store.listNodes(snapshotId, { includeSymbols: true }).map(toModelNode),\n edges,\n aliases: store.listAliases(snapshotId),\n metrics: store.listMetrics(snapshotId),\n describe: describeMetric,\n findings: deriveFindings(store, rules, { snapshotId, edges, read: findings?.read }),\n rules: toModelRules(rules),\n });\n}\n\nexport interface LiveSource extends ReadSource {\n /** Snapshot ids currently cached, eldest first. */\n cachedSnapshots(): number[];\n}\n\n/** A `ReadSource` over a code-graph store; snapshots are immutable, so models are cached by id alone. */\nconst NO_RULES: readonly CheckRule[] = [];\n\ninterface RuleTrackedModels {\n models: LruCache<number, ReadModel>;\n /** The product's current rules; a different array than last time empties the model cache. */\n rules(): readonly CheckRule[];\n}\n\nfunction ruleTrackedModels(deps: CodeReadDeps): RuleTrackedModels {\n const models = new LruCache<number, ReadModel>(deps.cacheSize ?? DEFAULT_MODEL_CACHE_SIZE);\n let seen = NO_RULES;\n const rules = (): readonly CheckRule[] => {\n const current = deps.rules?.() ?? NO_RULES;\n if (current !== seen) {\n models.clear();\n seen = current;\n }\n return current;\n };\n return { models, rules };\n}\n\n/** A `ReadSource` over a code-graph store; snapshots are immutable, so models are cached by id until the rules change. */\nexport function createLiveSource(deps: CodeReadDeps): LiveSource {\n let store: SnapshotStore | undefined;\n let reader: SourceReader | undefined;\n const openOnce = (): SnapshotStore => (store ??= deps.openStore());\n const root = deps.repoRoot ?? null;\n const read: SourceReader | undefined =\n root === null ? undefined : (id, file) => (reader ??= createWorktreeReader(openOnce(), root))(id, file);\n const { models, rules } = ruleTrackedModels(deps);\n const facts = (): SourceFacts => ({\n dataset: \"live\",\n commands: COMMAND_NAMES,\n capabilities: liveCapabilities(read !== undefined),\n rules: rules().map((r) => ({ id: r.id, type: r.type, severity: r.severity ?? \"error\" })),\n });\n return {\n facts,\n snapshots: () => openOnce().listSnapshots({ limit: ALL_SNAPSHOTS }).map(toSnapshotInfo),\n model: (snapshotId) => {\n const current = rules();\n return models.getOrLoad(snapshotId, () => loadReadModel(openOnce(), snapshotId, { rules: current, read }));\n },\n ...(read ? { readSource: read } : {}),\n repoRoot: root,\n cachedSnapshots: () => models.keys(),\n };\n}\n","import { snapshotViolations, violationKey, type CheckRule, type CheckViolation, type RuleStore } from \"@titan-design/code-graph\";\nimport type { ModelEdge, ModelFinding, ModelRule } from \"./query/model.js\";\nimport type { Span } from \"./query/schemas.js\";\nimport { describeRule } from \"./rule-text.js\";\nimport type { SourceReader } from \"./source-reader.js\";\n\nconst IMPORT_KINDS = new Set([\"imports\", \"re-exports\"]);\nconst QUOTES = ['\"', \"'\", \"`\"];\n\nexport function toModelRules(rules: readonly CheckRule[]): ModelRule[] {\n return rules.map((r) => {\n const rule: ModelRule = { id: r.id, type: r.type, severity: r.severity ?? \"error\", text: describeRule(r) };\n if (r.type === \"layered-deps\") rule.layers = r.layers;\n return rule;\n });\n}\n\nconst pairKey = (srcId: string, dstId: string): string => `${srcId}\\n${dstId}`;\n\nfunction specifiersOf(edges: readonly ModelEdge[]): Map<string, string> {\n const out = new Map<string, string>();\n for (const e of edges) {\n if (IMPORT_KINDS.has(e.kind) && typeof e.attrs.specifier === \"string\") out.set(pairKey(e.srcId, e.dstId), e.attrs.specifier);\n }\n return out;\n}\n\n/** Lines naming the specifier in quotes: the import statement's last line, where `from \"x\"` sits. */\nexport function specifierLines(lines: readonly string[], specifier: string): Span[] {\n const quoted = QUOTES.map((q) => `${q}${specifier}${q}`);\n const out: Span[] = [];\n lines.forEach((line, i) => {\n if (quoted.some((q) => line.includes(q))) out.push({ startLine: i + 1, endLine: i + 1 });\n });\n return out;\n}\n\nexport interface FindingInputs {\n snapshotId: number;\n edges: readonly ModelEdge[];\n read?: SourceReader;\n}\n\ninterface Located extends FindingInputs {\n specifiers: ReadonlyMap<string, string>;\n}\n\n// Edges carry no line numbers, so an import finding's range comes from the source text, when it matches the snapshot.\nfunction importRanges(v: CheckViolation, inputs: Located): Span[] | undefined {\n if (!v.destinationId || !inputs.read) return undefined;\n const specifier = inputs.specifiers.get(pairKey(v.nodeId, v.destinationId));\n if (specifier === undefined) return undefined;\n const source = inputs.read(inputs.snapshotId, v.nodeId);\n if (\"unavailable\" in source) return undefined;\n const ranges = specifierLines(source.lines, specifier);\n return ranges.length > 0 ? ranges : undefined;\n}\n\nfunction toModelFinding(v: CheckViolation, inputs: Located): ModelFinding {\n const f: ModelFinding = { id: violationKey(v), rule: v.ruleId, severity: v.severity, nodeId: v.nodeId, message: v.message };\n if (v.destinationId !== undefined) f.destinationId = v.destinationId;\n if (v.metric !== undefined) f.metric = v.metric;\n if (v.value !== undefined) f.value = v.value;\n if (v.threshold !== undefined) f.threshold = v.threshold;\n const ranges = importRanges(v, inputs);\n if (ranges) f.ranges = ranges;\n return f;\n}\n\n/** The snapshot's check-rule violations as findings, computed by the same engine and keyed as the ratchet keys them. */\nexport function deriveFindings(store: RuleStore, rules: readonly CheckRule[], inputs: FindingInputs): ModelFinding[] {\n if (rules.length === 0) return [];\n const violations = snapshotViolations(store, inputs.snapshotId, rules);\n const located: Located = { ...inputs, specifiers: specifiersOf(inputs.edges) };\n return violations.map((v) => toModelFinding(v, located));\n}\n","import { defineCommand, type AnyCommand, type BaseContext, type CliMeta, type CommandRegistry } from \"@titan-design/registry\";\nimport { createLiveSource, type CodeReadDeps, type LiveSource } from \"./live-source.js\";\nimport { QUERIES, type QueryFn } from \"./query/commands.js\";\nimport { COMMAND_NAMES, CONTRACT, type CommandName } from \"./query/contract.js\";\nimport type { ReadSource } from \"./query/source.js\";\n\nconst CLI: Partial<Record<CommandName, CliMeta>> = {\n \"snapshot.list\": {\n options: {\n ref: { long: \"--ref\", description: \"Only snapshots of this ref\" },\n limit: { long: \"--limit\", description: \"Most snapshots to return (default 50, max 500)\" },\n },\n },\n \"hierarchy.get\": {\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n root: { long: \"--root\", description: \"Node id to start from; a directory id ends in / (default: the repo)\" },\n depth: { long: \"--depth\", description: \"Levels below the root (default 2, max 8)\" },\n metrics: { long: \"--metric\", description: \"Metric to report; repeatable (default loc)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to compute deltas against\" },\n include_symbols: { long: \"--include-symbols\", description: \"Descend into symbols below files\" },\n exclude_roles: { long: \"--exclude-role\", description: \"Leave out files with this role; repeatable\" },\n },\n },\n \"node.get\": {\n positional: [\"id\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to compute deltas against\" },\n metrics: { long: \"--metric\", description: \"Metric to report; repeatable (default: every one that applies)\" },\n lenses: { long: \"--lens\", description: \"exports, score, centrality, coupling, or tests; repeatable\" },\n window: { long: \"--window\", description: \"Churn window the score lens reads, such as 90d, or lifetime (default 30d)\" },\n },\n },\n \"node.resolve\": {\n positional: [\"query\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n path: { long: \"--path\", description: \"A file path instead of a query\" },\n line: { long: \"--line\", description: \"With --path: resolve to the innermost symbol containing this line\" },\n limit: { long: \"--limit\", description: \"Most candidates (default 10, max 50)\" },\n },\n },\n \"findings.list\": {\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to give each finding a status against\" },\n scope: { long: \"--scope\", description: \"Node id; only findings on it or under it\" },\n rule: { long: \"--rule\", description: \"Only this rule; repeatable\" },\n severity: { long: \"--severity\", description: \"Only this severity; repeatable\" },\n tool: { long: \"--tool\", description: \"Only this tool; repeatable\" },\n provenance: { long: \"--provenance\", description: \"Only measured, derived, or model findings; repeatable\" },\n kind: { long: \"--kind\", description: \"Only findings on nodes of this kind; repeatable\" },\n status: { long: \"--status\", description: \"With --baseline: new, carryover, resolved, worsened, or improved; repeatable\" },\n sort: { long: \"--sort\", description: \"severity (default), excess, value, path, or rule\" },\n order: { long: \"--order\", description: \"desc (default) or asc; flips the sort key only\" },\n offset: { long: \"--offset\", description: \"Rows to skip (default 0)\" },\n limit: { long: \"--limit\", description: \"Rows to return (default 20, max 500; 0 for counts only)\" },\n facets: { long: \"--facets\", description: \"Also count rows per rule, severity, tool, provenance, kind, and child\" },\n },\n },\n \"finding.get\": {\n positional: [\"id\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref for status and the baseline value\" },\n context_lines: { long: \"--context-lines\", description: \"Lines of context either side of the flagged range (default 5, max 20)\" },\n },\n },\n \"hotspots.list\": {\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to mark rows new or worsened against\" },\n grain: { long: \"--grain\", description: \"file (default) or symbol\" },\n window: { long: \"--window\", description: \"Churn window such as 90d, or lifetime (default 30d)\" },\n cutoff: { long: \"--cutoff\", description: \"Only rows scoring at least this\" },\n offset: { long: \"--offset\", description: \"Rows to skip (default 0)\" },\n limit: { long: \"--limit\", description: \"Rows to return (default 20, max 500; 0 for the total only)\" },\n },\n },\n \"overview.get\": {\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to count findings new, carried over, or resolved against\" },\n window: { long: \"--window\", description: \"Churn window such as 90d, or lifetime (default 30d)\" },\n cutoff: { long: \"--cutoff\", description: \"Hotspot score a file is over the cutoff at (default 3000)\" },\n exclude_rules: { long: \"--exclude-rule\", description: \"Leave this rule out of the findings signal; repeatable\" },\n combined: { long: \"--combined\", description: \"Also return 100 minus every signal's penalty\" },\n reading_limit: { long: \"--reading-limit\", description: \"Files in the reading order (default 6, max 50)\" },\n look_limit: { long: \"--look-limit\", description: \"Look-first rows (default 8, max 50)\" },\n },\n },\n \"changes.get\": {\n positional: [\"baseline\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n window: { long: \"--window\", description: \"Churn window such as 90d, or lifetime (default 30d)\" },\n cutoff: { long: \"--cutoff\", description: \"Hotspot score a file is over the cutoff at (default 3000)\" },\n limit: { long: \"--limit\", description: \"Rows per list (default 20, max 500; 0 for counts only)\" },\n },\n },\n \"paths.impact\": {\n options: {\n paths: { long: \"--path\", description: \"Repo-relative file path, or absolute under --root; repeatable\" },\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n baseline: { long: \"--baseline\", description: \"Snapshot id or ref to compute score, complexity, and findings deltas against\" },\n root: { long: \"--root\", description: \"Absolute checkout directory, so absolute paths under it are read as repo paths\" },\n window: { long: \"--window\", description: \"Churn window such as 90d, or lifetime (default 30d)\" },\n },\n },\n \"packages.stats\": {\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n packages: { long: \"--package\", description: \"Package root such as packages/cli; repeatable (default: every package the tier config declares)\" },\n },\n },\n \"node.neighbors\": {\n positional: [\"id\"],\n options: {\n snapshot: { long: \"--snapshot\", description: \"Snapshot id or ref name (default: newest)\" },\n direction: { long: \"--direction\", description: \"in, out, or both (default)\" },\n edge_kinds: { long: \"--edge-kind\", description: \"Only this edge kind; repeatable (default: all but references, except for a symbol)\" },\n metrics: { long: \"--metric\", description: \"Neighbour metric to report; repeatable (default loc and utilization)\" },\n offset: { long: \"--offset\", description: \"Edges to skip on each side (default 0)\" },\n limit: { long: \"--limit\", description: \"Edges per side (default 20, max 100)\" },\n },\n },\n};\n\nfunction defineOne<Ctx extends BaseContext>(source: ReadSource, name: CommandName): AnyCommand<Ctx> {\n const { description, args, result } = CONTRACT[name];\n const query = QUERIES[name] as QueryFn<CommandName>;\n return defineCommand<unknown, unknown, Ctx>({\n name,\n description,\n args,\n result,\n cli: CLI[name],\n run: (parsed) => Promise.resolve(query(source, parsed as never)),\n });\n}\n\n/**\n * One registry command per contract entry, answering from `source`. Exposed so a product can\n * register a subset on a second registry, for example an MCP-only one, until the registry filters surfaces.\n */\nexport function defineCodeReadCommands<Ctx extends BaseContext = BaseContext>(source: ReadSource): AnyCommand<Ctx>[] {\n return COMMAND_NAMES.map((name) => defineOne<Ctx>(source, name));\n}\n\n/** Register every read command on a product's registry over a live store; returns the source for inspection. */\nexport function registerCodeReadCommands<Ctx extends BaseContext>(\n registry: CommandRegistry<Ctx>,\n deps: CodeReadDeps,\n): LiveSource {\n const source = createLiveSource(deps);\n for (const cmd of defineCodeReadCommands<Ctx>(source)) registry.register(cmd);\n return source;\n}\n"],"mappings":"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","names":["value"]}