@promptci/core 0.0.1 → 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.
Files changed (253) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +29 -30
  3. package/dist/action-pinning.d.ts +37 -0
  4. package/dist/action-pinning.d.ts.map +1 -0
  5. package/dist/action-pinning.js +277 -0
  6. package/dist/action-pinning.js.map +1 -0
  7. package/dist/agent-practices.d.ts +3 -1
  8. package/dist/agent-practices.d.ts.map +1 -1
  9. package/dist/agent-practices.js +198 -94
  10. package/dist/agent-practices.js.map +1 -1
  11. package/dist/ai-config.d.ts +178 -0
  12. package/dist/ai-config.d.ts.map +1 -0
  13. package/dist/ai-config.js +721 -0
  14. package/dist/ai-config.js.map +1 -0
  15. package/dist/alias-files.d.ts +33 -0
  16. package/dist/alias-files.d.ts.map +1 -0
  17. package/dist/alias-files.js +60 -0
  18. package/dist/alias-files.js.map +1 -0
  19. package/dist/baseline.d.ts +17 -1
  20. package/dist/baseline.d.ts.map +1 -1
  21. package/dist/baseline.js +5 -1
  22. package/dist/baseline.js.map +1 -1
  23. package/dist/buried-critical.d.ts +17 -0
  24. package/dist/buried-critical.d.ts.map +1 -0
  25. package/dist/buried-critical.js +107 -0
  26. package/dist/buried-critical.js.map +1 -0
  27. package/dist/canonical-owner.d.ts.map +1 -1
  28. package/dist/canonical-owner.js +60 -30
  29. package/dist/canonical-owner.js.map +1 -1
  30. package/dist/ci-alignment.d.ts.map +1 -1
  31. package/dist/ci-alignment.js +3 -2
  32. package/dist/ci-alignment.js.map +1 -1
  33. package/dist/command-validity.d.ts +16 -0
  34. package/dist/command-validity.d.ts.map +1 -1
  35. package/dist/command-validity.js +387 -134
  36. package/dist/command-validity.js.map +1 -1
  37. package/dist/conflicts.d.ts.map +1 -1
  38. package/dist/conflicts.js +4 -44
  39. package/dist/conflicts.js.map +1 -1
  40. package/dist/context-analysis.d.ts.map +1 -1
  41. package/dist/context-analysis.js +13 -2
  42. package/dist/context-analysis.js.map +1 -1
  43. package/dist/context-bloat.d.ts +20 -1
  44. package/dist/context-bloat.d.ts.map +1 -1
  45. package/dist/context-bloat.js +99 -15
  46. package/dist/context-bloat.js.map +1 -1
  47. package/dist/context-optimizer.d.ts.map +1 -1
  48. package/dist/context-optimizer.js +18 -54
  49. package/dist/context-optimizer.js.map +1 -1
  50. package/dist/copilot-instructions-detector.d.ts +24 -0
  51. package/dist/copilot-instructions-detector.d.ts.map +1 -0
  52. package/dist/copilot-instructions-detector.js +145 -0
  53. package/dist/copilot-instructions-detector.js.map +1 -0
  54. package/dist/cursor-rules-detector.d.ts +17 -0
  55. package/dist/cursor-rules-detector.d.ts.map +1 -0
  56. package/dist/cursor-rules-detector.js +110 -0
  57. package/dist/cursor-rules-detector.js.map +1 -0
  58. package/dist/custom-rules.d.ts +52 -0
  59. package/dist/custom-rules.d.ts.map +1 -0
  60. package/dist/custom-rules.js +303 -0
  61. package/dist/custom-rules.js.map +1 -0
  62. package/dist/dead-references.d.ts +8 -2
  63. package/dist/dead-references.d.ts.map +1 -1
  64. package/dist/dead-references.js +315 -68
  65. package/dist/dead-references.js.map +1 -1
  66. package/dist/dependency-staleness.d.ts +35 -0
  67. package/dist/dependency-staleness.d.ts.map +1 -0
  68. package/dist/dependency-staleness.js +1001 -0
  69. package/dist/dependency-staleness.js.map +1 -0
  70. package/dist/detectors.d.ts +1 -3
  71. package/dist/detectors.d.ts.map +1 -1
  72. package/dist/detectors.js +74 -56
  73. package/dist/detectors.js.map +1 -1
  74. package/dist/duplicates.d.ts.map +1 -1
  75. package/dist/duplicates.js +15 -9
  76. package/dist/duplicates.js.map +1 -1
  77. package/dist/evidence.d.ts +39 -0
  78. package/dist/evidence.d.ts.map +1 -0
  79. package/dist/evidence.js +78 -0
  80. package/dist/evidence.js.map +1 -0
  81. package/dist/finding-id.d.ts +21 -0
  82. package/dist/finding-id.d.ts.map +1 -0
  83. package/dist/finding-id.js +31 -0
  84. package/dist/finding-id.js.map +1 -0
  85. package/dist/fix-engine.d.ts +11 -0
  86. package/dist/fix-engine.d.ts.map +1 -1
  87. package/dist/fix-engine.js +88 -71
  88. package/dist/fix-engine.js.map +1 -1
  89. package/dist/frameworks/dotnet.js +2 -2
  90. package/dist/frameworks/dotnet.js.map +1 -1
  91. package/dist/frameworks/python.d.ts.map +1 -1
  92. package/dist/frameworks/python.js +5 -2
  93. package/dist/frameworks/python.js.map +1 -1
  94. package/dist/frameworks/rust.d.ts.map +1 -1
  95. package/dist/frameworks/rust.js +2 -1
  96. package/dist/frameworks/rust.js.map +1 -1
  97. package/dist/git-symlinks.d.ts +30 -0
  98. package/dist/git-symlinks.d.ts.map +1 -0
  99. package/dist/git-symlinks.js +161 -0
  100. package/dist/git-symlinks.js.map +1 -0
  101. package/dist/gitignore.d.ts +22 -0
  102. package/dist/gitignore.d.ts.map +1 -0
  103. package/dist/gitignore.js +157 -0
  104. package/dist/gitignore.js.map +1 -0
  105. package/dist/health-score.d.ts.map +1 -1
  106. package/dist/health-score.js +35 -5
  107. package/dist/health-score.js.map +1 -1
  108. package/dist/hooks-settings-detector.d.ts +17 -0
  109. package/dist/hooks-settings-detector.d.ts.map +1 -0
  110. package/dist/hooks-settings-detector.js +228 -0
  111. package/dist/hooks-settings-detector.js.map +1 -0
  112. package/dist/index.d.ts +29 -8
  113. package/dist/index.d.ts.map +1 -1
  114. package/dist/index.js +21 -6
  115. package/dist/index.js.map +1 -1
  116. package/dist/makefile.d.ts +37 -0
  117. package/dist/makefile.d.ts.map +1 -0
  118. package/dist/makefile.js +156 -0
  119. package/dist/makefile.js.map +1 -0
  120. package/dist/manifest-consistency.d.ts +6 -0
  121. package/dist/manifest-consistency.d.ts.map +1 -1
  122. package/dist/manifest-consistency.js +75 -10
  123. package/dist/manifest-consistency.js.map +1 -1
  124. package/dist/markdown-fences.d.ts +112 -0
  125. package/dist/markdown-fences.d.ts.map +1 -0
  126. package/dist/markdown-fences.js +174 -0
  127. package/dist/markdown-fences.js.map +1 -0
  128. package/dist/mcp-config-detector.d.ts +20 -0
  129. package/dist/mcp-config-detector.d.ts.map +1 -0
  130. package/dist/mcp-config-detector.js +237 -0
  131. package/dist/mcp-config-detector.js.map +1 -0
  132. package/dist/missing-context.d.ts.map +1 -1
  133. package/dist/missing-context.js +2 -52
  134. package/dist/missing-context.js.map +1 -1
  135. package/dist/model-budgets.d.ts +69 -0
  136. package/dist/model-budgets.d.ts.map +1 -0
  137. package/dist/model-budgets.js +110 -0
  138. package/dist/model-budgets.js.map +1 -0
  139. package/dist/negative-instructions.d.ts +26 -0
  140. package/dist/negative-instructions.d.ts.map +1 -0
  141. package/dist/negative-instructions.js +169 -0
  142. package/dist/negative-instructions.js.map +1 -0
  143. package/dist/path-containment.d.ts +41 -0
  144. package/dist/path-containment.d.ts.map +1 -0
  145. package/dist/path-containment.js +123 -0
  146. package/dist/path-containment.js.map +1 -0
  147. package/dist/project-type.d.ts +12 -2
  148. package/dist/project-type.d.ts.map +1 -1
  149. package/dist/project-type.js +25 -12
  150. package/dist/project-type.js.map +1 -1
  151. package/dist/prompt-cache.d.ts.map +1 -1
  152. package/dist/prompt-cache.js +33 -24
  153. package/dist/prompt-cache.js.map +1 -1
  154. package/dist/promptci-gitignore.d.ts +34 -0
  155. package/dist/promptci-gitignore.d.ts.map +1 -0
  156. package/dist/promptci-gitignore.js +42 -0
  157. package/dist/promptci-gitignore.js.map +1 -0
  158. package/dist/repo-context.d.ts +80 -0
  159. package/dist/repo-context.d.ts.map +1 -1
  160. package/dist/repo-context.js +170 -16
  161. package/dist/repo-context.js.map +1 -1
  162. package/dist/report.d.ts +8 -0
  163. package/dist/report.d.ts.map +1 -1
  164. package/dist/report.js +163 -63
  165. package/dist/report.js.map +1 -1
  166. package/dist/scan.d.ts.map +1 -1
  167. package/dist/scan.js +47 -4
  168. package/dist/scan.js.map +1 -1
  169. package/dist/scanner.d.ts +61 -1
  170. package/dist/scanner.d.ts.map +1 -1
  171. package/dist/scanner.js +367 -70
  172. package/dist/scanner.js.map +1 -1
  173. package/dist/security-pack.d.ts +20 -0
  174. package/dist/security-pack.d.ts.map +1 -1
  175. package/dist/security-pack.js +33 -14
  176. package/dist/security-pack.js.map +1 -1
  177. package/dist/skill-supply-chain.d.ts +132 -0
  178. package/dist/skill-supply-chain.d.ts.map +1 -0
  179. package/dist/skill-supply-chain.js +2954 -0
  180. package/dist/skill-supply-chain.js.map +1 -0
  181. package/dist/skills-detector.d.ts +23 -0
  182. package/dist/skills-detector.d.ts.map +1 -0
  183. package/dist/skills-detector.js +279 -0
  184. package/dist/skills-detector.js.map +1 -0
  185. package/dist/stale-instructions.d.ts +4 -1
  186. package/dist/stale-instructions.d.ts.map +1 -1
  187. package/dist/stale-instructions.js +53 -55
  188. package/dist/stale-instructions.js.map +1 -1
  189. package/dist/subagents-detector.d.ts +19 -0
  190. package/dist/subagents-detector.d.ts.map +1 -0
  191. package/dist/subagents-detector.js +155 -0
  192. package/dist/subagents-detector.js.map +1 -0
  193. package/dist/suppression.d.ts +2 -0
  194. package/dist/suppression.d.ts.map +1 -1
  195. package/dist/suppression.js +16 -47
  196. package/dist/suppression.js.map +1 -1
  197. package/dist/types.d.ts +62 -4
  198. package/dist/types.d.ts.map +1 -1
  199. package/dist/types.js +47 -1
  200. package/dist/types.js.map +1 -1
  201. package/dist/vague-guidance.d.ts +15 -2
  202. package/dist/vague-guidance.d.ts.map +1 -1
  203. package/dist/vague-guidance.js +44 -41
  204. package/dist/vague-guidance.js.map +1 -1
  205. package/dist/windsurf-detector.d.ts +22 -0
  206. package/dist/windsurf-detector.d.ts.map +1 -0
  207. package/dist/windsurf-detector.js +96 -0
  208. package/dist/windsurf-detector.js.map +1 -0
  209. package/dist/within-section-dedup.d.ts +16 -0
  210. package/dist/within-section-dedup.d.ts.map +1 -0
  211. package/dist/within-section-dedup.js +148 -0
  212. package/dist/within-section-dedup.js.map +1 -0
  213. package/dist/workspace-manifests.d.ts +80 -0
  214. package/dist/workspace-manifests.d.ts.map +1 -0
  215. package/dist/workspace-manifests.js +333 -0
  216. package/dist/workspace-manifests.js.map +1 -0
  217. package/package.json +11 -8
  218. package/dist/cheap-model-routing.d.ts +0 -4
  219. package/dist/cheap-model-routing.d.ts.map +0 -1
  220. package/dist/cheap-model-routing.js +0 -43
  221. package/dist/cheap-model-routing.js.map +0 -1
  222. package/dist/cli-output-filter.d.ts +0 -16
  223. package/dist/cli-output-filter.d.ts.map +0 -1
  224. package/dist/cli-output-filter.js +0 -88
  225. package/dist/cli-output-filter.js.map +0 -1
  226. package/dist/context-cost.d.ts +0 -4
  227. package/dist/context-cost.d.ts.map +0 -1
  228. package/dist/context-cost.js +0 -70
  229. package/dist/context-cost.js.map +0 -1
  230. package/dist/context-recommender.d.ts +0 -3
  231. package/dist/context-recommender.d.ts.map +0 -1
  232. package/dist/context-recommender.js +0 -329
  233. package/dist/context-recommender.js.map +0 -1
  234. package/dist/llm.d.ts +0 -6
  235. package/dist/llm.d.ts.map +0 -1
  236. package/dist/llm.js +0 -67
  237. package/dist/llm.js.map +0 -1
  238. package/dist/mcp-detector.d.ts +0 -4
  239. package/dist/mcp-detector.d.ts.map +0 -1
  240. package/dist/mcp-detector.js +0 -131
  241. package/dist/mcp-detector.js.map +0 -1
  242. package/dist/native-tool-preference.d.ts +0 -20
  243. package/dist/native-tool-preference.d.ts.map +0 -1
  244. package/dist/native-tool-preference.js +0 -94
  245. package/dist/native-tool-preference.js.map +0 -1
  246. package/dist/output-verbosity.d.ts +0 -3
  247. package/dist/output-verbosity.d.ts.map +0 -1
  248. package/dist/output-verbosity.js +0 -83
  249. package/dist/output-verbosity.js.map +0 -1
  250. package/dist/product-boundary.d.ts +0 -11
  251. package/dist/product-boundary.d.ts.map +0 -1
  252. package/dist/product-boundary.js +0 -301
  253. package/dist/product-boundary.js.map +0 -1
