ucn 3.8.22 → 3.8.25

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 (47) hide show
  1. package/.claude/skills/ucn/SKILL.md +114 -11
  2. package/README.md +152 -156
  3. package/cli/index.js +363 -37
  4. package/core/analysis.js +960 -37
  5. package/core/bridge.js +1111 -0
  6. package/core/brief.js +408 -0
  7. package/core/cache.js +213 -59
  8. package/core/callers.js +117 -41
  9. package/core/check.js +200 -0
  10. package/core/deadcode.js +31 -2
  11. package/core/discovery.js +57 -34
  12. package/core/entrypoints.js +638 -4
  13. package/core/execute.js +304 -5
  14. package/core/git-enrich.js +130 -0
  15. package/core/graph-build.js +4 -4
  16. package/core/graph.js +31 -12
  17. package/core/output/analysis.js +157 -25
  18. package/core/output/brief.js +100 -0
  19. package/core/output/check.js +79 -0
  20. package/core/output/doctor.js +85 -0
  21. package/core/output/endpoints.js +239 -0
  22. package/core/output/extraction.js +2 -0
  23. package/core/output/find.js +126 -39
  24. package/core/output/graph.js +48 -15
  25. package/core/output/refactoring.js +103 -5
  26. package/core/output/reporting.js +63 -23
  27. package/core/output/search.js +110 -17
  28. package/core/output/shared.js +56 -2
  29. package/core/output.js +4 -0
  30. package/core/parallel-build.js +10 -7
  31. package/core/parser.js +8 -2
  32. package/core/project.js +147 -41
  33. package/core/registry.js +30 -14
  34. package/core/reporting.js +465 -2
  35. package/core/search.js +139 -15
  36. package/core/shared.js +101 -5
  37. package/core/tracing.js +31 -12
  38. package/core/verify.js +982 -95
  39. package/languages/go.js +91 -6
  40. package/languages/html.js +10 -0
  41. package/languages/java.js +151 -35
  42. package/languages/javascript.js +290 -33
  43. package/languages/python.js +78 -11
  44. package/languages/rust.js +267 -12
  45. package/languages/utils.js +315 -3
  46. package/mcp/server.js +91 -16
  47. package/package.json +10 -2
@@ -91,15 +91,56 @@ ucn deadcode --exclude=test # Skip test files (most useful)
91
91
  ucn deadcode --include-decorated # Include framework-registered functions
92
92
  ```
93
93
 
94
- ### 7. `entrypoints` — Detect framework entry points
94
+ ### 7. `brief` — One-screen "before-I-touch-this" summary
95
+
96
+ AST-only summary of a function: typed signature, first sentence of docstring,
97
+ side-effect classification (fs/network/process/global_mutation), and complexity
98
+ metrics (branches, depth, line count). Lighter than `about`, more useful than
99
+ `fn` when you don't need the body.
100
+
101
+ ```bash
102
+ ucn brief fetch_user
103
+ # fetch_user(user_id: int): dict
104
+ # svc.py:4-8 (5 lines)
105
+ # "Fetch a user from the API."
106
+ # async: no | side_effects: [fs, network, process] | complexity: branches=2, depth=2
107
+ ```
108
+
109
+ ### 8. `doctor` — Project trust report
110
+
111
+ One command that tells you how much UCN trusts the index for this project:
112
+ file/symbol counts, language breakdown, dynamic-import / eval / reflection
113
+ blind spots, parse failures, and a verdict (HIGH/MEDIUM/LOW). Add `--deep` to
114
+ sample resolution coverage and bucket edges by confidence.
115
+
116
+ ```bash
117
+ ucn doctor # fast: counts + blind spots + verdict
118
+ ucn doctor --deep # also samples resolution coverage
119
+ ucn doctor --in=src/core # scope to a subtree
120
+ ```
121
+
122
+ ### 9. `check` — Pre-commit summary
123
+
124
+ Composes `diff-impact` + `verify` + `affected-tests` into one output. Lists
125
+ changed/added/deleted functions, flags signature drift across call sites,
126
+ calls out new functions with no callers, and recommends which tests to run.
127
+
128
+ ```bash
129
+ ucn check # vs HEAD
130
+ ucn check --base=main # vs main branch
131
+ ucn check --staged # only staged changes
132
+ ```
133
+
134
+ ### 10. `entrypoints` — Detect framework entry points
95
135
 
96
136
  Lists functions registered as framework handlers (HTTP routes, DI beans, job schedulers, etc.). Detects patterns across Express, FastAPI, Flask, Spring, Gin, Actix, Celery, pytest, and more.
97
137
 
98
138
  ```bash
99
- ucn entrypoints # All detected entry points
139
+ ucn entrypoints # All detected entry points (tests included by default)
100
140
  ucn entrypoints --type=http # HTTP routes only
101
141
  ucn entrypoints --framework=express # Specific framework
102
142
  ucn entrypoints --file=routes/ # Scoped to files
