ucn 5.4.1 → 5.5.0

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 (87) hide show
  1. package/.claude/skills/ucn/SKILL.md +58 -236
  2. package/.claude/skills/ucn/references/commands.md +144 -68
  3. package/.claude/skills/ucn/references/resolution-rules.md +171 -0
  4. package/.claude/skills/ucn/references/trust-contract.md +27 -33
  5. package/README.md +18 -12
  6. package/cli/index.js +42 -16
  7. package/core/accessors.js +118 -3
  8. package/core/account.js +30 -0
  9. package/core/analysis.js +508 -264
  10. package/core/ast-analysis.js +76 -117
  11. package/core/async-producers.js +1729 -0
  12. package/core/bridge.js +1877 -268
  13. package/core/brief.js +6 -0
  14. package/core/build-worker.js +78 -14
  15. package/core/cache.js +522 -31
  16. package/core/callers.js +12053 -1047
  17. package/core/check.js +30 -38
  18. package/core/class-identity.js +1028 -0
  19. package/core/command-contracts.js +6 -6
  20. package/core/configuration-items.js +86 -0
  21. package/core/contract-membership.js +2262 -0
  22. package/core/cpp-scope.js +532 -0
  23. package/core/deadcode.js +171 -49
  24. package/core/decorator-binding.js +260 -0
  25. package/core/discovery.js +281 -164
  26. package/core/errors.js +52 -0
  27. package/core/execute.js +21 -9
  28. package/core/external-macros.js +326 -0
  29. package/core/graph-build.js +277 -8
  30. package/core/graph.js +35 -2
  31. package/core/ignore-rules.js +472 -0
  32. package/core/imports.js +504 -42
  33. package/core/index-ir.js +94 -11
  34. package/core/inprocess-clients.js +636 -0
  35. package/core/ir.js +87 -8
  36. package/core/macro-expansion.js +1416 -0
  37. package/core/output/analysis-ext.js +6 -6
  38. package/core/output/analysis.js +18 -2
  39. package/core/output/brief.js +3 -0
  40. package/core/output/doctor.js +4 -0
  41. package/core/output/endpoints.js +15 -6
  42. package/core/output/find.js +11 -2
  43. package/core/output/lines.js +8 -2
  44. package/core/output/refactoring.js +121 -14
  45. package/core/output/reporting.js +31 -3
  46. package/core/output/shared.js +14 -0
  47. package/core/output-budget.js +316 -122
  48. package/core/parallel-build.js +124 -47
  49. package/core/parser.js +3 -2
  50. package/core/project.js +457 -60
  51. package/core/provenance-facts.js +156 -12
  52. package/core/provenance-overload.js +30 -3
  53. package/core/provenance.js +104 -30
  54. package/core/pytest-fixtures.js +434 -0
  55. package/core/python-fixture-flow.js +17 -3
  56. package/core/python-modules.js +173 -0
  57. package/core/reflection.js +877 -0
  58. package/core/registry.js +1 -1
  59. package/core/reporting.js +234 -52
  60. package/core/request-helpers.js +561 -0
  61. package/core/route-graph.js +1922 -0
  62. package/core/route-lists.js +2414 -0
  63. package/core/rust-macro-expansion.js +2113 -0
  64. package/core/rust-modules.js +185 -0
  65. package/core/search.js +121 -29
  66. package/core/shared.js +19 -1
  67. package/core/test-name-bindings.js +256 -0
  68. package/core/type-denotation.js +1161 -0
  69. package/core/type-references.js +3229 -0
  70. package/core/verify.js +3360 -672
  71. package/languages/adapter.js +31 -5
  72. package/languages/c-family.js +4061 -212
  73. package/languages/c-macro-invocations.js +380 -0
  74. package/languages/c-preprocessor.js +254 -0
  75. package/languages/csharp.js +1406 -49
  76. package/languages/go.js +1243 -70
  77. package/languages/index.js +728 -6
  78. package/languages/java.js +473 -61
  79. package/languages/javascript.js +1270 -197
  80. package/languages/lexical-scope.js +1280 -0
  81. package/languages/python.js +1557 -72
  82. package/languages/rust-macro-rules.js +1020 -0
  83. package/languages/rust-value-flow.js +416 -0
  84. package/languages/rust.js +2237 -115
  85. package/languages/utils.js +298 -4
  86. package/mcp/server.js +25 -11
  87. package/package.json +1 -1
package/core/check.js CHANGED
@@ -136,12 +136,12 @@ function check(index, options = {}) {
136
136
  });
137
137
  continue;
138
138
  }
