ucn 5.4.2 → 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 (85) 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 +40 -14
  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.js +18 -2
  38. package/core/output/brief.js +3 -0
  39. package/core/output/doctor.js +4 -0
  40. package/core/output/endpoints.js +15 -6
  41. package/core/output/find.js +7 -2
  42. package/core/output/refactoring.js +121 -14
  43. package/core/output/reporting.js +31 -3
  44. package/core/output/shared.js +14 -0
  45. package/core/output-budget.js +305 -122
  46. package/core/parallel-build.js +124 -47
  47. package/core/parser.js +3 -2
  48. package/core/project.js +457 -60
  49. package/core/provenance-facts.js +156 -12
  50. package/core/provenance-overload.js +30 -3
  51. package/core/provenance.js +104 -30
  52. package/core/pytest-fixtures.js +434 -0
  53. package/core/python-fixture-flow.js +17 -3
  54. package/core/python-modules.js +173 -0
  55. package/core/reflection.js +877 -0
  56. package/core/registry.js +1 -1
  57. package/core/reporting.js +234 -52
  58. package/core/request-helpers.js +561 -0
  59. package/core/route-graph.js +1922 -0
  60. package/core/route-lists.js +2414 -0
  61. package/core/rust-macro-expansion.js +2113 -0
  62. package/core/rust-modules.js +185 -0
  63. package/core/search.js +121 -29
  64. package/core/shared.js +19 -1
  65. package/core/test-name-bindings.js +256 -0
  66. package/core/type-denotation.js +1161 -0
  67. package/core/type-references.js +3229 -0
  68. package/core/verify.js +3360 -672
  69. package/languages/adapter.js +31 -5
  70. package/languages/c-family.js +4061 -212
  71. package/languages/c-macro-invocations.js +380 -0
  72. package/languages/c-preprocessor.js +254 -0
  73. package/languages/csharp.js +1406 -49
  74. package/languages/go.js +1243 -70
  75. package/languages/index.js +728 -6
  76. package/languages/java.js +473 -61
  77. package/languages/javascript.js +1270 -197
  78. package/languages/lexical-scope.js +1280 -0
  79. package/languages/python.js +1557 -72
  80. package/languages/rust-macro-rules.js +1020 -0
  81. package/languages/rust-value-flow.js +416 -0
  82. package/languages/rust.js +2237 -115
  83. package/languages/utils.js +298 -4
  84. package/mcp/server.js +22 -8
  85. package/package.json +1 -1
package/core/ir.js CHANGED
@@ -8,6 +8,8 @@
8
8
  * this boundary. The shape is deliberately data-only and versioned.
9
9
  */
10
10
 
11
+ const { openCallShape } = require('../languages/rust-value-flow');
12
+
11
13
  const IR_SCHEMA_VERSION = 1;
12
14
  const EVIDENCE_TIERS = Object.freeze(['confirmed', 'unverified', 'excluded']);
13
15
 