143
+ ucn entrypoints --exclude-tests # Hide test fixtures (JUnit @Test, pytest, Rust #[test], etc.)
103
144
  ```
104
145
 
105
146
  ## When to Use the Other Commands
@@ -117,7 +158,7 @@ ucn entrypoints --file=routes/ # Scoped to files
117
158
  | Understanding who depends on a file | `ucn exporters <file>` | Which files import it |
118
159
  | See what a file exports | `ucn file-exports <file>` | All exported functions, classes, variables with signatures |
119
160
  | Quick project overview | `ucn toc` | Every file with function/class counts and line counts |
120
- | Project complexity stats | `ucn stats` | File counts, symbol counts, lines by language. `--functions` for per-function line counts |
161
+ | Project complexity stats | `ucn stats` | File counts, symbol counts, lines by language. `--functions` for per-function line counts. `--hot --top=N` for the most-called functions (orientation primitive on a new repo) |
121
162
  | Find by glob pattern | `ucn find "handle*"` | Locate definitions matching a glob (supports * and ?) |
122
163
  | Text search with context | `ucn search term --context=3` | Like grep -C 3, shows surrounding lines |
123
164
  | Regex search (default) | `ucn search '\d+'` | Search supports regex by default (alternation, character classes, etc.) |
@@ -133,13 +174,62 @@ ucn entrypoints --file=routes/ # Scoped to files
133
174
  | File-level dependency tree | `ucn graph <file> --depth=1` | Visual import tree. Setting `--depth=N` expands all children. Can be noisy — use depth=1 for large projects. For function-level flow, use `trace` instead |
134
175
  | Are there circular dependencies? | `ucn circular-deps` | Detect circular import chains. `--file=<pattern>` filters to cycles involving a file. `--exclude=test` skips test files |
135
176
  | What are the framework entry points? | `ucn entrypoints` | Lists all detected routes, DI beans, tasks, etc. Filter: `--type=http`, `--framework=express` |
177
+ | Polyglot route ↔ request matching | `ucn endpoints --bridge` | Server routes (Express/Fastify/Koa/NestJS/Flask/FastAPI/Spring/JAX-RS/Gin/Echo/Chi/Fiber/axum/actix/Next.js) ↔ client requests (fetch/axios/requests/httpx/RestTemplate/WebClient/reqwest). Match confidence: EXACT, PARTIAL, UNCERTAIN. Filter with `--method`, `--prefix`, `--server-only`, `--client-only`, `--unmatched`, `--hide-uncertain` |
136
178
  | Find which tests cover a function | `ucn tests <name>` | Test files and test function names. Scope with `--file`, `--class-name`, `--exclude`, `--calls-only` |
137
- | Extract specific lines from a file | `ucn lines --file=<file> --range=10-20` | Pull a line range without reading the whole file |
179
+ | Extract specific lines from a file | `ucn lines 10-20 --file=<file>` | Pull a line range without reading the whole file |
138
180
  | Find type definitions | `ucn typedef <name>` | Interfaces, enums, structs, traits, type aliases |
139
181
  | See a project's public API | `ucn api` or `ucn api --file=<file>` | All exported/public symbols with signatures |
140
182
  | Drill into context results | `ucn expand <N>` | Show source code for item N from a previous `context` call |
141
183
  | Best usage example of a function | `ucn example <name>` | Finds and scores the best call site with surrounding context |
142
184
  | Debug a stack trace | `ucn stacktrace --stack="<trace>"` | Parses stack frames and shows source context per frame |
185
+ | Quick look before touching a function | `ucn brief <name>` | Signature + docstring + side effects + complexity, one screen |
186
+ | Project trust report | `ucn doctor [--deep]` | Index coverage, blind spots, parse failures, verdict |
187
+ | Pre-commit summary | `ucn check [--base=main]` | Changed funcs + signature drift + affected tests in one shot |
188
+ | Find missing-await bugs | `ucn audit-async` | Lists async calls inside async functions that lack `await`. JS/TS/Python only. Filter with `--file`, `--exclude`, `--limit` |
189
+
190
+ ## Reading Call-Site Patterns
191
+
192
+ `verify`, `impact`, and `about` annotate call sites with structural classification flags. Watch for these in summary lines (`Patterns: 4 in try, 4 in callback`) and per-call-site entries:
193
+
194
+ | Flag | What it means | Why it matters |
195
+ |------|--------------|---------------|
196
+ | `inLoop` | Call is inside a `for`/`while`/comprehension | N+1 query risk, repeated work, performance hot path |
197
+ | `inTry` | Call is wrapped in try/catch (or equivalent) | Errors are handled — different from "must fix" code paths |
198
+ | `inCallback` | Call sits inside a callback/lambda/closure that's not the enclosing function | Async deferred work, may run on a different stack frame |
199
+ | `inTestCase` | Call originates from inside a test function | Isolate production callers from test setup |
200
+ | `awaited` | Call's parent is `await` / `Promise.then` (JS/TS/Python) | Confirms async coordination — its absence on async callees signals a missing-await bug |
201
+
202
+ `audit-async` is the focused tool for the `awaited=false` case across an entire async function body.
203
+
204
+ ## Confidence Scores
205
+
206
+ `about` and `context` show confidence per caller/callee edge by default (e.g. `confidence: 0.65 (scope-match)`). Resolution labels (high to low):
207
+
208
+ | Label | Score | Meaning |
209
+ |-------|-------|---------|
210
+ | `exact-binding` | 0.98 | Import or binding evidence — direct call |
211
+ | `same-class` | 0.92 | Method call resolved within the enclosing class |
212
+ | `receiver-hint` | 0.80 | Receiver type inferred (Go/Java/Rust) — e.g. `f.run()` where `f: Filter` |
213
+ | `scope-match` | 0.65 | Symbol resolved by name within a file/package scope |
214
+ | `name-only` | 0.40 | Name match only, no binding/scope evidence — review before trusting |
215
+ | `uncertain` | 0.25 | Ambiguous — multiple candidates, hidden unless `--include-uncertain` |
216
+
217
+ Filter or hide:
218
+ - `--min-confidence=0.7` — keep only high-confidence edges (≥ same-class)
219
+ - `--hide-confidence` — silence the scores (legacy `--no-confidence` is a silent alias)
220
+ - `--include-uncertain` — include otherwise-filtered low-confidence matches
221
+
222
+ ## Symbol Handles (stable IDs)
223
+
224
+ Every result that lists a symbol emits a **handle** in the form `relativePath:line:name` (e.g. `core/api.ts:42:handler`). Pass it back to any name-accepting command and resolution is pinned to that exact definition — no name disambiguation, no `--file` needed.
225
+
226
+ ```bash
227
+ ucn find handler # → emits src/api.ts:42:handler
228
+ ucn brief src/api.ts:42:handler # pins to that exact one
229
+ ucn impact src/api.ts:42:handler # same
230
+ ```
231
+
232
+ The shorter `relativePath:line` form (no `:name`) also works — UCN looks up the symbol by location. Plain names (`handler`) still work for the fuzzy/heuristic path.
143
233
 
144
234
  ## Command Format
145
235
 
@@ -157,14 +247,15 @@ ucn [target] <command> [name] [--flags]
157
247
 
158
248
  | Flag | When to use it |
159
249
  |------|---------------|
160
- | `--class-name=X` | Scope to specific class (e.g., `--class-name=Repository` for method `save`). Works with `fn`, `about`, `context`, `impact`, `tests`, `example`, `typedef`, `verify`, `plan` |
250
+ | `--class-name=X` | Scope to specific class (e.g., `--class-name=Repository` for method `save`). Works with `about`, `context`, `impact`, `blast`, `smart`, `trace`, `reverse-trace`, `example`, `related`, `brief`, `find`, `usages`, `tests`, `affected-tests`, `fn`, `verify`, `plan`, `typedef` |
161
251
  | `--file=<pattern>` | Disambiguate when a name exists in multiple files (e.g., `--file=api`) |
162
252
  | `--exclude=test,mock` | Focus on production code only |
163
253
  | `--in=src/core` | Limit search to a subdirectory |
164
254
  | `--depth=N` | Control tree depth for `trace`, `graph`, and detail level for `find` (default 3). Also expands all children — no breadth limit |
165
- | `--all` | Expand truncated sections in `about`, `trace`, `graph`, `related` |
255
+ | `--all` | Expand truncated sections. Applies to `about`, `blast`, `trace`, `reverse-trace`, `related`, `find`, `toc`, `fn`, `class`, `graph`, `diff-impact` |
166
256
  | `--include-tests` | Include test files in usage counts (`about`) and results (`find`, `usages`, `deadcode`). Callers always include tests. |
167
- | `--include-methods` | Include `obj.method()` calls in `context`/`smart` (only direct calls shown by default) |
257
+ | `--exclude-tests` | Exclude test entries from `entrypoints` (tests are included by default since they ARE entry points). |
258
+ | `--include-methods` | Include `obj.method()` calls in caller/callee analysis. `impact` defaults to true (show all callable sites); other commands default to false (use `--no-include-methods` to opt out). Applies to `about`, `context`, `impact`, `verify`, `blast`, `smart`, `trace`, `reverse-trace`, `affected-tests` |
168
259
  | `--base=<ref>` | Git ref for diff-impact (default: HEAD) |
169
260
  | `--staged` | Analyze staged changes (diff-impact) |
170
261
  | `--no-cache` | Force re-index after editing files |
@@ -172,19 +263,22 @@ ucn [target] <command> [name] [--flags]
172
263
  | `--context=N` | Lines of surrounding context in `usages`/`search` output |
173
264
  | `--no-regex` | Force plain text search (regex is default) |
174
265
  | `--functions` | Show per-function line counts in `stats` (complexity audit) |
175
- | `--json` | Machine-readable JSON output (wrapped in `{meta, data}`) |
266
+ | `--hot` | List top N most-called functions in `stats` (use with `--top=N`, default 10). Best orientation primitive when entering a new repo |
267
+ | `--diverse` | Cluster `example` call sites by argument shape and return one representative per cluster (use with `--top=N`, default 3) |
268
+ | `--git` | Attach git enrichment to `about` / `brief`: last commit (ISO + author) and recent change count (last 30 days). Skipped silently when not a git repo |
269
+ | `--json` | Machine-readable JSON output. Some commands wrap in `{meta, data}` (e.g., `find`, `deadcode`); others return flat objects (e.g., `about`, `impact`, `verify`, `plan`, `imports`) — check each command's output shape |
176
270
  | `--code-only` | Exclude matches in comments and strings (`search`/`usages`) |
177
271
  | `--with-types` | Include related type definitions in `smart`/`about` output |
178
272
  | `--detailed` | Show full symbol listing per file in `toc` |
179
273
  | `--top-level` | Show only top-level functions in `toc` (exclude nested/indented) |
180
274
  | `--top=N` | Limit result count (default: 10 for most commands) |
181
- | `--limit=N` | Limit result count for `find`, `usages`, `search`, `deadcode`, `api`, `toc`, `entrypoints`, `diff-impact` |
275
+ | `--limit=N` | Limit result count for `find`, `usages`, `toc`, `search`, `deadcode`, `entrypoints`, `endpoints`, `diff-impact`, `check`, `api`, `doctor`, `audit-async` |
182
276
  | `--max-files=N` | Max files to index (for large projects with 10K+ files) |
183
277
  | `--max-lines=N` | Max source lines for `class` (large classes show summary by default) |
184
278
  | `--case-sensitive` | Case-sensitive text search (default: case-insensitive) |
185
279
  | `--exact` | Exact name match only in `find`/`typedef` (no substring) |
186
- | `--include-uncertain` | Include ambiguous/uncertain matches in `context`/`smart`/`about` |
187
- | `--no-confidence` | Hide confidence scores (shown by default) in `context`/`about` |
280
+ | `--include-uncertain` | Include ambiguous/uncertain matches. Applies to `about`, `context`, `blast`, `smart`, `trace`, `reverse-trace`, `affected-tests` |
281
+ | `--hide-confidence` | Hide confidence scores (shown by default) in `context`/`about` |
188
282
  | `--min-confidence=N` | Filter edges below confidence threshold (e.g., `--min-confidence=0.7` keeps only high-confidence edges) |
189
283
  | `--calls-only` | Only show call/test-case matches in `tests` (skip file-level results) |
190
284
  | `--add-param=<name>` | Add a parameter (`plan` command). Combine with `--default=<value>` |
@@ -193,6 +287,13 @@ ucn [target] <command> [name] [--flags]
193
287
  | `--include-exported` | Include exported symbols in `deadcode` results |
194
288
  | `--include-decorated` | Include decorated/annotated symbols in `deadcode` results |
195
289
  | `--framework=X` | Filter `entrypoints` by framework (e.g., `express`, `spring`, `celery`) |
290
+ | `--bridge` | Match server routes to client requests (`endpoints`). Confidence tiers: EXACT, PARTIAL, UNCERTAIN |
291
+ | `--server-only` | Only list server routes (`endpoints`) |
292
+ | `--client-only` | Only list client requests (`endpoints`) |
293
+ | `--unmatched` | Only show routes/requests with no match (`endpoints`, pair with `--bridge`) |
294
+ | `--method=GET` | Filter by HTTP method (`endpoints`) |
295
+ | `--prefix=/api` | Filter routes/requests by path prefix (`endpoints`) |
296
+ | `--hide-uncertain` | Hide UNCERTAIN-confidence bridges (`endpoints`) |
196
297
  | `--type=<kind>` | Structural search: `function`, `class`, `call`, `method`, `type`. Triggers index query instead of text grep |
197
298
  | `--param=<name>` | Structural search: filter by parameter name or type (e.g., `--param=Request`) |
198
299
  | `--receiver=<name>` | Structural search: filter calls by receiver (e.g., `--receiver=db` for all db.* calls) |
@@ -202,6 +303,8 @@ ucn [target] <command> [name] [--flags]
202
303
  | `--unused` | Structural search: only symbols with zero callers |
203
304
  | `--no-follow-symlinks` | Don't follow symbolic links during file discovery |
204
305
  | `--workers=N` | Parallel build workers (auto-detect by default; `0` to disable; env: `UCN_WORKERS`) |
306
+ | `--deep` | `doctor` only: sample resolution coverage. Slower but produces confidence histogram. |
307
+ | `--compact` | One-line-per-item output for `about`/`context`/`find`/`usages`/`impact`. Halves token cost; same info. |
205
308
 
206
309
  ## Workflow Integration
207
310
 
package/README.md CHANGED
@@ -51,21 +51,21 @@ ucn deadcode --exclude=test # unused code, AST-verified
51
51
  $ ucn trace build --depth=2
52
52
 
53
53
  build
54
- ├── detectProjectPattern (core/discovery.js:399) 1x
55
- ├── checkDir (core/discovery.js:403) 2x
56
- │ └── shouldIgnore (core/discovery.js:347) 1x
57
- ├── parseGitignore (core/discovery.js:130) 1x
58
- ├── expandGlob (core/discovery.js:190) 1x
59
- ├── parseGlobPattern (core/discovery.js:226) 1x
60
- ├── walkDir (core/discovery.js:283) 1x
61
- │ └── compareNames (core/discovery.js:169) 1x
62
- ├── indexFile (core/project.js:273) 1x
63
- │ ├── addSymbol (core/project.js:343) 4x
64
- │ ├── detectLanguage (languages/index.js:157) 1x
54
+ ├── detectProjectPattern (core/discovery.js:431) 1x
55
+ ├── parseGitignore (core/discovery.js:131) 1x
56
+ ├── expandGlob (core/discovery.js:191) 1x
57
+ ├── parseGlobPattern (core/discovery.js:227) 1x
58
+ ├── walkDir (core/discovery.js:284) 1x
59
+ └── compareNames (core/discovery.js:170) 1x
60
+ ├── parallelBuild (core/parallel-build.js:25) 1x
61
+ ├── indexFile (core/project.js:310) 1x
62
+ ├── addSymbol (core/project.js:398) 4x
63
+ │ ├── detectLanguage (languages/index.js:209) 1x
65
64
  │ ├── parse (core/parser.js:69) 1x
66
- └── extractImports (core/imports.js:19) 1x
67
- ├── buildImportGraph (core/project.js:549) 1x
68
- └── buildInheritanceGraph (core/project.js:627) 1x
65
+ ├── extractImports (core/imports.js:19) 1x
66
+ │ └── extractExports (core/imports.js:44) 1x
67
+ ├── buildImportGraph (core/project.js:631) 1x
68
+ └── buildInheritanceGraph (core/project.js:636) 1x
69
69
  ```
