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
@@ -69,11 +69,11 @@ const COMMAND_CONTRACTS = Object.freeze({
69
69
  modes: [
70
70
  { name: 'inventory', when: 'Always.', answer: 'Occurrence records classified by usage kind.' },
71
71
  ],
72
- defaults: ['Tests excluded unless `includeTests=true`.', 'Comments/strings included unless `codeOnly=true`.'],
72
+ defaults: ['Test files included; `excludeTests=true` hides them and reports how many.', 'Comments/strings included unless `codeOnly=true`.'],
73
73
  truth: 'The command reports the indexed literal-name occurrence universe, not exact semantic references to one definition. Classification is by syntax alone; show/impact ACCOUNT lines are engine-adjudicated, so the two breakdowns can legitimately differ (a method reference is a `reference` here but may be a confirmed caller there).',
74
74
  nonGoals: ['Alias-only references whose source line does not contain the queried name.', 'Safe-delete proof.'],
75
75
  invalidCombinations: ['A missing name is rejected.'],
76
- examples: ['ucn usages parseRequest --include-tests', 'ucn usages parseRequest --code-only --file=src'],
76
+ examples: ['ucn usages parseRequest --exclude-tests', 'ucn usages parseRequest --code-only --file=src'],
77
77
  jsonData: 'Definition/reference records plus separately classified text occurrences, each with file, line, and content.',
78
78
  output: 'Broad output; narrow with `file`, `in`, `exclude`, or `limit`.',
79
79
  next: ['Use `find` plus `impact` when target identity matters.', 'Use `search` for arbitrary text.'],
@@ -182,17 +182,17 @@ const COMMAND_CONTRACTS = Object.freeze({
182
182
  purpose: 'Validate a symbol signature against call sites or compose checks over a Git diff.',
183
183
  target: 'Optional symbol/handle. Omitting it selects diff/precommit mode.',
184
184
  modes: [
185
- { name: 'symbol', when: 'A symbol target is supplied.', answer: 'Argument-count compatibility, uncertain sites, and the caller account.' },
185
+ { name: 'symbol', when: 'A symbol target is supplied; `base` names the revision whose declaration its call sites were written against.', answer: 'Argument-count compatibility, uncertain sites, and the caller account.' },
186
186
  { name: 'diff', when: 'No target is supplied; `base` or `staged` selects changes.', answer: 'Composed diff impact, signature checks, and affected tests.' },
187
187
  ],
188
- defaults: ['Symbol mode checks static arity, not compiler type compatibility.'],
188
+ defaults: ['Symbol mode checks static arity, not compiler type compatibility.', '`base` defaults to HEAD in both modes.'],
189
189
  truth: 'Findings are static diagnostics with explicit uncertainty; a clean result is not a compiler/test pass.',
190
190
  nonGoals: ['Full type checking.', 'Linting or executing project tests.'],
191
191
  invalidCombinations: [
192
- 'A named symbol cannot also select staged/diff scope.',
192
+ 'A named symbol cannot take `staged`.',
193
193
  '`base` and `staged` cannot both select the diff.',
194
194
  ],
195
- examples: ['ucn check publishOrderCreated', 'ucn check --staged'],
195
+ examples: ['ucn check publishOrderCreated', 'ucn check publishOrderCreated --base=main', 'ucn check --staged'],
196
196
  jsonData: 'Symbol mode returns signature, valid/mismatched/uncertain sites and accounting; diff mode returns composed diagnostics.',
197
197
  output: 'Broad diagnostic; scope to a symbol or focused Git diff.',
198
198
  next: ['Run the language compiler/type checker and selected tests.', 'Use `plan` before a signature refactor.'],
@@ -0,0 +1,86 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Configuration items of dynamically configured scopes (fix #398F).
5
+ *
6
+ * A Python name bound in one scope only in mutually exclusive branches
7
+ * (`if sys.platform == "win32": def getchar` / `else: def getchar`, `try:
8
+ * from ._speedups import f` / `except ImportError: def f`) is one item with
9
+ * an alternative per configuration. The parser records each item
10
+ * (`fileEntry.configurationItems`): its sites (def, class, import or value),
11
+ * each site's branch path, and the line range of every clause on those paths.
12
+ *
13
+ * Reachability of an alternative from a line: code inside another exclusive
14
+ * clause of a statement on the site's branch path runs only in a
15
+ * configuration without that site. Code anywhere else may run in either.
16
+ */
17
+
18
+ const { branchClausesExclusive } = require('../languages/utils');
19
+
20
+ const NO_ITEMS = Object.freeze([]);
21
+
22
+ function configurationItemsOf(index, file) {
23
+ return index.files.get(file)?.configurationItems || NO_ITEMS;
24
+ }
25
+
26
+ const DEFINITION_KINDS = new Set(['def', 'class']);
27
+
28
+ /** The item a def/class definition is an alternative of, with its site. */
29
+ function itemOfDefinition(index, definition) {
30
+ if (!definition?.file || definition.startLine == null) return null;
31
+ for (const item of configurationItemsOf(index, definition.file)) {
32
+ if (item.name !== definition.name) continue;
33
+ const site = item.sites.find(s => DEFINITION_KINDS.has(s.kind) && s.line === definition.startLine);
34
+ if (site) return { item, site };
35
+ }
36
+ return null;
37
+ }
38
+
39
+ /** Two definitions are alternatives of one configuration item. */
40
+ function sameConfigurationItem(index, a, b) {
41
+ if (!a || !b || a === b || a.file !== b.file || a.name !== b.name) return false;
42
+ const found = itemOfDefinition(index, a);
43
+ return !!found && found.item.sites.some(s => DEFINITION_KINDS.has(s.kind) && s.line === b.startLine &&
44
+ s !== found.site);
45
+ }
46
+
47
+ /** The module-scope item of `name` in `file`, if any. */
48
+ function moduleItemNamed(index, file, name) {
49
+ return configurationItemsOf(index, file).find(item => item.scope === 0 && item.name === name) || null;
50
+ }
51
+
52
+ /** Items of `name` in `file` (any scope). */
53
+ function itemsNamed(index, file, name) {
54
+ return configurationItemsOf(index, file).filter(item => item.name === name);
55
+ }
56
+
57
+ /**
58
+ * Code at `line` never reaches `site`: the line lies inside another
59
+ * exclusive clause of a statement on the site's branch path.
60
+ */
61
+ function siteExcludedAt(item, site, line) {
62
+ if (!Number.isInteger(line)) return false;
63
+ for (const [statement, tag] of site.branch) {
64
+ const clauses = item.clauses.find(([at]) => at === statement)?.[1];
65
+ if (!clauses) continue;
66
+ const holder = clauses.find(([, start, end]) => start <= line && line <= end);
67
+ if (holder && holder[0] !== tag && branchClausesExclusive(holder[0], tag)) return true;
68
+ }
69
+ return false;
70
+ }
71
+
72
+ /** The sites of `item` code at `line` may reach. */
73
+ function sitesReachableAt(item, line) {
74
+ return item.sites.filter(site => !siteExcludedAt(item, site, line));
75
+ }
76
+
77
+ module.exports = {
78
+ DEFINITION_KINDS,
79
+ configurationItemsOf,
80
+ itemOfDefinition,
81
+ sameConfigurationItem,
82
+ moduleItemNamed,
83
+ itemsNamed,
84
+ siteExcludedAt,
85
+ sitesReachableAt,
86
+ };