ucn 5.5.1 → 5.5.3

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.
Files changed (97) hide show
  1. package/.claude/skills/ucn/SKILL.md +35 -9
  2. package/.claude/skills/ucn/references/commands.md +40 -18
  3. package/.claude/skills/ucn/references/resolution-rules.md +126 -20
  4. package/.claude/skills/ucn/references/trust-contract.md +5 -3
  5. package/README.md +32 -21
  6. package/cli/index.js +2 -1
  7. package/core/accessors.js +341 -54
  8. package/core/account.js +74 -20
  9. package/core/analysis.js +257 -125
  10. package/core/ast-analysis.js +12 -3
  11. package/core/bridge.js +15 -65
  12. package/core/brief.js +8 -4
  13. package/core/build-worker.js +2 -1
  14. package/core/cache.js +137 -6
  15. package/core/call-name-cache.js +134 -0
  16. package/core/callable-scope.js +21 -0
  17. package/core/callers.js +4726 -940
  18. package/core/check.js +22 -5
  19. package/core/class-identity.js +399 -12
  20. package/core/client-receivers.js +189 -0
  21. package/core/constructor-calls.js +831 -0
  22. package/core/constructor-hierarchy.js +147 -0
  23. package/core/constructor-protocol.js +196 -0
  24. package/core/contract-membership.js +346 -140
  25. package/core/cpp-conversion-constraints.js +123 -0
  26. package/core/cpp-conversion-syntax.js +216 -0
  27. package/core/cpp-conversions.js +414 -0
  28. package/core/cpp-scope.js +245 -44
  29. package/core/deadcode.js +61 -16
  30. package/core/decorator-binding.js +137 -3
  31. package/core/enum-reference-syntax.js +134 -0
  32. package/core/execute.js +17 -1
  33. package/core/external-macros.js +42 -10
  34. package/core/go-packages.js +171 -0
  35. package/core/graph-build.js +2 -0
  36. package/core/graph.js +75 -59
  37. package/core/ignore-rules.js +2 -1
  38. package/core/imports.js +145 -19
  39. package/core/index-ir.js +41 -4
  40. package/core/inprocess-clients.js +41 -15
  41. package/core/ir.js +27 -6
  42. package/core/macro-expansion.js +38 -2
  43. package/core/out-of-class-members.js +182 -0
  44. package/core/output/analysis-ext.js +4 -2
  45. package/core/output/analysis.js +89 -20
  46. package/core/output/graph.js +12 -3
  47. package/core/output/lines.js +4 -3
  48. package/core/output/public.js +2 -0
  49. package/core/output/reporting.js +12 -1
  50. package/core/output/shared.js +2 -0
  51. package/core/output/tracing.js +28 -22
  52. package/core/output-budget.js +2 -2
  53. package/core/parallel-build.js +52 -1
  54. package/core/project.js +217 -112
  55. package/core/provenance-constructor-base.js +161 -0
  56. package/core/provenance-facts.js +257 -27
  57. package/core/provenance-overload.js +458 -54
  58. package/core/provenance-type.js +487 -0
  59. package/core/provenance.js +234 -15
  60. package/core/public-command.js +17 -2
  61. package/core/query-bodies.js +159 -0
  62. package/core/reflection.js +270 -2
  63. package/core/rename-token-syntax.js +111 -0
  64. package/core/reporting.js +13 -7
  65. package/core/request-helpers.js +63 -7
  66. package/core/rust-macro-expansion.js +151 -19
  67. package/core/rust-modules.js +1 -1
  68. package/core/rust-names.js +607 -0
  69. package/core/search.js +70 -17
  70. package/core/shared.js +98 -1
  71. package/core/source-memo.js +201 -0
  72. package/core/text-usage-syntax.js +38 -0
  73. package/core/tracing.js +7 -1
  74. package/core/type-denotation.js +124 -37
  75. package/core/type-references.js +615 -246
  76. package/core/value-references.js +2777 -0
  77. package/core/verify.js +1097 -281
  78. package/languages/adapter.js +28 -4
  79. package/languages/c-family.js +1118 -164
  80. package/languages/constructor-bases.js +105 -0
  81. package/languages/cpp-platform.js +26 -0
  82. package/languages/cpp-site-syntax.js +83 -0
  83. package/languages/csharp-scope.js +439 -0
  84. package/languages/csharp.js +428 -68
  85. package/languages/go.js +385 -207
  86. package/languages/html.js +4 -2
  87. package/languages/index.js +397 -2
  88. package/languages/java-platform.js +226 -0
  89. package/languages/java-unicode.js +269 -0
  90. package/languages/java.js +461 -117
  91. package/languages/javascript.js +418 -66
  92. package/languages/lexical-scope.js +190 -23
  93. package/languages/python.js +404 -54
  94. package/languages/rust.js +510 -82
  95. package/languages/utils.js +67 -8
  96. package/mcp/server.js +8 -2
  97. package/package.json +3 -3
