ucn 3.8.3 → 3.8.5

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.
@@ -0,0 +1 @@
1
+ {"sessionId":"5e2a28ce-7f65-4369-a922-8d1d902f9d8f","pid":18086,"acquiredAt":1773363188494}
@@ -26,7 +26,7 @@ Extract functions, trace call chains, find callers, and detect dead code — wit
26
26
  - Language not supported (only JS/TS, Python, Go, Rust, Java, HTML)
27
27
  - Finding files by name — use glob
28
28
 
29
- ## The 5 Commands You'll Use Most
29
+ ## The Commands You'll Use Most
30
30
 
31
31
  ### 1. `about` — First stop for any investigation
32
32
 
@@ -157,6 +157,7 @@ ucn [target] <command> [name] [--flags]
157
157
 
158
158
  | Flag | When to use it |
159
159
  |------|---------------|
160
+ | `--class-name=X` | Scope to specific class (e.g., `--class-name=Repository` for method `save`) |
160
161
  | `--file=<pattern>` | Disambiguate when a name exists in multiple files (e.g., `--file=api`) |
161
162
  | `--exclude=test,mock` | Focus on production code only |
162
163
  | `--in=src/core` | Limit search to a subdirectory |
@@ -185,6 +186,10 @@ ucn [target] <command> [name] [--flags]
185
186
  | `--include-uncertain` | Include ambiguous/uncertain matches in `context`/`smart`/`about` |
186
187
  | `--show-confidence` | Show confidence scores (0.0–1.0) per caller/callee edge in `context`/`about` |
187
188
  | `--min-confidence=N` | Filter edges below confidence threshold (e.g., `--min-confidence=0.7` keeps only high-confidence edges) |
189
+ | `--calls-only` | Only show call/test-case matches in `tests` (skip file-level results) |
190
+ | `--add-param=<name>` | Add a parameter (`plan` command). Combine with `--default=<value>` |
191
+ | `--remove-param=<name>` | Remove a parameter (`plan` command) |
192
+ | `--rename-to=<name>` | Rename a function (`plan` command) |
188
193
  | `--include-exported` | Include exported symbols in `deadcode` results |
189
194
  | `--include-decorated` | Include decorated/annotated symbols in `deadcode` results |
190
195
  | `--framework=X` | Filter `entrypoints` by framework (e.g., `express`, `spring`, `celery`) |
package/README.md CHANGED
@@ -1,34 +1,13 @@
1
1
  # UCN - Universal Code Navigator
2
2
 
3
- Code intelligence for AI agents and developers - understand, extract, and navigate code without reading whole files.
3
+ See what code does before you touch it.
4
4
 
5
- Precise answers to structural code questions:
6
- - Who calls this function? → without grepping the whole project
7
- - What breaks if I change this? → every call site, with arguments
8
- - What does this function do? → extracted with dependencies inline
9
- - What code is safe to delete? → verified unused symbols
10
-
11
- One command replaces 3-4 grep+read cycles. Powered by tree-sitter.
5
+ Find symbols, trace callers, check impact, pick the right tests, extract code and spot what's dead - from the terminal.
12
6
 