70
70
 
71
71
  One command. No files opened. Every function located by file and line.
@@ -81,26 +81,28 @@ $ ucn about expandGlob
81
81
 
82
82
  expandGlob (function)
83
83
  ════════════════════════════════════════════════════════════
84
- core/discovery.js:190-221
85
- expandGlob (pattern, options = {})
84
+ core/discovery.js:191-222 → core/discovery.js:191:expandGlob
85
+ expandGlob (pattern: string, options: number = {}) : string[]
86
86
 
87
- CALLERS (3):
88
- cli/index.js:859 [runGlobCommand]
87
+ CALLERS (7):
88
+ confidence: 0 high (>0.8), 7 medium (0.5-0.8), 0 low (<0.5)
89
+ cli/index.js:1190 [runGlobCommand]
89
90
  const files = expandGlob(pattern);
90
- core/cache.js:274 [isCacheStale]
91
+ confidence: 0.65 (scope-match)
92
+ core/cache.js:417 [isCacheStale]
91
93
  const currentFiles = expandGlob(pattern, globOpts);
92
- core/project.js:195 [build]
93
- const files = expandGlob(pattern, globOpts);
94
+ confidence: 0.65 (scope-match)
95
+ ... (5 more)
94
96
 
95
97
  CALLEES (3):