@@ -80,7 +80,11 @@ function nodeToLocation(node, codeOrLines) {
80
80
  const indentMatch = firstLine.match(/^(\s*)/);
81
81
  const indent = indentMatch ? indentMatch[1].length : 0;
82
82
 
83
- return { startLine, endLine, indent };
83
+ return { startLine, endLine, indent, sourceSpan: {
84
+ start: node.startIndex, end: node.endIndex,
85
+ startLine, endLine,
86
+ startColumn: node.startPosition.column, endColumn: node.endPosition.column,
87
+ } };
84
88
  }
85
89
 
86
90
  /**
@@ -343,7 +347,7 @@ function parseRustParam(param, info) {
343
347
  function parseJavaParam(param, info) {
344
348
  if (param.type === 'formal_parameter' || param.type === 'spread_parameter') {
345
349
  let nameNode = param.childForFieldName('name');
346
- const typeNode = param.childForFieldName('type');
350
+ let typeNode = param.childForFieldName('type');
347
351
  // Java varargs: spread_parameter wraps name in variable_declarator
348
352
  // e.g., `String... args` → spread_parameter > variable_declarator > identifier
349
353
  if (!nameNode && param.type === 'spread_parameter') {
@@ -355,8 +359,14 @@ function parseJavaParam(param, info) {
355
359
  }
356
360
  }
357
361
  }
362
+ if (!typeNode && param.type === 'spread_parameter') {
363
+ const types = new Set(['type_identifier', 'scoped_type_identifier', 'generic_type',
364
+ 'array_type', 'annotated_type', 'integral_type', 'floating_point_type', 'boolean_type']);
365
+ typeNode = param.namedChildren.find(child => types.has(child.type));
366
+ }
358
367
  if (nameNode) info.name = nodeTextWithoutComments(nameNode);
359
- if (typeNode) info.type = nodeTextWithoutComments(typeNode);
368
+ if (typeNode) info.type = nodeTextWithoutComments(typeNode) +
369
+ (param.type === 'spread_parameter' ? '[]' : '');
360
370
  if (param.type === 'spread_parameter') info.rest = true;
361
371
  }
362
372
  }
@@ -676,6 +686,10 @@ function getTokenTypeAtPosition(rootNode, line, column) {
676
686
  // Find the smallest node at this position
677
687
  const node = rootNode.descendantForPosition({ row, column });
678
688
  if (!node) return 'code';
689
+ // A comment in an aliased rule can be wrapped with the alias type,
690
+ // depending on which traversal read it first (fix #420): an extra's
691
+ // grammar type is stable.
692
+ if (node.isExtra && /comment/.test(node.grammarType || '')) return 'comment';
679
693
 
680
694
  // Walk up the tree to check if we're in a comment or string
681
695
  let current = node;
@@ -843,17 +857,16 @@ const NAMED_CHILDREN_LIST = Symbol.for('ucn.namedChildrenList');
843
857
  function _buildNodeList(rootNode) {
844
858
  const nodes = [];
845
859
  const subtreeEnds = [];
846
- // Iterative DFS with subtreeEnd tracking
847
- // We use a post-processing step to fill subtreeEnds
848
- function collect(node) {
860
+ // Depth-first preorder with each subtree boundary filled on return.
861
+ function collect(node, parent) {
849
862
  const idx = nodes.length;
850
863
  nodes.push(node);
851
864
  subtreeEnds.push(0);
852
865
  // Batched children read — one native call instead of N+1 (see
853
866
  // traverseTree); the array stays on the node for later reads.
854
- const children = node[NAMED_CHILDREN_LIST] ? node[NAMED_CHILDREN_LIST]() : node.namedChildren;
867
+ const children = node[NAMED_CHILDREN_LIST] ? node[NAMED_CHILDREN_LIST](parent) : node.namedChildren;
855
868
  for (let i = 0; i < children.length; i++) {
856
- collect(children[i]);
869
+ collect(children[i], node);
857
870
  }
858
871
  subtreeEnds[idx] = nodes.length;
859
872
  }
@@ -1322,6 +1335,20 @@ function genericArityOf(text) {
1322
1335
  return null;
1323
1336
  }
1324
1337
 
1338
+ // A type argument list on an enclosing segment belongs to that segment:
1339
+ // erasing everything after the first '<' would turn Outer<T>.Inner into
1340
+ // Outer. Callers without enclosing generic identity must retain uncertainty.
1341
+ function hasParameterizedQualifier(text) {
1342
+ let depth = 0, parameterized = false;
1343
+ for (const ch of String(text || '')) {
1344
+ if (ch === '<') depth++;
1345
+ else if (ch === '>') {
1346
+ if (--depth === 0) parameterized = true;
1347
+ } else if (ch === '.' && depth === 0 && parameterized) return true;
1348
+ }
1349
+ return false;
1350
+ }
1351
+
1325
1352
  // Exclusive clauses of one compound statement (fix #398F): `if`/`elif`/
1326
1353
  // `else` and `case` arms never both run; a `try` body and its handlers, two
1327
1354
  // handlers, a handler and the `try` `else` are alternatives. A `try` body and
@@ -1358,8 +1385,40 @@ function goPathPackageName(modulePath) {
1358
1385
  return cut > 0 ? base.slice(0, cut) : base;
1359
1386
  }
1360
1387
 
1388
+ // Node types that declare a type parameter, and the name-token types under
1389
+ // them (fix #421; shared with core/provenance-type.js).
1390
+ const TYPE_PARAMETER_PARENTS = Object.freeze(['type_parameter', 'type_parameters',
1391
+ 'constrained_type_parameter', 'type_parameter_declaration',
1392
+ 'optional_type_parameter_declaration', 'variadic_type_parameter_declaration']);
1393
+ const TYPE_PARAMETER_NAME_TOKENS = Object.freeze(['identifier', 'type_identifier', 'namespace_identifier',
1394
+ 'qualified_identifier', 'scoped_type_identifier', 'qualified_name', 'alias_qualified_name']);
1395
+ const TYPE_PARAMETER_NAME_TOKEN_SET = new Set(TYPE_PARAMETER_NAME_TOKENS);
1396
+
1397
+ /**
1398
+ * Every name token written directly in a type-parameter declaration of the
1399
+ * trees (fix #421): a superset of the file's type-parameter names (bounds
1400
+ * and defaults included), sorted. A name outside it is no type parameter
1401
+ * anywhere in the file, which a construction's name-scope proof reads
1402
+ * without parsing the file again.
1403
+ */
1404
+ function declaredTypeParameterNames(...trees) {
1405
+ const names = new Set();
1406
+ for (const tree of trees) {
1407
+ for (const parent of tree?.rootNode?.descendantsOfType([...TYPE_PARAMETER_PARENTS]) || []) {
1408
+ for (const node of parent.children) {
1409
+ if (TYPE_PARAMETER_NAME_TOKEN_SET.has(node.type)) names.add(node.text);
1410
+ }
1411
+ }
1412
+ }
1413
+ return [...names].sort();
1414
+ }
1415
+
1361
1416
  module.exports = {
1417
+ TYPE_PARAMETER_PARENTS,
1418
+ TYPE_PARAMETER_NAME_TOKENS,
1419
+ declaredTypeParameterNames,
1362
1420
  genericArityOf,
1421
+ hasParameterizedQualifier,
1363
1422
  goPathPackageName,
1364
1423
  parseErrorRegions,
1365
1424
  containsOwnNode,
package/mcp/server.js CHANGED
@@ -35,6 +35,7 @@ const {
35
35
  formatSurfaceMessage,
36
36
  } = require('../core/registry');
37
37
  const { execute } = require('../core/execute');
38
+ const { sourceRangeTarget } = require('../core/public-command');
38
39
  const { describeError, UcnError } = require('../core/errors');
39
40
  const { applyOutputBudget, MAX_OUTPUT_CHARS } = require('../core/output-budget');
40
41
 
@@ -245,7 +246,7 @@ Use UCN for semantic questions: exact definitions, symbol-aware callers/callees,
245
246
  - check: symbol signature check when name is set; precommit check when omitted. plan previews the selected declaration plus indexed call/import/export edits.
246
247
  - deadcode/audit_async/stacktrace: focused audits and runtime evidence. Computed dispatch is reported as a health/deletion blind spot; unknown decorators and member-assigned handlers are withheld from default dead-code claims.
247
248
 
248
- CONFIRMED carries target-identity evidence. UNVERIFIED is possible and requires review; when same-name definitions compete, show returns their stable handles once above the sites. ACCOUNT conserves observed literal-name lines; an observed-text zero never claims semantic completeness or safe deletion. Evidence weights are ordinal, not probabilities. Warnings, excluded reasons, and contract metadata remain visible when caller evidence is returned. Release evaluation cross-checks overlapping stable-handle claims across find, show, source, impact, tests, check, and caller trace, and compares pinned real-repository samples with ts-morph, Pyright, gopls, rust-analyzer, JDT LS, clangd, and Roslyn.` + generateMcpParamSection();
249
+ CONFIRMED carries target-identity evidence. UNVERIFIED is possible and requires review; when same-name definitions compete, show returns their stable handles once above the sites. ACCOUNT conserves observed literal-name lines; an observed-text zero never claims semantic completeness or safe deletion. Evidence weights are ordinal, not probabilities. Warnings, excluded reasons, and contract metadata remain visible when caller evidence is returned. Releases are gated on pinned real repositories: sampled callers, callees, value references, and dead-code claims are compared with ts-morph, Pyright, gopls, rust-analyzer, JDT LS, Roslyn, and clangd, and one handle's claims must agree across find, show, source, impact, tests, check, and caller trace.` + generateMcpParamSection();
249
250
 
250
251
  // The default description is the only public contract. The former verbose
251
252
  // description is intentionally not selectable: it documented retired commands
@@ -306,7 +307,7 @@ const INPUT_SHAPE = {
306
307
  rename_to: stringParam('New name for the function, method, or type (plan command)'),
307
308
  default_value: stringParam('Default value for added parameter (plan command)'),
308
309
  stack: stringParam('The stack trace text to parse (stacktrace command)'),
309
- range: stringParam('source line range, e.g. "10-20" or "15"; requires file.'),
310
+ range: stringParam('source line range, e.g. "10-20" or "15", of the file given as file or name.'),
310
311
  base: stringParam('Git ref (default: HEAD). impact/check without a symbol: diff against it; check with a symbol: compare the declaration with its version there. E.g. "HEAD~3", "main", a commit SHA'),
311
312
  staged: booleanParam('impact/check without a symbol: analyze staged changes.'),
312
313
  deep: booleanParam('repo: include health and sample the ordinal resolution-evidence profile, not accuracy.'),
@@ -473,6 +474,11 @@ server.registerTool(
473
474
  // Post-result checks are still retained below for symbol-derived
474
475
  // paths, but a range request may point at a real file outside the
475
476
  // project and must fail before any content leaves the process.
477
+ // `name` is the file of a range request (name=<file>, range="N-M").
478
+ if (canonicalCommand === 'source') {
479
+ const target = sourceRangeTarget(ep);
480
+ if (target !== ep) { delete ep.name; ep.file = target.file; }
481
+ }
476
482
  if (canonicalCommand === 'source' && ep.file) {
477
483
  const sourcePath = resolveAndValidatePath(index, ep.file);
478
484
  if (typeof sourcePath !== 'string') return sourcePath;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ucn",
3
- "version": "5.5.1",
3
+ "version": "5.5.3",
4
4
  "mcpName": "io.github.mleoca/ucn",
5
5
  "description": "Auditable AST code intelligence for AI agents: 18 task-oriented commands through one MCP tool, CLI, or agent skill. Supports JS/TS, Python, Go, Rust, Java, C, C++, C#, and HTML.",
6
6
  "main": "index.js",
@@ -10,7 +10,7 @@
10
10
  },
11
11
  "scripts": {
12
12
  "version": "node scripts/sync-server-version.js && git add server.json",
13
- "test": "node --test test/audit-5.4.0.test.js test/audit-5.3.8.test.js test/audit-5.3.7.test.js test/audit-5.3.6.test.js test/evidence-provenance.test.js test/provenance-unit.test.js test/shell-output.test.js test/parser-unit.test.js test/integration.test.js test/cache.test.js test/formatter.test.js test/interactive.test.js test/feature.test.js test/regression-js.test.js test/regression-py.test.js test/regression-go.test.js test/regression-java.test.js test/regression-rust.test.js test/regression-c-family.test.js test/regression-cross.test.js test/regression-mcp.test.js test/mcp-protocol.test.js test/mcp-sdk-compat.test.js test/dependency-security.test.js test/regression-parser.test.js test/regression-commands.test.js test/regression-fixes.test.js test/regression-bugfixes.test.js test/release-surface-regressions.test.js test/prerelease-audit.test.js test/release-readiness-audit.test.js test/cross-language.test.js test/accuracy.test.js test/command-coverage.test.js test/perf-optimizations.test.js test/performance-gate-policy.test.js test/oracle-gate-policy.test.js test/outcome-policy.test.js test/consistency-eval.test.js test/agent-public-surface-benchmark.test.js test/command-contracts.test.js test/language-adapter.test.js test/systematic-test.js test/mcp-edge-cases.js test/conservation.test.js test/parity-test.js test/trust-matrix.test.js",
13
+ "test": "node --test test/audit-5.4.0.test.js test/audit-5.3.8.test.js test/audit-5.3.7.test.js test/audit-5.3.6.test.js test/evidence-provenance.test.js test/provenance-unit.test.js test/provenance-scope.test.js test/shell-output.test.js test/parser-unit.test.js test/integration.test.js test/cache.test.js test/formatter.test.js test/interactive.test.js test/feature.test.js test/regression-js.test.js test/regression-py.test.js test/regression-go.test.js test/regression-java.test.js test/regression-rust.test.js test/regression-c-family.test.js test/regression-cross.test.js test/regression-mcp.test.js test/mcp-protocol.test.js test/mcp-sdk-compat.test.js test/dependency-security.test.js test/regression-parser.test.js test/regression-commands.test.js test/regression-fixes.test.js test/regression-bugfixes.test.js test/release-surface-regressions.test.js test/prerelease-audit.test.js test/release-readiness-audit.test.js test/cross-language.test.js test/accuracy.test.js test/command-coverage.test.js test/perf-optimizations.test.js test/performance-gate-policy.test.js test/oracle-gate-policy.test.js test/outcome-policy.test.js test/consistency-eval.test.js test/agent-public-surface-benchmark.test.js test/command-contracts.test.js test/language-adapter.test.js test/systematic-test.js test/mcp-edge-cases.js test/conservation.test.js test/parity-test.js test/trust-matrix.test.js",
14
14
  "benchmark:agent": "node test/agent-public-surface-benchmark.js",
15
15
  "benchmark:agent:gate": "node test/agent-public-surface-benchmark.js --gate",
16
16
  "benchmark:agent:legacy": "node test/agent-understanding-benchmark.js",
@@ -87,7 +87,7 @@
87
87
  "dependencies": {
88
88
  "node-addon-api": "8.9.2",
89
89
  "node-gyp-build": "4.8.4",
90
- "re2js": "2.8.6",
90
+ "re2js": "2.8.7",
91
91
  "ret": "0.5.0",
92
92
  "safe-regex2": "5.1.1",
93
93
  "tree-sitter": "0.21.1",