ucn 3.8.26 → 4.0.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.
- package/.claude/skills/ucn/SKILL.md +31 -17
- package/README.md +95 -28
- package/cli/index.js +28 -5
- package/core/account.js +354 -0
- package/core/analysis.js +335 -15
- package/core/build-worker.js +21 -1
- package/core/cache.js +52 -3
- package/core/callers.js +3434 -158
- package/core/confidence.js +82 -19
- package/core/deadcode.js +114 -21
- package/core/execute.js +4 -0
- package/core/graph-build.js +44 -2
- package/core/imports.js +118 -1
- package/core/output/analysis.js +345 -83
- package/core/output/reporting.js +8 -2
- package/core/output/shared.js +33 -2
- package/core/output/tracing.js +208 -10
- package/core/project.js +19 -2
- package/core/registry.js +15 -3
- package/core/tracing.js +534 -190
- package/languages/go.js +317 -6
- package/languages/index.js +79 -0
- package/languages/java.js +243 -16
- package/languages/javascript.js +357 -24
- package/languages/python.js +423 -28
- package/languages/rust.js +377 -8
- package/languages/utils.js +72 -18
- package/mcp/server.js +3 -3
- package/package.json +9 -3
- package/.github/workflows/ci.yml +0 -45
- package/.github/workflows/publish.yml +0 -79
|
@@ -57,8 +57,11 @@ Walks UP the caller chain recursively. Shows the full tree of functions affected
|
|
|
57
57
|
ucn blast helper # callers of callers (depth 3)
|
|
58
58
|
ucn blast helper --depth=5 # deeper chain
|
|
59
59
|
ucn blast helper --exclude=test # skip test callers
|
|
60
|
+
ucn blast helper --expand-unverified # follow unverified edges too (marked ⚠, possible impact)
|
|
60
61
|
```
|
|
61
62
|
|
|
63
|
+
The tree trunk is confirmed-evidence-only; dispatch-possible/ambiguous caller candidates appear in an `UNVERIFIED EDGES` section (see "Reading Tiered Output" below).
|
|
64
|
+
|
|
62
65
|
### 4. `trace` — Understand execution flow (downward)
|
|
63
66
|
|
|
64
67
|
Draws the call tree downward from any function. Compact by default; setting `--depth=N` shows the full tree to that depth with all children expanded.
|
|
@@ -85,12 +88,13 @@ ucn class MarketDataFetcher
|
|
|
85
88
|
|
|
86
89
|
### 6. `deadcode` — Find unused code
|
|
87
90
|
|
|
88
|
-
Lists all functions and classes with zero callers across the project. Framework entry points (Express routes, Spring controllers, Celery tasks, etc.) are automatically excluded.
|
|
91
|
+
Lists all functions and classes with zero callers across the project. Framework entry points (Express routes, Spring controllers, Celery tasks, etc.) and exported/public API symbols — including methods of exported classes in JS/TS/Python — are automatically excluded (`--include-exported` audits them). Interface/trait method declarations are labeled `[declared on interface X — contract surface, not executable code]`: unreferenced is true, but deleting one changes the API contract, not dead logic.
|
|
89
92
|
|
|
90
93
|
```bash
|
|
91
94
|
ucn deadcode # Everything
|
|
92
95
|
ucn deadcode --exclude=test # Skip test files (most useful)
|
|
93
96
|
ucn deadcode --include-decorated # Include framework-registered functions
|
|
97
|
+
ucn deadcode --include-exported # Audit exported/public API symbols too
|
|
94
98
|
```
|
|
95
99
|
|
|
96
100
|
### 7. `brief` — One-screen "before-I-touch-this" summary
|
|
@@ -213,23 +217,32 @@ ucn entrypoints --exclude-tests # Hide test fixtures (JUnit @Test, pyte
|
|
|
213
217
|
|
|
214
218
|
`audit-async` is the focused tool for the `awaited=false` case across an entire async function body.
|
|
215
219
|
|
|
216
|
-
##
|
|
220
|
+
## Reading Tiered Output (about / context / impact / trace / blast / reverse-trace / affected-tests)
|
|
221
|
+
|
|
222
|
+
Caller answers are a **partition of every text occurrence** of the symbol — nothing is silently hidden. Sections:
|
|
223
|
+
|
|
224
|
+
- `CALLERS — CONFIRMED (N, X prod + Y test):` — edges with binding/receiver/import evidence. Prod callers listed first, then a `test callers:` subheader. An `evidence:` line aggregates resolution labels for the section.
|
|
225
|
+
- `CALLERS — UNVERIFIED (N) — call syntax, no binding/receiver evidence:` — name-matched call sites the engine could not verify, one line each with the reason (`method-no-evidence`, `ambiguous-binding`, `call-not-resolved`). Capped at 10; `--all` lifts the cap. **Treat these as possible callers when refactoring.**
|
|
226
|
+
- `NON-CALL OCCURRENCES: N (...)` — imports/definitions/references/other-text, counts only (drill in with `ucn usages <name>`).
|
|
227
|
+
- `ACCOUNT:` — the reconciliation line. Every ground line is in exactly one bucket; `0 unaccounted` means the partition is complete. `+N beyond-text callers` are alias-resolved call sites plain text search would miss.
|
|
228
|
+
- `WARNING: N unparsed file(s) ...` — files containing the symbol that failed to parse. Their lines were NOT analyzed — fall back to text search for those files.
|
|
229
|
+
- `FILTERED: N hidden by flags` — entries your display flags hid (they still count in ACCOUNT).
|
|
230
|
+
|
|
231
|
+
**Trust rules:** a CONFIRMED(0) + UNVERIFIED(0) answer with `0 unaccounted` and no WARNING means the symbol genuinely has no callers — safe to act on, same as a clean grep. Any UNVERIFIED entries or WARNINGs mean: verify those sites before a breaking change.
|
|
232
|
+
|
|
233
|
+
Resolution labels in `evidence:` lines (high to low): `exact-binding` (0.98, import/binding evidence) · `same-class` (0.92) · `receiver-hint` (0.80, inferred receiver type) · `scope-match` (0.65, import/receiver-binding scope evidence) · `name-only` (0.40) · `uncertain` (0.25). Confirmed tier = scope-match and above. JSON output keeps per-edge decimals plus `tier`.
|
|
234
|
+
|
|
235
|
+
Flags: `--min-confidence=0.7` filters confirmed edges (hidden count appears in FILTERED). `--include-uncertain` is an **implied no-op** for about/context/impact/trace/blast/reverse-trace/affected-tests (everything is shown, tiered); it keeps its meaning for `smart`/`verify`. `--include-methods` is an implied no-op for about/context/impact.
|
|
236
|
+
|
|
237
|
+
### Tree commands (trace / blast / reverse-trace / affected-tests)
|
|
217
238
|
|
|
218
|
-
`
|
|
239
|
+
The tree trunk holds **confirmed edges only**. Unverified caller candidates render in an `UNVERIFIED EDGES` section with parent attribution (`at <node> (hop N): file:line [enclosing fn] (reason)`) and are **not expanded by default** — pass `--expand-unverified` to follow them; every downstream node is then marked `[⚠ via <reason>]` / `[⚠ unverified chain]` and counted as *possibly affected*, never confirmed. Unresolved callee calls (`trace` down) render as `[unverified] name — reason` leaves under their node. Reconciliation lines:
|
|
219
240
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
| `same-class` | 0.92 | Method call resolved within the enclosing class |
|
|
224
|
-
| `receiver-hint` | 0.80 | Receiver type inferred (Go/Java/Rust) — e.g. `f.run()` where `f: Filter` |
|
|
225
|
-
| `scope-match` | 0.65 | Symbol resolved by name within a file/package scope |
|
|
226
|
-
| `name-only` | 0.40 | Name match only, no binding/scope evidence — review before trusting |
|
|
227
|
-
| `uncertain` | 0.25 | Ambiguous — multiple candidates, hidden unless `--include-uncertain` |
|
|
241
|
+
- `ACCOUNT:` — the root hop's text-ground partition (same as context/impact).
|
|
242
|
+
- `TREE ACCOUNT:` — interior conservation: nodes expanded, confirmed/unverified/excluded edge counts by reason, depth-limit cuts.
|
|
243
|
+
- `CALLEE ACCOUNT:` (trace down) — every call site in every expanded node lands in confirmed/unverified/external/excluded/filtered.
|
|
228
244
|
|
|
229
|
-
|
|
230
|
-
- `--min-confidence=0.7` — keep only high-confidence edges (≥ same-class)
|
|
231
|
-
- `--hide-confidence` — silence the scores (legacy `--no-confidence` is a silent alias)
|
|
232
|
-
- `--include-uncertain` — include otherwise-filtered low-confidence matches
|
|
245
|
+
`reverse-trace` marks `★ entry point` only when a node has **zero candidates in both tiers**; zero confirmed with unverified candidates shows `⚠ no confirmed callers — N unverified` instead. `affected-tests` splits its answer into the confirmed band (`Test files to run`, coverage, `Uncovered`) and a `POSSIBLY AFFECTED` band (functions + test files reachable only through unverified chains).
|
|
233
246
|
|
|
234
247
|
## Symbol Handles (stable IDs)
|
|
235
248
|
|
|
@@ -265,9 +278,10 @@ ucn [target] <command> [name] [--flags]
|
|
|
265
278
|
| `--in=src/core` | Limit search to a subdirectory |
|
|
266
279
|
| `--depth=N` | Control tree depth for `trace`, `graph`, and detail level for `find` (default 3). Also expands all children — no breadth limit |
|
|
267
280
|
| `--all` | Expand truncated sections. Applies to `about`, `blast`, `trace`, `reverse-trace`, `related`, `find`, `toc`, `fn`, `class`, `graph`, `diff-impact` |
|
|
281
|
+
| `--expand-unverified` | `blast`/`reverse-trace`: follow unverified caller edges in the tree. Downstream nodes are marked as unverified chains — possible, not confirmed, impact |
|
|
268
282
|
| `--include-tests` | Include test files in usage counts (`about`) and results (`find`, `usages`, `deadcode`). Callers always include tests. |
|
|
269
283
|
| `--exclude-tests` | Exclude test entries from `entrypoints` (tests are included by default since they ARE entry points). |
|
|
270
|
-
| `--include-methods` | Include `obj.method()` calls in caller/callee analysis.
|
|
284
|
+
| `--include-methods` | Include `obj.method()` calls in caller/callee analysis. Implied (no-op) for `about`/`context`/`impact` — method calls are always analyzed and tiered by receiver evidence. Applies to `verify`, `blast`, `smart`, `trace`, `reverse-trace`, `affected-tests` |
|
|
271
285
|
| `--base=<ref>` | Git ref for diff-impact (default: HEAD) |
|
|
272
286
|
| `--staged` | Analyze staged changes (diff-impact) |
|
|
273
287
|
| `--no-cache` | Force re-index after editing files |
|
|
@@ -289,7 +303,7 @@ ucn [target] <command> [name] [--flags]
|
|
|
289
303
|
| `--max-lines=N` | Max source lines for `class` (large classes show summary by default) |
|
|
290
304
|
| `--case-sensitive` | Case-sensitive text search (default: case-insensitive) |
|
|
291
305
|
| `--exact` | Exact name match only in `find`/`typedef` (no substring) |
|
|
292
|
-
| `--include-uncertain` | Include ambiguous/uncertain matches.
|
|
306
|
+
| `--include-uncertain` | Include ambiguous/uncertain matches. Implied (no-op) for `about`/`context`/`impact` — unverified callers are always shown in their own tier. Applies to `blast`, `smart`, `trace`, `reverse-trace`, `affected-tests` |
|
|
293
307
|
| `--hide-confidence` | Hide confidence scores (shown by default) in `context`/`about` |
|
|
294
308
|
| `--min-confidence=N` | Filter edges below confidence threshold (e.g., `--min-confidence=0.7` keeps only high-confidence edges) |
|
|
295
309
|
| `--calls-only` | Only show call/test-case matches in `tests` (skip file-level results) |
|
package/README.md
CHANGED
|
@@ -34,6 +34,8 @@ UCN is deliberately lightweight:
|
|
|
34
34
|
- **No language servers** - tree-sitter does the parsing, no compilation needed
|
|
35
35
|
- **MCP is optional** - only needed if you connect UCN to an AI agent, the CLI and Skill work on their own
|
|
36
36
|
|
|
37
|
+
And it's built to be **trusted**: every "who calls this?" splits into what UCN can prove and what it can't — each flagged with a reason, nothing silently dropped, [measured in CI against real compilers and language servers](#answers-you-can-trust).
|
|
38
|
+
|
|
37
39
|
---
|
|
38
40
|
|
|
39
41
|
```bash
|
|
@@ -59,16 +61,20 @@ build
|
|
|
59
61
|
│ └── compareNames (core/discovery.js:170) 1x
|
|
60
62
|
├── parallelBuild (core/parallel-build.js:25) 1x
|
|
61
63
|
├── indexFile (core/project.js:310) 1x
|
|
62
|
-
│ ├── addSymbol (core/project.js:
|
|
63
|
-
│ ├── detectLanguage (languages/index.js:
|
|
64
|
+
│ ├── addSymbol (core/project.js:410) 4x
|
|
65
|
+
│ ├── detectLanguage (languages/index.js:288) 1x
|
|
64
66
|
│ ├── parse (core/parser.js:69) 1x
|
|
65
67
|
│ ├── extractImports (core/imports.js:19) 1x
|
|
66
68
|
│ └── extractExports (core/imports.js:44) 1x
|
|
67
|
-
├── buildImportGraph (core/project.js:
|
|
68
|
-
└── buildInheritanceGraph (core/project.js:
|
|
69
|
+
├── buildImportGraph (core/project.js:648) 1x
|
|
70
|
+
└── buildInheritanceGraph (core/project.js:653) 1x
|
|
71
|
+
… calls UCN can't prove a receiver for (arr.push(), obj.get()) show as
|
|
72
|
+
[unverified] leaves — abridged here
|
|
73
|
+
|
|
74
|
+
CALLEE ACCOUNT: 23 nodes · 329 call sites = 43 confirmed + 151 unverified + 34 builtin + 101 excluded
|
|
69
75
|
```
|
|
70
76
|
|
|
71
|
-
One command
|
|
77
|
+
One command, no files opened — and the `CALLEE ACCOUNT:` line proves all 329 calls were sorted, nothing dropped.
|
|
72
78
|
|
|
73
79
|
---
|
|
74
80
|
|
|
@@ -84,25 +90,81 @@ expandGlob (function)
|
|
|
84
90
|
core/discovery.js:191-222 → core/discovery.js:191:expandGlob
|
|
85
91
|
expandGlob (pattern: string, options: number = {}) : string[]
|
|
86
92
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
USAGES: 6 total
|
|
94
|
+
3 calls, 3 imports, 0 references
|
|
95
|
+
|
|
96
|
+
CALLERS — CONFIRMED (7, 3 prod + 4 test):
|
|
97
|
+
evidence: scope-match (all)
|
|
98
|
+
cli/index.js:1201 [runGlobCommand]
|
|
90
99
|
const files = expandGlob(pattern);
|
|
91
|
-
|
|
92
|
-
core/cache.js:417 [isCacheStale]
|
|
100
|
+
core/cache.js:466 [isCacheStale]
|
|
93
101
|
const currentFiles = expandGlob(pattern, globOpts);
|
|
94
|
-
|
|
95
|
-
|
|
102
|
+
core/project.js:192 [build]
|
|
103
|
+
files = expandGlob(pattern, globOpts);
|
|
104
|
+
test callers:
|
|
105
|
+
test/integration.test.js:167
|
|
106
|
+
const files = expandGlob('**/*.go', { root: tmpDir });
|
|
107
|
+
... (3 more test callers)
|
|
96
108
|
|
|
97
109
|
CALLEES (3):
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
110
|
+
evidence: exact-binding (all)
|
|
111
|
+
parseGlobPattern [utility] - core/discovery.js:227 (1x)
|
|
112
|
+
walkDir [utility] {fs} - core/discovery.js:284 (1x)
|
|
113
|
+
compareNames [utility] - core/discovery.js:170 (1x)
|
|
114
|
+
|
|
115
|
+
ACCOUNT: "expandGlob" occurs on 14 lines in 6 files: 7 confirmed, 0 unverified,
|
|
116
|
+
7 non-call (4 import, 1 definition, 1 reference, 1 other-text), 0 other-target, 0 unaccounted
|
|
101
117
|
|
|
102
118
|
TESTS: 5 matches in 1 file(s)
|
|
103
119
|
```
|
|
104
120
|
|
|
105
|
-
|
|
121
|
+
Callers split into **CONFIRMED** (binding/receiver/import evidence — prod first, then tests) and **UNVERIFIED** (found but unproven, each with a reason). The `ACCOUNT:` line reconciles every occurrence; `0 unaccounted` means nothing was hidden. Tune with `--min-confidence` / `--hide-confidence` / `--git`; walk callers *upward* with `ucn reverse-trace fn`.
|
|
122
|
+
|
|
123
|
+
## Answers you can trust
|
|
124
|
+
|
|
125
|
+
UCN doesn't just find a name — it tells you how sure it is. Every answer from `about`, `context`, and `impact` partitions *every* place the name appears into buckets you can act on:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
$ ucn impact saveCache
|
|
129
|
+
|
|
130
|
+
CALL SITES: 2 confirmed + 9 unverified
|
|
131
|
+
|
|
132
|
+
test/regression-go.test.js (2 calls)
|
|
133
|
+
:2004
|
|
134
|
+
saveCache(index, cachePath);
|
|
135
|
+
|
|
136
|
+
UNVERIFIED CALL SITES (9) — call syntax, no binding/receiver evidence:
|
|
137
|
+
mcp/server.js:779: index.saveCache(); (method-ambiguous)
|
|
138
|
+
test/cache.test.js:1779: index.saveCache(); (method-ambiguous)
|
|
139
|
+
... (7 more)
|
|
140
|
+
|
|
141
|
+
ACCOUNT: "saveCache" occurs on 47 lines in 8 files: 2 confirmed, 9 unverified,
|
|
142
|
+
9 non-call (2 import, 1 definition, 0 reference, 6 other-text), 27 other-target, 0 unaccounted
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
UCN sorts every one of the 47 places the name appears:
|
|
146
|
+
|
|
147
|
+
- **2 confirmed** — call sites it can prove resolve to *this* `saveCache`.
|
|
148
|
+
- **9 unverified** — real call sites it found but won't claim. `index.saveCache()` has an untyped receiver, so UCN can't prove which `saveCache` runs; it shows the site and the reason (`method-ambiguous`) instead of guessing.
|
|
149
|
+
- **27 other-target** — occurrences that belong to a *different* `saveCache`, kept separate so they never pollute the answer.
|
|
150
|
+
- **9 non-call** — imports, the definition, plain text.
|
|
151
|
+
- **`0 unaccounted`** — the partition is complete. Nothing was dropped on the floor.
|
|
152
|
+
|
|
153
|
+
The payoff: a **confirmed** answer is safe to refactor against, and an empty result with `0 unaccounted` means the symbol truly has no callers. UCN never hides a caller — and never invents one.
|
|
154
|
+
|
|
155
|
+
### Measured against ground truth
|
|
156
|
+
|
|
157
|
+
This isn't a promise — it's a gate. CI re-derives UCN's caller answers from real compilers and language servers and fails the build if a single true call edge is neither shown nor accounted for:
|
|
158
|
+
|
|
159
|
+
| Language | Oracle | Confirmed-tier precision |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| TypeScript / JavaScript | ts-morph | 99.4–100% |
|
|
162
|
+
| Python | pyright (LSP) | 97.7–99.9% |
|
|
163
|
+
| Go | gopls | 99.9–100% |
|
|
164
|
+
| Rust | rust-analyzer | 98.9–100% |
|
|
165
|
+
| Java | jdtls | 96.2% |
|
|
166
|
+
|
|
167
|
+
Ten pinned real-world repos (zod, express, httpx, rich, cobra, grpc-go, ripgrep, cursive, gson, preact-signals), three sampling seeds, every run gated at `missing-unexplained = 0`. The tree commands — `trace`, `blast`, `reverse-trace`, `affected-tests` — follow the same rule: confirmed trunk, uncertain branches flagged (`--expand-unverified` to follow). Run `ucn doctor` for the trust report on *your* repo.
|
|
106
168
|
|
|
107
169
|
## Change code without breaking things
|
|
108
170
|
|
|
@@ -217,33 +279,36 @@ affected-tests: expandGlob
|
|
|
217
279
|
core/discovery.js:191
|
|
218
280
|
1 function changed → 15 functions affected (depth 3)
|
|
219
281
|
|
|
220
|
-
Test files to run (
|
|
282
|
+
Test files to run (20):
|
|
221
283
|
|
|
222
284
|
test/integration.test.js (covers: expandGlob, build, idx, setupProject)
|
|
223
285
|
L47: index.build(null, { quiet: true }); [call]
|
|
224
286
|
L167: const files = expandGlob('**/*.go', { root: tmpDir }); [call]
|
|
225
287
|
...
|
|
226
288
|
|
|
227
|
-
|
|
289
|
+
POSSIBLY AFFECTED (1) — reachable only through unverified call edges:
|
|
290
|
+
doctor
|
|
291
|
+
|
|
292
|
+
Uncovered (10): runGlobCommand, main, runProjectCommand, runFileCommand, evaluateRepo, ...
|
|
228
293
|
⚠ These affected functions have no test references
|
|
229
294
|
|
|
230
|
-
Summary: 15 affected →
|
|
295
|
+
Summary: 15 affected → 20 test files, 5/15 functions covered (33%) · 1 possibly affected (unverified chains)
|
|
231
296
|
```
|
|
232
297
|
|
|
298
|
+
The confirmed closure is what you run; `POSSIBLY AFFECTED` lists functions reached only through unverified edges — extra tests worth a look, kept separate.
|
|
299
|
+
|
|
233
300
|
## Find unused code
|
|
234
301
|
|
|
235
302
|
```
|
|
236
303
|
$ ucn deadcode --exclude=test
|
|
237
304
|
|
|
238
|
-
Dead code:
|
|
305
|
+
Dead code: 2 unused symbol(s)
|
|
239
306
|
|
|
240
|
-
core/
|
|
241
|
-
[
|
|
242
|
-
[
|
|
243
|
-
core/search.js
|
|
244
|
-
[1409-1445] _testBodyReferencesClass (function)
|
|
307
|
+
core/output/analysis.js
|
|
308
|
+
[ 29- 32] formatHistogramLine (function)
|
|
309
|
+
[ 41- 44] shouldShowReachability (function)
|
|
245
310
|
|
|
246
|
-
|
|
311
|
+
353 exported symbol(s) excluded (all have callers). Use --include-exported to audit them.
|
|
247
312
|
```
|
|
248
313
|
|
|
249
314
|
Find missing-await bugs:
|
|
@@ -297,6 +362,7 @@ function compareNames(a, b) {
|
|
|
297
362
|
- **Coverage** - every command, every supported language, every surface (CLI, MCP, interactive)
|
|
298
363
|
- **Systematic** - a harness exercises all command and flag combinations against real multi-language fixtures
|
|
299
364
|
- **Test types** - unit, integration, per-language regression, formatter, cache, MCP edge cases, architecture parity guards
|
|
365
|
+
- **Ground truth** - caller accuracy is measured against ts-morph, pyright, gopls, rust-analyzer, and jdtls on 10 pinned real repos, gated on zero unexplained edges (see [Answers you can trust](#answers-you-can-trust))
|
|
300
366
|
|
|
301
367
|
---
|
|
302
368
|
|
|
@@ -369,8 +435,9 @@ Run `ucn --help` for the full command list and flags.
|
|
|
369
435
|
|
|
370
436
|
- Single-project scope - follows imports within the project, not into `node_modules` or `site-packages`
|
|
371
437
|
- No runtime execution - static analysis only
|
|
372
|
-
-
|
|
373
|
-
-
|
|
438
|
+
- Reflection (Python `getattr`, Java reflection) is invisible - the target is built at runtime
|
|
439
|
+
- Interface/trait dispatch can't be resolved to a single impl, but candidates are surfaced as `possible-dispatch` in the unverified tier, never silently dropped
|
|
440
|
+
- JS, TS, and Python method calls on an untyped receiver can't always be proven - UCN surfaces these in the UNVERIFIED tier with a reason rather than dropping or guessing them ([Answers you can trust](#answers-you-can-trust))
|
|
374
441
|
- Large repos take a few seconds on the first query, then use cache
|
|
375
442
|
|
|
376
443
|
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.
|
package/cli/index.js
CHANGED
|
@@ -197,6 +197,7 @@ function parseFlags(tokens) {
|
|
|
197
197
|
includeExported: tokens.includes('--include-exported') || undefined,
|
|
198
198
|
includeDecorated: tokens.includes('--include-decorated') || undefined,
|
|
199
199
|
includeUncertain: tokens.includes('--include-uncertain') || undefined,
|
|
200
|
+
expandUnverified: tokens.includes('--expand-unverified') || undefined,
|
|
200
201
|
includeMethods: tokens.some(a => a === '--include-methods=false' || a === '--no-include-methods') ? false : tokens.some(a => a === '--include-methods' || (a.startsWith('--include-methods=') && a !== '--include-methods=false')) ? true : undefined,
|
|
201
202
|
detailed: tokens.includes('--detailed') || undefined,
|
|
202
203
|
topLevel: tokens.includes('--top-level') || undefined,
|
|
@@ -279,11 +280,11 @@ flags.followSymlinks = !args.includes('--no-follow-symlinks');
|
|
|
279
280
|
|
|
280
281
|
// Known flags for validation
|
|
281
282
|
const knownFlags = new Set([
|
|
282
|
-
'--help', '-h', '--mcp',
|
|
283
|
+
'--help', '-h', '--version', '-v', '--mcp',
|
|
283
284
|
'--json', '--verbose', '--no-quiet', '--quiet',
|
|
284
285
|
'--code-only', '--with-types', '--top-level', '--exact', '--case-sensitive',
|
|
285
286
|
'--no-cache', '--clear-cache', '--include-tests', '--exclude-tests',
|
|
286
|
-
'--include-exported', '--include-decorated', '--expand', '--interactive', '-i', '--all', '--include-methods', '--no-include-methods', '--include-uncertain', '--detailed', '--calls-only',
|
|
287
|
+
'--include-exported', '--include-decorated', '--expand', '--interactive', '-i', '--all', '--include-methods', '--no-include-methods', '--include-uncertain', '--expand-unverified', '--detailed', '--calls-only',
|
|
287
288
|
'--file', '--context', '--exclude', '--not', '--in',
|
|
288
289
|
'--depth', '--direction', '--add-param', '--remove-param', '--rename-to',
|
|
289
290
|
'--default', '--top', '--no-follow-symlinks',
|
|
@@ -303,6 +304,12 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
303
304
|
process.exit(0);
|
|
304
305
|
}
|
|
305
306
|
|
|
307
|
+
// Handle version flag — read from package.json (single source of truth, shared with MCP serverInfo)
|
|
308
|
+
if (args.includes('--version') || args.includes('-v')) {
|
|
309
|
+
console.log(require('../package.json').version);
|
|
310
|
+
process.exit(0);
|
|
311
|
+
}
|
|
312
|
+
|
|
306
313
|
// Validate flags
|
|
307
314
|
const unknownFlags = args.filter(a => {
|
|
308
315
|
if (!a.startsWith('-')) return false;
|
|
@@ -653,6 +660,16 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
653
660
|
console.error(`Warning: ${flagToCli(key)} has no effect on '${toCliName(canonical)}'.`);
|
|
654
661
|
}
|
|
655
662
|
}
|
|
663
|
+
// Tiered-output contract: unverified callers are always shown for
|
|
664
|
+
// these commands, so the legacy reveal flags are implied no-ops.
|
|
665
|
+
if (['about', 'context', 'impact', 'trace', 'blast', 'reverseTrace', 'affectedTests'].includes(canonical)) {
|
|
666
|
+
if (flags.includeUncertain) {
|
|
667
|
+
console.error(`Note: --include-uncertain is implied for '${toCliName(canonical)}' — unverified candidates are always shown (tiered).`);
|
|
668
|
+
}
|
|
669
|
+
if (['about', 'context', 'impact'].includes(canonical) && flags.includeMethods) {
|
|
670
|
+
console.error(`Note: --include-methods is implied for '${toCliName(canonical)}' — method calls are tiered by receiver evidence.`);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
656
673
|
}
|
|
657
674
|
|
|
658
675
|
switch (canonical) {
|
|
@@ -1514,7 +1531,7 @@ Common Flags:
|
|
|
1514
1531
|
--in=<path> Only in path (e.g., --in=src/core)
|
|
1515
1532
|
--depth=N Max depth: blast=3, trace=3, reverse-trace=5, graph=2, affected-tests=3
|
|
1516
1533
|
--direction=X Graph direction: imports, importers, or both (default: both)
|
|
1517
|
-
--all Show full results: all callers/callees (about), full tree (trace/blast),
|
|
1534
|
+
--all Show full results: all callers/callees + unverified (about/context), full tree (trace/blast),
|
|
1518
1535
|
all names (related/find/fn/class/toc), all changed (diff-impact)
|
|
1519
1536
|
--top=N Limit callers/callees (about), similar functions (related), search results
|
|
1520
1537
|
--limit=N Limit result count (find, usages, search, deadcode, api, toc, entrypoints, diff-impact)
|
|
@@ -1527,8 +1544,13 @@ Common Flags:
|
|
|
1527
1544
|
--include-tests Include test files in usage counts (about) and results (find, usages, deadcode)
|
|
1528
1545
|
--exclude-tests Exclude test files (entrypoints — tests are included by default)
|
|
1529
1546
|
--class-name=X Scope to specific class (e.g., --class-name=Repository)
|
|
1530
|
-
--include-methods Include method calls (obj.fn) in
|
|
1531
|
-
|
|
1547
|
+
--include-methods Include method calls (obj.fn) in trace/blast/smart/verify analysis
|
|
1548
|
+
(implied for about/context/impact — method calls are tiered by evidence)
|
|
1549
|
+
--include-uncertain Include ambiguous/uncertain matches in smart/verify
|
|
1550
|
+
(implied for about/context/impact/trace/blast/reverse-trace/affected-tests —
|
|
1551
|
+
unverified candidates always shown, tiered)
|
|
1552
|
+
--expand-unverified Follow unverified caller edges in blast/reverse-trace trees
|
|
1553
|
+
(downstream nodes marked as unverified chains — possible, not confirmed, impact)
|
|
1532
1554
|
--hide-confidence Hide confidence scores (shown by default in about, context)
|
|
1533
1555
|
--min-confidence=N Filter low-confidence edges (about, context, blast, trace,
|
|
1534
1556
|
reverse-trace, smart, affected-tests)
|
|
@@ -1561,6 +1583,7 @@ Common Flags:
|
|
|
1561
1583
|
--staged Analyze staged changes (diff-impact)
|
|
1562
1584
|
--no-follow-symlinks Don't follow symbolic links
|
|
1563
1585
|
-i, --interactive Keep index in memory for multiple queries
|
|
1586
|
+
-v, --version Print the UCN version and exit
|
|
1564
1587
|
|
|
1565
1588
|
Quick Start:
|
|
1566
1589
|
ucn toc # See project structure
|