13
7
  [![npm](https://img.shields.io/npm/v/ucn)](https://www.npmjs.com/package/ucn)
14
8
  [![license](https://img.shields.io/npm/l/ucn)](LICENSE)
15
9
 
16
- ---
17
-
18
- ## 60-Second Quickstart
19
-
20
- ```bash
21
- npm install -g ucn
22
-
23
- ucn toc # project overview
24
- ucn fn handleRequest # extract a function without reading the file
25
- ucn about handleRequest # full picture: definition, callers, callees, tests
26
- ucn impact handleRequest # all call sites with arguments
27
- ucn trace main --depth=3 # call tree, no file reads
28
- ucn deadcode # unused functions, AST-verified
29
- ```
30
-
31
- Supports JS/TS, Python, Go, Rust, Java, and HTML. Runs locally.
10
+ All commands, one engine, three surfaces:
32
11
 
33
12
  ```
34
13
  Terminal AI Agents Agent Skills
@@ -43,11 +22,27 @@ Supports JS/TS, Python, Go, Rust, Java, and HTML. Runs locally.
43
22
  └─────────────┘
44
23
  ```
45
24
 
25
+ Supports JavaScript, TypeScript, Python, Go, Rust, Java, and HTML inline scripts.
26
+
27
+ If you work with AI, add UCN as a [Skill or MCP](#ai-setup) and let the agent ask better code questions instead of reading whole files.
28
+ All commands ship as a single tool.
29
+
30
+ UCN is deliberately lightweight:
31
+
32
+ - **No background processes** - parses on demand, answers, exits
33
+ - **No language servers** - tree-sitter does the parsing, no compilation needed
34
+ - **MCP is optional** - only needed if you connect UCN to an AI agent, the CLI and Skill work on their own
35
+
46
36
  ---
47
37
 
48
- ## Why UCN
38
+ ```bash
39
+ npm install -g ucn
49
40
 
50
- AI agents waste tokens reading entire files to find one function, or grep for callers and miss half of them. UCN builds a structural index of the codebase - it knows which functions call which, what depends on what, and what's unused. One command gives what would take 3-4 file reads and greps.
41
+ ucn trace main --depth=3 # full execution flow
42
+ ucn about handleRequest # definition + callers + callees + tests
43
+ ucn impact handleRequest # every call site with arguments
44
+ ucn deadcode --exclude=test # unused code, AST-verified
45
+ ```
51
46
 
52
47
  "What happens when `build()` runs?"
53
48
 
@@ -55,47 +50,155 @@ AI agents waste tokens reading entire files to find one function, or grep for ca
55
50
  $ ucn trace build --depth=2
56
51
 
57
52
  build
58
- ├── detectProjectPattern (discovery.js:392) 1x
59
- │ ├── checkDir (discovery.js:396) 2x
60
- │ └── shouldIgnore (discovery.js:340) 1x
61
- ├── parseGitignore (discovery.js:123) 1x
62
- ├── expandGlob (discovery.js:183) 1x
63
- │ ├── parseGlobPattern (discovery.js:219) 1x
64
- │ ├── walkDir (discovery.js:276) 1x
65
- │ └── compareNames (discovery.js:162) 1x
66
- ├── indexFile (project.js:236) 1x
67
- │ ├── addSymbol (project.js:293) 4x
53
+ ├── detectProjectPattern (core/discovery.js:399) 1x
54
+ │ ├── checkDir (core/discovery.js:403) 2x
55
+ │ └── shouldIgnore (core/discovery.js:347) 1x
56
+ ├── parseGitignore (core/discovery.js:130) 1x
57
+ ├── expandGlob (core/discovery.js:190) 1x
58
+ │ ├── parseGlobPattern (core/discovery.js:226) 1x
59
+ │ ├── walkDir (core/discovery.js:283) 1x
60
+ │ └── compareNames (core/discovery.js:169) 1x
61
+ ├── indexFile (core/project.js:273) 1x
62
+ │ ├── addSymbol (core/project.js:343) 4x
68
63
  │ ├── detectLanguage (languages/index.js:157) 1x
69
- │ ├── parseFile (parser.js:93) 1x
70
- │ └── extractImports (imports.js:19) 1x
71
- ├── buildImportGraph (project.js:419) 1x
72
- └── buildInheritanceGraph (project.js:465) 1x
64
+ │ ├── parse (core/parser.js:69) 1x
65
+ │ └── extractImports (core/imports.js:19) 1x
66
+ ├── buildImportGraph (core/project.js:549) 1x
67
+ └── buildInheritanceGraph (core/project.js:627) 1x
73
68
  ```
74
69
 
75
- One command. No files opened. The full execution flow with every function located by file and line.
70
+ One command. No files opened. Every function located by file and line.
76
71
 
77
72
  ---
78
73
 
79
- ## What it does
74
+ ## Understand code you didn't write
75
+
76
+ `ucn about` gives you everything about a function in one shot - who calls it, what it calls, which tests cover it, and the source code.
77
+
78
+ ```
79
+ $ ucn about expandGlob
80
+
81
+ expandGlob (function)
82
+ ════════════════════════════════════════════════════════════
83
+ core/discovery.js:190-221
84
+ expandGlob (pattern, options = {})
85
+
86
+ CALLERS (3):
87
+ cli/index.js:859 [runGlobCommand]
88
+ const files = expandGlob(pattern);
89
+ core/cache.js:274 [isCacheStale]
90
+ const currentFiles = expandGlob(pattern, globOpts);
91
+ core/project.js:195 [build]
92
+ const files = expandGlob(pattern, globOpts);
93
+
94
+ CALLEES (3):
95
+ parseGlobPattern [utility] - core/discovery.js:226
96
+ walkDir [utility] - core/discovery.js:283
97
+ compareNames [utility] - core/discovery.js:169
98
+
99
+ TESTS: 6 matches in 2 file(s)
100
+ ```
101
+
102
+ Need to trace execution upward instead? `ucn reverse-trace fn` walks the caller chain back to entry points.
103
+
104
+ ## Change code without breaking things
105
+
106
+ Before touching a function, check if all existing call sites match its signature:
107
+
108
+ ```
109
+ $ ucn verify expandGlob
110
+
111
+ expandGlob (pattern, options = {})
112
+ Expected arguments: 1-2
113
+
114
+ STATUS: ✓ All calls valid (7 calls, 0 mismatches)
115
+ ```
116
+
117
+ Then preview the refactoring. UCN shows exactly what needs to change and where:
118
+
119
+ ```
120
+ $ ucn plan expandGlob --rename-to=expandGlobPattern
121
+
122
+ SIGNATURE CHANGE:
123
+ Before: expandGlob (pattern, options = {})
124
+ After: expandGlobPattern (pattern, options = {})
125
+
126
+ CHANGES NEEDED: 7 across 4 files
127
+
128
+ cli/index.js :859
129
+ const files = expandGlob(pattern);
130
+ → const files = expandGlobPattern(pattern);
131
+
132
+ core/cache.js :274
133
+ const currentFiles = expandGlob(pattern, globOpts);
134
+ → const currentFiles = expandGlobPattern(pattern, globOpts);
135
+
136
+ core/project.js :195
137
+ const files = expandGlob(pattern, globOpts);
138
+ → const files = expandGlobPattern(pattern, globOpts);
139
+ ```
140
+
141
+ Run `ucn diff-impact --staged` before committing to see what you changed and who calls it.
142
+
143
+ ## Find what to clean up
144
+
145
+ Which tests should you run after a change? `affected-tests` walks the blast radius and finds every test that touches the affected functions:
146
+
147
+ ```
148
+ $ ucn affected-tests expandGlob
149
+
150
+ 1 function changed → 18 functions affected (depth 3)
151
+ Summary: 18 affected → 12 test files, 11/18 functions covered (61%)
152
+
153
+ Uncovered (7): runGlobCommand, runProjectCommand, ...
154
+ ⚠ These affected functions have no test references
155
+ ```
156
+
157
+ ## Find unused code
158
+
159
+ ```
160
+ $ ucn deadcode --exclude=test
161
+
162
+ Dead code: 1 unused symbol(s)
163
+
164
+ core/discovery.js
165
+ [ 162- 166] legacyResolve (function)
166
+ ```
167
+
168
+ ## Extract without reading the whole file
169
+
170
+ ```
171
+ $ ucn fn compareNames
80
172
 
81
- | Task | Command | Output |
82
- |------|---------|--------|
83
- | Understand one symbol deeply | `ucn about expandGlob` | Definition, callers, callees, tests |
84
- | Who calls this and what do they pass? | `ucn impact shouldIgnore` | Call sites with argument context |
85
- | Map an execution path | `ucn trace expandGlob --depth=2` | Call tree |
86
- | Extract just one function | `ucn fn expandGlob` | Surgical snippet, no file read |
87
- | Check all call sites match signature | `ucn verify expandGlob` | Mismatch/uncertain call sites |
88
- | Review branch impact | `ucn diff-impact --base=main` | Changed functions + downstream callers |
89
- | Find deletable code | `ucn deadcode` | Unused symbols, AST-verified |
90
- | Get function + helpers inline | `ucn smart shouldIgnore` | Source with dependencies expanded |
173
+ core/discovery.js:169
174
+ [ 169- 177] compareNames(a, b)
175
+ ────────────────────────────────────────────────────────────
176
+ function compareNames(a, b) {
177
+ const aLower = a.toLowerCase();
178
+ const bLower = b.toLowerCase();
179
+ if (aLower < bLower) return -1;
180
+ if (aLower > bLower) return 1;
181
+ if (a < b) return -1;
182
+ if (a > b) return 1;
183
+ return 0;
184
+ }
185
+ ```
91
186
 
92
187
  ---
93
188
 
94
- ## Setup
189
+ ## Testing and reliability
190
+
191
+ - **Fast** - indexes its own ~25K-line codebase in under 100ms, cached after first run
192
+ - **Discipline** - every bug fix gets a regression test, test code is ~3x the source
193
+ - **Coverage** - every command, every supported language, every surface (CLI, MCP, interactive)
194
+ - **Systematic** - a harness exercises all command and flag combinations against real multi-language fixtures
195
+ - **Test types** - unit, integration, per-language regression, formatter, cache, MCP edge cases, architecture parity guards
95
196
 
96
- ### MCP Server (for AI agents)
197
+ ---
198
+
199
+ ## AI Setup
97
200
 
98
- One-line setup:
201
+ ### MCP
99
202
 
100
203
  ```bash
101
204
  # Claude Code
@@ -138,12 +241,8 @@ VS Code uses `.vscode/mcp.json`:
138
241
 
139
242
  </details>
140
243
 
141
- All commands ship as a single MCP tool - under 2KB of context.
142
-
143
244
  ### Agent Skill (no server needed)
144
245
 
145
- Drop-in for Claude Code or Codex CLI:
146
-
147
246
  ```bash
148
247
  # Claude Code
149
248
  mkdir -p ~/.claude/skills
@@ -156,156 +255,126 @@ cp -r "$(npm root -g)/ucn/.claude/skills/ucn" ~/.agents/skills/
156
255
 
157
256
  ---
158
257
 
159
- ## Examples
160
-
161
- **Extract a function** without reading the file:
162
-
163
- ```
164
- $ ucn fn expandGlob
165
-
166
- core/discovery.js:183
167
- [ 183- 214] expandGlob(pattern, options = {})
168
- ────────────────────────────────────────────────────────────
169
- function expandGlob(pattern, options = {}) {
170
- const root = path.resolve(options.root || process.cwd());
171
- const ignores = options.ignores || DEFAULT_IGNORES;
172
- ...
173
- return files.sort(compareNames);
174
- }
175
- ```
176
-
177
- **See callers and callees:**
178
-
179
- ```
180
- $ ucn context expandGlob
181
-
182
- CALLERS (7):
183
- [1] cli/index.js:785 [runGlobCommand]
184
- const files = expandGlob(pattern);
185
- [2] core/cache.js:149 [isCacheStale]
186
- const currentFiles = expandGlob(pattern, globOpts);
187
- [3] core/project.js:171 [build]
188
- const files = expandGlob(pattern, globOpts);
189
- ...
190
-
191
- CALLEES (3):
192
- [8] parseGlobPattern [utility] - core/discovery.js:219
193
- [9] walkDir [utility] - core/discovery.js:276
194
- [10] compareNames [utility] - core/discovery.js:162
195
- ```
196
-
197
- **See impact of recent edits:**
198
-
199
- ```
200
- $ ucn diff-impact --base=HEAD~1
201
-
202
- 3 modified, 1 new, 12 call sites across 4 files
203
-
204
- MODIFIED FUNCTIONS:
205
-
206
- processOrder
207
- src/orders/service.ts:45
208
- Lines added: 48-52, Lines deleted: 49
209
- Callers (3):
210
- src/api/checkout.ts:89 [handleCheckout]
211
- await processOrder(cart.items, req.user)
212
- src/workers/batch.ts:12 [batchProcess]
213
- processOrder(order.items, systemUser)
214
- src/jobs/daily.ts:88 [runDailyOrders]
215
- results.push(await processOrder(items, admin))
216
- ```
217
-
218
- **Trace a call tree:**
219
-
220
- ```
221
- $ ucn trace expandGlob --depth=2
222
-
223
- expandGlob
224
- ├── parseGlobPattern (core/discovery.js:219) [utility] 1x
225
- │ └── globToRegex (core/discovery.js:256) [utility] 1x
226
- ├── walkDir (core/discovery.js:276) [utility] 1x
227
- │ ├── compareNames (core/discovery.js:162) [utility] 1x
228
- │ ├── shouldIgnore (core/discovery.js:340) [utility] 1x
229
- └── walkDir (core/discovery.js:276) [utility] 1x (see above)
230
- └── compareNames (core/discovery.js:162) [utility] 1x (see above)
231
- ```
232
-
233
- **Find unused code:**
234
-
235
- ```
236
- $ ucn deadcode --exclude=test
237
-
238
- Dead code: 1 unused symbol(s)
239
-
240
- core/discovery.js
241
- [ 162- 166] legacyResolve (function)
242
- ```
243
-
244
- ---
245
-
246
- ## Workflows
247
-
248
- ```bash
249
- # Investigating a bug
250
- ucn about buggyFunction # understand it fully
251
- ucn trace buggyFunction --depth=2 # see what it calls
252
-
253
- # Before modifying code
254
- ucn impact theFunction # who will break?
255
- ucn smart theFunction # function + its helpers inline
256
- # ... make changes ...
257
- ucn verify theFunction # do all call sites still match?
258
-
259
- # Before committing
260
- ucn diff-impact --staged # what I changed + who calls it
261
-
262
- # Cleanup
263
- ucn deadcode --exclude=test # what can be deleted?
264
- ```
265
-
266
- ---
267
-
268
- ## All commands
269
-
270
- ```
271
- UNDERSTAND MODIFY SAFELY
272
- ───────────────────── ─────────────────────
273
- about full picture impact all call sites
274
- context callers + callees blast transitive impact
275
- smart function + helpers diff-impact git diff + callers
276
- trace call tree verify signature check
277
- reverse-trace callers → root plan refactor preview
278
-
279
- FIND & EXTRACT ARCHITECTURE
280
- ───────────────────── ─────────────────────
281
- find locate definitions imports file dependencies
282
- usages all occurrences exporters reverse dependencies
283
- fn extract function graph dependency tree
284
- class extract class circular-deps import cycles
285
- toc project overview related sibling functions
286
- deadcode unused code tests find test coverage
287
- search text search affected-tests tests for changes
288
- example best usage example stacktrace error trace context
289
- lines extract line range api public API surface
290
- expand drill into context typedef type definitions
291
- file-exports file's exports
292
- stats project stats
258
+ ## Full help
259
+
260
+ ```text
261
+ UCN - Universal Code Navigator
262
+
263
+ Supported: JavaScript, TypeScript, Python, Go, Rust, Java, HTML
264
+
265
+ Usage:
266
+ ucn [command] [args] Project mode (current directory)
267
+ ucn <file> [command] [args] Single file mode
268
+ ucn <dir> [command] [args] Project mode (specific directory)
269
+ ucn "pattern" [command] [args] Glob pattern mode
270
+ (Default output is text; add --json for machine-readable JSON)
271
+
272
+ ═══════════════════════════════════════════════════════════════════════════════
273
+ UNDERSTAND CODE
274
+ ═══════════════════════════════════════════════════════════════════════════════
275
+ about <name> Full picture (definition, callers, callees, tests, code)
276
+ context <name> Who calls this + what it calls (numbered for expand)
277
+ smart <name> Function + all dependencies inline
278
+ impact <name> What breaks if changed (call sites grouped by file)
279
+ blast <name> Transitive blast radius (callers of callers, --depth=N)
280
+ trace <name> Call tree visualization (--depth=N expands all children)
281
+ reverse-trace <name> Upward call chain to entry points (--depth=N, default 5)
282
+ related <name> Find similar functions (same file, shared deps)
283
+ example <name> Best usage example with context
284
+
285
+ ═══════════════════════════════════════════════════════════════════════════════
286
+ FIND CODE
287
+ ═══════════════════════════════════════════════════════════════════════════════
288
+ find <name> Find symbol definitions (supports glob: find "handle*")
289
+ usages <name> All usages grouped: definitions, calls, imports, references
290
+ toc Table of contents (compact; --detailed lists all symbols)
291
+ search <term> Text search (regex default, --context=N, --exclude=, --in=)
292
+ Structural: --type=function|class|call --param= --returns= --decorator= --exported --unused
293
+ tests <name> Find test files for a function
294
+ affected-tests <n> Tests affected by a change (blast + test detection, --depth=N)
295
+
296
+ ═══════════════════════════════════════════════════════════════════════════════
297
+ EXTRACT CODE
298
+ ═══════════════════════════════════════════════════════════════════════════════
299
+ fn <name>[,n2,...] Extract function(s) (comma-separated for bulk, --file)
300
+ class <name> Extract class
301
+ lines <range> Extract line range (e.g., lines 50-100)
302
+ expand <N> Show code for item N from context output
303
+
304
+ ═══════════════════════════════════════════════════════════════════════════════
305
+ FILE DEPENDENCIES
306
+ ═══════════════════════════════════════════════════════════════════════════════
307
+ imports <file> What does file import
308
+ exporters <file> Who imports this file
309
+ file-exports <file> What does file export
310
+ graph <file> Full dependency tree (--depth=N, --direction=imports|importers|both)
311
+ circular-deps Detect circular import chains (--file=, --exclude=)
312
+
313
+ ═══════════════════════════════════════════════════════════════════════════════
314
+ REFACTORING HELPERS
315
+ ═══════════════════════════════════════════════════════════════════════════════
316
+ plan <name> Preview refactoring (--add-param, --remove-param, --rename-to)
317
+ verify <name> Check all call sites match signature
318
+ diff-impact What changed in git diff and who calls it (--base, --staged)
319
+ deadcode Find unused functions/classes
320
+ entrypoints Detect framework entry points (routes, DI, tasks)
321
+
322
+ ═══════════════════════════════════════════════════════════════════════════════
323
+ OTHER
324
+ ═══════════════════════════════════════════════════════════════════════════════
325
+ api Show exported/public symbols
326
+ typedef <name> Find type definitions
327
+ stats Project statistics (--functions for per-function line counts)
328
+ stacktrace <text> Parse stack trace, show code at each frame (alias: stack)
329
+
330
+ Common Flags:
331
+ --file <pattern> Filter by file path (e.g., --file=routes)
332
+ --exclude=a,b Exclude patterns (e.g., --exclude=test,mock)
333
+ --in=<path> Only in path (e.g., --in=src/core)
334
+ --depth=N Trace/graph depth (default: 3, also expands all children)
335
+ --direction=X Graph direction: imports, importers, or both (default: both)
336
+ --all Expand truncated sections (about, trace, graph, related)
337
+ --top=N Limit results (find, deadcode)
338
+ --limit=N Limit result count (find, usages, search, deadcode, api, toc)
339
+ --max-files=N Max files to index (large projects)
340
+ --context=N Lines of context around matches
341
+ --json Machine-readable output
342
+ --code-only Filter out comments and strings
343
+ --with-types Include type definitions
344
+ --include-tests Include test files
345
+ --class-name=X Scope to specific class (e.g., --class-name=Repository)
346
+ --include-methods Include method calls (obj.fn) in caller/callee analysis
347
+ --include-uncertain Include ambiguous/uncertain matches
348
+ --show-confidence Show confidence scores per caller/callee edge
349
+ --min-confidence=N Filter edges below confidence threshold (0.0-1.0)
350
+ --include-exported Include exported symbols in deadcode
351
+ --no-regex Force plain text search (regex is default)
352
+ --functions Show per-function line counts (stats command)
353
+ --include-decorated Include decorated/annotated symbols in deadcode
354
+ --framework=X Filter entrypoints by framework (e.g., --framework=express,spring)
355
+ --exact Exact name match only (find)
356
+ --calls-only Only show call/test-case matches (tests)
357
+ --case-sensitive Case-sensitive text search (search)
358
+ --detailed List all symbols in toc (compact by default)
359
+ --top-level Show only top-level functions in toc
360
+ --max-lines=N Max source lines for class (large classes show summary)
361
+ --no-cache Disable caching
362
+ --clear-cache Clear cache before running
363
+ --base=<ref> Git ref for diff-impact (default: HEAD)
293
364
  ```
294
365
 
295
366
  ---
296
367
 
297
368
  ## Limitations
298
369
 
299
- UCN analyzes code structure statically - it doesn't run code.
370
+ - Single-project scope - follows imports within the project, not into `node_modules` or `site-packages`
371
+ - No runtime execution - static analysis only
372
+ - Dynamic dispatch and reflection are only partially visible or invisible
373
+ - JS, TS, and Python method calls can be uncertain when receiver type is unknown
374
+ - Large repos take a few seconds on the first query, then use cache
300
375
 
301
- - **5 languages + HTML** - JS/TS, Python, Go, Rust, Java. Falls back to text search for others.
302
- - **Static analysis only** - Can't follow `eval()`, `getattr()`, reflection, or other dynamic dispatch.
303
- - **Duck-typed methods** - `obj.method()` in JS/TS/Python is marked "uncertain" when the receiver type is ambiguous. Go/Rust/Java resolve with high confidence.
304
- - **Single project scope** - Follows imports within the project but not into `node_modules` or `site-packages`.
305
- - **First-query index time** - A few seconds on large projects. Cached incrementally after that.
376
+ If you need compiler diagnostics, taint analysis, or runtime semantics, those are different tools for different jobs. UCN trades that depth for speed, portability, and zero setup.
306
377
 
307
378
  ---
308
379
 
309
- ## License
310
-
311
380
  MIT
package/cli/index.js CHANGED
@@ -169,7 +169,9 @@ if (unknownFlags.length > 0) {
169
169
  const VALUE_FLAGS = new Set([
170
170
  '--file', '--depth', '--top', '--context', '--direction',
171
171
  '--add-param', '--remove-param', '--rename-to', '--default',
172
- '--base', '--exclude', '--not', '--in', '--max-lines', '--class-name'
172
+ '--base', '--exclude', '--not', '--in', '--max-lines', '--class-name',
173
+ '--type', '--param', '--receiver', '--returns', '--decorator',
174
+ '--limit', '--max-files', '--min-confidence', '--stack', '--framework'
173
175
  ]);
174
176
 
175
177
  // Remove flags from args, then add args after -- (which are all positional)
@@ -1122,6 +1124,7 @@ Common Flags:
1122
1124
  --code-only Filter out comments and strings
1123
1125
  --with-types Include type definitions
1124
1126
  --include-tests Include test files
1127
+ --class-name=X Scope to specific class (e.g., --class-name=Repository)
1125
1128
  --include-methods Include method calls (obj.fn) in caller/callee analysis
1126
1129
  --include-uncertain Include ambiguous/uncertain matches
1127
1130
  --show-confidence Show confidence scores per caller/callee edge
@@ -1246,7 +1249,7 @@ Flags can be added per-command: context myFunc --include-methods
1246
1249
  const tokens = input.split(/\s+/);
1247
1250
  const command = tokens[0];
1248
1251
  // Flags that take a space-separated value (--flag value)
1249
- const valueFlagNames = new Set(['--file', '--in', '--base', '--add-param', '--remove-param', '--rename-to', '--default', '--depth', '--top', '--context', '--max-lines', '--direction', '--exclude', '--not', '--stack']);
1252
+ const valueFlagNames = new Set(['--file', '--in', '--base', '--add-param', '--remove-param', '--rename-to', '--default', '--depth', '--top', '--context', '--max-lines', '--direction', '--exclude', '--not', '--stack', '--type', '--param', '--receiver', '--returns', '--decorator', '--limit', '--max-files', '--min-confidence', '--class-name', '--framework']);
1250
1253
  const flagTokens = [];
1251
1254
  const argTokens = [];
1252
1255
  const skipNext = new Set();
@@ -1456,7 +1459,7 @@ function executeInteractiveCommand(index, command, arg, iflags = {}, cache = nul
1456
1459
  }
1457
1460
 
1458
1461
  case 'graph': {
1459
- const { ok, result, error } = execute(index, 'graph', { file: arg, ...iflags });
1462
+ const { ok, result, error } = execute(index, 'graph', { file: arg || iflags.file, direction: iflags.direction, depth: iflags.depth, all: iflags.all });
1460
1463
  if (!ok) { console.log(error); return; }
1461
1464
  const graphDepth = iflags.depth ? parseInt(iflags.depth) : 2;
1462
1465
  console.log(output.formatGraph(result, { showAll: iflags.all || !!iflags.depth, maxDepth: graphDepth, file: arg }));
package/core/callers.js CHANGED
@@ -456,6 +456,15 @@ function findCallers(index, name, options = {}) {
456
456
  const receiverLower = call.receiver.toLowerCase();
457
457
  const matchesTarget = [...targetTypes].some(cn => cn.toLowerCase() === receiverLower);
458
458
  if (!matchesTarget) {
459
+ // Rust/Go path calls (Type::method() / pkg.Method()): receiver IS the type name
460
+ // If it doesn't match target, it's definitely a different type — filter it
461
+ if (call.isPathCall && /^[A-Z]/.test(call.receiver)) {
462
+ isUncertain = true;
463
+ if (!options.includeUncertain) {
464
+ if (stats) stats.uncertain = (stats.uncertain || 0) + 1;
465
+ continue;
466
+ }
467
+ }
459
468
  const nonTargetClasses = new Set();
460
469
  for (const d of definitions) {
461
470
  const t = d.className || (d.receiver && d.receiver.replace(/^\*/, ''));
@@ -915,7 +924,8 @@ function findCallees(index, def, options = {}) {
915
924
  callees.set(calleeKey, {
916
925
  name: effectiveName,
917
926
  bindingId: bindingResolved,
918
- count: 1
927
+ count: 1,
928
+ ...(call.isConstructor && { isConstructor: true })
919
929
  });
920
930
  }
921
931
  }
@@ -1023,7 +1033,7 @@ function findCallees(index, def, options = {}) {
1023
1033
  // Pre-compute import graph for callee confidence scoring
1024
1034
  const callerImportSet = new Set(index.importGraph.get(def.file) || []);
1025
1035
 
1026
- for (const { name: calleeName, bindingId, count } of callees.values()) {
1036
+ for (const { name: calleeName, bindingId, count, isConstructor } of callees.values()) {
1027
1037
  const symbols = index.symbols.get(calleeName);
1028
1038
  if (symbols && symbols.length > 0) {
1029
1039
  let callee = symbols[0];
@@ -1122,7 +1132,8 @@ function findCallees(index, def, options = {}) {
1122
1132
  if (!bindingId && NON_CALLABLE_TYPES.has(callee.type)) {
1123
1133
  const isFuncField = callee.type === 'field' && callee.fieldType &&
1124
1134
  /^func\b/.test(callee.fieldType);
1125
- if (!isFuncField) continue;
1135
+ // Constructor calls (new Foo()) are always callable regardless of type
1136
+ if (!isFuncField && !isConstructor) continue;
1126
1137
  }
1127
1138
 
1128
1139
  // Skip test-file callees when caller is production code and