dsh-ptc-plus 0.3.2 → 0.4.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 (206) hide show
  1. package/README.en.md +63 -80
  2. package/README.md +63 -80
  3. package/assets/ptc-plus-bindings-en.png +0 -0
  4. package/assets/ptc-plus-bindings-zh.png +0 -0
  5. package/assets/ptc-plus-repair-en.png +0 -0
  6. package/assets/ptc-plus-repair-zh.png +0 -0
  7. package/assets/ptc-plus-repl-workspace-en.png +0 -0
  8. package/assets/ptc-plus-repl-workspace-zh.png +0 -0
  9. package/assets/ptc-plus-settings-en.png +0 -0
  10. package/assets/ptc-plus-settings-zh.png +0 -0
  11. package/client.js +30827 -742
  12. package/compiler-amaro.cjs +5 -0
  13. package/compiler-amaro.cjs.map +6 -0
  14. package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
  15. package/compiler-assets.json +3 -0
  16. package/compiler-core.cjs +556 -0
  17. package/compiler-core.cjs.map +6 -0
  18. package/compiler-platform.cjs +2 -0
  19. package/compiler-platform.cjs.map +6 -0
  20. package/compiler-typescript.cjs +388 -0
  21. package/compiler-typescript.cjs.map +6 -0
  22. package/docs/README.md +7 -0
  23. package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
  24. package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
  25. package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
  26. package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
  27. package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
  28. package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
  29. package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
  30. package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
  31. package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
  32. package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
  33. package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
  34. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
  35. package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
  36. package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
  37. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
  38. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
  39. package/docs/adr/0023-global-user-bindings.md +104 -0
  40. package/docs/adr/0024-repl-console-observation.md +33 -0
  41. package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
  42. package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
  43. package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
  44. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
  45. package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
  46. package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
  47. package/docs/architecture.md +77 -21
  48. package/docs/binding-review-placement-design.md +200 -0
  49. package/docs/capability-projection.md +1 -1
  50. package/docs/client-ui.md +95 -19
  51. package/docs/durability-design.md +28 -10
  52. package/docs/evaluation.md +78 -6
  53. package/docs/installation.md +41 -6
  54. package/docs/publishing.md +5 -3
  55. package/docs/runtime-reference.md +76 -25
  56. package/docs/semantic-validation.md +29 -0
  57. package/docs/stateful-binding-updates-proposal.md +759 -0
  58. package/docs/user-bindings.en.md +66 -0
  59. package/docs/user-bindings.md +66 -0
  60. package/docs/value-wire.md +3 -3
  61. package/docs/verification-optimization-work.md +41 -0
  62. package/docs/verification.md +71 -0
  63. package/index.js +369 -92
  64. package/internal/ast-traversal.js +5 -2
  65. package/internal/async-local-storage-intrinsics.js +38 -0
  66. package/internal/binding-declaration-contract.js +8 -0
  67. package/internal/binding-descriptors.js +1 -0
  68. package/internal/binding-pattern-traversal.js +25 -0
  69. package/internal/binding-pattern.js +26 -29
  70. package/internal/binding-source-analysis.js +708 -0
  71. package/internal/binding-update-policy.js +72 -0
  72. package/internal/bounded-worker-round.js +56 -0
  73. package/internal/callable-definition-environment.js +42 -0
  74. package/internal/callable-source-catalog.js +129 -0
  75. package/internal/callable-source-encoding.js +47 -0
  76. package/internal/callable-source-facts.js +459 -0
  77. package/internal/callable-source-format.js +2 -0
  78. package/internal/callable-source-lowering.js +123 -0
  79. package/internal/cell-analysis-contract.js +25 -0
  80. package/internal/cell-analysis.js +253 -290
  81. package/internal/cell-completion.js +15 -0
  82. package/internal/cell-error.js +7 -0
  83. package/internal/cell-parser.js +66 -0
  84. package/internal/cell-rewriter.js +3 -677
  85. package/internal/commonjs-export-evidence.js +63 -0
  86. package/internal/commonjs-source-evidence.js +72 -0
  87. package/internal/compiler-amaro.cjs +2 -0
  88. package/internal/compiler-compression.js +12 -0
  89. package/internal/compiler-data.js +58 -0
  90. package/internal/compiler-descriptors.js +54 -0
  91. package/internal/compiler-dynamic-cache.js +48 -0
  92. package/internal/compiler-entry.js +35 -0
  93. package/internal/compiler-generated-names.js +17 -0
  94. package/internal/compiler-intrinsics.js +50 -0
  95. package/internal/compiler-module-links.js +37 -0
  96. package/internal/compiler-operations.js +61 -0
  97. package/internal/compiler-platform-factory.js +84 -0
  98. package/internal/compiler-platform.js +136 -0
  99. package/internal/compiler-record-roles.js +53 -0
  100. package/internal/compiler-region-output.js +259 -0
  101. package/internal/compiler-resource-lowering.js +103 -0
  102. package/internal/compiler-scope-facts.js +115 -0
  103. package/internal/compiler-service.js +109 -0
  104. package/internal/compiler-source-cache.js +32 -0
  105. package/internal/compiler-source-pieces.js +93 -0
  106. package/internal/compiler-source-regions.js +132 -0
  107. package/internal/compiler-storage-source.js +54 -0
  108. package/internal/compiler-text.js +15 -0
  109. package/internal/compiler-typescript.cjs +2 -0
  110. package/internal/config-spec.js +83 -27
  111. package/internal/cordis-tools-owner.js +130 -21
  112. package/internal/diagnostic.js +27 -1
  113. package/internal/direct-surface-owner.js +76 -23
  114. package/internal/dynamic-binding-evidence.js +16 -0
  115. package/internal/dynamic-environment-compiler.js +779 -0
  116. package/internal/dynamic-environment-integration.js +91 -0
  117. package/internal/dynamic-environment-runtime.js +383 -0
  118. package/internal/dynamic-native-calls.js +153 -0
  119. package/internal/dynamic-native-runtime.js +262 -0
  120. package/internal/dynamic-scope-analysis.js +90 -0
  121. package/internal/edit-transport-owner.js +27 -2
  122. package/internal/execution-seam-compat.js +193 -0
  123. package/internal/failure-reporting.js +136 -28
  124. package/internal/host-rpc.js +66 -0
  125. package/internal/isolated-worker.js +555 -0
  126. package/internal/kernel-child.js +139 -0
  127. package/internal/kernel-worker.js +1179 -233
  128. package/internal/language-semantics.js +14 -0
  129. package/internal/legacy-binding-catalog.js +48 -0
  130. package/internal/legacy-cell-analysis.js +600 -0
  131. package/internal/legacy-cell-parser.js +50 -0
  132. package/internal/legacy-cell-rewriter.js +631 -0
  133. package/internal/legacy-repl-convenience.js +291 -0
  134. package/internal/managed-module-operations.js +170 -0
  135. package/internal/module-compilation.js +322 -0
  136. package/internal/module-runtime-platform.js +19 -0
  137. package/internal/module-transform-contract.js +42 -0
  138. package/internal/native-await-declarations.js +68 -0
  139. package/internal/native-root-compilation.js +54 -0
  140. package/internal/native-root-dynamic.js +67 -0
  141. package/internal/record-utils.js +24 -15
  142. package/internal/recovery-tips.js +27 -15
  143. package/internal/rejected-cell-editor.js +13 -8
  144. package/internal/repl-convenience.js +2 -289
  145. package/internal/repl-memory-projection.js +81 -12
  146. package/internal/repl-observation-interest.js +70 -0
  147. package/internal/repl-rewrite-contract.js +6 -0
  148. package/internal/repl-scope-normalizer.js +2091 -0
  149. package/internal/repl-value-observer.js +117 -0
  150. package/internal/rpc-contract.js +52 -0
  151. package/internal/runtime-bridge-owner.js +172 -28
  152. package/internal/runtime-config.js +48 -52
  153. package/internal/runtime-contexts.js +82 -10
  154. package/internal/runtime-intrinsics.js +101 -0
  155. package/internal/runtime-messages.js +111 -0
  156. package/internal/session-cell-executor.js +402 -87
  157. package/internal/session-journal-recovery.js +684 -0
  158. package/internal/session-journal-schema.js +123 -0
  159. package/internal/session-journal.js +199 -654
  160. package/internal/session-log-view.js +42 -9
  161. package/internal/session-runtime.js +257 -95
  162. package/internal/session-state.js +247 -71
  163. package/internal/source-position-map.js +230 -71
  164. package/internal/stateful-module-compiler.js +154 -0
  165. package/internal/stateful-module-runtime.js +303 -0
  166. package/internal/stateful-root-compiler.js +600 -0
  167. package/internal/stateful-root-runtime.js +340 -0
  168. package/internal/typert-codec-compat.js +28 -0
  169. package/internal/typescript-transform.js +31 -0
  170. package/internal/user-binding-authoring.js +70 -0
  171. package/internal/user-binding-console-worker.js +244 -0
  172. package/internal/user-binding-console.js +148 -0
  173. package/internal/user-binding-draft-projection.js +335 -0
  174. package/internal/user-binding-model-context.js +31 -0
  175. package/internal/user-binding-runner.js +56 -0
  176. package/internal/user-bindings-owner.js +1065 -0
  177. package/internal/user-bindings-store.js +293 -0
  178. package/internal/user-bindings.js +361 -0
  179. package/internal/value-wire-schema.js +28 -0
  180. package/internal/value-wire.js +130 -91
  181. package/internal/worker-client.js +57 -67
  182. package/internal/worker-cwd-virtualization.js +80 -53
  183. package/internal/worker-environment.js +65 -0
  184. package/internal/worker-output-relay.js +29 -0
  185. package/internal/worker-repl-realm.js +134 -0
  186. package/internal/worker-shutdown.js +14 -0
  187. package/package.json +76 -7
  188. package/src/client-activity.js +95 -53
  189. package/src/client-authoring-view.js +580 -0
  190. package/src/client-binding-review.js +230 -0
  191. package/src/client-bindings-data.js +29 -0
  192. package/src/client-catalog.js +127 -0
  193. package/src/client-code-editor.js +84 -0
  194. package/src/client-console.js +112 -0
  195. package/src/client-copy.js +370 -0
  196. package/src/client-feature-gates.js +62 -0
  197. package/src/client-host-compat.js +150 -0
  198. package/src/client-indicator-view.js +267 -0
  199. package/src/client-repl-view.js +292 -0
  200. package/src/client-rpc.js +20 -0
  201. package/src/client-settings-view.js +221 -0
  202. package/src/client-styles.js +106 -0
  203. package/src/client-tool-view.js +108 -0
  204. package/src/client-transport.js +159 -0
  205. package/src/client-workbench.js +521 -0
  206. package/src/client.js +233 -615
