ucn 3.8.9 → 3.8.11
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 +1 -1
- package/cli/index.js +3 -3
- package/mcp/server.js +25 -19
- package/package.json +1 -1
|
@@ -184,7 +184,7 @@ ucn [target] <command> [name] [--flags]
|
|
|
184
184
|
| `--case-sensitive` | Case-sensitive text search (default: case-insensitive) |
|
|
185
185
|
| `--exact` | Exact name match only in `find`/`typedef` (no substring) |
|
|
186
186
|
| `--include-uncertain` | Include ambiguous/uncertain matches in `context`/`smart`/`about` |
|
|
187
|
-
| `--
|
|
187
|
+
| `--no-confidence` | Hide confidence scores (shown by default) in `context`/`about` |
|
|
188
188
|
| `--min-confidence=N` | Filter edges below confidence threshold (e.g., `--min-confidence=0.7` keeps only high-confidence edges) |
|
|
189
189
|
| `--calls-only` | Only show call/test-case matches in `tests` (skip file-level results) |
|
|
190
190
|
| `--add-param=<name>` | Add a parameter (`plan` command). Combine with `--default=<value>` |
|
package/cli/index.js
CHANGED
|
@@ -112,7 +112,7 @@ function parseFlags(tokens) {
|
|
|
112
112
|
decorator: getValueFlag('--decorator'),
|
|
113
113
|
exported: tokens.includes('--exported'),
|
|
114
114
|
unused: tokens.includes('--unused'),
|
|
115
|
-
showConfidence: tokens.includes('--
|
|
115
|
+
showConfidence: !tokens.includes('--no-confidence'),
|
|
116
116
|
minConfidence: parseFloat(getValueFlag('--min-confidence') || '0') || 0,
|
|
117
117
|
framework: getValueFlag('--framework'),
|
|
118
118
|
};
|
|
@@ -141,7 +141,7 @@ const knownFlags = new Set([
|
|
|
141
141
|
'--regex', '--no-regex', '--functions',
|
|
142
142
|
'--max-lines', '--class-name', '--limit', '--max-files',
|
|
143
143
|
'--type', '--param', '--receiver', '--returns', '--decorator', '--exported', '--unused',
|
|
144
|
-
'--show-confidence', '--min-confidence',
|
|
144
|
+
'--show-confidence', '--no-confidence', '--min-confidence',
|
|
145
145
|
'--framework'
|
|
146
146
|
]);
|
|
147
147
|
|
|
@@ -1127,7 +1127,7 @@ Common Flags:
|
|
|
1127
1127
|
--class-name=X Scope to specific class (e.g., --class-name=Repository)
|
|
1128
1128
|
--include-methods Include method calls (obj.fn) in caller/callee analysis
|
|
1129
1129
|
--include-uncertain Include ambiguous/uncertain matches
|
|
1130
|
-
--
|
|
1130
|
+
--no-confidence Hide confidence scores (shown by default)
|
|
1131
1131
|
--min-confidence=N Filter edges below confidence threshold (0.0-1.0)
|
|
1132
1132
|
--include-exported Include exported symbols in deadcode
|
|
1133
1133
|
--no-regex Force plain text search (regex is default)
|
package/mcp/server.js
CHANGED
|
@@ -114,12 +114,17 @@ const server = new McpServer({
|
|
|
114
114
|
// TOOL HELPERS
|
|
115
115
|
// ============================================================================
|
|
116
116
|
|
|
117
|
-
const DEFAULT_OUTPUT_CHARS =
|
|
117
|
+
const DEFAULT_OUTPUT_CHARS = 10000; // ~2.5K tokens — targeted commands (about, context, smart, etc.)
|
|
118
|
+
const BROAD_OUTPUT_CHARS = 3000; // ~750 tokens — broad commands where truncated listings are useless
|
|
118
119
|
const MAX_OUTPUT_CHARS = 100000; // hard ceiling even with max_chars override
|
|
119
120
|
|
|
121
|
+
// Broad commands: output is project-wide, truncation means you need a filter, not more text
|
|
122
|
+
const BROAD_COMMANDS = new Set(['toc', 'entrypoints', 'diff_impact', 'affected_tests', 'deadcode', 'usages']);
|
|
123
|
+
|
|
120
124
|
function toolResult(text, command, maxChars) {
|
|
121
125
|
if (!text) return { content: [{ type: 'text', text: '(no output)' }] };
|
|
122
|
-
const
|
|
126
|
+
const defaultLimit = BROAD_COMMANDS.has(command) ? BROAD_OUTPUT_CHARS : DEFAULT_OUTPUT_CHARS;
|
|
127
|
+
const limit = Math.min(maxChars || defaultLimit, MAX_OUTPUT_CHARS);
|
|
123
128
|
if (text.length > limit) {
|
|
124
129
|
const fullSize = text.length;
|
|
125
130
|
const fullTokens = Math.round(fullSize / 4);
|
|
@@ -128,14 +133,15 @@ function toolResult(text, command, maxChars) {
|
|
|
128
133
|
const lastNewline = truncated.lastIndexOf('\n');
|
|
129
134
|
const cleanCut = lastNewline > limit * 0.8 ? truncated.substring(0, lastNewline) : truncated;
|
|
130
135
|
// Command-specific narrowing hints
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}
|
|
136
|
+
const hints = {
|
|
137
|
+
toc: 'Use in= to scope to a subdirectory, or detailed=false for compact view.',
|
|
138
|
+
entrypoints: 'Use framework= to filter by framework, exclude= to skip patterns.',
|
|
139
|
+
diff_impact: 'Use file= to scope to specific files/directories.',
|
|
140
|
+
affected_tests: 'Use file= to scope, exclude= to skip patterns.',
|
|
141
|
+
deadcode: 'Use file= to scope, exclude= to skip patterns.',
|
|
142
|
+
usages: 'Use file= to scope to specific files.',
|
|
143
|
+
};
|
|
144
|
+
const narrow = hints[command] || 'Use file=/in=/exclude= to narrow scope.';
|
|
139
145
|
return { content: [{ type: 'text', text: cleanCut + `\n\n... OUTPUT TRUNCATED: showing ${limit} of ${fullSize} chars. Full output would be ~${fullTokens} tokens. ${narrow} Or use all=true to see everything (warning: ~${fullTokens} tokens).` }] };
|
|
140
146
|
}
|
|
141
147
|
return { content: [{ type: 'text', text }] };
|
|
@@ -253,7 +259,7 @@ server.registerTool(
|
|
|
253
259
|
include_methods: z.boolean().optional().describe('Include obj.method() calls (default: true for about/trace)'),
|
|
254
260
|
include_uncertain: z.boolean().optional().describe('Include uncertain/ambiguous matches'),
|
|
255
261
|
min_confidence: z.number().optional().describe('Minimum confidence threshold (0.0-1.0) to filter caller/callee edges'),
|
|
256
|
-
show_confidence: z.boolean().optional().describe('Show confidence scores
|
|
262
|
+
show_confidence: z.boolean().optional().describe('Show confidence scores per edge (default: true). Set false to hide.'),
|
|
257
263
|
with_types: z.boolean().optional().describe('Include related type definitions in output'),
|
|
258
264
|
detailed: z.boolean().optional().describe('Show full symbol listing per file'),
|
|
259
265
|
exact: z.boolean().optional().describe('Exact name match only (no substring matching)'),
|
|
@@ -285,7 +291,7 @@ server.registerTool(
|
|
|
285
291
|
class_name: z.string().optional().describe('Class name to scope method analysis (e.g. "MarketDataFetcher" for close)'),
|
|
286
292
|
limit: z.number().optional().describe('Max results to return (default: 500). Caps find, usages, search, deadcode, api, toc --detailed.'),
|
|
287
293
|
max_files: z.number().optional().describe('Max files to index (default: 10000). Use for very large codebases.'),
|
|
288
|
-
max_chars: z.number().optional().describe('Max output chars before truncation (
|
|
294
|
+
max_chars: z.number().optional().describe('Max output chars before truncation. Targeted commands (about, context, smart, etc.): 10K default. Broad commands (toc, entrypoints, deadcode, etc.): 3K default. Max: 100K. Use all=true to bypass all caps.'),
|
|
289
295
|
// Structural search flags (search command)
|
|
290
296
|
type: z.string().optional().describe('Symbol type filter for structural search: function, class, call, method, type. Triggers index-based search.'),
|
|
291
297
|
param: z.string().optional().describe('Filter by parameter name or type (structural search). E.g. "Request", "ctx".'),
|
|
@@ -308,8 +314,8 @@ server.registerTool(
|
|
|
308
314
|
// all=true bypasses both formatter caps AND char truncation (parity with CLI --all)
|
|
309
315
|
const maxChars = ep.all ? MAX_OUTPUT_CHARS : ep.maxChars;
|
|
310
316
|
|
|
311
|
-
// Wrap toolResult to auto-inject maxChars from this request
|
|
312
|
-
const tr = (text
|
|
317
|
+
// Wrap toolResult to auto-inject command + maxChars from this request
|
|
318
|
+
const tr = (text) => toolResult(text, command, maxChars);
|
|
313
319
|
|
|
314
320
|
try {
|
|
315
321
|
switch (command) {
|
|
@@ -327,7 +333,7 @@ server.registerTool(
|
|
|
327
333
|
return tr(output.formatAbout(result, {
|
|
328
334
|
allHint: 'Repeat with all=true to show all.',
|
|
329
335
|
methodsHint: 'Note: obj.method() callers/callees excluded. Use include_methods=true to include them.',
|
|
330
|
-
showConfidence: ep.showConfidence,
|
|
336
|
+
showConfidence: ep.showConfidence !== false,
|
|
331
337
|
}));
|
|
332
338
|
}
|
|
333
339
|
|
|
@@ -337,7 +343,7 @@ server.registerTool(
|
|
|
337
343
|
if (!ok) return tr(error); // context uses soft error (not toolError)
|
|
338
344
|
const { text, expandable } = output.formatContext(ctx, {
|
|
339
345
|
expandHint: 'Use expand command with item number to see code for any item.',
|
|
340
|
-
showConfidence: ep.showConfidence,
|
|
346
|
+
showConfidence: ep.showConfidence !== false,
|
|
341
347
|
});
|
|
342
348
|
expandCacheInstance.save(index.root, ep.name, ep.file, expandable);
|
|
343
349
|
return tr(text);
|
|
@@ -432,7 +438,7 @@ server.registerTool(
|
|
|
432
438
|
topHint: 'Set top=N or use detailed=false for compact view.'
|
|
433
439
|
});
|
|
434
440
|
if (note) text += '\n\n' + note;
|
|
435
|
-
return tr(text
|
|
441
|
+
return tr(text);
|
|
436
442
|
}
|
|
437
443
|
|
|
438
444
|
case 'search': {
|
|
@@ -456,7 +462,7 @@ server.registerTool(
|
|
|
456
462
|
const index = getIndex(project_dir, ep);
|
|
457
463
|
const { ok, result, error } = execute(index, 'affectedTests', ep);
|
|
458
464
|
if (!ok) return tr(error);
|
|
459
|
-
return tr(output.formatAffectedTests(result, { all: ep.all })
|
|
465
|
+
return tr(output.formatAffectedTests(result, { all: ep.all }));
|
|
460
466
|
}
|
|
461
467
|
|
|
462
468
|
case 'deadcode': {
|
|
@@ -542,7 +548,7 @@ server.registerTool(
|
|
|
542
548
|
const index = getIndex(project_dir, ep);
|
|
543
549
|
const { ok, result, error } = execute(index, 'diffImpact', ep);
|
|
544
550
|
if (!ok) return tr(error); // soft error — e.g. "not a git repo"
|
|
545
|
-
return tr(output.formatDiffImpact(result, { all: ep.all })
|
|
551
|
+
return tr(output.formatDiffImpact(result, { all: ep.all }));
|
|
546
552
|
}
|
|
547
553
|
|
|
548
554
|
// ── Other ───────────────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ucn",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.11",
|
|
4
4
|
"mcpName": "io.github.mleoca/ucn",
|
|
5
5
|
"description": "Code intelligence toolkit for AI agents — extract functions, trace call chains, find callers, detect dead code without reading entire files. Works as MCP server, CLI, or agent skill. Supports JS/TS, Python, Go, Rust, Java.",
|
|
6
6
|
"main": "index.js",
|