@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/README.md +111 -3
- package/dist/chunk-7FNTXO7C.js +2344 -0
- package/dist/chunk-7FNTXO7C.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +133 -3
- package/dist/index.js.map +1 -1
- package/dist/query/index.d.ts +1283 -5
- package/dist/query/index.js +77 -1
- package/package.json +5 -5
- package/dist/chunk-VXQFCVGB.js +0 -1326
- package/dist/chunk-VXQFCVGB.js.map +0 -1
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-
|
|
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) =>
|
|
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"]}
|