@@ -62,20 +64,25 @@ function normalizeSymbol(symbol, family, language, kind, owner = null) {
62
64
  const passthrough = [
63
65
  'docstring', 'returnedFunctionResult', 'isFunctionVariable', 'paramTypes',
64
66
  'isAsync', 'isGenerator', 'generics', 'ownerGenerics', 'genericBounds', 'extends', 'implements', 'indent',
65
- 'isNested', 'enclosingType', 'isMethod', 'memberType', 'fieldType',
66
- 'aliasOf', 'aliasMembers', 'aliasTypeText', 'aliasTypeParameters', 'aliasTypeDefaults', 'derefTarget', 'decorators', 'decoratorsWithArgs',
67
+ 'isNested', 'enclosingType', 'isMethod', 'memberType', 'fieldType', 'embedded',
68
+ 'aliasOf', 'aliasQualifier', 'aliasMembers', 'aliasTypeText', 'aliasTypeParameters', 'aliasTypeDefaults', 'derefTarget', 'decorators', 'decoratorsWithArgs',
67
69
  'annotationsWithArgs', 'attributesWithArgs', 'nameLine', 'traitImpl',
68
- 'traitName', 'isSignature', 'memberAssigned', 'assignedReceiver', 'bodyScopedName',
69
- 'registryMember', 'registryContainer', 'isConstructor',
70
- 'isExtensionMethod', 'extensionReceiver', 'explicitInterface',
70
+ 'traitName', 'isSignature', 'memberAssigned', 'assignedReceiver', 'assignedObject', 'selfNamed', 'bodyScopedName',
71
+ 'registryMember', 'registryContainer', 'registryContainerType', 'objectLiteralLine', 'isConstructor',
72
+ 'isExtensionMethod', 'extensionReceiver', 'explicitInterface', 'primaryParams',
71
73
  'namespace', 'lexicalScopeStartLine', 'lexicalScopeEndLine',
72
- 'returnTypeQualifier', 'macroNeverReturns', 'callbackParamTypes', 'iteratorItemType',
74
+ 'returnTypeQualifier', 'returnTypeResolved', 'supertraits', 'ownerGenericBounds', 'ownerSelfArgs', 'implSelfRef', 'implSelfQualifier', 'blanketSelfBounds', 'selfParamKind', 'macroNeverReturns', 'callbackParamTypes', 'iteratorItemType', 'futureReturn',
73
75
  'returnedConcreteType', 'returnedConstructors', 'templateDependent',
74
76
  'returnedCallStart', 'returnedCallEnd',
75
- 'returnedReceiverPath',
77
+ 'returnedReceiverPath', 'valueType', 'valueDerefVia',
76
78
  'isSpecialization',
77
79
  'linkage', 'functionLike', 'callableAlias', 'exportedAlias',
78
80
  'aliasOwner', 'aliasMember', 'callableTarget', 'macroParamEffects',
81
+ 'namespaceScope', 'ppParams', 'ppVariadic', 'ppBody', 'ppConditional', 'languageBranch', 'macroScope', 'accessAfterMacro', 'ppBranch',
82
+ 'generatedByMacro',
83
+ 'typeArity', 'ownerTypeArity',
84
+ 'annotationType', 'valueShape', 'friendOf', 'templateParams', 'delegateParams',
85
+ 'typedefName',
79
86
  ];
80
87
  for (const field of passthrough) {
81
88
  if (symbol[field] !== undefined && symbol[field] !== null) {
@@ -101,8 +108,11 @@ function createFileIR({
101
108
  const normalizedSymbols = [];
102
109
  const seen = new Set();
103
110
  const append = (symbol, family, kind, owner = null) => {
111
+ // Members one macro invocation declares share its lines (fix #385):
112
+ // their own binding ids keep overloads apart.
104
113
  const key = `${owner || symbol.className || ''}\0${symbol.name}\0${kind}\0` +
105
- `${symbol.startLine}\0${symbol.endLine}`;
114
+ `${symbol.startLine}\0${symbol.endLine}` +
115
+ (symbol.generatedByMacro ? `\0${symbol.bindingId || ''}` : '');
106
116
  if (seen.has(key)) return;
107
117
  seen.add(key);
108
118
  normalizedSymbols.push(normalizeSymbol(symbol, family, language, kind, owner));
@@ -223,8 +233,77 @@ function createFileIR({
223
233
  dynamicImports: imports.filter(item => item.dynamic).length,
224
234
  importAliases: parsed.imports?.aliases || null,
225
235
  moduleAssignedNames: [...(parsed.moduleAssignedNames || [])],
236
+ ...(parsed.asyncClosureNames?.length > 0 && {
237
+ asyncClosureNames: [...parsed.asyncClosureNames],
238
+ }),
239
+ // Shapes of calls whose value is not consumed where it is produced
240
+ // (fix #371/#372): audit-async reads a file's call records only when
241
+ // one of these can reach a future producer.
242
+ ...(require('../languages').langTraits(language)?.callValueFacts && {
243
+ openCalls: [...new Set(calls.filter(call => call?.name && !call.inMacro &&
244
+ !call.valueConsumed).map(openCallShape))].sort(),
245
+ }),
246
+ ...(parsed.typeConversions?.length > 0 && {
247
+ typeConversions: parsed.typeConversions.map(item => ({ ...item })),
248
+ }),
249
+ ...(parsed.reflectionSites?.length > 0 && {
250
+ reflectionSites: parsed.reflectionSites.map(item => ({ ...item })),
251
+ }),
252
+ ...(parsed.macroScopeMarkers?.length > 0 && {
253
+ macroScopeMarkers: parsed.macroScopeMarkers.map(item => ({ ...item })),
254
+ }),
255
+ ...(parsed.cppUsings?.length > 0 && {
256
+ cppUsings: parsed.cppUsings.map(item => ({ ...item })),
257
+ }),
258
+ ...(parsed.languageFeatures?.length > 0 && {
259
+ languageFeatures: [...parsed.languageFeatures],
260
+ }),
261
+ // C# conditional groups read through configuration views (fix #391).
262
+ ...(Array.isArray(parsed.conditionalViews) && {
263
+ conditionalViews: parsed.conditionalViews.map(group => [...group]),
264
+ }),
265
+ ...(parsed.packageName && { packageName: parsed.packageName }),
266
+ // Go package-level variables with their declared static types (fix #399).
267
+ ...(parsed.buildConstraint && { buildConstraint: parsed.buildConstraint }),
268
+ ...(parsed.packageVars?.length > 0 && {
269
+ packageVars: parsed.packageVars.map(item => ({ ...item, ...(item.origin && { origin: { ...item.origin } }) })),
270
+ }),
271
+ // Module-level names bound once to another name (fix #389): class
272
+ // aliases when the target resolves to a class.
273
+ ...(parsed.moduleValueAliases?.length > 0 && {
274
+ moduleValueAliases: parsed.moduleValueAliases.map(item => ({ ...item })),
275
+ }),
276
+ // Module values built by calling a name that an alias reads an
277
+ // attribute of (fix #398F).
278
+ ...(parsed.moduleConstructedValues?.length > 0 && {
279
+ moduleConstructedValues: parsed.moduleConstructedValues.map(item => ({ ...item })),
280
+ }),
281
+ // Python names bound only in exclusive branches (fix #398F): one
282
+ // item per configuration alternative set.
283
+ ...(parsed.configurationItems?.length > 0 && {
284
+ configurationItems: parsed.configurationItems.map(item => ({
285
+ ...item,
286
+ sites: item.sites.map(site => ({ ...site, branch: site.branch.map(step => [...step]) })),
287
+ clauses: item.clauses.map(([line, ranges]) => [line, ranges.map(range => [...range])]),
288
+ })),
289
+ }),
290
+ // The byte ranges the C/C++ recovery blanked (fix #387): a query
291
+ // rebuilds the recovered tree with one parse.
292
+ ...(Array.isArray(parsed.recoveryBlanks) && {
293
+ recoveryBlanks: parsed.recoveryBlanks.map(range => [...range]),
294
+ }),
295
+ // Names at the C/C++ parse damage (fix #396).
296
+ ...(Array.isArray(parsed.recoveryCandidates) && {
297
+ recoveryCandidates: [...parsed.recoveryCandidates],
298
+ }),
299
+ ...(Array.isArray(parsed.externalMacroNames) && {
300
+ externalMacroNames: [...parsed.externalMacroNames],
301
+ }),
226
302
  diagnostics: {
227
303
  parseRecovery: !!parsed.parseRecovery,
304
+ ...(parsed.parseErrorRegions?.length > 0 && {
305
+ parseErrorRegions: parsed.parseErrorRegions.map(region => [...region]),
306
+ }),
228
307
  },
229
308
  capabilities: { ...capabilities },
230
309
  };