icopilot 2.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 (203) hide show
  1. package/CHANGELOG.md +250 -0
  2. package/LICENSE +21 -0
  3. package/README.md +214 -0
  4. package/bin/icopilot.js +6 -0
  5. package/dist/acp/router.js +123 -0
  6. package/dist/acp/schema.js +53 -0
  7. package/dist/agents/aggregator.js +187 -0
  8. package/dist/agents/custom-agents.js +97 -0
  9. package/dist/agents/goal-driven.js +411 -0
  10. package/dist/agents/multi-repo.js +350 -0
  11. package/dist/agents/parallel-runner.js +181 -0
  12. package/dist/agents/router.js +144 -0
  13. package/dist/agents/self-heal.js +481 -0
  14. package/dist/agents/tdd-agent.js +278 -0
  15. package/dist/api/github-models.js +158 -0
  16. package/dist/bridge/ide-bridge.js +479 -0
  17. package/dist/cloud/routine-executor.js +34 -0
  18. package/dist/cloud/routine-scheduler.js +67 -0
  19. package/dist/cloud/routine-storage.js +297 -0
  20. package/dist/commands/acp-cmd.js +143 -0
  21. package/dist/commands/actions-cmd.js +624 -0
  22. package/dist/commands/agent-cmd.js +144 -0
  23. package/dist/commands/alias-cmd.js +132 -0
  24. package/dist/commands/bookmark-cmd.js +77 -0
  25. package/dist/commands/changelog-cmd.js +99 -0
  26. package/dist/commands/changes-cmd.js +120 -0
  27. package/dist/commands/clipboard-cmd.js +217 -0
  28. package/dist/commands/cloud-routine-cmd.js +265 -0
  29. package/dist/commands/codegen-cmd.js +544 -0
  30. package/dist/commands/compare-cmd.js +116 -0
  31. package/dist/commands/context-cmd.js +247 -0
  32. package/dist/commands/context-viz-cmd.js +43 -0
  33. package/dist/commands/conventions-cmd.js +116 -0
  34. package/dist/commands/cost-cmd.js +51 -0
  35. package/dist/commands/deps-cmd.js +294 -0
  36. package/dist/commands/diagram-cmd.js +658 -0
  37. package/dist/commands/diff-review-cmd.js +92 -0
  38. package/dist/commands/doc-cmd.js +412 -0
  39. package/dist/commands/doctor-cmd.js +152 -0
  40. package/dist/commands/editor-cmd.js +49 -0
  41. package/dist/commands/env-cmd.js +86 -0
  42. package/dist/commands/explain-cmd.js +78 -0
  43. package/dist/commands/explain-shell-cmd.js +22 -0
  44. package/dist/commands/explore-cmd.js +231 -0
  45. package/dist/commands/feedback-cmd.js +98 -0
  46. package/dist/commands/fix-cmd.js +17 -0
  47. package/dist/commands/generate-cmd.js +38 -0
  48. package/dist/commands/git-extra.js +197 -0
  49. package/dist/commands/git-log-cmd.js +98 -0
  50. package/dist/commands/git-undo-cmd.js +137 -0
  51. package/dist/commands/git.js +155 -0
  52. package/dist/commands/history-cmd.js +122 -0
  53. package/dist/commands/index-cmd.js +65 -0
  54. package/dist/commands/init-cmd.js +73 -0
  55. package/dist/commands/lint-cmd.js +133 -0
  56. package/dist/commands/memory-cmd.js +98 -0
  57. package/dist/commands/metrics-cmd.js +97 -0
  58. package/dist/commands/mode-prefix.js +30 -0
  59. package/dist/commands/multi-cmd.js +44 -0
  60. package/dist/commands/notify-cmd.js +204 -0
  61. package/dist/commands/profile-cmd.js +101 -0
  62. package/dist/commands/prompts.js +17 -0
  63. package/dist/commands/rag-cmd.js +60 -0
  64. package/dist/commands/readme-cmd.js +564 -0
  65. package/dist/commands/reasoning-cmd.js +34 -0
  66. package/dist/commands/refactor-cmd.js +96 -0
  67. package/dist/commands/release-cmd.js +450 -0
  68. package/dist/commands/repo-cmd.js +195 -0
  69. package/dist/commands/route-cmd.js +21 -0
  70. package/dist/commands/schedule-cmd.js +109 -0
  71. package/dist/commands/search-cmd.js +47 -0
  72. package/dist/commands/security-cmd.js +156 -0
  73. package/dist/commands/settings-cmd.js +238 -0
  74. package/dist/commands/skill-cmd.js +338 -0
  75. package/dist/commands/slash.js +2721 -0
  76. package/dist/commands/snippets-cmd.js +83 -0
  77. package/dist/commands/space-cmd.js +92 -0
  78. package/dist/commands/stash-cmd.js +156 -0
  79. package/dist/commands/stats-cmd.js +36 -0
  80. package/dist/commands/style-cmd.js +85 -0
  81. package/dist/commands/suggest-cmd.js +40 -0
  82. package/dist/commands/summary-cmd.js +138 -0
  83. package/dist/commands/task-cmd.js +58 -0
  84. package/dist/commands/team-memory-cmd.js +97 -0
  85. package/dist/commands/template-cmd.js +475 -0
  86. package/dist/commands/test-cmd.js +146 -0
  87. package/dist/commands/todo-cmd.js +172 -0
  88. package/dist/commands/tokens-cmd.js +277 -0
  89. package/dist/commands/trigger-cmd.js +147 -0
  90. package/dist/commands/undo-cmd.js +18 -0
  91. package/dist/commands/voice-cmd.js +89 -0
  92. package/dist/commands/watch-cmd.js +110 -0
  93. package/dist/commands/web-cmd.js +183 -0
  94. package/dist/commands/worktree-cmd.js +119 -0
  95. package/dist/config-profile.js +66 -0
  96. package/dist/config.js +288 -0
  97. package/dist/context/compactor.js +53 -0
  98. package/dist/context/dep-context.js +329 -0
  99. package/dist/context/file-refs.js +54 -0
  100. package/dist/context/git-context.js +229 -0
  101. package/dist/context/image-input.js +66 -0
  102. package/dist/context/memory.js +55 -0
  103. package/dist/context/persistent-memory.js +104 -0
  104. package/dist/context/pinned.js +96 -0
  105. package/dist/context/priority.js +150 -0
  106. package/dist/context/read-only.js +48 -0
  107. package/dist/context/smart-files.js +286 -0
  108. package/dist/context/team-memory.js +156 -0
  109. package/dist/extensions/loader.js +149 -0
  110. package/dist/extensions/marketplace.js +49 -0
  111. package/dist/extensions/slack-provider.js +181 -0
  112. package/dist/extensions/team.js +56 -0
  113. package/dist/extensions/teams-provider.js +222 -0
  114. package/dist/extensions/voice.js +18 -0
  115. package/dist/hooks/lifecycle.js +215 -0
  116. package/dist/hooks/precommit.js +463 -0
  117. package/dist/index/embeddings.js +23 -0
  118. package/dist/index/indexer.js +86 -0
  119. package/dist/index/retrieve.js +20 -0
  120. package/dist/index/store.js +95 -0
  121. package/dist/index.js +286 -0
  122. package/dist/intelligence/dead-code.js +457 -0
  123. package/dist/intelligence/error-watch.js +263 -0
  124. package/dist/intelligence/navigation.js +141 -0
  125. package/dist/intelligence/stack-trace.js +210 -0
  126. package/dist/intelligence/symbol-index.js +410 -0
  127. package/dist/knowledge/auto-memory.js +412 -0
  128. package/dist/knowledge/conventions.js +475 -0
  129. package/dist/knowledge/corrections.js +213 -0
  130. package/dist/knowledge/rag.js +450 -0
  131. package/dist/knowledge/style-learner.js +324 -0
  132. package/dist/logger.js +35 -0
  133. package/dist/mcp/client.js +144 -0
  134. package/dist/mcp/config.js +24 -0
  135. package/dist/mcp/index.js +89 -0
  136. package/dist/modes/auto-compact.js +20 -0
  137. package/dist/modes/autopilot.js +157 -0
  138. package/dist/modes/background.js +82 -0
  139. package/dist/modes/interactive.js +187 -0
  140. package/dist/modes/oneshot.js +36 -0
  141. package/dist/modes/tui.js +265 -0
  142. package/dist/modes/turn.js +342 -0
  143. package/dist/notifications/manager.js +107 -0
  144. package/dist/plugins/marketplace.js +244 -0
  145. package/dist/providers/custom-provider.js +298 -0
  146. package/dist/providers/local-model.js +121 -0
  147. package/dist/routing/profiles.js +44 -0
  148. package/dist/routing/router.js +18 -0
  149. package/dist/sandbox/container.js +151 -0
  150. package/dist/security/audit.js +237 -0
  151. package/dist/security/content-filter.js +449 -0
  152. package/dist/security/proxy.js +301 -0
  153. package/dist/security/retention.js +281 -0
  154. package/dist/security/roles.js +252 -0
  155. package/dist/server/api-server.js +679 -0
  156. package/dist/session/bookmarks.js +72 -0
  157. package/dist/session/cloud-session.js +291 -0
  158. package/dist/session/handoff.js +405 -0
  159. package/dist/session/manager.js +35 -0
  160. package/dist/session/session.js +296 -0
  161. package/dist/session/share.js +313 -0
  162. package/dist/session/undo-journal.js +91 -0
  163. package/dist/snippets/store.js +60 -0
  164. package/dist/spaces/space-config.js +156 -0
  165. package/dist/spaces/space.js +220 -0
  166. package/dist/stats/store.js +101 -0
  167. package/dist/tools/apply-patch.js +134 -0
  168. package/dist/tools/auto-check.js +218 -0
  169. package/dist/tools/diff-edit.js +150 -0
  170. package/dist/tools/diff-prompt.js +36 -0
  171. package/dist/tools/edit-file.js +66 -0
  172. package/dist/tools/file-ops.js +205 -0
  173. package/dist/tools/glob.js +17 -0
  174. package/dist/tools/grep.js +56 -0
  175. package/dist/tools/image.js +194 -0
  176. package/dist/tools/list-directory.js +228 -0
  177. package/dist/tools/memory.js +17 -0
  178. package/dist/tools/multi-edit.js +299 -0
  179. package/dist/tools/policy.js +95 -0
  180. package/dist/tools/registry.js +484 -0
  181. package/dist/tools/retry.js +74 -0
  182. package/dist/tools/run-in-terminal.js +162 -0
  183. package/dist/tools/safety.js +64 -0
  184. package/dist/tools/sandbox.js +15 -0
  185. package/dist/tools/search-symbols.js +212 -0
  186. package/dist/tools/shell.js +118 -0
  187. package/dist/tools/web.js +167 -0
  188. package/dist/ui/prompt.js +37 -0
  189. package/dist/ui/render.js +96 -0
  190. package/dist/ui/screen.js +13 -0
  191. package/dist/ui/theme.js +56 -0
  192. package/dist/util/browser.js +34 -0
  193. package/dist/util/completion.js +350 -0
  194. package/dist/util/cost.js +28 -0
  195. package/dist/util/keybindings.js +113 -0
  196. package/dist/util/lazy.js +26 -0
  197. package/dist/util/perf.js +25 -0
  198. package/dist/util/token-worker.js +11 -0
  199. package/dist/util/tokens.js +50 -0
  200. package/dist/workflows/builtins.js +128 -0
  201. package/dist/workflows/engine.js +496 -0
  202. package/dist/workflows/file-trigger.js +197 -0
  203. package/package.json +79 -0