package/dist/types.d.ts CHANGED
@@ -1,10 +1,29 @@
1
1
  /** Core data types for PromptCI */
2
- export type FileType = 'claude' | 'agents' | 'cursor' | 'copilot' | 'readme' | 'docs' | 'prompt' | 'unknown';
2
+ export type FileType = 'claude' | 'agents' | 'cursor' | 'windsurf' | 'copilot' | 'gemini' | 'cline' | 'persona' | 'readme' | 'docs' | 'prompt' | 'skill' | 'agent' | 'unknown';
3
+ /**
4
+ * Persistent, always-loaded agent instruction file types: the allowlist the
5
+ * prose detectors (negative-instruction overload, buried-critical, within-
6
+ * section dedup, prompt-cache friendliness) target. `context optimize` uses it
7
+ * minus 'persona', which it never rewrites.
8
+ *
9
+ * One shared definition on purpose (BUG-19): each detector used to carry its
10
+ * own copy, so a newly discovered file type was scanned and counted toward
11
+ * context cost but silently skipped by every copy nobody remembered to update.
12
+ * README/docs are human-facing and deliberately excluded.
13
+ */
14
+ export declare const INSTRUCTION_FILE_TYPES: ReadonlySet<FileType>;
15
+ export declare function isOnDemandFileType(fileType: FileType): boolean;
3
16
  export type IssueSeverity = 'info' | 'warning' | 'high' | 'critical';