96
- parseGlobPattern [utility] - core/discovery.js:226
97
- walkDir [utility] - core/discovery.js:283
98
- compareNames [utility] - core/discovery.js:169
98
+ parseGlobPattern [utility] - core/discovery.js:227
99
+ walkDir [utility] {fs} - core/discovery.js:284
100
+ compareNames [utility] - core/discovery.js:170
99
101
 
100
- TESTS: 6 matches in 2 file(s)
102
+ TESTS: 5 matches in 1 file(s)
101
103
  ```
102
104
 
103
- Need to trace execution upward instead? `ucn reverse-trace fn` walks the caller chain back to entry points.
105
+ Each caller comes with a confidence score (`exact-binding`, `same-class`, `receiver-hint`, `scope-match`, `name-only`) so you can tell direct calls from name-only matches. Add `--hide-confidence` to silence the scores, or `--min-confidence=0.7` to drop everything below `same-class`. Add `--git` to see who last touched the function. Need to trace execution upward instead? `ucn reverse-trace fn` walks the caller chain back to entry points.
104
106
 
105
107
  ## Change code without breaking things
106
108
 
@@ -109,38 +111,100 @@ Before touching a function, check if all existing call sites match its signature
109
111
  ```
110
112
  $ ucn verify expandGlob
111
113
 