@@ -1,5 +1,36 @@
1
1
  // Runtime state transitions shared by the session coordinator and cell executor.
2
2
 
3
+ import { userBindingCatalogEntries } from './user-bindings.js'
4
+ import { LEGACY_USER_BINDINGS_SHADOW_POLICY } from './session-journal-schema.js'
5
+ import { advanceLegacyBindings } from './legacy-binding-catalog.js'
6
+ import { dynamicBindingOrigin } from './dynamic-binding-evidence.js'
7
+ import { LEGACY_LANGUAGE_SEMANTICS, normalizeLanguageSemantics } from './language-semantics.js'
8
+
9
+ /**
10
+ * Reuse counts belong to a logical binding identity, not to one declaration
11
+ * occurrence. Every catalog transition carries the previous count forward by
12
+ * name, so a redeclaration can change the definition without resetting how many
13
+ * later cells reused the binding.
14
+ */
15
+ function carryReuseCounts(entries, previousEntries) {
16
+ for (const [name, entry] of entries) {
17
+ const previous = previousEntries.get(name)
18
+ if (previous?.reuseCount === undefined || entry.reuseCount === previous.reuseCount) continue
19
+ entries.set(name, { ...entry, reuseCount: previous.reuseCount })
20
+ }
21
+ }
22
+
23
+ /** One settled cell contributes at most one reuse event per identity its
24
+ * rewritten source statically references; the count is a source fact, not a
25
+ * runtime trace of which references executed. */
26
+ function applyReuseEvents(entries, previousEntries, reusedNames) {
27
+ for (const name of new Set(reusedNames ?? [])) {
28
+ const entry = entries.get(name)
29
+ if (entry === undefined || previousEntries.get(name) === undefined) continue
30
+ entries.set(name, { ...entry, reuseCount: (entry.reuseCount ?? 0) + 1 })
31
+ }
32
+ }
33
+
3
34
  export function durabilityState(overrides = {}) {
4
35
  return Object.freeze({
5
36
  status: 'durable',
@@ -18,102 +49,247 @@ export function transitionDurability(state, transition) {
18
49
  }
19
50
 
20
51
  export class BindingCatalog {
21
- #known
22
- #kinds
23
- #definitions
24
- #imports
52
+ #entries
25
53
  #namespaces
26
- #writable
27
-
28
- constructor(
29
- known = new Set(),
30
- imports = new Map(),
31
- namespaces = new Set(),
32
- kinds = new Map(),
33
- definitions = new Map(),
34
- writable = new Set(),
35
- ) {
36
- this.#known = new Set(known)
37
- this.#kinds = new Map([...this.#known].map(name => [name, kinds.get(name) ?? 'variable']))
38
- this.#definitions = new Map([...this.#known]
39
- .filter(name => definitions.has(name))
40
- .map(name => [name, definitions.get(name)]))
41
- this.#imports = new Map(imports)
54
+ #userBindingAncestry
55
+ #rootCandidates
56
+ #dynamicOrigins
57
+
58
+ constructor({ entries = new Map(), namespaces = new Set(), userBindingAncestry = new Set(), rootCandidates = new Map(), dynamicOrigins = new Map() } = {}) {
59
+ this.#entries = new Map([...entries].map(([name, entry]) => [name, Object.freeze({ ...entry })]))
42
60
  this.#namespaces = new Set(namespaces)
43
- this.#writable = new Set([...writable].filter(name => this.#known.has(name)))
61
+ // A closure can perform its first implicit assignment in a later cell.
62
+ // Its source plan is ancestry, not an initialized binding or provider shadow.
63
+ this.#rootCandidates = new Map(rootCandidates)
64
+ this.#dynamicOrigins = new Map(dynamicOrigins)
65
+ // Escaped provider setters may create local values after their entries are
66
+ // removed. Eligibility follows the catalog ancestry, not the visible inventory.
67
+ this.#userBindingAncestry = new Set([
68
+ ...userBindingAncestry,
69
+ ...[...entries].filter(([, entry]) => entry.origin?.kind === 'user-global').map(([name]) => name),
70
+ ])
44
71
  Object.freeze(this)
45
72
  }
46
73
 
47
74
  inputs() {
48
75
  return {
49
- knownBindings: new Set(this.#known),
50
- importBindings: new Map(this.#imports),
76
+ knownBindings: new Set([...this.#entries]
77
+ .filter(([, entry]) => entry.unavailable !== true)
78
+ .map(([name]) => name)),
79
+ importBindings: new Map([...this.#entries]
80
+ .filter(([, entry]) => entry.import !== undefined)
81
+ .map(([name, entry]) => [name, entry.import])),
51
82
  importNamespaces: new Set(this.#namespaces),
52
- writableBindings: new Set(this.#writable),
83
+ writableBindings: new Set([...this.#entries]
84
+ .filter(([, entry]) => entry.writable === true)
85
+ .map(([name]) => name)),
86
+ nativeBindings: new Set([...this.#entries].filter(([, entry]) => entry.native === true).map(([name]) => name)),
87
+ nativeLexicalBindings: new Set([...this.#entries].filter(([, entry]) => entry.nativeLexical === true).map(([name]) => name)),
88
+ rootCandidates: new Map([...this.#rootCandidates].map(([target, declaration]) => [target, declaration.name])),
89
+ dynamicOrigins: [...this.#dynamicOrigins.keys()],
90
+ establishedRoots: new Map([...this.#entries].filter(([, entry]) => entry.rootSource !== undefined)
91
+ .map(([name, entry]) => [name, entry.rootSource])),
53
92
  }
54
93
  }
55
94
 
56
- advance(prepared, source = undefined, committedRedeclarations = undefined) {
57
- const known = new Set(this.#known)
58
- const kinds = new Map(this.#kinds)
59
- const definitions = new Map(this.#definitions)
60
- const writable = new Set(this.#writable)
61
- const touched = new Set()
62
- const redeclared = new Set((prepared.redeclared ?? []).map(declaration => declaration.name))
63
- const commitGated = prepared.commitTargets
64
- const committed = committedRedeclarations instanceof Set
65
- ? committedRedeclarations
66
- : new Set([...redeclared, ...commitGated])
67
- const uncommitted = new Set()
68
- const extractDefinition = sourceDefinitionExtractor(source)
69
- for (const declaration of prepared.declarations ?? []) {
70
- if (typeof declaration?.name !== 'string') continue
71
- const dependency = typeof declaration.commitDependency === 'string'
72
- && commitGated.has(declaration.commitDependency)
73
- ? declaration.commitDependency
74
- : commitGated.has(declaration.name) ? declaration.name : undefined
75
- if (dependency !== undefined && !committed.has(dependency)) {
76
- uncommitted.add(declaration.name)
77
- continue
95
+ advance(prepared, source = undefined, committedRedeclarations = undefined, rootBindingFacts = undefined) {
96
+ const semantics = normalizeLanguageSemantics(prepared.languageSemantics ?? LEGACY_LANGUAGE_SEMANTICS)
97
+ if (semantics === LEGACY_LANGUAGE_SEMANTICS) {
98
+ const legacy = advanceLegacyBindings(this.#entries, prepared, sourceDefinitionExtractor(source), committedRedeclarations)
99
+ const nativePublications = new Set(prepared.moduleLoads.flatMap(load => (load.nativePublications ?? []).map(binding => binding.name)))
100
+ for (const [name, entry] of legacy.entries) {
101
+ if (entry.rootSource === undefined && entry.origin === undefined && entry.userBindingState === undefined) {
102
+ legacy.entries.set(name, { ...entry, native: true,
103
+ nativeLexical: this.#entries.get(name)?.nativeLexical === true || prepared.nativeLexicals?.has(name) === true })
104
+ }
78
105
  }
79
- touched.add(declaration.name)
80
- kinds.set(declaration.name, declaration.kind ?? 'variable')
81
- const definition = extractDefinition(declaration.definitionSpan)
82
- if (definition !== undefined) definitions.set(declaration.name, definition)
83
- if (!redeclared.has(declaration.name)) {
84
- if (declaration.writable === true) writable.add(declaration.name)
85
- else writable.delete(declaration.name)
106
+ for (const fact of rootBindingFacts ?? []) {
107
+ const previous = legacy.entries.get(fact.name)
108
+ if (previous !== undefined) legacy.entries.set(fact.name, { ...previous,
109
+ native: this.#entries.get(fact.name)?.native || nativePublications.has(fact.name) && fact.source !== 'absent',
110
+ import: this.#entries.get(fact.name)?.import,
111
+ })
86
112
  }
113
+ applyRootBindingFacts(legacy.entries, rootBindingFacts, this.#rootCandidates, this.#dynamicOrigins,
114
+ prepared.imports, this.#entries)
115
+ // The frozen legacy-v1 preparation reports no reference facts, so a
116
+ // legacy cell contributes no reuse event; accumulated counts still carry
117
+ // across the transition.
118
+ carryReuseCounts(legacy.entries, this.#entries)
119
+ return new BindingCatalog({
120
+ ...legacy,
121
+ userBindingAncestry: this.#userBindingAncestry,
122
+ rootCandidates: this.#rootCandidates,
123
+ dynamicOrigins: this.#dynamicOrigins,
124
+ })
125
+ }
126
+ const entries = new Map(this.#entries)
127
+ const committed = committedRedeclarations ?? prepared.commitTargets
128
+ const extractDefinition = sourceDefinitionExtractor(source)
129
+ const rootCandidates = new Map(this.#rootCandidates)
130
+ const dynamicOrigins = new Map(this.#dynamicOrigins)
131
+ for (const origin of prepared.dynamicOrigins ?? []) {
132
+ dynamicOrigins.set(origin.target, extractDefinition(origin.definitionSpan))
133
+ }
134
+ for (const declaration of prepared.implicitDeclarations ?? []) {
135
+ rootCandidates.set(declaration.target, { name: declaration.name, kind: 'variable', writable: true,
136
+ definition: extractDefinition(declaration.definitionSpan) })
87
137
  }
88
- for (const name of prepared.declared) {
89
- if (!uncommitted.has(name)) touched.add(name)
138
+ const commitOrder = new Map([...committed].map((target, index) => [target, index]))
139
+ const declarations = prepared.declarations.filter(declaration => committed.has(declaration.commitDependency))
140
+ .sort((left, right) => commitOrder.get(left.commitDependency) - commitOrder.get(right.commitDependency))
141
+ for (const declaration of declarations) {
142
+ const previous = entries.get(declaration.name)
143
+ entries.set(declaration.name, { kind: declaration.kind,
144
+ writable: declaration.writable,
145
+ ...(previous?.nativeLexical === true ? { nativeLexical: true } : {}),
146
+ definition: extractDefinition(declaration.definitionSpan) ?? previous?.definition,
147
+ import: declaration.kind === 'import' ? prepared.imports.get(declaration.name) : undefined,
148
+ })
90
149
  }
91
- for (const name of touched) {
92
- known.delete(name)
93
- known.add(name)
150
+ // Value provenance follows actual commits, including repeated loop targets.
151
+ // The inventory separately presents accepted declarations in source order.
152
+ for (const { name } of declarations.sort((left, right) => left.span.line - right.span.line
153
+ || left.span.column - right.span.column)) {
154
+ const entry = entries.get(name)
155
+ entries.delete(name)
156
+ entries.set(name, entry)
94
157
  }
95
- const imports = new Map(prepared.imports)
96
- for (const [name, binding] of imports) {
97
- if (typeof binding?.commitDependency !== 'string'
98
- || !commitGated.has(binding.commitDependency)
99
- || committed.has(binding.commitDependency)) continue
100
- if (this.#imports.has(name)) imports.set(name, this.#imports.get(name))
101
- else imports.delete(name)
158
+ applyRootBindingFacts(entries, rootBindingFacts, rootCandidates, dynamicOrigins, prepared.imports, this.#entries)
159
+ carryReuseCounts(entries, this.#entries)
160
+ applyReuseEvents(entries, this.#entries, prepared.reusedNames)
161
+ return new BindingCatalog({ entries, namespaces: this.#namespaces, userBindingAncestry: this.#userBindingAncestry, rootCandidates, dynamicOrigins })
162
+ }
163
+
164
+ userBindings(snapshot, activeEntryIds = undefined, shadowPolicy = LEGACY_USER_BINDINGS_SHADOW_POLICY) {
165
+ const candidates = (snapshot === undefined ? [] : userBindingCatalogEntries(snapshot))
166
+ .filter(entry => activeEntryIds === undefined || activeEntryIds.has(entry.entryId))
167
+ const shadowedNames = new Set([...this.#entries]
168
+ .filter(([, entry]) => entry.origin?.kind !== 'user-global')
169
+ .map(([name]) => name))
170
+ const shadowedEntryIds = new Set(candidates
171
+ .filter(entry => shadowedNames.has(entry.name))
172
+ .map(entry => entry.entryId))
173
+ const desired = new Map(candidates.filter(entry => shadowPolicy === LEGACY_USER_BINDINGS_SHADOW_POLICY
174
+ ? !shadowedEntryIds.has(entry.entryId) : !shadowedNames.has(entry.name))
175
+ .map(entry => [entry.name, entry]))
176
+ const entries = new Map(this.#entries)
177
+ for (const [name, { origin }] of entries) {
178
+ if (origin?.kind !== 'user-global') continue
179
+ const next = desired.get(name)
180
+ if (next !== undefined && next.entryId === origin.entryId
181
+ && next.fingerprint === origin.fingerprint) continue
182
+ entries.delete(name)
183
+ }
184
+
185
+ for (const entry of desired.values()) {
186
+ entries.delete(entry.name)
187
+ entries.set(entry.name, {
188
+ kind: entry.kind,
189
+ definition: entry.definition,
190
+ writable: true,
191
+ origin: Object.freeze({ kind: 'user-global', entryId: entry.entryId, fingerprint: entry.fingerprint }),
192
+ })
102
193
  }
103
- return new BindingCatalog(known, imports, prepared.importNamespaces, kinds, definitions, writable)
194
+ carryReuseCounts(entries, this.#entries)
195
+ return Object.freeze({
196
+ catalog: new BindingCatalog({ entries, namespaces: this.#namespaces, userBindingAncestry: this.#userBindingAncestry, rootCandidates: this.#rootCandidates, dynamicOrigins: this.#dynamicOrigins }),
197
+ shadowedNames,
198
+ })
199
+ }
200
+
201
+ userBindingNameSet(snapshot, includeProviderAncestry = false) {
202
+ return new Set([
203
+ ...(includeProviderAncestry ? this.#userBindingAncestry : []),
204
+ ...[...this.#entries].filter(([, entry]) => (entry.userBindingState !== undefined
205
+ && (includeProviderAncestry || entry.userBindingState !== 'provider'))
206
+ || (includeProviderAncestry && entry.origin?.kind === 'user-global')).map(([name]) => name),
207
+ ...(snapshot === undefined ? [] : userBindingCatalogEntries(snapshot).map(entry => entry.name)),
208
+ ])
209
+ }
210
+
211
+ /** Actual worker sources override static declaration plans at this one boundary. */
212
+ reconcileUserBindingNames(snapshot, facts, source = undefined) {
213
+ const entries = new Map(this.#entries)
214
+ const candidates = new Map((snapshot === undefined ? [] : userBindingCatalogEntries(snapshot)).map(entry => [entry.name, entry]))
215
+ for (const [name, entry] of entries) {
216
+ if (entry.origin?.kind === 'user-global') entries.delete(name)
217
+ }
218
+ for (const fact of facts) {
219
+ const previous = this.#entries.get(fact.name)
220
+ if (fact.state === 'provider') {
221
+ const candidate = candidates.get(fact.name)
222
+ entries.set(fact.name, {
223
+ kind: candidate.kind, definition: candidate.definition, writable: true, userBindingState: 'provider',
224
+ origin: Object.freeze({ kind: 'user-global', entryId: candidate.entryId, fingerprint: candidate.fingerprint }),
225
+ })
226
+ } else {
227
+ entries.set(fact.name, {
228
+ kind: previous?.kind ?? 'variable',
229
+ // Preserve compiler-owned import accessors while replacing only the
230
+ // per-name user-binding proof. Imports are the canonical storage for
231
+ // aliases and must remain available to the next preparation pass.
232
+ import: previous?.import,
233
+ rootSource: previous?.rootSource,
234
+ native: previous?.native,
235
+ nativeLexical: previous?.nativeLexical,
236
+ definition: previous?.origin === undefined && previous?.definition !== undefined
237
+ ? previous.definition
238
+ : fact.state === 'local' && typeof source === 'string' && source.length > 0
239
+ ? Object.freeze({ source: source.slice(0, MAX_DEFINITION_SOURCE_LENGTH), line: 1, column: 1 }) : undefined,
240
+ writable: previous?.writable ?? true,
241
+ userBindingState: fact.state,
242
+ unavailable: fact.state !== 'local',
243
+ })
244
+ }
245
+ }
246
+ carryReuseCounts(entries, this.#entries)
247
+ return new BindingCatalog({ entries, namespaces: this.#namespaces, userBindingAncestry: this.#userBindingAncestry, rootCandidates: this.#rootCandidates, dynamicOrigins: this.#dynamicOrigins })
248
+ }
249
+
250
+ withoutUserBindings() {
251
+ const entries = new Map([...this.#entries].filter(([, entry]) => entry.origin?.kind !== 'user-global'))
252
+ return new BindingCatalog({ entries, namespaces: this.#namespaces, userBindingAncestry: this.#userBindingAncestry, rootCandidates: this.#rootCandidates, dynamicOrigins: this.#dynamicOrigins })
253
+ }
254
+
255
+ shadowUserBindings(names) {
256
+ const entries = new Map(this.#entries)
257
+ for (const name of names) {
258
+ const entry = entries.get(name)
259
+ if (entry?.origin?.kind !== 'user-global') continue
260
+ entries.set(name, { ...entry, origin: undefined, definition: undefined })
261
+ }
262
+ return new BindingCatalog({ entries, namespaces: this.#namespaces, userBindingAncestry: this.#userBindingAncestry, rootCandidates: this.#rootCandidates, dynamicOrigins: this.#dynamicOrigins })
104
263
  }
105
264
 
106
265
  snapshot() {
107
- return [...this.#known].reverse()
108
- .filter(name => !this.#namespaces.has(name))
109
- .map(name => ({
266
+ return [...this.#entries].reverse()
267
+ .filter(([name, entry]) => !this.#namespaces.has(name) && entry.unavailable !== true)
268
+ .map(([name, entry]) => ({
110
269
  name,
111
- kind: this.#kinds.get(name) ?? 'variable',
112
- ...(this.#definitions.has(name) ? { definition: this.#definitions.get(name) } : {}),
270
+ kind: entry.kind,
271
+ reuseCount: entry.reuseCount ?? 0,
272
+ ...(entry.definition === undefined ? {} : { definition: entry.definition }),
113
273
  }))
114
274
  }
115
275
  }
116
276
 
277
+ function applyRootBindingFacts(entries, facts, rootCandidates, dynamicOrigins, imports, previousEntries) {
278
+ for (const fact of facts ?? []) {
279
+ const origin = dynamicBindingOrigin(fact.write, fact.name, dynamicOrigins)
280
+ const write = rootCandidates.get(fact.write) ?? (origin === undefined ? undefined
281
+ : { name: fact.name, kind: 'variable', writable: true, definition: dynamicOrigins.get(origin) })
282
+ const previous = entries.get(fact.name) ?? write
283
+ if (previous === undefined) continue
284
+ const root = { ...previous, rootSource: fact.source,
285
+ ...(write === undefined ? {} : { definition: write.definition }) }
286
+ if (fact.source === 'local') entries.set(fact.name, { ...root, unavailable: false, import: undefined, origin: undefined,
287
+ ...(previous.import === undefined && write === undefined ? {} : { kind: 'variable', writable: true }) })
288
+ else if (fact.source === 'absent') entries.set(fact.name, { ...root, unavailable: true, import: undefined })
289
+ else entries.set(fact.name, { ...root, unavailable: false, import: imports.get(fact.name) ?? previousEntries.get(fact.name)?.import })
290
+ }
291
+ }
292
+
117
293
  const MAX_DEFINITION_SOURCE_LENGTH = 1024
118
294
 
119
295
  function lineOffsets(source) {