@kogu/context-check 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +213 -0
  3. package/dist/analyzer/engine.d.ts +27 -0
  4. package/dist/analyzer/engine.js +64 -0
  5. package/dist/analyzer/engine.js.map +1 -0
  6. package/dist/analyzer/rules/context-overhead.d.ts +21 -0
  7. package/dist/analyzer/rules/context-overhead.js +53 -0
  8. package/dist/analyzer/rules/context-overhead.js.map +1 -0
  9. package/dist/analyzer/rules/duplicate.d.ts +15 -0
  10. package/dist/analyzer/rules/duplicate.js +53 -0
  11. package/dist/analyzer/rules/duplicate.js.map +1 -0
  12. package/dist/analyzer/rules/high-stakes.d.ts +36 -0
  13. package/dist/analyzer/rules/high-stakes.js +96 -0
  14. package/dist/analyzer/rules/high-stakes.js.map +1 -0
  15. package/dist/analyzer/rules/large-file.d.ts +15 -0
  16. package/dist/analyzer/rules/large-file.js +41 -0
  17. package/dist/analyzer/rules/large-file.js.map +1 -0
  18. package/dist/analyzer/rules/mapping.d.ts +29 -0
  19. package/dist/analyzer/rules/mapping.js +51 -0
  20. package/dist/analyzer/rules/mapping.js.map +1 -0
  21. package/dist/analyzer/rules/repetition.d.ts +20 -0
  22. package/dist/analyzer/rules/repetition.js +80 -0
  23. package/dist/analyzer/rules/repetition.js.map +1 -0
  24. package/dist/analyzer/rules/scoped-no-match.d.ts +15 -0
  25. package/dist/analyzer/rules/scoped-no-match.js +46 -0
  26. package/dist/analyzer/rules/scoped-no-match.js.map +1 -0
  27. package/dist/analyzer/run.d.ts +25 -0
  28. package/dist/analyzer/run.js +59 -0
  29. package/dist/analyzer/run.js.map +1 -0
  30. package/dist/analyzer/severity.d.ts +21 -0
  31. package/dist/analyzer/severity.js +39 -0
  32. package/dist/analyzer/severity.js.map +1 -0
  33. package/dist/analyzer/types.d.ts +35 -0
  34. package/dist/analyzer/types.js +17 -0
  35. package/dist/analyzer/types.js.map +1 -0
  36. package/dist/cli/index.d.ts +23 -0
  37. package/dist/cli/index.js +159 -0
  38. package/dist/cli/index.js.map +1 -0
  39. package/dist/config/load.d.ts +11 -0
  40. package/dist/config/load.js +38 -0
  41. package/dist/config/load.js.map +1 -0
  42. package/dist/discovery/adapters/agents.d.ts +8 -0
  43. package/dist/discovery/adapters/agents.js +25 -0
  44. package/dist/discovery/adapters/agents.js.map +1 -0
  45. package/dist/discovery/adapters/artifact.d.ts +21 -0
  46. package/dist/discovery/adapters/artifact.js +40 -0
  47. package/dist/discovery/adapters/artifact.js.map +1 -0
  48. package/dist/discovery/adapters/claude.d.ts +8 -0
  49. package/dist/discovery/adapters/claude.js +25 -0
  50. package/dist/discovery/adapters/claude.js.map +1 -0
  51. package/dist/discovery/adapters/cursor.d.ts +11 -0
  52. package/dist/discovery/adapters/cursor.js +32 -0
  53. package/dist/discovery/adapters/cursor.js.map +1 -0
  54. package/dist/discovery/adapters/index.d.ts +10 -0
  55. package/dist/discovery/adapters/index.js +18 -0
  56. package/dist/discovery/adapters/index.js.map +1 -0
  57. package/dist/discovery/adapters/skill.d.ts +9 -0
  58. package/dist/discovery/adapters/skill.js +26 -0
  59. package/dist/discovery/adapters/skill.js.map +1 -0
  60. package/dist/discovery/adapters/types.d.ts +22 -0
  61. package/dist/discovery/adapters/types.js +9 -0
  62. package/dist/discovery/adapters/types.js.map +1 -0
  63. package/dist/discovery/discover.d.ts +32 -0
  64. package/dist/discovery/discover.js +51 -0
  65. package/dist/discovery/discover.js.map +1 -0
  66. package/dist/discovery/exclusions.d.ts +19 -0
  67. package/dist/discovery/exclusions.js +40 -0
  68. package/dist/discovery/exclusions.js.map +1 -0
  69. package/dist/discovery/scanner.d.ts +31 -0
  70. package/dist/discovery/scanner.js +75 -0
  71. package/dist/discovery/scanner.js.map +1 -0
  72. package/dist/git/history.d.ts +25 -0
  73. package/dist/git/history.js +71 -0
  74. package/dist/git/history.js.map +1 -0
  75. package/dist/git/sufficiency.d.ts +38 -0
  76. package/dist/git/sufficiency.js +98 -0
  77. package/dist/git/sufficiency.js.map +1 -0
  78. package/dist/index.d.ts +8 -0
  79. package/dist/index.js +13 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/output/json.d.ts +58 -0
  82. package/dist/output/json.js +52 -0
  83. package/dist/output/json.js.map +1 -0
  84. package/dist/output/terminal.d.ts +21 -0
  85. package/dist/output/terminal.js +163 -0
  86. package/dist/output/terminal.js.map +1 -0
  87. package/dist/parser/frontmatter.d.ts +26 -0
  88. package/dist/parser/frontmatter.js +63 -0
  89. package/dist/parser/frontmatter.js.map +1 -0
  90. package/dist/parser/markdown.d.ts +23 -0
  91. package/dist/parser/markdown.js +63 -0
  92. package/dist/parser/markdown.js.map +1 -0
  93. package/dist/parser/normalize.d.ts +20 -0
  94. package/dist/parser/normalize.js +35 -0
  95. package/dist/parser/normalize.js.map +1 -0
  96. package/dist/parser/parse.d.ts +34 -0
  97. package/dist/parser/parse.js +35 -0
  98. package/dist/parser/parse.js.map +1 -0
  99. package/dist/parser/plain-text.d.ts +30 -0
  100. package/dist/parser/plain-text.js +52 -0
  101. package/dist/parser/plain-text.js.map +1 -0
  102. package/dist/parser/scope.d.ts +20 -0
  103. package/dist/parser/scope.js +44 -0
  104. package/dist/parser/scope.js.map +1 -0
  105. package/dist/snapshot/diff.d.ts +62 -0
  106. package/dist/snapshot/diff.js +146 -0
  107. package/dist/snapshot/diff.js.map +1 -0
  108. package/dist/snapshot/manager.d.ts +54 -0
  109. package/dist/snapshot/manager.js +131 -0
  110. package/dist/snapshot/manager.js.map +1 -0
  111. package/dist/tokens/estimator.d.ts +12 -0
  112. package/dist/tokens/estimator.js +16 -0
  113. package/dist/tokens/estimator.js.map +1 -0
  114. package/dist/types/configuration.d.ts +47 -0
  115. package/dist/types/configuration.js +9 -0
  116. package/dist/types/configuration.js.map +1 -0
  117. package/dist/types/finding.d.ts +32 -0
  118. package/dist/types/finding.js +14 -0
  119. package/dist/types/finding.js.map +1 -0
  120. package/dist/types/report.d.ts +20 -0
  121. package/dist/types/report.js +9 -0
  122. package/dist/types/report.js.map +1 -0
  123. package/package.json +70 -0
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * contextcheck CLI entry point.
4
+ *
5
+ * Wires the local-first pipeline to commands: analyze, snapshot and diff are
6
+ * functional; config remains a stub (handled by `.contextcheck.json`).
7
+ */
8
+ import { Command } from "commander";
9
+ import { version } from "../index.js";
10
+ import { loadConfig } from "../config/load.js";
11
+ import { runAnalyze } from "../analyzer/run.js";
12
+ import { formatTokens, renderCompactReport, renderDiff, renderReport, } from "../output/terminal.js";
13
+ import { serializeDiff, serializeReport } from "../output/json.js";
14
+ import { isValidFailThreshold, shouldFailOnSeverity, } from "../analyzer/severity.js";
15
+ import { buildSnapshot, latestSnapshotFile, listSnapshots, loadSnapshotFile, resolveSnapshotRef, saveSnapshot, } from "../snapshot/manager.js";
16
+ import { diffBetweenSnapshots } from "../snapshot/diff.js";
17
+ /** Placeholder for not-yet-implemented commands. */
18
+ function placeholder(commandName) {
19
+ // eslint-disable-next-line no-console
20
+ console.log(`[contextcheck] '${commandName}' command is not implemented yet.`);
21
+ }
22
+ export async function analyzeAction(opts) {
23
+ const rootPath = process.cwd();
24
+ const options = await loadConfig(rootPath);
25
+ const { report } = await runAnalyze({ rootPath, options });
26
+ if (opts.json) {
27
+ // Privacy-safe DTO: raw configuration content is never serialized (Rule 23).
28
+ process.stdout.write(`${serializeReport(report)}\n`);
29
+ }
30
+ else if (opts.compact) {
31
+ process.stdout.write(`${renderCompactReport(report)}\n`);
32
+ }
33
+ else {
34
+ process.stdout.write(`${renderReport(report, opts.verbose === true)}\n`);
35
+ }
36
+ // Exit-code policy: informational by default; only `--fail-on` fails CI.
37
+ const failOn = normalizeFailThreshold(opts.failOn);
38
+ if (failOn && shouldFailOnSeverity(report.findings, failOn)) {
39
+ process.exitCode = 1;
40
+ }
41
+ }
42
+ /** Parses `--fail-on` into a validated threshold, or undefined when absent. */
43
+ function normalizeFailThreshold(value) {
44
+ if (!value)
45
+ return undefined;
46
+ if (isValidFailThreshold(value))
47
+ return value;
48
+ // eslint-disable-next-line no-console
49
+ console.error(`[contextcheck] Invalid --fail-on value "${value}". ` +
50
+ `Use one of: info, notice, warning. Defaulting to informational.`);
51
+ return undefined;
52
+ }
53
+ /** `contextcheck snapshot` — records current AI configuration + findings. */
54
+ export async function snapshotAction() {
55
+ const rootPath = process.cwd();
56
+ const options = await loadConfig(rootPath);
57
+ // Capture analysis findings so a snapshot reflects the full context state.
58
+ const { report } = await runAnalyze({ rootPath, options });
59
+ const snapshot = buildSnapshot(report.artifacts, report.findings);
60
+ const file = await saveSnapshot(rootPath, snapshot);
61
+ // eslint-disable-next-line no-console
62
+ console.log(`Snapshot saved: ${snapshot.id} (${snapshot.configurationFiles} files, ` +
63
+ `~${snapshot.estimatedTokens} tokens, ${report.findings.length} findings)`);
64
+ void file;
65
+ }
66
+ /** `contextcheck diff [snapshot-id]` — compares a snapshot vs current state. */
67
+ export async function diffAction(from, opts = {}) {
68
+ const rootPath = process.cwd();
69
+ const options = await loadConfig(rootPath);
70
+ const { report } = await runAnalyze({ rootPath, options });
71
+ const currentSnapshot = buildSnapshot(report.artifacts, report.findings);
72
+ let before;
73
+ if (from) {
74
+ const resolved = await resolveSnapshotRef(rootPath, from);
75
+ if (!resolved) {
76
+ // eslint-disable-next-line no-console
77
+ console.error(`[contextcheck] No snapshot found for "${from}".`);
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+ before = await loadSnapshotFile(resolved);
82
+ }
83
+ else {
84
+ const latest = await latestSnapshotFile(rootPath);
85
+ if (!latest) {
86
+ // eslint-disable-next-line no-console
87
+ console.log("No snapshot to diff against. Run `contextcheck snapshot` first.");
88
+ return;
89
+ }
90
+ before = await loadSnapshotFile(latest);
91
+ }
92
+ const diff = diffBetweenSnapshots(before, currentSnapshot);
93
+ if (opts.json) {
94
+ process.stdout.write(`${serializeDiff(diff, before)}\n`);
95
+ return;
96
+ }
97
+ process.stdout.write(`${renderDiff(diff)}\n`);
98
+ }
99
+ /** `contextcheck snapshot list` — lists stored snapshots. */
100
+ export async function snapshotListAction() {
101
+ const rootPath = process.cwd();
102
+ const snaps = await listSnapshots(rootPath);
103
+ if (snaps.length === 0) {
104
+ // eslint-disable-next-line no-console
105
+ console.log("No snapshots yet. Run `contextcheck snapshot` first.");
106
+ return;
107
+ }
108
+ const short = (s) => s.id.split("_")[1] ?? s.id;
109
+ const dateFmt = (iso) => iso.replace("T", " ").replace(/\..*/, "");
110
+ const lines = [];
111
+ lines.push("ContextCheck Snapshots");
112
+ lines.push("");
113
+ lines.push("ID Created Files Tokens Findings");
114
+ for (const s of snaps) {
115
+ lines.push(`${short(s).padEnd(9)}${dateFmt(s.createdAt).padEnd(25)}${String(s.configurationFiles).padEnd(7)}` +
116
+ `${formatTokens(s.estimatedTokens).padEnd(8)}${s.findings?.length ?? 0}`);
117
+ }
118
+ // eslint-disable-next-line no-console
119
+ console.log(lines.join("\n"));
120
+ }
121
+ function buildProgram() {
122
+ const program = new Command();
123
+ program
124
+ .name("context-check")
125
+ .description("AI coding configuration intelligence layer")
126
+ .version(version);
127
+ program
128
+ .command("analyze")
129
+ .description("Discover and analyze AI coding configuration files")
130
+ .option("--verbose", "show detailed findings")
131
+ .option("--json", "output machine-readable JSON")
132
+ .option("--compact", "compact human-readable output")
133
+ .option("--fail-on <severity>", "fail with exit 1 on finding severity (info|notice|warning)")
134
+ .action(async (opts) => analyzeAction(opts));
135
+ const snapshotCommand = program
136
+ .command("snapshot")
137
+ .description("Create or inspect AI configuration snapshots");
138
+ snapshotCommand
139
+ .command("list")
140
+ .description("List stored snapshots")
141
+ .action(() => snapshotListAction());
142
+ snapshotCommand.action(() => snapshotAction());
143
+ program
144
+ .command("diff")
145
+ .description("Show AI configuration changes between a snapshot and current state")
146
+ .argument("[from]", "snapshot id to diff against (default: latest)")
147
+ .option("--json", "output privacy-safe JSON diff")
148
+ .action((from, opts) => diffAction(from, opts));
149
+ program
150
+ .command("config")
151
+ .description("View or modify contextcheck configuration")
152
+ .action(() => placeholder("config"));
153
+ return program;
154
+ }
155
+ export const program = buildProgram();
156
+ if (process.argv[1] && process.argv[1].endsWith("index.js")) {
157
+ program.parse(process.argv);
158
+ }
159
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * `.contextcheck.json` config loading (Spec §52).
3
+ *
4
+ * Optional. Defaults must work without a config file. Only supported
5
+ * `analysis` keys are honored; unknown keys are ignored so an older/newer
6
+ * config never breaks the CLI.
7
+ */
8
+ import { type AnalysisOptions } from "../analyzer/types.js";
9
+ export declare const CONFIG_FILENAME = ".contextcheck.json";
10
+ /** Reads and merges `.contextcheck.json` from a repo root. Never throws. */
11
+ export declare function loadConfig(rootPath: string): Promise<AnalysisOptions>;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * `.contextcheck.json` config loading (Spec §52).
3
+ *
4
+ * Optional. Defaults must work without a config file. Only supported
5
+ * `analysis` keys are honored; unknown keys are ignored so an older/newer
6
+ * config never breaks the CLI.
7
+ */
8
+ import { readFile } from "node:fs/promises";
9
+ import { join } from "node:path";
10
+ import { DEFAULT_ANALYSIS_OPTIONS, } from "../analyzer/types.js";
11
+ export const CONFIG_FILENAME = ".contextcheck.json";
12
+ /** Reads and merges `.contextcheck.json` from a repo root. Never throws. */
13
+ export async function loadConfig(rootPath) {
14
+ const result = { ...DEFAULT_ANALYSIS_OPTIONS };
15
+ let raw;
16
+ try {
17
+ const text = await readFile(join(rootPath, CONFIG_FILENAME), "utf8");
18
+ raw = JSON.parse(text);
19
+ }
20
+ catch {
21
+ // Missing or malformed config -> use defaults (Spec §52).
22
+ return result;
23
+ }
24
+ const a = raw?.analysis;
25
+ if (a && typeof a === "object") {
26
+ if (isPositiveNumber(a.largeFileTokens))
27
+ result.largeFileTokens = a.largeFileTokens;
28
+ if (isPositiveNumber(a.warningFileTokens))
29
+ result.warningFileTokens = a.warningFileTokens;
30
+ if (isPositiveNumber(a.gitWindowDays))
31
+ result.gitWindowDays = a.gitWindowDays;
32
+ }
33
+ return result;
34
+ }
35
+ function isPositiveNumber(value) {
36
+ return typeof value === "number" && Number.isFinite(value) && value > 0;
37
+ }
38
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EACL,wBAAwB,GAEzB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,CAAC,MAAM,eAAe,GAAG,oBAAoB,CAAC;AAUpD,4EAA4E;AAC5E,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAAgB;IAC/C,MAAM,MAAM,GAAoB,EAAE,GAAG,wBAAwB,EAAE,CAAC;IAEhE,IAAI,GAA0B,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,eAAe,CAAC,EAAE,MAAM,CAAC,CAAC;QACrE,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAc,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,0DAA0D;QAC1D,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,GAAG,GAAG,EAAE,QAAQ,CAAC;IACxB,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,IAAI,gBAAgB,CAAC,CAAC,CAAC,eAAe,CAAC;YACrC,MAAM,CAAC,eAAe,GAAG,CAAC,CAAC,eAAe,CAAC;QAC7C,IAAI,gBAAgB,CAAC,CAAC,CAAC,iBAAiB,CAAC;YACvC,MAAM,CAAC,iBAAiB,GAAG,CAAC,CAAC,iBAAiB,CAAC;QACjD,IAAI,gBAAgB,CAAC,CAAC,CAAC,aAAa,CAAC;YACnC,MAAM,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,CAAC;IAC3C,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC;AAC1E,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * AGENTS adapter (Spec §14, §50).
3
+ *
4
+ * Owns `AGENTS.md` files — shared per-project agent instructions used by many
5
+ * AI coding tools.
6
+ */
7
+ import type { ConfigurationAdapter } from "./types.js";
8
+ export declare const agentsAdapter: ConfigurationAdapter;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * AGENTS adapter (Spec §14, §50).
3
+ *
4
+ * Owns `AGENTS.md` files — shared per-project agent instructions used by many
5
+ * AI coding tools.
6
+ */
7
+ import { readTextFile } from "../scanner.js";
8
+ import { buildArtifact } from "./artifact.js";
9
+ function isAgentsInstruction(path) {
10
+ return path === "AGENTS.md" || path.endsWith("/AGENTS.md");
11
+ }
12
+ export const agentsAdapter = {
13
+ name: "agents",
14
+ matches: isAgentsInstruction,
15
+ async parse(filePath, rootPath) {
16
+ const content = await readTextFile(filePath);
17
+ return buildArtifact({
18
+ type: "instruction",
19
+ absolutePath: filePath,
20
+ rootPath,
21
+ content,
22
+ });
23
+ },
24
+ };
25
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/discovery/adapters/agents.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAyB;IACjD,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,mBAAmB;IAC5B,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ;QAC5B,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC7C,OAAO,aAAa,CAAC;YACnB,IAAI,EAAE,aAAa;YACnB,YAAY,EAAE,QAAQ;YACtB,QAAQ;YACR,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Shared artifact builder used by all adapters (Spec §12, §16).
3
+ *
4
+ * Keeps id generation, relative-path computation and metadata parsing DRY so
5
+ * each adapter only concerns itself with what makes its format unique.
6
+ */
7
+ import type { ConfigurationArtifact, ConfigurationScope, ConfigurationType } from "../../types/configuration.js";
8
+ /** Re-exported for backward-compat; single source of truth is the estimator. */
9
+ export { estimateTokens } from "../../tokens/estimator.js";
10
+ /** Computes a deterministic artifact id from its path. */
11
+ export declare function artifactId(path: string): string;
12
+ export declare function toRelativePath(rootPath: string, absolutePath: string): string;
13
+ export interface BuildArtifactOptions {
14
+ type: ConfigurationType;
15
+ absolutePath: string;
16
+ rootPath: string;
17
+ content: string;
18
+ /** Override scope; when omitted it is derived from the content's frontmatter. */
19
+ scope?: ConfigurationScope;
20
+ }
21
+ export declare function buildArtifact(opts: BuildArtifactOptions): ConfigurationArtifact;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Shared artifact builder used by all adapters (Spec §12, §16).
3
+ *
4
+ * Keeps id generation, relative-path computation and metadata parsing DRY so
5
+ * each adapter only concerns itself with what makes its format unique.
6
+ */
7
+ import { relative, sep } from "node:path";
8
+ import { createHash } from "node:crypto";
9
+ import { parseConfiguration } from "../../parser/parse.js";
10
+ import { estimateTokens } from "../../tokens/estimator.js";
11
+ import { countLines } from "../scanner.js";
12
+ /** Re-exported for backward-compat; single source of truth is the estimator. */
13
+ export { estimateTokens } from "../../tokens/estimator.js";
14
+ /** Computes a deterministic artifact id from its path. */
15
+ export function artifactId(path) {
16
+ return `artifact_${createHash("sha1").update(path).digest("hex").slice(0, 8)}`;
17
+ }
18
+ export function toRelativePath(rootPath, absolutePath) {
19
+ return relative(rootPath, absolutePath).split(sep).join("/");
20
+ }
21
+ export function buildArtifact(opts) {
22
+ const { type, absolutePath, rootPath, content, scope } = opts;
23
+ const path = toRelativePath(rootPath, absolutePath);
24
+ const lineCount = countLines(content);
25
+ // Default scope is derived from the file's own frontmatter (Spec §16/§17).
26
+ const resolvedScope = scope ?? parseConfiguration(content).scope;
27
+ return {
28
+ id: artifactId(path),
29
+ type,
30
+ path,
31
+ content,
32
+ scope: resolvedScope,
33
+ metadata: {
34
+ sizeBytes: Buffer.byteLength(content, "utf8"),
35
+ estimatedTokens: estimateTokens(content),
36
+ lineCount,
37
+ },
38
+ };
39
+ }
40
+ //# sourceMappingURL=artifact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact.js","sourceRoot":"","sources":["../../../src/discovery/adapters/artifact.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAO3C,gFAAgF;AAChF,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,0DAA0D;AAC1D,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,YAAY,UAAU,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,YAAoB;IACnE,OAAO,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/D,CAAC;AAWD,MAAM,UAAU,aAAa,CAC3B,IAA0B;IAE1B,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC;IAE9D,MAAM,IAAI,GAAG,cAAc,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;IACpD,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IACtC,2EAA2E;IAC3E,MAAM,aAAa,GAAG,KAAK,IAAI,kBAAkB,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC;IAEjE,OAAO;QACL,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC;QACpB,IAAI;QACJ,IAAI;QACJ,OAAO;QACP,KAAK,EAAE,aAAa;QACpB,QAAQ,EAAE;YACR,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC;YAC7C,eAAe,EAAE,cAAc,CAAC,OAAO,CAAC;YACxC,SAAS;SACV;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Claude adapter (Spec §14, §50).
3
+ *
4
+ * Owns `CLAUDE.md` files. Claude instructions are markdown; the parsing of
5
+ * markdown structure (headings, frontmatter) happens in the parser phase.
6
+ */
7
+ import type { ConfigurationAdapter } from "./types.js";
8
+ export declare const claudeAdapter: ConfigurationAdapter;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Claude adapter (Spec §14, §50).
3
+ *
4
+ * Owns `CLAUDE.md` files. Claude instructions are markdown; the parsing of
5
+ * markdown structure (headings, frontmatter) happens in the parser phase.
6
+ */
7
+ import { readTextFile } from "../scanner.js";
8
+ import { buildArtifact } from "./artifact.js";
9
+ function isClaudeInstruction(path) {
10
+ return path === "CLAUDE.md" || path.endsWith("/CLAUDE.md");
11
+ }
12
+ export const claudeAdapter = {
13
+ name: "claude",
14
+ matches: isClaudeInstruction,
15
+ async parse(filePath, rootPath) {
16
+ const content = await readTextFile(filePath);
17
+ return buildArtifact({
18
+ type: "instruction",
19
+ absolutePath: filePath,
20
+ rootPath,
21
+ content,
22
+ });
23
+ },
24
+ };
25
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../../src/discovery/adapters/claude.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC;AAC7D,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAyB;IACjD,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,mBAAmB;IAC5B,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ;QAC5B,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC7C,OAAO,aAAa,CAAC;YACnB,IAAI,EAAE,aAAa;YACnB,YAAY,EAAE,QAAQ;YACtB,QAAQ;YACR,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Cursor adapter (Spec §14, §50).
3
+ *
4
+ * Owns two Cursor formats:
5
+ * - `.cursorrules` (root-level plain text rule file)
6
+ * - `.cursor/rules/**` (rule files, typically `.mdc` or `.md`)
7
+ *
8
+ * Both are classified as `rule`.
9
+ */
10
+ import type { ConfigurationAdapter } from "./types.js";
11
+ export declare const cursorAdapter: ConfigurationAdapter;
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Cursor adapter (Spec §14, §50).
3
+ *
4
+ * Owns two Cursor formats:
5
+ * - `.cursorrules` (root-level plain text rule file)
6
+ * - `.cursor/rules/**` (rule files, typically `.mdc` or `.md`)
7
+ *
8
+ * Both are classified as `rule`.
9
+ */
10
+ import { readTextFile } from "../scanner.js";
11
+ import { buildArtifact } from "./artifact.js";
12
+ function isCursorRule(path) {
13
+ if (path === ".cursorrules")
14
+ return true;
15
+ if (path.startsWith(".cursor/rules/"))
16
+ return true;
17
+ return false;
18
+ }
19
+ export const cursorAdapter = {
20
+ name: "cursor",
21
+ matches: isCursorRule,
22
+ async parse(filePath, rootPath) {
23
+ const content = await readTextFile(filePath);
24
+ return buildArtifact({
25
+ type: "rule",
26
+ absolutePath: filePath,
27
+ rootPath,
28
+ content,
29
+ });
30
+ },
31
+ };
32
+ //# sourceMappingURL=cursor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor.js","sourceRoot":"","sources":["../../../src/discovery/adapters/cursor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,SAAS,YAAY,CAAC,IAAY;IAChC,IAAI,IAAI,KAAK,cAAc;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAyB;IACjD,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,YAAY;IACrB,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ;QAC5B,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC7C,OAAO,aAAa,CAAC;YACnB,IAAI,EAAE,MAAM;YACZ,YAAY,EAAE,QAAQ;YACtB,QAAQ;YACR,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Registers every supported adapter (Spec §14, §49).
3
+ *
4
+ * The discovery engine iterates this list in order. The first adapter whose
5
+ * `matches` returns true owns the file.
6
+ */
7
+ import type { ConfigurationAdapter } from "./types.js";
8
+ export declare const adapters: readonly ConfigurationAdapter[];
9
+ export type { ConfigurationAdapter } from "./types.js";
10
+ export { artifactId, buildArtifact, estimateTokens, toRelativePath, } from "./artifact.js";
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Registers every supported adapter (Spec §14, §49).
3
+ *
4
+ * The discovery engine iterates this list in order. The first adapter whose
5
+ * `matches` returns true owns the file.
6
+ */
7
+ import { agentsAdapter } from "./agents.js";
8
+ import { claudeAdapter } from "./claude.js";
9
+ import { cursorAdapter } from "./cursor.js";
10
+ import { skillAdapter } from "./skill.js";
11
+ export const adapters = [
12
+ claudeAdapter,
13
+ agentsAdapter,
14
+ skillAdapter,
15
+ cursorAdapter,
16
+ ];
17
+ export { artifactId, buildArtifact, estimateTokens, toRelativePath, } from "./artifact.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/discovery/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C,MAAM,CAAC,MAAM,QAAQ,GAAoC;IACvD,aAAa;IACb,aAAa;IACb,YAAY;IACZ,aAAa;CACd,CAAC;AAGF,OAAO,EACL,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,GACf,MAAM,eAAe,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Skill adapter (Spec §14, §50).
3
+ *
4
+ * Owns any `SKILL.md` file. Skills can live at any depth (a skill is a
5
+ * directory containing `SKILL.md`), so we match the basename anywhere in the
6
+ * tree minus excluded directories.
7
+ */
8
+ import type { ConfigurationAdapter } from "./types.js";
9
+ export declare const skillAdapter: ConfigurationAdapter;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Skill adapter (Spec §14, §50).
3
+ *
4
+ * Owns any `SKILL.md` file. Skills can live at any depth (a skill is a
5
+ * directory containing `SKILL.md`), so we match the basename anywhere in the
6
+ * tree minus excluded directories.
7
+ */
8
+ import { readTextFile } from "../scanner.js";
9
+ import { buildArtifact } from "./artifact.js";
10
+ function isSkillFile(path) {
11
+ return path === "SKILL.md" || path.endsWith("/SKILL.md");
12
+ }
13
+ export const skillAdapter = {
14
+ name: "skill",
15
+ matches: isSkillFile,
16
+ async parse(filePath, rootPath) {
17
+ const content = await readTextFile(filePath);
18
+ return buildArtifact({
19
+ type: "skill",
20
+ absolutePath: filePath,
21
+ rootPath,
22
+ content,
23
+ });
24
+ },
25
+ };
26
+ //# sourceMappingURL=skill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill.js","sourceRoot":"","sources":["../../../src/discovery/adapters/skill.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAG9C,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,IAAI,KAAK,UAAU,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAyB;IAChD,IAAI,EAAE,OAAO;IACb,OAAO,EAAE,WAAW;IACpB,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ;QAC5B,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,QAAQ,CAAC,CAAC;QAC7C,OAAO,aAAa,CAAC;YACnB,IAAI,EAAE,OAAO;YACb,YAAY,EAAE,QAAQ;YACtB,QAAQ;YACR,OAAO;SACR,CAAC,CAAC;IACL,CAAC;CACF,CAAC"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Adapter port (Spec §50).
3
+ *
4
+ * Platform-specific behavior — which files each tool uses and how they are
5
+ * parsed — lives inside an adapter (Rule 14). The discovery engine and
6
+ * analyzer never hard-code tool-specific logic.
7
+ */
8
+ import type { ConfigurationArtifact } from "../../types/configuration.js";
9
+ export interface ConfigurationAdapter {
10
+ /** Stable identifier, e.g. "claude". */
11
+ name: string;
12
+ /**
13
+ * Returns true if this adapter owns the given file path (relative to the
14
+ * repository root).
15
+ */
16
+ matches(relativePath: string): boolean;
17
+ /**
18
+ * Parses a discovered file into a normalized artifact. Must not depend on
19
+ * any discovery state; safe to call for any file it owns.
20
+ */
21
+ parse(filePath: string, rootPath: string): Promise<ConfigurationArtifact>;
22
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Adapter port (Spec §50).
3
+ *
4
+ * Platform-specific behavior — which files each tool uses and how they are
5
+ * parsed — lives inside an adapter (Rule 14). The discovery engine and
6
+ * analyzer never hard-code tool-specific logic.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/discovery/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Discovery engine (Spec §14, §49).
3
+ *
4
+ * Combines the filesystem scanner with every registered adapter to produce a
5
+ * normalized list of configuration artifacts for a repository root.
6
+ *
7
+ * Pipeline:
8
+ * walk files (skipping excluded dirs)
9
+ * -> first matching adapter owns the file
10
+ * -> parse into a ConfigurationArtifact
11
+ */
12
+ import type { ConfigurationAdapter } from "./adapters/types.js";
13
+ import { type DiscoveredFile } from "./scanner.js";
14
+ import type { ConfigurationArtifact } from "../types/configuration.js";
15
+ export interface DiscoveryResult {
16
+ artifacts: ConfigurationArtifact[];
17
+ /** Paths recognized as configuration but not parsed for any reason. */
18
+ skipped: string[];
19
+ /** Files whose ownership could not be determined. */
20
+ unowned: string[];
21
+ }
22
+ /** Returns the first adapter that claims `path`, or undefined. */
23
+ export declare function adapterFor(path: string): ConfigurationAdapter | undefined;
24
+ /**
25
+ * Discovers all AI configuration artifacts under `rootPath`.
26
+ *
27
+ * A single file failing to parse must not fail the entire discovery
28
+ * (Spec §34); such files are collected in `skipped` and analysis continues.
29
+ */
30
+ export declare function discover(rootPath: string): Promise<DiscoveryResult>;
31
+ /** Discover from an explicit list of files (used by integration tests). */
32
+ export declare function discoverFromFiles(files: DiscoveredFile[], rootPath: string): Promise<DiscoveryResult>;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Discovery engine (Spec §14, §49).
3
+ *
4
+ * Combines the filesystem scanner with every registered adapter to produce a
5
+ * normalized list of configuration artifacts for a repository root.
6
+ *
7
+ * Pipeline:
8
+ * walk files (skipping excluded dirs)
9
+ * -> first matching adapter owns the file
10
+ * -> parse into a ConfigurationArtifact
11
+ */
12
+ import { adapters } from "./adapters/index.js";
13
+ import { walkFiles } from "./scanner.js";
14
+ /** Returns the first adapter that claims `path`, or undefined. */
15
+ export function adapterFor(path) {
16
+ return adapters.find((adapter) => adapter.matches(path));
17
+ }
18
+ /**
19
+ * Discovers all AI configuration artifacts under `rootPath`.
20
+ *
21
+ * A single file failing to parse must not fail the entire discovery
22
+ * (Spec §34); such files are collected in `skipped` and analysis continues.
23
+ */
24
+ export async function discover(rootPath) {
25
+ const files = await walkFiles(rootPath);
26
+ return discoverFromFiles(files, rootPath);
27
+ }
28
+ /** Discover from an explicit list of files (used by integration tests). */
29
+ export async function discoverFromFiles(files, rootPath) {
30
+ const artifacts = [];
31
+ const skipped = [];
32
+ const unowned = [];
33
+ for (const file of files) {
34
+ const adapter = adapterFor(file.relativePath);
35
+ if (!adapter) {
36
+ unowned.push(file.relativePath);
37
+ continue;
38
+ }
39
+ try {
40
+ const artifact = await adapter.parse(file.absolutePath, rootPath);
41
+ artifacts.push(artifact);
42
+ }
43
+ catch (err) {
44
+ skipped.push(file.relativePath);
45
+ // eslint-disable-next-line no-console
46
+ console.error(`[contextcheck] Could not parse configuration: ${file.relativePath}`, err instanceof Error ? err.message : String(err));
47
+ }
48
+ }
49
+ return { artifacts, skipped, unowned };
50
+ }
51
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../src/discovery/discover.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAE/C,OAAO,EAAE,SAAS,EAAuB,MAAM,cAAc,CAAC;AAW9D,kEAAkE;AAClE,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAAgB;IAC7C,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;IACxC,OAAO,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAED,2EAA2E;AAC3E,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,KAAuB,EACvB,QAAgB;IAEhB,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC9C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAChC,SAAS;QACX,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;YAClE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAChC,sCAAsC;YACtC,OAAO,CAAC,KAAK,CACX,iDAAiD,IAAI,CAAC,YAAY,EAAE,EACpE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACjD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AACzC,CAAC"}