@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
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 contextcheck
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # contextcheck
2
+
3
+ > **See what your AI coding context contains, what changed, and what deserves review.**
4
+
5
+ > **Beta:** `contextcheck` şu anda beta kanalında yayınlanıyor. Kullanım:
6
+ > `npm install -g context-check@beta` veya `npx context-check@beta analyze`.
7
+
8
+ contextcheck, AI coding agent'ların kullandığı instructions, rules ve skills
9
+ dosyalarını (CLAUDE.md, AGENTS.md, .cursor/rules, SKILL.md) keşfeden,
10
+ deterministic olarak analiz eden ve context layer'ın zaman içindeki değişimini
11
+ takip etmeni sağlayan **local-first** bir developer tooludur.
12
+
13
+ - Local-first: içerik makineden çıkmaz
14
+ - Deterministic: LLM/embedding/API/DB yok
15
+ - Açıklanabilir: her finding ne/neden/hangi dosya açıklamalı
16
+ - Review, never remove: otomatik silme/düzeltme yok
17
+
18
+ ## Hızlı Başlangıç (ilk 30 saniye)
19
+
20
+ ```bash
21
+ # 1) Mevcut AI context'ini gör
22
+ npx context-check@beta analyze
23
+
24
+ # 2) Bir anlık görüntü al
25
+ npx context-check@beta snapshot
26
+
27
+ # 3) Kurallarında değişiklik yap, ne değiştiğini gör
28
+ npx context-check@beta diff
29
+ ```
30
+
31
+ Bunların hepsi hesap gerektirmez, hiçbir içerik cihazından çıkmaz.
32
+
33
+ Global kurulum tercih edersen:
34
+
35
+ ```bash
36
+ npm install -g context-check@beta
37
+ context-check analyze
38
+ ```
39
+
40
+ ## Kullanım
41
+
42
+ ```bash
43
+ # Tüm AI configuration dosyalarını keşfet + analiz et
44
+ context-check analyze
45
+
46
+ # Detaylı bulgular
47
+ context-check analyze --verbose
48
+
49
+ # Hızlı insan çıktısı (summary + findings)
50
+ context-check analyze --compact
51
+
52
+ # Makine tarafından okunabilir, privacy-safe JSON çıktısı
53
+ context-check analyze --json
54
+
55
+ # CI'da findings eşik üstüyse başarısız ol
56
+ context-check analyze --json --fail-on notice
57
+ ```
58
+
59
+ Üç çıktı kontratı:
60
+
61
+ ```text
62
+ context-check analyze -> detaylı, varsayılan (spec §9)
63
+ context-check analyze --compact -> hızlı insan çıktısı
64
+ context-check analyze --json -> CI / automation (privacy-safe)
65
+ ```
66
+
67
+ ## Komutlar
68
+
69
+ - `context-check analyze` — keşfet ve analiz et
70
+ - `context-check analyze --verbose` — detaylı bulgular
71
+ - `context-check analyze --json` — privacy-safe JSON (raw content yok)
72
+ - `context-check analyze --compact` — hızlı/kompakt insan çıktısı
73
+ - `context-check analyze --fail-on <info|notice|warning>` — eşik üstü finding'de exit 1
74
+ - `context-check snapshot` — AI configuration snapshot oluştur
75
+ - `context-check snapshot list` — kayıtlı snapshot'ları listele
76
+ - `context-check diff` — en son snapshot ile mevcut durumu karşılaştır (artifact + token + finding değişimleri)
77
+ - `context-check diff <snapshot-id>` — belirtilen snapshot ile mevcut durumu karşılaştır
78
+ - `context-check diff --json` — privacy-safe JSON diff
79
+ - `context-check config` — yapılandırma (`.contextcheck.json`)
80
+
81
+ ## Exit code politkası
82
+
83
+ Varsayılan (informational): findings CI'ı kırmaz — `no findings`, `info` ve
84
+ `notice` hepsi `exit 0`. `--fail-on` belirtilirse eşik (veya üstü) seviyesinde
85
+ finding varsa `exit 1`:
86
+
87
+ ```bash
88
+ # notice (REVIEW/CAUTION) findings → exit 1; sadece info → exit 0
89
+ context-check analyze --fail-on notice
90
+ ```
91
+
92
+ `--fail-on` değeri finding **severity** kullanır (info < notice < warning).
93
+ Label→severity: INFO/CONTEXT → info, REVIEW/CAUTION → notice.
94
+
95
+ ## Diff (snapshot → current)
96
+
97
+ `context-check diff`, context layer'ın zaman içindeki değişimini gösterir:
98
+ artifact (eklenen/silinmiş/değişen dosyalar), toplam context token değişimi ve
99
+ **analiz bulgularının değişimi** (yeni/çözülen/değişen finding):
100
+
101
+ ```text
102
+ ContextCheck Diff
103
+
104
+ Snapshot: previous → current
105
+
106
+ Artifacts
107
+ ~ CLAUDE.md
108
+ 59 → 70 tokens
109
+
110
+ Context
111
+ Previous ~235 tokens
112
+ Current ~246 tokens
113
+ Change +11 tokens
114
+
115
+ Findings
116
+ + 1 new
117
+ = 1 unchanged
118
+
119
+ Summary
120
+ 0 added · 1 modified · 0 removed
121
+ ```
122
+
123
+ Bu, "context layer değişti ve bunun sonucunda hangi bulgular ortaya
124
+ çıktı/kayboldu?" sorusunu cevaplar — model performansıyla ilgili kausal iddia
125
+ **değildir** (Spec §28).
126
+
127
+ ## Snapshot list ve seçimi (v2)
128
+
129
+ `context-check snapshot list` kayıtlı snapshot'ları gösterir:
130
+
131
+ ```text
132
+ ContextCheck Snapshots
133
+
134
+ ID Created Files Tokens Findings
135
+ 7ebv3k 2026-09-09 00:14:22 12 4,820 3
136
+ 43d791 2026-09-08 12:03:44 10 3,980 1
137
+ ```
138
+
139
+ Belirli bir snapshot'a karşı diff:
140
+
141
+ ```bash
142
+ context-check diff 7ebv3k
143
+ ```
144
+
145
+ `diff --json` CI/automation için privacy-safe JSON üretir (artifact token
146
+ delta'ları, finding değişimleri, snapshot metadata — **asla raw content yok**).
147
+
148
+ ## GitHub Actions (CI)
149
+
150
+ ```yaml
151
+ name: ContextCheck
152
+
153
+ on:
154
+ pull_request:
155
+ push:
156
+
157
+ jobs:
158
+ contextcheck:
159
+ runs-on: ubuntu-latest
160
+ steps:
161
+ - uses: actions/checkout@v4
162
+ with:
163
+ fetch-depth: 0 # scoped-no-match Git history için tam geçmiş
164
+ - run: npx context-check analyze --fail-on notice # CI gate
165
+ - run: npx context-check analyze --compact # PR log
166
+ ```
167
+
168
+ `fetch-depth: 0` önemli: shallow checkout'u ContextCheck tespit eder ve
169
+ `scoped-no-match`'i güvenli şekilde atlar (Rule 26).
170
+
171
+ İki kullanım modu:
172
+
173
+ ```text
174
+ Developer workflow analyze → snapshot → diff
175
+ CI workflow analyze --fail-on notice
176
+ ```
177
+
178
+ `--fail-on notice` REVIEW/CAUTION findings'de CI'ı kırar; yalnızca INFO
179
+ (duplicate/large-file) findings build'i kırmaz. Bu repo'da workflow
180
+ `.github/workflows/contextcheck.yml` mevcut ve paket yayınlanana kadar repo
181
+ içinden dogfooding modunda çalışır (yayın sonrası `npx`'e döner).
182
+
183
+ ## Geliştirme
184
+
185
+ ```bash
186
+ npm install
187
+ npm run build # tsc
188
+ npm test # vitest
189
+ npm run lint # eslint
190
+ ```
191
+
192
+ ## Lisans
193
+
194
+ MIT — bkz. [LICENSE](LICENSE).
195
+
196
+ ## Yayınlama (maintainer)
197
+
198
+ Beta kanalına yayın (kontrollü, mevcut `latest`'i korur):
199
+
200
+ ```bash
201
+ npm login
202
+ npm publish --tag beta
203
+ ```
204
+
205
+ Beta'yı test et:
206
+
207
+ ```bash
208
+ npm install -g context-check@beta
209
+ npx context-check@beta analyze
210
+ ```
211
+
212
+ Stabil sürüm hazır olduğunda `--tag latest` ile (veya `npm dist-tag add context-check@<version> latest`)
213
+ mevcut sürümü `latest` kanalına taşı.
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Analyzer engine (Spec §51).
3
+ *
4
+ * Runs each registered rule independently over the discovered artifacts and
5
+ * aggregates their findings into an `AnalysisReport`. Rules are isolation
6
+ * boundaries: a failure in one must not prevent the others from running
7
+ * (Spec §34), and presentation never affects analysis (Rule 15).
8
+ */
9
+ import type { ConfigurationArtifact } from "../types/configuration.js";
10
+ import type { Finding } from "../types/finding.js";
11
+ import type { AnalysisReport } from "../types/report.js";
12
+ import type { AnalysisContext, AnalyzerRule } from "./types.js";
13
+ export interface AnalyzeInput {
14
+ artifacts: ConfigurationArtifact[];
15
+ context: AnalysisContext;
16
+ /** Rules to run; defaults to the full registered set when omitted. */
17
+ rules?: AnalyzerRule[];
18
+ }
19
+ /** Rules enabled for the current MVP build (grown across sprints). */
20
+ export declare const DEFAULT_RULES: AnalyzerRule[];
21
+ /**
22
+ * Runs all rules and returns an aggregated report. Rule failures are caught
23
+ * and logged instead of failing the whole analysis.
24
+ */
25
+ export declare function analyze(input: AnalyzeInput): Promise<AnalysisReport>;
26
+ /** Builds the summary + report from artifacts and findings. */
27
+ export declare function aggregate(artifacts: ConfigurationArtifact[], findings: Finding[]): AnalysisReport;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Analyzer engine (Spec §51).
3
+ *
4
+ * Runs each registered rule independently over the discovered artifacts and
5
+ * aggregates their findings into an `AnalysisReport`. Rules are isolation
6
+ * boundaries: a failure in one must not prevent the others from running
7
+ * (Spec §34), and presentation never affects analysis (Rule 15).
8
+ */
9
+ import { buildContextOverheadFinding, estimateOverhead, } from "./rules/context-overhead.js";
10
+ import { duplicateRule } from "./rules/duplicate.js";
11
+ import { highStakesRule } from "./rules/high-stakes.js";
12
+ import { largeFileRule } from "./rules/large-file.js";
13
+ import { repetitionRule } from "./rules/repetition.js";
14
+ import { scopedNoMatchRule } from "./rules/scoped-no-match.js";
15
+ /** Rules enabled for the current MVP build (grown across sprints). */
16
+ export const DEFAULT_RULES = [
17
+ duplicateRule,
18
+ highStakesRule,
19
+ largeFileRule,
20
+ repetitionRule,
21
+ scopedNoMatchRule,
22
+ ];
23
+ /**
24
+ * Runs all rules and returns an aggregated report. Rule failures are caught
25
+ * and logged instead of failing the whole analysis.
26
+ */
27
+ export async function analyze(input) {
28
+ const { artifacts, context, rules } = input;
29
+ const ruleSet = rules ?? DEFAULT_RULES;
30
+ const findings = [];
31
+ for (const rule of ruleSet) {
32
+ try {
33
+ const result = await rule.run(artifacts, context);
34
+ findings.push(...(Array.isArray(result) ? result : []));
35
+ }
36
+ catch (err) {
37
+ // eslint-disable-next-line no-console
38
+ console.error(`[contextcheck] Analyzer rule '${rule.name}' failed:`, err instanceof Error ? err.message : String(err));
39
+ }
40
+ }
41
+ return aggregate(artifacts, findings);
42
+ }
43
+ /** Builds the summary + report from artifacts and findings. */
44
+ export function aggregate(artifacts, findings) {
45
+ const totalTokens = artifacts.reduce((sum, a) => sum + a.metadata.estimatedTokens, 0);
46
+ const skills = artifacts.filter((a) => a.type === "skill").length;
47
+ // Potential Context Overhead is derived from the other findings (Spec §22).
48
+ const contextOverhead = estimateOverhead(artifacts, findings);
49
+ const overheadFinding = buildContextOverheadFinding(contextOverhead, findings.flatMap((f) => f.filePaths));
50
+ const allFindings = overheadFinding
51
+ ? [...findings, overheadFinding]
52
+ : findings;
53
+ return {
54
+ summary: {
55
+ configurationFiles: artifacts.length,
56
+ skills,
57
+ estimatedTokens: totalTokens,
58
+ potentialContextOverhead: contextOverhead,
59
+ },
60
+ artifacts,
61
+ findings: allFindings,
62
+ };
63
+ }
64
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/analyzer/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,EACL,2BAA2B,EAC3B,gBAAgB,GACjB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAS/D,sEAAsE;AACtE,MAAM,CAAC,MAAM,aAAa,GAAmB;IAC3C,aAAa;IACb,cAAc;IACd,aAAa;IACb,cAAc;IACd,iBAAiB;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,KAAmB;IAC/C,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IAC5C,MAAM,OAAO,GAAG,KAAK,IAAI,aAAa,CAAC;IAEvC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;YAClD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC1D,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,sCAAsC;YACtC,OAAO,CAAC,KAAK,CACX,iCAAiC,IAAI,CAAC,IAAI,WAAW,EACrD,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CACjD,CAAC;QACJ,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,SAAS,CACvB,SAAkC,EAClC,QAAmB;IAEnB,MAAM,WAAW,GAAG,SAAS,CAAC,MAAM,CAClC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,eAAe,EAC5C,CAAC,CACF,CAAC;IACF,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,MAAM,CAAC;IAElE,4EAA4E;IAC5E,MAAM,eAAe,GAAG,gBAAgB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC9D,MAAM,eAAe,GAAG,2BAA2B,CACjD,eAAe,EACf,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CACrC,CAAC;IACF,MAAM,WAAW,GAAG,eAAe;QACjC,CAAC,CAAC,CAAC,GAAG,QAAQ,EAAE,eAAe,CAAC;QAChC,CAAC,CAAC,QAAQ,CAAC;IAEb,OAAO;QACL,OAAO,EAAE;YACP,kBAAkB,EAAE,SAAS,CAAC,MAAM;YACpC,MAAM;YACN,eAAe,EAAE,WAAW;YAC5B,wBAAwB,EAAE,eAAe;SAC1C;QACD,SAAS;QACT,QAAQ,EAAE,WAAW;KACtB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Context overhead aggregation (Spec §22).
3
+ *
4
+ * Potential Context Overhead is a deterministic estimate of tokens that may
5
+ * be redundant, computed from signals already detected by other rules
6
+ * (duplicate content, repeated sections/blocks). The MVP does NOT detect
7
+ * semantic redundancy, and we never use "wasted tokens" — only "Potential
8
+ * Context Overhead" (Spec §22).
9
+ */
10
+ import type { ConfigurationArtifact } from "../../types/configuration.js";
11
+ import type { Finding } from "../../types/finding.js";
12
+ /**
13
+ * Estimates redundant tokens from the duplicate/repetition findings. Uses
14
+ * only deterministic signals; bounds each category to avoid double counting.
15
+ */
16
+ export declare function estimateOverhead(artifacts: ConfigurationArtifact[], findings: Finding[]): number;
17
+ /**
18
+ * Builds a `context-overhead` finding when overhead is meaningful.
19
+ * Returns `null` when overhead is negligible (avoids noisy output).
20
+ */
21
+ export declare function buildContextOverheadFinding(overhead: number, sourcePaths: string[]): Finding | null;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Context overhead aggregation (Spec §22).
3
+ *
4
+ * Potential Context Overhead is a deterministic estimate of tokens that may
5
+ * be redundant, computed from signals already detected by other rules
6
+ * (duplicate content, repeated sections/blocks). The MVP does NOT detect
7
+ * semantic redundancy, and we never use "wasted tokens" — only "Potential
8
+ * Context Overhead" (Spec §22).
9
+ */
10
+ import { makeFinding } from "./mapping.js";
11
+ /**
12
+ * Estimates redundant tokens from the duplicate/repetition findings. Uses
13
+ * only deterministic signals; bounds each category to avoid double counting.
14
+ */
15
+ export function estimateOverhead(artifacts, findings) {
16
+ let overhead = 0;
17
+ // Duplicate groups: each extra copy beyond the first is redundant.
18
+ for (const f of findings) {
19
+ if (f.type !== "duplicate" || f.filePaths.length <= 1)
20
+ continue;
21
+ const group = artifacts.filter((a) => f.filePaths.includes(a.path));
22
+ const avg = group.length
23
+ ? Math.round(group.reduce((sum, a) => sum + a.metadata.estimatedTokens, 0) /
24
+ group.length)
25
+ : 0;
26
+ overhead += avg * (f.filePaths.length - 1);
27
+ }
28
+ // Repetitions: a bounded per-extra-occurrence contribution.
29
+ for (const f of findings) {
30
+ if (f.type !== "repetition")
31
+ continue;
32
+ overhead += Math.min(800, 200 * Math.max(0, f.filePaths.length));
33
+ }
34
+ return Math.round(overhead);
35
+ }
36
+ /**
37
+ * Builds a `context-overhead` finding when overhead is meaningful.
38
+ * Returns `null` when overhead is negligible (avoids noisy output).
39
+ */
40
+ export function buildContextOverheadFinding(overhead, sourcePaths) {
41
+ if (overhead <= 0)
42
+ return null;
43
+ return makeFinding({
44
+ type: "context-overhead",
45
+ filePaths: sourcePaths.length > 0 ? sourcePaths : ["."],
46
+ title: "Potential context overhead",
47
+ description: `Potential Context Overhead ~${overhead.toLocaleString("en-US")} tokens ` +
48
+ `based on duplicate content and repeated sections.`,
49
+ recommendation: `Review the flagged duplicates and repetitions; consolidating them may ` +
50
+ `reduce how much of the model context your configuration uses.`,
51
+ });
52
+ }
53
+ //# sourceMappingURL=context-overhead.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-overhead.js","sourceRoot":"","sources":["../../../src/analyzer/rules/context-overhead.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,SAAkC,EAClC,QAAmB;IAEnB,IAAI,QAAQ,GAAG,CAAC,CAAC;IAEjB,mEAAmE;IACnE,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC;YAAE,SAAS;QAChE,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACpE,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM;YACtB,CAAC,CAAC,IAAI,CAAC,KAAK,CACR,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,eAAe,EAAE,CAAC,CAAC;gBAC3D,KAAK,CAAC,MAAM,CACf;YACH,CAAC,CAAC,CAAC,CAAC;QACN,QAAQ,IAAI,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC7C,CAAC;IAED,4DAA4D;IAC5D,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY;YAAE,SAAS;QACtC,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAAgB,EAChB,WAAqB;IAErB,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAE/B,OAAO,WAAW,CAAC;QACjB,IAAI,EAAE,kBAAkB;QACxB,SAAS,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACvD,KAAK,EAAE,4BAA4B;QACnC,WAAW,EACT,+BAA+B,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,UAAU;YACzE,mDAAmD;QACrD,cAAc,EACZ,wEAAwE;YACxE,+DAA+D;KAClE,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Exact duplicate detection (Spec §19, Rule 22).
3
+ *
4
+ * Compares document BODIES only, after stripping YAML frontmatter and
5
+ * normalizing. Two files with identical bodies but different frontmatter
6
+ * (description/globs/alwaysApply/metadata) are still duplicate candidates.
7
+ *
8
+ * Cross-file duplicates produce ONE finding listing every file path (Rule 16,
9
+ * Spec §12). This is a high-confidence, deterministic detection.
10
+ */
11
+ import type { ConfigurationArtifact } from "../../types/configuration.js";
12
+ import type { AnalyzerRule } from "../types.js";
13
+ /** Normalized-body fingerprint (hash) for a single artifact. */
14
+ export declare function bodyFingerprint(artifact: ConfigurationArtifact): string;
15
+ export declare const duplicateRule: AnalyzerRule;
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Exact duplicate detection (Spec §19, Rule 22).
3
+ *
4
+ * Compares document BODIES only, after stripping YAML frontmatter and
5
+ * normalizing. Two files with identical bodies but different frontmatter
6
+ * (description/globs/alwaysApply/metadata) are still duplicate candidates.
7
+ *
8
+ * Cross-file duplicates produce ONE finding listing every file path (Rule 16,
9
+ * Spec §12). This is a high-confidence, deterministic detection.
10
+ */
11
+ import { createHash } from "node:crypto";
12
+ import { normalizeBody } from "../../parser/normalize.js";
13
+ import { makeFinding } from "./mapping.js";
14
+ /** Normalized-body fingerprint (hash) for a single artifact. */
15
+ export function bodyFingerprint(artifact) {
16
+ const normalized = normalizeBody(artifact.content);
17
+ return createHash("sha256").update(normalized).digest("hex");
18
+ }
19
+ export const duplicateRule = {
20
+ name: "duplicate",
21
+ run(artifacts) {
22
+ // Group artifacts by normalized-body fingerprint (bodies only).
23
+ const groups = new Map();
24
+ for (const artifact of artifacts) {
25
+ const fp = bodyFingerprint(artifact);
26
+ const existing = groups.get(fp);
27
+ if (existing) {
28
+ existing.push(artifact.path);
29
+ }
30
+ else {
31
+ groups.set(fp, [artifact.path]);
32
+ }
33
+ }
34
+ const findings = [];
35
+ for (const [, paths] of groups) {
36
+ if (paths.length < 2)
37
+ continue;
38
+ const sorted = [...paths].sort();
39
+ const sample = sorted.slice(0, 2).join(" and ");
40
+ findings.push(makeFinding({
41
+ type: "duplicate",
42
+ filePaths: sorted,
43
+ title: "Identical instructions in multiple files",
44
+ description: `Found ${paths.length} files with an identical instruction body ` +
45
+ `(frontmatter ignored): ${sample}.`,
46
+ recommendation: `Consider keeping a single source of truth and referencing it, ` +
47
+ `or removing the redundant copies after review.`,
48
+ }));
49
+ }
50
+ return findings;
51
+ },
52
+ };
53
+ //# sourceMappingURL=duplicate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"duplicate.js","sourceRoot":"","sources":["../../../src/analyzer/rules/duplicate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAG1D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,gEAAgE;AAChE,MAAM,UAAU,eAAe,CAAC,QAA+B;IAC7D,MAAM,UAAU,GAAG,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAiB;IACzC,IAAI,EAAE,WAAW;IACjB,GAAG,CAAC,SAAS;QACX,gEAAgE;QAChE,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAC;QAE3C,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,MAAM,EAAE,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;YACrC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAChC,IAAI,QAAQ,EAAE,CAAC;gBACb,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC/B,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YAClC,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,EAAE,CAAC;QAEpB,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;YAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS;YAE/B,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAChD,QAAQ,CAAC,IAAI,CACX,WAAW,CAAC;gBACV,IAAI,EAAE,WAAW;gBACjB,SAAS,EAAE,MAAM;gBACjB,KAAK,EAAE,0CAA0C;gBACjD,WAAW,EACT,SAAS,KAAK,CAAC,MAAM,4CAA4C;oBACjE,0BAA0B,MAAM,GAAG;gBACrC,cAAc,EACZ,gEAAgE;oBAChE,gDAAgD;aACnD,CAAC,CACH,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * High-stakes detection (Spec §26, §27, Rule 20) — REVISED after real-world
3
+ * pilot, two-tier model.
4
+ *
5
+ * Tier 1 (STRONG): a single strong term in CONTENT alone justifies CAUTION
6
+ * e.g. secret, credential, password, authentication, authorization,
7
+ * permission, payment, private key, api key, access token.
8
+ *
9
+ * Tier 2 (CONTEXTUAL): weaker terms (deploy, production, security, database,
10
+ * billing, infrastructure, migration) NEVER trigger a finding on their own.
11
+ * They may only reinforce a strong signal, never substitute for it. This
12
+ * removes the pilot's false positives ("docs deployed", "security gateways",
13
+ * "deployment scripts").
14
+ *
15
+ * Path/scope names are never the sole trigger: `.env.example`, `config/auth.ts`,
16
+ * `deployment.md` must not produce CAUTION by naming alone.
17
+ *
18
+ * Practically: a finding is produced iff a STRONG term is present in a rule's
19
+ * content. CONTEXTUAL entries are retained as reinforcement only.
20
+ */
21
+ import type { ConfigurationArtifact } from "../../types/configuration.js";
22
+ import type { AnalyzerRule } from "../types.js";
23
+ /** Strong terms that alone justify a CAUTION finding (word-boundary match). */
24
+ export declare const STRONG_TERMS: readonly string[];
25
+ /** Contextual terms that NEVER trigger alone (Spec §26 weak categories). */
26
+ export declare const CONTEXTUAL_TERMS: readonly string[];
27
+ /** Returns the first STRONG term present in `text`, or undefined. */
28
+ export declare function matchStrongTerm(text: string): string | undefined;
29
+ /** Returns the first CONTEXTUAL term present in `text`, or undefined. */
30
+ export declare function matchContextualTerm(text: string): string | undefined;
31
+ export declare const highStakesRule: AnalyzerRule;
32
+ /**
33
+ * Returns the matched STRONG term, or undefined. Detection is content-driven
34
+ * (Rule 20 still reads the artifact, but path/scope names never trigger alone).
35
+ */
36
+ export declare function detectHighStakes(artifact: ConfigurationArtifact): string | undefined;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * High-stakes detection (Spec §26, §27, Rule 20) — REVISED after real-world
3
+ * pilot, two-tier model.
4
+ *
5
+ * Tier 1 (STRONG): a single strong term in CONTENT alone justifies CAUTION
6
+ * e.g. secret, credential, password, authentication, authorization,
7
+ * permission, payment, private key, api key, access token.
8
+ *
9
+ * Tier 2 (CONTEXTUAL): weaker terms (deploy, production, security, database,
10
+ * billing, infrastructure, migration) NEVER trigger a finding on their own.
11
+ * They may only reinforce a strong signal, never substitute for it. This
12
+ * removes the pilot's false positives ("docs deployed", "security gateways",
13
+ * "deployment scripts").
14
+ *
15
+ * Path/scope names are never the sole trigger: `.env.example`, `config/auth.ts`,
16
+ * `deployment.md` must not produce CAUTION by naming alone.
17
+ *
18
+ * Practically: a finding is produced iff a STRONG term is present in a rule's
19
+ * content. CONTEXTUAL entries are retained as reinforcement only.
20
+ */
21
+ import { makeFinding } from "./mapping.js";
22
+ /** Strong terms that alone justify a CAUTION finding (word-boundary match). */
23
+ export const STRONG_TERMS = [
24
+ "secret",
25
+ "credential",
26
+ "password",
27
+ "authentication",
28
+ "authorization",
29
+ "permission",
30
+ "payment",
31
+ "api key",
32
+ "private key",
33
+ "access token",
34
+ ];
35
+ /** Contextual terms that NEVER trigger alone (Spec §26 weak categories). */
36
+ export const CONTEXTUAL_TERMS = [
37
+ "deploy",
38
+ "deployment",
39
+ "production",
40
+ "security",
41
+ "database",
42
+ "billing",
43
+ "infrastructure",
44
+ "migration",
45
+ ];
46
+ /**
47
+ * Escapes a literal and anchors it to whole-word boundaries. Single-word terms
48
+ * accept an optional trailing `s` so (credential/credentials) both match.
49
+ */
50
+ function termPattern(term) {
51
+ const escaped = term.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
52
+ const plural = term.includes(" ") ? escaped : `${escaped}(?:s|es)?`;
53
+ return new RegExp(`\\b${plural}\\b`, "i");
54
+ }
55
+ /** Returns the first STRONG term present in `text`, or undefined. */
56
+ export function matchStrongTerm(text) {
57
+ return STRONG_TERMS.find((term) => termPattern(term).test(text));
58
+ }
59
+ /** Returns the first CONTEXTUAL term present in `text`, or undefined. */
60
+ export function matchContextualTerm(text) {
61
+ return CONTEXTUAL_TERMS.find((term) => termPattern(term).test(text));
62
+ }
63
+ export const highStakesRule = {
64
+ name: "high-stakes",
65
+ run(artifacts) {
66
+ const findings = [];
67
+ for (const artifact of artifacts) {
68
+ const strong = matchStrongTerm(artifact.content);
69
+ if (!strong)
70
+ continue;
71
+ // A contextual term can only reinforce a strong signal; it is never sufficient.
72
+ const context = matchContextualTerm(artifact.content);
73
+ const why = context ? `(reinforced by "${context}")` : "";
74
+ findings.push(makeFinding({
75
+ type: "high-stakes",
76
+ filePaths: [artifact.path],
77
+ title: "Potentially high-stakes configuration",
78
+ description: `${artifact.path} contains a strong high-stakes signal related to ` +
79
+ `"${strong}" ${why}. Potentially high-stakes configuration detected: ` +
80
+ `this instruction may be low frequency but important. Review manually ` +
81
+ `before modifying or removing it.`,
82
+ recommendation: `Before changing or removing this rule, confirm its scope and ` +
83
+ `purpose with context of the related system.`,
84
+ }));
85
+ }
86
+ return findings;
87
+ },
88
+ };
89
+ /**
90
+ * Returns the matched STRONG term, or undefined. Detection is content-driven
91
+ * (Rule 20 still reads the artifact, but path/scope names never trigger alone).
92
+ */
93
+ export function detectHighStakes(artifact) {
94
+ return matchStrongTerm(artifact.content);
95
+ }
96
+ //# sourceMappingURL=high-stakes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"high-stakes.js","sourceRoot":"","sources":["../../../src/analyzer/rules/high-stakes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,+EAA+E;AAC/E,MAAM,CAAC,MAAM,YAAY,GAAsB;IAC7C,QAAQ;IACR,YAAY;IACZ,UAAU;IACV,gBAAgB;IAChB,eAAe;IACf,YAAY;IACZ,SAAS;IACT,SAAS;IACT,aAAa;IACb,cAAc;CACf,CAAC;AAEF,4EAA4E;AAC5E,MAAM,CAAC,MAAM,gBAAgB,GAAsB;IACjD,QAAQ;IACR,YAAY;IACZ,YAAY;IACZ,UAAU;IACV,UAAU;IACV,SAAS;IACT,gBAAgB;IAChB,WAAW;CACZ,CAAC;AAEF;;;GAGG;AACH,SAAS,WAAW,CAAC,IAAY;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,WAAW,CAAC;IACpE,OAAO,IAAI,MAAM,CAAC,MAAM,MAAM,KAAK,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,mBAAmB,CAAC,IAAY;IAC9C,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,IAAI,EAAE,aAAa;IACnB,GAAG,CAAC,SAAS;QACX,MAAM,QAAQ,GAAG,EAAE,CAAC;QAEpB,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACjD,IAAI,CAAC,MAAM;gBAAE,SAAS;YAEtB,gFAAgF;YAChF,MAAM,OAAO,GAAG,mBAAmB,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YACtD,MAAM,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,mBAAmB,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAE1D,QAAQ,CAAC,IAAI,CACX,WAAW,CAAC;gBACV,IAAI,EAAE,aAAa;gBACnB,SAAS,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAC1B,KAAK,EAAE,uCAAuC;gBAC9C,WAAW,EACT,GAAG,QAAQ,CAAC,IAAI,mDAAmD;oBACnE,IAAI,MAAM,KAAK,GAAG,oDAAoD;oBACtE,uEAAuE;oBACvE,kCAAkC;gBACpC,cAAc,EACZ,+DAA+D;oBAC/D,6CAA6C;aAChD,CAAC,CACH,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,QAA+B;IAE/B,OAAO,eAAe,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Large instruction detection (Spec §20).
3
+ *
4
+ * A file being large is not inherently bad, but a file above the token
5
+ * threshold may contribute significantly to model context. In the MVP both
6
+ * the notice and warning thresholds map to `label=CONTEXT`, `severity=info`
7
+ * through the normative mapping; we only ever emit `large-file` findings.
8
+ *
9
+ * Note: the `warningFileTokens` threshold is reserved (Spec §11) and produces
10
+ * no additional severity in the MVP — the taxonomy keeps `info` here.
11
+ */
12
+ import { type AnalyzerRule } from "../types.js";
13
+ export declare const largeFileRule: AnalyzerRule;
14
+ /** Formats a token count with thousands separators, e.g. 4800 -> "4,800". */
15
+ export declare function formatTokens(tokens: number): string;