4
- export type IssueCategory = 'duplicate' | 'conflict' | 'context_bloat' | 'missing_context' | 'stale_instruction' | 'vague_guidance' | 'structure' | 'command_validity' | 'agent_practices' | 'security';
17
+ export type IssueCategory = 'duplicate' | 'conflict' | 'context_bloat' | 'missing_context' | 'stale_instruction' | 'vague_guidance' | 'structure' | 'command_validity' | 'agent_practices' | 'ai_config' | 'security' | 'custom';
5
18
  export type InstructionSection = {
6
19
  id: string;
7
20
  filePath: string;
21
+ /**
22
+ * `filePath` relative to the scan root, forward slashes. Set by the scanner;
23
+ * finding ids hash this instead of the absolute path so one repo scanned from
24
+ * two checkout locations yields identical ids (see finding-id.ts).
25
+ */
26
+ relativePath?: string;
8
27
  heading?: string;
9
28
  startLine: number;
10
29
  endLine: number;
@@ -13,6 +32,18 @@ export type InstructionSection = {
13
32
  };
14
33
  export type InstructionFile = {
15
34
  path: string;
35
+ /**
36
+ * `path` relative to the scan root, forward slashes. Set by the scanner;
37
+ * finding ids hash this instead of the absolute path (see finding-id.ts).
38
+ * Optional so hand-built test fixtures keep type-checking.
39
+ */
40
+ relativePath?: string;
41
+ /**
42
+ * Set only on a symlink ALIAS: the `relativePath` of the file this name is a
43
+ * symlink to, which is the copy detectors scan (the alias is listed in the
44
+ * report inventory but never scanned, so its content is not double-counted).
45
+ */
46
+ aliasOf?: string;
16
47
  fileType: FileType;
17
48
  content: string;
18
49
  sections: InstructionSection[];
@@ -34,7 +65,15 @@ export type PromptCiIssue = {
34
65
  }>;
35
66
  evidence: string[];
36
67
  recommendation: string;
68
+ /** Advisory, human-readable "here's how to fix it" text. Not machine-applied. */
37
69
  fixRecipe?: string;
70
+ /**
71
+ * True only when `applyFixRecipe` implements a mechanical, reversible edit for
72
+ * this issue and it is safe to auto-apply. Gates `promptci fix` (see
73
+ * `isRepairable`). Detectors set this deliberately per recipe — it is never
74
+ * inferred from the presence of `fixRecipe`, which is usually advisory prose.
75
+ */
76
+ autoApplySafe?: boolean;
38
77
  confidence: number;
39
78
  tags?: string[];
40
79
  impact?: 'high' | 'medium' | 'low';
@@ -44,7 +83,8 @@ export type TopFix = {
44
83
  reason: string;
45
84
  suggestedAction: string;
46
85
  };
47
- export type ProjectType = 'auto' | 'typescript' | 'nextjs' | 'unity' | 'dotnet' | 'python' | 'go' | 'rust' | 'unknown';
86
+ export declare const PROJECT_TYPES: readonly ["auto", "typescript", "nextjs", "unity", "dotnet", "python", "go", "rust", "unknown"];
87
+ export type ProjectType = (typeof PROJECT_TYPES)[number];
48
88
  export type ScanTrend = {
49
89
  previousScanDate?: string;
50
90
  scoreDelta: number;
@@ -83,6 +123,8 @@ export type ScanMetrics = {
83
123
  path: string;
84
124
  estimatedTokens: number;
85
125
  }>;
126
+ onDemandFileCount?: number;
127
+ estimatedOnDemandTokens?: number;
86
128
  };
87
129
  /**
88
130
  * R1: report.json intentionally omits InstructionFile's `content` and
@@ -98,7 +140,10 @@ export type ScanMetrics = {
98
140
  * that matches what's really on disk, instead of the full in-memory
99
141
  * `ScanReport`/`InstructionFile` types.
100
142
  */
101
- export type CompactFileSummary = Pick<InstructionFile, 'path' | 'fileType' | 'lineCount' | 'charCount' | 'estimatedTokens'>;
143
+ export type CompactFileSummary = Pick<InstructionFile, 'path' | 'fileType' | 'lineCount' | 'charCount' | 'estimatedTokens'> & {
144
+ /** Repo-relative path of the file this entry is a symlink to (aliases only). */
145
+ aliasOf?: string;
146
+ };
102
147
  export type ScanReportJson = Omit<ScanReport, 'filesScanned'> & {
103
148
  filesScanned: CompactFileSummary[];
104
149
  };
@@ -124,5 +169,18 @@ export type ScanInput = {
124
169
  baseline?: Baseline;
125
170
  contextBudget?: number;
126
171
  fileContextBudget?: number;
172
+ /**
173
+ * FEAT-012: a target-model preset name (e.g. `claude-opus-5`) that scales the
174
+ * context-bloat thresholds to that model's context window. An explicit
175
+ * `contextBudget`/`fileContextBudget` always overrides the preset. Surfaced
176
+ * as the `targetModel` config key and `--target-model` flag.
177
+ */
178
+ targetModel?: string;
179
+ /**
180
+ * FEAT-004: force every vague-guidance finding to this severity, overriding
181
+ * the detector's high-signal/soft tiering. Surfaced as the
182
+ * `vagueGuidanceSeverity` config key.
183
+ */
184
+ vagueGuidanceSeverity?: 'info' | 'warning';
127
185
  };
128
186
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js CHANGED
@@ -1,3 +1,49 @@
1
1
  /** Core data types for PromptCI */
2
- export {};
2
+ /**
3
+ * Persistent, always-loaded agent instruction file types: the allowlist the
4
+ * prose detectors (negative-instruction overload, buried-critical, within-
5
+ * section dedup, prompt-cache friendliness) target. `context optimize` uses it
6
+ * minus 'persona', which it never rewrites.
7
+ *
8
+ * One shared definition on purpose (BUG-19): each detector used to carry its
9
+ * own copy, so a newly discovered file type was scanned and counted toward
10
+ * context cost but silently skipped by every copy nobody remembered to update.
11
+ * README/docs are human-facing and deliberately excluded.
12
+ */
13
+ export const INSTRUCTION_FILE_TYPES = new Set([
14
+ 'claude',
15
+ 'agents',
16
+ 'cursor',
17
+ 'windsurf',
18
+ 'copilot',
19
+ 'gemini',
20
+ 'cline',
21
+ 'persona',
22
+ 'prompt',
23
+ ]);
24
+ /**
25
+ * On-demand file types are loaded by an agent only when a skill/subagent is
26
+ * invoked, not on every turn. They do not count toward always-loaded context
27
+ * cost and are owned by the ai_config detectors, so the generic prose detectors
28
+ * skip them.
29
+ */
30
+ const ON_DEMAND_FILE_TYPES = new Set(['skill', 'agent']);
31
+ export function isOnDemandFileType(fileType) {
32
+ return ON_DEMAND_FILE_TYPES.has(fileType);
33
+ }
34
+ // Single source of truth: consumers that need to *validate* a project type at
35
+ // runtime (the CLI's config loader, `promptci init`) import this array rather
36
+ // than keeping their own copy, which is how `python`/`go`/`rust` previously
37
+ // ended up writable by `init` but rejected by `loadConfig`.
38
+ export const PROJECT_TYPES = [
39
+ 'auto',
40
+ 'typescript',
41
+ 'nextjs',
42
+ 'unity',
43
+ 'dotnet',
44
+ 'python',
45
+ 'go',
46
+ 'rust',
47
+ 'unknown',
48
+ ];
3
49
  //# sourceMappingURL=types.js.map
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mCAAmC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,mCAAmC;AA0BnC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAA0B,IAAI,GAAG,CAAW;IAC7E,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,SAAS;IACT,QAAQ;IACR,OAAO;IACP,SAAS;IACT,QAAQ;CACT,CAAC,CAAC;AAEH;;;;;GAKG;AACH,MAAM,oBAAoB,GAA0B,IAAI,GAAG,CAAW,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC;AAE1F,MAAM,UAAU,kBAAkB,CAAC,QAAkB;IACnD,OAAO,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC;AAuFD,8EAA8E;AAC9E,8EAA8E;AAC9E,4EAA4E;AAC5E,4DAA4D;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,MAAM;IACN,YAAY;IACZ,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,IAAI;IACJ,MAAM;IACN,SAAS;CACD,CAAC"}
@@ -5,8 +5,21 @@
5
5
  * Emits at most one issue per section regardless of how many vague phrases
6
6
  * appear in it.
7
7
  *
8
- * Heuristic detector — confidence 0.8, severity "info".
8
+ * Heuristic detector. Findings are tiered (FEAT-004): high-signal platitudes
9
+ * ("write clean code", "best practices", "SOLID principles", …) are
10
+ * warning 0.80; soft style/UX/paradigm phrases are info 0.75. A team can force
11
+ * one severity for every finding via the `severityOverride` option (wired to
12
+ * the `vagueGuidanceSeverity` config key).
9
13
  */
10
14
  import type { InstructionFile, PromptCiIssue } from './types.js';
11
- export declare function detectVagueGuidance(files: InstructionFile[]): PromptCiIssue[];
15
+ export type VagueGuidanceOptions = {
16
+ /**
17
+ * FEAT-004: force every vague-guidance finding to this severity, overriding
18
+ * the per-section high-signal/soft tiering. Wired to the `vagueGuidanceSeverity`
19
+ * config key so teams can enforce a stricter (all-warning) or looser
20
+ * (all-info) posture. Confidence still reflects the matched tier.
21
+ */
22
+ severityOverride?: 'info' | 'warning';
23
+ };
24
+ export declare function detectVagueGuidance(files: InstructionFile[], options?: VagueGuidanceOptions): PromptCiIssue[];
12
25
  //# sourceMappingURL=vague-guidance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"vague-guidance.d.ts","sourceRoot":"","sources":["../src/vague-guidance.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAC;AA8LrF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,aAAa,EAAE,CAsD7E"}
1
+ {"version":3,"file":"vague-guidance.d.ts","sourceRoot":"","sources":["../src/vague-guidance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAqC,aAAa,EAAE,MAAM,YAAY,CAAC;AAsLpG,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC,CAAC;AAEF,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,eAAe,EAAE,EACxB,OAAO,GAAE,oBAAyB,GACjC,aAAa,EAAE,CA8DjB"}
@@ -5,9 +5,15 @@
5
5
  * Emits at most one issue per section regardless of how many vague phrases
6
6
  * appear in it.
7
7
  *
8
- * Heuristic detector — confidence 0.8, severity "info".
8
+ * Heuristic detector. Findings are tiered (FEAT-004): high-signal platitudes
9
+ * ("write clean code", "best practices", "SOLID principles", …) are
10
+ * warning 0.80; soft style/UX/paradigm phrases are info 0.75. A team can force
11
+ * one severity for every finding via the `severityOverride` option (wired to
12
+ * the `vagueGuidanceSeverity` config key).
9
13
  */
10
14
  import * as crypto from 'node:crypto';
15
+ import { stripCodeBlocks } from './markdown-fences.js';
16
+ import { sectionIdPath } from './finding-id.js';
11
17
  const VAGUE_PHRASES = [
12
18
  'write clean code',
13
19
  'write clean', // catches "write clean Go code", "write clean Python code", etc.
@@ -105,6 +111,31 @@ function expandHyphenVariants(phrases) {
105
111
  return [...expanded];
106
112
  }
107
113
  const ALL_VAGUE_PHRASES = expandHyphenVariants(VAGUE_PHRASES);
114
+ /**
115
+ * FEAT-004: High-signal platitudes. These are the phrases that most reliably
116
+ * mark instruction rot — broad quality/effort exhortations that give an agent
117
+ * no constraint at all. A section containing any of them is emitted at
118
+ * `warning` (0.80); sections whose only matches are softer style/UX/paradigm
119
+ * phrases stay `info` (0.75). Listed in the post-hyphen-expansion form so the
120
+ * no-hyphen twins ("production ready" ↔ "production-ready") both qualify.
121
+ */
122
+ const HIGH_SIGNAL_PHRASES = new Set([
123
+ 'write clean code',
124
+ 'write clean',
125
+ 'use best practices',
126
+ 'best practices',
127
+ 'follow best practices',
128
+ 'make it production ready',
129
+ 'production ready',
130
+ 'production-ready',
131
+ 'production quality',
132
+ 'production-quality',
133
+ 'be careful',
134
+ 'solid principles',
135
+ 'follow solid',
136
+ 'clean architecture',
137
+ 'make it maintainable',
138
+ ]);
108
139
  function escapeRegExp(text) {
109
140
  return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
110
141
  }
@@ -115,41 +146,6 @@ function escapeRegExp(text) {
115
146
  * reused across every section/file.
116
147
  */
117
148
  const PHRASE_PATTERNS = new Map(ALL_VAGUE_PHRASES.map((phrase) => [phrase, new RegExp(`\\b${escapeRegExp(phrase)}\\b`)]));
118
- /**
119
- * V4: Strip fenced code blocks (``` and ~~~, matching either fence
120
- * character/length per CommonMark — see scanner.ts) and inline code spans
121
- * before matching. A fenced example that quotes a vague phrase is
122
- * documentation about the phrase, not real guidance directed at the agent.
123
- */
124
- function stripCodeBlocks(text) {
125
- const lines = text.split('\n');
126
- const kept = [];
127
- let inBlock = false;
128
- let fenceChar = null;
129
- let fenceLen = 0;
130
- for (const line of lines) {
131
- if (!inBlock) {
132
- const openMatch = /^ {0,3}([`~]{3,})/.exec(line);
133
- if (openMatch) {
134
- inBlock = true;
135
- fenceChar = openMatch[1][0] ?? null;
136
- fenceLen = openMatch[1].length;
137
- continue;
138
- }
139
- kept.push(line);
140
- }
141
- else {
142
- const closeMatch = /^ {0,3}([`~]{3,})\s*$/.exec(line);
143
- if (closeMatch && closeMatch[1][0] === fenceChar && closeMatch[1].length >= fenceLen) {
144
- inBlock = false;
145
- fenceChar = null;
146
- fenceLen = 0;
147
- }
148
- // else: still inside the fence — drop the line
149
- }
150
- }
151
- return kept.join('\n').replace(/`[^`\n]+`/g, '');
152
- }
153
149
  /**
154
150
  * V1: Find lines (or pairs of consecutive wrapped lines) containing `phraseRe`
155
151
  * within the per-line length budget. Hard-wrapped guidance like:
@@ -177,11 +173,11 @@ function findPhraseMatches(scanText, phraseRe) {
177
173
  return matches;
178
174
  }
179
175
  function issueId(section) {
180
- const key = `${section.filePath}:${section.startLine}:vague`;
176
+ const key = `${sectionIdPath(section)}:${section.startLine}:vague`;
181
177
  const hash = crypto.createHash('sha1').update(key).digest('hex').slice(0, 12);
182
178
  return `vague-${hash}`;
183
179
  }
184
- export function detectVagueGuidance(files) {
180
+ export function detectVagueGuidance(files, options = {}) {
185
181
  const issues = [];
186
182
  // One issue per section — collect all matching phrases and lines first
187
183
  const seen = new Set();
@@ -190,7 +186,7 @@ export function detectVagueGuidance(files) {
190
186
  const sectionKey = `${file.path}:${section.startLine}`;
191
187
  if (seen.has(sectionKey))
192
188
  continue;
193
- const scanText = stripCodeBlocks(section.text);
189
+ const scanText = stripCodeBlocks(section.text, { stripInlineCode: true });
194
190
  // V1: collapse newlines to spaces for this fast pre-filter only, so a
195
191
  // phrase hard-wrapped across two lines still passes the gate. The actual
196
192
  // evidence extraction below (findPhraseMatches) independently re-checks
@@ -214,9 +210,16 @@ export function detectVagueGuidance(files) {
214
210
  continue;
215
211
  seen.add(sectionKey);
216
212
  const phraseList = matchedPhrases.map((p) => `"${p}"`).join(', ');
213
+ // FEAT-004: tier by the strongest phrase in the section. Any high-signal
214
+ // platitude escalates the whole finding to warning; a config override,
215
+ // when set, wins over the derived tier (but not the tier-based confidence).
216
+ const isHighSignal = matchedPhrases.some((p) => HIGH_SIGNAL_PHRASES.has(p));
217
+ const tierSeverity = isHighSignal ? 'warning' : 'info';
218
+ const severity = options.severityOverride ?? tierSeverity;
219
+ const confidence = isHighSignal ? 0.8 : 0.75;
217
220
  issues.push({
218
221
  id: issueId(section),
219
- severity: 'info',
222
+ severity,
220
223
  category: 'vague_guidance',
221
224
  title: 'Vague guidance detected',
222
225
  summary: `This section contains guidance that may be too vague to be actionable: ${phraseList}.`,
@@ -226,7 +229,7 @@ export function detectVagueGuidance(files) {
226
229
  recommendation: 'Replace vague guidance with concrete constraints — specific commands, forbidden ' +
227
230
  'patterns, or measurable criteria. For example, replace "write clean code" with ' +
228
231
  '"functions must be ≤ 50 lines; no unused variables".',
229
- confidence: 0.8,
232
+ confidence,
230
233
  });
231
234
  }
232
235
  }
@@ -1 +1 @@
1
- {"version":3,"file":"vague-guidance.js","sourceRoot":"","sources":["../src/vague-guidance.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vague-guidance.js","sourceRoot":"","sources":["../src/vague-guidance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Windsurf Rules Detector (issue #67)
3
+ *
4
+ * `.windsurfrules` is Windsurf's legacy, always-on, workspace-wide rules file:
5
+ * every rule in it is fed to the model on every request for the whole
6
+ * workspace. Windsurf also supports scoped `.windsurf/rules/*.md` files with
7
+ * glob / manual / model-decision activation.
8
+ *
9
+ * This detector flags one thing the generic prose detectors miss: a workspace
10
+ * `.windsurfrules` that clearly carries language- or framework-specific rules,
11
+ * which are cheaper as glob-scoped rules that load only for matching files. It
12
+ * emits a single cautious `info` suggesting the author clarify intended scope.
13
+ *
14
+ * The Windsurf-specific size/truncation check for `.windsurfrules` lives in
15
+ * `context-bloat.ts`, alongside the other file-type-specific size thresholds.
16
+ *
17
+ * Deterministic and offline.
18
+ */
19
+ import type { RepoContext } from './repo-context.js';
20
+ import type { PromptCiIssue } from './types.js';
21
+ export declare function detectWindsurfRules(context: RepoContext): PromptCiIssue[];
22
+ //# sourceMappingURL=windsurf-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windsurf-detector.d.ts","sourceRoot":"","sources":["../src/windsurf-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAA6B,aAAa,EAAE,MAAM,YAAY,CAAC;AAoC3E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAiDzE"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Windsurf Rules Detector (issue #67)
3
+ *
4
+ * `.windsurfrules` is Windsurf's legacy, always-on, workspace-wide rules file:
5
+ * every rule in it is fed to the model on every request for the whole
6
+ * workspace. Windsurf also supports scoped `.windsurf/rules/*.md` files with
7
+ * glob / manual / model-decision activation.
8
+ *
9
+ * This detector flags one thing the generic prose detectors miss: a workspace
10
+ * `.windsurfrules` that clearly carries language- or framework-specific rules,
11
+ * which are cheaper as glob-scoped rules that load only for matching files. It
12
+ * emits a single cautious `info` suggesting the author clarify intended scope.
13
+ *
14
+ * The Windsurf-specific size/truncation check for `.windsurfrules` lives in
15
+ * `context-bloat.ts`, alongside the other file-type-specific size thresholds.
16
+ *
17
+ * Deterministic and offline.
18
+ */
19
+ import { shortHash } from './ai-config.js';
20
+ import { fileIdPath } from './finding-id.js';
21
+ import { aliasesWithNewType, groupAliasesByTarget } from './alias-files.js';
22
+ /**
23
+ * Language / framework signals that, when they appear as SECTION HEADINGS in an
24
+ * always-on workspace file, indicate rules scoped to only part of the codebase.
25
+ * Heading-only matching keeps this precise: a passing mention of "python" in
26
+ * prose does not count, but a `## Python` section does. Terms are chosen to be
27
+ * unambiguous in a heading (e.g. `golang`, not bare `go`).
28
+ */
29
+ const SCOPED_TOPICS = [
30
+ { label: 'TypeScript', re: /\btypescript\b/i },
31
+ { label: 'JavaScript', re: /\bjavascript\b/i },
32
+ { label: 'Python', re: /\bpython\b/i },
33
+ { label: 'Rust', re: /\brust\b/i },
34
+ { label: 'Go', re: /\bgolang\b/i },
35
+ { label: 'Ruby', re: /\bruby\b|\brails\b/i },
36
+ { label: 'Java', re: /\bjava\b(?!script)/i },
37
+ { label: 'Kotlin', re: /\bkotlin\b/i },
38
+ { label: 'Swift', re: /\bswift\b/i },
39
+ { label: 'C#', re: /\bc#|\bcsharp\b|\bdotnet\b|\.net\b/i },
40
+ { label: 'React', re: /\breact\b/i },
41
+ { label: 'Vue', re: /\bvue\b/i },
42
+ { label: 'Svelte', re: /\bsvelte\b/i },
43
+ { label: 'Django', re: /\bdjango\b/i },
44
+ ];
45
+ /**
46
+ * Two or more distinct scoped topics in headings is a strong, low-noise signal
47
+ * that an always-on file mixes rule sets that would be better glob-scoped. One
48
+ * topic is left alone — a single `## Python` section in a Python repo is normal.
49
+ */
50
+ const MIN_DISTINCT_TOPICS = 2;
51
+ export function detectWindsurfRules(context) {
52
+ const issues = [];
53
+ // `.windsurfrules -> AGENTS.md`: Windsurf loads that content always-on under the alias's name, so the
54
+ // check runs for the alias (against the real content) unless the real file is already a Windsurf file.
55
+ // Several links to one file are one finding listing every link, not one per link.
56
+ const isWindsurf = (type) => type === 'windsurf';
57
+ const groups = [
58
+ ...context.files.filter((file) => file.fileType === 'windsurf').map((file) => [file]),
59
+ ...groupAliasesByTarget(aliasesWithNewType(context.files, context.aliasFiles ?? [], isWindsurf)),
60
+ ];
61
+ for (const group of groups) {
62
+ const file = group[0];
63
+ const topics = new Set();
64
+ for (const section of file.sections) {
65
+ const heading = section.heading;
66
+ if (!heading)
67
+ continue;
68
+ for (const topic of SCOPED_TOPICS) {
69
+ if (topic.re.test(heading))
70
+ topics.add(topic.label);
71
+ }
72
+ }
73
+ if (topics.size >= MIN_DISTINCT_TOPICS) {
74
+ const found = [...topics].sort();
75
+ issues.push({
76
+ id: `ai-config-windsurf-scope-${shortHash(fileIdPath(file))}`,
77
+ severity: 'info',
78
+ category: 'ai_config',
79
+ title: '.windsurfrules mixes language-specific rules in a workspace-wide file',
80
+ summary: `This \`.windsurfrules\` has headings for multiple languages/frameworks ` +
81
+ `(${found.join(', ')}), but it applies to the whole workspace on every ` +
82
+ `request. Language- or framework-specific rules are cheaper as glob-scoped ` +
83
+ `rules that load only for matching files.`,
84
+ filePaths: group.map((f) => f.path),
85
+ locations: group.map((f) => ({ filePath: f.path, startLine: 1 })),
86
+ evidence: [`Scoped topics found in headings: ${found.join(', ')}`],
87
+ recommendation: 'Clarify the intended scope: keep genuinely workspace-wide conventions in ' +
88
+ '`.windsurfrules`, and move language- or framework-specific rules into ' +
89
+ 'glob-scoped `.windsurf/rules/*.md` files, each with a glob trigger.',
90
+ confidence: 0.6,
91
+ });
92
+ }
93
+ }
94
+ return issues;
95
+ }
96
+ //# sourceMappingURL=windsurf-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"windsurf-detector.js","sourceRoot":"","sources":["../src/windsurf-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Within-section semantic dedup detector (FEAT-013).
3
+ *
4
+ * The cross-file `detectDuplicates` detector works at section granularity and
5
+ * misses a single section that restates the same point several ways. This
6
+ * detector looks *inside* a section: for sections with more than five
7
+ * paragraphs, it computes pairwise Jaccard similarity on the paragraphs and
8
+ * flags any pair that is ≥ 0.65 similar, naming the paragraph numbers.
9
+ *
10
+ * Info severity only — near-duplicate prose within one section is worth a
11
+ * gentle nudge, not a hard failure. Deterministic: no clock, network, or
12
+ * randomness.
13
+ */
14
+ import type { InstructionFile, PromptCiIssue } from './types.js';
15
+ export declare function detectWithinSectionDedup(files: InstructionFile[]): PromptCiIssue[];
16
+ //# sourceMappingURL=within-section-dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"within-section-dedup.d.ts","sourceRoot":"","sources":["../src/within-section-dedup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAsB,aAAa,EAAE,MAAM,YAAY,CAAC;AA6FrF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,aAAa,EAAE,CA2DlF"}