ucn 3.7.25 → 3.7.27
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/README.md +188 -466
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,230 +1,171 @@
|
|
|
1
|
-
# UCN
|
|
1
|
+
# UCN — Universal Code Navigator
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
AST-powered code intelligence from the terminal.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
UCN answers structural code questions instantly:
|
|
6
|
+
- Who calls this function?
|
|
7
|
+
- What breaks if I change this signature?
|
|
8
|
+
- What changed in this diff, and who depends on it?
|
|
9
|
+
- What code is safe to delete?
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
|
|
11
|
+
Instead of reading full files, UCN gives precise, AST-verified answers.
|
|
12
|
+
|
|
13
|
+
[](https://www.npmjs.com/package/ucn)
|
|
14
|
+
[](LICENSE)
|
|
9
15
|
|
|
10
16
|
---
|
|
11
17
|
|
|
12
|
-
##
|
|
18
|
+
## 60-Second Quickstart
|
|
13
19
|
|
|
14
|
-
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g ucn
|
|
15
22
|
|
|
23
|
+
ucn about handleRequest # full picture: definition, callers, callees, tests
|
|
24
|
+
ucn impact handleRequest # all call sites with arguments
|
|
25
|
+
ucn trace main --depth=3 # call tree, no file reads
|
|
26
|
+
ucn deadcode # unused functions, AST-verified
|
|
27
|
+
ucn fn handleRequest # extract a function without reading the file
|
|
28
|
+
ucn toc # project overview
|
|
29
|
+
ucn --interactive # REPL mode, index stays in memory
|
|
16
30
|
```
|
|
17
|
-
TASK COMMAND
|
|
18
|
-
───────────────────── ─────────────────────
|
|
19
|
-
|
|
20
|
-
Pull one function from $ ucn fn handleRequest
|
|
21
|
-
a 2000-line file → 20 lines, just that function
|
|
22
|
-
|
|
23
|
-
Who calls this? Will they $ ucn impact handleRequest
|
|
24
|
-
break if I change it? → 8 call sites, with arguments
|
|
25
|
-
|
|
26
|
-
What happens when $ ucn trace main --depth=3
|
|
27
|
-
main() runs? → full call tree, no file reads
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
→ unused functions, AST-verified
|
|
32
|
+
Parses JS/TS, Python, Go, Rust, Java, and HTML with tree-sitter. Runs locally.
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
```
|
|
35
|
+
Terminal AI Agents Agent Skills
|
|
36
|
+
│ │ │
|
|
37
|
+
CLI MCP Skill
|
|
38
|
+
└────────────────────┼───────────────────────┘
|
|
39
|
+
│
|
|
40
|
+
┌──────┴──────┐
|
|
41
|
+
│ UCN Engine │
|
|
42
|
+
│ 28 commands │
|
|
43
|
+
│ tree-sitter │
|
|
44
|
+
└─────────────┘
|
|
34
45
|
```
|
|
35
46
|
|
|
36
47
|
---
|
|
37
48
|
|
|
38
|
-
##
|
|
49
|
+
## Why UCN
|
|
50
|
+
|
|
51
|
+
UCN uses tree-sitter to parse code into an AST, then builds a call graph and symbol table on top of it. Instead of matching text, it understands which functions call which, what depends on what, and what's unused. Everything runs locally.
|
|
52
|
+
|
|
53
|
+
"What happens when `build()` runs?"
|
|
39
54
|
|
|
40
55
|
```
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
56
|
+
$ ucn trace build --depth=2
|
|
57
|
+
|
|
58
|
+
build
|
|
59
|
+
├── detectProjectPattern (discovery.js:392) 1x
|
|
60
|
+
│ ├── checkDir (discovery.js:396) 2x
|
|
61
|
+
│ └── shouldIgnore (discovery.js:340) 1x
|
|
62
|
+
├── parseGitignore (discovery.js:123) 1x
|
|
63
|
+
├── expandGlob (discovery.js:183) 1x
|
|
64
|
+
│ ├── parseGlobPattern (discovery.js:219) 1x
|
|
65
|
+
│ ├── walkDir (discovery.js:276) 1x
|
|
66
|
+
│ └── compareNames (discovery.js:162) 1x
|
|
67
|
+
├── indexFile (project.js:236) 1x
|
|
68
|
+
│ ├── addSymbol (project.js:293) 4x
|
|
69
|
+
│ ├── detectLanguage (languages/index.js:157) 1x
|
|
70
|
+
│ ├── parseFile (parser.js:93) 1x
|
|
71
|
+
│ └── extractImports (imports.js:19) 1x
|
|
72
|
+
├── buildImportGraph (project.js:419) 1x
|
|
73
|
+
└── buildInheritanceGraph (project.js:465) 1x
|
|
53
74
|
```
|
|
54
75
|
|
|
76
|
+
One command. No files opened. The full execution flow with every function located by file and line.
|
|
77
|
+
|
|
55
78
|
---
|
|
56
79
|
|
|
57
|
-
##
|
|
80
|
+
## What it does
|
|
58
81
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
│
|
|
70
|
-
▼
|
|
71
|
-
read file3.ts → found it, finally
|
|
72
|
-
│
|
|
73
|
-
▼
|
|
74
|
-
grep "whoCallsThis" → start over
|
|
75
|
-
│
|
|
76
|
-
▼
|
|
77
|
-
┌─────────────────────────────────────────┐
|
|
78
|
-
│ Half the context window is gone. │
|
|
79
|
-
│ The agent hasn't changed a single line.│
|
|
80
|
-
└─────────────────────────────────────────┘
|
|
81
|
-
```
|
|
82
|
+
| Task | Command | Output |
|
|
83
|
+
|------|---------|--------|
|
|
84
|
+
| Understand one symbol deeply | `ucn about expandGlob` | Definition, callers, callees, tests |
|
|
85
|
+
| Who calls this and what do they pass? | `ucn impact shouldIgnore` | Call sites with argument context |
|
|
86
|
+
| Map an execution path | `ucn trace expandGlob --depth=2` | Call tree |
|
|
87
|
+
| Extract just one function | `ucn fn expandGlob` | Surgical snippet, no file read |
|
|
88
|
+
| Check all call sites match signature | `ucn verify expandGlob` | Mismatch/uncertain call sites |
|
|
89
|
+
| Review branch impact | `ucn diff-impact --base=main` | Changed functions + downstream callers |
|
|
90
|
+
| Find deletable code | `ucn deadcode` | Unused symbols, AST-verified |
|
|
91
|
+
| Get function + helpers inline | `ucn smart shouldIgnore` | Source with dependencies expanded |
|
|
82
92
|
|
|
83
93
|
---
|
|
84
94
|
|
|
85
|
-
##
|
|
95
|
+
## Setup
|
|
86
96
|
|
|
87
|
-
|
|
88
|
-
┌──────────────────────────────────────────────┐
|
|
89
|
-
│ Any AI Agent │
|
|
90
|
-
│ Claude Code · Cursor · Windsurf · Copilot │
|
|
91
|
-
└───────────────────────┬──────────────────────┘
|
|
92
|
-
│
|
|
93
|
-
MCP
|
|
94
|
-
│
|
|
95
|
-
▼
|
|
96
|
-
┌───────────────────┐
|
|
97
|
-
│ UCN MCP Server │
|
|
98
|
-
│ 28 commands │
|
|
99
|
-
│ runs locally │
|
|
100
|
-
└────────┬──────────┘
|
|
101
|
-
│
|
|
102
|
-
tree-sitter AST
|
|
103
|
-
│
|
|
104
|
-
┌─────────────────┴───────────────────┐
|
|
105
|
-
│ Supported Languages │
|
|
106
|
-
│ JS/TS, Python, Go, Rust, Java, HTML │
|
|
107
|
-
└─────────────────────────────────────┘
|
|
108
|
-
```
|
|
97
|
+
### MCP Server (for AI agents)
|
|
109
98
|
|
|
110
|
-
|
|
99
|
+
One-line setup:
|
|
111
100
|
|
|
112
|
-
|
|
101
|
+
```bash
|
|
102
|
+
# Claude Code
|
|
103
|
+
claude mcp add ucn -- npx -y ucn --mcp
|
|
113
104
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
│ │
|
|
120
|
-
▼ ▼
|
|
121
|
-
34 matches, mostly noise 8 call sites, grouped by file,
|
|
122
|
-
│ with actual arguments passed
|
|
123
|
-
▼ │
|
|
124
|
-
read service.ts (800 lines) │
|
|
125
|
-
│ │
|
|
126
|
-
▼ │
|
|
127
|
-
read handler.ts (600 lines) ucn smart "processOrder"
|
|
128
|
-
│ │
|
|
129
|
-
▼ ▼
|
|
130
|
-
read batch.ts (400 lines) function + all dependencies
|
|
131
|
-
│ expanded inline
|
|
132
|
-
▼ │
|
|
133
|
-
read orders.test (500 lines) │
|
|
134
|
-
│ ▼
|
|
135
|
-
▼ Done. Full picture.
|
|
136
|
-
grep "import.*processOrder" Ready to make the change.
|
|
137
|
-
│
|
|
138
|
-
▼
|
|
139
|
-
read routes.ts (300 lines)
|
|
140
|
-
│
|
|
141
|
-
▼
|
|
142
|
-
... still not sure about full impact
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
8+ tool calls 2 tool calls
|
|
146
|
-
Reads thousands of lines Reads zero full files
|
|
147
|
-
Context spent on file contents Context spent on reasoning
|
|
105
|
+
# OpenAI Codex CLI
|
|
106
|
+
codex mcp add ucn -- npx -y ucn --mcp
|
|
107
|
+
|
|
108
|
+
# VS Code Copilot
|
|
109
|
+
code --add-mcp '{"name":"ucn","command":"npx","args":["-y","ucn","--mcp"]}'
|
|
148
110
|
```
|
|
149
111
|
|
|
150
|
-
|
|
112
|
+
<details>
|
|
113
|
+
<summary>Or add to the MCP config file manually</summary>
|
|
151
114
|
|
|
115
|
+
```json
|
|
116
|
+
{
|
|
117
|
+
"mcpServers": {
|
|
118
|
+
"ucn": {
|
|
119
|
+
"command": "npx",
|
|
120
|
+
"args": ["-y", "ucn", "--mcp"]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
152
124
|
```
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
▼ • every downstream caller
|
|
167
|
-
ucn impact on each function • caller context
|
|
168
|
-
you identified (repeat 5-10x) │
|
|
169
|
-
│ ▼
|
|
170
|
-
▼ Done. Full blast radius.
|
|
171
|
-
hope you didn't miss one One command.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
10+ tool calls 1 tool call
|
|
125
|
+
|
|
126
|
+
VS Code uses `.vscode/mcp.json`:
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"servers": {
|
|
131
|
+
"ucn": {
|
|
132
|
+
"type": "stdio",
|
|
133
|
+
"command": "npx",
|
|
134
|
+
"args": ["-y", "ucn", "--mcp"]
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
175
138
|
```
|
|
176
139
|
|
|
177
|
-
|
|
140
|
+
</details>
|
|
178
141
|
|
|
179
|
-
|
|
142
|
+
All 28 commands ship as a single MCP tool, under 2KB of schema in the agent's context.
|
|
180
143
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
│ ✗ // TODO: refactor processOrder ← comment, not a call │
|
|
190
|
-
│ ✗ const processOrder = "label" ← string, not a call │
|
|
191
|
-
│ ✗ order.processOrder() ← different class │
|
|
192
|
-
│ ✗ import { processOrder } ← import, not a call │
|
|
193
|
-
│ │
|
|
194
|
-
│ 5 results. 1 is what you wanted. │
|
|
195
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
┌─────────────────────────────────────────────────────────────────┐
|
|
199
|
-
│ ucn context "processOrder" │
|
|
200
|
-
│ │
|
|
201
|
-
│ Callers: │
|
|
202
|
-
│ handleCheckout src/api/checkout.ts:45 │
|
|
203
|
-
│ batchProcess src/workers/batch.ts:12 │
|
|
204
|
-
│ runDailyOrders src/jobs/daily.ts:88 │
|
|
205
|
-
│ │
|
|
206
|
-
│ Callees: │
|
|
207
|
-
│ validateItems src/orders/validate.ts:20 │
|
|
208
|
-
│ calculateTotal src/orders/pricing.ts:55 │
|
|
209
|
-
│ saveOrder src/db/orders.ts:30 │
|
|
210
|
-
│ │
|
|
211
|
-
│ 3 callers, 3 callees. Verified from the AST. │
|
|
212
|
-
└─────────────────────────────────────────────────────────────────┘
|
|
213
|
-
```
|
|
144
|
+
### Agent Skill (no server needed)
|
|
145
|
+
|
|
146
|
+
Drop-in for Claude Code or Codex CLI:
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Claude Code
|
|
150
|
+
mkdir -p ~/.claude/skills
|
|
151
|
+
cp -r "$(npm root -g)/ucn/.claude/skills/ucn" ~/.claude/skills/
|
|
214
152
|
|
|
215
|
-
|
|
153
|
+
# OpenAI Codex CLI
|
|
154
|
+
mkdir -p ~/.agents/skills
|
|
155
|
+
cp -r "$(npm root -g)/ucn/.claude/skills/ucn" ~/.agents/skills/
|
|
156
|
+
```
|
|
216
157
|
|
|
217
158
|
---
|
|
218
159
|
|
|
219
|
-
##
|
|
160
|
+
## Examples
|
|
220
161
|
|
|
221
|
-
Extract a function
|
|
162
|
+
**Extract a function** without reading the file:
|
|
222
163
|
|
|
223
164
|
```
|
|
224
165
|
$ ucn fn expandGlob
|
|
225
166
|
|
|
226
|
-
core/discovery.js:
|
|
227
|
-
[
|
|
167
|
+
core/discovery.js:183
|
|
168
|
+
[ 183- 214] expandGlob(pattern, options = {})
|
|
228
169
|
────────────────────────────────────────────────────────────
|
|
229
170
|
function expandGlob(pattern, options = {}) {
|
|
230
171
|
const root = path.resolve(options.root || process.cwd());
|
|
@@ -234,110 +175,38 @@ function expandGlob(pattern, options = {}) {
|
|
|
234
175
|
}
|
|
235
176
|
```
|
|
236
177
|
|
|
237
|
-
See
|
|
178
|
+
**See callers and callees:**
|
|
238
179
|
|
|
239
180
|
```
|
|
240
181
|
$ ucn context expandGlob
|
|
241
182
|
|
|
242
|
-
Context for expandGlob:
|
|
243
|
-
════════════════════════════════════════════════════════════
|
|
244
|
-
|
|
245
183
|
CALLERS (7):
|
|
246
|
-
[1] cli/index.js:
|
|
184
|
+
[1] cli/index.js:785 [runGlobCommand]
|
|
247
185
|
const files = expandGlob(pattern);
|
|
248
|
-
[2] core/
|
|
249
|
-
const
|
|
250
|
-
[3] core/project.js:
|
|
251
|
-
const
|
|
186
|
+
[2] core/cache.js:149 [isCacheStale]
|
|
187
|
+
const currentFiles = expandGlob(pattern, globOpts);
|
|
188
|
+
[3] core/project.js:171 [build]
|
|
189
|
+
const files = expandGlob(pattern, globOpts);
|
|
252
190
|
...
|
|
253
191
|
|
|
254
|
-
CALLEES (
|
|
255
|
-
[8] parseGlobPattern [utility] - core/discovery.js:
|
|
256
|
-
[9] walkDir [utility] - core/discovery.js:
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
See what breaks if you change it:
|
|
260
|
-
|
|
261
|
-
```
|
|
262
|
-
$ ucn impact shouldIgnore
|
|
263
|
-
|
|
264
|
-
Impact analysis for shouldIgnore
|
|
265
|
-
════════════════════════════════════════════════════════════
|
|
266
|
-
core/discovery.js:289
|
|
267
|
-
shouldIgnore (name, ignores, parentDir)
|
|
268
|
-
|
|
269
|
-
CALL SITES: 2
|
|
270
|
-
Files affected: 1
|
|
271
|
-
|
|
272
|
-
BY FILE:
|
|
273
|
-
|
|
274
|
-
core/discovery.js (2 calls)
|
|
275
|
-
:255 [walkDir]
|
|
276
|
-
if (shouldIgnore(entry.name, options.ignores, dir)) continue;
|
|
277
|
-
args: entry.name, options.ignores, dir
|
|
278
|
-
:373 [detectProjectPattern]
|
|
279
|
-
!shouldIgnore(entry.name, DEFAULT_IGNORES)) {
|
|
280
|
-
args: entry.name, DEFAULT_IGNORES
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
Get a function with all its dependencies inline:
|
|
284
|
-
|
|
285
|
-
```
|
|
286
|
-
$ ucn smart shouldIgnore
|
|
287
|
-
|
|
288
|
-
shouldIgnore (core/discovery.js:289)
|
|
289
|
-
════════════════════════════════════════════════════════════
|
|
290
|
-
function shouldIgnore(name, ignores, parentDir) {
|
|
291
|
-
for (const pattern of ignores) {
|
|
292
|
-
if (pattern.includes('*')) {
|
|
293
|
-
const regex = globToRegex(pattern);
|
|
294
|
-
...
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
...
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
─── DEPENDENCIES ───
|
|
301
|
-
|
|
302
|
-
// globToRegex [utility] (core/discovery.js:208)
|
|
303
|
-
function globToRegex(glob) {
|
|
304
|
-
let regex = glob.replace(/[.+^$[\]\\]/g, '\\$&');
|
|
305
|
-
...
|
|
306
|
-
return new RegExp('^' + regex + '$');
|
|
307
|
-
}
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
Trace the call tree:
|
|
311
|
-
|
|
312
|
-
```
|
|
313
|
-
$ ucn trace expandGlob --depth=2
|
|
314
|
-
|
|
315
|
-
Call tree for expandGlob
|
|
316
|
-
════════════════════════════════════════════════════════════
|
|
317
|
-
|
|
318
|
-
expandGlob
|
|
319
|
-
├── parseGlobPattern (core/discovery.js:171) [utility] 1x
|
|
320
|
-
│ └── globToRegex (core/discovery.js:208) [utility] 1x
|
|
321
|
-
└── walkDir (core/discovery.js:227) [utility] 1x
|
|
322
|
-
└── shouldIgnore (core/discovery.js:289) [utility] 1x
|
|
192
|
+
CALLEES (3):
|
|
193
|
+
[8] parseGlobPattern [utility] - core/discovery.js:219
|
|
194
|
+
[9] walkDir [utility] - core/discovery.js:276
|
|
195
|
+
[10] compareNames [utility] - core/discovery.js:162
|
|
323
196
|
```
|
|
324
197
|
|
|
325
|
-
See
|
|
198
|
+
**See impact of recent edits:**
|
|
326
199
|
|
|
327
200
|
```
|
|
328
201
|
$ ucn diff-impact --base=HEAD~1
|
|
329
202
|
|
|
330
|
-
Diff Impact Analysis (vs HEAD~1)
|
|
331
|
-
════════════════════════════════════════════════════════════
|
|
332
203
|
3 modified, 1 new, 12 call sites across 4 files
|
|
333
204
|
|
|
334
205
|
MODIFIED FUNCTIONS:
|
|
335
206
|
|
|
336
207
|
processOrder
|
|
337
208
|
src/orders/service.ts:45
|
|
338
|
-
|
|
339
|
-
Lines added: 48-52
|
|
340
|
-
Lines deleted: 49
|
|
209
|
+
Lines added: 48-52, Lines deleted: 49
|
|
341
210
|
Callers (3):
|
|
342
211
|
src/api/checkout.ts:89 [handleCheckout]
|
|
343
212
|
await processOrder(cart.items, req.user)
|
|
@@ -345,243 +214,96 @@ MODIFIED FUNCTIONS:
|
|
|
345
214
|
processOrder(order.items, systemUser)
|
|
346
215
|
src/jobs/daily.ts:88 [runDailyOrders]
|
|
347
216
|
results.push(await processOrder(items, admin))
|
|
348
|
-
|
|
349
|
-
validateItems
|
|
350
|
-
src/orders/validate.ts:20
|
|
351
|
-
validateItems (items: Item[]): ValidationResult
|
|
352
|
-
Lines added: 25-30
|
|
353
|
-
Callers (2):
|
|
354
|
-
src/orders/service.ts:46 [processOrder]
|
|
355
|
-
const valid = validateItems(items)
|
|
356
|
-
src/api/admin.ts:55 [bulkValidate]
|
|
357
|
-
return items.map(i => validateItems([i]))
|
|
358
|
-
|
|
359
|
-
NEW FUNCTIONS:
|
|
360
|
-
calculateShipping — src/orders/shipping.ts:10
|
|
361
|
-
calculateShipping (items: Item[], region: Region): number
|
|
362
|
-
|
|
363
|
-
MODULE-LEVEL CHANGES:
|
|
364
|
-
src/orders/service.ts: +5 lines, -1 lines
|
|
365
|
-
```
|
|
366
|
-
|
|
367
|
-
Scoped to staged changes or a specific file:
|
|
368
|
-
|
|
369
|
-
```
|
|
370
|
-
$ ucn diff-impact --staged # Only what's staged for commit
|
|
371
|
-
$ ucn diff-impact --base=main # Everything since branching from main
|
|
372
|
-
$ ucn diff-impact --file=src/orders # Only changes in this path
|
|
373
217
|
```
|
|
374
218
|
|
|
375
|
-
|
|
219
|
+
**Trace a call tree:**
|
|
376
220
|
|
|
377
221
|
```
|
|
378
|
-
$ ucn
|
|
379
|
-
|
|
380
|
-
Dead code: 15 unused symbol(s)
|
|
381
|
-
|
|
382
|
-
cli/index.js
|
|
383
|
-
[1649-1654] extractFunctionNameFromContent (function)
|
|
384
|
-
core/project.js
|
|
385
|
-
[1664-1694] findReExportsOf (method)
|
|
386
|
-
[1998-2020] withCompleteness (method)
|
|
387
|
-
...
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
---
|
|
391
|
-
|
|
392
|
-
## Install
|
|
393
|
-
|
|
394
|
-
```bash
|
|
395
|
-
npm install -g ucn
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
### As an MCP Server
|
|
399
|
-
|
|
400
|
-
One-line setup for supported clients:
|
|
401
|
-
|
|
402
|
-
```bash
|
|
403
|
-
# Claude Code
|
|
404
|
-
claude mcp add ucn -- npx -y ucn --mcp
|
|
405
|
-
|
|
406
|
-
# OpenAI Codex CLI
|
|
407
|
-
codex mcp add ucn -- npx -y ucn --mcp
|
|
408
|
-
|
|
409
|
-
# VS Code Copilot
|
|
410
|
-
code --add-mcp '{"name":"ucn","command":"npx","args":["-y","ucn","--mcp"]}'
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
Or add to your client's MCP config file manually:
|
|
414
|
-
|
|
415
|
-
```json
|
|
416
|
-
{
|
|
417
|
-
"mcpServers": {
|
|
418
|
-
"ucn": {
|
|
419
|
-
"command": "npx",
|
|
420
|
-
"args": ["-y", "ucn", "--mcp"]
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
```
|
|
425
|
-
|
|
426
|
-
<details>
|
|
427
|
-
<summary>VS Code Copilot uses a slightly different format (.vscode/mcp.json)</summary>
|
|
222
|
+
$ ucn trace expandGlob --depth=2
|
|
428
223
|
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
}
|
|
224
|
+
expandGlob
|
|
225
|
+
├── parseGlobPattern (core/discovery.js:219) [utility] 1x
|
|
226
|
+
│ └── globToRegex (core/discovery.js:256) [utility] 1x
|
|
227
|
+
├── walkDir (core/discovery.js:276) [utility] 1x
|
|
228
|
+
│ ├── compareNames (core/discovery.js:162) [utility] 1x
|
|
229
|
+
│ ├── shouldIgnore (core/discovery.js:340) [utility] 1x
|
|
230
|
+
│ └── walkDir (core/discovery.js:276) [utility] 1x (see above)
|
|
231
|
+
└── compareNames (core/discovery.js:162) [utility] 1x (see above)
|
|
439
232
|
```
|
|
440
|
-
</details>
|
|
441
233
|
|
|
442
|
-
|
|
234
|
+
**Find unused code:**
|
|
443
235
|
|
|
444
|
-
When MCP server is not needed, drop it in as a native skill:
|
|
445
|
-
|
|
446
|
-
```bash
|
|
447
|
-
# Claude Code
|
|
448
|
-
mkdir -p ~/.claude/skills
|
|
449
|
-
cp -r "$(npm root -g)/ucn/.claude/skills/ucn" ~/.claude/skills/
|
|
450
|
-
|
|
451
|
-
# OpenAI Codex CLI
|
|
452
|
-
mkdir -p ~/.agents/skills
|
|
453
|
-
cp -r "$(npm root -g)/ucn/.claude/skills/ucn" ~/.agents/skills/
|
|
454
236
|
```
|
|
237
|
+
$ ucn deadcode --exclude=test
|
|
455
238
|
|
|
456
|
-
|
|
239
|
+
Dead code: 1 unused symbol(s)
|
|
457
240
|
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
```bash
|
|
461
|
-
ucn toc # Project overview
|
|
462
|
-
ucn about handleRequest # Understand a function
|
|
463
|
-
ucn impact handleRequest # Before modifying
|
|
464
|
-
ucn fn handleRequest --file api # Extract specific function
|
|
465
|
-
ucn --interactive # Multiple queries, index stays in memory
|
|
241
|
+
core/discovery.js
|
|
242
|
+
[ 162- 166] legacyResolve (function)
|
|
466
243
|
```
|
|
467
244
|
|
|
468
245
|
---
|
|
469
246
|
|
|
470
|
-
##
|
|
247
|
+
## Workflows
|
|
471
248
|
|
|
472
|
-
Investigating a bug:
|
|
473
249
|
```bash
|
|
474
|
-
|
|
475
|
-
ucn
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
Before modifying a function:
|
|
479
|
-
```bash
|
|
480
|
-
ucn impact the_function # Who will break?
|
|
481
|
-
ucn smart the_function # See it + its helpers
|
|
482
|
-
# ... make your changes ...
|
|
483
|
-
ucn verify the_function # Did all call sites survive?
|
|
484
|
-
```
|
|
250
|
+
# Investigating a bug
|
|
251
|
+
ucn about buggyFunction # understand it fully
|
|
252
|
+
ucn trace buggyFunction --depth=2 # see what it calls
|
|
485
253
|
|
|
486
|
-
Before
|
|
487
|
-
|
|
488
|
-
ucn
|
|
489
|
-
|
|
490
|
-
ucn
|
|
491
|
-
```
|
|
492
|
-
|
|
493
|
-
Periodic cleanup:
|
|
494
|
-
```bash
|
|
495
|
-
ucn deadcode --exclude=test # What can be deleted?
|
|
496
|
-
ucn toc # Project overview
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
---
|
|
254
|
+
# Before modifying code
|
|
255
|
+
ucn impact theFunction # who will break?
|
|
256
|
+
ucn smart theFunction # function + its helpers inline
|
|
257
|
+
# ... make changes ...
|
|
258
|
+
ucn verify theFunction # do all call sites still match?
|
|
500
259
|
|
|
501
|
-
|
|
260
|
+
# Before committing
|
|
261
|
+
ucn diff-impact --staged # what I changed + who calls it
|
|
502
262
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
│ Limitation │ What happens │
|
|
506
|
-
├──────────────────────────┼──────────────────────────────────────────┤
|
|
507
|
-
│ │ │
|
|
508
|
-
│ 5 languages + HTML │ JS/TS, Python, Go, Rust, Java. │
|
|
509
|
-
│ (no C, Ruby, PHP, etc.) │ Agents fall back to text search for │
|
|
510
|
-
│ │ the rest. UCN complements, doesn't │
|
|
511
|
-
│ │ replace. │
|
|
512
|
-
│ │ │
|
|
513
|
-
├──────────────────────────┼──────────────────────────────────────────┤
|
|
514
|
-
│ │ │
|
|
515
|
-
│ Dynamic dispatch │ getattr(), reflection, eval() — UCN │
|
|
516
|
-
│ │ does static analysis and can't follow │
|
|
517
|
-
│ │ calls that only exist at runtime. │
|
|
518
|
-
│ │ │
|
|
519
|
-
├──────────────────────────┼──────────────────────────────────────────┤
|
|
520
|
-
│ │ │
|
|
521
|
-
│ Duck-typed methods │ obj.method() in JS/TS/Python — when │
|
|
522
|
-
│ │ the receiver type is ambiguous, results │
|
|
523
|
-
│ │ are marked "uncertain" so the agent │
|
|
524
|
-
│ │ knows to verify. Go/Rust/Java resolve │
|
|
525
|
-
│ │ with high confidence. │
|
|
526
|
-
│ │ │
|
|
527
|
-
├──────────────────────────┼──────────────────────────────────────────┤
|
|
528
|
-
│ │ │
|
|
529
|
-
│ Single project scope │ UCN follows imports within the project │
|
|
530
|
-
│ │ but stops at the boundary — no tracing │
|
|
531
|
-
│ │ into node_modules or site-packages. │
|
|
532
|
-
│ │ │
|
|
533
|
-
├──────────────────────────┼──────────────────────────────────────────┤
|
|
534
|
-
│ │ │
|
|
535
|
-
│ First-query index time │ Tree-sitter index is built on first │
|
|
536
|
-
│ │ query. A few seconds on large projects. │
|
|
537
|
-
│ │ Cached and incrementally updated — │
|
|
538
|
-
│ │ only changed files are re-indexed. │
|
|
539
|
-
│ │ │
|
|
540
|
-
└──────────────────────────┴──────────────────────────────────────────┘
|
|
263
|
+
# Cleanup
|
|
264
|
+
ucn deadcode --exclude=test # what can be deleted?
|
|
541
265
|
```
|
|
542
266
|
|
|
543
267
|
---
|
|
544
268
|
|
|
545
|
-
## All 28
|
|
546
|
-
|
|
547
|
-
All commands are accessible through a single `ucn` MCP tool with a `command` parameter.
|
|
269
|
+
## All 28 commands
|
|
548
270
|
|
|
549
271
|
```
|
|
550
272
|
UNDERSTAND MODIFY SAFELY
|
|
551
273
|
───────────────────── ─────────────────────
|
|
552
|
-
about
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
(quick overview)
|
|
559
|
-
verify check all sites
|
|
560
|
-
smart function + helpers match signature
|
|
561
|
-
expanded inline
|
|
562
|
-
plan preview a refactor
|
|
563
|
-
trace call tree — map before doing it
|
|
564
|
-
a whole pipeline
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
FIND & NAVIGATE ARCHITECTURE
|
|
274
|
+
about full picture impact all call sites
|
|
275
|
+
context callers + callees diff-impact git diff + callers
|
|
276
|
+
smart function + helpers verify signature check
|
|
277
|
+
trace call tree plan refactor preview
|
|
278
|
+
|
|
279
|
+
FIND & EXTRACT ARCHITECTURE
|
|
568
280
|
───────────────────── ─────────────────────
|
|
569
281
|
find locate definitions imports file dependencies
|
|
570
|
-
usages all occurrences exporters
|
|
571
|
-
fn extract
|
|
572
|
-
class extract
|
|
573
|
-
toc project overview tests find
|
|
574
|
-
deadcode unused
|
|
282
|
+
usages all occurrences exporters reverse dependencies
|
|
283
|
+
fn extract function graph dependency tree
|
|
284
|
+
class extract class related sibling functions
|
|
285
|
+
toc project overview tests find test coverage
|
|
286
|
+
deadcode unused code stacktrace error trace context
|
|
575
287
|
search text search api public API surface
|
|
576
288
|
example best usage example typedef type definitions
|
|
577
|
-
lines extract line range
|
|
578
|
-
expand drill into context stats project
|
|
289
|
+
lines extract line range file-exports file's exports
|
|
290
|
+
expand drill into context stats project stats
|
|
579
291
|
```
|
|
580
292
|
|
|
581
293
|
---
|
|
582
294
|
|
|
295
|
+
## Limitations
|
|
296
|
+
|
|
297
|
+
UCN is static AST analysis, not runtime instrumentation.
|
|
298
|
+
|
|
299
|
+
- **5 languages + HTML** — JS/TS, Python, Go, Rust, Java. Falls back to text search for others.
|
|
300
|
+
- **Static analysis only** — Can't follow `eval()`, `getattr()`, reflection, or other dynamic dispatch.
|
|
301
|
+
- **Duck-typed methods** — `obj.method()` in JS/TS/Python is marked "uncertain" when the receiver type is ambiguous. Go/Rust/Java resolve with high confidence.
|
|
302
|
+
- **Single project scope** — Follows imports within the project but not into `node_modules` or `site-packages`.
|
|
303
|
+
- **First-query index time** — A few seconds on large projects. Cached incrementally after that.
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
583
307
|
## License
|
|
584
308
|
|
|
585
309
|
MIT
|
|
586
|
-
|
|
587
|
-
UCN - Universal Code Navigator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ucn",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.27",
|
|
4
4
|
"mcpName": "io.github.mleoca/ucn",
|
|
5
5
|
"description": "Universal Code Navigator — AST-based call graph analysis for AI agents. Find callers, trace impact, detect dead code across JS/TS, Python, Go, Rust, Java, and HTML. CLI, MCP server, and agent skill.",
|
|
6
6
|
"main": "index.js",
|