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.
- package/README.en.md +63 -80
- package/README.md +63 -80
- 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 +30827 -742
- 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 +556 -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 +7 -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 +5 -3
- package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
- 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 +3 -1
- package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
- 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 +5 -3
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
- package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
- 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 +77 -21
- package/docs/binding-review-placement-design.md +200 -0
- package/docs/capability-projection.md +1 -1
- package/docs/client-ui.md +95 -19
- package/docs/durability-design.md +28 -10
- package/docs/evaluation.md +78 -6
- package/docs/installation.md +41 -6
- package/docs/publishing.md +5 -3
- package/docs/runtime-reference.md +76 -25
- package/docs/semantic-validation.md +29 -0
- package/docs/stateful-binding-updates-proposal.md +759 -0
- package/docs/user-bindings.en.md +66 -0
- package/docs/user-bindings.md +66 -0
- package/docs/value-wire.md +3 -3
- package/docs/verification-optimization-work.md +41 -0
- package/docs/verification.md +71 -0
- package/index.js +369 -92
- package/internal/ast-traversal.js +5 -2
- package/internal/async-local-storage-intrinsics.js +38 -0
- package/internal/binding-declaration-contract.js +8 -0
- 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 +708 -0
- package/internal/binding-update-policy.js +72 -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 +253 -290
- 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 -677
- 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 +50 -0
- package/internal/compiler-module-links.js +37 -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 +83 -27
- 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 +91 -0
- package/internal/dynamic-environment-runtime.js +383 -0
- package/internal/dynamic-native-calls.js +153 -0
- package/internal/dynamic-native-runtime.js +262 -0
- package/internal/dynamic-scope-analysis.js +90 -0
- package/internal/edit-transport-owner.js +27 -2
- package/internal/execution-seam-compat.js +193 -0
- package/internal/failure-reporting.js +136 -28
- package/internal/host-rpc.js +66 -0
- package/internal/isolated-worker.js +555 -0
- package/internal/kernel-child.js +139 -0
- package/internal/kernel-worker.js +1179 -233
- 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 +322 -0
- package/internal/module-runtime-platform.js +19 -0
- package/internal/module-transform-contract.js +42 -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/record-utils.js +24 -15
- package/internal/recovery-tips.js +27 -15
- package/internal/rejected-cell-editor.js +13 -8
- package/internal/repl-convenience.js +2 -289
- package/internal/repl-memory-projection.js +81 -12
- package/internal/repl-observation-interest.js +70 -0
- package/internal/repl-rewrite-contract.js +6 -0
- package/internal/repl-scope-normalizer.js +2091 -0
- package/internal/repl-value-observer.js +117 -0
- package/internal/rpc-contract.js +52 -0
- package/internal/runtime-bridge-owner.js +172 -28
- package/internal/runtime-config.js +48 -52
- package/internal/runtime-contexts.js +82 -10
- package/internal/runtime-intrinsics.js +101 -0
- package/internal/runtime-messages.js +111 -0
- package/internal/session-cell-executor.js +402 -87
- package/internal/session-journal-recovery.js +684 -0
- package/internal/session-journal-schema.js +123 -0
- package/internal/session-journal.js +199 -654
- package/internal/session-log-view.js +42 -9
- package/internal/session-runtime.js +257 -95
- package/internal/session-state.js +247 -71
- package/internal/source-position-map.js +230 -71
- package/internal/stateful-module-compiler.js +154 -0
- package/internal/stateful-module-runtime.js +303 -0
- package/internal/stateful-root-compiler.js +600 -0
- package/internal/stateful-root-runtime.js +340 -0
- package/internal/typert-codec-compat.js +28 -0
- package/internal/typescript-transform.js +31 -0
- package/internal/user-binding-authoring.js +70 -0
- package/internal/user-binding-console-worker.js +244 -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 +361 -0
- package/internal/value-wire-schema.js +28 -0
- package/internal/value-wire.js +130 -91
- package/internal/worker-client.js +57 -67
- package/internal/worker-cwd-virtualization.js +80 -53
- package/internal/worker-environment.js +65 -0
- package/internal/worker-output-relay.js +29 -0
- package/internal/worker-repl-realm.js +134 -0
- package/internal/worker-shutdown.js +14 -0
- package/package.json +76 -7
- package/src/client-activity.js +95 -53
- 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
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/** Session logical identities, independent of the native cell's lexical frame. */
|
|
2
|
+
import { createDynamicEnvironmentRuntime } from './dynamic-environment-runtime.js'
|
|
3
|
+
import { captureCompilerIntrinsics, moduleRuntimeIntrinsics as internal } from './compiler-intrinsics.js'
|
|
4
|
+
|
|
5
|
+
const { Map, Set, Object, Proxy, mapGet, mapSet, mapHas, mapClear, mapForEach,
|
|
6
|
+
setHas, setAdd, includes, appendArray, stringify } = internal
|
|
7
|
+
|
|
8
|
+
export function createStatefulRootRuntime({ readAmbient, typeofAmbient, writeAmbient, deleteAmbient,
|
|
9
|
+
canWriteAmbient = () => true,
|
|
10
|
+
errors,
|
|
11
|
+
dynamicIntrinsics, importModule = (source, options) => import(source, options),
|
|
12
|
+
hasOverlay = () => false, hasAmbient, publish = () => {}, changed = () => {}, refresh = () => {} }) {
|
|
13
|
+
const entries = new Map()
|
|
14
|
+
const intrinsics = captureCompilerIntrinsics(dynamicIntrinsics?.realmFunction)
|
|
15
|
+
errors ??= intrinsics
|
|
16
|
+
const dynamicRuntime = createDynamicEnvironmentRuntime({ ...dynamicIntrinsics, importModule })
|
|
17
|
+
const moduleRuntime = dynamicIntrinsics === undefined ? undefined : createDynamicEnvironmentRuntime()
|
|
18
|
+
let commit
|
|
19
|
+
const read = name => {
|
|
20
|
+
refresh(name)
|
|
21
|
+
const entry = mapGet(entries, name)
|
|
22
|
+
return hasOverlay(name) || entry === undefined || entry.object === true || entry.deleted === true
|
|
23
|
+
? readAmbient(name) : entry.read === undefined ? entry.value : entry.read()
|
|
24
|
+
}
|
|
25
|
+
const storeValue = (name, value, { source = 'local', readOnly = false, declaration = false,
|
|
26
|
+
strict = false, target, nativeKind } = {}) => {
|
|
27
|
+
refresh(name)
|
|
28
|
+
const previous = mapGet(entries, name)
|
|
29
|
+
if (hasOverlay(name)) {
|
|
30
|
+
// A hard request overlay is not shadowable, so this store cannot publish a session identity.
|
|
31
|
+
// A declaration is the overlay's own pre-emption and stays absorbed; an actual write that the
|
|
32
|
+
// ambient property cannot accept must fail observably instead of being discarded.
|
|
33
|
+
if (!declaration && !canWriteAmbient(name)) {
|
|
34
|
+
throw new errors.TypeError(`${name} cannot be overwritten because reserved program bindings are not shadowable`)
|
|
35
|
+
}
|
|
36
|
+
writeAmbient(name, value, strict)
|
|
37
|
+
return undefined
|
|
38
|
+
}
|
|
39
|
+
if (!declaration && (previous === undefined || previous.object === true || previous.deleted === true) && writeAmbient !== undefined) {
|
|
40
|
+
writeAmbient(name, value, strict)
|
|
41
|
+
mapSet(entries, name, { source, object: true, ...(previous?.legacyWritable === true ? { legacyWritable: true } : {}) })
|
|
42
|
+
} else if (previous?.legacyWritable === true && writeAmbient !== undefined
|
|
43
|
+
&& (previous.object !== true || canWriteAmbient(name))) {
|
|
44
|
+
writeAmbient(name, value)
|
|
45
|
+
mapSet(entries, name, { ...previous, source, readOnly })
|
|
46
|
+
} else mapSet(entries, name, { value, source, readOnly, ...(previous?.nativeKind === undefined ? {} : { nativeKind: previous.nativeKind }) })
|
|
47
|
+
const writeTarget = target ?? (declaration ? undefined : previous?.writeTarget)
|
|
48
|
+
const entry = mapGet(entries, name)
|
|
49
|
+
delete entry.writeTarget
|
|
50
|
+
if (writeTarget !== undefined) entry.writeTarget = writeTarget
|
|
51
|
+
if (nativeKind !== undefined) entry.nativeKind = nativeKind
|
|
52
|
+
return entry
|
|
53
|
+
}
|
|
54
|
+
const write = (name, value, options) => {
|
|
55
|
+
const entry = storeValue(name, value, options)
|
|
56
|
+
if (entry === undefined) return value
|
|
57
|
+
if (entry.object !== true) publish(name, () => read(name), value => write(name, value))
|
|
58
|
+
changed(name, entry.source)
|
|
59
|
+
return value
|
|
60
|
+
}
|
|
61
|
+
const begin = ({ declared = [], known = [], readOnly = [], legacyImports = [], legacyWritable = [], legacyLexicals = [], legacyObjects = [],
|
|
62
|
+
declarationKinds = [], declaredKinds = [], callableSources = [], languageSemantics = 'stateful-v1', committed }) => {
|
|
63
|
+
dynamicRuntime.registerSources(callableSources)
|
|
64
|
+
commit = committed
|
|
65
|
+
const kinds = new Map()
|
|
66
|
+
for (let index = 0; index < declarationKinds.length; index++) mapSet(kinds, declarationKinds[index][0], declarationKinds[index][1])
|
|
67
|
+
for (let index = 0; index < legacyImports.length; index++) {
|
|
68
|
+
const name = legacyImports[index][0], binding = legacyImports[index][1]
|
|
69
|
+
if (!mapHas(entries, name)) mapSet(entries, name, { source: 'import', read: () => {
|
|
70
|
+
const namespace = readAmbient(binding.namespace)
|
|
71
|
+
return binding.imported === undefined ? namespace : namespace[binding.imported]
|
|
72
|
+
} })
|
|
73
|
+
}
|
|
74
|
+
for (let index = 0; index < legacyWritable.length; index++) {
|
|
75
|
+
const name = legacyWritable[index]
|
|
76
|
+
if (!mapHas(entries, name)) mapSet(entries, name, { source: 'local', legacyWritable: true,
|
|
77
|
+
...(includes(legacyObjects, name) ? { object: true } : {}), read: () => readAmbient(name) })
|
|
78
|
+
}
|
|
79
|
+
for (let index = 0; index < legacyLexicals.length; index++) {
|
|
80
|
+
const name = legacyLexicals[index]
|
|
81
|
+
if (!mapHas(entries, name)) mapSet(entries, name, { source: 'local', readOnly: true, read: () => readAmbient(name) })
|
|
82
|
+
}
|
|
83
|
+
const protectedNames = new Set()
|
|
84
|
+
if (languageSemantics === 'protected-v1') {
|
|
85
|
+
for (let index = 0; index < readOnly.length; index++) setAdd(protectedNames, readOnly[index])
|
|
86
|
+
mapForEach(entries, (entry, name) => { if (entry.readOnly) setAdd(protectedNames, name) })
|
|
87
|
+
}
|
|
88
|
+
const fresh = new Set()
|
|
89
|
+
for (let index = 0; index < declared.length; index++) {
|
|
90
|
+
const name = declared[index]
|
|
91
|
+
if (!mapHas(entries, name) && !includes(known, name)) setAdd(fresh, name)
|
|
92
|
+
}
|
|
93
|
+
const checkInitialized = name => {
|
|
94
|
+
if (!hasOverlay(name) && setHas(fresh, name) && !mapHas(entries, name)) throw new errors.ReferenceError(`Cannot access '${name}' before initialization`)
|
|
95
|
+
}
|
|
96
|
+
const get = name => {
|
|
97
|
+
checkInitialized(name)
|
|
98
|
+
return read(name)
|
|
99
|
+
}
|
|
100
|
+
const checkWritable = name => {
|
|
101
|
+
if (languageSemantics === 'protected-v1') checkInitialized(name)
|
|
102
|
+
if (languageSemantics === 'protected-v1' && (setHas(protectedNames, name) || mapGet(entries, name)?.readOnly === true)) {
|
|
103
|
+
throw new errors.TypeError('Assignment to constant variable.')
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
const needsDeclaration = name => {
|
|
107
|
+
const entry = mapGet(entries, name)
|
|
108
|
+
return entry === undefined && (setHas(fresh, name) || hasAmbient !== undefined && !hasAmbient(name))
|
|
109
|
+
|| (entry?.object === true || entry?.deleted === true) && !hasAmbient(name)
|
|
110
|
+
}
|
|
111
|
+
const remove = name => {
|
|
112
|
+
const entry = mapGet(entries, name)
|
|
113
|
+
if (hasOverlay(name) || entry?.object || entry?.deleted || entry === undefined && !setHas(fresh, name)) return deleteAmbient(name)
|
|
114
|
+
if (entry?.nativeKind !== 'eval-var') return false
|
|
115
|
+
mapSet(entries, name, { ...entry, deleted: true })
|
|
116
|
+
return true
|
|
117
|
+
}
|
|
118
|
+
const values = new Proxy(Object.create(null), {
|
|
119
|
+
get: (_, name) => get(name),
|
|
120
|
+
set: (_, name, value) => {
|
|
121
|
+
checkWritable(name)
|
|
122
|
+
write(name, value)
|
|
123
|
+
return true
|
|
124
|
+
},
|
|
125
|
+
deleteProperty: (_, name) => remove(name),
|
|
126
|
+
})
|
|
127
|
+
const result = {
|
|
128
|
+
values,
|
|
129
|
+
intrinsics,
|
|
130
|
+
importModule,
|
|
131
|
+
dynamic({ realm = false } = {}) {
|
|
132
|
+
const pendingKinds = new Map()
|
|
133
|
+
for (let index = 0; index < declaredKinds.length; index++) mapSet(pendingKinds, declaredKinds[index][0], declaredKinds[index][1])
|
|
134
|
+
const kindFor = name => {
|
|
135
|
+
const entry = mapGet(entries, name)
|
|
136
|
+
if (hasOverlay(name) || entry?.deleted) return undefined
|
|
137
|
+
if (entry?.object || entry === undefined && realm && !setHas(fresh, name)) return realm && hasAmbient(name) ? 'var' : undefined
|
|
138
|
+
return entry === undefined ? setHas(fresh, name) ? mapGet(pendingKinds, name) ?? 'let' : undefined : entry.nativeKind ?? 'let'
|
|
139
|
+
}
|
|
140
|
+
const variableKind = kind => includes(['var', 'eval-var', 'hoisted'], kind)
|
|
141
|
+
const descriptor = (name, kind) => ({
|
|
142
|
+
kind,
|
|
143
|
+
get: () => get(name),
|
|
144
|
+
set(value, strict, origin, writeTarget) {
|
|
145
|
+
result.reference(name, strict, writeTarget ?? (origin === undefined ? undefined : `${origin}:${stringify(name)}`)).value = value
|
|
146
|
+
},
|
|
147
|
+
delete() {
|
|
148
|
+
const entry = mapGet(entries, name)
|
|
149
|
+
if (realm && (entry === undefined || entry.object)) return delete values[name]
|
|
150
|
+
return remove(name)
|
|
151
|
+
},
|
|
152
|
+
})
|
|
153
|
+
const lexicalFrame = { has: name => kindFor(name) !== undefined && !variableKind(kindFor(name)),
|
|
154
|
+
get: name => lexicalFrame.has(name) ? descriptor(name, kindFor(name)) : undefined }
|
|
155
|
+
const varFrame = { has: name => variableKind(kindFor(name)), get: name => varFrame.has(name) ? descriptor(name, 'var') : undefined,
|
|
156
|
+
set() {} }
|
|
157
|
+
return dynamicRuntime.environment({
|
|
158
|
+
varFrame, frames: [{ kind: 'lexical', bindings: lexicalFrame }],
|
|
159
|
+
declareVars: realm ? (names, functionNames) => {
|
|
160
|
+
const globals = []
|
|
161
|
+
for (let index = 0; index < names.length; index++) {
|
|
162
|
+
const name = names[index], entry = mapGet(entries, name)
|
|
163
|
+
if (hasOverlay(name) || entry === undefined || entry.object === true || entry.deleted === true) appendArray(globals, name)
|
|
164
|
+
}
|
|
165
|
+
dynamicRuntime.declareGlobals(globals, functionNames)
|
|
166
|
+
} : undefined,
|
|
167
|
+
ambient(name, strict, origin, writeTarget) {
|
|
168
|
+
return dynamicRuntime.reference(name, {
|
|
169
|
+
get: () => get(name),
|
|
170
|
+
set: value => { result.reference(name, strict, writeTarget ?? (origin === undefined ? undefined : `${origin}:${stringify(name)}`)).value = value },
|
|
171
|
+
typeof: () => result.typeof(name),
|
|
172
|
+
delete: () => delete values[name],
|
|
173
|
+
}, undefined, strict)
|
|
174
|
+
},
|
|
175
|
+
createVar(name, origin) {
|
|
176
|
+
if (!mapHas(entries, name) || mapGet(entries, name).object || mapGet(entries, name).deleted) {
|
|
177
|
+
// A hard overlay pre-empts a realm-level var declaration, so that declaration is
|
|
178
|
+
// absorbed instead of being written through to a property the ambient cannot accept.
|
|
179
|
+
write(name, undefined, { declaration: !realm || hasOverlay(name), nativeKind: 'eval-var',
|
|
180
|
+
target: origin === undefined ? undefined : `${origin}:${stringify(name)}` })
|
|
181
|
+
}
|
|
182
|
+
return descriptor(name, 'var')
|
|
183
|
+
},
|
|
184
|
+
})
|
|
185
|
+
},
|
|
186
|
+
typeof(name) {
|
|
187
|
+
// Native typeof distinguishes an unresolvable reference from any error
|
|
188
|
+
// thrown by resolving a getter, including errors from another realm.
|
|
189
|
+
if (hasOverlay(name) || !mapHas(entries, name) && !setHas(fresh, name)
|
|
190
|
+
|| mapGet(entries, name)?.object === true || mapGet(entries, name)?.deleted === true) return typeofAmbient(name)
|
|
191
|
+
return typeof get(name)
|
|
192
|
+
},
|
|
193
|
+
declare(name, target) {
|
|
194
|
+
if (needsDeclaration(name)) {
|
|
195
|
+
write(name, undefined, { readOnly: setHas(protectedNames, name), declaration: true,
|
|
196
|
+
nativeKind: mapGet(kinds, target) ?? 'var' })
|
|
197
|
+
commit(target)
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
assign(name, value, target) {
|
|
201
|
+
write(name, value, { readOnly: setHas(protectedNames, name), declaration: true,
|
|
202
|
+
nativeKind: mapGet(kinds, target) ?? 'let' })
|
|
203
|
+
commit(target)
|
|
204
|
+
return value
|
|
205
|
+
},
|
|
206
|
+
reference(name, strict, target) {
|
|
207
|
+
return new Proxy(Object.create(null), {
|
|
208
|
+
get: () => get(name),
|
|
209
|
+
set: (_, key, value) => {
|
|
210
|
+
checkWritable(name)
|
|
211
|
+
write(name, value, { strict, target })
|
|
212
|
+
return true
|
|
213
|
+
},
|
|
214
|
+
})
|
|
215
|
+
},
|
|
216
|
+
import(name, namespace, imported, target) {
|
|
217
|
+
mapSet(entries, name, { source: 'import', nativeKind: 'const', readOnly: setHas(protectedNames, name), read: () => imported === null ? namespace : namespace[imported] })
|
|
218
|
+
publish(name, () => read(name), value => write(name, value))
|
|
219
|
+
changed(name, 'import')
|
|
220
|
+
commit(target)
|
|
221
|
+
},
|
|
222
|
+
link(name, linked, target) {
|
|
223
|
+
if (name !== linked) {
|
|
224
|
+
mapSet(entries, name, { source: 'local', read: () => read(linked) })
|
|
225
|
+
publish(name, () => read(name), value => write(name, value))
|
|
226
|
+
changed(name, 'local')
|
|
227
|
+
}
|
|
228
|
+
commit(target)
|
|
229
|
+
},
|
|
230
|
+
candidate(names) {
|
|
231
|
+
const pending = new Map()
|
|
232
|
+
let published = false
|
|
233
|
+
// Pattern targets initialize values; source references enforce writes.
|
|
234
|
+
const values = new Proxy(Object.create(null), {
|
|
235
|
+
deleteProperty: (_, name) => published ? remove(name) : false,
|
|
236
|
+
get: (_, name) => {
|
|
237
|
+
if (published) return read(name)
|
|
238
|
+
return mapHas(pending, name) ? mapGet(pending, name) : get(name)
|
|
239
|
+
},
|
|
240
|
+
set: (_, name, value) => {
|
|
241
|
+
if (published) {
|
|
242
|
+
checkWritable(name)
|
|
243
|
+
write(name, value)
|
|
244
|
+
}
|
|
245
|
+
else mapSet(pending, name, value)
|
|
246
|
+
return true
|
|
247
|
+
},
|
|
248
|
+
})
|
|
249
|
+
return {
|
|
250
|
+
values,
|
|
251
|
+
reference(name, strict = false, target) {
|
|
252
|
+
return dynamicRuntime.reference(name, {
|
|
253
|
+
get: () => values[name],
|
|
254
|
+
set(value) {
|
|
255
|
+
if (!published && mapHas(pending, name)) {
|
|
256
|
+
if (setHas(protectedNames, name)) throw new errors.TypeError('Assignment to constant variable.')
|
|
257
|
+
} else checkWritable(name)
|
|
258
|
+
if (published) write(name, value, { strict, target })
|
|
259
|
+
else mapSet(pending, name, value)
|
|
260
|
+
},
|
|
261
|
+
delete: () => published ? remove(name) : false,
|
|
262
|
+
}, undefined, strict)
|
|
263
|
+
},
|
|
264
|
+
commit(target) {
|
|
265
|
+
const stored = []
|
|
266
|
+
for (let index = 0; index < names.length; index++) {
|
|
267
|
+
const name = names[index]
|
|
268
|
+
// A with/catch target can receive a var initializer while the
|
|
269
|
+
// declaration still establishes its own previously absent name.
|
|
270
|
+
if (!mapHas(pending, name) && (mapGet(kinds, target) !== 'var' || !needsDeclaration(name))) continue
|
|
271
|
+
if (storeValue(name, mapGet(pending, name), { readOnly: setHas(protectedNames, name), declaration: true,
|
|
272
|
+
nativeKind: mapGet(kinds, target) ?? 'let' }) === undefined) continue
|
|
273
|
+
appendArray(stored, name)
|
|
274
|
+
}
|
|
275
|
+
mapClear(pending)
|
|
276
|
+
published = true
|
|
277
|
+
for (let index = 0; index < stored.length; index++) {
|
|
278
|
+
const name = stored[index]
|
|
279
|
+
publish(name, () => read(name), value => write(name, value))
|
|
280
|
+
changed(name, 'local')
|
|
281
|
+
}
|
|
282
|
+
commit(target)
|
|
283
|
+
},
|
|
284
|
+
}
|
|
285
|
+
},
|
|
286
|
+
}
|
|
287
|
+
dynamicRuntime.setRootEnvironment(() => result.dynamic({ realm: true }))
|
|
288
|
+
// Only new-generation environments select intrinsic interfaces. Native
|
|
289
|
+
// global/prototype properties and saved legacy identities remain intact.
|
|
290
|
+
if (dynamicIntrinsics !== undefined) {
|
|
291
|
+
dynamicRuntime.installIntrinsics()
|
|
292
|
+
moduleRuntime.installIntrinsics()
|
|
293
|
+
}
|
|
294
|
+
return result
|
|
295
|
+
}
|
|
296
|
+
return {
|
|
297
|
+
begin,
|
|
298
|
+
read,
|
|
299
|
+
legacyReference(name, writable) {
|
|
300
|
+
const kind = mapGet(entries, name)?.nativeKind ?? 'let'
|
|
301
|
+
return { kind: includes(['var', 'eval-var', 'hoisted'], kind) ? 'var' : kind,
|
|
302
|
+
get: () => read(name),
|
|
303
|
+
typeof: () => mapGet(entries, name)?.deleted === true ? typeofAmbient(name) : typeof read(name),
|
|
304
|
+
set(value) {
|
|
305
|
+
if (!writable) throw new errors.TypeError('Assignment to constant variable.')
|
|
306
|
+
write(name, value)
|
|
307
|
+
},
|
|
308
|
+
declare() { write(name, undefined, { declaration: true }) },
|
|
309
|
+
delete() {
|
|
310
|
+
const entry = mapGet(entries, name)
|
|
311
|
+
if (entry.nativeKind !== 'eval-var') return false
|
|
312
|
+
mapSet(entries, name, { ...entry, deleted: true })
|
|
313
|
+
return true
|
|
314
|
+
},
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
publishLegacy(name, writable, binding, object = false) {
|
|
318
|
+
mapSet(entries, name, binding === undefined
|
|
319
|
+
? { source: 'local', readOnly: !writable, legacyWritable: writable, object, read: () => readAmbient(name) }
|
|
320
|
+
: { source: 'import', read: () => {
|
|
321
|
+
const namespace = readAmbient(binding.namespace)
|
|
322
|
+
return binding.imported === undefined ? namespace : namespace[binding.imported]
|
|
323
|
+
} })
|
|
324
|
+
publish(name, () => read(name), value => write(name, value))
|
|
325
|
+
changed(name, binding === undefined ? 'local' : 'import')
|
|
326
|
+
},
|
|
327
|
+
localValue(name) {
|
|
328
|
+
const entry = mapGet(entries, name)
|
|
329
|
+
return entry?.source === 'local' && entry.object !== true && entry.read === undefined ? { value: entry.value } : undefined
|
|
330
|
+
},
|
|
331
|
+
has: name => mapHas(entries, name) && mapGet(entries, name).object !== true && mapGet(entries, name).deleted !== true,
|
|
332
|
+
facts() {
|
|
333
|
+
const facts = []
|
|
334
|
+
mapForEach(entries, (entry, name) => appendArray(facts, { name,
|
|
335
|
+
source: entry.deleted === true || entry.object === true && !hasAmbient(name) ? 'absent' : entry.source,
|
|
336
|
+
...(entry.writeTarget === undefined ? {} : { write: entry.writeTarget }) }))
|
|
337
|
+
return facts
|
|
338
|
+
},
|
|
339
|
+
}
|
|
340
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Own the strict codec shape PTC Plus publishes into DSH's TYPERT registry.
|
|
3
|
+
*
|
|
4
|
+
* A strict codec decodes one wire member. DSH changed where the host reads that
|
|
5
|
+
* decoder: the preceding generation keeps it on `codec.schema` and evaluates
|
|
6
|
+
* `codec.schema.parse(value)`, while the current generation keeps a `create()`
|
|
7
|
+
* factory and evaluates `codec.create().parse(value)`. Each generation validates
|
|
8
|
+
* the member it owns and ignores the other, so every codec here publishes both
|
|
9
|
+
* and serves whichever shape the installed host implements — no version gate, no
|
|
10
|
+
* second registration path, and one decoder for both.
|
|
11
|
+
*
|
|
12
|
+
* The decoder is the maintained schema runtime, presented as the `parse` member
|
|
13
|
+
* both generations evaluate. Business payload validation stays with the owner of
|
|
14
|
+
* each RPC contract.
|
|
15
|
+
*
|
|
16
|
+
* @param {object} options - `typeSymbol` names the wire type; `schema` is the
|
|
17
|
+
* maintained schema the decoder evaluates.
|
|
18
|
+
* @returns {object} a strict codec accepted by either generation.
|
|
19
|
+
*/
|
|
20
|
+
export function strictCodec({ typeSymbol, schema }) {
|
|
21
|
+
const decoder = { parse: schema }
|
|
22
|
+
return {
|
|
23
|
+
mode: 'strict',
|
|
24
|
+
typeSymbol,
|
|
25
|
+
schema: decoder,
|
|
26
|
+
create: () => decoder,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import loadAmaro from './compiler-amaro.cjs'
|
|
2
|
+
|
|
3
|
+
export { LEGACY_USER_BINDING_TRANSFORM, PREVIOUS_USER_BINDING_TRANSFORM, USER_BINDING_TRANSFORM,
|
|
4
|
+
PROTECTED_MODULE_TRANSFORM, isStatefulUserBindingTransform,
|
|
5
|
+
historicalModuleTransformForLanguage, moduleTransformForLanguage, moduleTransformMatchesLanguage,
|
|
6
|
+
normalizeModuleTransform, supportedUserBindingTransform } from './module-transform-contract.js'
|
|
7
|
+
|
|
8
|
+
/** Keep binding-module lowering independent of the Host's experimental transform API. */
|
|
9
|
+
export function transformTypeScriptModule(source) {
|
|
10
|
+
return transformTypeScriptSource(source).code
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function transformTypeScriptSource(source, options = {}) {
|
|
14
|
+
try {
|
|
15
|
+
return loadAmaro().transformSync(source, { mode: 'transform', sourceMap: false, ...options })
|
|
16
|
+
} catch (error) {
|
|
17
|
+
if (error instanceof Error) throw error
|
|
18
|
+
throw new SyntaxError(error.message, { cause: error })
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let nativeUsingSupport
|
|
23
|
+
|
|
24
|
+
/** Node 22.19 does not parse explicit resource declarations by default. Keep
|
|
25
|
+
* one compiler-owned fallback so every source entry gets the same disposal
|
|
26
|
+
* semantics until the host parser proves native support. */
|
|
27
|
+
export function supportsNativeUsing() {
|
|
28
|
+
if (nativeUsingSupport !== undefined) return nativeUsingSupport
|
|
29
|
+
try { Function('using __ptc_resource = null')(); nativeUsingSupport = true } catch { nativeUsingSupport = false }
|
|
30
|
+
return nativeUsingSupport
|
|
31
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { deepFreeze } from './record-utils.js'
|
|
2
|
+
|
|
3
|
+
export const BINDING_SUBMISSION = deepFreeze({
|
|
4
|
+
name: 'submitBindingDraft',
|
|
5
|
+
description: 'Submit a Global User Binding draft for user review during /binding. Call inside run_code with the supplied requestId. Validates source and accepts one draft per request; does not save, enable or run it.',
|
|
6
|
+
parameters: {
|
|
7
|
+
type: 'object', additionalProperties: false, required: ['requestId', 'entry'],
|
|
8
|
+
properties: {
|
|
9
|
+
requestId: { type: 'string', description: 'Copy from the active /binding request.' },
|
|
10
|
+
entry: {
|
|
11
|
+
type: 'object', additionalProperties: false,
|
|
12
|
+
required: ['id', 'name', 'scope', 'purpose', 'source'],
|
|
13
|
+
properties: {
|
|
14
|
+
id: { type: 'string', description: 'Stable storage ID: 1-64 ASCII letters, digits, dots, underscores or hyphens; starts with a letter or digit.' },
|
|
15
|
+
name: { type: 'string', description: 'namespace: JavaScript identifier used directly as the call name; top-level: display label.' },
|
|
16
|
+
scope: { type: 'string', enum: ['namespace', 'top-level'] },
|
|
17
|
+
symbols: { type: 'array', items: { type: 'string' }, description: 'Named value exports to expose; omit to select all. Names must exist in source.' },
|
|
18
|
+
purpose: { type: 'string', description: 'One factual line explaining the API.' },
|
|
19
|
+
modelContext: {
|
|
20
|
+
type: 'object', additionalProperties: false,
|
|
21
|
+
description: 'Model documentation when enabled: includeDeclaration selects the source-derived interface (default true); instructions supplies a separate usage prompt (default empty, at most 4096 characters).',
|
|
22
|
+
properties: {
|
|
23
|
+
includeDeclaration: { type: 'boolean', description: 'Include the source-derived interface (default true), independently of instructions.' },
|
|
24
|
+
instructions: { type: 'string', maxLength: 4096, description: 'Usage prompt for the model: when to call this API and any constraints absent from its types. Empty omits the prompt.' },
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
source: { type: 'string', description: 'Complete TypeScript module with named value exports, explicit useful types, no default exports or re-exports.' },
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
returns: {
|
|
33
|
+
type: 'object', additionalProperties: false, required: ['accepted', 'id', 'requestId'],
|
|
34
|
+
properties: { accepted: { const: true }, id: { type: 'string' }, requestId: { type: 'string' } },
|
|
35
|
+
},
|
|
36
|
+
effect: 'ptc-state', authority: 'ptc-plus-program-binding', completeness: 'complete', replay: 'recorded-value',
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
export const BINDING_AUTHORING_SDK = `
|
|
40
|
+
During /binding, submit a draft for user review from run_code using the supplied requestId. Submission does not save, enable or execute it.
|
|
41
|
+
\`\`\`ts
|
|
42
|
+
declare namespace code {
|
|
43
|
+
function submitBindingDraft(args: {
|
|
44
|
+
requestId: string;
|
|
45
|
+
entry: { id: string; name: string; scope: "namespace" | "top-level"; symbols?: string[]; purpose: string; source: string; modelContext?: { includeDeclaration?: boolean; instructions?: string } };
|
|
46
|
+
}): Promise<{ accepted: true; id: string; requestId: string }>;
|
|
47
|
+
}
|
|
48
|
+
\`\`\``
|
|
49
|
+
|
|
50
|
+
export function bindingAuthoringInstructions(requestId, cwd) {
|
|
51
|
+
return `Create exactly one Global User Binding candidate for the user's requirement.
|
|
52
|
+
|
|
53
|
+
Develop and check the helper in small run_code cells before submission. Start with a small executable check of the core behavior, then extend it using in-memory inputs and assertions for normal cases, edge cases and failures. Use node:assert/strict for comparisons. Keep the candidate and reusable test inputs in REPL variables; correct them from observed results and recheck changed behavior. For bulk tests, print totals and a few representative failures, keeping successful cases out of the output.
|
|
54
|
+
|
|
55
|
+
Tests must not write or delete files, change external services, or call effectful tools. For filesystem or network helpers, use in-memory substitutes and check argument forwarding and error propagation. Check imports and initializers before executing them; review unknown effects without running them. A substitute verifies only the behavior its assertions cover; real integration remains untested.
|
|
56
|
+
|
|
57
|
+
Review the final source, selected exports, types and usage prompt against the requirement and tested implementation. Keep test scaffolding out of the submitted module. In the answer, briefly report verified behavior and remaining limits; distinguish test-harness errors from helper errors and cite only behavior supported by the checks.
|
|
58
|
+
|
|
59
|
+
Submit from run_code with code.submitBindingDraft({ requestId: ${JSON.stringify(requestId)}, entry }). One valid submission completes this request; correct validation errors and retry only rejected submissions. The receipt confirms a disabled draft awaiting the user's save decision. Saving and enabling belong to the user.
|
|
60
|
+
|
|
61
|
+
Candidate contract:
|
|
62
|
+
${Object.entries(BINDING_SUBMISSION.parameters.properties.entry.properties).map(([name, field]) => `- ${name}: ${field.description ?? field.enum.join(' | ')}`).join('\n')}
|
|
63
|
+
|
|
64
|
+
Use namespace scope for a compact API: name "textHelpers" with export "trim" is called as textHelpers.trim(...). Top-level scope exposes selected exports directly. Supply complete TypeScript module source with useful types and API comments; the interface is generated from it. Do not supply entry.enabled or entry.declaration. Include modelContext.includeDeclaration and modelContext.instructions; leave instructions empty when the interface is sufficient, otherwise add only usage information missing from it. On edit, preserve the entry ID and existing prompt preferences unless the requirement changes them.
|
|
65
|
+
|
|
66
|
+
Relative imports in saved modules resolve from ${JSON.stringify(cwd)}, the binding storage directory, rather than the session cwd used by ordinary REPL cells. Prefer Node built-ins when sufficient; inspect dependencies only as needed. The selected entry is supplied for edits. Do not read or modify binding storage or unrelated entries, or scan the host installation to discover this API.
|
|
67
|
+
|
|
68
|
+
Submission example:
|
|
69
|
+
await code.submitBindingDraft({ requestId: ${JSON.stringify(requestId)}, entry: { id: "text-helpers", name: "textHelpers", scope: "namespace", purpose: "Trim surrounding whitespace.", source: "export function trim(value: string): string { return value.trim() }", modelContext: { includeDeclaration: true, instructions: "" } } })`
|
|
70
|
+
}
|