ucn 5.5.1 → 5.5.2

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 (93) hide show
  1. package/.claude/skills/ucn/SKILL.md +35 -9
  2. package/.claude/skills/ucn/references/commands.md +38 -16
  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 +30 -21
  6. package/cli/index.js +1 -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/brief.js +8 -4
  12. package/core/build-worker.js +2 -1
  13. package/core/cache.js +137 -6
  14. package/core/call-name-cache.js +134 -0
  15. package/core/callable-scope.js +21 -0
  16. package/core/callers.js +4726 -940
  17. package/core/check.js +22 -5
  18. package/core/class-identity.js +399 -12
  19. package/core/constructor-calls.js +831 -0
  20. package/core/constructor-hierarchy.js +147 -0
  21. package/core/constructor-protocol.js +196 -0
  22. package/core/contract-membership.js +346 -140
  23. package/core/cpp-conversion-constraints.js +123 -0
  24. package/core/cpp-conversion-syntax.js +216 -0
  25. package/core/cpp-conversions.js +414 -0
  26. package/core/cpp-scope.js +245 -44
  27. package/core/deadcode.js +35 -15
  28. package/core/decorator-binding.js +137 -3
  29. package/core/enum-reference-syntax.js +134 -0
  30. package/core/execute.js +17 -1
  31. package/core/external-macros.js +42 -10
  32. package/core/go-packages.js +171 -0
  33. package/core/graph-build.js +2 -0
  34. package/core/graph.js +75 -59
  35. package/core/ignore-rules.js +2 -1
  36. package/core/imports.js +145 -19
  37. package/core/index-ir.js +41 -4
  38. package/core/ir.js +27 -6
  39. package/core/macro-expansion.js +38 -2
  40. package/core/out-of-class-members.js +182 -0
  41. package/core/output/analysis-ext.js +4 -2
  42. package/core/output/analysis.js +89 -20
  43. package/core/output/graph.js +12 -3
  44. package/core/output/lines.js +4 -3
  45. package/core/output/public.js +1 -0
  46. package/core/output/reporting.js +6 -1
  47. package/core/output/shared.js +2 -0
  48. package/core/output/tracing.js +28 -22
  49. package/core/output-budget.js +2 -2
  50. package/core/parallel-build.js +52 -1
  51. package/core/project.js +217 -112
  52. package/core/provenance-constructor-base.js +161 -0
  53. package/core/provenance-facts.js +257 -27
  54. package/core/provenance-overload.js +458 -54
  55. package/core/provenance-type.js +487 -0
  56. package/core/provenance.js +234 -15
  57. package/core/public-command.js +17 -2
  58. package/core/query-bodies.js +159 -0
  59. package/core/reflection.js +255 -2
  60. package/core/rename-token-syntax.js +111 -0
  61. package/core/reporting.js +13 -7
  62. package/core/rust-macro-expansion.js +151 -19
  63. package/core/rust-modules.js +1 -1
  64. package/core/rust-names.js +607 -0
  65. package/core/search.js +70 -17
  66. package/core/shared.js +98 -1
  67. package/core/source-memo.js +201 -0
  68. package/core/text-usage-syntax.js +38 -0
  69. package/core/tracing.js +7 -1
  70. package/core/type-denotation.js +124 -37
  71. package/core/type-references.js +615 -246
  72. package/core/value-references.js +2777 -0
  73. package/core/verify.js +1097 -281
  74. package/languages/adapter.js +28 -4
  75. package/languages/c-family.js +1118 -164
  76. package/languages/constructor-bases.js +105 -0
  77. package/languages/cpp-platform.js +26 -0
  78. package/languages/cpp-site-syntax.js +83 -0
  79. package/languages/csharp-scope.js +439 -0
  80. package/languages/csharp.js +428 -68
  81. package/languages/go.js +385 -207
  82. package/languages/html.js +4 -2
  83. package/languages/index.js +397 -2
  84. package/languages/java-platform.js +226 -0
  85. package/languages/java-unicode.js +269 -0
  86. package/languages/java.js +461 -117
  87. package/languages/javascript.js +418 -66
  88. package/languages/lexical-scope.js +190 -23
  89. package/languages/python.js +404 -54
  90. package/languages/rust.js +510 -82
  91. package/languages/utils.js +67 -8
  92. package/mcp/server.js +8 -2
  93. package/package.json +2 -2
@@ -39,18 +39,31 @@ function renderFrontier(lines, frontier, options = {}, expanded = false) {
39
39
  return true;
40
40
  }
41
41
 