@@ -0,0 +1,457 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import fg from 'fast-glob';
4
+ const DEFAULT_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs'];
5
+ const DEFAULT_EXCLUDES = [
6
+ '**/node_modules/**',
7
+ '**/dist/**',
8
+ '**/.git/**',
9
+ '**/coverage/**',
10
+ '**/*.d.ts',
11
+ '**/__tests__/**',
12
+ '**/tests/**',
13
+ '**/*.test.*',
14
+ '**/*.spec.*',
15
+ ];
16
+ const RUNTIME_EXTENSIONS = ['.js', '.jsx', '.mjs', '.cjs'];
17
+ export class DeadCodeDetector {
18
+ scan(rootDir, options = {}) {
19
+ const state = this.buildState(rootDir, options);
20
+ const unusedExports = this.computeUnusedExports(state);
21
+ const unusedFiles = this.computeUnusedFiles(state);
22
+ const total = state.files.length + state.totalExports;
23
+ const unused = unusedFiles.length + unusedExports.length;
24
+ return {
25
+ unusedExports,
26
+ unusedFiles,
27
+ stats: {
28
+ total,
29
+ unused,
30
+ percentage: total === 0 ? 0 : Number(((unused / total) * 100).toFixed(2)),
31
+ },
32
+ };
33
+ }
34
+ getUnusedExports(rootDir) {
35
+ return this.scan(rootDir).unusedExports;
36
+ }
37
+ getUnusedFiles(rootDir) {
38
+ return this.scan(rootDir).unusedFiles;
39
+ }
40
+ buildState(rootDir, options) {
41
+ const normalizedRoot = path.resolve(rootDir);
42
+ const extensions = normalizeExtensions(options.extensions);
43
+ const files = listSourceFiles(normalizedRoot, extensions, options.exclude);
44
+ const entryPoints = findEntryPoints(normalizedRoot, files, extensions, options.entryPoints);
45
+ const modules = new Map();
46
+ for (const file of files) {
47
+ const moduleInfo = {
48
+ file,
49
+ exports: new Map(),
50
+ exportAll: [],
51
+ importedNames: new Set(),
52
+ inboundReferences: 0,
53
+ };
54
+ modules.set(file, moduleInfo);
55
+ }
56
+ for (const file of files) {
57
+ const content = safeRead(file);
58
+ if (content === undefined)
59
+ continue;
60
+ const moduleInfo = modules.get(file);
61
+ if (!moduleInfo)
62
+ continue;
63
+ const lineLookup = createLineLookup(content);
64
+ this.collectExports(moduleInfo, content, lineLookup);
65
+ this.collectImports(modules, normalizedRoot, file, content, extensions);
66
+ }
67
+ this.propagateReExportUsage(modules, normalizedRoot, entryPoints, extensions);
68
+ const totalExports = [...modules.values()].reduce((sum, moduleInfo) => sum + moduleInfo.exports.size, 0);
69
+ return {
70
+ rootDir: normalizedRoot,
71
+ files,
72
+ modules,
73
+ entryPoints,
74
+ totalExports,
75
+ };
76
+ }
77
+ collectExports(moduleInfo, content, lineLookup) {
78
+ const register = (name, line, kind, source, sourceName) => {
79
+ const exportName = name.trim();
80
+ if (!exportName || moduleInfo.exports.has(exportName))
81
+ return;
82
+ moduleInfo.exports.set(exportName, {
83
+ name: exportName,
84
+ file: moduleInfo.file,
85
+ line,
86
+ kind,
87
+ source,
88
+ sourceName,
89
+ });
90
+ };
91
+ const declarationExport = /^\s*export\s+(?:declare\s+)?(?:(default)\s+)?(?:(async)\s+)?(function|class|interface|type|enum|const|let|var)\s+([A-Za-z_$][\w$]*)/gmu;
92
+ for (const match of content.matchAll(declarationExport)) {
93
+ const [, isDefault, , kind, name] = match;
94
+ const line = lookupLine(lineLookup, match.index ?? 0);
95
+ if (name)
96
+ register(name, line, kind ?? 'symbol');
97
+ if (isDefault)
98
+ register('default', line, kind ?? 'default');
99
+ }
100
+ const anonymousDefaultExport = /^\s*export\s+default\s+(?!function\s+[A-Za-z_$]|class\s+[A-Za-z_$])(?:async\s+)?(function|class)?/gmu;
101
+ for (const match of content.matchAll(anonymousDefaultExport)) {
102
+ const line = lookupLine(lineLookup, match.index ?? 0);
103
+ register('default', line, match[1] ?? 'default');
104
+ }
105
+ const namedExport = /^\s*export\s*\{([^}]+)\}\s*(?:from\s*['"]([^'"]+)['"])?/gmu;
106
+ for (const match of content.matchAll(namedExport)) {
107
+ const line = lookupLine(lineLookup, match.index ?? 0);
108
+ const specifier = match[2];
109
+ for (const item of splitNamedBindings(match[1] ?? '')) {
110
+ const parsed = parseNamedBinding(item);
111
+ if (!parsed)
112
+ continue;
113
+ register(parsed.exportedName, line, specifier ? 're-export' : 'named export', specifier, parsed.importedName);
114
+ }
115
+ }
116
+ const exportNamespace = /^\s*export\s+\*\s+as\s+([A-Za-z_$][\w$]*)\s+from\s+['"]([^'"]+)['"]/gmu;
117
+ for (const match of content.matchAll(exportNamespace)) {
118
+ const line = lookupLine(lineLookup, match.index ?? 0);
119
+ const [, name, specifier] = match;
120
+ if (name && specifier)
121
+ register(name, line, 'namespace re-export', specifier, '*');
122
+ }
123
+ const exportAll = /^\s*export\s+\*\s+from\s+['"]([^'"]+)['"]/gmu;
124
+ for (const match of content.matchAll(exportAll)) {
125
+ const specifier = match[1];
126
+ if (specifier)
127
+ moduleInfo.exportAll.push(specifier);
128
+ }
129
+ }
130
+ collectImports(modules, rootDir, importerFile, content, extensions) {
131
+ const importer = modules.get(importerFile);
132
+ if (!importer)
133
+ return;
134
+ const registerFileReference = (specifier) => {
135
+ const resolved = resolveModuleSpecifier(rootDir, importerFile, specifier, extensions);
136
+ if (!resolved)
137
+ return null;
138
+ const target = modules.get(resolved);
139
+ if (!target)
140
+ return null;
141
+ target.inboundReferences += 1;
142
+ return target;
143
+ };
144
+ const importFrom = /^\s*import\s+(?!['"])([\s\S]*?)\s+from\s+['"]([^'"]+)['"]/gmu;
145
+ for (const match of content.matchAll(importFrom)) {
146
+ const clause = match[1];
147
+ const specifier = match[2];
148
+ if (!clause || !specifier)
149
+ continue;
150
+ const target = registerFileReference(specifier);
151
+ if (!target)
152
+ continue;
153
+ for (const name of parseImportClause(clause)) {
154
+ target.importedNames.add(name);
155
+ }
156
+ }
157
+ const sideEffectImport = /^\s*import\s+['"]([^'"]+)['"]/gmu;
158
+ for (const match of content.matchAll(sideEffectImport)) {
159
+ const specifier = match[1];
160
+ if (specifier)
161
+ registerFileReference(specifier);
162
+ }
163
+ const reExportFrom = /^\s*export\s*\{([^}]+)\}\s*from\s*['"]([^'"]+)['"]/gmu;
164
+ for (const match of content.matchAll(reExportFrom)) {
165
+ const bindings = match[1];
166
+ const specifier = match[2];
167
+ if (!bindings || !specifier)
168
+ continue;
169
+ const target = registerFileReference(specifier);
170
+ if (!target)
171
+ continue;
172
+ for (const item of splitNamedBindings(bindings)) {
173
+ const parsed = parseNamedBinding(item);
174
+ if (parsed)
175
+ target.importedNames.add(parsed.importedName);
176
+ }
177
+ }
178
+ const exportAll = /^\s*export\s+\*\s+from\s+['"]([^'"]+)['"]/gmu;
179
+ for (const match of content.matchAll(exportAll)) {
180
+ const specifier = match[1];
181
+ if (specifier)
182
+ registerFileReference(specifier);
183
+ }
184
+ const exportNamespace = /^\s*export\s+\*\s+as\s+[A-Za-z_$][\w$]*\s+from\s+['"]([^'"]+)['"]/gmu;
185
+ for (const match of content.matchAll(exportNamespace)) {
186
+ const specifier = match[1];
187
+ if (specifier)
188
+ registerFileReference(specifier);
189
+ }
190
+ const dynamicImport = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/gmu;
191
+ for (const match of content.matchAll(dynamicImport)) {
192
+ const specifier = match[1];
193
+ if (specifier)
194
+ registerFileReference(specifier);
195
+ }
196
+ const requireCall = /\brequire\s*\(\s*['"]([^'"]+)['"]\s*\)/gmu;
197
+ for (const match of content.matchAll(requireCall)) {
198
+ const specifier = match[1];
199
+ if (specifier)
200
+ registerFileReference(specifier);
201
+ }
202
+ }
203
+ propagateReExportUsage(modules, rootDir, entryPoints, extensions) {
204
+ for (const entryPoint of entryPoints) {
205
+ const moduleInfo = modules.get(entryPoint);
206
+ if (!moduleInfo)
207
+ continue;
208
+ for (const name of moduleInfo.exports.keys()) {
209
+ moduleInfo.importedNames.add(name);
210
+ }
211
+ }
212
+ let changed = true;
213
+ while (changed) {
214
+ changed = false;
215
+ for (const [file, moduleInfo] of modules) {
216
+ for (const record of moduleInfo.exports.values()) {
217
+ if (!record.source || !moduleInfo.importedNames.has(record.name))
218
+ continue;
219
+ const targetFile = resolveModuleSpecifier(rootDir, file, record.source, extensions);
220
+ const target = targetFile ? modules.get(targetFile) : undefined;
221
+ if (!target || !record.sourceName)
222
+ continue;
223
+ if (!target.importedNames.has(record.sourceName)) {
224
+ target.importedNames.add(record.sourceName);
225
+ changed = true;
226
+ }
227
+ }
228
+ if (moduleInfo.importedNames.size === 0 || moduleInfo.exportAll.length === 0)
229
+ continue;
230
+ for (const specifier of moduleInfo.exportAll) {
231
+ const targetFile = resolveModuleSpecifier(rootDir, file, specifier, extensions);
232
+ const target = targetFile ? modules.get(targetFile) : undefined;
233
+ if (!target)
234
+ continue;
235
+ for (const name of moduleInfo.importedNames) {
236
+ if (!target.exports.has(name) || target.importedNames.has(name))
237
+ continue;
238
+ target.importedNames.add(name);
239
+ changed = true;
240
+ }
241
+ }
242
+ }
243
+ }
244
+ }
245
+ computeUnusedExports(state) {
246
+ const unused = [];
247
+ for (const [file, moduleInfo] of state.modules) {
248
+ if (state.entryPoints.has(file))
249
+ continue;
250
+ for (const record of moduleInfo.exports.values()) {
251
+ if (moduleInfo.importedNames.has(record.name))
252
+ continue;
253
+ unused.push({
254
+ name: record.name,
255
+ file: toRelativeFile(state.rootDir, record.file),
256
+ line: record.line,
257
+ kind: record.kind,
258
+ });
259
+ }
260
+ }
261
+ return unused.sort(compareUnusedExports);
262
+ }
263
+ computeUnusedFiles(state) {
264
+ return state.files
265
+ .filter((file) => !state.entryPoints.has(file))
266
+ .filter((file) => (state.modules.get(file)?.inboundReferences ?? 0) === 0)
267
+ .map((file) => toRelativeFile(state.rootDir, file))
268
+ .sort((left, right) => left.localeCompare(right));
269
+ }
270
+ }
271
+ function listSourceFiles(rootDir, extensions, exclude = []) {
272
+ const patterns = extensions.map((extension) => `**/*${extension}`);
273
+ const files = fg.sync(patterns, {
274
+ cwd: rootDir,
275
+ onlyFiles: true,
276
+ absolute: true,
277
+ unique: true,
278
+ dot: false,
279
+ ignore: [...DEFAULT_EXCLUDES, ...readGitignorePatterns(rootDir), ...exclude],
280
+ });
281
+ return files.map((file) => path.resolve(file)).sort((left, right) => left.localeCompare(right));
282
+ }
283
+ function normalizeExtensions(extensions) {
284
+ if (!extensions?.length)
285
+ return [...DEFAULT_EXTENSIONS];
286
+ return [
287
+ ...new Set(extensions.map((extension) => (extension.startsWith('.') ? extension : `.${extension}`))),
288
+ ];
289
+ }
290
+ function findEntryPoints(rootDir, files, extensions, entryPoints = []) {
291
+ const entries = new Set();
292
+ for (const file of files) {
293
+ const normalized = normalizeForMatch(path.relative(rootDir, file));
294
+ if (path.basename(file).startsWith('index.'))
295
+ entries.add(file);
296
+ if (normalized.startsWith('bin/'))
297
+ entries.add(file);
298
+ }
299
+ for (const entryPoint of entryPoints) {
300
+ const resolved = resolveExplicitEntryPoint(rootDir, entryPoint, files, extensions);
301
+ if (resolved)
302
+ entries.add(resolved);
303
+ }
304
+ return entries;
305
+ }
306
+ function resolveExplicitEntryPoint(rootDir, entryPoint, files, extensions) {
307
+ const base = path.resolve(rootDir, entryPoint);
308
+ const candidates = resolveCandidates(base, extensions);
309
+ for (const candidate of candidates) {
310
+ if (files.includes(candidate))
311
+ return candidate;
312
+ }
313
+ return null;
314
+ }
315
+ function parseImportClause(clause) {
316
+ const trimmed = clause.replace(/\s+/g, ' ').trim();
317
+ if (!trimmed)
318
+ return [];
319
+ if (trimmed.startsWith('type '))
320
+ return parseImportClause(trimmed.slice(5));
321
+ const names = new Set();
322
+ const addDefault = (value) => {
323
+ const name = value.trim();
324
+ if (name && !name.startsWith('{') && !name.startsWith('*'))
325
+ names.add('default');
326
+ };
327
+ if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
328
+ for (const item of splitNamedBindings(trimmed.slice(1, -1))) {
329
+ const parsed = parseNamedBinding(item);
330
+ if (parsed)
331
+ names.add(parsed.importedName);
332
+ }
333
+ return [...names];
334
+ }
335
+ if (trimmed.startsWith('*')) {
336
+ return [];
337
+ }
338
+ const commaIndex = trimmed.indexOf(',');
339
+ if (commaIndex === -1) {
340
+ addDefault(trimmed);
341
+ return [...names];
342
+ }
343
+ addDefault(trimmed.slice(0, commaIndex));
344
+ const remainder = trimmed.slice(commaIndex + 1).trim();
345
+ if (remainder.startsWith('{') && remainder.endsWith('}')) {
346
+ for (const item of splitNamedBindings(remainder.slice(1, -1))) {
347
+ const parsed = parseNamedBinding(item);
348
+ if (parsed)
349
+ names.add(parsed.importedName);
350
+ }
351
+ }
352
+ return [...names];
353
+ }
354
+ function splitNamedBindings(value) {
355
+ return value
356
+ .split(',')
357
+ .map((part) => part.trim())
358
+ .filter(Boolean);
359
+ }
360
+ function parseNamedBinding(value) {
361
+ const cleaned = value.replace(/^type\s+/u, '').trim();
362
+ if (!cleaned)
363
+ return null;
364
+ const match = /^([A-Za-z_$][\w$]*)(?:\s+as\s+([A-Za-z_$][\w$]*))?$/u.exec(cleaned);
365
+ if (!match)
366
+ return null;
367
+ const importedName = match[1];
368
+ const exportedName = match[2] ?? importedName;
369
+ return { importedName, exportedName };
370
+ }
371
+ function resolveModuleSpecifier(rootDir, importerFile, specifier, extensions) {
372
+ if (!specifier.startsWith('.') && !specifier.startsWith('/'))
373
+ return null;
374
+ const base = specifier.startsWith('/')
375
+ ? path.resolve(rootDir, `.${specifier}`)
376
+ : path.resolve(path.dirname(importerFile), specifier);
377
+ for (const candidate of resolveCandidates(base, extensions)) {
378
+ if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
379
+ return path.resolve(candidate);
380
+ }
381
+ }
382
+ return null;
383
+ }
384
+ function resolveCandidates(basePath, extensions) {
385
+ const candidates = new Set();
386
+ const baseExtension = path.extname(basePath);
387
+ candidates.add(basePath);
388
+ if (!baseExtension) {
389
+ for (const extension of extensions) {
390
+ candidates.add(`${basePath}${extension}`);
391
+ candidates.add(path.join(basePath, `index${extension}`));
392
+ }
393
+ }
394
+ else if (RUNTIME_EXTENSIONS.includes(baseExtension)) {
395
+ const stem = basePath.slice(0, -baseExtension.length);
396
+ for (const extension of extensions) {
397
+ candidates.add(`${stem}${extension}`);
398
+ }
399
+ }
400
+ if (baseExtension) {
401
+ const withoutExtension = basePath.slice(0, -baseExtension.length);
402
+ for (const extension of extensions) {
403
+ candidates.add(path.join(withoutExtension, `index${extension}`));
404
+ }
405
+ }
406
+ return [...candidates];
407
+ }
408
+ function readGitignorePatterns(rootDir) {
409
+ const gitignorePath = path.join(rootDir, '.gitignore');
410
+ if (!fs.existsSync(gitignorePath))
411
+ return [];
412
+ return (safeRead(gitignorePath)
413
+ ?.split(/\r?\n/u)
414
+ .map((line) => line.trim())
415
+ .filter((line) => line && !line.startsWith('#') && !line.startsWith('!')) ?? []);
416
+ }
417
+ function createLineLookup(content) {
418
+ const offsets = [0];
419
+ for (let index = 0; index < content.length; index += 1) {
420
+ if (content[index] === '\n')
421
+ offsets.push(index + 1);
422
+ }
423
+ return offsets;
424
+ }
425
+ function lookupLine(offsets, index) {
426
+ let low = 0;
427
+ let high = offsets.length - 1;
428
+ while (low <= high) {
429
+ const mid = Math.floor((low + high) / 2);
430
+ if (offsets[mid] <= index) {
431
+ low = mid + 1;
432
+ }
433
+ else {
434
+ high = mid - 1;
435
+ }
436
+ }
437
+ return high + 1;
438
+ }
439
+ function toRelativeFile(rootDir, file) {
440
+ return normalizeForMatch(path.relative(rootDir, file));
441
+ }
442
+ function normalizeForMatch(value) {
443
+ return value.replace(/\\/g, '/');
444
+ }
445
+ function safeRead(file) {
446
+ try {
447
+ return fs.readFileSync(file, 'utf8');
448
+ }
449
+ catch {
450
+ return undefined;
451
+ }
452
+ }
453
+ function compareUnusedExports(left, right) {
454
+ return (left.file.localeCompare(right.file) ||
455
+ left.line - right.line ||
456
+ left.name.localeCompare(right.name));
457
+ }