@rigour-labs/core 5.0.0 → 5.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 (139) hide show
  1. package/README.md +9 -1
  2. package/dist/gates/agent-team.d.ts +0 -1
  3. package/dist/gates/agent-team.js +0 -1
  4. package/dist/gates/checkpoint.d.ts +0 -2
  5. package/dist/gates/checkpoint.js +0 -2
  6. package/dist/gates/context-window-artifacts.d.ts +6 -2
  7. package/dist/gates/context-window-artifacts.js +107 -31
  8. package/dist/gates/deep-analysis.d.ts +2 -0
  9. package/dist/gates/deep-analysis.js +41 -11
  10. package/dist/gates/dependency.d.ts +0 -2
  11. package/dist/gates/dependency.js +23 -5
  12. package/dist/gates/deprecated-apis.d.ts +0 -2
  13. package/dist/gates/deprecated-apis.js +33 -20
  14. package/dist/gates/duplication-drift/index.d.ts +61 -0
  15. package/dist/gates/duplication-drift/index.js +240 -0
  16. package/dist/gates/duplication-drift/similarity.d.ts +68 -0
  17. package/dist/gates/duplication-drift/similarity.js +177 -0
  18. package/dist/gates/duplication-drift/tokenizer.d.ts +55 -0
  19. package/dist/gates/duplication-drift/tokenizer.js +195 -0
  20. package/dist/gates/frontend-secret-exposure.d.ts +0 -3
  21. package/dist/gates/frontend-secret-exposure.js +1 -114
  22. package/dist/gates/frontend-secret-patterns.d.ts +33 -0
  23. package/dist/gates/frontend-secret-patterns.js +119 -0
  24. package/dist/gates/{hallucinated-imports.d.ts → hallucinated-imports/index.d.ts} +2 -29
  25. package/dist/gates/hallucinated-imports/index.js +174 -0
  26. package/dist/gates/hallucinated-imports/js-resolver.d.ts +45 -0
  27. package/dist/gates/hallucinated-imports/js-resolver.js +320 -0
  28. package/dist/gates/hallucinated-imports/manifest-discovery.d.ts +28 -0
  29. package/dist/gates/hallucinated-imports/manifest-discovery.js +114 -0
  30. package/dist/gates/hallucinated-imports/python-resolver.d.ts +24 -0
  31. package/dist/gates/hallucinated-imports/python-resolver.js +306 -0
  32. package/dist/gates/hallucinated-imports-lang.d.ts +2 -2
  33. package/dist/gates/hallucinated-imports-lang.js +269 -34
  34. package/dist/gates/hallucinated-imports.test.js +1 -2
  35. package/dist/gates/inconsistent-error-handling.d.ts +0 -5
  36. package/dist/gates/inconsistent-error-handling.js +15 -144
  37. package/dist/gates/language-adapters/csharp-adapter.d.ts +16 -0
  38. package/dist/gates/language-adapters/csharp-adapter.js +211 -0
  39. package/dist/gates/language-adapters/go-adapter.d.ts +26 -0
  40. package/dist/gates/language-adapters/go-adapter.js +195 -0
  41. package/dist/gates/language-adapters/index.d.ts +15 -0
  42. package/dist/gates/language-adapters/index.js +16 -0
  43. package/dist/gates/language-adapters/java-adapter.d.ts +16 -0
  44. package/dist/gates/language-adapters/java-adapter.js +237 -0
  45. package/dist/gates/language-adapters/js-adapter.d.ts +26 -0
  46. package/dist/gates/language-adapters/js-adapter.js +279 -0
  47. package/dist/gates/language-adapters/python-adapter.d.ts +25 -0
  48. package/dist/gates/language-adapters/python-adapter.js +183 -0
  49. package/dist/gates/language-adapters/registry.d.ts +26 -0
  50. package/dist/gates/language-adapters/registry.js +65 -0
  51. package/dist/gates/language-adapters/ruby-adapter.d.ts +25 -0
  52. package/dist/gates/language-adapters/ruby-adapter.js +217 -0
  53. package/dist/gates/language-adapters/rust-adapter.d.ts +27 -0
  54. package/dist/gates/language-adapters/rust-adapter.js +235 -0
  55. package/dist/gates/language-adapters/types.d.ts +60 -0
  56. package/dist/gates/language-adapters/types.js +22 -0
  57. package/dist/gates/logic-drift-extractors.d.ts +15 -0
  58. package/dist/gates/logic-drift-extractors.js +34 -0
  59. package/dist/gates/logic-drift.d.ts +0 -30
  60. package/dist/gates/logic-drift.js +39 -129
  61. package/dist/gates/phantom-apis.d.ts +0 -2
  62. package/dist/gates/phantom-apis.js +49 -20
  63. package/dist/gates/promise-safety.d.ts +0 -1
  64. package/dist/gates/promise-safety.js +14 -2
  65. package/dist/gates/runner.js +51 -22
  66. package/dist/gates/security-patterns-data.d.ts +14 -0
  67. package/dist/gates/security-patterns-data.js +235 -0
  68. package/dist/gates/security-patterns.d.ts +17 -3
  69. package/dist/gates/security-patterns.js +80 -211
  70. package/dist/gates/side-effect-analysis/categorizer.d.ts +32 -0
  71. package/dist/gates/side-effect-analysis/categorizer.js +83 -0
  72. package/dist/gates/{side-effect-analysis.d.ts → side-effect-analysis/index.d.ts} +3 -5
  73. package/dist/gates/{side-effect-analysis.js → side-effect-analysis/index.js} +33 -45
  74. package/dist/gates/side-effect-analysis/scope-tracker.d.ts +37 -0
  75. package/dist/gates/side-effect-analysis/scope-tracker.js +40 -0
  76. package/dist/gates/side-effect-helpers/index.d.ts +4 -0
  77. package/dist/gates/side-effect-helpers/index.js +4 -0
  78. package/dist/gates/side-effect-helpers/pattern-detection.d.ts +123 -0
  79. package/dist/gates/{side-effect-helpers.js → side-effect-helpers/pattern-detection.js} +22 -468
  80. package/dist/gates/side-effect-helpers/resource-tracking.d.ts +80 -0
  81. package/dist/gates/side-effect-helpers/resource-tracking.js +281 -0
  82. package/dist/gates/side-effect-helpers/scope-analysis.d.ts +21 -0
  83. package/dist/gates/side-effect-helpers/scope-analysis.js +146 -0
  84. package/dist/gates/side-effect-helpers/types.d.ts +38 -0
  85. package/dist/gates/side-effect-helpers/types.js +41 -0
  86. package/dist/gates/side-effect-rules.d.ts +0 -1
  87. package/dist/gates/side-effect-rules.js +0 -1
  88. package/dist/gates/style-drift-rules.d.ts +86 -0
  89. package/dist/gates/style-drift-rules.js +103 -0
  90. package/dist/gates/style-drift.d.ts +7 -16
  91. package/dist/gates/style-drift.js +101 -119
  92. package/dist/gates/test-quality-matchers.d.ts +53 -0
  93. package/dist/gates/test-quality-matchers.js +86 -0
  94. package/dist/gates/test-quality.d.ts +0 -3
  95. package/dist/gates/test-quality.js +47 -44
  96. package/dist/hooks/checker.d.ts +0 -1
  97. package/dist/hooks/checker.js +1 -3
  98. package/dist/hooks/dlp-templates.d.ts +0 -1
  99. package/dist/hooks/dlp-templates.js +0 -4
  100. package/dist/hooks/index.d.ts +0 -2
  101. package/dist/hooks/index.js +0 -2
  102. package/dist/hooks/input-validator.d.ts +0 -1
  103. package/dist/hooks/input-validator.js +0 -1
  104. package/dist/hooks/input-validator.test.js +0 -1
  105. package/dist/hooks/standalone-checker.d.ts +0 -1
  106. package/dist/hooks/standalone-checker.js +0 -1
  107. package/dist/hooks/standalone-dlp-checker.d.ts +0 -1
  108. package/dist/hooks/standalone-dlp-checker.js +0 -1
  109. package/dist/hooks/templates.d.ts +6 -1
  110. package/dist/hooks/templates.js +6 -1
  111. package/dist/hooks/types.d.ts +1 -2
  112. package/dist/hooks/types.js +1 -1
  113. package/dist/index.d.ts +1 -1
  114. package/dist/index.js +1 -1
  115. package/dist/services/adaptive-thresholds.d.ts +0 -2
  116. package/dist/services/adaptive-thresholds.js +0 -2
  117. package/dist/services/filesystem-cache.d.ts +0 -1
  118. package/dist/services/filesystem-cache.js +0 -1
  119. package/dist/services/score-history.d.ts +0 -1
  120. package/dist/services/score-history.js +0 -1
  121. package/dist/services/temporal-drift.d.ts +1 -2
  122. package/dist/services/temporal-drift.js +7 -8
  123. package/dist/storage/db.d.ts +23 -7
  124. package/dist/storage/db.js +116 -55
  125. package/dist/storage/findings.d.ts +4 -3
  126. package/dist/storage/findings.js +13 -20
  127. package/dist/storage/local-memory.d.ts +4 -4
  128. package/dist/storage/local-memory.js +20 -22
  129. package/dist/storage/patterns.d.ts +5 -5
  130. package/dist/storage/patterns.js +20 -26
  131. package/dist/storage/scans.d.ts +6 -6
  132. package/dist/storage/scans.js +12 -21
  133. package/dist/types/index.d.ts +1 -0
  134. package/dist/utils/scanner.js +1 -1
  135. package/package.json +7 -8
  136. package/dist/gates/duplication-drift.d.ts +0 -128
  137. package/dist/gates/duplication-drift.js +0 -585
  138. package/dist/gates/hallucinated-imports.js +0 -641
  139. package/dist/gates/side-effect-helpers.d.ts +0 -260
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Python import resolution for hallucinated-imports gate.
3
+ *
4
+ * Handles Python-specific import validation including:
5
+ * - Relative imports (PEP 328)
6
+ * - Local module discovery across source roots
7
+ * - Installed package detection from pyproject.toml, setup.py, requirements.txt, etc.
8
+ * - Namespace packages (PEP 420)
9
+ */
10
+ import { HallucinatedImport } from './index.js';
11
+ /**
12
+ * Check Python imports in a source file and add hallucinated findings.
13
+ */
14
+ export declare function checkPyImports(content: string, file: string, cwd: string, projectFiles: Set<string>, hallucinated: HallucinatedImport[]): Promise<void>;
15
+ /**
16
+ * Find Python source roots by discovering manifests and scanning directory structure.
17
+ * Returns array of relative paths that are on sys.path.
18
+ */
19
+ export declare function findPythonSourceRoots(cwd: string, projectFiles: Set<string>): Promise<string[]>;
20
+ /**
21
+ * Load installed Python package names from all manifest files in the project.
22
+ * Discovers pyproject.toml, setup.py, setup.cfg, requirements*.txt, Pipfile.
23
+ */
24
+ export declare function loadPythonInstalledPackages(cwd: string, projectFiles?: Set<string>): Promise<Set<string>>;
@@ -0,0 +1,306 @@
1
+ /**
2
+ * Python import resolution for hallucinated-imports gate.
3
+ *
4
+ * Handles Python-specific import validation including:
5
+ * - Relative imports (PEP 328)
6
+ * - Local module discovery across source roots
7
+ * - Installed package detection from pyproject.toml, setup.py, requirements.txt, etc.
8
+ * - Namespace packages (PEP 420)
9
+ */
10
+ import fs from 'fs-extra';
11
+ import path from 'path';
12
+ import { isPythonStdlib } from '../hallucinated-imports-stdlib.js';
13
+ /**
14
+ * Check Python imports in a source file and add hallucinated findings.
15
+ */
16
+ export async function checkPyImports(content, file, cwd, projectFiles, hallucinated) {
17
+ const lines = content.split('\n');
18
+ const pySourceRoots = await findPythonSourceRoots(cwd, projectFiles);
19
+ const pyInstalledPkgs = await loadPythonInstalledPackages(cwd, projectFiles);
20
+ for (let i = 0; i < lines.length; i++) {
21
+ const line = lines[i].trim();
22
+ const fromMatch = line.match(/^from\s+([\w.]+)\s+import/);
23
+ const importMatch = line.match(/^import\s+([\w.]+)/);
24
+ const modulePath = fromMatch?.[1] || importMatch?.[1];
25
+ if (!modulePath)
26
+ continue;
27
+ if (isPythonStdlib(modulePath))
28
+ continue;
29
+ if (modulePath.startsWith('.')) {
30
+ const dotMatch = modulePath.match(/^(\.+)/);
31
+ const dotCount = dotMatch ? dotMatch[1].length : 0;
32
+ const moduleRest = modulePath.slice(dotCount);
33
+ let baseDir = path.dirname(file);
34
+ for (let level = 1; level < dotCount; level++) {
35
+ const parent = path.dirname(baseDir);
36
+ if (parent === baseDir)
37
+ break;
38
+ baseDir = parent;
39
+ }
40
+ if (!moduleRest)
41
+ continue;
42
+ const moduleParts = moduleRest.replace(/\./g, '/');
43
+ const candidateBase = path.join(baseDir, moduleParts).replace(/\\/g, '/');
44
+ const candidates = [
45
+ candidateBase + '.py',
46
+ candidateBase + '/__init__.py',
47
+ ];
48
+ const isNamespacePackage = [...projectFiles].some(f => f.startsWith(candidateBase + '/') && f.endsWith('.py'));
49
+ if (!candidates.some(c => projectFiles.has(c)) && !isNamespacePackage) {
50
+ hallucinated.push({
51
+ file, line: i + 1, importPath: modulePath, type: 'python',
52
+ reason: `Relative module '${modulePath}' not found in project`,
53
+ });
54
+ }
55
+ }
56
+ else {
57
+ const topLevel = modulePath.split('.')[0];
58
+ if (pyInstalledPkgs.has(topLevel) || pyInstalledPkgs.has(topLevel.replace(/_/g, '-'))) {
59
+ continue;
60
+ }
61
+ let foundLocal = false;
62
+ const searchRoots = ['', ...pySourceRoots];
63
+ for (const root of searchRoots) {
64
+ const prefix = root ? root + '/' : '';
65
+ const pyFile = prefix + topLevel + '.py';
66
+ const pyInit = prefix + topLevel + '/__init__.py';
67
+ const dirPrefix = prefix + topLevel + '/';
68
+ const isLocalModule = projectFiles.has(pyFile) || projectFiles.has(pyInit) ||
69
+ [...projectFiles].some(f => f.startsWith(dirPrefix) && f.endsWith('.py'));
70
+ if (!isLocalModule)
71
+ continue;
72
+ foundLocal = true;
73
+ const fullModulePath = prefix + modulePath.replace(/\./g, '/');
74
+ const candidates = [
75
+ fullModulePath + '.py',
76
+ fullModulePath + '/__init__.py',
77
+ ];
78
+ const exists = candidates.some(c => projectFiles.has(c));
79
+ if (exists)
80
+ break;
81
+ if (modulePath.includes('.')) {
82
+ hallucinated.push({
83
+ file, line: i + 1, importPath: modulePath, type: 'python',
84
+ reason: `Module '${modulePath}' partially resolves but target not found`,
85
+ });
86
+ }
87
+ break;
88
+ }
89
+ }
90
+ }
91
+ }
92
+ /**
93
+ * Find Python source roots by discovering manifests and scanning directory structure.
94
+ * Returns array of relative paths that are on sys.path.
95
+ */
96
+ export async function findPythonSourceRoots(cwd, projectFiles) {
97
+ const roots = new Set();
98
+ const pyprojectFiles = [...projectFiles].filter(f => f.endsWith('pyproject.toml') || f.endsWith('/pyproject.toml'));
99
+ for (const pf of pyprojectFiles) {
100
+ const pfDir = path.dirname(pf);
101
+ const pfPrefix = pfDir === '.' ? '' : pfDir + '/';
102
+ try {
103
+ const content = await fs.readFile(path.join(cwd, pf), 'utf-8');
104
+ const whereMatch = content.match(/where\s*=\s*\[\s*"([^"]+)"\s*\]/);
105
+ if (whereMatch) {
106
+ roots.add(pfPrefix + whereMatch[1]);
107
+ }
108
+ const pkgDirMatch = content.match(/package-dir\s*=\s*\{[^}]*""\s*:\s*"([^"]+)"/);
109
+ if (pkgDirMatch) {
110
+ roots.add(pfPrefix + pkgDirMatch[1]);
111
+ }
112
+ const poetryFromMatch = content.match(/from\s*=\s*"([^"]+)"/g);
113
+ if (poetryFromMatch) {
114
+ for (const m of poetryFromMatch) {
115
+ const fromDir = m.match(/"([^"]+)"/)?.[1];
116
+ if (fromDir)
117
+ roots.add(pfPrefix + fromDir);
118
+ }
119
+ }
120
+ if (/src_layout\s*=\s*true/i.test(content)) {
121
+ roots.add(pfPrefix + 'src');
122
+ }
123
+ }
124
+ catch { /* skip */ }
125
+ }
126
+ const setupPyFiles = [...projectFiles].filter(f => f === 'setup.py' || f.endsWith('/setup.py'));
127
+ for (const sf of setupPyFiles) {
128
+ const sfDir = path.dirname(sf);
129
+ const sfPrefix = sfDir === '.' ? '' : sfDir + '/';
130
+ try {
131
+ const content = await fs.readFile(path.join(cwd, sf), 'utf-8');
132
+ const pkgDirMatch = content.match(/package_dir\s*=\s*\{[^}]*['"]{2}\s*:\s*['"]([^'"]+)['"]/);
133
+ if (pkgDirMatch) {
134
+ roots.add(sfPrefix + pkgDirMatch[1]);
135
+ }
136
+ }
137
+ catch { /* skip */ }
138
+ }
139
+ const setupCfgFiles = [...projectFiles].filter(f => f === 'setup.cfg' || f.endsWith('/setup.cfg'));
140
+ for (const cf of setupCfgFiles) {
141
+ const cfDir = path.dirname(cf);
142
+ const cfPrefix = cfDir === '.' ? '' : cfDir + '/';
143
+ try {
144
+ const content = await fs.readFile(path.join(cwd, cf), 'utf-8');
145
+ const pkgDirMatch = content.match(/package_dir\s*=\s*=\s*(\S+)/);
146
+ if (pkgDirMatch) {
147
+ roots.add(cfPrefix + pkgDirMatch[1]);
148
+ }
149
+ }
150
+ catch { /* skip */ }
151
+ }
152
+ const pyFiles = [...projectFiles].filter(f => f.endsWith('.py'));
153
+ const dirsWithPy = new Set();
154
+ for (const f of pyFiles) {
155
+ const parts = f.split('/');
156
+ for (let i = 0; i < parts.length - 1; i++) {
157
+ dirsWithPy.add(parts.slice(0, i + 1).join('/'));
158
+ }
159
+ }
160
+ for (const dir of dirsWithPy) {
161
+ const baseName = path.basename(dir);
162
+ if (['src', 'lib', 'app'].includes(baseName)) {
163
+ roots.add(dir);
164
+ }
165
+ }
166
+ return [...roots];
167
+ }
168
+ /**
169
+ * Load installed Python package names from all manifest files in the project.
170
+ * Discovers pyproject.toml, setup.py, setup.cfg, requirements*.txt, Pipfile.
171
+ */
172
+ export async function loadPythonInstalledPackages(cwd, projectFiles) {
173
+ const packages = new Set();
174
+ const normalize = (name) => name.toLowerCase().replace(/[-_.]+/g, '-');
175
+ const addPkg = (name) => {
176
+ if (!name || name === 'dependencies')
177
+ return;
178
+ packages.add(normalize(name));
179
+ packages.add(name.replace(/-/g, '_').toLowerCase());
180
+ };
181
+ const extractPyprojectDeps = (content) => {
182
+ const depsMatch = content.match(/dependencies\s*=\s*\[([\s\S]*?)\]/g);
183
+ if (depsMatch) {
184
+ for (const block of depsMatch) {
185
+ const pkgs = block.match(/"([^">=<!\s\[]+)/g);
186
+ if (pkgs) {
187
+ for (const pkg of pkgs) {
188
+ addPkg(pkg.replace(/^"/, '').split(/[>=<!\[]/)[0].trim());
189
+ }
190
+ }
191
+ }
192
+ }
193
+ const optDepsMatch = content.match(/optional-dependencies\s*\]([\s\S]*?)(?:\n\[|\n$)/g);
194
+ if (optDepsMatch) {
195
+ for (const block of optDepsMatch) {
196
+ const pkgs = block.match(/"([^">=<!\s\[]+)/g);
197
+ if (pkgs) {
198
+ for (const pkg of pkgs) {
199
+ addPkg(pkg.replace(/^"/, '').split(/[>=<!\[]/)[0].trim());
200
+ }
201
+ }
202
+ }
203
+ }
204
+ const poetryMatch = content.match(/\[tool\.poetry\.(?:dev-)?dependencies\]([\s\S]*?)(?:\n\[|$)/g);
205
+ if (poetryMatch) {
206
+ for (const block of poetryMatch) {
207
+ const pkgs = block.match(/^(\w[\w.-]*)\s*=/gm);
208
+ if (pkgs) {
209
+ for (const pkg of pkgs) {
210
+ const name = pkg.replace(/\s*=.*/, '').trim();
211
+ if (name !== 'python')
212
+ addPkg(name);
213
+ }
214
+ }
215
+ }
216
+ }
217
+ };
218
+ const extractRequirementsDeps = (content) => {
219
+ for (const line of content.split('\n')) {
220
+ const trimmed = line.trim();
221
+ if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('-'))
222
+ continue;
223
+ const name = trimmed.split(/[>=<!\[;@\s]/)[0].trim();
224
+ if (name)
225
+ addPkg(name);
226
+ }
227
+ };
228
+ const allFiles = projectFiles ? [...projectFiles] : [];
229
+ const pyprojectPaths = allFiles.filter(f => f.endsWith('pyproject.toml'));
230
+ const rootPyprojectPath = path.join(cwd, 'pyproject.toml');
231
+ if (await fs.pathExists(rootPyprojectPath)) {
232
+ try {
233
+ extractPyprojectDeps(await fs.readFile(rootPyprojectPath, 'utf-8'));
234
+ }
235
+ catch { /* skip */ }
236
+ }
237
+ for (const pf of pyprojectPaths) {
238
+ if (pf === 'pyproject.toml')
239
+ continue;
240
+ try {
241
+ extractPyprojectDeps(await fs.readFile(path.join(cwd, pf), 'utf-8'));
242
+ }
243
+ catch { /* skip */ }
244
+ }
245
+ const setupPyPaths = allFiles.filter(f => f.endsWith('setup.py'));
246
+ for (const sf of setupPyPaths) {
247
+ try {
248
+ const content = await fs.readFile(path.join(cwd, sf), 'utf-8');
249
+ const reqMatch = content.match(/install_requires\s*=\s*\[([\s\S]*?)\]/);
250
+ if (reqMatch) {
251
+ const pkgs = reqMatch[1].match(/['"]([^'">=<!\s\[]+)/g);
252
+ if (pkgs) {
253
+ for (const pkg of pkgs) {
254
+ addPkg(pkg.replace(/^['"]/, '').split(/[>=<!\[]/)[0].trim());
255
+ }
256
+ }
257
+ }
258
+ }
259
+ catch { /* skip */ }
260
+ }
261
+ const reqPaths = allFiles.filter(f => /(?:^|\/)requirements[^/]*\.txt$/.test(f));
262
+ for (const reqFile of ['requirements.txt', 'requirements-dev.txt', 'requirements_dev.txt', 'requirements-test.txt']) {
263
+ const reqPath = path.join(cwd, reqFile);
264
+ if (await fs.pathExists(reqPath)) {
265
+ try {
266
+ extractRequirementsDeps(await fs.readFile(reqPath, 'utf-8'));
267
+ }
268
+ catch { /* skip */ }
269
+ }
270
+ }
271
+ for (const rf of reqPaths) {
272
+ try {
273
+ extractRequirementsDeps(await fs.readFile(path.join(cwd, rf), 'utf-8'));
274
+ }
275
+ catch { /* skip */ }
276
+ }
277
+ const pipfilePaths = allFiles.filter(f => f.endsWith('Pipfile'));
278
+ for (const pf of pipfilePaths) {
279
+ try {
280
+ const content = await fs.readFile(path.join(cwd, pf), 'utf-8');
281
+ const pkgs = content.match(/^(\w[\w.-]*)\s*=/gm);
282
+ if (pkgs) {
283
+ for (const pkg of pkgs) {
284
+ const name = pkg.replace(/\s*=.*/, '').trim();
285
+ if (!['python_version', 'python_full_version', 'name', 'url', 'verify_ssl'].includes(name)) {
286
+ addPkg(name);
287
+ }
288
+ }
289
+ }
290
+ }
291
+ catch { /* skip */ }
292
+ }
293
+ const eggInfoDirs = allFiles.filter(f => (f.includes('.egg-info/') || f.includes('.dist-info/')) && f.endsWith('top_level.txt'));
294
+ for (const ei of eggInfoDirs) {
295
+ try {
296
+ const content = await fs.readFile(path.join(cwd, ei), 'utf-8');
297
+ for (const line of content.split('\n')) {
298
+ const name = line.trim();
299
+ if (name)
300
+ addPkg(name);
301
+ }
302
+ }
303
+ catch { /* skip */ }
304
+ }
305
+ return packages;
306
+ }
@@ -2,10 +2,10 @@
2
2
  * Language-specific import checkers and dependency loaders for hallucinated-imports gate.
3
3
  * Go, Ruby, C#, Rust, Java/Kotlin parsers extracted to keep main gate file under 500 lines.
4
4
  */
5
- import { HallucinatedImport } from './hallucinated-imports.js';
5
+ import { HallucinatedImport } from './hallucinated-imports/index.js';
6
6
  export declare function checkGoImports(content: string, file: string, cwd: string, projectFiles: Set<string>, hallucinated: HallucinatedImport[]): void;
7
7
  export declare function checkRubyImports(content: string, file: string, cwd: string, projectFiles: Set<string>, hallucinated: HallucinatedImport[]): void;
8
- export declare function loadRubyGems(cwd: string): Set<string>;
8
+ export declare function loadRubyGems(cwd: string, projectFiles?: Set<string>): Set<string>;
9
9
  export declare function checkCSharpImports(content: string, file: string, cwd: string, projectFiles: Set<string>, hallucinated: HallucinatedImport[]): void;
10
10
  export declare function hasCsprojFile(cwd: string): boolean;
11
11
  export declare function loadNuGetPackages(cwd: string): Set<string>;