112
- expandGlob (pattern, options = {})
114
+ Verification: expandGlob
115
+ ════════════════════════════════════════════════════════════
116
+ core/discovery.js:191
117
+ expandGlob (pattern: string, options: number = {}) : string[]
118
+
113
119
  Expected arguments: 1-2
114
120
 
115
- STATUS: ✓ All calls valid (7 calls, 0 mismatches)
121
+ STATUS: ✓ All calls valid
122
+ Total calls: 7
123
+ Valid: 7
124
+ Mismatches: 0
125
+ Uncertain: 0
126
+ Patterns: 4 in try, 4 in callback
116
127
  ```
117
128
 
129
+ The `Patterns:` line surfaces structural classification of each call site — `inLoop`, `inTry`, `inCallback`, `inTestCase`, `awaited` — so you can spot risky call sites (e.g., calls inside loops, missing `await`) at a glance. Same line appears on `impact` and inside `about`.
130
+
118
131
  Then preview the refactoring. UCN shows exactly what needs to change and where:
119
132
 
120
133
  ```
121
134
  $ ucn plan expandGlob --rename-to=expandGlobPattern
122
135
 
136
+ Refactoring plan: rename
137
+ ════════════════════════════════════════════════════════════
138
+ core/discovery.js:191
139
+
123
140
  SIGNATURE CHANGE:
