@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/scanner.js CHANGED
@@ -1,12 +1,33 @@
1
1
  import fg from 'fast-glob';
2
+ import * as fsSync from 'node:fs';
2
3
  import * as fs from 'node:fs/promises';
3
4
  import * as path from 'node:path';
5
+ import { scanFencedLines } from './markdown-fences.js';
6
+ import { isWithinRoot, realPath, realPathWithinRoot } from './path-containment.js';
7
+ import { createGitSymlinkOracle } from './git-symlinks.js';
4
8
  const DEFAULT_PATTERNS = [
5
9
  // Core AI instruction files
6
10
  'CLAUDE.md',
7
11
  'AGENTS.md',
8
12
  '.cursorrules',
9
13
  '.windsurfrules',
14
+ // Gemini CLI. Root only, like CLAUDE.md/AGENTS.md above.
15
+ 'GEMINI.md',
16
+ // Cline: a single `.clinerules` file OR a `.clinerules/` directory of
17
+ // markdown rule files (fast-glob's onlyFiles default means the bare pattern
18
+ // matches only the file form; defaultPatterns() drops the directory globs
19
+ // when `.clinerules` is a file). `.clinerules/workflows/` holds on-demand
20
+ // slash-command workflows, not always-loaded rules, so it is left out.
21
+ '.clinerules',
22
+ '.clinerules/**/*.md',
23
+ '!.clinerules/workflows/**',
24
+ // Agent persona files (SOUL.md, USER.md, TOOLS.md). Repo ROOT only: the
25
+ // names are generic enough that a nested `docs/USER.md` is far more likely a
26
+ // user guide than an agent persona. deriveFileType enforces the same rule
27
+ // when an explicit `include` pattern pulls a nested copy in.
28
+ 'SOUL.md',
29
+ 'USER.md',
30
+ 'TOOLS.md',
10
31
  // Cursor IDE rules
11
32
  '.cursor/rules/**',
12
33
  // GitHub Copilot instructions (legacy + new per-file format)
@@ -40,17 +61,54 @@ const DEFAULT_PATTERNS = [
40
61
  // dir used by other agent tooling) — these are full copies of the repo and
41
62
  // would otherwise be scanned as duplicate instruction-file trees.
42
63
  const IGNORE_DIRS = ['.git', 'node_modules', 'Library', 'Temp', 'bin', 'obj', 'dist', 'build', 'worktrees', '.worktrees'];
43
- const MAX_FILE_SIZE = 500 * 1024;
44
- const BINARY_CHECK_BYTES = 512;
45
- function deriveFileType(absPath) {
46
- const base = path.basename(absPath);
47
- const norm = absPath.replace(/\\/g, '/');
64
+ // Exported so ai_config discovery (ai-config.ts) applies the exact same
65
+ // size/binary policy as this scanner — one definition of "scannable file".
66
+ export const MAX_FILE_SIZE = 500 * 1024;
67
+ export const BINARY_CHECK_BYTES = 512;
68
+ const PERSONA_ROOT_PATHS = new Set(['/SOUL.md', '/USER.md', '/TOOLS.md']);
69
+ // Takes the repo-root-relative path (not the absolute path): classification must
70
+ // depend only on where a file sits INSIDE the scanned repo. Using the absolute
71
+ // path let the checkout location leak in — a repo checked out under an external
72
+ // `.../.claude/worktrees/<branch>/` path (e.g. a Claude Code worktree) made every
73
+ // scanned file match `/.claude/` and get classified 'claude', producing bogus
74
+ // findings like "No behavioral guidance in CLAUDE.md" against README.md.
75
+ //
76
+ // A root-relative path has no leading slash (e.g. `.claude/foo.md`), so normalise
77
+ // to a leading-slash, forward-slash form before the directory-substring checks.
78
+ function deriveFileType(relPath) {
79
+ const norm = '/' + relPath.replace(/\\/g, '/').replace(/^\/+/, '');
80
+ const base = norm.slice(norm.lastIndexOf('/') + 1);
48
81
  if (base === 'AGENTS.md')
49
82
  return 'agents';
50
83
  if (base === '.cursorrules' || norm.includes('/.cursor/rules/'))
51
84
  return 'cursor';
85
+ // BUG-19: `.windsurfrules` is in DEFAULT_PATTERNS above, so it was always read
86
+ // and counted toward context-bloat totals — but with no branch here it fell
87
+ // through to 'unknown', which every filetype-gated detector's allowlist omits.
88
+ // The file was scanned and then silently ignored by ~6 detectors.
89
+ if (base === '.windsurfrules')
90
+ return 'windsurf';
52
91
  if (base === 'copilot-instructions.md' || norm.includes('/.github/instructions/'))
53
92
  return 'copilot';
93
+ // Gemini/Cline/persona files are matched anchored at the scan ROOT (`norm` is
94
+ // leading-slash root-relative), never by basename or directory substring.
95
+ // That is what they are discovered as, and it guarantees no file an earlier
96
+ // release already discovered changes type: `.claude/skills/x/GEMINI.md` stays
97
+ // an on-demand 'skill', `prompts/USER.md` stays 'prompt'.
98
+ if (norm === '/GEMINI.md')
99
+ return 'gemini';
100
+ if (norm === '/.clinerules' || norm.startsWith('/.clinerules/'))
101
+ return 'cline';
102
+ if (PERSONA_ROOT_PATHS.has(norm))
103
+ return 'persona';
104
+ // Load-on-demand Claude Code config surfaces. Classified before the generic
105
+ // '/.claude/' → 'claude' rule below so a skill's SKILL.md and its reference
106
+ // files (and every agent definition) are treated as on-demand, not as
107
+ // always-loaded prose — the ai_config detectors audit them structurally.
108
+ if (norm.includes('/.claude/agents/'))
109
+ return 'agent';
110
+ if (norm.includes('/.claude/skills/'))
111
+ return 'skill';
54
112
  if (base === 'CLAUDE.md' || norm.includes('/.claude/'))
55
113
  return 'claude';
56
114
  if (base === 'README.md')
@@ -78,7 +136,15 @@ function splitLines(content) {
78
136
  }
79
137
  return rawLines;
80
138
  }
81
- function parseSections(content, filePath) {
139
+ /**
140
+ * Splits markdown into heading-delimited sections.
141
+ *
142
+ * Exported because context-optimizer previously carried a forked copy with a
143
+ * naive fence toggle (any ``` line flipped the flag, so ~~~ fences and longer
144
+ * ``` runs desynchronised it) — and that copy decided which sections get moved
145
+ * out of a user's instruction files.
146
+ */
147
+ export function parseSections(content, filePath, relativePath) {
82
148
  const lines = splitLines(content);
83
149
  const sections = [];
84
150
  let currentHeading = undefined;
@@ -90,6 +156,7 @@ function parseSections(content, filePath) {
90
156
  sections.push({
91
157
  id,
92
158
  filePath,
159
+ ...(relativePath !== undefined ? { relativePath } : {}),
93
160
  heading: currentHeading,
94
161
  startLine: currentStartLine,
95
162
  endLine,
@@ -97,35 +164,13 @@ function parseSections(content, filePath) {
97
164
  normalizedText: text.toLowerCase().trim(),
98
165
  });
99
166
  };
100
- let inCodeBlock = false;
101
- let fenceChar = null;
102
- let fenceLen = 0;
167
+ // Fenced lines are kept in the section text but never read as headings —
168
+ // otherwise a bash comment (`# text`) inside a code block splits the section.
169
+ const fenceLines = scanFencedLines(content);
103
170
  for (let i = 0; i < lines.length; i++) {
104
171
  const lineNum = i + 1;
105
172
  const line = lines[i] ?? '';
106
- // Track fenced code blocks so bash comments (`# text`) are not treated as
107
- // headings. A closing fence must use the same fence character (``` vs ~~~
108
- // are not interchangeable) and be at least as long as the opening fence,
109
- // per CommonMark. Up to 3 leading spaces are allowed on either fence.
110
- if (!inCodeBlock) {
111
- const openMatch = /^ {0,3}([`~]{3,})/.exec(line);
112
- if (openMatch) {
113
- inCodeBlock = true;
114
- fenceChar = openMatch[1][0] ?? null;
115
- fenceLen = openMatch[1].length;
116
- currentLines.push(line);
117
- continue;
118
- }
119
- }
120
- else {
121
- const closeMatch = /^ {0,3}([`~]{3,})\s*$/.exec(line);
122
- if (closeMatch && closeMatch[1][0] === fenceChar && closeMatch[1].length >= fenceLen) {
123
- inCodeBlock = false;
124
- fenceChar = null;
125
- fenceLen = 0;
126
- currentLines.push(line);
127
- continue;
128
- }
173
+ if (fenceLines[i]?.inFence) {
129
174
  currentLines.push(line);
130
175
  continue;
131
176
  }
@@ -147,7 +192,7 @@ function parseSections(content, filePath) {
147
192
  }
148
193
  return sections;
149
194
  }
150
- function isBinary(buffer) {
195
+ export function isBinary(buffer) {
151
196
  const end = Math.min(buffer.length, BINARY_CHECK_BYTES);
152
197
  for (let i = 0; i < end; i++) {
153
198
  if (buffer[i] === 0)
@@ -155,62 +200,314 @@ function isBinary(buffer) {
155
200
  }
156
201
  return false;
157
202
  }
158
- export async function scanFiles(input) {
203
+ const CLINE_DIR_PATTERNS = new Set([
204
+ '.clinerules/**/*.md',
205
+ '!.clinerules/workflows/**',
206
+ ]);
207
+ /**
208
+ * DEFAULT_PATTERNS, minus the `.clinerules/` directory globs unless
209
+ * `.clinerules` really is a directory. fast-glob scandirs `.clinerules` to
210
+ * expand them, and a FILE of that name (Cline's single-file form) makes it
211
+ * throw ENOTDIR — which scanFiles' catch turned into an empty scan of the
212
+ * WHOLE repo. `suppressErrors` now contains that too; dropping the globs
213
+ * keeps the default scan from relying on it.
214
+ */
215
+ async function defaultPatterns(repoRoot) {
216
+ let clineIsDir = false;
217
+ try {
218
+ clineIsDir = (await fs.stat(path.join(repoRoot, '.clinerules'))).isDirectory();
219
+ }
220
+ catch {
221
+ // absent — the directory globs would match nothing anyway
222
+ }
223
+ return clineIsDir ? DEFAULT_PATTERNS : DEFAULT_PATTERNS.filter((p) => !CLINE_DIR_PATTERNS.has(p));
224
+ }
225
+ /** The canonical real path, or null when it does not exist. Kept apart from `realPath` (used only to group names). */
226
+ function resolveReal(p) {
227
+ try {
228
+ return fsSync.realpathSync.native(p);
229
+ }
230
+ catch {
231
+ return null;
232
+ }
233
+ }
234
+ /**
235
+ * Read one instruction file.
236
+ *
237
+ * Threat model: the scanner runs on checkouts it does not trust (a fork's PR in
238
+ * CI), where the committer controls every symlink in the tree. A link must never
239
+ * make the scanner read a file outside the repo. So the path is resolved to its
240
+ * real path ONCE, that real path is checked against the repo root, and the file
241
+ * is then opened by the REAL path (never the link) with O_NOFOLLOW where the OS
242
+ * has it, and stat'ed and read from that one handle. A link swapped in after the
243
+ * check cannot redirect the read. What remains is a race against a writer that
244
+ * can already modify the working tree during the scan, which is outside this
245
+ * guard's scope.
246
+ */
247
+ async function readInstructionFile(repoRoot, realRoot, absPath, typeRelPath) {
248
+ const real = resolveReal(absPath);
249
+ if (real === null || !isWithinRoot(realRoot, real))
250
+ return undefined;
251
+ let handle;
252
+ try {
253
+ const noFollow = fsSync.constants.O_NOFOLLOW ?? 0;
254
+ handle = await fs.open(real, fsSync.constants.O_RDONLY | noFollow);
255
+ const stat = await handle.stat();
256
+ if (!stat.isFile())
257
+ return undefined;
258
+ if (stat.size > MAX_FILE_SIZE)
259
+ return undefined;
260
+ const buffer = await handle.readFile();
261
+ if (isBinary(buffer))
262
+ return undefined;
263
+ const content = buffer.toString('utf-8');
264
+ // Root-relative, forward slashes: the location-independent form finding
265
+ // ids hash (finding-id.ts), identical on every OS and checkout path.
266
+ const relativePath = path.relative(repoRoot, absPath).replace(/\\/g, '/');
267
+ const sections = parseSections(content, absPath, relativePath);
268
+ const lineCount = splitLines(content).length;
269
+ const charCount = content.length;
270
+ return {
271
+ path: absPath,
272
+ relativePath,
273
+ fileType: deriveFileType(typeRelPath),
274
+ content,
275
+ sections,
276
+ lineCount,
277
+ charCount,
278
+ estimatedTokens: Math.round(charCount / 4),
279
+ };
280
+ }
281
+ catch {
282
+ // skip unreadable files
283
+ return undefined;
284
+ }
285
+ finally {
286
+ await handle?.close().catch(() => undefined);
287
+ }
288
+ }
289
+ /**
290
+ * Longest trimmed content (characters) of a file that stands in for a symlink.
291
+ * A path longer than this is not a link target anyone wrote by hand (MAX_PATH).
292
+ */
293
+ const MAX_TEXT_SYMLINK_CHARS = 260;
294
+ /** A chain of text symlinks followed to the real file (`A -> B -> C`); longer chains are left as plain files. */
295
+ const MAX_TEXT_SYMLINK_HOPS = 8;
296
+ /**
297
+ * The repo-relative path a "text symlink" points to, or undefined when the file
298
+ * is not one. A checkout without link support (Windows without `core.symlinks`)
299
+ * materializes a committed symlink as a small regular file whose whole content
300
+ * is the link's target path (`CLAUDE.md` containing `AGENTS.md`). Such a file is
301
+ * recognised only when ALL of these hold, so a genuine short instruction file is
302
+ * never mistaken for one:
303
+ * - its trimmed content is a single line of at most {@link MAX_TEXT_SYMLINK_CHARS} characters;
304
+ * - that line is a relative path (no absolute or drive prefix, no backslashes, no `..` out of the repo);
305
+ * - the path, resolved relative to the link's own directory exactly as git stores a link
306
+ * target (`../AGENTS.md` from `docs/CLAUDE.md`, `./AGENTS.md` from the root), is EXACTLY the
307
+ * repo-relative path of another discovered file;
308
+ * - the repository itself says the file is a symlink (see git-symlinks.ts): its index entry has
309
+ * mode 120000, or, with no readable index, its own config has `core.symlinks = false`.
310
+ * A hand-written one-line pointer file in a repository that tracks it as a regular file
311
+ * stays a real file.
312
+ */
313
+ function textSymlinkTarget(file, discovered, oracle) {
314
+ const rel = file.relativePath;
315
+ if (rel === undefined || file.charCount > MAX_TEXT_SYMLINK_CHARS + 16)
316
+ return undefined;
317
+ const text = file.content.replace(/^\u{FEFF}/u, '').trim();
318
+ if (text === '' || text.length > MAX_TEXT_SYMLINK_CHARS || /[\r\n]/.test(text))
319
+ return undefined;
320
+ if (text.startsWith('/') || /^[A-Za-z]:/.test(text) || text.includes('\\'))
321
+ return undefined;
322
+ const target = path.posix.normalize(path.posix.join(path.posix.dirname(rel), text));
323
+ if (target === '..' || target.startsWith('../') || target === rel || !discovered.has(target))
324
+ return undefined;
325
+ return oracle.isSymlink(rel) ? target : undefined;
326
+ }
327
+ /** `link` as an alias of `real`: the real content and sections (parsed under the link's own path), the link's name and type. */
328
+ function aliasOfReal(link, real) {
329
+ return {
330
+ ...real,
331
+ path: link.path,
332
+ relativePath: link.relativePath,
333
+ fileType: link.fileType,
334
+ sections: parseSections(real.content, link.path, link.relativePath),
335
+ aliasOf: real.relativePath,
336
+ };
337
+ }
338
+ /**
339
+ * Make the text symlinks among `files` aliases of the file they name, so a
340
+ * Windows checkout without link support scans like the Linux one: the real file
341
+ * is scanned once, the link name is an alias carrying the real content (so tool-
342
+ * specific checks run for it under its own type) and is listed with zeroed counts.
343
+ * Chains (`A -> B -> C`) resolve to the final real file; a cycle, an over-long chain
344
+ * or a target that is not a discovered file leaves the file as it was. Aliases that
345
+ * pointed at a file which turned out to be a link are re-pointed at the real one.
346
+ */
347
+ export function foldTextSymlinks(files, aliases, oracle) {
348
+ const byRelativePath = new Map();
349
+ for (const file of files)
350
+ if (file.relativePath !== undefined)
351
+ byRelativePath.set(file.relativePath, file);
352
+ const links = new Map();
353
+ for (const file of files) {
354
+ const target = textSymlinkTarget(file, byRelativePath, oracle);
355
+ if (target !== undefined)
356
+ links.set(file.relativePath, target);
357
+ }
358
+ if (links.size === 0)
359
+ return { files, aliases };
360
+ // Follow each link to its real file: at most MAX_TEXT_SYMLINK_HOPS links in a row.
361
+ const real = new Map();
362
+ for (const rel of links.keys()) {
363
+ let current = links.get(rel);
364
+ let hops = 1;
365
+ while (links.has(current) && hops < MAX_TEXT_SYMLINK_HOPS) {
366
+ current = links.get(current);
367
+ hops++;
368
+ }
369
+ if (!links.has(current))
370
+ real.set(rel, byRelativePath.get(current));
371
+ }
372
+ if (real.size === 0)
373
+ return { files, aliases };
374
+ const folded = files.filter((file) => file.relativePath === undefined || !real.has(file.relativePath));
375
+ // An alias that pointed at a file which turned out to be a link now stands for the real file: rebuilt in full, never left with the stub's text.
376
+ const out = aliases.map((alias) => {
377
+ const target = alias.aliasOf === undefined ? undefined : real.get(alias.aliasOf);
378
+ return target === undefined ? alias : aliasOfReal(alias, target);
379
+ });
380
+ for (const [rel, target] of real)
381
+ out.push(aliasOfReal(byRelativePath.get(rel), target));
382
+ return { files: folded, aliases: out };
383
+ }
384
+ /**
385
+ * Discover and read instruction files, plus the symlinked names that point at
386
+ * them.
387
+ *
388
+ * fast-glob with `followSymbolicLinks: false` never lists a symlinked FILE as
389
+ * a file (its dirent is a symlink), so `CLAUDE.md -> AGENTS.md` — a very common
390
+ * way to share one rule set between tools — used to be skipped entirely. Names
391
+ * are grouped by REAL path, so the same content is scanned once whether it is
392
+ * reached through a symlinked file or a linked directory
393
+ * (`.clinerules -> .cursor/rules`):
394
+ *
395
+ * - A name whose real path leaves the repo is skipped (never read).
396
+ * - A name that resolves to a file already discovered is an ALIAS: it is
397
+ * returned in `aliases` (with `aliasOf` naming the canonical file) and its
398
+ * content is NOT scanned a second time, so findings are not double-counted
399
+ * and a file is never reported as a duplicate of its own symlink. The
400
+ * canonical name is the one that reaches the file without crossing a symlink.
401
+ * - A link whose target was not discovered (an in-repo file outside the
402
+ * patterns, or excluded) is scanned under the LINK's path and typed by the
403
+ * link's name. Several links to the same such target: the first (by path)
404
+ * is scanned, the rest are aliases of it.
405
+ * - A small regular file that is nothing but the repo-relative path of another
406
+ * discovered file (`CLAUDE.md` containing `AGENTS.md`) is how a checkout without
407
+ * symlink support (Windows without `core.symlinks`) materializes a link; it is
408
+ * folded into an alias of that file, so both platforms scan the same repo alike
409
+ * (see {@link foldTextSymlinks}).
410
+ */
411
+ export async function scanFilesWithAliases(input) {
159
412
  const repoRoot = path.resolve(input.repoPath);
160
- const patterns = (input.include && input.include.length > 0) ? input.include : DEFAULT_PATTERNS;
413
+ const realRoot = resolveReal(repoRoot) ?? repoRoot;
414
+ const patterns = (input.include && input.include.length > 0)
415
+ ? input.include
416
+ : await defaultPatterns(repoRoot);
161
417
  const ignorePatterns = [
162
418
  ...IGNORE_DIRS.map((d) => `**/${d}/**`),
163
419
  ...(input.exclude ?? []),
164
420
  ];
165
- let relativePaths;
421
+ let entries;
166
422
  try {
167
- relativePaths = await fg(patterns, {
423
+ entries = await fg(patterns, {
168
424
  cwd: repoRoot,
169
425
  ignore: ignorePatterns,
170
426
  dot: true,
171
427
  absolute: false,
428
+ // `onlyFiles: false` + `objectMode` so symlinked entries are listed;
429
+ // regular files and links are told apart by dirent below.
430
+ onlyFiles: false,
431
+ objectMode: true,
172
432
  followSymbolicLinks: false,
433
+ // Skip unreadable entries instead of failing the whole glob: an explicit
434
+ // `include: [".clinerules/**"]` with a `.clinerules` FILE (ENOTDIR), or
435
+ // one permission-denied directory, used to empty the entire scan via the
436
+ // catch below.
437
+ suppressErrors: true,
173
438
  });
174
439
  }
175
440
  catch {
176
- return [];
441
+ return { files: [], aliases: [] };
177
442
  }
178
- const results = [];
179
- for (const relPath of relativePaths) {
443
+ const fileRels = [];
444
+ const linkRels = [];
445
+ for (const entry of entries) {
446
+ if (entry.dirent.isSymbolicLink())
447
+ linkRels.push(entry.path);
448
+ else if (entry.dirent.isFile())
449
+ fileRels.push(entry.path);
450
+ }
451
+ linkRels.sort();
452
+ const files = [];
453
+ const aliases = [];
454
+ // Real path -> the file whose content represents it.
455
+ const canonicalByReal = new Map();
456
+ // Path traversal guard: skip anything a glob result resolves outside the
457
+ // root — lexically, or through a symlink. With `followSymbolicLinks: false`
458
+ // fast-glob never descends into a linked directory, but it does START its
459
+ // walk at a pattern's base directory even when that directory is a link
460
+ // (`.cursor/rules -> /elsewhere`), and every file below it would then be
461
+ // read through.
462
+ const regular = [];
463
+ for (const relPath of fileRels) {
180
464
  const absPath = path.resolve(repoRoot, relPath);
181
- // Path traversal guard
182
- const relative = path.relative(repoRoot, absPath);
183
- if (relative.startsWith('..') || path.isAbsolute(relative)) {
465
+ if (!isWithinRoot(repoRoot, absPath) || !realPathWithinRoot(repoRoot, absPath))
466
+ continue;
467
+ const real = realPath(absPath);
468
+ // "Direct": reaches the file without crossing a symlink, so it is the natural canonical name
469
+ // when a linked directory makes the same file visible under two paths.
470
+ regular.push({ relPath, absPath, real, direct: real !== null && real === path.join(realRoot, relPath) });
471
+ }
472
+ regular.sort((a, b) => Number(b.direct) - Number(a.direct) || a.relPath.localeCompare(b.relPath));
473
+ for (const { relPath, absPath, real } of regular) {
474
+ const file = await readInstructionFile(repoRoot, realRoot, absPath, relPath);
475
+ if (!file)
476
+ continue;
477
+ const canonical = real !== null ? canonicalByReal.get(real) : undefined;
478
+ if (canonical) {
479
+ aliases.push({ ...file, aliasOf: canonical.relativePath });
184
480
  continue;
185
481
  }
186
- try {
187
- const stat = await fs.stat(absPath);
188
- if (!stat.isFile())
189
- continue;
190
- if (stat.size > MAX_FILE_SIZE)
191
- continue;
192
- const buffer = await fs.readFile(absPath);
193
- if (isBinary(buffer))
194
- continue;
195
- const content = buffer.toString('utf-8');
196
- const sections = parseSections(content, absPath);
197
- const lineCount = splitLines(content).length;
198
- const charCount = content.length;
199
- results.push({
200
- path: absPath,
201
- fileType: deriveFileType(absPath),
202
- content,
203
- sections,
204
- lineCount,
205
- charCount,
206
- estimatedTokens: Math.round(charCount / 4),
207
- });
208
- }
209
- catch {
210
- // skip unreadable files
482
+ files.push(file);
483
+ if (real !== null)
484
+ canonicalByReal.set(real, file);
485
+ }
486
+ for (const relPath of linkRels) {
487
+ const absPath = path.resolve(repoRoot, relPath);
488
+ // Out-of-repo targets are skipped. A dangling link has nothing to read
489
+ // (readInstructionFile fails on it) and a link to a directory is not a file.
490
+ if (!isWithinRoot(repoRoot, absPath) || !realPathWithinRoot(repoRoot, absPath))
491
+ continue;
492
+ const file = await readInstructionFile(repoRoot, realRoot, absPath, relPath);
493
+ if (!file)
494
+ continue;
495
+ const real = realPath(absPath);
496
+ const canonical = real !== null ? canonicalByReal.get(real) : undefined;
497
+ if (canonical) {
498
+ aliases.push({ ...file, aliasOf: canonical.relativePath });
499
+ continue;
211
500
  }
501
+ files.push(file);
502
+ if (real !== null)
503
+ canonicalByReal.set(real, file);
212
504
  }
213
- results.sort((a, b) => a.path.localeCompare(b.path));
214
- return results;
505
+ const linked = foldTextSymlinks(files, aliases, createGitSymlinkOracle(repoRoot));
506
+ linked.files.sort((a, b) => a.path.localeCompare(b.path));
507
+ linked.aliases.sort((a, b) => a.path.localeCompare(b.path));
508
+ return linked;
509
+ }
510
+ export async function scanFiles(input) {
511
+ return (await scanFilesWithAliases(input)).files;
215
512
  }
216
513
  //# sourceMappingURL=scanner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,24 @@
1
1
  import type { PromptCiIssue } from './types.js';
2
2
  import type { RepoContext } from './repo-context.js';
3
+ /**
4
+ * SP3: does this .gitignore LINE actually ignore `target` (a bare directory
5
+ * or dotfile name, no slashes)?
6
+ *
7
+ * Old behavior used `clean.includes(target)` as a catch-all fallback, which
8
+ * was wrong two ways:
9
+ * 1. A NEGATION line ("!.promptci/") re-includes a path (un-ignores it) in
10
+ * gitignore syntax, but `"!.promptci".includes(".promptci")` is true, so
11
+ * the negation was misread as "yes, this is ignored".
12
+ * 2. Substring matching let an unrelated entry satisfy the check —
13
+ * "distribution.md".includes("dist") and "builds-notes/".includes("build")
14
+ * are both true, so those unrelated lines were misread as ignoring
15
+ * "dist"/"build", masking a real unignored-directory finding (FN).
16
+ *
17
+ * Fixed by rejecting negation lines outright, then requiring an EXACT path
18
+ * SEGMENT match (splitting on '/' so a leading globstar segment doesn't
19
+ * block the match, but a differently-named file/dir never accidentally
20
+ * satisfies it).
21
+ */
22
+ export declare function gitignoreLineMatchesTarget(line: string, target: string): boolean;
3
23
  export declare function detectSecurityPack(context: RepoContext): PromptCiIssue[];
4
24
  //# sourceMappingURL=security-pack.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"security-pack.d.ts","sourceRoot":"","sources":["../src/security-pack.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAyJrD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CA6SxE"}
1
+ {"version":3,"file":"security-pack.d.ts","sourceRoot":"","sources":["../src/security-pack.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAmIrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAKhF;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,EAAE,CA6TxE"}