@promptci/core 0.0.1 → 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 (205) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +29 -30
  3. package/dist/agent-practices.d.ts +2 -0
  4. package/dist/agent-practices.d.ts.map +1 -1
  5. package/dist/agent-practices.js +91 -51
  6. package/dist/agent-practices.js.map +1 -1
  7. package/dist/ai-config.d.ts +139 -0
  8. package/dist/ai-config.d.ts.map +1 -0
  9. package/dist/ai-config.js +523 -0
  10. package/dist/ai-config.js.map +1 -0
  11. package/dist/baseline.d.ts +17 -1
  12. package/dist/baseline.d.ts.map +1 -1
  13. package/dist/baseline.js +5 -1
  14. package/dist/baseline.js.map +1 -1
  15. package/dist/buried-critical.d.ts +17 -0
  16. package/dist/buried-critical.d.ts.map +1 -0
  17. package/dist/buried-critical.js +112 -0
  18. package/dist/buried-critical.js.map +1 -0
  19. package/dist/canonical-owner.d.ts.map +1 -1
  20. package/dist/canonical-owner.js +18 -8
  21. package/dist/canonical-owner.js.map +1 -1
  22. package/dist/command-validity.d.ts.map +1 -1
  23. package/dist/command-validity.js +53 -74
  24. package/dist/command-validity.js.map +1 -1
  25. package/dist/conflicts.d.ts.map +1 -1
  26. package/dist/conflicts.js +1 -42
  27. package/dist/conflicts.js.map +1 -1
  28. package/dist/context-analysis.d.ts.map +1 -1
  29. package/dist/context-analysis.js +13 -2
  30. package/dist/context-analysis.js.map +1 -1
  31. package/dist/context-bloat.d.ts +19 -0
  32. package/dist/context-bloat.d.ts.map +1 -1
  33. package/dist/context-bloat.js +82 -9
  34. package/dist/context-bloat.js.map +1 -1
  35. package/dist/context-optimizer.d.ts.map +1 -1
  36. package/dist/context-optimizer.js +15 -54
  37. package/dist/context-optimizer.js.map +1 -1
  38. package/dist/copilot-instructions-detector.d.ts +24 -0
  39. package/dist/copilot-instructions-detector.d.ts.map +1 -0
  40. package/dist/copilot-instructions-detector.js +145 -0
  41. package/dist/copilot-instructions-detector.js.map +1 -0
  42. package/dist/cursor-rules-detector.d.ts +17 -0
  43. package/dist/cursor-rules-detector.d.ts.map +1 -0
  44. package/dist/cursor-rules-detector.js +110 -0
  45. package/dist/cursor-rules-detector.js.map +1 -0
  46. package/dist/custom-rules.d.ts +52 -0
  47. package/dist/custom-rules.d.ts.map +1 -0
  48. package/dist/custom-rules.js +298 -0
  49. package/dist/custom-rules.js.map +1 -0
  50. package/dist/dead-references.js +11 -9
  51. package/dist/dead-references.js.map +1 -1
  52. package/dist/detectors.d.ts +1 -3
  53. package/dist/detectors.d.ts.map +1 -1
  54. package/dist/detectors.js +46 -53
  55. package/dist/detectors.js.map +1 -1
  56. package/dist/duplicates.d.ts.map +1 -1
  57. package/dist/duplicates.js +10 -5
  58. package/dist/duplicates.js.map +1 -1
  59. package/dist/evidence.d.ts +28 -0
  60. package/dist/evidence.d.ts.map +1 -0
  61. package/dist/evidence.js +38 -0
  62. package/dist/evidence.js.map +1 -0
  63. package/dist/fix-engine.d.ts +11 -0
  64. package/dist/fix-engine.d.ts.map +1 -1
  65. package/dist/fix-engine.js +88 -71
  66. package/dist/fix-engine.js.map +1 -1
  67. package/dist/frameworks/python.d.ts.map +1 -1
  68. package/dist/frameworks/python.js +5 -2
  69. package/dist/frameworks/python.js.map +1 -1
  70. package/dist/health-score.d.ts.map +1 -1
  71. package/dist/health-score.js +1 -0
  72. package/dist/health-score.js.map +1 -1
  73. package/dist/hooks-settings-detector.d.ts +17 -0
  74. package/dist/hooks-settings-detector.d.ts.map +1 -0
  75. package/dist/hooks-settings-detector.js +228 -0
  76. package/dist/hooks-settings-detector.js.map +1 -0
  77. package/dist/index.d.ts +22 -7
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +18 -6
  80. package/dist/index.js.map +1 -1
  81. package/dist/manifest-consistency.d.ts +6 -0
  82. package/dist/manifest-consistency.d.ts.map +1 -1
  83. package/dist/manifest-consistency.js +26 -5
  84. package/dist/manifest-consistency.js.map +1 -1
  85. package/dist/markdown-fences.d.ts +112 -0
  86. package/dist/markdown-fences.d.ts.map +1 -0
  87. package/dist/markdown-fences.js +174 -0
  88. package/dist/markdown-fences.js.map +1 -0
  89. package/dist/mcp-config-detector.d.ts +20 -0
  90. package/dist/mcp-config-detector.d.ts.map +1 -0
  91. package/dist/mcp-config-detector.js +237 -0
  92. package/dist/mcp-config-detector.js.map +1 -0
  93. package/dist/missing-context.d.ts.map +1 -1
  94. package/dist/missing-context.js +2 -52
  95. package/dist/missing-context.js.map +1 -1
  96. package/dist/model-budgets.d.ts +69 -0
  97. package/dist/model-budgets.d.ts.map +1 -0
  98. package/dist/model-budgets.js +110 -0
  99. package/dist/model-budgets.js.map +1 -0
  100. package/dist/negative-instructions.d.ts +26 -0
  101. package/dist/negative-instructions.d.ts.map +1 -0
  102. package/dist/negative-instructions.js +174 -0
  103. package/dist/negative-instructions.js.map +1 -0
  104. package/dist/path-containment.d.ts +12 -0
  105. package/dist/path-containment.d.ts.map +1 -0
  106. package/dist/path-containment.js +53 -0
  107. package/dist/path-containment.js.map +1 -0
  108. package/dist/project-type.d.ts +12 -2
  109. package/dist/project-type.d.ts.map +1 -1
  110. package/dist/project-type.js +25 -12
  111. package/dist/project-type.js.map +1 -1
  112. package/dist/prompt-cache.d.ts.map +1 -1
  113. package/dist/prompt-cache.js +26 -19
  114. package/dist/prompt-cache.js.map +1 -1
  115. package/dist/promptci-gitignore.d.ts +34 -0
  116. package/dist/promptci-gitignore.d.ts.map +1 -0
  117. package/dist/promptci-gitignore.js +42 -0
  118. package/dist/promptci-gitignore.js.map +1 -0
  119. package/dist/repo-context.d.ts +27 -0
  120. package/dist/repo-context.d.ts.map +1 -1
  121. package/dist/repo-context.js +42 -11
  122. package/dist/repo-context.js.map +1 -1
  123. package/dist/report.d.ts +1 -0
  124. package/dist/report.d.ts.map +1 -1
  125. package/dist/report.js +132 -61
  126. package/dist/report.js.map +1 -1
  127. package/dist/scan.d.ts.map +1 -1
  128. package/dist/scan.js +7 -3
  129. package/dist/scan.js.map +1 -1
  130. package/dist/scanner.d.ts +13 -1
  131. package/dist/scanner.d.ts.map +1 -1
  132. package/dist/scanner.js +49 -37
  133. package/dist/scanner.js.map +1 -1
  134. package/dist/security-pack.d.ts +20 -0
  135. package/dist/security-pack.d.ts.map +1 -1
  136. package/dist/security-pack.js +27 -10
  137. package/dist/security-pack.js.map +1 -1
  138. package/dist/skills-detector.d.ts +19 -0
  139. package/dist/skills-detector.d.ts.map +1 -0
  140. package/dist/skills-detector.js +203 -0
  141. package/dist/skills-detector.js.map +1 -0
  142. package/dist/stale-instructions.d.ts +4 -1
  143. package/dist/stale-instructions.d.ts.map +1 -1
  144. package/dist/stale-instructions.js +51 -54
  145. package/dist/stale-instructions.js.map +1 -1
  146. package/dist/subagents-detector.d.ts +19 -0
  147. package/dist/subagents-detector.d.ts.map +1 -0
  148. package/dist/subagents-detector.js +155 -0
  149. package/dist/subagents-detector.js.map +1 -0
  150. package/dist/suppression.d.ts.map +1 -1
  151. package/dist/suppression.js +11 -45
  152. package/dist/suppression.js.map +1 -1
  153. package/dist/types.d.ts +28 -3
  154. package/dist/types.d.ts.map +1 -1
  155. package/dist/types.js +25 -1
  156. package/dist/types.js.map +1 -1
  157. package/dist/vague-guidance.d.ts +15 -2
  158. package/dist/vague-guidance.d.ts.map +1 -1
  159. package/dist/vague-guidance.js +42 -40
  160. package/dist/vague-guidance.js.map +1 -1
  161. package/dist/windsurf-detector.d.ts +22 -0
  162. package/dist/windsurf-detector.d.ts.map +1 -0
  163. package/dist/windsurf-detector.js +87 -0
  164. package/dist/windsurf-detector.js.map +1 -0
  165. package/dist/within-section-dedup.d.ts +16 -0
  166. package/dist/within-section-dedup.d.ts.map +1 -0
  167. package/dist/within-section-dedup.js +153 -0
  168. package/dist/within-section-dedup.js.map +1 -0
  169. package/package.json +11 -8
  170. package/dist/cheap-model-routing.d.ts +0 -4
  171. package/dist/cheap-model-routing.d.ts.map +0 -1
  172. package/dist/cheap-model-routing.js +0 -43
  173. package/dist/cheap-model-routing.js.map +0 -1
  174. package/dist/cli-output-filter.d.ts +0 -16
  175. package/dist/cli-output-filter.d.ts.map +0 -1
  176. package/dist/cli-output-filter.js +0 -88
  177. package/dist/cli-output-filter.js.map +0 -1
  178. package/dist/context-cost.d.ts +0 -4
  179. package/dist/context-cost.d.ts.map +0 -1
  180. package/dist/context-cost.js +0 -70
  181. package/dist/context-cost.js.map +0 -1
  182. package/dist/context-recommender.d.ts +0 -3
  183. package/dist/context-recommender.d.ts.map +0 -1
  184. package/dist/context-recommender.js +0 -329
  185. package/dist/context-recommender.js.map +0 -1
  186. package/dist/llm.d.ts +0 -6
  187. package/dist/llm.d.ts.map +0 -1
  188. package/dist/llm.js +0 -67
  189. package/dist/llm.js.map +0 -1
  190. package/dist/mcp-detector.d.ts +0 -4
  191. package/dist/mcp-detector.d.ts.map +0 -1
  192. package/dist/mcp-detector.js +0 -131
  193. package/dist/mcp-detector.js.map +0 -1
  194. package/dist/native-tool-preference.d.ts +0 -20
  195. package/dist/native-tool-preference.d.ts.map +0 -1
  196. package/dist/native-tool-preference.js +0 -94
  197. package/dist/native-tool-preference.js.map +0 -1
  198. package/dist/output-verbosity.d.ts +0 -3
  199. package/dist/output-verbosity.d.ts.map +0 -1
  200. package/dist/output-verbosity.js +0 -83
  201. package/dist/output-verbosity.js.map +0 -1
  202. package/dist/product-boundary.d.ts +0 -11
  203. package/dist/product-boundary.d.ts.map +0 -1
  204. package/dist/product-boundary.js +0 -301
  205. package/dist/product-boundary.js.map +0 -1