139
- let verifyResult;
140
- try {
141
- verifyResult = index.verify(fn.name, { file: filePath, line: fn.startLine });
142
- } catch (e) {
143
- verifyResult = null;
144
- }
139
+ // The base revision decides which call sites the changed
140
+ // declaration bound before (fix #394). An exception inside verify is
141
+ // an internal error, never a silently skipped check.
142
+ const verifyResult = index.verify(fn.name, {
143
+ file: filePath, line: fn.startLine, base: options.staged ? 'HEAD' : (options.base || 'HEAD'),
144
+ });
145
145
  // Note: verify() returns `mismatches` as a COUNT and `mismatchDetails` as the array.
146
146
  const mismatches = verifyResult && Array.isArray(verifyResult.mismatchDetails)
147
147
  ? verifyResult.mismatchDetails
@@ -152,22 +152,22 @@ function check(index, options = {}) {
152
152
  let callers = Array.isArray(fn.callers) ? fn.callers : [];
153
153
  let unverifiedCallers = Array.isArray(fn.unverifiedCallers) ? fn.unverifiedCallers : [];
154
154
  let account = fn.account || null;
155
+ // An exception here is an internal error, never a silent orphan claim
156
+ // (fix #394).
155
157
  if (callers.length === 0 && fn._kind === 'added') {
156
- try {
157
- const definitions = (index.symbols.get(fn.name) || []).filter(d =>
158
- (d.relativePath === filePath || d.file === fn.filePath) &&
159
- (!fn.startLine || d.startLine === fn.startLine));
160
- const raw = index.findCallers(fn.name, {
161
- includeMethods: true,
162
- collectAccount: true,
163
- targetDefinitions: definitions.length > 0 ? definitions : undefined,
164
- }) || [];
165
- callers = raw.filter(c => c.tier !== 'unverified');
166
- unverifiedCallers = raw.filter(c => c.tier === 'unverified')
167
- .concat(raw.unverifiedEntries || []);
168
- account = composeAccount(index, fn.name, raw);
169
- unverifiedCallers = unverifiedCallers.concat(callNotResolvedEntries(index, account));
170
- } catch (e) { /* skip */ }
158
+ const definitions = (index.symbols.get(fn.name) || []).filter(d =>
159
+ (d.relativePath === filePath || d.file === fn.filePath) &&
160
+ (!fn.startLine || d.startLine === fn.startLine));
161
+ const raw = index.findCallers(fn.name, {
162
+ includeMethods: true,
163
+ collectAccount: true,
164
+ targetDefinitions: definitions.length > 0 ? definitions : undefined,
165
+ }) || [];
166
+ callers = raw.filter(c => c.tier !== 'unverified');
167
+ unverifiedCallers = raw.filter(c => c.tier === 'unverified')
168
+ .concat(raw.unverifiedEntries || []);
169
+ account = composeAccount(index, fn.name, raw);
170
+ unverifiedCallers = unverifiedCallers.concat(callNotResolvedEntries(index, account));
171
171
  }
172
172
 
173
173
  const item = {
@@ -189,14 +189,8 @@ function check(index, options = {}) {
189
189
  // would be the exact silent-drop the contract forbids).
190
190
  if (item.kind === 'added' && callers.length === 0 && unverifiedCallers.length === 0) {
191
191
  // Check entry points: if the symbol is a known entry-point pattern, not orphan
192
- let isEntry = false;
193
- try {
194
- const ep = require('./entrypoints');
195
- if (typeof ep.detectEntrypoints === 'function') {
196
- const eps = ep.detectEntrypoints(index) || [];
197
- isEntry = eps.some(e => e.name === fn.name && (e.file === filePath || e.relativePath === filePath));
198
- }
199
- } catch (e) { /* skip */ }
192
+ const eps = require('./entrypoints').detectEntrypoints(index) || [];
193
+ const isEntry = eps.some(e => e.name === fn.name && (e.file === filePath || e.relativePath === filePath));
200
194
  item.orphan = !isEntry;
201
195
  }
202
196
 
@@ -229,17 +223,15 @@ function check(index, options = {}) {
229
223
  let testFiles = [];
230
224
  let testCount = 0;
231
225
  for (const fn of changed.slice(0, 10)) {
232
- try {
233
- const t = index.affectedTests(fn.name, { depth: 2 });
234
- if (t && t.testFiles) {
235
- for (const tf of t.testFiles) {
236
- if (!testFiles.find(x => x.file === tf.file)) {
237
- testFiles.push(tf);
238
- testCount += tf.testCount || 0;
239
- }
226
+ const t = index.affectedTests(fn.name, { depth: 2 });
227
+ if (t && t.testFiles) {
228
+ for (const tf of t.testFiles) {
229
+ if (!testFiles.find(x => x.file === tf.file)) {
230
+ testFiles.push(tf);
231
+ testCount += tf.testCount || 0;
240
232
  }
241
233
  }
242
- } catch (e) { /* skip */ }
234
+ }
243
235
  }
244
236
 
245
237
  // Action items