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.
@@ -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
- | `--show-confidence` | Show confidence scores (0.0–1.0) per caller/callee edge in `context`/`about` |
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('--show-confidence'),
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
- --show-confidence Show confidence scores per caller/callee edge
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 = 30000; // ~7.5K tokens — safe default for AI context
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 limit = Math.min(maxChars || DEFAULT_OUTPUT_CHARS, MAX_OUTPUT_CHARS);
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
- let narrow = 'Use file=/in=/exclude= to narrow scope.';
132
- if (command === 'toc') {
133
- narrow = 'Use in= to scope to a subdirectory, or detailed=false for compact view.';
134
- } else if (command === 'diff_impact') {
135
- narrow = 'Use file= to scope to specific files/directories.';
136
- } else if (command === 'affected_tests') {
137
- narrow = 'Use file= to scope, exclude= to skip patterns.';
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 and resolution evidence per edge'),
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 (default: 30000 ~7.5K tokens, max: 100000 ~25K tokens). Use all=true to bypass all caps, or set this for fine-grained control. Truncation message shows full size.'),
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, cmd) => toolResult(text, cmd, maxChars);
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, 'toc');
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 }), 'affected_tests');
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 }), 'diff_impact');
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.9",
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",