dsh-ptc-plus 0.4.1 → 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 +6 -10
- package/README.md +6 -10
- package/client.js +262 -31
- package/compiler-core.cjs +132 -130
- package/compiler-core.cjs.map +3 -3
- package/docs/README.md +1 -0
- package/docs/adr/0023-global-user-bindings.md +6 -6
- package/docs/adr/0025-use-versioned-logical-binding-identities.md +3 -3
- package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +5 -5
- package/docs/architecture.md +9 -5
- package/docs/client-ui.md +1 -1
- package/docs/durability-design.md +6 -3
- package/docs/installation.md +4 -4
- package/docs/runtime-reference.md +5 -1
- package/docs/stateful-binding-updates-proposal.md +8 -4
- package/docs/user-bindings.en.md +5 -3
- package/docs/user-bindings.md +4 -2
- package/docs/verification-optimization-work.md +41 -0
- package/docs/verification.md +15 -1
- package/internal/async-local-storage-intrinsics.js +38 -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/cell-analysis.js +21 -8
- package/internal/compiler-intrinsics.js +9 -43
- package/internal/compiler-module-links.js +7 -4
- 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/failure-reporting.js +38 -30
- package/internal/isolated-worker.js +17 -10
- package/internal/kernel-worker.js +493 -331
- package/internal/module-compilation.js +5 -4
- package/internal/module-transform-contract.js +32 -2
- package/internal/record-utils.js +24 -15
- package/internal/repl-value-observer.js +6 -3
- package/internal/runtime-intrinsics.js +101 -0
- package/internal/session-cell-executor.js +2 -1
- package/internal/session-journal-schema.js +30 -13
- package/internal/session-journal.js +19 -4
- package/internal/session-runtime.js +1 -0
- package/internal/source-position-map.js +19 -0
- package/internal/stateful-root-compiler.js +3 -1
- package/internal/typescript-transform.js +4 -2
- package/internal/user-binding-console-worker.js +101 -41
- package/internal/user-bindings.js +10 -2
- package/internal/value-wire.js +101 -71
- package/internal/worker-cwd-virtualization.js +80 -53
- package/internal/worker-environment.js +20 -0
- package/internal/worker-repl-realm.js +134 -0
- package/package.json +2 -1
- package/src/client-activity.js +8 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { createContext, runInContext, runInThisContext } from 'node:vm'
|
|
2
|
+
import { types } from 'node:util'
|
|
3
|
+
import { protectNextAsyncLocalStorageRun } from './async-local-storage-intrinsics.js'
|
|
4
|
+
|
|
5
|
+
export const WORKER_REPL_OPTIONS = Object.freeze({ useGlobal: true })
|
|
6
|
+
const NativeMap = Map
|
|
7
|
+
const ownKeys = Reflect.ownKeys
|
|
8
|
+
const deleteProperty = Reflect.deleteProperty
|
|
9
|
+
const getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor
|
|
10
|
+
const defineProperty = Object.defineProperty
|
|
11
|
+
const createObject = Object.create
|
|
12
|
+
const hasOwn = Object.hasOwn
|
|
13
|
+
const sameValue = Object.is
|
|
14
|
+
const isMap = types.isMap
|
|
15
|
+
const mapSet = Function.prototype.call.bind(Map.prototype.set)
|
|
16
|
+
const mapHas = Function.prototype.call.bind(Map.prototype.has)
|
|
17
|
+
const mapForEach = Function.prototype.call.bind(Map.prototype.forEach)
|
|
18
|
+
const DESCRIPTOR_FIELDS = ['configurable', 'enumerable', 'writable', 'value', 'get', 'set']
|
|
19
|
+
|
|
20
|
+
/** Snapshot the native worker surface before Node installs REPL conveniences. */
|
|
21
|
+
export function captureWorkerReplGlobals(globalObject = globalThis) {
|
|
22
|
+
const baseline = new NativeMap()
|
|
23
|
+
const keys = ownKeys(globalObject)
|
|
24
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
25
|
+
mapSet(baseline, keys[index], getOwnPropertyDescriptor(globalObject, keys[index]))
|
|
26
|
+
}
|
|
27
|
+
return baseline
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function descriptorsEqual(left, right) {
|
|
31
|
+
const field = (descriptor, name) => descriptor !== undefined && hasOwn(descriptor, name)
|
|
32
|
+
? descriptor[name] : undefined
|
|
33
|
+
return left !== undefined && right !== undefined
|
|
34
|
+
&& field(left, 'configurable') === field(right, 'configurable')
|
|
35
|
+
&& field(left, 'enumerable') === field(right, 'enumerable')
|
|
36
|
+
&& field(left, 'writable') === field(right, 'writable')
|
|
37
|
+
&& sameValue(field(left, 'value'), field(right, 'value'))
|
|
38
|
+
&& field(left, 'get') === field(right, 'get')
|
|
39
|
+
&& field(left, 'set') === field(right, 'set')
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function detachedDescriptor(descriptor) {
|
|
43
|
+
const detached = createObject(null)
|
|
44
|
+
for (let index = 0; index < DESCRIPTOR_FIELDS.length; index += 1) {
|
|
45
|
+
const name = DESCRIPTOR_FIELDS[index]
|
|
46
|
+
if (hasOwn(descriptor, name)) detached[name] = descriptor[name]
|
|
47
|
+
}
|
|
48
|
+
return detached
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Remove Node's REPL-only module shortcuts and restore changed native globals. */
|
|
52
|
+
export function restoreWorkerReplGlobals(baseline, globalObject = globalThis) {
|
|
53
|
+
if (!isMap(baseline)) throw new TypeError('worker REPL global baseline must be a Map')
|
|
54
|
+
const keys = ownKeys(globalObject)
|
|
55
|
+
for (let index = 0; index < keys.length; index += 1) {
|
|
56
|
+
const key = keys[index]
|
|
57
|
+
if (typeof key === 'string' && !mapHas(baseline, key) && !deleteProperty(globalObject, key)) {
|
|
58
|
+
throw new Error(`worker REPL added a non-configurable global ${String(key)}`)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
mapForEach(baseline, (descriptor, key) => {
|
|
62
|
+
if (!descriptorsEqual(getOwnPropertyDescriptor(globalObject, key), descriptor)) {
|
|
63
|
+
defineProperty(globalObject, key, detachedDescriptor(descriptor))
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
return globalObject
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** A dedicated worker is the native realm shared by its REPL and Node modules. */
|
|
70
|
+
export function workerReplContext(server) {
|
|
71
|
+
if (server.context !== globalThis) {
|
|
72
|
+
throw new Error('worker REPL did not use its native global realm')
|
|
73
|
+
}
|
|
74
|
+
return server.context
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let replAsyncContextProtected = false
|
|
78
|
+
|
|
79
|
+
/** Newer Node REPLs own an AsyncLocalStorage instance whose public prototype
|
|
80
|
+
* remains user-mutable. Give only that platform instance its native operations
|
|
81
|
+
* before the first user evaluation. */
|
|
82
|
+
export function protectWorkerReplAsyncContext(server) {
|
|
83
|
+
if (replAsyncContextProtected) return
|
|
84
|
+
let callbackError
|
|
85
|
+
const scope = protectNextAsyncLocalStorageRun(() => {
|
|
86
|
+
server.eval('void 0\n', server.context, 'ptc-plus-repl-bootstrap', error => { callbackError = error })
|
|
87
|
+
})
|
|
88
|
+
if (callbackError !== null && callbackError !== undefined) throw callbackError
|
|
89
|
+
replAsyncContextProtected = true
|
|
90
|
+
return scope !== undefined
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function runInWorkerReplRealm(source, options) {
|
|
94
|
+
return runInThisContext(source, options)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Control promises stay outside the user-mutable worker realm. */
|
|
98
|
+
export function createWorkerControlPromise() {
|
|
99
|
+
return runInContext('Promise', createContext())
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** PTC owns settlement; the REPL's legacy domain would run Node bookkeeping
|
|
103
|
+
* through user-mutable prototypes in the shared worker realm. */
|
|
104
|
+
export function disableWorkerReplDomain(domain) {
|
|
105
|
+
domain.enter = () => domain
|
|
106
|
+
domain.exit = () => domain
|
|
107
|
+
return domain
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Newer REPLs format errors before the eval callback unless an owned
|
|
111
|
+
* evaluation consumes the original thrown value through handleError. */
|
|
112
|
+
export function createWorkerReplErrorHandler(evaluationScope, settle) {
|
|
113
|
+
return error => {
|
|
114
|
+
const finish = evaluationScope.getStore()
|
|
115
|
+
if (finish === undefined) return 'unhandled'
|
|
116
|
+
settle(finish, error)
|
|
117
|
+
return 'ignore'
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** Older REPLs can bypass handleError. Keep their process-level fallback
|
|
122
|
+
* directly testable without requiring a version-specific uncaught event. */
|
|
123
|
+
export function createWorkerUncaughtExceptionHandler(evaluationScope, listenerOwner = process) {
|
|
124
|
+
const handleUncaughtException = error => {
|
|
125
|
+
const finish = evaluationScope.getStore()
|
|
126
|
+
if (finish !== undefined) {
|
|
127
|
+
finish(true, error)
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
listenerOwner.removeListener('uncaughtException', handleUncaughtException)
|
|
131
|
+
throw error
|
|
132
|
+
}
|
|
133
|
+
return handleUncaughtException
|
|
134
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-ptc-plus",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "A session-bound agent-native REPL for DeepSeek Harness PTC mode.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -96,6 +96,7 @@
|
|
|
96
96
|
"review:gate": "node scripts/review-findings.mjs gate",
|
|
97
97
|
"session:migrate": "node scripts/migrate-session-log.mjs",
|
|
98
98
|
"coverage": "node scripts/coverage.mjs",
|
|
99
|
+
"coverage:focus": "node scripts/coverage.mjs --focus",
|
|
99
100
|
"verify": "npm run review:validate && npm run build:check && node --check index.js && node --check internal/kernel-worker.js && node --check scripts/migrate-session-log.mjs && node --check scripts/expensive-headless-acceptance.mjs && node --check scripts/ab-headless-trajectories.mjs && npm run test:client && npm run coverage",
|
|
100
101
|
"check": "node scripts/review-findings.mjs check",
|
|
101
102
|
"test:expensive": "node scripts/expensive-headless-acceptance.mjs",
|
package/src/client-activity.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
STATUSES as JOURNAL_STATUSES,
|
|
4
4
|
BINDING_MODES,
|
|
5
5
|
JOURNAL_FIELDS,
|
|
6
|
+
LANGUAGE_SEMANTICS_JOURNAL_FIELDS,
|
|
6
7
|
PER_NAME_JOURNAL_FIELDS,
|
|
7
8
|
LANGUAGE_SEMANTICS_JOURNAL_VERSION,
|
|
8
9
|
WHOLE_ENTRY_JOURNAL_FIELDS,
|
|
@@ -33,6 +34,7 @@ import {
|
|
|
33
34
|
USER_BINDINGS_REUSE_POLICIES,
|
|
34
35
|
} from '../internal/session-journal-schema.js'
|
|
35
36
|
import { normalizeLanguageSemantics } from '../internal/language-semantics.js'
|
|
37
|
+
import { normalizeModuleTransform } from '../internal/module-transform-contract.js'
|
|
36
38
|
import {
|
|
37
39
|
VALUE_CODEC,
|
|
38
40
|
DEFAULT_VALUE_LIMITS,
|
|
@@ -292,7 +294,8 @@ function isReadableJournalUnchecked(value) {
|
|
|
292
294
|
: value.version === 4 ? RELATIONLESS_JOURNAL_FIELDS
|
|
293
295
|
: value.version === 5 ? FINGERPRINT_REUSE_JOURNAL_FIELDS
|
|
294
296
|
: value.version < PER_NAME_USER_BINDINGS_JOURNAL_VERSION ? WHOLE_ENTRY_JOURNAL_FIELDS
|
|
295
|
-
|
|
297
|
+
: value.version < LANGUAGE_SEMANTICS_JOURNAL_VERSION ? PER_NAME_JOURNAL_FIELDS
|
|
298
|
+
: value.version === LANGUAGE_SEMANTICS_JOURNAL_VERSION ? LANGUAGE_SEMANTICS_JOURNAL_FIELDS : JOURNAL_FIELDS
|
|
296
299
|
const required = predecessor
|
|
297
300
|
? ['version', 'bindingMode', 'status', 'calls', 'operations', 'diagnostics']
|
|
298
301
|
: ['version', 'bindingPolicy', 'rewritePolicy', 'moduleSemantics', 'status', 'calls', 'operations', 'diagnostics']
|
|
@@ -307,6 +310,10 @@ function isReadableJournalUnchecked(value) {
|
|
|
307
310
|
required.push('languageSemantics')
|
|
308
311
|
normalizeLanguageSemantics(value.languageSemantics)
|
|
309
312
|
}
|
|
313
|
+
if (value.version > LANGUAGE_SEMANTICS_JOURNAL_VERSION) {
|
|
314
|
+
required.push('moduleTransform')
|
|
315
|
+
normalizeModuleTransform(value.moduleTransform, value.languageSemantics)
|
|
316
|
+
}
|
|
310
317
|
if (!hasClosedFields(value, fields, required)
|
|
311
318
|
|| (predecessor && !BINDING_MODES.has(value.bindingMode))
|
|
312
319
|
|| (value.version >= 4 && !isValidBindingPolicy(value.bindingPolicy))
|