ucn 5.5.3 → 5.6.1

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 (77) hide show
  1. package/.claude/skills/ucn/SKILL.md +37 -12
  2. package/.claude/skills/ucn/references/commands.md +18 -14
  3. package/.claude/skills/ucn/references/resolution-rules.md +4 -0
  4. package/.claude/skills/ucn/references/trust-contract.md +4 -4
  5. package/CHANGELOG.md +485 -0
  6. package/README.md +66 -29
  7. package/cli/flags.js +184 -0
  8. package/cli/index.js +137 -324
  9. package/core/account.js +44 -87
  10. package/core/analysis.js +274 -108
  11. package/core/ast-analysis.js +2 -0
  12. package/core/bridge.js +14 -0
  13. package/core/cache.js +103 -16
  14. package/core/call-fit.js +130 -0
  15. package/core/callers.js +353 -71
  16. package/core/capture.js +363 -0
  17. package/core/change-kinds.js +1107 -0
  18. package/core/check.js +1150 -139
  19. package/core/command-contracts.js +8 -7
  20. package/core/constructed-class.js +1195 -0
  21. package/core/contract-membership.js +142 -0
  22. package/core/deadcode.js +455 -106
  23. package/core/deletion.js +421 -0
  24. package/core/discovery.js +104 -9
  25. package/core/entrypoint-toml.js +110 -0
  26. package/core/entrypoints.js +12 -6
  27. package/core/evidence-bands.js +68 -0
  28. package/core/evidence-bands.json +44 -0
  29. package/core/execute.js +172 -161
  30. package/core/hot-summary.js +241 -0
  31. package/core/index-ir.js +5 -3
  32. package/core/ir.js +6 -2
  33. package/core/member-signatures.js +789 -0
  34. package/core/outgoing-check.js +116 -0
  35. package/core/output/analysis-ext.js +20 -10
  36. package/core/output/analysis.js +98 -60
  37. package/core/output/check.js +101 -37
  38. package/core/output/doctor.js +34 -1
  39. package/core/output/find.js +2 -1
  40. package/core/output/lines.js +63 -3
  41. package/core/output/public.js +29 -11
  42. package/core/output/refactoring.js +32 -0
  43. package/core/output/reporting.js +19 -2
  44. package/core/output/search.js +14 -2
  45. package/core/output/tracing.js +36 -8
  46. package/core/output-budget.js +146 -61
  47. package/core/parallel-build.js +3 -3
  48. package/core/project.js +106 -23
  49. package/core/provenance-type.js +12 -5
  50. package/core/public-command.js +35 -9
  51. package/core/python-binding-identity.js +707 -0
  52. package/core/python-modules.js +6 -0
  53. package/core/reflection.js +248 -31
  54. package/core/registry.js +623 -72
  55. package/core/reporting.js +69 -34
  56. package/core/review-items.js +75 -0
  57. package/core/runtime-entrypoints.js +159 -0
  58. package/core/search.js +148 -164
  59. package/core/shared.js +0 -45
  60. package/core/snapshot.js +350 -0
  61. package/core/source-universe.js +707 -0
  62. package/core/test-units.js +3698 -0
  63. package/core/tracing.js +270 -658
  64. package/core/verify.js +63 -22
  65. package/languages/adapter.js +8 -3
  66. package/languages/c-family.js +12 -0
  67. package/languages/csharp.js +634 -0
  68. package/languages/go.js +120 -0
  69. package/languages/index.js +466 -4
  70. package/languages/java.js +712 -0
  71. package/languages/javascript.js +1498 -6
  72. package/languages/lexical-scope.js +68 -0
  73. package/languages/python.js +1708 -3
  74. package/languages/rust.js +209 -104
  75. package/languages/static-js.js +88 -0
  76. package/mcp/server.js +44 -110
  77. package/package.json +11 -5
@@ -1443,5 +1443,73 @@ function pythonClassBodyOrder(classNode, node, name) {
1443
1443
  return before === 0 ? 'outer' : 'class';
1444
1444
  }
1445
1445
 
1446
+ /**
1447
+ * The import statement that binds `name` for a reference at `node`, when
1448
+ * the nearest function scope binding the name binds it by that one
1449
+ * statement alone (`def f(): from m import Name`). Null when the name is
1450
+ * bound at module scope, by anything else, more than once, or the scope
1451
+ * declares it `global` / `nonlocal` or star-imports.
1452
+ */
1453
+ function localImportStatement(node, language, name = node?.text) {
1454
+ if (familyOf(language) !== 'python' || !node?.parent) return null;
1455
+ let child = node;
1456
+ let crossedFunction = false;
1457
+ try {
1458
+ for (let scope = node.parent; scope; child = scope, scope = scope.parent) {
1459
+ switch (scope.type) {
1460
+ case 'function_definition': {
1461
+ const body = scope.childForFieldName('body');
1462
+ if (!sameNode(body, child)) continue;
1463
+ const sites = [];
1464
+ const info = pyScopeBindings(scope, body, name, true, true,
1465
+ (site, kind) => sites.push({ site, kind }));
1466
+ if (info.starImport || info.global || info.nonlocal) return null;
1467
+ if (sites.length === 0) { crossedFunction = true; continue; }
1468
+ if (sites.length !== 1 || sites[0].kind !== 'import') return null;
1469
+ let statement = sites[0].site;
1470
+ while (statement && statement.type !== 'import_statement' &&
1471
+ statement.type !== 'import_from_statement') statement = statement.parent;
1472
+ return statement || null;
1473
+ }
1474
+ case 'lambda': {
1475
+ if (!sameNode(scope.childForFieldName('body'), child)) continue;
1476
+ const names = [];
1477
+ pyParameterNames(scope.childForFieldName('parameters'), names);
1478
+ if (names.some(n => n.text === name)) return null;
1479
+ crossedFunction = true;
1480
+ continue;
1481
+ }
1482
+ case 'class_definition': {
1483
+ const body = scope.childForFieldName('body');
1484
+ if (!sameNode(body, child) || crossedFunction) continue;
1485
+ const info = pyScopeBindings(scope, body, name, false, true);
1486
+ if (info.bound || info.starImport) return null;
1487
+ continue;
1488
+ }
1489
+ case 'list_comprehension': case 'set_comprehension':
1490
+ case 'dictionary_comprehension': case 'generator_expression': {
1491
+ const clauses = namedChildrenOf(scope).filter(c => c.type === 'for_in_clause');
1492
+ if (within(node, clauses[0]?.childForFieldName('right'))) continue;
1493
+ for (const clause of clauses) {
1494
+ const names = [];
1495
+ pyTargetNames(clause.childForFieldName('left'), names);
1496
+ if (names.some(n => n.text === name)) return null;
1497
+ }
1498
+ crossedFunction = true;
1499
+ continue;
1500
+ }
1501
+ case 'module':
1502
+ return null;
1503
+ default:
1504
+ continue;
1505
+ }
1506
+ }
1507
+ } catch {
1508
+ return null;
1509
+ }
1510
+ return null;
1511
+ }
1512
+
1446
1513
  module.exports = { referenceScope, referenceScopeNode, scopeFields, familyOf, rustLetBindingOf, rustSelfFieldBinding,
1514
+ localImportStatement,
1447
1515
  pythonBindingSites, pythonClassBodyOrder, pythonScopeBindingKinds, goExpressionTypeArgument, jsPatternTarget };