124
- Before: expandGlob (pattern, options = {})
125
- After: expandGlobPattern (pattern, options = {})
141
+ Before: expandGlob (pattern: string, options: number = {}) : string[]
142
+ After: expandGlobPattern (pattern: string, options: number = {}) : string[]
126
143
 
127
- CHANGES NEEDED: 7 across 4 files
144
+ CHANGES NEEDED: 11
145
+ Files affected: 4
128
146
 
129
- cli/index.js :859
130
- const files = expandGlob(pattern);
131
- → const files = expandGlobPattern(pattern);
147
+ BY FILE:
132
148
 
133
- core/cache.js :274
134
- const currentFiles = expandGlob(pattern, globOpts);
135
- const currentFiles = expandGlobPattern(pattern, globOpts);
149
+ cli/index.js (2 changes)
150
+ :1190
151
+ const files = expandGlob(pattern);
152
+ → Rename to: const files = expandGlobPattern(pattern);
153
+ :15
154
+ const { expandGlob, findProjectRoot } = require('../core/discovery');
155
+ → Update import: const { expandGlobPattern, findProjectRoot } = require('../core/discovery');
136
156
 
137
- core/project.js :195
138
- const files = expandGlob(pattern, globOpts);
139
- → const files = expandGlobPattern(pattern, globOpts);
157
+ ... (more changes in core/cache.js, core/project.js, test/integration.test.js)
140
158
  ```
141
159
 
142
160
  Run `ucn diff-impact --staged` before committing to see what you changed and who calls it.
143
161
 
162
+ Or wrap the same checks in a single command:
163
+
164
+ ```
165
+ $ ucn check --staged
166
+
167
+ Pre-commit Check vs HEAD
168
+ ════════════════════════════════════════════════════════════
169
+ Changed: 3 functions
170
+ parseFlags (cli/index.js:165) [MODIFIED] 2 callers
171
+ ...
172
+ ```
173
+
174
+ `ucn check` composes `diff-impact` + `verify` + `affected-tests` in one shot — flags ADDED functions with no callers, signature drift across call sites, and recommends which tests to run.
175
+
176
+ ## Get the lay of the land in a new repo
177
+
178
+ ```
179
+ $ ucn brief fetch_user
180
+ fetch_user(user_id: int): dict
181
+ svc.py:4-8 (5 lines)
182
+ "Fetch a user from the API."
183
+ async: no | side_effects: [fs, network, process] | complexity: branches=2, depth=2
184
+ ```
185
+
186
+ `brief` is the lighter alternative to `about` — typed signature, first sentence of the docstring, side-effect classification, and complexity, all in one screen. Pair with `--git` to see who last touched it and how often.
187
+
188
+ ```
189
+ $ ucn doctor
190
+
191
+ UCN Trust Report — /path/to/project
192
+ Index: 144 files, 1569 symbols
193
+ Languages: javascript (74%), typescript (13%), java (4%), python (3%), rust (3%), go (3%)
194
+ Cache: fresh, 221ms build
195
+ ...
196
+ Trust level: HIGH
197
+ ```
198
+
199
+ `doctor` reports how much UCN trusts the index — file/symbol counts, blind spots (dynamic imports, eval, reflection), parse failures, and a verdict. Use `--deep` to also sample resolution coverage.
200
+
201
+ `entrypoints` lists detected framework handlers (HTTP routes, DI beans, jobs, tests):
202
+
203
+ ```
204
+ ucn entrypoints --type=http --framework=spring # narrow to one framework
205
+ ucn entrypoints --exclude-tests # tests are included by default
206
+ ```
207
+
144
208
  ## Find what to clean up
145
209
 
146
210
  Which tests should you run after a change? `affected-tests` walks the blast radius and finds every test that touches the affected functions:
@@ -148,11 +212,22 @@ Which tests should you run after a change? `affected-tests` walks the blast radi
148
212
  ```
