ucn 5.5.3 → 5.6.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 (71) hide show
  1. package/.claude/skills/ucn/SKILL.md +35 -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 +474 -0
  6. package/README.md +69 -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 +273 -107
  11. package/core/ast-analysis.js +2 -0
  12. package/core/bridge.js +14 -0
  13. package/core/cache.js +101 -16
  14. package/core/callers.js +352 -70
  15. package/core/capture.js +331 -0
  16. package/core/change-kinds.js +888 -0
  17. package/core/check.js +1117 -139
  18. package/core/command-contracts.js +7 -6
  19. package/core/constructed-class.js +1195 -0
  20. package/core/contract-membership.js +142 -0
  21. package/core/deadcode.js +362 -84
  22. package/core/deletion.js +401 -0
  23. package/core/discovery.js +104 -9
  24. package/core/entrypoints.js +12 -6
  25. package/core/evidence-bands.js +68 -0
  26. package/core/evidence-bands.json +44 -0
  27. package/core/execute.js +172 -161
  28. package/core/hot-summary.js +241 -0
  29. package/core/index-ir.js +3 -1
  30. package/core/ir.js +5 -1
  31. package/core/member-signatures.js +789 -0
  32. package/core/output/analysis-ext.js +20 -10
  33. package/core/output/analysis.js +98 -60
  34. package/core/output/check.js +98 -37
  35. package/core/output/doctor.js +34 -1
  36. package/core/output/find.js +2 -1
  37. package/core/output/lines.js +63 -3
  38. package/core/output/public.js +29 -11
  39. package/core/output/refactoring.js +32 -0
  40. package/core/output/reporting.js +15 -2
  41. package/core/output/search.js +11 -2
  42. package/core/output/tracing.js +35 -7
  43. package/core/output-budget.js +124 -57
  44. package/core/parallel-build.js +3 -3
  45. package/core/project.js +106 -23
  46. package/core/provenance-type.js +12 -5
  47. package/core/public-command.js +35 -9
  48. package/core/python-modules.js +6 -0
  49. package/core/reflection.js +151 -23
  50. package/core/registry.js +623 -72
  51. package/core/reporting.js +69 -34
  52. package/core/review-items.js +75 -0
  53. package/core/search.js +89 -128
  54. package/core/shared.js +0 -45
  55. package/core/snapshot.js +350 -0
  56. package/core/source-universe.js +707 -0
  57. package/core/test-units.js +3624 -0
  58. package/core/tracing.js +150 -96
  59. package/core/verify.js +27 -11
  60. package/languages/adapter.js +8 -3
  61. package/languages/c-family.js +12 -0
  62. package/languages/csharp.js +634 -0
  63. package/languages/go.js +120 -0
  64. package/languages/index.js +422 -4
  65. package/languages/java.js +712 -0
  66. package/languages/javascript.js +1460 -2
  67. package/languages/lexical-scope.js +68 -0
  68. package/languages/python.js +1672 -1
  69. package/languages/rust.js +91 -0
  70. package/mcp/server.js +44 -110
  71. package/package.json +10 -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 };