dsh-ptc-plus 0.4.1 → 0.4.3
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 +164 -78
- package/README.md +165 -79
- package/assets/dsh-ptc-plus-banner-en.webp +0 -0
- package/assets/dsh-ptc-plus-banner-zh.webp +0 -0
- package/assets/ptc-plus-icon.svg +5 -0
- package/client.js +854 -336
- package/compiler-core.cjs +161 -157
- package/compiler-core.cjs.map +3 -3
- package/docs/README.md +4 -1
- package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +8 -7
- package/docs/adr/0008-define-agent-operating-contract.md +2 -2
- package/docs/adr/0010-session-log-derived-recovery-tips.md +7 -0
- package/docs/adr/0016-archive-resolved-review-findings.md +3 -3
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +3 -3
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -0
- package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +14 -3
- package/docs/adr/0023-global-user-bindings.md +7 -7
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +3 -3
- package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +23 -7
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +9 -5
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +26 -6
- package/docs/adr/0031-close-semantic-obligations-by-owner.md +29 -0
- package/docs/adr/README.md +4 -4
- package/docs/architecture.md +15 -10
- package/docs/binding-review-placement-design.md +1 -1
- package/docs/client-ui.md +9 -5
- package/docs/durability-design.md +12 -9
- package/docs/installation.md +27 -9
- package/docs/runtime-reference.md +23 -12
- package/docs/semantic-validation.md +7 -3
- package/docs/stateful-binding-updates-proposal.md +8 -4
- package/docs/user-bindings.en.md +10 -7
- package/docs/user-bindings.md +9 -6
- package/docs/value-wire.md +1 -1
- package/docs/verification-optimization-work.md +41 -0
- package/docs/verification.md +53 -2
- package/index.js +39 -34
- package/internal/async-local-storage-intrinsics.js +43 -0
- package/internal/binding-declaration-contract.js +8 -0
- package/internal/binding-source-analysis.js +381 -64
- package/internal/binding-update-policy.js +7 -1
- package/internal/callable-source-facts.js +37 -1
- package/internal/cell-analysis.js +85 -17
- package/internal/compiler-intrinsics.js +9 -43
- package/internal/compiler-module-links.js +7 -4
- package/internal/config-spec.js +1 -1
- package/internal/cordis-tools-owner.js +20 -10
- package/internal/dynamic-environment-integration.js +8 -4
- package/internal/dynamic-environment-runtime.js +24 -3
- package/internal/dynamic-native-calls.js +4 -1
- package/internal/dynamic-native-runtime.js +15 -1
- package/internal/edit-transport-owner.js +80 -20
- package/internal/execution-seam-compat.js +192 -30
- package/internal/failure-reporting.js +38 -30
- package/internal/isolated-worker.js +17 -10
- package/internal/kernel-worker.js +645 -393
- package/internal/message-sources.js +14 -0
- package/internal/module-compilation.js +7 -5
- package/internal/module-transform-contract.js +32 -2
- package/internal/record-utils.js +24 -15
- package/internal/repl-memory-projection.js +10 -0
- package/internal/repl-scope-normalizer.js +72 -35
- package/internal/repl-value-observer.js +145 -46
- package/internal/runtime-config.js +62 -2
- package/internal/runtime-intrinsics.js +104 -0
- package/internal/runtime-messages.js +6 -4
- package/internal/session-cell-executor.js +26 -2
- package/internal/session-journal-recovery.js +267 -67
- package/internal/session-journal-schema.js +30 -13
- package/internal/session-journal.js +485 -44
- package/internal/session-log-view.js +5 -4
- package/internal/session-runtime.js +46 -21
- package/internal/session-state.js +7 -29
- package/internal/settings-compat.js +66 -1
- package/internal/source-position-map.js +38 -0
- package/internal/stateful-root-compiler.js +3 -1
- package/internal/typescript-transform.js +4 -2
- package/internal/user-binding-console-worker.js +115 -41
- package/internal/user-binding-draft-projection.js +3 -2
- package/internal/user-bindings-owner.js +2 -1
- package/internal/user-bindings.js +16 -3
- package/internal/validated-parse-repair.js +6 -2
- package/internal/value-wire.js +189 -94
- package/internal/worker-client.js +99 -8
- package/internal/worker-cwd-virtualization.js +82 -54
- package/internal/worker-environment.js +20 -0
- package/internal/worker-output-capture.js +187 -0
- package/internal/worker-output-fence.js +26 -0
- package/internal/worker-realm-surfaces.js +197 -0
- package/internal/worker-repl-realm.js +140 -0
- package/package.json +37 -4
- package/src/client-activity.js +12 -2
- package/src/client-authoring-view.js +121 -62
- package/src/client-console.js +4 -2
- package/src/client-copy.js +4 -2
- package/src/client-feature-gates.js +7 -9
- package/src/client-host-compat.js +104 -27
- package/src/client-repl-view.js +3 -1
- package/src/client-styles.js +12 -1
- package/src/client-tool-view.js +3 -1
- package/src/client-transport.js +2 -2
- package/src/client-workbench.js +4 -3
- package/src/client.js +56 -17
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AsyncLocalStorage } from 'node:async_hooks'
|
|
2
1
|
import { randomUUID } from 'node:crypto'
|
|
2
|
+
import { createPrivateAsyncLocalStorage } from './async-local-storage-intrinsics.js'
|
|
3
3
|
import { create as createDomain } from 'node:domain'
|
|
4
4
|
import { createRequire, registerHooks } from 'node:module'
|
|
5
5
|
import { resolve } from 'node:path'
|
|
@@ -8,7 +8,6 @@ import { PassThrough } from 'node:stream'
|
|
|
8
8
|
import { inspect } from 'node:util'
|
|
9
9
|
import { pathToFileURL } from 'node:url'
|
|
10
10
|
import { parentPort, workerData } from 'node:worker_threads'
|
|
11
|
-
import { runInContext } from 'node:vm'
|
|
12
11
|
import { prepareConsoleProgram } from './compiler-service.js'
|
|
13
12
|
import { createStatefulRootRuntime } from './stateful-root-runtime.js'
|
|
14
13
|
import { managedModuleImport, managedRequire, readModuleImport } from './stateful-module-runtime.js'
|
|
@@ -17,22 +16,31 @@ import { USER_BINDING_TRANSFORM } from './module-transform-contract.js'
|
|
|
17
16
|
import { moduleRuntimeIntrinsics } from './compiler-intrinsics.js'
|
|
18
17
|
import { stringifyCompilerData } from './compiler-data.js'
|
|
19
18
|
import { createCellCompletionObserver } from './cell-completion.js'
|
|
19
|
+
import {
|
|
20
|
+
WORKER_REALM_MUTATION,
|
|
21
|
+
assignWorkerRealmProperty,
|
|
22
|
+
defineWorkerRealmProperty,
|
|
23
|
+
deleteWorkerRealmProperty,
|
|
24
|
+
} from './worker-realm-surfaces.js'
|
|
20
25
|
import { WORKER_SHUTDOWN_ACKNOWLEDGEMENT, WORKER_SHUTDOWN_REQUEST } from './worker-shutdown.js'
|
|
26
|
+
import { WORKER_REPL_OPTIONS, createWorkerControlPromise, createWorkerReplErrorHandler,
|
|
27
|
+
disableWorkerReplDomain,
|
|
28
|
+
captureWorkerReplGlobals, protectWorkerReplAsyncContext, restoreWorkerReplGlobals, runInWorkerReplRealm,
|
|
29
|
+
workerReplContext } from './worker-repl-realm.js'
|
|
21
30
|
|
|
22
31
|
const { Object, Set, setHas, setAdd, setDelete, appendArray } = moduleRuntimeIntrinsics
|
|
32
|
+
const Promise = globalThis.Promise
|
|
33
|
+
const process = globalThis.process
|
|
34
|
+
const hasProperty = globalThis.Reflect.has
|
|
35
|
+
const ControlPromise = createWorkerControlPromise()
|
|
23
36
|
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const completionObserver = createCellCompletionObserver(runInContext('Function', server.context))
|
|
30
|
-
server.context.console = console
|
|
31
|
-
const errorDomain = server.eval.domain ?? createDomain()
|
|
32
|
-
errorDomain.removeAllListeners('error')
|
|
33
|
-
errorDomain.on('error', error => evaluations.getStore()?.finish(true, error))
|
|
37
|
+
const evaluations = createPrivateAsyncLocalStorage()
|
|
38
|
+
const context = globalThis
|
|
39
|
+
const completionObserver = createCellCompletionObserver(runInWorkerReplRealm('Function'))
|
|
40
|
+
assignWorkerRealmProperty(WORKER_REALM_MUTATION.STABLE, 'console', context, 'console', console)
|
|
41
|
+
let retainedEvaluator
|
|
34
42
|
const completionKey = `__ptc_console_${randomUUID().replaceAll('-', '')}`
|
|
35
|
-
|
|
43
|
+
defineWorkerRealmProperty(WORKER_REALM_MUTATION.TEMPORARY, undefined, context, completionKey, { value: value => {
|
|
36
44
|
evaluations.getStore().completed = true
|
|
37
45
|
return value
|
|
38
46
|
} })
|
|
@@ -44,16 +52,16 @@ const adapterParents = new Set()
|
|
|
44
52
|
const knownBindings = new Set()
|
|
45
53
|
const roots = createStatefulRootRuntime({
|
|
46
54
|
importModule: (source, options) => managedModuleImport(replParent, source, options, replModuleRealm),
|
|
47
|
-
errors:
|
|
48
|
-
dynamicIntrinsics:
|
|
49
|
-
readAmbient: name =>
|
|
50
|
-
typeofAmbient: name =>
|
|
55
|
+
errors: runInWorkerReplRealm('({ ReferenceError, TypeError })'),
|
|
56
|
+
dynamicIntrinsics: runInWorkerReplRealm('({intrinsicEval:eval,realmFunction:Function,globalObject:globalThis,errors:{ReferenceError,TypeError,SyntaxError},reflect:Reflect,object:Object})'),
|
|
57
|
+
readAmbient: name => runInWorkerReplRealm(name),
|
|
58
|
+
typeofAmbient: name => runInWorkerReplRealm(`typeof ${name}`),
|
|
51
59
|
writeAmbient(name, value, strict) {
|
|
52
60
|
const argument = name === '__ptc_value' ? '__ptc_other_value' : '__ptc_value'
|
|
53
|
-
|
|
61
|
+
runInWorkerReplRealm(`${strict ? '"use strict";' : ''}(${argument}) => (${name} = ${argument})`)(value)
|
|
54
62
|
},
|
|
55
|
-
deleteAmbient: name =>
|
|
56
|
-
hasAmbient: name =>
|
|
63
|
+
deleteAmbient: name => runInWorkerReplRealm(`delete ${name}`),
|
|
64
|
+
hasAmbient: name => hasProperty(context, name),
|
|
57
65
|
publish: name => setAdd(knownBindings, name),
|
|
58
66
|
})
|
|
59
67
|
class ConsoleReturn {
|
|
@@ -62,7 +70,9 @@ class ConsoleReturn {
|
|
|
62
70
|
const moduleCompilation = createUserModuleCompilationHooks({
|
|
63
71
|
transformForParent: parent => parent === replParent || parent === parentUrl ? USER_BINDING_TRANSFORM : undefined,
|
|
64
72
|
})
|
|
65
|
-
|
|
73
|
+
const providedRequire = managedRequire(parentUrl, createRequire(parentUrl))
|
|
74
|
+
defineWorkerRealmProperty(WORKER_REALM_MUTATION.STABLE, 'cell module metadata',
|
|
75
|
+
context, 'require', { configurable: true, value: providedRequire })
|
|
66
76
|
const importCanary = 'data:text/javascript,export default 1'
|
|
67
77
|
registerHooks({ resolve(specifier, context, nextResolve) {
|
|
68
78
|
if (specifier === importCanary) replParent = context.parentURL
|
|
@@ -74,14 +84,38 @@ const describe = value => inspect(value, {
|
|
|
74
84
|
colors: false, customInspect: false, getters: false, depth: 4,
|
|
75
85
|
maxArrayLength: 40, maxStringLength: Math.min(workerData.maxOutputBytes, 8192), breakLength: 100,
|
|
76
86
|
})
|
|
87
|
+
process.on('uncaughtException', error => {
|
|
88
|
+
const state = evaluations.getStore()
|
|
89
|
+
if (state?.finish(true, error) === true || state?.settled === true) return
|
|
90
|
+
parentPort.postMessage({ fatal: true, error: describe(error) })
|
|
91
|
+
})
|
|
77
92
|
|
|
78
|
-
|
|
93
|
+
function evaluate(source) {
|
|
79
94
|
const prepared = prepareConsoleProgram(source, { languageSemantics: 'stateful-v1', knownBindings })
|
|
80
95
|
const helpers = [prepared.rootRuntimeName, prepared.returnSignal]
|
|
81
|
-
|
|
96
|
+
defineWorkerRealmProperty(WORKER_REALM_MUTATION.TEMPORARY, undefined,
|
|
97
|
+
context, prepared.rootRuntimeName, {
|
|
82
98
|
configurable: true, value: roots.begin({ ...prepared.rootBindings, committed: () => {} }),
|
|
83
99
|
})
|
|
84
|
-
|
|
100
|
+
defineWorkerRealmProperty(WORKER_REALM_MUTATION.TEMPORARY, undefined,
|
|
101
|
+
context, prepared.returnSignal, { configurable: true, value: ConsoleReturn })
|
|
102
|
+
if (prepared.moduleLoads.length === 0) {
|
|
103
|
+
const operation = evaluatePrepared(prepared.code, prepared.asyncCompletion)
|
|
104
|
+
return new ControlPromise((resolve, reject) => operation.then(
|
|
105
|
+
value => { removeHelpers(helpers); resolve(value) },
|
|
106
|
+
error => { removeHelpers(helpers); reject(error) },
|
|
107
|
+
))
|
|
108
|
+
}
|
|
109
|
+
return evaluateWithModules(prepared, helpers)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function removeHelpers(helpers) {
|
|
113
|
+
for (let index = 0; index < helpers.length; index++) {
|
|
114
|
+
deleteWorkerRealmProperty(WORKER_REALM_MUTATION.RESTORE, undefined, context, helpers[index])
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
async function evaluateWithModules(prepared, helpers) {
|
|
85
119
|
try {
|
|
86
120
|
for (let index = 0; index < prepared.moduleLoads.length; index++) {
|
|
87
121
|
const load = prepared.moduleLoads[index]
|
|
@@ -109,30 +143,50 @@ async function evaluate(source) {
|
|
|
109
143
|
} finally { setDelete(adapterParents, adapter) }
|
|
110
144
|
if (load.global !== undefined) {
|
|
111
145
|
appendArray(helpers, load.global)
|
|
112
|
-
|
|
146
|
+
defineWorkerRealmProperty(WORKER_REALM_MUTATION.TEMPORARY, undefined,
|
|
147
|
+
context, load.global, { configurable: true, value: namespace })
|
|
113
148
|
}
|
|
114
149
|
}
|
|
115
150
|
return await evaluatePrepared(prepared.code, prepared.asyncCompletion)
|
|
116
151
|
} finally {
|
|
117
|
-
|
|
152
|
+
removeHelpers(helpers)
|
|
118
153
|
}
|
|
119
154
|
}
|
|
120
155
|
|
|
121
156
|
function evaluatePrepared(javascript, asyncCompletion = false) {
|
|
122
|
-
|
|
157
|
+
releaseRetainedEvaluator()
|
|
158
|
+
const input = new PassThrough()
|
|
159
|
+
const output = new PassThrough()
|
|
160
|
+
output.resume()
|
|
161
|
+
const workerGlobalBaseline = captureWorkerReplGlobals(context)
|
|
162
|
+
const server = repl.start({ input, output, terminal: false, prompt: '', ...WORKER_REPL_OPTIONS,
|
|
163
|
+
handleError: createWorkerReplErrorHandler(evaluations, (state, error) => state.finish(true, error)) })
|
|
164
|
+
protectWorkerReplAsyncContext(server)
|
|
165
|
+
workerReplContext(server)
|
|
166
|
+
restoreWorkerReplGlobals(workerGlobalBaseline, context)
|
|
167
|
+
defineWorkerRealmProperty(WORKER_REALM_MUTATION.STABLE, 'cell module metadata',
|
|
168
|
+
context, 'require', { configurable: true, value: providedRequire })
|
|
169
|
+
const errorDomain = disableWorkerReplDomain(server.eval.domain ?? createDomain())
|
|
170
|
+
const evaluator = { server, input, output, errorDomain }
|
|
171
|
+
retainedEvaluator = evaluator
|
|
172
|
+
return new ControlPromise((resolve, reject) => {
|
|
123
173
|
const complete = `this[${stringifyCompilerData(completionKey)}]`
|
|
124
174
|
// Preserve expression results while distinguishing rejection with null/undefined.
|
|
125
175
|
const code = `${javascript}\n;{let completed = ${complete}();}\n;`
|
|
126
176
|
let settled = false
|
|
127
177
|
const state = { completed: false, finish(failed, value) {
|
|
128
|
-
if (settled) return
|
|
178
|
+
if (settled) return false
|
|
129
179
|
settled = true
|
|
180
|
+
state.settled = true
|
|
130
181
|
if (failed && value instanceof ConsoleReturn) completionObserver.settle(value.value, resolve, reject)
|
|
131
182
|
else if (failed) reject(value)
|
|
132
183
|
else completionObserver.settle(value, resolve, reject)
|
|
184
|
+
return true
|
|
133
185
|
} }
|
|
186
|
+
evaluator.state = state
|
|
187
|
+
errorDomain.on('error', error => state.finish(true, error))
|
|
134
188
|
evaluations.run(state, () => errorDomain.run(() => {
|
|
135
|
-
server.eval(`${code}\n`,
|
|
189
|
+
server.eval(`${code}\n`, context, 'ptc-plus-console', (error, value) => {
|
|
136
190
|
if (asyncCompletion && (error === null || error === undefined)) {
|
|
137
191
|
completionObserver.observe(value, value => state.finish(false, value), error => state.finish(true, error))
|
|
138
192
|
return
|
|
@@ -143,6 +197,16 @@ function evaluatePrepared(javascript, asyncCompletion = false) {
|
|
|
143
197
|
}))
|
|
144
198
|
})
|
|
145
199
|
}
|
|
200
|
+
|
|
201
|
+
function releaseRetainedEvaluator() {
|
|
202
|
+
const evaluator = retainedEvaluator
|
|
203
|
+
if (evaluator === undefined) return undefined
|
|
204
|
+
retainedEvaluator = undefined
|
|
205
|
+
evaluator.errorDomain.removeAllListeners('error')
|
|
206
|
+
evaluator.server.close()
|
|
207
|
+
evaluator.input.destroy()
|
|
208
|
+
evaluator.output.destroy()
|
|
209
|
+
}
|
|
146
210
|
try {
|
|
147
211
|
replModuleRealm = await evaluatePrepared('({Promise,stringify:value=>`${value}`,importModule:(source,options)=>import(source,options)})')
|
|
148
212
|
const prepared = compileStatefulModule(workerData.source)
|
|
@@ -154,30 +218,40 @@ try {
|
|
|
154
218
|
for (let index = 0; index < names.length; index++) {
|
|
155
219
|
const name = names[index]
|
|
156
220
|
setAdd(knownBindings, name)
|
|
157
|
-
|
|
221
|
+
defineWorkerRealmProperty(WORKER_REALM_MUTATION.USER, undefined,
|
|
222
|
+
context, name, { configurable: true, enumerable: true, get: () => namespace[name] })
|
|
158
223
|
}
|
|
159
|
-
parentPort.on('message',
|
|
224
|
+
parentPort.on('message', (message) => {
|
|
160
225
|
if (message?.type === WORKER_SHUTDOWN_REQUEST) {
|
|
161
226
|
// Release the realm, REPL and domain this console owns, then report the
|
|
162
227
|
// release before the host gives up on the thread; see worker-shutdown.js.
|
|
163
|
-
|
|
164
|
-
input.destroy()
|
|
165
|
-
output.destroy()
|
|
166
|
-
errorDomain.removeAllListeners('error')
|
|
228
|
+
releaseRetainedEvaluator()
|
|
167
229
|
parentPort.postMessage({ type: WORKER_SHUTDOWN_ACKNOWLEDGEMENT })
|
|
168
230
|
parentPort.close()
|
|
169
231
|
return
|
|
170
232
|
}
|
|
171
233
|
const { id, code } = message
|
|
172
|
-
|
|
234
|
+
const send = result => {
|
|
235
|
+
const flushed = new ControlPromise(resolve => process.stdout.write('', () => process.stderr.write('', resolve)))
|
|
236
|
+
moduleRuntimeIntrinsics.observeOwnedPromise(flushed, () => {
|
|
237
|
+
parentPort.postMessage(result)
|
|
238
|
+
releaseRetainedEvaluator()
|
|
239
|
+
/* c8 ignore next 3 -- flushed has no reject capability */
|
|
240
|
+
}, error => {
|
|
241
|
+
releaseRetainedEvaluator()
|
|
242
|
+
parentPort.postMessage({ id, error: describe(error) })
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
let operation
|
|
173
246
|
try {
|
|
174
|
-
|
|
175
|
-
result = { id, output: describe(value) }
|
|
247
|
+
operation = evaluate(code)
|
|
176
248
|
} catch (error) {
|
|
177
|
-
|
|
249
|
+
send({ id, error: describe(error) })
|
|
250
|
+
return
|
|
178
251
|
}
|
|
179
|
-
|
|
180
|
-
|
|
252
|
+
moduleRuntimeIntrinsics.observeOwnedPromise(operation,
|
|
253
|
+
value => send({ id, output: describe(value) }),
|
|
254
|
+
error => send({ id, error: describe(error) }))
|
|
181
255
|
})
|
|
182
256
|
} catch (error) {
|
|
183
257
|
parentPort.postMessage({ fatal: true, error: describe(error) })
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isPtcMessageSource, PTC_MESSAGE_SOURCE_KIND } from './message-sources.js'
|
|
1
2
|
import { isRecord } from './record-utils.js'
|
|
2
3
|
import { normalizeBindingModelContext } from './user-binding-model-context.js'
|
|
3
4
|
|
|
@@ -51,13 +52,13 @@ function normalizeAction(value) {
|
|
|
51
52
|
|
|
52
53
|
export function bindingActionNotice(action) {
|
|
53
54
|
return {
|
|
54
|
-
source: { kind:
|
|
55
|
+
source: { kind: PTC_MESSAGE_SOURCE_KIND, form: 'notice', summary: 'Global User Binding action' },
|
|
55
56
|
content: [{ type: 'text', text: ACTION_PREFIX + JSON.stringify(normalizeAction(action)) }],
|
|
56
57
|
}
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
export function readBindingAction(message) {
|
|
60
|
-
if (message?.source
|
|
61
|
+
if (!isPtcMessageSource(message?.source)
|
|
61
62
|
|| message.source.form !== 'notice' || message.source.summary !== 'Global User Binding action'
|
|
62
63
|
|| message.content?.length !== 1 || message.content[0]?.type !== 'text') return undefined
|
|
63
64
|
try {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PTC_MESSAGE_SOURCE_KIND } from './message-sources.js'
|
|
1
2
|
import { RPC_CONTRACTS } from './rpc-contract.js'
|
|
2
3
|
import { randomUUID } from 'node:crypto'
|
|
3
4
|
import { dirname } from 'node:path'
|
|
@@ -87,7 +88,7 @@ function authoringTask(command, current) {
|
|
|
87
88
|
function taskMessage(text) {
|
|
88
89
|
return createUserMessage({
|
|
89
90
|
content: [{ type: 'text', text }],
|
|
90
|
-
source: { kind:
|
|
91
|
+
source: { kind: PTC_MESSAGE_SOURCE_KIND, form: 'instructions' },
|
|
91
92
|
})
|
|
92
93
|
}
|
|
93
94
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto'
|
|
2
2
|
import { identifier, exportedSymbols, sourceDurability } from './compiler-service.js'
|
|
3
3
|
import { assertOwnFields, isRecord } from './record-utils.js'
|
|
4
|
+
import { boundedDefinitionSource } from './repl-memory-projection.js'
|
|
4
5
|
import { bindingModelPreferences, normalizeBindingModelContext } from './user-binding-model-context.js'
|
|
5
6
|
import { supportedUserBindingTransform, USER_BINDING_TRANSFORM } from './module-transform-contract.js'
|
|
6
7
|
|
|
@@ -62,11 +63,19 @@ function selectedDescriptors(source, symbols, transform) {
|
|
|
62
63
|
|
|
63
64
|
|
|
64
65
|
function declarationFor(entry, descriptors) {
|
|
66
|
+
const typeNamespace = `__ptcBinding_${createHash('sha256').update(entry.id).digest('hex').slice(0, 12)}`
|
|
67
|
+
const typeNamespaceTokens = new Set(descriptors.map(item => item.typeNamespaceToken))
|
|
68
|
+
if (typeNamespaceTokens.size !== 1 || typeNamespaceTokens.has(undefined)) throw new TypeError('binding symbols do not share one compiler type namespace')
|
|
69
|
+
const [typeNamespaceToken] = typeNamespaceTokens
|
|
70
|
+
const render = text => text.replaceAll(typeNamespaceToken, typeNamespace)
|
|
71
|
+
const typeDeclarations = [...new Set(descriptors.flatMap(item => item.typeDeclarations ?? []))]
|
|
72
|
+
const typePrefix = typeDeclarations.length === 0 ? '' : `declare namespace ${typeNamespace} {\n${typeDeclarations
|
|
73
|
+
.map(item => render(item).split('\n').map(line => ` ${line}`).join('\n')).join('\n')}\n}\n`
|
|
65
74
|
const comment = entry.purpose === '' ? '' : `/** ${entry.purpose.replaceAll('*/', '* /')} */\n`
|
|
66
75
|
if (entry.scope === 'namespace') {
|
|
67
|
-
return `${comment}declare const ${entry.name}: {\n${descriptors.map(item => ` ${item.member};`).join('\n')}\n}`
|
|
76
|
+
return `${typePrefix}${comment}declare const ${entry.name}: {\n${descriptors.map(item => ` ${render(item.member)};`).join('\n')}\n}`
|
|
68
77
|
}
|
|
69
|
-
return descriptors.map((item, index) => `${index === 0 ? comment : ''}declare ${item.declaration}`).join('\n')
|
|
78
|
+
return `${typePrefix}${descriptors.map((item, index) => `${index === 0 ? comment : ''}declare ${render(item.declaration)}`).join('\n')}`
|
|
70
79
|
}
|
|
71
80
|
|
|
72
81
|
export function normalizeUserBindingEntry(value, { transform = USER_BINDING_TRANSFORM } = {}) {
|
|
@@ -288,7 +297,11 @@ export function userBindingCatalogEntries(snapshot) {
|
|
|
288
297
|
kind: binding.kind,
|
|
289
298
|
entryId: entry.id,
|
|
290
299
|
fingerprint: entry.fingerprint,
|
|
291
|
-
definition: Object.freeze({
|
|
300
|
+
definition: Object.freeze({
|
|
301
|
+
source: boundedDefinitionSource(binding.declaration),
|
|
302
|
+
line: 1,
|
|
303
|
+
column: 1,
|
|
304
|
+
}),
|
|
292
305
|
})))
|
|
293
306
|
}
|
|
294
307
|
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { EXPECTED_TARGET_CALL_SEQ, editRejectedCell } from './rejected-cell-editor.js'
|
|
2
2
|
|
|
3
3
|
const CLOSING_DELIMITERS = Object.freeze(['}', ')', ']'])
|
|
4
|
+
const CLOSING_SUFFIXES = Object.freeze([
|
|
5
|
+
...CLOSING_DELIMITERS,
|
|
6
|
+
...CLOSING_DELIMITERS.flatMap(first => CLOSING_DELIMITERS.map(second => first + second)),
|
|
7
|
+
])
|
|
4
8
|
const LINE_TERMINATORS = /\r\n|[\n\r\u2028\u2029]/gu
|
|
5
9
|
export const MAX_PARSE_REPAIR_ANCHOR_CODE_UNITS = 256
|
|
6
10
|
|
|
@@ -52,14 +56,14 @@ function renderInvocation(argumentsValue) {
|
|
|
52
56
|
return `edit_run_code(${json})`
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
/**
|
|
59
|
+
/** Requires exactly one valid suffix across all one- and two-token EOF closures. */
|
|
56
60
|
export function validatedEofClosureRepair({ source, position, prepare, targetCallSeq }) {
|
|
57
61
|
if (!Number.isSafeInteger(targetCallSeq) || targetCallSeq < 0
|
|
58
62
|
|| !isSourceEnd(source, position)) return undefined
|
|
59
63
|
const anchor = boundedUniqueSuffix(source)
|
|
60
64
|
if (anchor === undefined) return undefined
|
|
61
65
|
const candidates = []
|
|
62
|
-
for (const delimiter of
|
|
66
|
+
for (const delimiter of CLOSING_SUFFIXES) {
|
|
63
67
|
const code = source + delimiter
|
|
64
68
|
let prepared
|
|
65
69
|
try {
|