149
213
  $ ucn affected-tests expandGlob
150
214
 
151
- 1 function changed → 18 functions affected (depth 3)
152
- Summary: 18 affected → 12 test files, 11/18 functions covered (61%)
215
+ affected-tests: expandGlob
216
+ ════════════════════════════════════════════════════════════
217
+ core/discovery.js:191
218
+ 1 function changed → 15 functions affected (depth 3)
219
+
220
+ Test files to run (19):
153
221
 
154
- Uncovered (7): runGlobCommand, runProjectCommand, ...
222
+ test/integration.test.js (covers: expandGlob, build, idx, setupProject)
223
+ L47: index.build(null, { quiet: true }); [call]
224
+ L167: const files = expandGlob('**/*.go', { root: tmpDir }); [call]
225
+ ...
226
+
227
+ Uncovered (10): runGlobCommand, main, runProjectCommand, ...
155
228
  ⚠ These affected functions have no test references
229
+
230
+ Summary: 15 affected → 19 test files, 5/15 functions covered (33%)
156
231
  ```
157
232
 
158
233
  ## Find unused code
@@ -160,19 +235,47 @@ Uncovered (7): runGlobCommand, runProjectCommand, ...
160
235
  ```
161
236
  $ ucn deadcode --exclude=test
162
237
 
163
- Dead code: 1 unused symbol(s)
238
+ Dead code: 3 unused symbol(s)
239
+
240
+ core/bridge.js
241
+ [ 90- 92] endsWithWildcard (function)
242
+ [ 258- 265] parsePythonDecorator (function)
243
+ core/search.js
244
+ [1409-1445] _testBodyReferencesClass (function)
245
+
246
+ 325 exported symbol(s) excluded (all have callers). Use --include-exported to audit them.
247
+ ```
248
+
249
+ Find missing-await bugs:
164
250
 
165
- core/discovery.js
166
- [ 162- 166] legacyResolve (function)
167
251
  ```
252
+ ucn audit-async
253
+ ```
254
+
255
+ Lists async calls inside async functions that lack `await` (JS/TS/Python).
256
+
257
+ ## Map your API surface across languages
258
+
259
+ UCN can match server routes to client requests across the supported languages — Express/Fastify/Koa/NestJS/Next.js, Flask/FastAPI, Spring/JAX-RS, Go net/http (Gin/Echo/Chi/Fiber), axum/actix-web on the server side; fetch/axios, requests/httpx, RestTemplate/WebClient, reqwest on the client side.
260
+
261
+ ```bash
262
+ ucn endpoints --bridge
263
+
264
+ # Filters
265
+ ucn endpoints --bridge --unmatched # routes with no client / clients with no server
266
+ ucn endpoints --bridge --method=POST
267
+ ucn endpoints --bridge --prefix=/api
268
+ ```
269
+
270
+ Match confidence: `EXACT` (literal-literal), `PARTIAL` (server param ↔ client literal), `UNCERTAIN` (template-literal client). Use `--hide-uncertain` to drop the noisy tier.
168
271
 
169
272
  ## Extract without reading the whole file
170
273
 
171
274
  ```
172
275
  $ ucn fn compareNames
173
276
 
174
- core/discovery.js:169
175
- [ 169- 177] compareNames(a, b)
277
+ core/discovery.js:170
278
+ [ 170- 178] compareNames(a, b)
176
279
  ────────────────────────────────────────────────────────────
