dsh-ptc-plus 0.3.1 → 0.4.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.
- package/README.en.md +66 -73
- package/README.md +66 -73
- package/assets/ptc-plus-bindings-en.png +0 -0
- package/assets/ptc-plus-bindings-zh.png +0 -0
- package/assets/ptc-plus-repair-en.png +0 -0
- package/assets/ptc-plus-repair-zh.png +0 -0
- package/assets/ptc-plus-repl-workspace-en.png +0 -0
- package/assets/ptc-plus-repl-workspace-zh.png +0 -0
- package/assets/ptc-plus-settings-en.png +0 -0
- package/assets/ptc-plus-settings-zh.png +0 -0
- package/client.js +30610 -722
- package/compiler-amaro.cjs +5 -0
- package/compiler-amaro.cjs.map +6 -0
- package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
- package/compiler-assets.json +3 -0
- package/compiler-core.cjs +554 -0
- package/compiler-core.cjs.map +6 -0
- package/compiler-platform.cjs +2 -0
- package/compiler-platform.cjs.map +6 -0
- package/compiler-typescript.cjs +388 -0
- package/compiler-typescript.cjs.map +6 -0
- package/docs/README.md +6 -0
- package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
- package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +6 -4
- package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +15 -3
- package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
- package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
- package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
- package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
- package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +9 -3
- package/docs/adr/0014-persist-cell-rewrite-policy.md +11 -5
- package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
- package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
- package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
- package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +8 -6
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +17 -3
- package/docs/adr/0023-global-user-bindings.md +104 -0
- package/docs/adr/0024-repl-console-observation.md +33 -0
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
- package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
- package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
- package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
- package/docs/architecture.md +82 -22
- package/docs/binding-review-placement-design.md +200 -0
- package/docs/capability-projection.md +1 -1
- package/docs/client-ui.md +96 -20
- package/docs/durability-design.md +61 -24
- package/docs/evaluation.md +78 -6
- package/docs/installation.md +41 -6
- package/docs/program-data-plane.md +6 -0
- package/docs/publishing.md +5 -3
- package/docs/runtime-reference.md +79 -25
- package/docs/semantic-validation.md +29 -0
- package/docs/stateful-binding-updates-proposal.md +755 -0
- package/docs/user-bindings.en.md +64 -0
- package/docs/user-bindings.md +64 -0
- package/docs/value-wire.md +3 -3
- package/docs/verification.md +57 -0
- package/index.js +374 -92
- package/internal/ast-traversal.js +5 -2
- package/internal/binding-descriptors.js +1 -0
- package/internal/binding-pattern-traversal.js +25 -0
- package/internal/binding-pattern.js +26 -29
- package/internal/binding-source-analysis.js +391 -0
- package/internal/binding-update-policy.js +66 -0
- package/internal/bounded-worker-round.js +56 -0
- package/internal/callable-definition-environment.js +42 -0
- package/internal/callable-source-catalog.js +129 -0
- package/internal/callable-source-encoding.js +47 -0
- package/internal/callable-source-facts.js +459 -0
- package/internal/callable-source-format.js +2 -0
- package/internal/callable-source-lowering.js +123 -0
- package/internal/cell-analysis-contract.js +25 -0
- package/internal/cell-analysis.js +252 -242
- package/internal/cell-completion.js +15 -0
- package/internal/cell-error.js +7 -0
- package/internal/cell-parser.js +66 -0
- package/internal/cell-rewriter.js +3 -553
- package/internal/commonjs-export-evidence.js +63 -0
- package/internal/commonjs-source-evidence.js +72 -0
- package/internal/compiler-amaro.cjs +2 -0
- package/internal/compiler-compression.js +12 -0
- package/internal/compiler-data.js +58 -0
- package/internal/compiler-descriptors.js +54 -0
- package/internal/compiler-dynamic-cache.js +48 -0
- package/internal/compiler-entry.js +35 -0
- package/internal/compiler-generated-names.js +17 -0
- package/internal/compiler-intrinsics.js +84 -0
- package/internal/compiler-module-links.js +34 -0
- package/internal/compiler-operations.js +61 -0
- package/internal/compiler-platform-factory.js +84 -0
- package/internal/compiler-platform.js +136 -0
- package/internal/compiler-record-roles.js +53 -0
- package/internal/compiler-region-output.js +259 -0
- package/internal/compiler-resource-lowering.js +103 -0
- package/internal/compiler-scope-facts.js +115 -0
- package/internal/compiler-service.js +109 -0
- package/internal/compiler-source-cache.js +32 -0
- package/internal/compiler-source-pieces.js +93 -0
- package/internal/compiler-source-regions.js +132 -0
- package/internal/compiler-storage-source.js +54 -0
- package/internal/compiler-text.js +15 -0
- package/internal/compiler-typescript.cjs +2 -0
- package/internal/config-spec.js +91 -25
- package/internal/cordis-tools-owner.js +130 -21
- package/internal/diagnostic.js +27 -1
- package/internal/direct-surface-owner.js +76 -23
- package/internal/dynamic-binding-evidence.js +16 -0
- package/internal/dynamic-environment-compiler.js +779 -0
- package/internal/dynamic-environment-integration.js +87 -0
- package/internal/dynamic-environment-runtime.js +362 -0
- package/internal/dynamic-native-calls.js +150 -0
- package/internal/dynamic-native-runtime.js +248 -0
- package/internal/dynamic-scope-analysis.js +90 -0
- package/internal/edit-transport-owner.js +28 -3
- package/internal/execution-seam-compat.js +193 -0
- package/internal/failure-reporting.js +118 -18
- package/internal/host-rpc.js +66 -0
- package/internal/isolated-worker.js +548 -0
- package/internal/kernel-child.js +139 -0
- package/internal/kernel-worker.js +911 -116
- package/internal/language-semantics.js +14 -0
- package/internal/legacy-binding-catalog.js +48 -0
- package/internal/legacy-cell-analysis.js +600 -0
- package/internal/legacy-cell-parser.js +50 -0
- package/internal/legacy-cell-rewriter.js +631 -0
- package/internal/legacy-repl-convenience.js +291 -0
- package/internal/managed-module-operations.js +170 -0
- package/internal/module-compilation.js +321 -0
- package/internal/module-runtime-platform.js +19 -0
- package/internal/module-transform-contract.js +12 -0
- package/internal/native-await-declarations.js +68 -0
- package/internal/native-root-compilation.js +54 -0
- package/internal/native-root-dynamic.js +67 -0
- package/internal/recovery-tips.js +27 -15
- package/internal/rejected-cell-editor.js +13 -8
- package/internal/repl-convenience.js +2 -201
- package/internal/repl-memory-projection.js +81 -12
- package/internal/repl-observation-interest.js +70 -0
- package/internal/repl-rewrite-contract.js +21 -0
- package/internal/repl-scope-normalizer.js +2091 -0
- package/internal/repl-value-observer.js +114 -0
- package/internal/rpc-contract.js +52 -0
- package/internal/runtime-bridge-owner.js +172 -28
- package/internal/runtime-config.js +48 -51
- package/internal/runtime-contexts.js +82 -10
- package/internal/runtime-messages.js +111 -0
- package/internal/session-cell-executor.js +455 -91
- package/internal/session-journal-recovery.js +684 -0
- package/internal/session-journal-schema.js +106 -0
- package/internal/session-journal.js +237 -440
- package/internal/session-log-view.js +42 -9
- package/internal/session-runtime.js +325 -80
- package/internal/session-state.js +249 -40
- package/internal/source-position-map.js +211 -71
- package/internal/stateful-module-compiler.js +154 -0
- package/internal/stateful-module-runtime.js +303 -0
- package/internal/stateful-root-compiler.js +598 -0
- package/internal/stateful-root-runtime.js +340 -0
- package/internal/typert-codec-compat.js +28 -0
- package/internal/typescript-transform.js +29 -0
- package/internal/user-binding-authoring.js +70 -0
- package/internal/user-binding-console-worker.js +184 -0
- package/internal/user-binding-console.js +148 -0
- package/internal/user-binding-draft-projection.js +335 -0
- package/internal/user-binding-model-context.js +31 -0
- package/internal/user-binding-runner.js +56 -0
- package/internal/user-bindings-owner.js +1065 -0
- package/internal/user-bindings-store.js +293 -0
- package/internal/user-bindings.js +353 -0
- package/internal/value-wire-schema.js +28 -0
- package/internal/value-wire.js +29 -20
- package/internal/worker-client.js +57 -67
- package/internal/worker-environment.js +45 -0
- package/internal/worker-output-relay.js +29 -0
- package/internal/worker-shutdown.js +14 -0
- package/package.json +81 -11
- package/src/client-activity.js +109 -45
- package/src/client-authoring-view.js +580 -0
- package/src/client-binding-review.js +230 -0
- package/src/client-bindings-data.js +29 -0
- package/src/client-catalog.js +127 -0
- package/src/client-code-editor.js +84 -0
- package/src/client-console.js +112 -0
- package/src/client-copy.js +370 -0
- package/src/client-feature-gates.js +62 -0
- package/src/client-host-compat.js +150 -0
- package/src/client-indicator-view.js +267 -0
- package/src/client-repl-view.js +292 -0
- package/src/client-rpc.js +20 -0
- package/src/client-settings-view.js +221 -0
- package/src/client-styles.js +106 -0
- package/src/client-tool-view.js +108 -0
- package/src/client-transport.js +159 -0
- package/src/client-workbench.js +521 -0
- package/src/client.js +233 -615
|
@@ -2,12 +2,15 @@ import {
|
|
|
2
2
|
decodeValue,
|
|
3
3
|
encodeValue,
|
|
4
4
|
normalizeValueWire,
|
|
5
|
-
|
|
5
|
+
prepareValueWire,
|
|
6
6
|
valueWiresEqual,
|
|
7
7
|
} from './value-wire.js'
|
|
8
8
|
import { diagnostic, renderDiagnostic } from './diagnostic.js'
|
|
9
|
+
import { normalizeBindingDescriptors } from './binding-descriptors.js'
|
|
9
10
|
import {
|
|
10
11
|
firstLine,
|
|
12
|
+
cellPosition,
|
|
13
|
+
exceptionOriginPosition,
|
|
11
14
|
limitLogs,
|
|
12
15
|
LONG_CELL_CODE_UNITS,
|
|
13
16
|
markBindingFailure,
|
|
@@ -16,14 +19,22 @@ import {
|
|
|
16
19
|
oneLineMessage,
|
|
17
20
|
safeProperty,
|
|
18
21
|
} from './failure-reporting.js'
|
|
19
|
-
import { assertStateName } from './session-journal.js'
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
+
import { assertStateName, LIVE_USER_BINDINGS_REUSE_POLICY } from './session-journal.js'
|
|
23
|
+
import { LIVE_USER_BINDINGS_SHADOW_POLICY, normalizeUserBindingNames } from './session-journal-schema.js'
|
|
24
|
+
import { PreflightError, prepareProgram } from './compiler-service.js'
|
|
25
|
+
import { executionPolicies } from './binding-update-policy.js'
|
|
26
|
+
import { createReplMemorySnapshot } from './repl-memory-projection.js'
|
|
27
|
+
import { ModuleRewriteError } from './cell-error.js'
|
|
22
28
|
import { mapSourcePosition } from './source-position-map.js'
|
|
23
29
|
import { durabilityState, transitionDurability } from './session-state.js'
|
|
30
|
+
import { dynamicBindingOrigin } from './dynamic-binding-evidence.js'
|
|
24
31
|
import { validatedEofClosureRepair } from './validated-parse-repair.js'
|
|
32
|
+
import {
|
|
33
|
+
normalizeUserBindingsSnapshot,
|
|
34
|
+
selectUserBindingsSnapshot,
|
|
35
|
+
} from './user-bindings.js'
|
|
25
36
|
|
|
26
|
-
const OUTPUT_LIMIT_MESSAGE = bytes => `output exceeded ${bytes} bytes;
|
|
37
|
+
const OUTPUT_LIMIT_MESSAGE = bytes => `output exceeded ${bytes} bytes; this cell was discarded and the worker reset. Only bindings in the verified recovery frontier can be restored. External effects may already have occurred and are not undone. For future cells, bound console output and return a smaller value; do not assume this cell's values remain available.`
|
|
27
38
|
|
|
28
39
|
function earlyResult(kind, message) {
|
|
29
40
|
return { logs: [], error: { kind, message } }
|
|
@@ -51,16 +62,15 @@ function isBindingReferenceError(error) {
|
|
|
51
62
|
|| /Cannot access ['"][^'"]+['"] before initialization/.test(error.message))
|
|
52
63
|
}
|
|
53
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Parse failures carry original cell coordinates in ModuleRewriteError.cellPosition; the rewriter
|
|
67
|
+
* owns any generated-source mapping, so the executor never re-applies wrapper offsets.
|
|
68
|
+
*/
|
|
54
69
|
function parseCellPosition(error) {
|
|
55
70
|
const cellPosition = error instanceof ModuleRewriteError ? error.cellPosition : undefined
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
:
|
|
59
|
-
const column = Number.isSafeInteger(cellPosition?.column)
|
|
60
|
-
? cellPosition.column
|
|
61
|
-
: Number.isSafeInteger(error?.loc?.column) ? error.loc.column + 1 : undefined
|
|
62
|
-
return line !== undefined && line >= 1 && column !== undefined
|
|
63
|
-
? { line, column }
|
|
71
|
+
return Number.isSafeInteger(cellPosition?.line) && cellPosition.line >= 1
|
|
72
|
+
&& Number.isSafeInteger(cellPosition?.column) && cellPosition.column >= 1
|
|
73
|
+
? { line: cellPosition.line, column: cellPosition.column }
|
|
64
74
|
: undefined
|
|
65
75
|
}
|
|
66
76
|
|
|
@@ -80,7 +90,7 @@ function parseDiagnostic(error, source, position, repair) {
|
|
|
80
90
|
: ['this cell was not executed; correct the reported syntax and retry only this cell with run_code']
|
|
81
91
|
: [
|
|
82
92
|
`this cell was not executed; validated syntax repair: append ${JSON.stringify(repair.delimiter)} at the end of this cell`,
|
|
83
|
-
`when edit_run_code is declared
|
|
93
|
+
`when this correction matches your intent and edit_run_code is declared, prefer the direct tool call ${repair.invocation} with its target guard to run the complete corrected cell; validation proves syntax/preflight acceptance, not intended behavior; otherwise submit corrected source in run_code`,
|
|
84
94
|
],
|
|
85
95
|
})
|
|
86
96
|
}
|
|
@@ -105,20 +115,157 @@ function preflightDiagnostic(error) {
|
|
|
105
115
|
})
|
|
106
116
|
}
|
|
107
117
|
|
|
118
|
+
function committedRedeclarationSet(message, prepared) {
|
|
119
|
+
if (!Array.isArray(message.committedRedeclarations)) {
|
|
120
|
+
throw new Error('kernel returned an invalid committed redeclaration set')
|
|
121
|
+
}
|
|
122
|
+
const allowed = prepared.commitTargets
|
|
123
|
+
const committed = new Set()
|
|
124
|
+
for (const name of message.committedRedeclarations) {
|
|
125
|
+
if (typeof name !== 'string' || committed.has(name) || !allowed.has(name)) {
|
|
126
|
+
throw new Error('kernel returned an invalid committed redeclaration set')
|
|
127
|
+
}
|
|
128
|
+
committed.add(name)
|
|
129
|
+
}
|
|
130
|
+
return committed
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Accept value-free worker facts only for this compilation's logical root. */
|
|
134
|
+
function completedRootBindingFacts(message, prepared, committed) {
|
|
135
|
+
if (prepared.rootRuntimeName === undefined && prepared.rootBindingFacts !== true) return undefined
|
|
136
|
+
if (!Array.isArray(message.rootBindingFacts)) throw new TypeError('kernel returned invalid root binding facts')
|
|
137
|
+
const established = new Map(prepared.rootBindings.established)
|
|
138
|
+
const initialized = new Set(prepared.declarations.filter(declaration => committed.has(declaration.commitDependency)
|
|
139
|
+
&& (prepared.languageSemantics !== 'legacy-v1' || established.has(declaration.name)))
|
|
140
|
+
.map(declaration => declaration.name))
|
|
141
|
+
const candidates = new Map(prepared.rootBindings.candidates)
|
|
142
|
+
const dynamicOrigins = new Set(prepared.rootBindings.dynamicOrigins)
|
|
143
|
+
const available = new Set([...prepared.rootBindings.known, ...established.keys(), ...initialized])
|
|
144
|
+
const allowed = new Set([...available, ...candidates.values()])
|
|
145
|
+
const required = new Set([...established.keys(), ...initialized])
|
|
146
|
+
const imports = new Set([...prepared.rootBindings.legacyImports.map(([name]) => name),
|
|
147
|
+
...[...established].filter(([, source]) => source === 'import').map(([name]) => name),
|
|
148
|
+
...prepared.declarations.filter(declaration => declaration.kind === 'import' && committed.has(declaration.commitDependency))
|
|
149
|
+
.map(declaration => declaration.name)])
|
|
150
|
+
const seen = new Set()
|
|
151
|
+
const facts = message.rootBindingFacts.map(fact => {
|
|
152
|
+
const dynamicOrigin = dynamicBindingOrigin(fact?.write, fact?.name, dynamicOrigins)
|
|
153
|
+
if (fact === null || typeof fact !== 'object' || Array.isArray(fact)
|
|
154
|
+
|| Object.keys(fact).length !== (Object.hasOwn(fact, 'write') ? 3 : 2)
|
|
155
|
+
|| !Object.hasOwn(fact, 'name') || !Object.hasOwn(fact, 'source')
|
|
156
|
+
|| typeof fact.name !== 'string' || !allowed.has(fact.name) && dynamicOrigin === undefined || seen.has(fact.name)
|
|
157
|
+
|| !['local', 'import', 'absent'].includes(fact.source)
|
|
158
|
+
|| Object.hasOwn(fact, 'write') && (typeof fact.write !== 'string'
|
|
159
|
+
|| candidates.get(fact.write) !== fact.name && dynamicOrigin === undefined || fact.source === 'import')
|
|
160
|
+
|| !available.has(fact.name) && !Object.hasOwn(fact, 'write')
|
|
161
|
+
|| fact.source === 'import' && !imports.has(fact.name)
|
|
162
|
+
|| fact.source === 'absent' && initialized.has(fact.name)) throw new TypeError('kernel returned invalid root binding facts')
|
|
163
|
+
seen.add(fact.name)
|
|
164
|
+
required.delete(fact.name)
|
|
165
|
+
return { name: fact.name, source: fact.source, ...(Object.hasOwn(fact, 'write') ? { write: fact.write } : {}) }
|
|
166
|
+
})
|
|
167
|
+
if (required.size !== 0) throw new TypeError('kernel returned incomplete root binding facts')
|
|
168
|
+
return facts
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function completedUserBindingNames(active, message, snapshot) {
|
|
172
|
+
const facts = normalizeUserBindingNames(message.userBindingNames)
|
|
173
|
+
const required = active.userBindingBaseCatalog.userBindingNameSet(snapshot)
|
|
174
|
+
const allowed = active.userBindingBaseCatalog.userBindingNameSet(snapshot, true)
|
|
175
|
+
const providers = new Map((snapshot?.entries ?? []).flatMap(entry => (
|
|
176
|
+
(entry.scope === 'namespace' ? [entry.name] : entry.symbols).map(name => [name, entry.id])
|
|
177
|
+
)))
|
|
178
|
+
for (const fact of facts) {
|
|
179
|
+
if (!allowed.has(fact.name) || (fact.state === 'provider'
|
|
180
|
+
&& (providers.get(fact.name) !== fact.entryId || active.request.bindingDescriptors.reservedNames.has(fact.name)))) {
|
|
181
|
+
throw new TypeError('kernel returned user binding name evidence with invalid ownership')
|
|
182
|
+
}
|
|
183
|
+
required.delete(fact.name)
|
|
184
|
+
}
|
|
185
|
+
if (required.size !== 0) throw new TypeError('kernel returned incomplete user binding name evidence')
|
|
186
|
+
if (active.replay !== undefined && JSON.stringify(facts) !== JSON.stringify(active.replay.userBindingNames)) {
|
|
187
|
+
throw new TypeError('cell replay produced different user binding name evidence')
|
|
188
|
+
}
|
|
189
|
+
return facts
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function validateUserBindingActivation(active, message, ids) {
|
|
193
|
+
if (!Array.isArray(message.userBindingFailures)) throw new TypeError('kernel returned invalid user binding failures')
|
|
194
|
+
const expected = new Set(active.userBindings.entries.map(entry => entry.id))
|
|
195
|
+
for (const id of ids) expected.delete(id)
|
|
196
|
+
for (const failure of message.userBindingFailures) {
|
|
197
|
+
if (failure === null || typeof failure !== 'object' || Object.keys(failure).length !== 2
|
|
198
|
+
|| typeof failure.error !== 'string' || !expected.delete(failure.id)) {
|
|
199
|
+
throw new TypeError('kernel returned invalid user binding failures')
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (expected.size !== 0) throw new TypeError('kernel omitted user binding activation outcomes')
|
|
203
|
+
if ([...ids].some(id => active.userBindingFailures.some(failure => failure.id === id))) {
|
|
204
|
+
throw new TypeError('kernel activated a request-owned user binding name')
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** A reserved program binding (`tools` and the injected error classes) is not shadowable at the
|
|
209
|
+
* session root, so a collision on it is not a repeated declaration. The collision producer records
|
|
210
|
+
* that reason, and rendering the recorded reason keeps "top-level bindings already exist" from
|
|
211
|
+
* implying the cell redeclared a name the session never created. */
|
|
212
|
+
const RESERVED_BINDING_REASON = 'reserved-program-binding-not-shadowable'
|
|
213
|
+
/** Reasons whose only remaining guidance is to reuse the binding already in session state. */
|
|
214
|
+
const REUSE_BINDING_REASONS = new Set([
|
|
215
|
+
'variable-redeclarations-disabled', 'redeclaration-splitting-disabled', 'protected-root-redeclaration',
|
|
216
|
+
'import-binding-redeclaration', RESERVED_BINDING_REASON,
|
|
217
|
+
])
|
|
218
|
+
|
|
219
|
+
function reservedBindingNote(collisions) {
|
|
220
|
+
const reserved = [...new Set(collisions.filter(collision => collision.reason === RESERVED_BINDING_REASON)
|
|
221
|
+
.map(collision => collision.name))]
|
|
222
|
+
return reserved.length === 0
|
|
223
|
+
? ''
|
|
224
|
+
: ` ${reserved.join(', ')} cannot be redeclared or overwritten because reserved program bindings are not shadowable.`
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** The model-visible structured form of every recorded collision, reduced to public fields. */
|
|
228
|
+
function collisionRecords(collisions) {
|
|
229
|
+
return collisions.map(collision => ({ name: collision.name, kind: collision.kind,
|
|
230
|
+
reason: collision.reason, start: collision.start, end: collision.end }))
|
|
231
|
+
}
|
|
232
|
+
|
|
108
233
|
function collisionDiagnostic(collisions) {
|
|
109
234
|
const names = [...new Set(collisions.map(item => item.name))]
|
|
235
|
+
const reasons = new Set(collisions.map(item => item.reason).filter(Boolean))
|
|
236
|
+
const disabledKinds = new Set(collisions
|
|
237
|
+
.filter(item => item.reason === 'function-class-redeclarations-disabled')
|
|
238
|
+
.map(item => item.kind))
|
|
110
239
|
const first = collisions[0]
|
|
240
|
+
const alternatives = [
|
|
241
|
+
...(disabledKinds.size === 2
|
|
242
|
+
? ['assign function or class expressions to the existing writable bindings']
|
|
243
|
+
: disabledKinds.has('function')
|
|
244
|
+
? ['assign a function expression to the existing writable binding']
|
|
245
|
+
: disabledKinds.has('class')
|
|
246
|
+
? ['assign a class expression to the existing writable binding']
|
|
247
|
+
: []),
|
|
248
|
+
...((reasons.size === 0 || [...reasons].some(reason => REUSE_BINDING_REASONS.has(reason)))
|
|
249
|
+
? ['reuse the existing bindings']
|
|
250
|
+
: []),
|
|
251
|
+
]
|
|
252
|
+
const help = [
|
|
253
|
+
...(reasons.has('binding-not-writable')
|
|
254
|
+
? ['use a fresh name because the existing binding is immutable']
|
|
255
|
+
: []),
|
|
256
|
+
...(alternatives.length === 0 ? [] : [alternatives.join('; ')]),
|
|
257
|
+
'place one-off declarations inside a block',
|
|
258
|
+
]
|
|
259
|
+
const reservedNote = reservedBindingNote(collisions)
|
|
111
260
|
return diagnostic({
|
|
112
261
|
code: 'PTC-N001',
|
|
113
262
|
severity: 'error',
|
|
114
263
|
phase: 'preflight',
|
|
115
|
-
message: `top-level bindings already exist: ${names.join(', ')}
|
|
264
|
+
message: `top-level bindings already exist: ${names.join(', ')}.${reservedNote} This cell was not executed; the REPL state is unchanged.`,
|
|
116
265
|
stateEffect: 'unchanged',
|
|
117
266
|
source: { cell: 'current', start: first.start, end: first.end },
|
|
118
|
-
help
|
|
119
|
-
|
|
120
|
-
'place one-off declarations inside a block',
|
|
121
|
-
],
|
|
267
|
+
help,
|
|
268
|
+
collisions: collisionRecords(collisions),
|
|
122
269
|
})
|
|
123
270
|
}
|
|
124
271
|
|
|
@@ -128,6 +275,8 @@ function exceptionDiagnostic({
|
|
|
128
275
|
position,
|
|
129
276
|
declared,
|
|
130
277
|
longCellFailure = false,
|
|
278
|
+
failureOrigin,
|
|
279
|
+
languageSemantics = 'legacy-v1',
|
|
131
280
|
}) {
|
|
132
281
|
const missingPath = error.name === 'ToolCallError' ? missingDescriptionPath(error) : undefined
|
|
133
282
|
const missingDescription = missingPath !== undefined
|
|
@@ -152,20 +301,24 @@ function exceptionDiagnostic({
|
|
|
152
301
|
...(cause === undefined ? {} : { cause }),
|
|
153
302
|
...(source === undefined ? {} : { source }),
|
|
154
303
|
help: [
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
304
|
+
'earlier statements or the failing operation may have caused effects; choose continuation using the operation owner\'s retry/idempotence contract and available execution facts; a thrown call or recorded-value replay does not prove a live retry is safe',
|
|
305
|
+
...(failureOrigin === 'lease'
|
|
306
|
+
? ['this REPL-captured capability reference belongs to an ended cell; obtain the member from the current program namespace, and have retained helpers resolve it at invocation']
|
|
307
|
+
: failureOrigin === 'capability'
|
|
308
|
+
? ['inspect the current capability with capabilities.tree(), capabilities.find(), or capabilities.inspect(); availability may have changed']
|
|
309
|
+
: missingDescription
|
|
310
|
+
? ['add a string `description` property to the nested native-tool argument object']
|
|
311
|
+
: []),
|
|
158
312
|
...(error.name === 'ToolCallError'
|
|
159
313
|
&& typeof error.toolName === 'string'
|
|
160
314
|
&& error.toolName.startsWith('cordis_')
|
|
161
315
|
? ['bindings assigned before this Cordis failure remain live; reuse them instead of resending large source']
|
|
162
|
-
:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
: ['use fresh names for one-off top-level bindings after partial execution; later declarations may be uninitialized']),
|
|
316
|
+
: longCellFailure
|
|
317
|
+
? ['inspect relevant live state in a new short `run_code` cell; edit_run_code executes the complete corrected cell, not only the failing expression']
|
|
318
|
+
: languageSemantics !== 'legacy-v1'
|
|
319
|
+
? ['completed declarations and actual assignments remain available; correct the failed initializer and continue with the same binding names']
|
|
320
|
+
: declared.size === 0 ? []
|
|
321
|
+
: ['use fresh names for one-off top-level bindings after partial execution; later declarations may be uninitialized']),
|
|
169
322
|
],
|
|
170
323
|
})
|
|
171
324
|
}
|
|
@@ -178,12 +331,18 @@ function invalidOutputDiagnostic(detail) {
|
|
|
178
331
|
message: `cell result could not cross the PTC Value V1 boundary: ${firstLine(detail, 'unknown output encoding failure')}`,
|
|
179
332
|
stateEffect: 'partially-applied',
|
|
180
333
|
help: [
|
|
181
|
-
'
|
|
334
|
+
'the worker remains live; inspect a retained binding in a later cell without rerunning the failed cell',
|
|
182
335
|
'reduce the returned graph when it exceeds the configured value budget',
|
|
183
336
|
],
|
|
184
337
|
})
|
|
185
338
|
}
|
|
186
339
|
|
|
340
|
+
/** Retain validated recorded wording while still comparing the actual failure. */
|
|
341
|
+
function replayFailureDiagnostic(actual, replay) {
|
|
342
|
+
const recorded = replay?.diagnostics?.find(item => item.code === actual.code)
|
|
343
|
+
return recorded?.message === actual.message ? recorded : actual
|
|
344
|
+
}
|
|
345
|
+
|
|
187
346
|
function stateArguments(value) {
|
|
188
347
|
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
189
348
|
throw new TypeError('repl.state expects an object')
|
|
@@ -217,24 +376,61 @@ export class SessionCellExecutor {
|
|
|
217
376
|
return result
|
|
218
377
|
}
|
|
219
378
|
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
379
|
+
let userBindings
|
|
380
|
+
const userBindingsShadowPolicy = replayRecord?.userBindingsShadowPolicy ?? LIVE_USER_BINDINGS_SHADOW_POLICY
|
|
381
|
+
const perNameUserBindings = userBindingsShadowPolicy === LIVE_USER_BINDINGS_SHADOW_POLICY
|
|
382
|
+
let userBindingBaseCatalog = kernel.bindingCatalog
|
|
383
|
+
let userBindingPlan
|
|
384
|
+
let userBindingFailures = []
|
|
385
|
+
try {
|
|
386
|
+
userBindings = request.userBindings === undefined
|
|
387
|
+
? undefined
|
|
388
|
+
: normalizeUserBindingsSnapshot(request.userBindings)
|
|
389
|
+
if (userBindings === undefined) {
|
|
390
|
+
const catalog = kernel.bindingCatalog.withoutUserBindings()
|
|
391
|
+
userBindingPlan = perNameUserBindings ? kernel.bindingCatalog.userBindings(undefined, undefined, userBindingsShadowPolicy) : {
|
|
392
|
+
catalog,
|
|
393
|
+
shadowedNames: catalog.inputs().knownBindings,
|
|
394
|
+
}
|
|
395
|
+
} else {
|
|
396
|
+
const activeEntryIds = new Set()
|
|
397
|
+
for (const entry of userBindings.entries) {
|
|
398
|
+
const names = entry.scope === 'namespace' ? [entry.name] : entry.symbols
|
|
399
|
+
const conflict = names.find(name => request.bindingDescriptors.reservedNames.has(name))
|
|
400
|
+
if (conflict === undefined) activeEntryIds.add(entry.id)
|
|
401
|
+
else {
|
|
402
|
+
userBindingFailures.push(Object.freeze({
|
|
403
|
+
id: entry.id,
|
|
404
|
+
error: `conflicts with request-owned program binding ${JSON.stringify(conflict)}`,
|
|
405
|
+
}))
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
userBindingPlan = kernel.bindingCatalog.userBindings(userBindings, activeEntryIds, userBindingsShadowPolicy)
|
|
409
|
+
}
|
|
410
|
+
} catch (error) {
|
|
411
|
+
const result = earlyResult('exception', `invalid user binding snapshot: ${messageOf(error)}`)
|
|
412
|
+
kernel.completeJournal(request.journal, 'noop', result)
|
|
413
|
+
return result
|
|
414
|
+
}
|
|
415
|
+
const priorBindingCatalog = userBindingPlan.catalog
|
|
416
|
+
const catalog = priorBindingCatalog.inputs()
|
|
417
|
+
const { bindingPolicy, rewritesEnabled, moduleSemantics, languageSemantics } = executionPolicies(config, replayRecord)
|
|
418
|
+
const prepareCell = program => prepareProgram(program, {
|
|
419
|
+
knownBindings: catalog.knownBindings,
|
|
420
|
+
bindingPolicy,
|
|
421
|
+
languageSemantics,
|
|
422
|
+
reservedBindings: request.bindingDescriptors.reservedNames,
|
|
234
423
|
rewritesEnabled,
|
|
235
|
-
catalog.importBindings,
|
|
236
|
-
catalog.importNamespaces,
|
|
237
|
-
|
|
424
|
+
importBindings: catalog.importBindings,
|
|
425
|
+
importNamespaces: catalog.importNamespaces,
|
|
426
|
+
writableBindings: catalog.writableBindings,
|
|
427
|
+
nativeBindings: catalog.nativeBindings,
|
|
428
|
+
nativeLexicalBindings: catalog.nativeLexicalBindings,
|
|
429
|
+
rootCandidates: catalog.rootCandidates,
|
|
430
|
+
dynamicOrigins: catalog.dynamicOrigins,
|
|
431
|
+
establishedRoots: catalog.establishedRoots,
|
|
432
|
+
moduleSemantics,
|
|
433
|
+
})
|
|
238
434
|
let prepared
|
|
239
435
|
try {
|
|
240
436
|
prepared = prepareCell(request.program)
|
|
@@ -280,7 +476,9 @@ export class SessionCellExecutor {
|
|
|
280
476
|
const result = earlyResult('abort', String(request.signal.reason))
|
|
281
477
|
kernel.completeJournal(request.journal, 'discarded', result)
|
|
282
478
|
kernel.rollbackToDurable()
|
|
283
|
-
|
|
479
|
+
// A refused reclamation stays recorded on the kernel so disposal remains
|
|
480
|
+
// observable instead of becoming an unhandled rejection after this abort.
|
|
481
|
+
kernel.resetWorker(worker)
|
|
284
482
|
return result
|
|
285
483
|
}
|
|
286
484
|
|
|
@@ -290,9 +488,9 @@ export class SessionCellExecutor {
|
|
|
290
488
|
const bindings = this.withControlBinding(request.bindingDescriptors, journal, replayRecord)
|
|
291
489
|
const id = ++kernel.sequence
|
|
292
490
|
return new Promise((resolve) => {
|
|
293
|
-
const started = worker.performance.eventLoopUtilization()
|
|
294
491
|
const active = {
|
|
295
492
|
id,
|
|
493
|
+
started: false,
|
|
296
494
|
request: { ...request, bindings: bindings.namespaces },
|
|
297
495
|
finish: resolve,
|
|
298
496
|
computeTimer: undefined,
|
|
@@ -321,40 +519,111 @@ export class SessionCellExecutor {
|
|
|
321
519
|
control: { names: new Set(kernel.history.checkpoints.keys()) },
|
|
322
520
|
rewrites: prepared.rewrites,
|
|
323
521
|
prepared,
|
|
324
|
-
priorBindingCatalog
|
|
522
|
+
priorBindingCatalog,
|
|
523
|
+
userBindingBaseCatalog,
|
|
524
|
+
userBindings,
|
|
525
|
+
userBindingsShadowPolicy,
|
|
526
|
+
userBindingFailures,
|
|
527
|
+
userBindingSnapshot: userBindings,
|
|
325
528
|
worker,
|
|
529
|
+
settled: false,
|
|
326
530
|
}
|
|
327
531
|
active.resolve = (result, terminate = false) => kernel.settleCell(active, result, terminate)
|
|
328
532
|
active.onAbort = () => active.resolve(
|
|
329
533
|
earlyResult('abort', String(request.signal?.reason)),
|
|
330
534
|
true,
|
|
331
535
|
)
|
|
332
|
-
active.
|
|
333
|
-
|
|
334
|
-
|
|
536
|
+
active.budgetsStarted = false
|
|
537
|
+
active.startBudgets = () => {
|
|
538
|
+
if (active.budgetsStarted) return active.budgetsReady
|
|
539
|
+
active.budgetsStarted = true
|
|
540
|
+
// The wall bound starts at the request, while the compute baseline is
|
|
541
|
+
// sampled from the worker instead of reusing the helper's last periodic
|
|
542
|
+
// cache. Work that completed before this request must not be charged to
|
|
543
|
+
// the new cell, and work after the sample must remain counted.
|
|
544
|
+
active.wallTimer = setTimeout(() => {
|
|
545
|
+
active.resolve(earlyResult('timeout', `wall-clock ceiling reached (${config.maxWallMs}ms); split long-running work into smaller cells`), true)
|
|
546
|
+
}, config.maxWallMs)
|
|
547
|
+
active.budgetsReady = (async () => {
|
|
548
|
+
let started
|
|
549
|
+
try {
|
|
550
|
+
started = await worker.sampleUtilization()
|
|
551
|
+
} catch (error) {
|
|
552
|
+
// No fresh baseline means this request cannot be measured. Use the
|
|
553
|
+
// existing worker-exit route instead of pretending the last cache
|
|
554
|
+
// sample is this request's starting point.
|
|
555
|
+
active.resolve(earlyResult('worker-exit', messageOf(error)), true)
|
|
556
|
+
return
|
|
557
|
+
}
|
|
558
|
+
if (active.settled) return
|
|
559
|
+
active.computeTimer = setInterval(() => {
|
|
560
|
+
if (active.settled) return
|
|
561
|
+
if (worker.performance.eventLoopUtilization(started).active > config.computeMs) {
|
|
562
|
+
active.resolve(earlyResult('timeout', `compute budget exhausted (${config.computeMs}ms event-loop active, including synchronous blocking); this measure does not establish CPU use or the specific cause. Use asynchronous waiting for long waits, or a DSH-owned managed job if available. This cell was discarded and the worker reset; external effects or processes may continue.`), true)
|
|
563
|
+
}
|
|
564
|
+
}, Math.min(100, config.computeMs))
|
|
565
|
+
})()
|
|
566
|
+
return active.budgetsReady
|
|
567
|
+
}
|
|
568
|
+
active.start = async () => {
|
|
569
|
+
if (active.started) return
|
|
570
|
+
active.started = true
|
|
571
|
+
kernel.workerObservation = undefined
|
|
572
|
+
await active.startBudgets()
|
|
573
|
+
if (active.settled) return
|
|
574
|
+
try {
|
|
575
|
+
kernel.client.post({
|
|
576
|
+
type: 'run', id, program: prepared.code, namespaces: bindings.workerDescriptors,
|
|
577
|
+
moduleLoads: prepared.moduleLoads,
|
|
578
|
+
languageSemantics,
|
|
579
|
+
rootRuntimeName: prepared.rootRuntimeName,
|
|
580
|
+
rootBindings: prepared.rootBindings,
|
|
581
|
+
importBindingNamespaces: new Map([...catalog.importBindings].map(([name, binding]) => [name, binding.namespace])),
|
|
582
|
+
preparedImportBindingNamespaces: new Map([...prepared.imports].map(([name, binding]) => [name, binding.namespace])),
|
|
583
|
+
returnSignal: prepared.returnSignal,
|
|
584
|
+
asyncCompletion: prepared.asyncCompletion,
|
|
585
|
+
commitSignal: prepared.commitSignal,
|
|
586
|
+
maxOutputBytes: config.maxOutputBytes,
|
|
587
|
+
valueLimits,
|
|
588
|
+
durability,
|
|
589
|
+
observeNames: replayRecord === undefined && kernel.observeValues()
|
|
590
|
+
? createReplMemorySnapshot(
|
|
591
|
+
priorBindingCatalog.advance(prepared, request.program).snapshot(),
|
|
592
|
+
).entries.map(entry => entry.name)
|
|
593
|
+
: [],
|
|
594
|
+
userBindings,
|
|
595
|
+
userBindingsShadowPolicy,
|
|
596
|
+
userBindingsReusePolicy: replayRecord === undefined
|
|
597
|
+
? LIVE_USER_BINDINGS_REUSE_POLICY
|
|
598
|
+
: replayRecord.userBindingsReusePolicy,
|
|
599
|
+
...(userBindings === undefined ? {} : { userBindingsCwd: kernel.userBindingsCwd }),
|
|
600
|
+
userBindingFailures,
|
|
601
|
+
shadowedUserBindingNames: [...new Set([
|
|
602
|
+
...userBindingPlan.shadowedNames,
|
|
603
|
+
...request.bindingDescriptors.reservedNames,
|
|
604
|
+
])],
|
|
605
|
+
})
|
|
606
|
+
} catch (error) {
|
|
607
|
+
active.resolve(earlyResult('worker-exit', messageOf(error)), true)
|
|
335
608
|
}
|
|
336
|
-
}
|
|
337
|
-
active.wallTimer = setTimeout(() => {
|
|
338
|
-
active.resolve(earlyResult('timeout', `wall-clock ceiling reached (${config.maxWallMs}ms); split long-running work into smaller cells`), true)
|
|
339
|
-
}, config.maxWallMs)
|
|
609
|
+
}
|
|
340
610
|
kernel.active = active
|
|
341
611
|
request.signal?.addEventListener('abort', active.onAbort, { once: true })
|
|
342
612
|
if (request.signal?.aborted) {
|
|
343
613
|
active.onAbort()
|
|
344
614
|
return
|
|
345
615
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
616
|
+
void (async () => {
|
|
617
|
+
try {
|
|
618
|
+
// Only worker-confirmed observation may defer these budgets; never restart them.
|
|
619
|
+
if (kernel.workerObservation?.worker !== worker
|
|
620
|
+
|| kernel.workerObservation.started !== true) await active.startBudgets()
|
|
621
|
+
if (active.settled) return
|
|
622
|
+
kernel.client.post({ type: 'prepare', id })
|
|
623
|
+
} catch (error) {
|
|
624
|
+
active.resolve(earlyResult('worker-exit', messageOf(error)), true)
|
|
625
|
+
}
|
|
626
|
+
})()
|
|
358
627
|
})
|
|
359
628
|
}
|
|
360
629
|
|
|
@@ -375,7 +644,7 @@ export class SessionCellExecutor {
|
|
|
375
644
|
reservedNames: bindingDescriptors.reservedNames,
|
|
376
645
|
workerDescriptors: Object.freeze([
|
|
377
646
|
...bindingDescriptors.workerDescriptors,
|
|
378
|
-
|
|
647
|
+
...normalizeBindingDescriptors([namespace]).workerDescriptors,
|
|
379
648
|
]),
|
|
380
649
|
})
|
|
381
650
|
}
|
|
@@ -413,6 +682,30 @@ export class SessionCellExecutor {
|
|
|
413
682
|
}
|
|
414
683
|
|
|
415
684
|
onMessage(message) {
|
|
685
|
+
if (message?.type === 'observation-started') {
|
|
686
|
+
const kernel = this.kernel
|
|
687
|
+
const observation = kernel.workerObservation
|
|
688
|
+
if (observation !== undefined && observation.id === message.id
|
|
689
|
+
&& observation.worker === kernel.client.worker) observation.started = true
|
|
690
|
+
return
|
|
691
|
+
}
|
|
692
|
+
if (message?.type === 'ready') {
|
|
693
|
+
const inspection = this.kernel.pendingInspection
|
|
694
|
+
if (inspection !== undefined && inspection.id === message.id) inspection.start()
|
|
695
|
+
const active = this.kernel.active
|
|
696
|
+
if (active !== undefined && active.id === message.id) void active.start()
|
|
697
|
+
return
|
|
698
|
+
}
|
|
699
|
+
if (message?.type === 'observation') {
|
|
700
|
+
const kernel = this.kernel
|
|
701
|
+
const observation = kernel.workerObservation
|
|
702
|
+
if (observation !== undefined && observation.id === message.id) {
|
|
703
|
+
kernel.workerObservation = undefined
|
|
704
|
+
if (kernel.active?.worker === observation.worker) kernel.active.startBudgets()
|
|
705
|
+
}
|
|
706
|
+
kernel.finishObservation(message)
|
|
707
|
+
return
|
|
708
|
+
}
|
|
416
709
|
if (message === null || typeof message !== 'object') return
|
|
417
710
|
const handler = {
|
|
418
711
|
volatile: this.handleVolatile,
|
|
@@ -472,6 +765,53 @@ export class SessionCellExecutor {
|
|
|
472
765
|
active.resolve({ logs, error: { kind: 'recovery', message: 'session log replay consumed a different host-call transcript' } }, true)
|
|
473
766
|
return
|
|
474
767
|
}
|
|
768
|
+
let activatedUserBindings
|
|
769
|
+
const perNameUserBindings = active.userBindingsShadowPolicy === LIVE_USER_BINDINGS_SHADOW_POLICY
|
|
770
|
+
try {
|
|
771
|
+
if (active.userBindings === undefined) {
|
|
772
|
+
active.userBindingSnapshot = undefined
|
|
773
|
+
active.priorBindingCatalog = active.userBindingBaseCatalog.withoutUserBindings()
|
|
774
|
+
} else {
|
|
775
|
+
const ids = Array.isArray(message.activatedUserBindings)
|
|
776
|
+
&& message.activatedUserBindings.every(id => typeof id === 'string')
|
|
777
|
+
? new Set(message.activatedUserBindings)
|
|
778
|
+
: undefined
|
|
779
|
+
if (ids === undefined || ids.size !== message.activatedUserBindings.length) {
|
|
780
|
+
throw new TypeError('kernel returned an invalid activated user binding set')
|
|
781
|
+
}
|
|
782
|
+
const expected = new Set(active.userBindings.entries.map(entry => entry.id))
|
|
783
|
+
if ([...ids].some(id => !expected.has(id))) {
|
|
784
|
+
throw new TypeError('kernel activated an unknown user binding entry')
|
|
785
|
+
}
|
|
786
|
+
if (perNameUserBindings) validateUserBindingActivation(active, message, ids)
|
|
787
|
+
activatedUserBindings = selectUserBindingsSnapshot(active.userBindings, ids)
|
|
788
|
+
active.userBindingSnapshot = activatedUserBindings
|
|
789
|
+
active.priorBindingCatalog = active.userBindingBaseCatalog.userBindings(active.userBindings, ids, active.userBindingsShadowPolicy).catalog
|
|
790
|
+
if (!perNameUserBindings) {
|
|
791
|
+
const shadowed = Array.isArray(message.shadowedUserBindings)
|
|
792
|
+
&& message.shadowedUserBindings.every(name => typeof name === 'string')
|
|
793
|
+
? new Set(message.shadowedUserBindings)
|
|
794
|
+
: undefined
|
|
795
|
+
const activeNames = new Set(activatedUserBindings.entries.flatMap(entry => (
|
|
796
|
+
entry.scope === 'namespace' ? [entry.name] : entry.symbols
|
|
797
|
+
)))
|
|
798
|
+
if (shadowed === undefined || shadowed.size !== message.shadowedUserBindings.length
|
|
799
|
+
|| [...shadowed].some(name => !activeNames.has(name))) {
|
|
800
|
+
throw new TypeError('kernel returned an invalid shadowed user binding set')
|
|
801
|
+
}
|
|
802
|
+
active.priorBindingCatalog = active.priorBindingCatalog.shadowUserBindings(shadowed)
|
|
803
|
+
}
|
|
804
|
+
if (active.replay !== undefined
|
|
805
|
+
&& activatedUserBindings.fingerprint !== active.userBindings.fingerprint) {
|
|
806
|
+
active.resolve({ logs, error: { kind: 'recovery', message: 'recorded user bindings could not be reactivated' } }, true)
|
|
807
|
+
return
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
if (perNameUserBindings) active.userBindingNames = completedUserBindingNames(active, message, activatedUserBindings)
|
|
811
|
+
} catch (error) {
|
|
812
|
+
active.resolve(earlyResult('worker-exit', messageOf(error)), true)
|
|
813
|
+
return
|
|
814
|
+
}
|
|
475
815
|
const bytes = Buffer.byteLength(JSON.stringify({ logs, value: message.value }), 'utf8')
|
|
476
816
|
if (bytes > active.config.maxOutputBytes) {
|
|
477
817
|
active.resolve({
|
|
@@ -480,6 +820,29 @@ export class SessionCellExecutor {
|
|
|
480
820
|
}, true)
|
|
481
821
|
return
|
|
482
822
|
}
|
|
823
|
+
let committed
|
|
824
|
+
let rootBindingFacts
|
|
825
|
+
try {
|
|
826
|
+
committed = committedRedeclarationSet(message, active.prepared)
|
|
827
|
+
rootBindingFacts = completedRootBindingFacts(message, active.prepared, committed)
|
|
828
|
+
} catch (error) {
|
|
829
|
+
active.resolve(earlyResult('worker-exit', messageOf(error)), true)
|
|
830
|
+
return
|
|
831
|
+
}
|
|
832
|
+
active.appliedBindingCatalog = message.moduleLoadFailed === true
|
|
833
|
+
? active.priorBindingCatalog
|
|
834
|
+
: active.priorBindingCatalog.advance(
|
|
835
|
+
active.prepared,
|
|
836
|
+
active.request.program,
|
|
837
|
+
committed,
|
|
838
|
+
rootBindingFacts,
|
|
839
|
+
)
|
|
840
|
+
if (perNameUserBindings) {
|
|
841
|
+
active.appliedBindingCatalog = active.appliedBindingCatalog.reconcileUserBindingNames(
|
|
842
|
+
activatedUserBindings, active.userBindingNames, active.request.program,
|
|
843
|
+
)
|
|
844
|
+
}
|
|
845
|
+
active.observing = message.observing === true
|
|
483
846
|
if (typeof message.error === 'string') {
|
|
484
847
|
const rawError = {
|
|
485
848
|
kind: 'exception',
|
|
@@ -490,33 +853,38 @@ export class SessionCellExecutor {
|
|
|
490
853
|
const actualFailure = exceptionDiagnostic({
|
|
491
854
|
error: rawError,
|
|
492
855
|
cause: message.cause,
|
|
856
|
+
// A diagnostic caret must exist in the submitted cell. A native frame
|
|
857
|
+
// is mapped first; an unmappable frame falls back to the recorded
|
|
858
|
+
// source origin rather than attaching an out-of-range position.
|
|
493
859
|
position: message.moduleLoadFailed === true
|
|
494
|
-
? message.position
|
|
495
|
-
:
|
|
496
|
-
|
|
497
|
-
|
|
860
|
+
? cellPosition(message.position, active.request.program)
|
|
861
|
+
: cellPosition(
|
|
862
|
+
mapSourcePosition(
|
|
863
|
+
message.position,
|
|
864
|
+
active.prepared.code,
|
|
865
|
+
active.request.program,
|
|
866
|
+
active.prepared.sourceMap,
|
|
867
|
+
),
|
|
498
868
|
active.request.program,
|
|
499
|
-
|
|
500
|
-
),
|
|
869
|
+
) ?? exceptionOriginPosition(message.exceptionOrigins, active.request.program),
|
|
501
870
|
declared: message.moduleLoadFailed === true ? new Set() : active.prepared.declared,
|
|
871
|
+
languageSemantics: active.prepared.languageSemantics,
|
|
502
872
|
longCellFailure: active.request.program.length >= LONG_CELL_CODE_UNITS,
|
|
873
|
+
failureOrigin: message.failureOrigin,
|
|
503
874
|
})
|
|
504
|
-
|
|
505
|
-
? active.priorBindingCatalog
|
|
506
|
-
: active.priorBindingCatalog.advance(active.prepared, active.request.program)
|
|
507
|
-
const recordedFailure = active.replay?.diagnostics?.find(item => item.code === 'PTC-X001')
|
|
508
|
-
const failure = recordedFailure?.message === actualFailure.message ? recordedFailure : actualFailure
|
|
875
|
+
const failure = replayFailureDiagnostic(actualFailure, active.replay)
|
|
509
876
|
const error = {
|
|
510
877
|
kind: 'exception',
|
|
511
878
|
message: renderDiagnostic(failure, active.request.program),
|
|
512
879
|
}
|
|
513
880
|
if (isBindingReferenceError(rawError)) markBindingFailure(error)
|
|
881
|
+
else if (message.failureOrigin === 'capability') markBindingFailure(error, 'capability')
|
|
514
882
|
active.diagnostics.push(failure)
|
|
515
883
|
active.resolve({ logs, error })
|
|
516
884
|
return
|
|
517
885
|
}
|
|
518
886
|
if (typeof message.invalidOutput === 'string') {
|
|
519
|
-
const failure = invalidOutputDiagnostic(message.invalidOutput)
|
|
887
|
+
const failure = replayFailureDiagnostic(invalidOutputDiagnostic(message.invalidOutput), active.replay)
|
|
520
888
|
const error = { kind: 'invalid-output', message: renderDiagnostic(failure, active.request.program) }
|
|
521
889
|
active.diagnostics.push(failure)
|
|
522
890
|
active.resolve({ logs, error })
|
|
@@ -527,27 +895,23 @@ export class SessionCellExecutor {
|
|
|
527
895
|
|| (message.hasValue ? message.value === undefined : message.value !== undefined)) {
|
|
528
896
|
throw new TypeError('invalid PTC completion envelope')
|
|
529
897
|
}
|
|
530
|
-
const
|
|
898
|
+
const completion = message.hasValue ? prepareValueWire(message.value, active.valueLimits) : undefined
|
|
531
899
|
active.completion = {
|
|
532
900
|
hasValue: message.hasValue,
|
|
533
|
-
...(message.hasValue ? { value } : {}),
|
|
901
|
+
...(message.hasValue ? { value: completion.wire } : {}),
|
|
534
902
|
}
|
|
535
|
-
active.appliedBindingCatalog = active.priorBindingCatalog.advance(
|
|
536
|
-
active.prepared,
|
|
537
|
-
active.request.program,
|
|
538
|
-
)
|
|
539
903
|
if (active.replay?.completion?.kind === 'return'
|
|
540
904
|
&& (active.replay.completion.hasValue !== message.hasValue
|
|
541
|
-
|| (message.hasValue && !valueWiresEqual(active.replay.completion.value,
|
|
905
|
+
|| (message.hasValue && !valueWiresEqual(active.replay.completion.value, completion.wire, active.valueLimits)))) {
|
|
542
906
|
active.resolve({ logs, error: { kind: 'recovery', message: 'cell replay produced a different completion value' } }, true)
|
|
543
907
|
return
|
|
544
908
|
}
|
|
545
909
|
active.resolve({
|
|
546
910
|
logs,
|
|
547
|
-
...(message.hasValue ? { value:
|
|
911
|
+
...(message.hasValue ? { value: completion.projectedValue } : {}),
|
|
548
912
|
})
|
|
549
913
|
} catch (error) {
|
|
550
|
-
const failure = invalidOutputDiagnostic(messageOf(error))
|
|
914
|
+
const failure = replayFailureDiagnostic(invalidOutputDiagnostic(messageOf(error)), active.replay)
|
|
551
915
|
const invalid = { kind: 'invalid-output', message: renderDiagnostic(failure, active.request.program) }
|
|
552
916
|
active.diagnostics.push(failure)
|
|
553
917
|
active.resolve({ logs, error: invalid })
|