@@ -143,6 +143,7 @@ codescythe query somepath src/main.ts src/features/
143143codescythe query allpaths src/main.ts src/runtime.ts:initRuntime --json
144144codescythe query allpaths src/main.ts src/runtime.ts:initRuntime --output mermaid
145145codescythe query allpaths src/main.ts src/runtime.ts:initRuntime --output svg > graph.svg
146+ codescythe query import-conflicts
146147```
147148
148149Selectors can point at files, directories, or exported symbols written as
@@ -154,6 +155,130 @@ by `-C` or `--config`.
154155 many.
155156- ` allpaths ` returns the subgraph of every node and edge that lies on a path
156157 from the source selector to the target selector.
158+ - ` import-conflicts ` lists modules reached through both runtime-static and
159+ dynamic paths from the same configured entrypoint, including every conflicting
160+ importer and specifier plus one shortest proof route. Type-only and configured
161+ test-file imports do not count. It exits with status ` 1 ` when conflicts are
162+ found and supports ` --json ` for CI or bulk cleanup.
163+
164+ ### Finding Static/Dynamic Import Conflicts
165+
166+ Use ` import-conflicts ` when a module intended as a lazy boundary may also be
167+ pulled into the runtime graph eagerly:
168+
169+ ``` sh
170+ codescythe query import-conflicts -C . --config codescythe.json
171+ ```
172+
173+ Each finding names the resolved target, then prints every runtime-static and
174+ dynamic edge that reaches it:
175+
176+ ``` text
177+ Found 1 module with runtime static/dynamic import conflicts:
178+
179+ src/module.ts
180+ runtime static imports:
181+ src/main.ts -- named import ./module
182+ dynamic imports:
183+ src/main.ts -- dynamic import ./module
184+ shortest conflicting entrypoint route (src/main.ts):
185+ runtime static path:
186+ src/main.ts
187+ -- named import ./module:value -> src/module.ts:value
188+ -- defined in file value -> src/module.ts
189+ dynamic path:
190+ src/main.ts
191+ -- dynamic import ./module -> src/module.ts
192+ ```
193+
194+ Runtime-static edges include named imports, side-effect imports, re-exports,
195+ and namespace imports or member access. Dynamic edges come from supported
196+ string-literal ` import() ` calls. ` import type ` edges are reported as
197+ ` typeImport ` by path queries but do not affect bundling, so they are excluded
198+ from conflict findings. Configured test files are also excluded.
199+
200+ A finding is reported only when one configured entrypoint can reach the target
201+ through runtime-static edges and can also reach a dynamic importer of that
202+ target. The printed route is the shortest deterministic proof: one fully static
203+ path from the entrypoint to the target, plus one runtime path ending at the
204+ conflicting dynamic import. This avoids treating imports isolated in separate
205+ entrypoint graphs as conflicts.
206+
207+ The command exits with status ` 1 ` when findings exist and ` 0 ` when the scan is
208+ clean. Use ` --json ` for CI or scripted cleanup:
209+
210+ ``` json
211+ {
212+ "scannedFileCount" : 2 ,
213+ "entrypointCount" : 1 ,
214+ "conflicts" : [
215+ {
216+ "target" : " src/module.ts" ,
217+ "runtimeStaticImports" : [
218+ {
219+ "importer" : " src/main.ts" ,
220+ "specifier" : " ./module" ,
221+ "kind" : " namedImport"
222+ }
223+ ],
224+ "dynamicImports" : [
225+ {
226+ "importer" : " src/main.ts" ,
227+ "specifier" : " ./module" ,
228+ "kind" : " dynamicImport"
229+ }
230+ ],
231+ "entrypointRoute" : {
232+ "entrypoint" : " src/main.ts" ,
233+ "runtimeStaticPath" : {
234+ "nodes" : [
235+ { "id" : " file:src/main.ts" , "kind" : " file" , "path" : " src/main.ts" },
236+ { "id" : " export:src/module.ts:value" , "kind" : " export" , "path" : " src/module.ts" , "symbol" : " value" },
237+ { "id" : " file:src/module.ts" , "kind" : " file" , "path" : " src/module.ts" }
238+ ],
239+ "edges" : [
240+ {
241+ "from" : " file:src/main.ts" ,
242+ "to" : " export:src/module.ts:value" ,
243+ "kind" : " namedImport" ,
244+ "importer" : " src/main.ts" ,
245+ "specifier" : " ./module" ,
246+ "imported" : " value"
247+ },
248+ {
249+ "from" : " export:src/module.ts:value" ,
250+ "to" : " file:src/module.ts" ,
251+ "kind" : " exportDefinition" ,
252+ "imported" : " value"
253+ }
254+ ]
255+ },
256+ "dynamicPath" : {
257+ "nodes" : [
258+ { "id" : " file:src/main.ts" , "kind" : " file" , "path" : " src/main.ts" },
259+ { "id" : " file:src/module.ts" , "kind" : " file" , "path" : " src/module.ts" }
260+ ],
261+ "edges" : [
262+ {
263+ "from" : " file:src/main.ts" ,
264+ "to" : " file:src/module.ts" ,
265+ "kind" : " dynamicImport" ,
266+ "importer" : " src/main.ts" ,
267+ "specifier" : " ./module"
268+ }
269+ ]
270+ }
271+ }
272+ }
273+ ]
274+ }
275+ ```
276+
277+ Fix the listed runtime-static edges, rerun the command, and confirm the target
278+ disappears. Entrypoint reachability follows Codescythe's source graph, not
279+ bundler-specific chunk naming, shared-chunk extraction, or preload behavior.
280+ Use a production bundle inspection when you need proof of emitted boundaries
281+ and transferred bytes.
157282
158283Text output is optimized for terminal inspection, including the resolved
159284selector kinds, match counts, and a reachability summary that helps explain
0 commit comments