177
280
  function compareNames(a, b) {
178
281
  const aLower = a.toLowerCase();
@@ -258,114 +361,7 @@ cp -r "$(npm root -g)/ucn/.claude/skills/ucn" ~/.agents/skills/
258
361
 
259
362
  ## Full help
260
363
 
261
- ```text
262
- UCN - Universal Code Navigator
263
-
264
- Supported: JavaScript, TypeScript, Python, Go, Rust, Java, HTML
265
-
266
- Usage:
267
- ucn [command] [args] Project mode (current directory)
268
- ucn <file> [command] [args] Single file mode
269
- ucn <dir> [command] [args] Project mode (specific directory)
270
- ucn "pattern" [command] [args] Glob pattern mode
271
- (Default output is text; add --json for machine-readable JSON)
272
-
273
- ═══════════════════════════════════════════════════════════════════════════════
274
- UNDERSTAND CODE
275
- ═══════════════════════════════════════════════════════════════════════════════
276
- about <name> Full picture (definition, callers, callees, tests, code)
277
- context <name> Who calls this + what it calls (numbered for expand)
278
- smart <name> Function + all dependencies inline
279
- impact <name> What breaks if changed (call sites grouped by file)
280
- blast <name> Transitive blast radius (callers of callers, --depth=N)
281
- trace <name> Call tree visualization (--depth=N expands all children)
282
- reverse-trace <name> Upward call chain to entry points (--depth=N, default 5)
283
- related <name> Find similar functions (same file, shared deps)
284
- example <name> Best usage example with context
285
-
286
- ═══════════════════════════════════════════════════════════════════════════════
287
- FIND CODE
288
- ═══════════════════════════════════════════════════════════════════════════════
289
- find <name> Find symbol definitions (supports glob: find "handle*")
290
- usages <name> All usages grouped: definitions, calls, imports, references
291
- toc Table of contents (compact; --detailed lists all symbols)
292
- search <term> Text search (regex default, --context=N, --exclude=, --in=)
293
- Structural: --type=function|class|call --param= --returns= --decorator= --exported --unused
294
- tests <name> Find test files for a function
295
- affected-tests <n> Tests affected by a change (blast + test detection, --depth=N)
296
-
297
- ═══════════════════════════════════════════════════════════════════════════════
298
- EXTRACT CODE
299
- ═══════════════════════════════════════════════════════════════════════════════
300
- fn <name>[,n2,...] Extract function(s) (comma-separated for bulk, --file)
301
- class <name> Extract class
302
- lines <range> Extract line range (e.g., lines 50-100)
303
- expand <N> Show code for item N from context output
304
-
305
- ═══════════════════════════════════════════════════════════════════════════════
306
- FILE DEPENDENCIES
307
- ═══════════════════════════════════════════════════════════════════════════════
308
- imports <file> What does file import
309
- exporters <file> Who imports this file
310
- file-exports <file> What does file export
311
- graph <file> Full dependency tree (--depth=N, --direction=imports|importers|both)
312
- circular-deps Detect circular import chains (--file=, --exclude=)
313
-
314
- ═══════════════════════════════════════════════════════════════════════════════
315
- REFACTORING HELPERS
316
- ═══════════════════════════════════════════════════════════════════════════════
317
- plan <name> Preview refactoring (--add-param, --remove-param, --rename-to)
318
- verify <name> Check all call sites match signature
319
- diff-impact What changed in git diff and who calls it (--base, --staged)
320
- deadcode Find unused functions/classes
321
- entrypoints Detect framework entry points (routes, DI, tasks)
322
-
323
- ═══════════════════════════════════════════════════════════════════════════════
324
- OTHER
325
- ═══════════════════════════════════════════════════════════════════════════════
326
- api Show exported/public symbols
327
- typedef <name> Find type definitions
328
- stats Project statistics (--functions for per-function line counts)
329
- stacktrace <text> Parse stack trace, show code at each frame (alias: stack)
330
-
331
- Common Flags:
332
- --file <pattern> Filter by file path (e.g., --file=routes)
333
- --exclude=a,b Exclude patterns (e.g., --exclude=test,mock)
334
- --in=<path> Only in path (e.g., --in=src/core)
335
- --depth=N Trace/graph depth (default: 3, also expands all children)
336
- --direction=X Graph direction: imports, importers, or both (default: both)
337
- --all Expand truncated sections (about, trace, graph, related)
338
- --top=N Limit results (find, deadcode)
339
- --limit=N Limit result count (find, usages, search, deadcode, api, toc)
340
- --max-files=N Max files to index (large projects)
341
- --context=N Lines of context around matches
342
- --json Machine-readable output
343
- --code-only Filter out comments and strings
344
- --with-types Include type definitions
345
- --include-tests Include test files
346
- --class-name=X Scope to specific class (e.g., --class-name=Repository)
347
- --include-methods Include method calls (obj.fn) in caller/callee analysis
348
- --include-uncertain Include ambiguous/uncertain matches
349
- --no-confidence Hide confidence scores (shown by default)
350
- --min-confidence=N Filter edges below confidence threshold (0.0-1.0)
351
- --include-exported Include exported symbols in deadcode
352
- --no-regex Force plain text search (regex is default)
353
- --functions Show per-function line counts (stats command)
354
- --include-decorated Include decorated/annotated symbols in deadcode
355
- --framework=X Filter entrypoints by framework (e.g., --framework=express,spring)
356
- --exact Exact name match only (find)
357
- --calls-only Only show call/test-case matches (tests)
358
- --case-sensitive Case-sensitive text search (search)
359
- --detailed List all symbols in toc (compact by default)
360
- --top-level Show only top-level functions in toc
361
- --max-lines=N Max source lines for class (large classes show summary)
362
- --no-cache Disable caching
363
- --clear-cache Clear cache before running
364
- --base=<ref> Git ref for diff-impact (default: HEAD)
365
- --staged Analyze staged changes (diff-impact)
366
- --no-follow-symlinks Don't follow symbolic links
367
- -i, --interactive Keep index in memory for multiple queries
368
- ```
364
+ Run `ucn --help` for the full command list and flags.
369
365
 
370
366
  ---
371
367