ucn 4.2.2 → 5.0.1
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 +445 -300
- 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 -131
- package/core/cache.js +533 -11
- package/core/callers.js +5533 -494
- 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 +421 -20
- package/core/discovery.js +359 -46
- package/core/entrypoints.js +204 -42
- 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 +216 -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 -177
- package/core/public-command.js +47 -0
- package/core/registry.js +247 -117
- package/core/reporting.js +312 -290
- package/core/search.js +371 -116
- 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 +428 -16
- package/languages/javascript.js +452 -49
- package/languages/python.js +1041 -32
- package/languages/rust.js +1415 -152
- package/languages/utils.js +40 -3
- package/mcp/server.js +254 -636
- package/package.json +41 -24
- 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,182 +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
|
-
##
|
|
119
|
+
## Follow the execution path
|
|
139
120
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
```
|
|
143
|
-
$ ucn impact saveCache
|
|
121
|
+
What happens when `build()` runs?
|
|
144
122
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
test/regression-go.test.js (2 calls)
|
|
148
|
-
:2007
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
|
182
|
-
|
|
|
183
|
-
|
|
|
184
|
-
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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):
|
|
204
|
+
|
|
205
|
+
| Repository | Pinned commit | Oracle | Caller precision | Caller recall | Callee prec / recall | Command checks |
|
|
206
|
+
|---|---|---|---:|---:|---:|---:|
|
|
207
|
+
| [preact-signals](https://github.com/preactjs/signals) | [`e0ce9fdf`](https://github.com/preactjs/signals/commit/e0ce9fdf92df7f0ece2c89d44554c39f36dc6882) | ts-morph | 100% | 100% | 100% / 100% | 100% |
|
|
208
|
+
| [httpx](https://github.com/encode/httpx) | [`b5addb64`](https://github.com/encode/httpx/commit/b5addb64f0161ff6bfe94c124ef76f6a1fba5254) | Pyright | 100% | 100% | 100% / 100% | 100% |
|
|
209
|
+
| [cobra](https://github.com/spf13/cobra) | [`ad460ea8`](https://github.com/spf13/cobra/commit/ad460ea8f249db69c943a365fb84f3a59042d54e) | gopls | 100% | 100% | 100% / 100% | 100% |
|
|
210
|
+
| [viper](https://github.com/spf13/viper) | [`528f7416`](https://github.com/spf13/viper/commit/528f7416c4b56a4948673984b190bf8713f0c3c4) | gopls | 100% | 100% | 100% / 100% | 100% |
|
|
211
|
+
| [ripgrep](https://github.com/BurntSushi/ripgrep) | [`82313cf9`](https://github.com/BurntSushi/ripgrep/commit/82313cf95849bfe425109ad9506a52154879b1b1) | rust-analyzer | 100% | 100% | 100% / 100% | 100% |
|
|
212
|
+
| [clap](https://github.com/clap-rs/clap) | [`d3e59a9a`](https://github.com/clap-rs/clap/commit/d3e59a9ab214910b9dad02921b7ef42c6400de9b) | rust-analyzer | 100% | 100% | 100% / 100% | 100% |
|
|
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.
|
|
191
244
|
|
|
192
245
|
## Change code without breaking things
|
|
193
246
|
|
|
194
|
-
|
|
247
|
+
Will this change break a call site you've never seen? Check before you edit:
|
|
195
248
|
|
|
196
|
-
```
|
|
197
|
-
$ ucn
|
|
249
|
+
```text
|
|
250
|
+
$ ucn check expandGlob
|
|
198
251
|
|
|
199
252
|
Verification: expandGlob
|
|
200
253
|
════════════════════════════════════════════════════════════
|
|
201
|
-
core/discovery.js:
|
|
254
|
+
core/discovery.js:314
|
|
202
255
|
expandGlob (pattern: string, options: number = {}) : string[]
|
|
203
256
|
|
|
204
257
|
Expected arguments: 1-2
|
|
@@ -209,228 +262,301 @@ STATUS: ✓ All calls valid
|
|
|
209
262
|
Mismatches: 0
|
|
210
263
|
Uncertain: 0
|
|
211
264
|
Patterns: 4 in try, 4 in callback
|
|
212
|
-
```
|
|
213
265
|
|
|
214
|
-
|
|
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
|
+
```
|
|
215
269
|
|
|
216
|
-
|
|
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:
|
|
217
273
|
|
|
218
|
-
```
|
|
274
|
+
```text
|
|
219
275
|
$ ucn plan expandGlob --rename-to=expandGlobPattern
|
|
220
276
|
|
|
221
277
|
Refactoring plan: rename
|
|
222
278
|
════════════════════════════════════════════════════════════
|
|
223
|
-
core/discovery.js:
|
|
279
|
+
core/discovery.js:314
|
|
224
280
|
|
|
225
281
|
SIGNATURE CHANGE:
|
|
226
282
|
Before: expandGlob (pattern: string, options: number = {}) : string[]
|
|
227
283
|
After: expandGlobPattern (pattern: string, options: number = {}) : string[]
|
|
228
284
|
|
|
229
|
-
CHANGES NEEDED:
|
|
230
|
-
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
|
|
231
288
|
|
|
232
289
|
BY FILE:
|
|
233
290
|
|
|
234
291
|
cli/index.js (2 changes)
|
|
235
|
-
:
|
|
292
|
+
:771 [call]
|
|
236
293
|
const files = expandGlob(pattern);
|
|
237
294
|
→ Rename to: const files = expandGlobPattern(pattern);
|
|
238
|
-
:15
|
|
295
|
+
:15 [import]
|
|
239
296
|
const { expandGlob, findProjectRoot } = require('../core/discovery');
|
|
240
297
|
→ Update import: const { expandGlobPattern, findProjectRoot } = require('../core/discovery');
|
|
241
298
|
|
|
242
|
-
... (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)
|
|
243
300
|
```
|
|
244
301
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
```
|
|
250
|
-
$ ucn check --staged
|
|
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:
|
|
251
305
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
parseFlags (cli/index.js:165) [MODIFIED] 2 callers
|
|
256
|
-
...
|
|
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
|
|
257
309
|
```
|
|
258
310
|
|
|
259
|
-
|
|
311
|
+
## Pick the right tests
|
|
260
312
|
|
|
261
|
-
|
|
313
|
+
Which tests actually exercise this function, directly or three hops away?
|
|
262
314
|
|
|
263
|
-
|
|
315
|
+
```text
|
|
316
|
+
$ ucn tests expandGlob --depth=3
|
|
264
317
|
|
|
265
|
-
|
|
266
|
-
$ ucn orient
|
|
267
|
-
|
|
268
|
-
PROJECT ORIENTATION: /path/to/project
|
|
318
|
+
affected-tests: expandGlob
|
|
269
319
|
════════════════════════════════════════════════════════════
|
|
270
|
-
|
|
320
|
+
core/discovery.js:314
|
|
321
|
+
1 function changed → 12 functions affected (depth 3)
|
|
271
322
|
|
|
272
|
-
|
|
273
|
-
core 516 symbols · 29 file(s)
|
|
274
|
-
languages 282 symbols · 8 file(s)
|
|
275
|
-
test 209 symbols · 29 file(s)
|
|
276
|
-
core/output 142 symbols · 14 file(s)
|
|
277
|
-
...
|
|
323
|
+
Test files to run (30):
|
|
278
324
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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]
|
|
283
329
|
...
|
|
284
330
|
|
|
285
|
-
|
|
286
|
-
TRUST: MEDIUM; 41 dynamic import(s), 13 eval, 6 reflection (ucn doctor for detail)
|
|
287
|
-
|
|
288
|
-
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)
|
|
289
332
|
```
|
|
290
333
|
|
|
291
|
-
|
|
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.
|
|
292
338
|
|
|
293
|
-
|
|
294
|
-
$ ucn brief fetch_user
|
|
295
|
-
fetch_user(user_id: int): dict
|
|
296
|
-
svc.py:4-8 (5 lines)
|
|
297
|
-
"Fetch a user from the API."
|
|
298
|
-
async: no | side_effects: [fs, network, process] | complexity: branches=2, depth=2
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
`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.
|
|
339
|
+
## Get the lay of the land
|
|
302
340
|
|
|
303
|
-
|
|
304
|
-
$ ucn doctor
|
|
305
|
-
|
|
306
|
-
UCN Trust Report: /path/to/project
|
|
307
|
-
Index: 169 files, 2104 symbols
|
|
308
|
-
Languages: javascript (72%), typescript (14%), java (4%), python (4%), rust (4%), go (3%)
|
|
309
|
-
Cache: fresh, 344ms build
|
|
310
|
-
Command proofs: 39/39 classified, 22 external-oracle-backed, 0 unclassified
|
|
311
|
-
|
|
312
|
-
Readiness:
|
|
313
|
-
navigation: HIGH: fresh index; no parse failures
|
|
314
|
-
refactor: UNKNOWN: run --deep; review unverified and non-call occurrences
|
|
315
|
-
deletion: REVIEW: usages, public API, compiler, and tests are still required
|
|
316
|
-
```
|
|
341
|
+
One command answers "what is this codebase?" Here it is on ripgrep:
|
|
317
342
|
|
|
318
|
-
|
|
343
|
+
```text
|
|
344
|
+
$ ucn repo
|
|
319
345
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
```
|
|
323
|
-
ucn entrypoints --type=http --framework=spring # narrow to one framework
|
|
324
|
-
ucn entrypoints --exclude-tests # tests are included by default
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
## Find what to clean up
|
|
328
|
-
|
|
329
|
-
Which tests should you run after a change? `affected-tests` walks the blast radius and finds every test that touches the affected functions:
|
|
330
|
-
|
|
331
|
-
```
|
|
332
|
-
$ ucn affected-tests expandGlob
|
|
333
|
-
|
|
334
|
-
affected-tests: expandGlob
|
|
346
|
+
PROJECT ORIENTATION — ripgrep
|
|
335
347
|
════════════════════════════════════════════════════════════
|
|
336
|
-
|
|
337
|
-
1 function changed → 15 functions affected (depth 3)
|
|
348
|
+
100 files · 4755 symbols · language mix by symbols: rust 100%
|
|
338
349
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
+
...
|
|
348
362
|
|
|
349
|
-
|
|
350
|
-
|
|
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.
|
|
351
366
|
|
|
352
|
-
|
|
367
|
+
Next: ucn show parse_low_raw · ucn repo --sections=files --detailed · ucn repo --sections=health --deep
|
|
353
368
|
```
|
|
354
369
|
|
|
355
|
-
|
|
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.
|
|
356
374
|
|
|
357
|
-
## Find
|
|
375
|
+
## Find dead code you can act on
|
|
358
376
|
|
|
359
|
-
```
|
|
377
|
+
```text
|
|
360
378
|
$ ucn deadcode --exclude=test # run on ripgrep
|
|
361
379
|
|
|
362
|
-
Dead code:
|
|
380
|
+
Dead code: 3 unused symbol(s)
|
|
363
381
|
|
|
364
382
|
crates/globset/src/serde_impl.rs
|
|
365
383
|
[ 38- 42] Glob.deserialize (method)
|
|
366
384
|
[ 70- 74] GlobSet.deserialize (method)
|
|
367
385
|
crates/matcher/src/lib.rs
|
|
368
386
|
[ 397- 399] Captures.as_match (method)
|
|
369
|
-
[ 669- 678] Matcher.try_find_iter (method) [only self-references, recursive]
|
|
370
|
-
[ 796- 806] Matcher.try_captures_iter (method) [only self-references, recursive]
|
|
371
|
-
...
|
|
372
387
|
|
|
373
|
-
|
|
374
|
-
```
|
|
388
|
+
33 decorated/annotated symbol(s) hidden (framework-registered). Use --include-decorated to include them.
|
|
375
389
|
|
|
376
|
-
|
|
390
|
+
903 exported symbol(s) excluded from the audit (public API may have external callers). Use --include-exported to audit them.
|
|
377
391
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
```
|
|
381
|
-
ucn audit-async
|
|
392
|
+
WARNING: source coverage is incomplete (5 unsupported-language); 17 candidate name(s) found in skipped source were suppressed.
|
|
382
393
|
```
|
|
383
394
|
|
|
384
|
-
|
|
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.
|
|
385
402
|
|
|
386
|
-
|
|
403
|
+
For missing-await bugs, `ucn audit-async` lists async calls inside async
|
|
404
|
+
functions that lack `await` (JS/TS/Python).
|
|
387
405
|
|
|
388
|
-
|
|
406
|
+
## Map dependencies and API surfaces
|
|
389
407
|
|
|
390
408
|
```bash
|
|
391
|
-
ucn
|
|
392
|
-
|
|
393
|
-
#
|
|
394
|
-
ucn
|
|
395
|
-
ucn
|
|
396
|
-
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
|
|
397
415
|
```
|
|
398
416
|
|
|
399
|
-
|
|
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.
|
|
400
423
|
|
|
401
|
-
## Extract without
|
|
424
|
+
## Extract and search without opening whole files
|
|
402
425
|
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
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": {}
|
|
417
488
|
}
|
|
418
489
|
```
|
|
419
490
|
|
|
420
|
-
|
|
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.
|
|
421
531
|
|
|
422
532
|
## Testing and reliability
|
|
423
533
|
|
|
424
|
-
- **
|
|
425
|
-
- **
|
|
426
|
-
|
|
427
|
-
- **
|
|
428
|
-
|
|
429
|
-
|
|
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.
|
|
430
546
|
|
|
431
|
-
|
|
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.
|
|
432
555
|
|
|
433
|
-
## AI
|
|
556
|
+
## AI setup
|
|
557
|
+
|
|
558
|
+
One tool, 18 commands, compact source-linked answers that keep their trust
|
|
559
|
+
metadata even when truncated.
|
|
434
560
|
|
|
435
561
|
### MCP
|
|
436
562
|
|
|
@@ -446,7 +572,7 @@ code --add-mcp '{"name":"ucn","command":"npx","args":["-y","ucn","--mcp"]}'
|
|
|
446
572
|
```
|
|
447
573
|
|
|
448
574
|
<details>
|
|
449
|
-
<summary>
|
|
575
|
+
<summary>Manual MCP configuration</summary>
|
|
450
576
|
|
|
451
577
|
```json
|
|
452
578
|
{
|
|
@@ -477,6 +603,8 @@ VS Code uses `.vscode/mcp.json`:
|
|
|
477
603
|
|
|
478
604
|
### Agent Skill (no server needed)
|
|
479
605
|
|
|
606
|
+
macOS / Linux:
|
|
607
|
+
|
|
480
608
|
```bash
|
|
481
609
|
# Claude Code
|
|
482
610
|
mkdir -p ~/.claude/skills
|
|
@@ -487,24 +615,41 @@ mkdir -p ~/.agents/skills
|
|
|
487
615
|
cp -r "$(npm root -g)/ucn/.claude/skills/ucn" ~/.agents/skills/
|
|
488
616
|
```
|
|
489
617
|
|
|
490
|
-
|
|
618
|
+
Windows PowerShell:
|
|
491
619
|
|
|
492
|
-
|
|
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\"
|
|
493
624
|
|
|
494
|
-
|
|
625
|
+
New-Item -ItemType Directory -Force "$env:USERPROFILE\.agents\skills"
|
|
626
|
+
Copy-Item -Recurse "$npmRoot\ucn\.claude\skills\ucn" "$env:USERPROFILE\.agents\skills\"
|
|
627
|
+
```
|
|
495
628
|
|
|
496
|
-
|
|
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.
|
|
497
632
|
|
|
498
633
|
## Limitations
|
|
499
634
|
|
|
500
|
-
-
|
|
501
|
-
-
|
|
502
|
-
- Reflection
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
-
|
|
506
|
-
|
|
507
|
-
|
|
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.
|
|
508
653
|
|
|
509
654
|
---
|
|
510
655
|
|