@@ -1,5 +1,22 @@
1
1
  import * as path from 'node:path';
2
2
  import * as fs from 'node:fs/promises';
3
+ import { renderPromptCiGitignore } from './promptci-gitignore.js';
4
+ import { isWithinRoot } from './path-containment.js';
5
+ import { gitignoreLineMatchesTarget } from './security-pack.js';
6
+ /**
7
+ * True when an active (non-comment) line of the given .gitignore content
8
+ * already covers `target`, using the same segment-based matching as the
9
+ * security-pack detector. The fix side must agree with the detector: a
10
+ * substring test would let an entry like `mydist/` suppress adding `dist/`
11
+ * even though the detector (correctly) still flags `dist` as unignored.
12
+ */
13
+ function gitignoreCovers(content, target) {
14
+ return content
15
+ .split(/\r?\n/)
16
+ .map((l) => l.trim())
17
+ .filter((l) => l && !l.startsWith('#'))
18
+ .some((line) => gitignoreLineMatchesTarget(line, target));
19
+ }
3
20
  /**
4
21
  * Validates and resolves a path relative to the repo root to prevent path traversal.
5
22
  */
@@ -8,7 +25,7 @@ export function resolveSafePath(repoRoot, relativeOrAbsolutePath) {
8
25
  const resolvedPath = path.isAbsolute(relativeOrAbsolutePath)
9
26
  ? path.resolve(relativeOrAbsolutePath)
10
27
  : path.resolve(resolvedRoot, relativeOrAbsolutePath);
11
- if (!resolvedPath.startsWith(resolvedRoot)) {
28
+ if (!isWithinRoot(resolvedRoot, resolvedPath)) {
12
29
  throw new Error(`Path traversal detected: "${relativeOrAbsolutePath}" is outside repo root "${resolvedRoot}"`);
13
30
  }
14
31
  return resolvedPath;
@@ -29,11 +46,14 @@ export async function applyFixRecipe(issue, repoRoot) {
29
46
  catch {
30
47
  // file doesn't exist, which is fine
31
48
  }
32
- if (!content.includes('.promptci/')) {
49
+ if (!gitignoreCovers(content, '.promptci')) {
33
50
  const lineEnding = content.includes('\r\n') ? '\r\n' : '\n';
51
+ // BUG-7: write the baseline-preserving stanza, not a bare `.promptci/`
52
+ // — the latter also ignores baseline.json and breaks the CI ratchet.
53
+ const block = renderPromptCiGitignore(lineEnding);
34
54
  const suffix = content.endsWith('\n') || content.endsWith('\r')
35
- ? `.promptci/${lineEnding}`
36
- : `${lineEnding}.promptci/${lineEnding}`;
55
+ ? block
56
+ : `${lineEnding}${block}`;
37
57
  changes.push({
38
58
  filePath: gitignorePath,
39
59
  originalContent: content,
@@ -58,7 +78,7 @@ export async function applyFixRecipe(issue, repoRoot) {
58
78
  const m = /Directory "([^"]+)" exists/.exec(ev);
59
79
  if (m && m[1]) {
60
80
  const dirName = m[1];
61
- if (!content.includes(`${dirName}/`)) {
81
+ if (!gitignoreCovers(content, dirName)) {
62
82
  newLines += `${dirName}/${lineEnding}`;
63
83
  }
64
84
  }
@@ -75,45 +95,22 @@ export async function applyFixRecipe(issue, repoRoot) {
75
95
  }
76
96
  return changes;
77
97
  }
78
- // 3. Outdated Stale Year Replacement (2019-2023 -> 2026)
98
+ // 3. Stale years are intentionally NOT auto-fixable.
99
+ //
100
+ // BUG-14: this branch used to rewrite every year matching a hardcoded
101
+ // 2019–2023 alternation to the literal string '2026' across the whole
102
+ // flagged section. Three problems, any one of which is disqualifying:
103
+ // - the source range and the replacement year were both hardcoded, so the
104
+ // recipe was wrong from Jan 1 2027 onward;
105
+ // - the range disagreed with the detector's own (2019–2025), so the fixer
106
+ // silently skipped most of what the detector flagged; and
107
+ // - a bare year substitution cannot tell a stale instruction from a
108
+ // copyright line, a release date, or a version pin — it rewrote
109
+ // "© 2021", "shipped in 2020", and "the 2022 spec" alike.
110
+ //
111
+ // The finding now carries an advisory `fixRecipe` string instead (see
112
+ // stale-instructions.ts) and produces no automated edit.
79
113
  if (issue.id.startsWith('stale-') && issue.category === 'stale_instruction') {
80
- const STALE_YEAR_RE = /(?<![/-])\b(2019|2020|2021|2022|2023)\b(?![/-])/g;
81
- // Check if this issue is specifically about stale years
82
- const hasYearEvidence = issue.evidence.some(ev => ev.includes('Year reference(s) that may be outdated'));
83
- if (hasYearEvidence && issue.locations.length > 0) {
84
- const loc = issue.locations[0];
85
- const filePath = resolveSafePath(repoRoot, loc.filePath);
86
- let content = '';
87
- try {
88
- content = await fs.readFile(filePath, 'utf-8');
89
- }
90
- catch {
91
- return [];
92
- }
93
- const lines = content.split(/\r?\n/);
94
- const hasCRLF = content.includes('\r\n');
95
- const lineEnding = hasCRLF ? '\r\n' : '\n';
96
- const startIdx = (loc.startLine ?? 1) - 1;
97
- const endIdx = (loc.endLine ?? lines.length) - 1;
98
- let modified = false;
99
- for (let i = startIdx; i <= endIdx; i++) {
100
- if (i >= 0 && i < lines.length) {
101
- const original = lines[i];
102
- const updated = original.replace(STALE_YEAR_RE, '2026');
103
- if (updated !== original) {
104
- lines[i] = updated;
105
- modified = true;
106
- }
107
- }
108
- }
109
- if (modified) {
110
- changes.push({
111
- filePath,
112
- originalContent: content,
113
- newContent: lines.join(lineEnding),
114
- });
115
- }
116
- }
117
114
  return changes;
118
115
  }
119
116
  // 4. Duplicate Markdown Section Consolidation
@@ -125,12 +122,22 @@ export async function applyFixRecipe(issue, repoRoot) {
125
122
  }
126
123
  const canonicalPath = resolveSafePath(repoRoot, canonicalLoc.filePath);
127
124
  const canonicalBase = path.basename(canonicalPath);
128
- // 4b. In all other files containing duplicates, replace the section body with a pointer link
125
+ // 4b. Group the non-canonical locations by file. A single file can contain
126
+ // the duplicated section more than once; computing one FileChange per
127
+ // location from the original content and writing them in sequence would
128
+ // clobber all but the last, so each file is rewritten exactly once with
129
+ // every one of its duplicate ranges replaced (BUG: same-file collision).
130
+ const byFile = new Map();
129
131
  for (const loc of issue.locations) {
130
132
  const filePath = resolveSafePath(repoRoot, loc.filePath);
131
133
  if (filePath === canonicalPath)
132
134
  continue; // skip canonical file
133
- let content = '';
135
+ const list = byFile.get(filePath) ?? [];
136
+ list.push(loc);
137
+ byFile.set(filePath, list);
138
+ }
139
+ for (const [filePath, locs] of byFile) {
140
+ let content;
134
141
  try {
135
142
  content = await fs.readFile(filePath, 'utf-8');
136
143
  }
@@ -138,42 +145,52 @@ export async function applyFixRecipe(issue, repoRoot) {
138
145
  continue;
139
146
  }
140
147
  const lines = content.split(/\r?\n/);
141
- const hasCRLF = content.includes('\r\n');
142
- const lineEnding = hasCRLF ? '\r\n' : '\n';
143
- const startIdx = (loc.startLine ?? 1) - 1;
144
- const endIdx = (loc.endLine ?? lines.length) - 1;
145
- // Find relative path from current file to canonical file for clean Markdown links
148
+ const lineEnding = content.includes('\r\n') ? '\r\n' : '\n';
149
+ // Relative path from this file to the canonical file for a clean link.
146
150
  const relPath = path.relative(path.dirname(filePath), canonicalPath).replace(/\\/g, '/');
147
151
  const linkTarget = relPath.startsWith('.') ? relPath : `./${relPath}`;
148
- // Extract the section lines
149
- const sectionLines = lines.slice(startIdx, endIdx + 1);
150
- let headingLine = '';
151
- let replaceStartIdx = startIdx;
152
- // Check if the section starts with a heading line (e.g. "## Deployment")
153
- // If so, we preserve the heading and replace only the body below it.
154
- if (sectionLines.length > 0 && sectionLines[0].trim().startsWith('#')) {
155
- headingLine = sectionLines[0];
156
- replaceStartIdx = startIdx + 1;
157
- }
158
152
  const pointerText = `See canonical instructions in [${canonicalBase}](${linkTarget}) for details.`;
159
- // Construct the new lines
160
- const prefixLines = lines.slice(0, replaceStartIdx);
161
- const suffixLines = lines.slice(endIdx + 1);
162
- let newSectionContent;
163
- if (headingLine) {
164
- newSectionContent = [pointerText];
165
- }
166
- else {
167
- newSectionContent = [pointerText];
153
+ // Replace each duplicate range bottom-up so an earlier (higher-line)
154
+ // replacement never shifts the indices of ranges still to be processed.
155
+ const ranges = locs
156
+ .map(loc => ({
157
+ startIdx: (loc.startLine ?? 1) - 1,
158
+ endIdx: (loc.endLine ?? lines.length) - 1,
159
+ }))
160
+ .sort((a, b) => b.startIdx - a.startIdx);
161
+ let working = lines;
162
+ for (const { startIdx, endIdx } of ranges) {
163
+ const sectionLines = working.slice(startIdx, endIdx + 1);
164
+ // Preserve a leading heading line (e.g. "## Deployment") and replace
165
+ // only the body below it; otherwise replace the whole range.
166
+ const hasHeading = sectionLines.length > 0 && sectionLines[0].trim().startsWith('#');
167
+ const replaceStartIdx = hasHeading ? startIdx + 1 : startIdx;
168
+ working = [
169
+ ...working.slice(0, replaceStartIdx),
170
+ pointerText,
171
+ ...working.slice(endIdx + 1),
172
+ ];
168
173
  }
169
- const finalLines = [...prefixLines, ...newSectionContent, ...suffixLines];
170
174
  changes.push({
171
175
  filePath,
172
176
  originalContent: content,
173
- newContent: finalLines.join(lineEnding),
177
+ newContent: working.join(lineEnding),
174
178
  });
175
179
  }
176
180
  }
177
181
  return changes;
178
182
  }
183
+ /**
184
+ * True when `promptci fix` may mechanically apply this issue's recipe.
185
+ *
186
+ * Driven by the explicit `autoApplySafe` flag the emitting detector sets — it is
187
+ * deliberately NOT `Boolean(issue.fixRecipe)`. Most `fixRecipe` strings are
188
+ * advisory prose that needs human judgment (stale years, framework/runtime
189
+ * guidance, agent-practices), and auto-applying them would corrupt files. Only
190
+ * the handful of recipes that `applyFixRecipe` implements as a mechanical,
191
+ * reversible edit are marked safe at their source.
192
+ */
193
+ export function isRepairable(issue) {
194
+ return issue.autoApplySafe === true;
195
+ }
179
196
  //# sourceMappingURL=fix-engine.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fix-engine.js","sourceRoot":"","sources":["../src/fix-engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"fix-engine.js","sourceRoot":"","sources":["../src/fix-engine.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../src/frameworks/python.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAkElE"}
1
+ {"version":3,"file":"python.d.ts","sourceRoot":"","sources":["../../src/frameworks/python.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,wBAAgB,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAqElE"}
@@ -4,7 +4,10 @@ export function detectPython(context) {
4
4
  const issues = [];
5
5
  const { manifests, repoRoot, files } = context;
6
6
  const hasPyProject = !!manifests.pyproject;
7
- const hasRequirements = fs.existsSync(path.join(repoRoot, 'requirements.txt'));
7
+ // BUG-004: requirements.txt content is read once, asynchronously, while the
8
+ // RepoContext is built — the detector must not do synchronous disk I/O inside
9
+ // the scan pipeline. Presence is derived from that captured content.
10
+ const hasRequirements = manifests.requirements !== undefined;
8
11
  const hasPipfile = fs.existsSync(path.join(repoRoot, 'Pipfile'));
9
12
  const hasCondaYaml = fs.existsSync(path.join(repoRoot, 'environment.yml'));
10
13
  if (!hasPyProject && !hasRequirements && !hasPipfile && !hasCondaYaml) {
@@ -12,7 +15,7 @@ export function detectPython(context) {
12
15
  }
13
16
  // Check for missing pytest guidance if pytest is in deps
14
17
  const isPytestInDeps = (manifests.pyproject?.includes('pytest') ||
15
- (hasRequirements && fs.readFileSync(path.join(repoRoot, 'requirements.txt'), 'utf-8').includes('pytest')));
18
+ manifests.requirements?.includes('pytest'));
16
19
  if (isPytestInDeps) {
17
20
  const hasPytestGuidance = files.some(file => file.content.toLowerCase().includes('pytest') ||
18
21
  file.content.toLowerCase().includes('test guidance'));
@@ -1 +1 @@
1
- {"version":3,"file":"python.js","sourceRoot":"","sources":["../../src/frameworks/python.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"python.js","sourceRoot":"","sources":["../../src/frameworks/python.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"health-score.d.ts","sourceRoot":"","sources":["../src/health-score.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAgC,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAwBtF;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAoBlE;AAQD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAiE9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAuChE"}
1
+ {"version":3,"file":"health-score.d.ts","sourceRoot":"","sources":["../src/health-score.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAgC,aAAa,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAyBtF;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,CAoBlE;AAQD;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAiE9E;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAuChE"}
@@ -23,6 +23,7 @@ const CATEGORY_DEDUCTION_CAP = {
23
23
  stale_instruction: 15,
24
24
  duplicate: 20,
25
25
  vague_guidance: 10,
26
+ ai_config: 25, // skills/subagents/hooks/mcp/cursor config checks
26
27
  };
27
28
  /**
28
29
  * Compute a health score from 0–100 based on issue severity and confidence.
@@ -1 +1 @@
1
- {"version":3,"file":"health-score.js","sourceRoot":"","sources":["../src/health-score.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"health-score.js","sourceRoot":"","sources":["../src/health-score.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Hooks / Settings Detector (issue #23)
3
+ *
4
+ * Audits `.claude/settings.json` and `.claude/settings.local.json`:
5
+ *
6
+ * - Invalid JSON: the file will not load at all.
7
+ * - Hook commands referencing local scripts that do not exist in the repo.
8
+ * - Dangerous hook patterns: piping a remote download straight into a shell
9
+ * (`curl … | sh`), and unquoted `$CLAUDE_PROJECT_DIR` path expansions.
10
+ *
11
+ * Hook commands run automatically on tool events, so a broken or unsafe command
12
+ * is higher-stakes than a stale doc line. Deterministic and offline.
13
+ */
14
+ import type { RepoContext } from './repo-context.js';
15
+ import type { PromptCiIssue } from './types.js';
16
+ export declare function detectHooksSettings(context: RepoContext): PromptCiIssue[];
17
+ //# sourceMappingURL=hooks-settings-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-settings-detector.d.ts","sourceRoot":"","sources":["../src/hooks-settings-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA0IhD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CAyFzE"}
@@ -0,0 +1,228 @@
1
+ /**
2
+ * Hooks / Settings Detector (issue #23)
3
+ *
4
+ * Audits `.claude/settings.json` and `.claude/settings.local.json`:
5
+ *
6
+ * - Invalid JSON: the file will not load at all.
7
+ * - Hook commands referencing local scripts that do not exist in the repo.
8
+ * - Dangerous hook patterns: piping a remote download straight into a shell
9
+ * (`curl … | sh`), and unquoted `$CLAUDE_PROJECT_DIR` path expansions.
10
+ *
11
+ * Hook commands run automatically on tool events, so a broken or unsafe command
12
+ * is higher-stakes than a stale doc line. Deterministic and offline.
13
+ */
14
+ import { readTextWithinRoot, isFileWithinRoot, shortHash, lineOf, withScannerPaths, SCRIPT_EXT_RE, aiConfigIssue as base, } from './ai-config.js';
15
+ /** curl/wget piped straight into a shell — the classic remote-code-execution footgun. */
16
+ const CURL_PIPE_SH_RE = /\b(curl|wget)\b[^|]*\|\s*(sudo\s+)?(sh|bash|zsh|dash)\b/i;
17
+ function id(kind, key) {
18
+ return `ai-config-hook-${kind}-${shortHash(key)}`;
19
+ }
20
+ /** Recursively collect `{ type: 'command', command }` hook entries, tagged with their event key. */
21
+ function collectCommandHooks(hooks, event, out) {
22
+ if (Array.isArray(hooks)) {
23
+ for (const item of hooks)
24
+ collectCommandHooks(item, event, out);
25
+ return;
26
+ }
27
+ if (typeof hooks !== 'object' || hooks === null)
28
+ return;
29
+ const obj = hooks;
30
+ if (obj.type === 'command' && typeof obj.command === 'string') {
31
+ out.push({ command: obj.command, event });
32
+ }
33
+ for (const [key, value] of Object.entries(obj)) {
34
+ // When we recurse from the top-level `hooks` map, the key names the event
35
+ // (PreToolUse, PostToolUse, …); deeper down `hooks`/`matcher` keys are just
36
+ // structure, so we keep the nearest event label.
37
+ const nextEvent = event === '' ? key : event;
38
+ if (typeof value === 'object' && value !== null)
39
+ collectCommandHooks(value, nextEvent, out);
40
+ }
41
+ }
42
+ /** Interpreters whose script argument is the file they execute. */
43
+ const INTERPRETERS = new Set([
44
+ 'bash', 'sh', 'zsh', 'dash', 'node', 'deno', 'python', 'python3', 'ruby',
45
+ 'ts-node', 'tsx', 'pwsh', 'powershell',
46
+ ]);
47
+ /** Launchers that wrap another command (`npx tsx x.ts`, `timeout 5 bash x.sh`). */
48
+ const WRAPPERS = new Set([
49
+ 'npx', 'bunx', 'pnpm', 'yarn', 'uv', 'uvx', 'env', 'timeout', 'nice', 'sudo', 'exec', 'command',
50
+ ]);
51
+ /** Strip surrounding quotes, then a leading `$CLAUDE_PROJECT_DIR/` / `${CLAUDE_PROJECT_DIR}/`. */
52
+ function normalizeScriptToken(token) {
53
+ const unquoted = token.replace(/^['"]|['"]$/g, '');
54
+ return unquoted.replace(/^\$\{?CLAUDE_PROJECT_DIR\}?[/\\]/, '');
55
+ }
56
+ /**
57
+ * Extract repo-relative local script references from a hook command string.
58
+ *
59
+ * Each `&&`/`||`/`;`/`|`-chained segment is its own command. Within a segment,
60
+ * the *executed script* is verified — the segment's own executable, or (after
61
+ * any interpreter/wrapper prefix like `bash`, `npx tsx`, `timeout 5 node`) the
62
+ * first argument bearing a script extension, which naturally skips flags and
63
+ * their extension-less values (`node --max-old-space-size 4096 scripts/x.js`).
64
+ * Other tokens are checked only when explicitly relative (`./x`, `.claude/x`,
65
+ * `$CLAUDE_PROJECT_DIR/x`), so a lint hook like `eslint --fix src/foo.js` does
66
+ * not get its target argument flagged as a missing script.
67
+ */
68
+ function extractScriptRefs(command) {
69
+ const refs = new Set();
70
+ const add = (rawToken, executed) => {
71
+ if (rawToken.startsWith('-'))
72
+ return;
73
+ const unquoted = rawToken.replace(/^['"]|['"]$/g, '');
74
+ const token = normalizeScriptToken(rawToken);
75
+ if (!token || token.includes('$') || /[<>{}*?|"'`]/.test(token))
76
+ return; // still has a var/placeholder
77
+ if (token.startsWith('/') || /^[a-zA-Z]:[\\/]/.test(token) || /^https?:/i.test(token))
78
+ return; // absolute/url
79
+ if (token.includes('..'))
80
+ return;
81
+ if (!SCRIPT_EXT_RE.test(token))
82
+ return;
83
+ // Tested on the quote-stripped form so `"./scripts/x.sh"` still counts.
84
+ const explicitRel = unquoted.startsWith('./') || unquoted.startsWith('.claude/') ||
85
+ /^\$\{?CLAUDE_PROJECT_DIR\}?[/\\]/.test(unquoted);
86
+ if (executed || explicitRel)
87
+ refs.add(token.replace(/\\/g, '/'));
88
+ };
89
+ for (const segment of command.split(/&&|\|\||;|\|/)) {
90
+ const tokens = segment.trim().split(/\s+/).filter(Boolean);
91
+ if (tokens.length === 0)
92
+ continue;
93
+ const first = normalizeScriptToken(tokens[0]);
94
+ if (INTERPRETERS.has(first) || WRAPPERS.has(first)) {
95
+ // The executed script is the first argument that looks like a script
96
+ // file; flags and their extension-less values are skipped naturally.
97
+ for (let i = 1; i < tokens.length; i++) {
98
+ if (!tokens[i].startsWith('-') && SCRIPT_EXT_RE.test(normalizeScriptToken(tokens[i]))) {
99
+ add(tokens[i], true);
100
+ break;
101
+ }
102
+ }
103
+ }
104
+ else {
105
+ // The segment itself may be a direct script invocation (`./scripts/x.sh`).
106
+ add(tokens[0], true);
107
+ }
108
+ // Remaining tokens are verified only when explicitly relative.
109
+ for (let i = 1; i < tokens.length; i++)
110
+ add(tokens[i], false);
111
+ }
112
+ return [...refs];
113
+ }
114
+ /**
115
+ * True when the character at `index` sits inside a single- or double-quoted
116
+ * region of `command`. Used so `sh -c "cd $CLAUDE_PROJECT_DIR/x"` — quoted,
117
+ * space-safe — is not flagged as an unquoted expansion.
118
+ */
119
+ function insideQuotes(command, index) {
120
+ let quote = '';
121
+ for (let i = 0; i < index; i++) {
122
+ const c = command[i];
123
+ if (quote) {
124
+ if (c === quote)
125
+ quote = '';
126
+ }
127
+ else if (c === '"' || c === "'") {
128
+ quote = c;
129
+ }
130
+ }
131
+ return quote !== '';
132
+ }
133
+ /** Finds a `$CLAUDE_PROJECT_DIR/...` expansion that no quote region protects. */
134
+ function hasUnquotedProjectDir(command) {
135
+ for (const m of command.matchAll(/\$\{?CLAUDE_PROJECT_DIR\}?[/\\]/g)) {
136
+ if (!insideQuotes(command, m.index))
137
+ return true;
138
+ }
139
+ return false;
140
+ }
141
+ export function detectHooksSettings(context) {
142
+ const issues = [];
143
+ for (const filePath of context.aiConfig.settings) {
144
+ const raw = readTextWithinRoot(context.repoRoot, filePath);
145
+ if (raw === undefined)
146
+ continue;
147
+ let parsed;
148
+ try {
149
+ parsed = JSON.parse(raw);
150
+ }
151
+ catch (err) {
152
+ issues.push(base({
153
+ id: id('invalid-json', filePath),
154
+ severity: 'high',
155
+ title: 'Settings file is not valid JSON',
156
+ summary: `${filePath} could not be parsed as JSON, so Claude Code cannot load its hooks or permissions.`,
157
+ filePaths: [filePath],
158
+ locations: [{ filePath, startLine: 1, endLine: 1 }],
159
+ evidence: [`Parse error: ${err.message}`],
160
+ recommendation: 'Fix the JSON syntax (trailing commas and comments are not allowed in settings.json).',
161
+ confidence: 0.95,
162
+ }));
163
+ continue;
164
+ }
165
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
166
+ continue;
167
+ const hooks = parsed.hooks;
168
+ if (hooks === undefined)
169
+ continue;
170
+ const commandHooks = [];
171
+ collectCommandHooks(hooks, '', commandHooks);
172
+ const reportedMissing = new Set();
173
+ for (const { command, event } of commandHooks) {
174
+ const line = lineOf(raw, command);
175
+ // Dangerous: remote download piped into a shell.
176
+ if (CURL_PIPE_SH_RE.test(command)) {
177
+ issues.push(base({
178
+ id: id('curl-pipe-sh', `${filePath}|${command}`),
179
+ severity: 'high',
180
+ impact: 'high',
181
+ title: 'Hook pipes a remote download into a shell',
182
+ summary: `A ${event || 'hook'} command in ${filePath} pipes \`curl\`/\`wget\` output directly into a shell, running whatever the remote host serves with your permissions.`,
183
+ filePaths: [filePath],
184
+ locations: [{ filePath, startLine: line, endLine: line }],
185
+ evidence: [`Command: ${command.slice(0, 160)}`],
186
+ recommendation: 'Download to a file, review it, and pin a checksum before executing — never pipe a network fetch straight into sh/bash.',
187
+ confidence: 0.85,
188
+ }));
189
+ }
190
+ // Footgun: unquoted $CLAUDE_PROJECT_DIR path expansion.
191
+ if (hasUnquotedProjectDir(command)) {
192
+ issues.push(base({
193
+ id: id('unquoted-project-dir', `${filePath}|${command}`),
194
+ severity: 'info',
195
+ title: 'Hook uses an unquoted $CLAUDE_PROJECT_DIR path',
196
+ summary: `A ${event || 'hook'} command in ${filePath} expands \`$CLAUDE_PROJECT_DIR\` unquoted; if the project path contains a space the command breaks or runs the wrong file.`,
197
+ filePaths: [filePath],
198
+ locations: [{ filePath, startLine: line, endLine: line }],
199
+ evidence: [`Command: ${command.slice(0, 160)}`],
200
+ recommendation: 'Wrap the path in double quotes, e.g. `"$CLAUDE_PROJECT_DIR/script.sh"`.',
201
+ confidence: 0.5,
202
+ }));
203
+ }
204
+ // Missing local script references.
205
+ for (const ref of extractScriptRefs(command)) {
206
+ if (isFileWithinRoot(context.repoRoot, ref))
207
+ continue;
208
+ const key = `${filePath}|${ref}`;
209
+ if (reportedMissing.has(key))
210
+ continue;
211
+ reportedMissing.add(key);
212
+ issues.push(base({
213
+ id: id('missing-script', key),
214
+ title: 'Hook command references a script that does not exist',
215
+ summary: `A ${event || 'hook'} command in ${filePath} runs \`${ref}\`, but that file is not present in the repository.`,
216
+ filePaths: [filePath],
217
+ locations: [{ filePath, startLine: line, endLine: line }],
218
+ evidence: [`Referenced script: ${ref}`, `Command: ${command.slice(0, 160)}`],
219
+ recommendation: 'Add the script, fix the path, or remove the hook.',
220
+ confidence: 0.75,
221
+ }));
222
+ }
223
+ }
224
+ }
225
+ // Scanner-form paths so inline suppressions can match (see withScannerPaths).
226
+ return withScannerPaths(context.repoRoot, issues);
227
+ }
228
+ //# sourceMappingURL=hooks-settings-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooks-settings-detector.js","sourceRoot":"","sources":["../src/hooks-settings-detector.ts"],"names":[],"mappings":"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"}