ucn 4.2.3 → 5.0.2
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 +89 -77
- package/.claude/skills/ucn/references/commands.md +62 -68
- package/.claude/skills/ucn/references/trust-contract.md +31 -6
- package/README.md +438 -305
- package/assets/demo.svg +31 -0
- package/cli/index.js +430 -1385
- package/core/account.js +144 -34
- package/core/analysis.js +182 -72
- package/core/ast-analysis.js +279 -0
- package/core/bridge.js +205 -24
- package/core/brief.js +27 -58
- package/core/build-worker.js +21 -140
- package/core/cache.js +513 -11
- package/core/callers.js +4920 -456
- package/core/check.js +13 -4
- package/core/command-contracts.js +402 -0
- package/core/compilation-database.js +276 -0
- package/core/confidence.js +4 -1
- package/core/deadcode.js +397 -19
- package/core/discovery.js +359 -46
- package/core/entrypoints.js +195 -41
- package/core/execute.js +887 -81
- package/core/graph-build.js +162 -7
- package/core/graph.js +53 -77
- package/core/imports.js +65 -6
- package/core/index-ir.js +138 -0
- package/core/ir.js +195 -0
- package/core/output/analysis.js +212 -22
- package/core/output/brief.js +23 -0
- package/core/output/check.js +4 -0
- package/core/output/doctor.js +37 -6
- package/core/output/endpoints.js +5 -2
- package/core/output/extraction.js +24 -12
- package/core/output/find.js +141 -36
- package/core/output/graph.js +11 -5
- package/core/output/public.js +462 -0
- package/core/output/refactoring.js +42 -10
- package/core/output/reporting.js +97 -20
- package/core/output/search.js +24 -16
- package/core/output/shared.js +22 -1
- package/core/output/tracing.js +30 -15
- package/core/output-budget.js +295 -0
- package/core/output.js +1 -0
- package/core/parallel-build.js +44 -11
- package/core/parser.js +3 -3
- package/core/project.js +384 -187
- package/core/public-command.js +47 -0
- package/core/registry.js +247 -117
- package/core/reporting.js +312 -290
- package/core/search.js +317 -185
- package/core/semantic-provider.js +110 -0
- package/core/stacktrace.js +25 -0
- package/core/tracing.js +101 -51
- package/core/trust-matrix.js +19 -40
- package/core/verify.js +534 -37
- package/languages/adapter.js +218 -0
- package/languages/c-family.js +2791 -0
- package/languages/c.js +3 -0
- package/languages/cpp.js +3 -0
- package/languages/csharp.js +1402 -0
- package/languages/go.js +60 -21
- package/languages/html.js +2 -2
- package/languages/index.js +85 -7
- package/languages/java.js +396 -13
- package/languages/javascript.js +199 -19
- package/languages/python.js +964 -22
- package/languages/rust.js +1317 -152
- package/languages/utils.js +40 -3
- package/mcp/server.js +254 -636
- package/package.json +39 -22
- package/eslint.config.js +0 -43
- package/jsconfig.json +0 -10
package/README.md
CHANGED
|
@@ -2,15 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
See what code does before you touch it.
|
|
4
4
|
|
|
5
|
-
Find symbols, trace callers, check impact, pick the right tests, extract code and spot what's dead - from the terminal.
|
|
6
|
-
|
|
7
5
|
[](https://www.npmjs.com/package/ucn)
|
|
8
6
|
[](https://github.com/mleoca/ucn/actions/workflows/ci.yml)
|
|
9
7
|
[](LICENSE)
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
If you work with AI Agents, add UCN as a [Skill or MCP tool](#ai-setup). One tool
|
|
10
|
+
gives the agent compact, source-linked answers to caller, impact, and test
|
|
11
|
+
questions, with uncertainty labeled instead of guessed.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Find symbols, trace callers, check impact, pick the right tests, extract exact
|
|
14
|
+
source, and spot dead code - from your terminal or your AI agent.
|
|
15
|
+
|
|
16
|
+
Supports JavaScript, TypeScript, JSX/TSX, Python, Go, Rust, Java, C, C++, C#,
|
|
17
|
+
and HTML inline scripts. All commands, one engine, three ways to use it:
|
|
18
|
+
|
|
19
|
+
```text
|
|
14
20
|
Terminal AI Agents Agent Skills
|
|
15
21
|
│ │ │
|
|
16
22
|
CLI MCP Skill
|
|
@@ -23,194 +29,229 @@ All commands, one engine, three surfaces:
|
|
|
23
29
|
└─────────────┘
|
|
24
30
|
```
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
UCN is deliberately lightweight:
|
|
32
|
-
|
|
33
|
-
- **No background processes** - parses on demand, answers, exits
|
|
34
|
-
- **No language servers** - tree-sitter does the parsing, no compilation needed
|
|
35
|
-
- **MCP is optional** - only needed if you connect UCN to an AI agent, the CLI and Skill work on their own
|
|
32
|
+
Your tools can already find text. UCN finds *the function* - its definition,
|
|
33
|
+
its callers, its blast radius, its tests - and tells you how sure it is. It
|
|
34
|
+
parses code the way a compiler does (tree-sitter ASTs, not regex) and answers
|
|
35
|
+
the questions you actually have: who calls this? what breaks if I change it?
|
|
36
|
+
which tests should I run? is this dead?
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
It's deliberately lightweight:
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
- **No required background process** - the CLI parses on demand, answers, and
|
|
41
|
+
exits. MCP stays warm only when you choose to run it.
|
|
42
|
+
- **No language servers, no compilation** - tree-sitter does the analysis
|
|
43
|
+
without building the project.
|
|
44
|
+
- **No config** - point it at a directory and ask.
|
|
40
45
|
|
|
41
|
-
|
|
46
|
+
And it's built for auditable trust. grep hands you raw matches to sift
|
|
47
|
+
yourself; UCN separates proven edges from possible ones, explains every
|
|
48
|
+
exclusion, and reconciles every occurrence of the name it searched. It never
|
|
49
|
+
turns a zero into a deletion claim. CI re-derives its answers from real
|
|
50
|
+
compilers and language servers (ts-morph, Pyright, gopls, rust-analyzer,
|
|
51
|
+
JDT LS, Roslyn, clangd) on pinned production repositories. See
|
|
52
|
+
[Answers you can trust](#answers-you-can-trust).
|
|
42
53
|
|
|
43
|
-
|
|
54
|
+
<img src="https://raw.githubusercontent.com/mleoca/ucn/main/assets/demo.svg" alt="ucn show on ripgrep: signature, 123 confirmed callers with evidence types, and the ACCOUNT line reconciling all 136 occurrences of the name" width="100%">
|
|
44
55
|
|
|
45
|
-
-
|
|
46
|
-
- MCP defaults `about`, `context`, and `impact` to compact text. Targeted commands have a 10K character default, broad commands have a 3K default, and the hard ceiling is 100K. Truncated answers retain contract metadata.
|
|
47
|
-
- MCP commands and parameters use snake_case. CLI commands and flags use hyphenated names.
|
|
48
|
-
- A persistent MCP server keeps the process and index warm across calls. Repeated calls are normally faster than launching the CLI for every query, while semantic execution and cache behavior remain shared.
|
|
56
|
+
<sub>Real output: one `ucn show` on [ripgrep](https://github.com/BurntSushi/ripgrep) - signature, 123 proven callers with their evidence, and an account of every occurrence of the name. No files opened.</sub>
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
---
|
|
58
|
+
## Start here
|
|
53
59
|
|
|
54
60
|
```bash
|
|
55
|
-
npm install -g ucn
|
|
61
|
+
npm install -g ucn # Node.js 20+
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
ucn
|
|
59
|
-
ucn
|
|
60
|
-
ucn
|
|
61
|
-
ucn
|
|
63
|
+
cd your-project
|
|
64
|
+
ucn repo # what is this codebase?
|
|
65
|
+
ucn find handleRequest # exact definitions, stable handles
|
|
66
|
+
ucn show src/server.ts:42:handleRequest # the full picture
|
|
67
|
+
ucn trace src/server.ts:42:handleRequest --direction=callers
|
|
68
|
+
ucn impact src/server.ts:42:handleRequest # every call site, with evidence
|
|
69
|
+
ucn tests src/server.ts:42:handleRequest --depth=3 # which tests to run
|
|
62
70
|
```
|
|
63
71
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
```
|
|
67
|
-
$ ucn trace build --depth=2
|
|
68
|
-
|
|
69
|
-
build
|
|
70
|
-
├── detectProjectPattern (core/discovery.js:450) 1x
|
|
71
|
-
├── parseGitignore (core/discovery.js:131) 1x
|
|
72
|
-
├── expandGlob (core/discovery.js:199) 1x
|
|
73
|
-
│ ├── parseGlobPattern (core/discovery.js:238) 1x
|
|
74
|
-
│ ├── walkDir (core/discovery.js:295) 1x
|
|
75
|
-
│ └── compareNames (core/discovery.js:178) 1x
|
|
76
|
-
├── parallelBuild (core/parallel-build.js:25) 1x
|
|
77
|
-
├── indexFile (core/project.js:397) 1x
|
|
78
|
-
│ ├── addSymbol (core/project.js:502) 4x
|
|
79
|
-
│ ├── detectLanguage (languages/index.js:344) 1x
|
|
80
|
-
│ ├── parse (core/parser.js:69) 1x
|
|
81
|
-
│ ├── extractImports (core/imports.js:19) 1x
|
|
82
|
-
│ └── extractExports (core/imports.js:44) 1x
|
|
83
|
-
├── buildImportGraph (core/project.js:798) 1x
|
|
84
|
-
└── buildInheritanceGraph (core/project.js:803) 1x
|
|
85
|
-
… calls UCN can't prove a receiver for (arr.push(), obj.get()) show as
|
|
86
|
-
[unverified] leaves (abridged here)
|
|
87
|
-
|
|
88
|
-
CALLEE ACCOUNT: 26 nodes expanded · 394 call sites = 61 confirmed + 162 unverified (162 uncertain-receiver) + 68 external/builtin + 103 excluded
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
One command, no files opened. The `CALLEE ACCOUNT:` line reconciles all 394 indexed call sites into explicit buckets.
|
|
92
|
-
|
|
93
|
-
---
|
|
72
|
+
The first command builds an incremental index; the rest reuse it. The cache
|
|
73
|
+
lives outside your project directory, so there's nothing to gitignore.
|
|
94
74
|
|
|
95
75
|
## Understand code you didn't write
|
|
96
76
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
77
|
+
What does this function do, who calls it, and how sure is the answer?
|
|
78
|
+
`ucn show` gathers everything useful about one symbol: signature, source,
|
|
79
|
+
callers, callees, tests, types, dependencies, examples. Project it down to
|
|
80
|
+
just the sections you need:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
$ ucn show detectLanguage --sections=summary,callers,callees --compact
|
|
84
|
+
|
|
85
|
+
SUMMARY
|
|
86
|
+
───────
|
|
87
|
+
detectLanguage(filePath: string, projectRoot = null): string|null
|
|
88
|
+
languages/index.js:420-428 (9 lines)
|
|
89
|
+
handle: languages/index.js:420:detectLanguage
|
|
90
|
+
"Detect language from file path"
|
|
91
|
+
async: no | side_effects: [none] | complexity: branches=1, depth=1
|
|
92
|
+
|
|
93
|
+
RELATIONSHIPS
|
|
94
|
+
─────────────
|
|
95
|
+
CALLERS — CONFIRMED (51, 30 prod + 21 test):
|
|
111
96
|
evidence: scope-match (all)
|
|
112
|
-
cli/index.js:
|
|
113
|
-
|
|
114
|
-
core/
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
test/integration.test.js:167
|
|
120
|
-
const files = expandGlob('**/*.go', { root: tmpDir });
|
|
121
|
-
... (3 more test callers)
|
|
122
|
-
|
|
123
|
-
CALLEES (3):
|
|
97
|
+
[1] cli/index.js:604 [runFileCommand]: const language = detectLanguage(filePath);
|
|
98
|
+
[7] core/build-worker.js:39 [processFile]: const language = detectLanguage(filePath, rootDir);
|
|
99
|
+
[17] core/project.js:472 [build]: const language = detectLanguage(filePath, this.root);
|
|
100
|
+
[34] test/parser-unit.test.js:19: assert.strictEqual(detectLanguage('file.js'), 'javascript');
|
|
101
|
+
... 47 more callers
|
|
102
|
+
|
|
103
|
+
CALLEES (1):
|
|
124
104
|
evidence: exact-binding (all)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
105
|
+
[52] detectHeaderLanguage {fs} - core/compilation-database.js:217
|
|
106
|
+
CALLEES — UNVERIFIED (1) — call syntax, receiver/binding unresolved:
|
|
107
|
+
toLowerCase ×1 — possible-dispatch L422
|
|
128
108
|
|
|
129
|
-
ACCOUNT: "
|
|
130
|
-
|
|
109
|
+
ACCOUNT: "detectLanguage" occurs on 79 lines in 20 files: 51 confirmed, 0 unverified,
|
|
110
|
+
28 non-call (18 import, 1 definition, 3 reference, 6 other-text), 0 other-target, 0 unaccounted
|
|
131
111
|
CONTRACT: literal-name text partition complete; semantic completeness is not claimed
|
|
132
|
-
|
|
133
|
-
TESTS: 5 matches in 1 file(s)
|
|
112
|
+
(aliases, indirect calls, generated code, and runtime dispatch may exist).
|
|
134
113
|
```
|
|
135
114
|
|
|
136
|
-
|
|
115
|
+
`find` returns stable handles in `file:line:name` form. Pass a handle to any
|
|
116
|
+
command to pin the answer to one definition, even when several files or classes
|
|
117
|
+
reuse the same name.
|
|
137
118
|
|
|
138
|
-
##
|
|
139
|
-
|
|
140
|
-
UCN doesn't just find a name. It shows the identity evidence it has and the uncertainty it retains. Every answer from `about`, `context`, and `impact` partitions *every observed literal-name occurrence* into auditable buckets:
|
|
141
|
-
|
|
142
|
-
```
|
|
143
|
-
$ ucn impact saveCache
|
|
119
|
+
## Follow the execution path
|
|
144
120
|
|
|
145
|
-
|
|
121
|
+
What happens when `build()` runs?
|
|
146
122
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
saveCache(index, cachePath);
|
|
123
|
+
```text
|
|
124
|
+
$ ucn trace build --depth=2
|
|
150
125
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
126
|
+
build
|
|
127
|
+
├── compareNames (core/discovery.js:293) [regular] 3x
|
|
128
|
+
├── recordDiscoveryIssue (core/project.js:346) 2x
|
|
129
|
+
│ └── [unverified] push — method-ambiguous L351
|
|
130
|
+
├── detectProjectPattern (core/discovery.js:760) [utility] 1x
|
|
131
|
+
├── parseGitignore (core/discovery.js:253) [utility] 1x
|
|
132
|
+
│ ├── gitignoreFiles (core/discovery.js:234) [utility] 1x
|
|
133
|
+
│ ├── compareNames (core/discovery.js:293) [utility] 1x (see above)
|
|
134
|
+
│ └── parseGitignoreFile (core/discovery.js:152) [utility] 1x
|
|
135
|
+
├── gitTrackedPaths (core/discovery.js:266) [utility] 1x
|
|
136
|
+
│ ├── hasGitMetadata (core/discovery.js:224) [utility] 1x
|
|
137
|
+
│ └── [unverified] dirname — method-ambiguous L281,L284
|
|
138
|
+
└── ... more callees
|
|
139
|
+
|
|
140
|
+
CALLEE ACCOUNT: 11 nodes expanded · 210 call sites = 31 confirmed + 33 unverified
|
|
141
|
+
(25 method-ambiguous, 1 possible-dispatch, 7 uncertain-receiver) + 86 external/builtin + 60 excluded
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`trace` walks callees, callers, or callers all the way up to runtime entry
|
|
145
|
+
points (`--direction=callers --to=entrypoints`). Proven edges form the tree;
|
|
146
|
+
calls UCN can't prove a receiver for show up as `[unverified]` leaves with a
|
|
147
|
+
reason. The account line reconciles every call site in the expanded tree, so
|
|
148
|
+
unresolved dispatch stays visible and counted instead of quietly vanishing.
|
|
156
149
|
|
|
157
|
-
|
|
158
|
-
11 non-call (2 import, 1 definition, 1 reference, 7 other-text), 31 other-target, 0 unaccounted
|
|
159
|
-
CONTRACT: literal-name text partition complete; semantic completeness is not claimed
|
|
160
|
-
```
|
|
150
|
+
## Answers you can trust
|
|
161
151
|
|
|
162
|
-
UCN
|
|
152
|
+
UCN doesn't turn every matching name into a semantic claim. Watch it work
|
|
153
|
+
through a name with two definitions and a pile of ambiguous method calls:
|
|
163
154
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
- **31 other-target**: occurrences that belong to a *different* `saveCache`, kept separate so they never pollute the answer.
|
|
167
|
-
- **11 non-call**: imports, the definition, plain text.
|
|
168
|
-
- **`0 unaccounted`**: every line in the observed literal-name set was assigned to a bucket.
|
|
155
|
+
```text
|
|
156
|
+
$ ucn impact saveCache
|
|
169
157
|
|
|
170
|
-
|
|
158
|
+
Impact analysis for saveCache
|
|
159
|
+
core/cache.js:610
|
|
160
|
+
Note: Found 2 definitions for "saveCache". Using core/cache.js:610. Also in: core/project.js:2380. Use file= to disambiguate.
|
|
161
|
+
CALL SITES: 5 confirmed + 15 unverified
|
|
162
|
+
Files affected: 3
|
|
163
|
+
BY FILE:
|
|
164
|
+
core/project.js:2380 [saveCache]: saveCache(cachePath) { return indexCache.saveCache(this, cachePath); }
|
|
165
|
+
test/prerelease-audit.test.js:1493: saveCache(built, cacheFile);
|
|
166
|
+
... (3 more)
|
|
167
|
+
UNVERIFIED CALL SITES (15) — call syntax, no binding/receiver evidence:
|
|
168
|
+
mcp/server.js:517: try { index.saveCache(); } catch (_) { /* best-effort */ } (possible-dispatch via local receiver)
|
|
169
|
+
test/cache.test.js:124: index.saveCache(); (possible-dispatch via local receiver)
|
|
170
|
+
(+13 more)
|
|
171
|
+
ACCOUNT: "saveCache" occurs on 68 lines in 11 files: 5 confirmed, 15 unverified,
|
|
172
|
+
12 non-call (3 import, 1 definition, 1 reference, 7 other-text), 36 other-target, 0 unaccounted
|
|
173
|
+
CONTRACT: literal-name text partition complete; semantic completeness is not claimed
|
|
174
|
+
(aliases, indirect calls, generated code, and runtime dispatch may exist).
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
UCN sorted all 68 places the name appears:
|
|
178
|
+
|
|
179
|
+
- **5 confirmed** - call sites it can *prove* resolve to this `saveCache`,
|
|
180
|
+
via a binding, import, receiver type, qualified path, or same-class evidence.
|
|
181
|
+
- **15 unverified** - real call syntax it refuses to claim. `index.saveCache()`
|
|
182
|
+
sits on an untyped receiver, so the site stays visible with its reason
|
|
183
|
+
(`possible-dispatch via local receiver`) instead of being guessed or dropped.
|
|
184
|
+
- **36 other-target** - occurrences that belong to the *other* `saveCache`,
|
|
185
|
+
kept out of the answer instead of quietly inflating it.
|
|
186
|
+
- **12 non-call** - imports, the definition, comments, strings.
|
|
187
|
+
- **0 unaccounted** - every observed line landed in exactly one bucket.
|
|
188
|
+
|
|
189
|
+
That's the payoff: an answer you (or your agent) can audit, instead of an
|
|
190
|
+
opaque match count. A confirmed edge is evidence about the pinned target. An
|
|
191
|
+
unverified edge is a review item with a stated reason. And a clean zero is an
|
|
192
|
+
*observed-text* zero, not a safe-to-delete claim: aliases, generated code,
|
|
193
|
+
reflection, runtime registration, and external consumers can live beyond the
|
|
194
|
+
indexed evidence, and `ucn repo --sections=health --deep` reports exactly those
|
|
195
|
+
blind spots. Even when output is truncated to fit an agent's budget, the
|
|
196
|
+
ACCOUNT, CONTRACT, and WARNING lines survive the cut.
|
|
171
197
|
|
|
172
198
|
### Measured against ground truth
|
|
173
199
|
|
|
174
|
-
|
|
200
|
+
Don't take the tiers on faith. Release gates re-derive UCN's answers from real
|
|
201
|
+
compilers and language servers on a ten-repository board of pinned production
|
|
202
|
+
codebases, and publishing is blocked unless they pass. The latest full
|
|
203
|
+
release-board run (2026-08-11):
|
|
175
204
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
| Repository | Pinned commit | Language oracle | Confirmed caller precision | Caller recall | Callee precision/recall | Command checks |
|
|
205
|
+
| Repository | Pinned commit | Oracle | Caller precision | Caller recall | Callee prec / recall | Command checks |
|
|
179
206
|
|---|---|---|---:|---:|---:|---:|
|
|
180
207
|
| [preact-signals](https://github.com/preactjs/signals) | [`e0ce9fdf`](https://github.com/preactjs/signals/commit/e0ce9fdf92df7f0ece2c89d44554c39f36dc6882) | ts-morph | 100% | 100% | 100% / 100% | 100% |
|
|
181
|
-
| [httpx](https://github.com/encode/httpx) | [`b5addb64`](https://github.com/encode/httpx/commit/b5addb64f0161ff6bfe94c124ef76f6a1fba5254) |
|
|
208
|
+
| [httpx](https://github.com/encode/httpx) | [`b5addb64`](https://github.com/encode/httpx/commit/b5addb64f0161ff6bfe94c124ef76f6a1fba5254) | Pyright | 100% | 100% | 100% / 100% | 100% |
|
|
182
209
|
| [cobra](https://github.com/spf13/cobra) | [`ad460ea8`](https://github.com/spf13/cobra/commit/ad460ea8f249db69c943a365fb84f3a59042d54e) | gopls | 100% | 100% | 100% / 100% | 100% |
|
|
183
210
|
| [viper](https://github.com/spf13/viper) | [`528f7416`](https://github.com/spf13/viper/commit/528f7416c4b56a4948673984b190bf8713f0c3c4) | gopls | 100% | 100% | 100% / 100% | 100% |
|
|
184
211
|
| [ripgrep](https://github.com/BurntSushi/ripgrep) | [`82313cf9`](https://github.com/BurntSushi/ripgrep/commit/82313cf95849bfe425109ad9506a52154879b1b1) | rust-analyzer | 100% | 100% | 100% / 100% | 100% |
|
|
185
212
|
| [clap](https://github.com/clap-rs/clap) | [`d3e59a9a`](https://github.com/clap-rs/clap/commit/d3e59a9ab214910b9dad02921b7ef42c6400de9b) | rust-analyzer | 100% | 100% | 100% / 100% | 100% |
|
|
186
|
-
| [javapoet](https://github.com/square/javapoet) | [`b9017a95`](https://github.com/square/javapoet/commit/b9017a9503b76e11b4ad4c1a9f050e2d29112cb0) |
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
213
|
+
| [javapoet](https://github.com/square/javapoet) | [`b9017a95`](https://github.com/square/javapoet/commit/b9017a9503b76e11b4ad4c1a9f050e2d29112cb0) | JDT LS | 100% | 100% | 100% / 100% | 100% |
|
|
214
|
+
| [newtonsoft-json](https://github.com/JamesNK/Newtonsoft.Json) | [`4f73e743`](https://github.com/JamesNK/Newtonsoft.Json/commit/4f73e74372445108d2c1bda37b36e6f5e43402e0) | Roslyn | 99.4% | 100% | 100% / 100% | 100% |
|
|
215
|
+
| [cjson](https://github.com/DaveGamble/cJSON) | [`c859b25d`](https://github.com/DaveGamble/cJSON/commit/c859b25da02955fef659d658b8f324b5cde87be3) | clangd | 100% | 100% | 100% / 100% | 100% |
|
|
216
|
+
| [fmt](https://github.com/fmtlib/fmt) | [`e424e3f2`](https://github.com/fmtlib/fmt/commit/e424e3f2e607da02742f73db84873b8084fc714c) | clangd | 99.6% | 100% | 100% / 100% | 100% |
|
|
217
|
+
|
|
218
|
+
On the same run: **zero** in-scope oracle call edges missing from the answer
|
|
219
|
+
(the release gate) on every repository, **zero** false-dead `deadcode` claims
|
|
220
|
+
in the oracle-visible sample, **8,000 / 8,000** cross-command consistency
|
|
221
|
+
comparisons in agreement, **10 / 10** repositories inside the performance
|
|
222
|
+
budget (slowest median cold build 15.4K lines/second by wall time, worst query
|
|
223
|
+
p95 73.8 ms, highest peak RSS 771 MB), and 3,383 automated tests with no
|
|
224
|
+
failures or skips. The same gates run in CI (the scheduled
|
|
225
|
+
[Eval workflow](https://github.com/mleoca/ucn/actions/workflows/eval.yml) and
|
|
226
|
+
every release tag), and `npm run trust:gate` reproduces the release board
|
|
227
|
+
locally. Pinned sources: [`eval/lib/repos.js`](eval/lib/repos.js).
|
|
228
|
+
|
|
229
|
+
Semantic runs draw a deterministic, reference-stratified sample of up to 50
|
|
230
|
+
compiler/LSP symbols per repository, then check caller identity, callee
|
|
231
|
+
identity, account conservation, review burden, and the public commands `find`,
|
|
232
|
+
`show`, `source`, `trace`, `impact`, `usages`, and `tests` against that same
|
|
233
|
+
external population. Unverified precision is reported separately and is
|
|
234
|
+
intentionally much lower on dispatch-heavy code: those entries are review
|
|
235
|
+
candidates, never confirmed claims.
|
|
236
|
+
|
|
237
|
+
Beyond the publish gate, a scheduled board re-checks 22 pinned repositories
|
|
238
|
+
across every supported oracle language (zod, express, hono, zustand, fastify,
|
|
239
|
+
rich, click, grpc-go, chi, cursive, gson, jsoup, and friends), plus a rotating
|
|
240
|
+
fresh-repo arm of codebases the engine was never tuned on. Repositories that
|
|
241
|
+
expose a gap stay on the board; they don't get removed to keep a table pretty.
|
|
242
|
+
These are measured results on pinned code, not a claim of universal program
|
|
243
|
+
understanding or identical performance on every machine.
|
|
203
244
|
|
|
204
245
|
## Change code without breaking things
|
|
205
246
|
|
|
206
|
-
|
|
247
|
+
Will this change break a call site you've never seen? Check before you edit:
|
|
207
248
|
|
|
208
|
-
```
|
|
209
|
-
$ ucn
|
|
249
|
+
```text
|
|
250
|
+
$ ucn check expandGlob
|
|
210
251
|
|
|
211
252
|
Verification: expandGlob
|
|
212
253
|
════════════════════════════════════════════════════════════
|
|
213
|
-
core/discovery.js:
|
|
254
|
+
core/discovery.js:314
|
|
214
255
|
expandGlob (pattern: string, options: number = {}) : string[]
|
|
215
256
|
|
|
216
257
|
Expected arguments: 1-2
|
|
@@ -221,228 +262,301 @@ STATUS: ✓ All calls valid
|
|
|
221
262
|
Mismatches: 0
|
|
222
263
|
Uncertain: 0
|
|
223
264
|
Patterns: 4 in try, 4 in callback
|
|
224
|
-
```
|
|
225
265
|
|
|
226
|
-
|
|
266
|
+
ACCOUNT: "expandGlob" occurs on 14 lines in 6 files: 7 confirmed, 0 unverified,
|
|
267
|
+
7 non-call (4 import, 1 definition, 2 reference, 0 other-text), 0 other-target, 0 unaccounted
|
|
268
|
+
```
|
|
227
269
|
|
|
228
|
-
|
|
270
|
+
The `Patterns:` line classifies call-site structure (`inLoop`, `inTry`,
|
|
271
|
+
`inCallback`, `awaited`) so risky sites stand out. Then preview the refactor.
|
|
272
|
+
UCN shows exactly what would need to change and where:
|
|
229
273
|
|
|
230
|
-
```
|
|
274
|
+
```text
|
|
231
275
|
$ ucn plan expandGlob --rename-to=expandGlobPattern
|
|
232
276
|
|
|
233
277
|
Refactoring plan: rename
|
|
234
278
|
════════════════════════════════════════════════════════════
|
|
235
|
-
core/discovery.js:
|
|
279
|
+
core/discovery.js:314
|
|
236
280
|
|
|
237
281
|
SIGNATURE CHANGE:
|
|
238
282
|
Before: expandGlob (pattern: string, options: number = {}) : string[]
|
|
239
283
|
After: expandGlobPattern (pattern: string, options: number = {}) : string[]
|
|
240
284
|
|
|
241
|
-
CHANGES NEEDED:
|
|
242
|
-
Files affected:
|
|
285
|
+
CHANGES NEEDED: 12
|
|
286
|
+
Files affected: 5
|
|
287
|
+
Definition 1, calls/references 7, imports 4, exports 0; manual review required for 0 of these changes
|
|
243
288
|
|
|
244
289
|
BY FILE:
|
|
245
290
|
|
|
246
291
|
cli/index.js (2 changes)
|
|
247
|
-
:
|
|
292
|
+
:771 [call]
|
|
248
293
|
const files = expandGlob(pattern);
|
|
249
294
|
→ Rename to: const files = expandGlobPattern(pattern);
|
|
250
|
-
:15
|
|
295
|
+
:15 [import]
|
|
251
296
|
const { expandGlob, findProjectRoot } = require('../core/discovery');
|
|
252
297
|
→ Update import: const { expandGlobPattern, findProjectRoot } = require('../core/discovery');
|
|
253
298
|
|
|
254
|
-
... (more changes in core/cache.js, core/project.js, test/integration.test.js)
|
|
299
|
+
... (more changes in core/discovery.js, core/cache.js, core/project.js, test/integration.test.js)
|
|
255
300
|
```
|
|
256
301
|
|
|
257
|
-
|
|
302
|
+
Anything `plan` can't represent safely is marked `needsReview` instead of
|
|
303
|
+
being silently rewritten. Before committing, point the same machinery at your
|
|
304
|
+
Git diff:
|
|
258
305
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
$ ucn check --staged
|
|
263
|
-
|
|
264
|
-
Pre-commit Check vs HEAD
|
|
265
|
-
════════════════════════════════════════════════════════════
|
|
266
|
-
Changed: 3 functions
|
|
267
|
-
parseFlags (cli/index.js:165) [MODIFIED] 2 callers
|
|
268
|
-
...
|
|
306
|
+
```bash
|
|
307
|
+
ucn impact --staged # what did I change, and who depends on it?
|
|
308
|
+
ucn check --staged # signature drift, orphaned functions, tests to run
|
|
269
309
|
```
|
|
270
310
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
## Get the lay of the land in a new repo
|
|
311
|
+
## Pick the right tests
|
|
274
312
|
|
|
275
|
-
|
|
313
|
+
Which tests actually exercise this function, directly or three hops away?
|
|
276
314
|
|
|
277
|
-
```
|
|
278
|
-
$ ucn
|
|
315
|
+
```text
|
|
316
|
+
$ ucn tests expandGlob --depth=3
|
|
279
317
|
|
|
280
|
-
|
|
318
|
+
affected-tests: expandGlob
|
|
281
319
|
════════════════════════════════════════════════════════════
|
|
282
|
-
|
|
320
|
+
core/discovery.js:314
|
|
321
|
+
1 function changed → 12 functions affected (depth 3)
|
|
283
322
|
|
|
284
|
-
|
|
285
|
-
core 516 symbols · 29 file(s)
|
|
286
|
-
languages 282 symbols · 8 file(s)
|
|
287
|
-
test 209 symbols · 29 file(s)
|
|
288
|
-
core/output 142 symbols · 14 file(s)
|
|
289
|
-
...
|
|
323
|
+
Test files to run (30):
|
|
290
324
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
325
|
+
test/integration.test.js (links: expandGlob, build, idx, setupProject)
|
|
326
|
+
L169: const files = expandGlob('**/*.go', { root: tmpDir }); [call]
|
|
327
|
+
test/prerelease-audit.test.js (links: isCacheStale, runInteractive, build, idx)
|
|
328
|
+
L39: const index = idx(dir); [call]
|
|
295
329
|
...
|
|
296
330
|
|
|
297
|
-
|
|
298
|
-
TRUST: MEDIUM; 41 dynamic import(s), 13 eval, 6 reflection (ucn doctor for detail)
|
|
299
|
-
|
|
300
|
-
Next: ucn about execute · ucn toc --detailed · ucn stats --hot --top=20 · ucn doctor --deep
|
|
331
|
+
Summary: 12 affected → 30 statically linked test files, 5/12 functions linked (42%) · 1 possibly affected (unverified chains)
|
|
301
332
|
```
|
|
302
333
|
|
|
303
|
-
|
|
334
|
+
`tests` reports static call/reference linkage, not runtime coverage. Functions
|
|
335
|
+
reached only through unverified edges are listed separately as *possibly
|
|
336
|
+
affected*, and empty results warn about subprocess tests, reflection, and
|
|
337
|
+
external harnesses that may still exercise the target.
|
|
304
338
|
|
|
305
|
-
|
|
306
|
-
$ ucn brief fetch_user
|
|
307
|
-
fetch_user(user_id: int): dict
|
|
308
|
-
svc.py:4-8 (5 lines)
|
|
309
|
-
"Fetch a user from the API."
|
|
310
|
-
async: no | side_effects: [fs, network, process] | complexity: branches=2, depth=2
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
`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.
|
|
314
|
-
|
|
315
|
-
```
|
|
316
|
-
$ ucn doctor
|
|
317
|
-
|
|
318
|
-
UCN Trust Report: /path/to/project
|
|
319
|
-
Index: 169 files, 2104 symbols
|
|
320
|
-
Languages: javascript (72%), typescript (14%), java (4%), python (4%), rust (4%), go (3%)
|
|
321
|
-
Cache: fresh, 344ms build
|
|
322
|
-
Command proofs: 39/39 classified, 22 external-oracle-backed, 0 unclassified
|
|
323
|
-
|
|
324
|
-
Readiness:
|
|
325
|
-
navigation: HIGH: fresh index; no parse failures
|
|
326
|
-
refactor: UNKNOWN: run --deep; review unverified and non-call occurrences
|
|
327
|
-
deletion: REVIEW: usages, public API, compiler, and tests are still required
|
|
328
|
-
```
|
|
329
|
-
|
|
330
|
-
`doctor` reports task-specific readiness for the index: file/symbol counts, blind spots (dynamic imports, eval, reflection), parse failures, command-proof classification, and separate navigation/refactor/deletion levels. Use `--deep` to sample the resolution evidence profile. This profile is not measured accuracy; use the oracle reports for accuracy.
|
|
339
|
+
## Get the lay of the land
|
|
331
340
|
|
|
332
|
-
|
|
341
|
+
One command answers "what is this codebase?" Here it is on ripgrep:
|
|
333
342
|
|
|
334
|
-
```
|
|
335
|
-
ucn
|
|
336
|
-
ucn entrypoints --exclude-tests # tests are included by default
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
## Find what to clean up
|
|
340
|
-
|
|
341
|
-
Which tests should you run after a change? `affected-tests` walks the blast radius and finds every test that touches the affected functions:
|
|
342
|
-
|
|
343
|
-
```
|
|
344
|
-
$ ucn affected-tests expandGlob
|
|
343
|
+
```text
|
|
344
|
+
$ ucn repo
|
|
345
345
|
|
|
346
|
-
|
|
346
|
+
PROJECT ORIENTATION — ripgrep
|
|
347
347
|
════════════════════════════════════════════════════════════
|
|
348
|
-
|
|
349
|
-
1 function changed → 15 functions affected (depth 3)
|
|
350
|
-
|
|
351
|
-
Test files to run (20):
|
|
348
|
+
100 files · 4755 symbols · language mix by symbols: rust 100%
|
|
352
349
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
350
|
+
TOP DIRS (by symbols):
|
|
351
|
+
crates/core/flags 1510 symbols · 6 file(s)
|
|
352
|
+
crates/printer/src 677 symbols · 11 file(s)
|
|
353
|
+
crates/ignore/src 607 symbols · 8 file(s)
|
|
354
|
+
crates/globset/src 331 symbols · 5 file(s)
|
|
355
|
+
|
|
356
|
+
HOT (most-called production functions, top 8 of 2238 raw candidates):
|
|
357
|
+
parse_low_raw — 545 call(s) · crates/core/flags/parse.rs:139
|
|
358
|
+
SearcherBuilder.build — 123 call(s) · crates/searcher/src/searcher/mod.rs:315
|
|
359
|
+
Searcher.search_reader — 123 call(s) · crates/searcher/src/searcher/mod.rs:727
|
|
360
|
+
RegexMatcher.new — 100 call(s) · crates/regex/src/matcher.rs:385
|
|
361
|
+
...
|
|
360
362
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
+
ENTRY POINTS: 426 — test 421, runtime 5
|
|
364
|
+
TRUST: PARTIAL — 48 glob import(s), 5 unsupported source file(s) (ucn repo --sections=health --deep for detail)
|
|
365
|
+
SKIPPED SOURCE: 5 file(s) (Shell 4, Ruby 1) — use grep/ripgrep plus a language-native analyzer.
|
|
363
366
|
|
|
364
|
-
|
|
367
|
+
Next: ucn show parse_low_raw · ucn repo --sections=files --detailed · ucn repo --sections=health --deep
|
|
365
368
|
```
|
|
366
369
|
|
|
367
|
-
|
|
370
|
+
Size, layout, hot spots, entry points, and an honest trust line. Note the
|
|
371
|
+
`SKIPPED SOURCE` handoff: when a repo mixes in languages UCN can't parse, it
|
|
372
|
+
says so and points you at the right tool, instead of presenting a clean-looking
|
|
373
|
+
answer over a partial index.
|
|
368
374
|
|
|
369
|
-
## Find
|
|
375
|
+
## Find dead code you can act on
|
|
370
376
|
|
|
371
|
-
```
|
|
377
|
+
```text
|
|
372
378
|
$ ucn deadcode --exclude=test # run on ripgrep
|
|
373
379
|
|
|
374
|
-
Dead code:
|
|
380
|
+
Dead code: 3 unused symbol(s)
|
|
375
381
|
|
|
376
382
|
crates/globset/src/serde_impl.rs
|
|
377
383
|
[ 38- 42] Glob.deserialize (method)
|
|
378
384
|
[ 70- 74] GlobSet.deserialize (method)
|
|
379
385
|
crates/matcher/src/lib.rs
|
|
380
386
|
[ 397- 399] Captures.as_match (method)
|
|
381
|
-
[ 669- 678] Matcher.try_find_iter (method) [only self-references, recursive]
|
|
382
|
-
[ 796- 806] Matcher.try_captures_iter (method) [only self-references, recursive]
|
|
383
|
-
...
|
|
384
387
|
|
|
385
|
-
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
Classes, structs, traits, and enums are audited alongside functions. Symbols whose only call sites live inside their own definitions are claimed too, marked `[only self-references, recursive]`. Deadcode claims are re-derived against compiler/LSP ground truth in CI. A default-audit claim with an oracle-visible reference fails the build.
|
|
388
|
+
33 decorated/annotated symbol(s) hidden (framework-registered). Use --include-decorated to include them.
|
|
389
389
|
|
|
390
|
-
|
|
390
|
+
903 exported symbol(s) excluded from the audit (public API may have external callers). Use --include-exported to audit them.
|
|
391
391
|
|
|
392
|
-
|
|
393
|
-
ucn audit-async
|
|
392
|
+
WARNING: source coverage is incomplete (5 unsupported-language); 17 candidate name(s) found in skipped source were suppressed.
|
|
394
393
|
```
|
|
395
394
|
|
|
396
|
-
|
|
395
|
+
Three claims, and every one is re-checked against rust-analyzer in CI: a
|
|
396
|
+
default-audit claim with an oracle-visible reference fails the build. Notice
|
|
397
|
+
what it *didn't* claim: exported API that external code may call,
|
|
398
|
+
framework-registered symbols, and anything whose name appears in files UCN
|
|
399
|
+
couldn't parse. `deadcode` is deliberately a candidate generator. Before
|
|
400
|
+
deleting, corroborate with `usages`, `impact`, `api`, and your compiler and
|
|
401
|
+
tests.
|
|
397
402
|
|
|
398
|
-
|
|
403
|
+
For missing-await bugs, `ucn audit-async` lists async calls inside async
|
|
404
|
+
functions that lack `await` (JS/TS/Python).
|
|
399
405
|
|
|
400
|
-
|
|
406
|
+
## Map dependencies and API surfaces
|
|
401
407
|
|
|
402
408
|
```bash
|
|
403
|
-
ucn
|
|
404
|
-
|
|
405
|
-
#
|
|
406
|
-
ucn
|
|
407
|
-
ucn
|
|
408
|
-
ucn endpoints --bridge --
|
|
409
|
+
ucn deps src/server.ts --direction=imports --detailed
|
|
410
|
+
ucn deps src/server.ts --direction=importers --depth=3
|
|
411
|
+
ucn deps --cycles # circular imports
|
|
412
|
+
ucn api # public surface of the project
|
|
413
|
+
ucn entrypoints --type=http # runtime and framework roots
|
|
414
|
+
ucn endpoints --bridge --unmatched # server routes with no client, and vice versa
|
|
409
415
|
```
|
|
410
416
|
|
|
411
|
-
|
|
417
|
+
`endpoints --bridge` matches server routes to client requests across
|
|
418
|
+
languages: Express/Fastify/Koa/NestJS/Next.js, Flask/FastAPI, Spring/JAX-RS,
|
|
419
|
+
Go net/http (Gin/Echo/Chi/Fiber), axum/actix-web, and ASP.NET on the server
|
|
420
|
+
side; fetch/axios, requests/httpx, RestTemplate/WebClient, reqwest, and .NET
|
|
421
|
+
HttpClient on the client side. Exact, partial, and uncertain matches stay in
|
|
422
|
+
separate tiers.
|
|
412
423
|
|
|
413
|
-
## Extract without
|
|
424
|
+
## Extract and search without opening whole files
|
|
414
425
|
|
|
415
|
-
```
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
426
|
+
```bash
|
|
427
|
+
ucn source core/discovery.js:314:expandGlob # exactly one function
|
|
428
|
+
ucn source core/discovery.js --range=314-364 # exactly one range
|
|
429
|
+
ucn search '$scope.$apply' # literal by default
|
|
430
|
+
ucn search 'TODO|FIXME' --regex # regex is explicit
|
|
431
|
+
ucn search --type=call --receiver=client # structural search
|
|
432
|
+
ucn usages expandGlob --include-tests # every occurrence, classified
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
`usages` is the escape hatch: the complete literal-name inventory (calls,
|
|
436
|
+
definitions, imports, references, comments, strings), for when you want
|
|
437
|
+
everything the text contains, not just what the engine can prove. Regex search runs on an
|
|
438
|
+
RE2-compatible linear-time engine; hostile nested repetition is rejected up
|
|
439
|
+
front instead of hanging your terminal.
|
|
440
|
+
|
|
441
|
+
## The 18 commands
|
|
442
|
+
|
|
443
|
+
| Task | Command |
|
|
444
|
+
|---|---|
|
|
445
|
+
| Repository orientation and health | `repo [--sections=summary,files,stats,health] [--deep]` |
|
|
446
|
+
| Symbol summary and relationships | `show <symbol> [--sections=...]` |
|
|
447
|
+
| Definition lookup | `find <name> [--type=type] [--with-source]` |
|
|
448
|
+
| Complete literal-name inventory | `usages <name>` |
|
|
449
|
+
| Literal, regex, or structural search | `search [term] [--regex] [structural flags]` |
|
|
450
|
+
| Exact source extraction | `source <symbol\|file:range>` |
|
|
451
|
+
| Call trees: down, up, or to entry points | `trace <symbol> [--direction=...] [--to=entrypoints]` |
|
|
452
|
+
| Symbol or Git-diff impact | `impact [symbol] [--staged]` |
|
|
453
|
+
| Direct or transitively linked tests | `tests <symbol> [--depth=N]` |
|
|
454
|
+
| Signature or pre-commit validation | `check [symbol] [--staged]` |
|
|
455
|
+
| Refactor preview | `plan <symbol> --rename-to=...` |
|
|
456
|
+
| Imports, importers, and cycles | `deps [file] [--direction=...] [--cycles]` |
|
|
457
|
+
| Project or file public API | `api [file]` |
|
|
458
|
+
| Runtime and framework roots | `entrypoints` |
|
|
459
|
+
| Server/client HTTP surface | `endpoints [--bridge]` |
|
|
460
|
+
| Conservative dead-code candidates | `deadcode` |
|
|
461
|
+
| Likely missing awaits | `audit-async` |
|
|
462
|
+
| Stack-trace frame resolution | `stacktrace <text>` |
|
|
463
|
+
|
|
464
|
+
Run `ucn --help` for every flag. Related modes live behind parameters rather
|
|
465
|
+
than extra verbs: `trace` handles down, up, and to-entry-points;
|
|
466
|
+
`impact`/`check` handle a symbol or the current Git diff; `show` projects any
|
|
467
|
+
subset of sections. Flags that don't apply to a command produce an explicit
|
|
468
|
+
warning instead of silently changing the task.
|
|
469
|
+
|
|
470
|
+
## Same engine, different transport
|
|
471
|
+
|
|
472
|
+
CLI, MCP, file mode, project mode, glob mode, and interactive mode resolve
|
|
473
|
+
commands through the same registry, handlers, index, cache, and formatters:
|
|
474
|
+
same answers everywhere, different delivery.
|
|
475
|
+
|
|
476
|
+
- The CLI prints readable text; `--json` returns a stable machine envelope.
|
|
477
|
+
- MCP exposes exactly one tool named `ucn`. Its `command` enum lists the 18
|
|
478
|
+
tasks, snake_cased where needed (`audit_async`, `project_dir`, `class_name`).
|
|
479
|
+
A persistent MCP process keeps the index warm across calls.
|
|
480
|
+
- Targeted text answers default to a 10K-character budget, broad ones to 3K,
|
|
481
|
+
ceiling 100K (`--max-chars` / `max_chars`). Truncation preserves ACCOUNT,
|
|
482
|
+
CONTRACT, and WARNING lines; JSON is never text-truncated.
|
|
483
|
+
|
|
484
|
+
```json
|
|
485
|
+
{
|
|
486
|
+
"meta": { "command": "audit-async", "canonicalCommand": "auditAsync", "ok": true, "contract": {} },
|
|
487
|
+
"data": {}
|
|
429
488
|
}
|
|
430
489
|
```
|
|
431
490
|
|
|
432
|
-
|
|
491
|
+
Failures keep the envelope: `meta.ok: false`, `data: null`, and an `error`
|
|
492
|
+
string, with the command contract when known.
|
|
493
|
+
|
|
494
|
+
## A cache that stays out of your project
|
|
495
|
+
|
|
496
|
+
The incremental index lives under your user cache root, not in the repo:
|
|
497
|
+
`UCN_CACHE_DIR` if set, else `$XDG_CACHE_HOME/ucn`, `~/Library/Caches/ucn`
|
|
498
|
+
(macOS), `%LOCALAPPDATA%/ucn/cache` (Windows), or `~/.cache/ucn`. Canonical
|
|
499
|
+
path hashes keep same-named checkouts separate. `--no-cache` bypasses,
|
|
500
|
+
`--clear-cache` clears the current project, `--clear-cache --all` clears every
|
|
501
|
+
bounded UCN cache. Old in-project `.ucn-cache` directories are migrated out
|
|
502
|
+
automatically on first use.
|
|
503
|
+
|
|
504
|
+
## Language coverage
|
|
505
|
+
|
|
506
|
+
All parsers feed the same versioned language IR and index path, and sequential
|
|
507
|
+
and worker builds are tested to produce identical symbols, calls, imports, and
|
|
508
|
+
evidence.
|
|
509
|
+
|
|
510
|
+
- **JavaScript / TypeScript / JSX / TSX** - functions, classes,
|
|
511
|
+
imports/exports, typed receivers, aliases, callbacks, async flow, framework
|
|
512
|
+
roots.
|
|
513
|
+
- **Python** - functions, classes, annotations, decorators, imports,
|
|
514
|
+
comprehensions, context-manager bindings, async flow, framework roots.
|
|
515
|
+
- **Go, Rust, Java** - nominal receivers, methods,
|
|
516
|
+
inheritance/traits/interfaces, package and path ownership, overload/arity
|
|
517
|
+
discipline, framework roots.
|
|
518
|
+
- **C** - functions, structs, macros, includes, calls, entry points, API
|
|
519
|
+
analysis.
|
|
520
|
+
- **C++** - C coverage plus classes, methods, constructors, inheritance,
|
|
521
|
+
namespaces, overloads, templates, typed field receivers.
|
|
522
|
+
- **C#** - namespaces, classes/interfaces/records, fields/properties,
|
|
523
|
+
attributes, overload-aware calls, async flow, top-level programs, .NET stack
|
|
524
|
+
frames, ASP.NET/HttpClient endpoints.
|
|
525
|
+
- **HTML** - inline JavaScript and `on*` event handlers.
|
|
526
|
+
|
|
527
|
+
For C and C++, a `compile_commands.json` improves header-language,
|
|
528
|
+
include-path, and ownership context when available. UCN keeps AST-proven
|
|
529
|
+
definitions from recoverable preprocessor branches without claiming which
|
|
530
|
+
branch a particular build activates.
|
|
433
531
|
|
|
434
532
|
## Testing and reliability
|
|
435
533
|
|
|
436
|
-
- **
|
|
437
|
-
- **
|
|
438
|
-
|
|
439
|
-
- **
|
|
440
|
-
|
|
441
|
-
|
|
534
|
+
- **Regression discipline** - every fixed defect gets a focused test.
|
|
535
|
+
- **Surface coverage** - all 18 commands run through CLI text, CLI JSON, and
|
|
536
|
+
MCP; parity between them is guarded by architecture tests.
|
|
537
|
+
- **External ground truth** - real compilers and language servers adjudicate
|
|
538
|
+
caller, callee, command, and dead-code claims on pinned repositories
|
|
539
|
+
([see the board](#measured-against-ground-truth)).
|
|
540
|
+
- **Release-blocking budgets** - publishing requires 100% in-scope semantic
|
|
541
|
+
recall, ≥98% confirmed precision, a conserved account for every sample, zero
|
|
542
|
+
cross-command disagreements, zero default-arm false-dead claims, and the
|
|
543
|
+
performance gate (≥10K lines/second cold build by wall time and ≥3K by CPU
|
|
544
|
+
time, query p50 ≤75 ms, p95 ≤250 ms, bounded peak RSS), all on the actual
|
|
545
|
+
release board.
|
|
442
546
|
|
|
443
|
-
|
|
547
|
+
```bash
|
|
548
|
+
npm run verify # lint + full test suite
|
|
549
|
+
npm run trust:gate # the release board: semantic, dead-code, consistency, performance
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
Gate runs write their reports under `eval/reports/` as local run artifacts;
|
|
553
|
+
the pinned manifest is [`eval/lib/repos.js`](eval/lib/repos.js). Before a tag,
|
|
554
|
+
the Eval workflow's pre-tag dry run must pass on the actual CI runner.
|
|
444
555
|
|
|
445
|
-
## AI
|
|
556
|
+
## AI setup
|
|
557
|
+
|
|
558
|
+
One tool, 18 commands, compact source-linked answers that keep their trust
|
|
559
|
+
metadata even when truncated.
|
|
446
560
|
|
|
447
561
|
### MCP
|
|
448
562
|
|
|
@@ -458,7 +572,7 @@ code --add-mcp '{"name":"ucn","command":"npx","args":["-y","ucn","--mcp"]}'
|
|
|
458
572
|
```
|
|
459
573
|
|
|
460
574
|
<details>
|
|
461
|
-
<summary>
|
|
575
|
+
<summary>Manual MCP configuration</summary>
|
|
462
576
|
|
|
463
577
|
```json
|
|
464
578
|
{
|
|
@@ -489,6 +603,8 @@ VS Code uses `.vscode/mcp.json`:
|
|
|
489
603
|
|
|
490
604
|
### Agent Skill (no server needed)
|
|
491
605
|
|
|
606
|
+
macOS / Linux:
|
|
607
|
+
|
|
492
608
|
```bash
|
|
493
609
|
# Claude Code
|
|
494
610
|
mkdir -p ~/.claude/skills
|
|
@@ -499,24 +615,41 @@ mkdir -p ~/.agents/skills
|
|
|
499
615
|
cp -r "$(npm root -g)/ucn/.claude/skills/ucn" ~/.agents/skills/
|
|
500
616
|
```
|
|
501
617
|
|
|
502
|
-
|
|
618
|
+
Windows PowerShell:
|
|
503
619
|
|
|
504
|
-
|
|
620
|
+
```powershell
|
|
621
|
+
$npmRoot = npm root -g
|
|
622
|
+
New-Item -ItemType Directory -Force "$env:USERPROFILE\.claude\skills"
|
|
623
|
+
Copy-Item -Recurse "$npmRoot\ucn\.claude\skills\ucn" "$env:USERPROFILE\.claude\skills\"
|
|
505
624
|
|
|
506
|
-
|
|
625
|
+
New-Item -ItemType Directory -Force "$env:USERPROFILE\.agents\skills"
|
|
626
|
+
Copy-Item -Recurse "$npmRoot\ucn\.claude\skills\ucn" "$env:USERPROFILE\.agents\skills\"
|
|
627
|
+
```
|
|
507
628
|
|
|
508
|
-
|
|
629
|
+
The skill teaches an agent how to orient, pin symbols, choose the smallest
|
|
630
|
+
useful command, interpret the evidence tiers, and recover from incomplete
|
|
631
|
+
answers. It's guidance over the same engine, not a second implementation.
|
|
509
632
|
|
|
510
633
|
## Limitations
|
|
511
634
|
|
|
512
|
-
-
|
|
513
|
-
-
|
|
514
|
-
- Reflection
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
-
|
|
518
|
-
|
|
519
|
-
|
|
635
|
+
- Static, single-project analysis - dependencies like `node_modules` and
|
|
636
|
+
`site-packages` aren't indexed, and nothing is executed.
|
|
637
|
+
- Reflection, generated code, runtime registration, dynamic property access,
|
|
638
|
+
and external consumers can be invisible. UCN reports these blind spots
|
|
639
|
+
(`repo --sections=health --deep`) rather than pretending they don't exist.
|
|
640
|
+
- Interface, trait, template, overload, and untyped-receiver dispatch may stay
|
|
641
|
+
in the UNVERIFIED tier with a reason instead of being guessed.
|
|
642
|
+
- C/C++ analysis doesn't run the preprocessor or compiler; build-specific
|
|
643
|
+
branches, advanced templates, and macro expansion can remain unresolved. C#
|
|
644
|
+
analysis doesn't run Roslyn; source generators and external assembly
|
|
645
|
+
semantics stay outside the index.
|
|
646
|
+
- HTML has regression coverage but no compiler/LSP real-repository oracle.
|
|
647
|
+
- Large repos take a few seconds on the first query, then use the cache.
|
|
648
|
+
|
|
649
|
+
If a decision needs compiler completeness or runtime truth, use the compiler,
|
|
650
|
+
the type checker, the test runner, or a profiler. Those are different tools
|
|
651
|
+
for different jobs. UCN's job is getting you to the right code fast, with
|
|
652
|
+
answers you can audit.
|
|
520
653
|
|
|
521
654
|
---
|
|
522
655
|
|