42
- /** Render a node's unresolved callee calls as [unverified] leaves. */
43
- function renderUnverifiedCallees(lines, node, prefix, isParentLast) {
44
- if (!node.unverifiedCallees || node.unverifiedCallees.length === 0) return;
45
- const extension = isParentLast ? ' ' : '│ ';
46
- for (let i = 0; i < node.unverifiedCallees.length; i++) {
47
- const u = node.unverifiedCallees[i];
48
- const isLast = i === node.unverifiedCallees.length - 1;
49
- const connector = isLast ? '└── ' : '├── ';
42
+ /**
43
+ * A node's unresolved callee calls as [unverified] leaves, then the
44
+ * constructions whose constructor body is undecided (fix #421; their class
45
+ * edge is a child of the node).
46
+ */
47
+ function undecidedLeafLines(node) {
48
+ const out = [];
49
+ for (const u of node.unverifiedCallees || []) {
50
50
  const owners = u.ownerCount > 1 ? ` (${u.ownerCount} owners)` : '';
51
51
  const linesPart = u.sites && u.sites.length > 0 ? ` L${u.sites.join(',L')}` : '';
52
- lines.push(`${prefix}${extension}${connector}[unverified] ${u.name} — ${u.reason}${owners}${linesPart}`);
52
+ out.push(`[unverified] ${u.name} — ${u.reason}${owners}${linesPart}`);
53
+ }
54
+ for (const r of node.initializerReviews || []) {
55
+ const candidates = r.candidates > 1 ? ` (${r.candidates} candidates)` : '';
56
+ const linesPart = r.sites && r.sites.length > 0 ? ` L${r.sites.join(',L')}` : '';
57
+ const label = r.name === r.initializerOf ? r.name : `${r.initializerOf}.${r.name}`;
58
+ out.push(`[constructor undecided] ${label} — ${r.reason}${candidates}${linesPart}`);
53
59
  }
60
+ return out;
61
+ }
62
+
63
+ function renderUnverifiedCallees(lines, node, prefix, isParentLast) {
64
+ const leaves = undecidedLeafLines(node);
65
+ const extension = isParentLast ? ' ' : '│ ';
66
+ leaves.forEach((text, i) => lines.push(`${prefix}${extension}${i === leaves.length - 1 ? '└── ' : '├── '}${text}`));
54
67
  }
55
68
 
56
69
  /** TREE ACCOUNT line for caller-direction trees. */
@@ -129,6 +142,7 @@ function formatTrace(trace, options = {}) {
129
142
  } else if (node.file) {
130
143
  label += ` (${node.file}:${node.line})`;
131
144
  }
145
+ if (node.constructs) label += ` (constructs ${node.constructs})`;
132
146
  if (node.weight && node.weight !== 'normal') {
133
147
  label += ` [${node.weight}]`;
134
148
  }
@@ -143,7 +157,7 @@ function formatTrace(trace, options = {}) {
143
157
 
144
158
  if (node.children && !node.alreadyShown) {
145
159
  const hasMore = node.truncatedChildren > 0;
146
- const hasUnverified = node.unverifiedCallees && node.unverifiedCallees.length > 0;
160
+ const hasUnverified = node.unverifiedCallees?.length > 0 || node.initializerReviews?.length > 0;
147
161
  for (let i = 0; i < node.children.length; i++) {
148
162
  const isChildLast = !hasMore && !hasUnverified && i === node.children.length - 1;
149
163
  renderNode(node.children[i], prefix + extension, isChildLast);
@@ -160,7 +174,8 @@ function formatTrace(trace, options = {}) {
160
174
  lines.push(trace.root);
161
175
  if (trace.tree && trace.tree.children) {
162
176
  const rootHasMore = trace.tree.truncatedChildren > 0;
163
- const rootHasUnverified = trace.tree.unverifiedCallees && trace.tree.unverifiedCallees.length > 0;
177
+ const rootLeaves = undecidedLeafLines(trace.tree);
178
+ const rootHasUnverified = rootLeaves.length > 0;
164
179
  for (let i = 0; i < trace.tree.children.length; i++) {
165
180
  const isLast = !rootHasMore && !rootHasUnverified && i === trace.tree.children.length - 1;
166
181
  renderNode(trace.tree.children[i], '', isLast);
@@ -169,17 +184,8 @@ function formatTrace(trace, options = {}) {
169
184
  hasTruncation = true;
170
185
  lines.push((rootHasUnverified ? '├── ' : '└── ') + `... and ${trace.tree.truncatedChildren} more callees`);
171
186
  }
172
- if (rootHasUnverified) {
173
- // Root-level unverified callees: render with no prefix
174
- for (let i = 0; i < trace.tree.unverifiedCallees.length; i++) {
175
- const u = trace.tree.unverifiedCallees[i];
176
- const isLast = i === trace.tree.unverifiedCallees.length - 1;
177
- const connector = isLast ? '└── ' : '├── ';
178
- const owners = u.ownerCount > 1 ? ` (${u.ownerCount} owners)` : '';
179
- const linesPart = u.sites && u.sites.length > 0 ? ` L${u.sites.join(',L')}` : '';
180
- lines.push(`${connector}[unverified] ${u.name} — ${u.reason}${owners}${linesPart}`);
181
- }
182
- }
187
+ // Root-level unverified callees: render with no prefix
188
+ rootLeaves.forEach((text, i) => lines.push(`${i === rootLeaves.length - 1 ? '└── ' : '├── '}${text}`));
183
189
  }
184
190
 
185
191
  // Callers section
@@ -15,10 +15,10 @@ const BROAD_COMMANDS = new Set([
15
15
  ...[...BROAD_CANONICAL].map(toMcpName),
16
16
  ]);
17
17
 
18
- const CONTRACT_LINE_RE = /^\s*(?:(?:Summary|ACCOUNT|CONTRACT|WARNING|FILTERED|CALLEE ACCOUNT|TREE ACCOUNT|Note):|\d+ test-file usage\(s\) hidden\b|Found \d+ (?:definitions|fuzzy matches)\b)/;
18
+ const CONTRACT_LINE_RE = /^\s*(?:(?:Summary|ACCOUNT|CONTRACT|WARNING|FILTERED|CALLEE ACCOUNT|TREE ACCOUNT|VALUE ACCOUNT|TYPE ACCOUNT|Note):|\d+ test-file usage\(s\) hidden\b|Found \d+ (?:definitions|fuzzy matches)\b)/;
19
19
  // Trust lines: the accounting and contract lines that qualify a caller
20
20
  // answer. A truncated answer carries every one of them or none of its body.
21
- const TRUST_LINE_RE = /^(?:ACCOUNT|CONTRACT|WARNING|FILTERED|CALLEE ACCOUNT|TREE ACCOUNT):/;
21
+ const TRUST_LINE_RE = /^(?:ACCOUNT|CONTRACT|WARNING|FILTERED|CALLEE ACCOUNT|TREE ACCOUNT|VALUE ACCOUNT|TYPE ACCOUNT):/;
22
22
  const MAX_PRESERVED_CONTRACT_LINES = 24;
23
23
  const MAX_PRESERVED_CONTRACT_CHARS = 8000;
24
24
 
@@ -275,4 +275,55 @@ function parallelBuild(index, files, options = {}) {
275
275
  return changed;
276
276
  }
277
277
 
278
- module.exports = { parallelBuild, scheduleFiles };
278
+ /**
279
+ * Worker threads for a sequential build's Rust macro expansion (fix #422): a
280
+ * pool shaped like the one a parallel build keeps (`options.onParsed`), whose
281
+ * workers have no file to parse and wait for their expansion job. A crate
282
+ * whose API macros generate most of its code has little source to parse and
283
+ * much expansion work.
284
+ */
285
+ function spawnExpansionPool(index, count) {
286
+ if (!(count >= 1)) return null;
287
+ const sab = new SharedArrayBuffer(4 * (count + 1));
288
+ const control = new SharedArrayBuffer(4 * count);
289
+ const controlArray = new Int32Array(control);
290
+ const ports = [];
291
+ const workers = [];
292
+ for (let i = 0; i < count; i++) {
293
+ const { port1, port2 } = new MessageChannel();
294
+ ports.push(port1);
295
+ const worker = new Worker(path.join(__dirname, 'build-worker.js'), {
296
+ workerData: {
297
+ files: [], rootDir: index.root, existingHashes: {}, signal: sab, workerIndex: i,
298
+ queueIndex: count, port: port2, control, macroDictionary: null, dictionarySignal: null,
299
+ },
300
+ transferList: [port2],
301
+ resourceLimits: { maxYoungGenerationSizeMb: WORKER_YOUNG_GENERATION_MB },
302
+ });
303
+ worker.unref();
304
+ workers.push(worker);
305
+ }
306
+ const live = new Set(workers.map((_, i) => i));
307
+ const retire = i => {
308
+ if (!live.delete(i)) return;
309
+ Atomics.store(controlArray, i, 1);
310
+ Atomics.notify(controlArray, i);
311
+ ports[i].close();
312
+ workers[i].terminate();
313
+ };
314
+ return {
315
+ available: [...live],
316
+ ports,
317
+ post(i, job) {
318
+ ports[i].postMessage(job);
319
+ Atomics.store(controlArray, i, 2);
320
+ Atomics.notify(controlArray, i);
321
+ },
322
+ retire,
323
+ dispose() {
324
+ for (const i of [...live]) retire(i);
325
+ },
326
+ };
327
+ }
328
+
329
+ module.exports = { parallelBuild, scheduleFiles, spawnExpansionPool };