dsh-ptc-plus 0.3.2 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/README.en.md +63 -80
  2. package/README.md +63 -80
  3. package/assets/ptc-plus-bindings-en.png +0 -0
  4. package/assets/ptc-plus-bindings-zh.png +0 -0
  5. package/assets/ptc-plus-repair-en.png +0 -0
  6. package/assets/ptc-plus-repair-zh.png +0 -0
  7. package/assets/ptc-plus-repl-workspace-en.png +0 -0
  8. package/assets/ptc-plus-repl-workspace-zh.png +0 -0
  9. package/assets/ptc-plus-settings-en.png +0 -0
  10. package/assets/ptc-plus-settings-zh.png +0 -0
  11. package/client.js +30827 -742
  12. package/compiler-amaro.cjs +5 -0
  13. package/compiler-amaro.cjs.map +6 -0
  14. package/compiler-asset-124f80c1bba92ff5fe79cfec6e8ad518f476de4a42514cae3919538887f510e8.txt +1 -0
  15. package/compiler-assets.json +3 -0
  16. package/compiler-core.cjs +556 -0
  17. package/compiler-core.cjs.map +6 -0
  18. package/compiler-platform.cjs +2 -0
  19. package/compiler-platform.cjs.map +6 -0
  20. package/compiler-typescript.cjs +388 -0
  21. package/compiler-typescript.cjs.map +6 -0
  22. package/docs/README.md +7 -0
  23. package/docs/adr/0004-declare-program-bindings-at-the-host.md +1 -1
  24. package/docs/adr/0006-rewrite-module-syntax-with-an-ast.md +5 -3
  25. package/docs/adr/0007-separate-worker-transport-from-session-semantics.md +1 -1
  26. package/docs/adr/0009-bound-expensive-acceptance-default.md +2 -0
  27. package/docs/adr/0010-session-log-derived-recovery-tips.md +59 -5
  28. package/docs/adr/0011-isolate-the-local-recovery-tip-provider.md +1 -1
  29. package/docs/adr/0012-preserve-mixed-destructuring-initialization.md +3 -1
  30. package/docs/adr/0013-isolate-repl-redeclaration-convenience.md +3 -1
  31. package/docs/adr/0014-persist-cell-rewrite-policy.md +6 -2
  32. package/docs/adr/0015-preserve-source-positions-through-rewrites.md +1 -1
  33. package/docs/adr/0016-archive-resolved-review-findings.md +1 -1
  34. package/docs/adr/0017-track-the-latest-dsh-public-surface.md +49 -0
  35. package/docs/adr/0018-use-versioned-fixture-for-ab-benchmark.md +3 -3
  36. package/docs/adr/0019-plugin-settings-and-kill-switch.md +5 -3
  37. package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +2 -2
  38. package/docs/adr/0021-separate-host-bootstrap-from-session-runtime.md +12 -0
  39. package/docs/adr/0023-global-user-bindings.md +104 -0
  40. package/docs/adr/0024-repl-console-observation.md +33 -0
  41. package/docs/adr/0025-use-versioned-logical-binding-identities.md +119 -0
  42. package/docs/adr/0026-persist-the-delivery-verdict-against-the-verified-candidate.md +21 -0
  43. package/docs/adr/0027-run-the-session-kernel-in-a-killable-helper-process.md +37 -0
  44. package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +103 -0
  45. package/docs/adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md +27 -0
  46. package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +27 -0
  47. package/docs/architecture.md +77 -21
  48. package/docs/binding-review-placement-design.md +200 -0
  49. package/docs/capability-projection.md +1 -1
  50. package/docs/client-ui.md +95 -19
  51. package/docs/durability-design.md +28 -10
  52. package/docs/evaluation.md +78 -6
  53. package/docs/installation.md +41 -6
  54. package/docs/publishing.md +5 -3
  55. package/docs/runtime-reference.md +76 -25
  56. package/docs/semantic-validation.md +29 -0
  57. package/docs/stateful-binding-updates-proposal.md +759 -0
  58. package/docs/user-bindings.en.md +66 -0
  59. package/docs/user-bindings.md +66 -0
  60. package/docs/value-wire.md +3 -3
  61. package/docs/verification-optimization-work.md +41 -0
  62. package/docs/verification.md +71 -0
  63. package/index.js +369 -92
  64. package/internal/ast-traversal.js +5 -2
  65. package/internal/async-local-storage-intrinsics.js +38 -0
  66. package/internal/binding-declaration-contract.js +8 -0
  67. package/internal/binding-descriptors.js +1 -0
  68. package/internal/binding-pattern-traversal.js +25 -0
  69. package/internal/binding-pattern.js +26 -29
  70. package/internal/binding-source-analysis.js +708 -0
  71. package/internal/binding-update-policy.js +72 -0
  72. package/internal/bounded-worker-round.js +56 -0
  73. package/internal/callable-definition-environment.js +42 -0
  74. package/internal/callable-source-catalog.js +129 -0
  75. package/internal/callable-source-encoding.js +47 -0
  76. package/internal/callable-source-facts.js +459 -0
  77. package/internal/callable-source-format.js +2 -0
  78. package/internal/callable-source-lowering.js +123 -0
  79. package/internal/cell-analysis-contract.js +25 -0
  80. package/internal/cell-analysis.js +253 -290
  81. package/internal/cell-completion.js +15 -0
  82. package/internal/cell-error.js +7 -0
  83. package/internal/cell-parser.js +66 -0
  84. package/internal/cell-rewriter.js +3 -677
  85. package/internal/commonjs-export-evidence.js +63 -0
  86. package/internal/commonjs-source-evidence.js +72 -0
  87. package/internal/compiler-amaro.cjs +2 -0
  88. package/internal/compiler-compression.js +12 -0
  89. package/internal/compiler-data.js +58 -0
  90. package/internal/compiler-descriptors.js +54 -0
  91. package/internal/compiler-dynamic-cache.js +48 -0
  92. package/internal/compiler-entry.js +35 -0
  93. package/internal/compiler-generated-names.js +17 -0
  94. package/internal/compiler-intrinsics.js +50 -0
  95. package/internal/compiler-module-links.js +37 -0
  96. package/internal/compiler-operations.js +61 -0
  97. package/internal/compiler-platform-factory.js +84 -0
  98. package/internal/compiler-platform.js +136 -0
  99. package/internal/compiler-record-roles.js +53 -0
  100. package/internal/compiler-region-output.js +259 -0
  101. package/internal/compiler-resource-lowering.js +103 -0
  102. package/internal/compiler-scope-facts.js +115 -0
  103. package/internal/compiler-service.js +109 -0
  104. package/internal/compiler-source-cache.js +32 -0
  105. package/internal/compiler-source-pieces.js +93 -0
  106. package/internal/compiler-source-regions.js +132 -0
  107. package/internal/compiler-storage-source.js +54 -0
  108. package/internal/compiler-text.js +15 -0
  109. package/internal/compiler-typescript.cjs +2 -0
  110. package/internal/config-spec.js +83 -27
  111. package/internal/cordis-tools-owner.js +130 -21
  112. package/internal/diagnostic.js +27 -1
  113. package/internal/direct-surface-owner.js +76 -23
  114. package/internal/dynamic-binding-evidence.js +16 -0
  115. package/internal/dynamic-environment-compiler.js +779 -0
  116. package/internal/dynamic-environment-integration.js +91 -0
  117. package/internal/dynamic-environment-runtime.js +383 -0
  118. package/internal/dynamic-native-calls.js +153 -0
  119. package/internal/dynamic-native-runtime.js +262 -0
  120. package/internal/dynamic-scope-analysis.js +90 -0
  121. package/internal/edit-transport-owner.js +27 -2
  122. package/internal/execution-seam-compat.js +193 -0
  123. package/internal/failure-reporting.js +136 -28
  124. package/internal/host-rpc.js +66 -0
  125. package/internal/isolated-worker.js +555 -0
  126. package/internal/kernel-child.js +139 -0
  127. package/internal/kernel-worker.js +1179 -233
  128. package/internal/language-semantics.js +14 -0
  129. package/internal/legacy-binding-catalog.js +48 -0
  130. package/internal/legacy-cell-analysis.js +600 -0
  131. package/internal/legacy-cell-parser.js +50 -0
  132. package/internal/legacy-cell-rewriter.js +631 -0
  133. package/internal/legacy-repl-convenience.js +291 -0
  134. package/internal/managed-module-operations.js +170 -0
  135. package/internal/module-compilation.js +322 -0
  136. package/internal/module-runtime-platform.js +19 -0
  137. package/internal/module-transform-contract.js +42 -0
  138. package/internal/native-await-declarations.js +68 -0
  139. package/internal/native-root-compilation.js +54 -0
  140. package/internal/native-root-dynamic.js +67 -0
  141. package/internal/record-utils.js +24 -15
  142. package/internal/recovery-tips.js +27 -15
  143. package/internal/rejected-cell-editor.js +13 -8
  144. package/internal/repl-convenience.js +2 -289
  145. package/internal/repl-memory-projection.js +81 -12
  146. package/internal/repl-observation-interest.js +70 -0
  147. package/internal/repl-rewrite-contract.js +6 -0
  148. package/internal/repl-scope-normalizer.js +2091 -0
  149. package/internal/repl-value-observer.js +117 -0
  150. package/internal/rpc-contract.js +52 -0
  151. package/internal/runtime-bridge-owner.js +172 -28
  152. package/internal/runtime-config.js +48 -52
  153. package/internal/runtime-contexts.js +82 -10
  154. package/internal/runtime-intrinsics.js +101 -0
  155. package/internal/runtime-messages.js +111 -0
  156. package/internal/session-cell-executor.js +402 -87
  157. package/internal/session-journal-recovery.js +684 -0
  158. package/internal/session-journal-schema.js +123 -0
  159. package/internal/session-journal.js +199 -654
  160. package/internal/session-log-view.js +42 -9
  161. package/internal/session-runtime.js +257 -95
  162. package/internal/session-state.js +247 -71
  163. package/internal/source-position-map.js +230 -71
  164. package/internal/stateful-module-compiler.js +154 -0
  165. package/internal/stateful-module-runtime.js +303 -0
  166. package/internal/stateful-root-compiler.js +600 -0
  167. package/internal/stateful-root-runtime.js +340 -0
  168. package/internal/typert-codec-compat.js +28 -0
  169. package/internal/typescript-transform.js +31 -0
  170. package/internal/user-binding-authoring.js +70 -0
  171. package/internal/user-binding-console-worker.js +244 -0
  172. package/internal/user-binding-console.js +148 -0
  173. package/internal/user-binding-draft-projection.js +335 -0
  174. package/internal/user-binding-model-context.js +31 -0
  175. package/internal/user-binding-runner.js +56 -0
  176. package/internal/user-bindings-owner.js +1065 -0
  177. package/internal/user-bindings-store.js +293 -0
  178. package/internal/user-bindings.js +361 -0
  179. package/internal/value-wire-schema.js +28 -0
  180. package/internal/value-wire.js +130 -91
  181. package/internal/worker-client.js +57 -67
  182. package/internal/worker-cwd-virtualization.js +80 -53
  183. package/internal/worker-environment.js +65 -0
  184. package/internal/worker-output-relay.js +29 -0
  185. package/internal/worker-repl-realm.js +134 -0
  186. package/internal/worker-shutdown.js +14 -0
  187. package/package.json +76 -7
  188. package/src/client-activity.js +95 -53
  189. package/src/client-authoring-view.js +580 -0
  190. package/src/client-binding-review.js +230 -0
  191. package/src/client-bindings-data.js +29 -0
  192. package/src/client-catalog.js +127 -0
  193. package/src/client-code-editor.js +84 -0
  194. package/src/client-console.js +112 -0
  195. package/src/client-copy.js +370 -0
  196. package/src/client-feature-gates.js +62 -0
  197. package/src/client-host-compat.js +150 -0
  198. package/src/client-indicator-view.js +267 -0
  199. package/src/client-repl-view.js +292 -0
  200. package/src/client-rpc.js +20 -0
  201. package/src/client-settings-view.js +221 -0
  202. package/src/client-styles.js +106 -0
  203. package/src/client-tool-view.js +108 -0
  204. package/src/client-transport.js +159 -0
  205. package/src/client-workbench.js +521 -0
  206. package/src/client.js +233 -615
@@ -0,0 +1,109 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { constants, createContext, Script } from 'node:vm'
3
+ import { fileURLToPath } from 'node:url'
4
+ import { workerData } from 'node:worker_threads'
5
+ import { deserialize } from 'node:v8'
6
+ import { copyCompilerData } from './compiler-data.js'
7
+ import { PreflightError } from './cell-analysis-contract.js'
8
+ import { ModuleRewriteError } from './cell-error.js'
9
+ import { installCompilerPlatform } from './compiler-platform.js'
10
+ import { compilerDescriptors } from './compiler-descriptors.js'
11
+
12
+ export { PreflightError } from './cell-analysis-contract.js'
13
+
14
+ const bundleUrl = new URL('../compiler-core.cjs', import.meta.url)
15
+ const filename = fileURLToPath(bundleUrl)
16
+ const directory = fileURLToPath(new URL('./', bundleUrl))
17
+ const compilerSource = readFileSync(bundleUrl, 'utf8')
18
+ const NativeScript = Script
19
+ const nativeCreateContext = createContext
20
+ const dontContextify = constants.DONT_CONTEXTIFY
21
+ const runInContext = Script.prototype.runInContext
22
+ const createCachedData = Script.prototype.createCachedData
23
+ const NativeUint8Array = Uint8Array
24
+ const apply = Reflect.apply
25
+ const hasInstance = Function.prototype[Symbol.hasInstance]
26
+ const nativeErrors = { Error, SyntaxError, TypeError, RangeError, ReferenceError,
27
+ EvalError, URIError, ModuleRewriteError, PreflightError }
28
+ const define = compilerDescriptors.defineProperty
29
+ const keys = Object.keys
30
+ let compiler
31
+ let compilerScript
32
+ const coverageEnabled = Boolean(process.env.NODE_V8_COVERAGE)
33
+ const bytecodeFile = process.env.DSH_PTC_COMPILER_BYTECODE
34
+ let workerCache = bytecodeFile ? deserialize(readFileSync(bytecodeFile)) : undefined
35
+ if (workerCache?.source !== compilerSource) workerCache = undefined
36
+ // Bytecode contains no compiler realm or program state. Match the complete
37
+ // source: V8's cache validation alone does not prove source text equality.
38
+ let cachedData = workerData?.compilerCache?.source === compilerSource
39
+ ? new NativeUint8Array(workerData.compilerCache.data) : undefined
40
+ // Keep the snapshot private before source code can inspect workerData.
41
+ if (workerData !== null && typeof workerData === 'object') delete workerData.compilerCache
42
+
43
+ /** Reuse compiled compiler code across fresh workers, never their realm state. */
44
+ export function compilerWorkerCache() {
45
+ if (compilerScript === undefined) return undefined
46
+ // Instrumented compiler instances neither produce nor consume bytecode.
47
+ // Coverage's runner supplies a snapshot from its uninstrumented preparation.
48
+ if (workerCache === undefined && coverageEnabled) return undefined
49
+ workerCache ??= { source: compilerSource, data: apply(createCachedData, compilerScript, []) }
50
+ return { source: workerCache.source, data: new NativeUint8Array(workerCache.data) }
51
+ }
52
+
53
+ /** Service errors are rehomed here before execution-realm translation. */
54
+ export const isCompilerSyntaxError = error => apply(hasInstance, nativeErrors.SyntaxError, [error])
55
+
56
+ function compilerEntry() {
57
+ if (compiler !== undefined) return compiler
58
+ // Workers can execute host-prepared cells without compiling dynamic source.
59
+ // Capture source and platform before user code, but parse only on first use.
60
+ compilerScript = new NativeScript(compilerSource, { __proto__: null, filename, displayErrors: false,
61
+ cachedData: coverageEnabled ? undefined : cachedData })
62
+ cachedData = undefined
63
+ const context = nativeCreateContext(dontContextify)
64
+ define(context, '__compilerBaseUrl', { value: import.meta.url })
65
+ define(context, '__filename', { value: filename })
66
+ define(context, '__dirname', { value: directory })
67
+ installCompilerPlatform(context)
68
+ apply(runInContext, compilerScript, [context, { __proto__: null, displayErrors: false }])
69
+ compiler = context.module.exports.compile
70
+ return compiler
71
+ }
72
+
73
+ function compile(operation, args, originalSource) {
74
+ const result = compilerEntry()(operation, args, originalSource)
75
+ if (result.error !== undefined) {
76
+ const { kind, message, properties } = result.error
77
+ const ErrorClass = nativeErrors[kind] ?? nativeErrors.Error
78
+ const error = ErrorClass === PreflightError
79
+ ? new PreflightError(message, undefined, copyCompilerData(properties.span?.value)) : new ErrorClass(message)
80
+ const names = keys(properties)
81
+ for (let index = 0; index < names.length; index++) {
82
+ const name = names[index]
83
+ const property = properties[name]
84
+ if (name === 'stack' || !('value' in property)) continue
85
+ define(error, name, { ...property, value: copyCompilerData(property.value) })
86
+ }
87
+ throw error
88
+ }
89
+ return copyCompilerData(result.value)
90
+ }
91
+
92
+ export const prepareProgram = (source, options) => compile('prepareProgram', [source, options])
93
+ export const prepareConsoleProgram = (source, options) => compile('prepareConsoleProgram', [source, options])
94
+ export const classifyDurability = (source, known, options) => compile('classifyDurability', [source, known, options])
95
+ export const compileModuleSource = (source, options) => compile('compileStatefulModule', [source, options])
96
+ export const detectModuleSourceFormat = (source, options) => compile('detectModuleSourceFormat', [source, options])
97
+ export const attachNamespaceSource = (source, attributes, reference, regions) =>
98
+ compile('attachModuleNamespace', [source, attributes, reference, regions])
99
+ export const linkCommonJsEvidenceSource = (source, prefix) => compile('linkCommonJsEvidenceSource', [source, prefix])
100
+ export const identifier = (value, subject, reserved) => compile('identifier', [value, subject, reserved])
101
+ export const exportedSymbols = (source, transform) => compile('exportedSymbols', [source, transform])
102
+ export const sourceDurability = (source, transform) => compile('sourceDurability', [source, transform])
103
+ export const hashText = (source, encoding, format) => compile('hashText', [source, encoding, format])
104
+ export const deflateText = source => compile('deflateText', [source])
105
+ export const inflateText = (source, maxOutputBytes) => compile('inflateText', [source, maxOutputBytes])
106
+ export const createCallableSourceCatalog = (buffers, ranges) => compile('createCallableSourceCatalog', [buffers, ranges])
107
+ export function compileDynamicSource(source, { resolveOriginalSource, ...options } = {}) {
108
+ return compile('compileDynamicEnvironmentSource', [source, options], resolveOriginalSource)
109
+ }
@@ -0,0 +1,32 @@
1
+ import { copyCompilerData } from './compiler-data.js'
2
+
3
+ /** Cache source-derived metadata within one compiler generation. Input and
4
+ * output data stay private; callers receive fresh collections on every read. */
5
+ export function createCompilerSourceCache(compute, { maxEntries = 64, maxCharacters = 512 * 1024 } = {}) {
6
+ const entries = new Map()
7
+ let characters = 0
8
+ return (source, transform) => {
9
+ // Unsupported inputs retain the owner's original validation and errors.
10
+ if (typeof source !== 'string' || transform !== undefined && typeof transform !== 'string') {
11
+ return compute(source, transform)
12
+ }
13
+ const key = JSON.stringify([source, transform])
14
+ const cached = entries.get(key)
15
+ if (cached !== undefined) {
16
+ entries.delete(key)
17
+ entries.set(key, cached)
18
+ return copyCompilerData(cached.value)
19
+ }
20
+ const value = compute(source, transform)
21
+ if (maxEntries > 0 && key.length <= maxCharacters) {
22
+ while (entries.size >= maxEntries || characters + key.length > maxCharacters) {
23
+ const oldest = entries.keys().next().value
24
+ entries.delete(oldest)
25
+ characters -= oldest.length
26
+ }
27
+ entries.set(key, { value })
28
+ characters += key.length
29
+ }
30
+ return copyCompilerData(value)
31
+ }
32
+ }
@@ -0,0 +1,93 @@
1
+ import { createSourceMapBuilder } from './source-position-map.js'
2
+
3
+ const WIDTH = 6
4
+ const BLOCK_SIZE = 4096
5
+ const TEXT = 0, COPY = 1, MAPPED = 2, JOIN = 3, REGION = 4
6
+
7
+ /** A numeric piece graph owns output without one object per copied token. */
8
+ export function createSourcePieces(source) {
9
+ const blocks = []
10
+ const strings = []
11
+ const regionFacts = []
12
+ const stringIds = new Map()
13
+ let count = 0
14
+ const get = (id, field) => blocks[Math.floor(id / BLOCK_SIZE)][id % BLOCK_SIZE * WIDTH + field]
15
+ const put = (size, kind, left, right = 0, start = 0, end = 0) => {
16
+ if (count % BLOCK_SIZE === 0) blocks.push(new Uint32Array(BLOCK_SIZE * WIDTH))
17
+ const id = count++
18
+ blocks.at(-1).set([size, kind, left, right, start, end], id % BLOCK_SIZE * WIDTH)
19
+ return id
20
+ }
21
+ const stringId = value => {
22
+ let id = stringIds.get(value)
23
+ if (id === undefined) { id = strings.length; strings.push(value); stringIds.set(value, id) }
24
+ return id
25
+ }
26
+ const length = id => get(id, 0)
27
+ const text = value => put(value.length, TEXT, stringId(value))
28
+ const original = (start, end) => put(end - start, COPY, start, end)
29
+ const mapped = (value, node) => put(value.length, MAPPED, stringId(value), 0, node.start, node.end)
30
+ const region = (piece, fact) => {
31
+ const index = regionFacts.length
32
+ regionFacts.push(fact)
33
+ return put(length(piece), REGION, piece, index)
34
+ }
35
+ const empty = text('')
36
+ const pair = (left, right) => {
37
+ if (length(left) === 0) return right
38
+ if (length(right) === 0) return left
39
+ if (get(left, 1) === COPY && get(right, 1) === COPY && get(left, 3) === get(right, 2)) {
40
+ return original(get(left, 2), get(right, 3))
41
+ }
42
+ return put(length(left) + length(right), JOIN, left, right)
43
+ }
44
+ const join = parts => {
45
+ const combine = (start, end) => end <= start ? empty : end === start + 1 ? parts[start]
46
+ : pair(combine(start, (start + end) >>> 1), combine((start + end) >>> 1, end))
47
+ return combine(0, parts.length)
48
+ }
49
+ const slice = (id, start, end = length(id)) => {
50
+ const size = length(id)
51
+ if (start === 0 && end === size) return id
52
+ const kind = get(id, 1), left = get(id, 2), right = get(id, 3)
53
+ if (kind === REGION) return slice(left, start, end)
54
+ if (kind === JOIN) {
55
+ const split = length(left)
56
+ if (end <= split) return slice(left, start, end)
57
+ if (start >= split) return slice(right, start - split, end - split)
58
+ return pair(slice(left, start), slice(right, 0, end - split))
59
+ }
60
+ if (kind === COPY) return original(left + start, left + end)
61
+ const value = strings[left].slice(start, end)
62
+ if (kind === TEXT) return text(value)
63
+ const from = get(id, 4), to = get(id, 5), linear = to - from === size
64
+ return mapped(value, { start: from + (linear ? start : 0), end: linear ? from + end : to })
65
+ }
66
+ const emit = id => {
67
+ const chunks = []
68
+ let pending = []
69
+ const mappings = createSourceMapBuilder()
70
+ const regions = []
71
+ let offset = 0
72
+ const visit = id => {
73
+ const size = length(id)
74
+ if (size === 0) return
75
+ const kind = get(id, 1), left = get(id, 2), right = get(id, 3)
76
+ if (kind === JOIN) { visit(left); visit(right); return }
77
+ if (kind === REGION) {
78
+ regions.push({ ...regionFacts[right], start: offset, end: offset + size })
79
+ visit(left)
80
+ return
81
+ }
82
+ pending.push(kind === COPY ? source.slice(left, right) : strings[left])
83
+ if (pending.length === BLOCK_SIZE) { chunks.push(pending.join('')); pending = [] }
84
+ if (kind !== TEXT) mappings.push({ generatedStart: offset, generatedEnd: offset + size,
85
+ originalStart: kind === COPY ? left : get(id, 4), originalEnd: kind === COPY ? right : get(id, 5) })
86
+ offset += size
87
+ }
88
+ visit(id)
89
+ chunks.push(pending.join(''))
90
+ return { text: chunks.join(''), mappings: mappings.finish(), regions }
91
+ }
92
+ return { text, original, mapped, join, slice, emit, length, region }
93
+ }
@@ -0,0 +1,132 @@
1
+ import traverseModule, { NodePath } from '@babel/traverse'
2
+ import { types as t } from '@babel/core'
3
+
4
+ const traverse = traverseModule.default ?? traverseModule
5
+ const SOURCE_CONTEXT = Object.freeze({ opts: Object.freeze({ noScope: true }) })
6
+
7
+ class SourceScope {
8
+ constructor(id, nodeId, parentId) { this.id = id; this.nodeId = nodeId; this.parentId = parentId }
9
+ get path() { return this.index.get(this.block) }
10
+ getFunctionParent() {
11
+ for (let scope = this; scope; scope = scope.parent) {
12
+ if (t.isFunction(scope.block) || t.isStaticBlock(scope.block)) return scope
13
+ }
14
+ return null
15
+ }
16
+ getProgramParent() {
17
+ let scope = this
18
+ while (scope.parent) scope = scope.parent
19
+ return scope
20
+ }
21
+ }
22
+
23
+ export function sourcePath(node, parentPath, container, key, listKey = null, scope = null) {
24
+ const path = new NodePath(undefined, parentPath?.node ?? container)
25
+ path.parentPath = parentPath
26
+ path.container = container
27
+ path.key = key
28
+ path.listKey = listKey
29
+ path.node = node
30
+ path.type = node.type
31
+ path.setContext(SOURCE_CONTEXT)
32
+ path.scope = scope
33
+ return path
34
+ }
35
+
36
+ /** Visit source facts with Babel's syntax predicates, retaining only ancestry.
37
+ * These paths do not enter Babel's whole-tree path/scope caches. Mutating
38
+ * transforms use separately bounded work trees instead. */
39
+ export function visitSource(tree, visitor) {
40
+ const handlers = traverse.visitors.explode({ ...visitor, noScope: true })
41
+ const callbacks = new Map()
42
+ let stopped = false
43
+ const visit = (parentPath, container, key, listKey) => {
44
+ const node = container[key]
45
+ if (node === null || node === undefined) return
46
+ const path = sourcePath(node, parentPath, container, key, listKey)
47
+ let selected = callbacks.get(node.type)
48
+ if (selected === undefined) {
49
+ selected = { enter: [...handlers.enter ?? [], ...handlers[node.type]?.enter ?? []],
50
+ exit: [...handlers[node.type]?.exit ?? [], ...handlers.exit ?? []] }
51
+ callbacks.set(node.type, selected)
52
+ }
53
+ for (const handler of selected.enter) {
54
+ handler(path)
55
+ if (path.shouldStop) { stopped = true; return }
56
+ if (path.shouldSkip) return
57
+ }
58
+ for (const field of t.VISITOR_KEYS[node.type] ?? []) {
59
+ if (path.skipKeys?.[field]) continue
60
+ const child = node[field]
61
+ if (Array.isArray(child)) {
62
+ for (let index = 0; index < child.length && !stopped; index++) visit(path, child, index, field)
63
+ } else if (!stopped) visit(path, node, field, null)
64
+ }
65
+ for (const handler of selected.exit) {
66
+ handler(path)
67
+ if (path.shouldStop) { stopped = true; return }
68
+ }
69
+ }
70
+ if (tree.type === 'File') visit(null, tree, 'program', null)
71
+ else visit(null, { root: tree }, 'root', null)
72
+ }
73
+
74
+ /** Compact ancestry survives a work tree; NodePaths are materialized on demand. */
75
+ export function indexSource(tree) {
76
+ const ids = new WeakMap()
77
+ const nodes = [], parentIds = [], keys = [], lists = [], scopeIds = []
78
+ const scopes = []
79
+ const visit = (node, parentId, key, listKey) => {
80
+ if (node === null || node === undefined) return
81
+ const parent = parentId === undefined ? tree : nodes[parentId]
82
+ const id = nodes.length
83
+ ids.set(node, id)
84
+ nodes.push(node)
85
+ parentIds.push(parentId ?? -1)
86
+ keys.push(key)
87
+ lists.push(listKey)
88
+ let parentScope = parentId === undefined ? -1 : scopeIds[parentId]
89
+ if (parentId !== undefined && (key === 'key' || listKey === 'decorators') && t.isMethod(parent)
90
+ || parentId !== undefined && key === 'discriminant' && t.isSwitchStatement(parent)) {
91
+ parentScope = scopes[parentScope]?.parentId ?? -1
92
+ }
93
+ let scopeId = parentScope
94
+ if (t.isScope(node, parent)) {
95
+ scopeId = scopes.length
96
+ scopes.push(new SourceScope(scopeId, id, parentScope))
97
+ }
98
+ scopeIds.push(scopeId)
99
+ for (const field of t.VISITOR_KEYS[node.type] ?? []) {
100
+ const child = node[field]
101
+ if (Array.isArray(child)) {
102
+ for (let index = 0; index < child.length; index++) visit(child[index], id, index, field)
103
+ } else visit(child, id, field, null)
104
+ }
105
+ }
106
+ visit(tree.type === 'File' ? tree.program : tree, undefined, tree.type === 'File' ? 'program' : 'root', null)
107
+ const parents = Int32Array.from(parentIds)
108
+ const nodeScopes = Int32Array.from(scopeIds)
109
+ const get = node => {
110
+ let id = ids.get(node)
111
+ if (id === undefined) return undefined
112
+ const ancestors = []
113
+ while (id >= 0) { ancestors.push(id); id = parents[id] }
114
+ let path = null
115
+ for (let index = ancestors.length - 1; index >= 0; index--) {
116
+ id = ancestors[index]
117
+ const node = nodes[id]
118
+ const container = lists[id] === null ? path?.node ?? tree : path.node[lists[id]]
119
+ path = sourcePath(node, path, container, keys[id], lists[id], scopes[nodeScopes[id]])
120
+ }
121
+ return path
122
+ }
123
+ const index = { get, ids, nodes, scopes, scopeFor: node => scopes[nodeScopes[ids.get(node)]],
124
+ parentFor: node => nodes[parents[ids.get(node)]] ?? tree,
125
+ }
126
+ for (const scope of scopes) {
127
+ scope.block = nodes[scope.nodeId]
128
+ scope.parent = scopes[scope.parentId] ?? null
129
+ scope.index = index
130
+ }
131
+ return index
132
+ }
@@ -0,0 +1,54 @@
1
+ /** One construction contract for compiler-owned storage in every emitted realm. */
2
+ export const compilerStorageSource = `(object, WeakMap, WeakSet, symbol, promise, reflect, arrayConstructor, functionPrototype) => {
3
+ const define = object.defineProperty, defineProperties = object.defineProperties, setPrototype = object.setPrototypeOf;
4
+ const uncurry = functionPrototype.bind.bind(functionPrototype.call);
5
+ const descriptor = (value,writable=false,configurable=false) => {
6
+ const result=object.create(null);result.value=value;result.writable=writable;result.configurable=configurable;return result;
7
+ };
8
+ if(symbol.dispose===void 0)define(symbol,'dispose',descriptor(symbol.for('nodejs.dispose')));
9
+ if(symbol.asyncDispose===void 0)define(symbol,'asyncDispose',descriptor(symbol.for('nodejs.asyncDispose')));
10
+ const mapMethods = object.create(null), setMethods = object.create(null);
11
+ for (const name of ['get','set','has','delete']) mapMethods[name] = descriptor(WeakMap.prototype[name]);
12
+ for (const name of ['has','add','delete']) setMethods[name] = descriptor(WeakSet.prototype[name]);
13
+ const values = uncurry(arrayConstructor.prototype.values);
14
+ const arrayMethods = object.create(null);
15
+ for (const name of ['push','pop','unshift']) arrayMethods[name] = descriptor(arrayConstructor.prototype[name]);
16
+ const apply = reflect.apply;
17
+ for (const name of ['concat','splice']) {
18
+ const operation = arrayConstructor.prototype[name];
19
+ arrayMethods[name] = descriptor(function(...args){return array(apply(operation,this,args))});
20
+ }
21
+ const next = uncurry(object.getPrototypeOf(values([])).next);
22
+ const description = uncurry(object.getOwnPropertyDescriptor(symbol.prototype,'description').get);
23
+ const then = uncurry(promise.prototype.then);
24
+ function array(value){
25
+ setPrototype(value,null);
26
+ defineProperties(value,arrayMethods);
27
+ define(value,'constructor',descriptor(void 0,true,true));
28
+ define(value,symbol.iterator,descriptor(function(){
29
+ const iterator=values(value);
30
+ setPrototype(iterator,null);
31
+ define(iterator,'next',descriptor(function(){return next(iterator)}));
32
+ return iterator;
33
+ },false,true));
34
+ return value;
35
+ }
36
+ return {
37
+ functionCall:functionPrototype.call,functionApply:functionPrototype.apply,functionBind:functionPrototype.bind,
38
+ promiseThen:promise.prototype.then,
39
+ record(value){return setPrototype(value,null)},
40
+ observeOwnedPromise(value,fulfilled,rejected){
41
+ setPrototype(value,null);
42
+ then(value,result=>{try{fulfilled(result)}catch(error){rejected(error)}},rejected);
43
+ },
44
+ async awaitValue(value,fulfilled,rejected){
45
+ let result;
46
+ try{result=await value}catch(error){if(rejected)return await rejected(error);throw error}
47
+ return await fulfilled(result);
48
+ },
49
+ weakMapStore(){return defineProperties(new WeakMap(),mapMethods)},
50
+ weakSetStore(){return defineProperties(new WeakSet(),setMethods)},
51
+ symbolDescription:description,
52
+ array
53
+ };
54
+ }`
@@ -0,0 +1,15 @@
1
+ import { createHash } from 'node:crypto'
2
+ import { deflateRawSync, inflateRawSync } from 'node:zlib'
3
+
4
+ /** Exact source facts cross the compiler boundary as strings, never buffers. */
5
+ export function hashText(source, encoding = 'utf8', format = 'base64') {
6
+ return createHash('sha256').update(source, encoding).digest(format)
7
+ }
8
+
9
+ export function deflateText(source) {
10
+ return deflateRawSync(Buffer.from(source, 'utf16le')).toString('base64')
11
+ }
12
+
13
+ export function inflateText(encoded, maxOutputBytes) {
14
+ return inflateRawSync(Buffer.from(encoded, 'base64'), { maxOutputLength: maxOutputBytes }).toString('utf16le')
15
+ }
@@ -0,0 +1,2 @@
1
+ // Keep the maintained legacy decorator compiler lazy in both source and bundle.
2
+ module.exports = () => require('typescript')
@@ -5,12 +5,21 @@ export const MAX_TIMER_DELAY_MS = 2_147_483_647
5
5
  export const SETTINGS_NAMESPACE = 'ptc-plus'
6
6
 
7
7
  /**
8
- * Ordered field definitions for the plugin configuration card. `label` and
8
+ * Shared field definitions for the Host schema and settings card. `label` and
9
9
  * `description` are the canonical Host schema copy; `labelEn` and
10
10
  * `descriptionEn` carry the English settings-card copy. A field's description
11
11
  * exists in both locales or in neither.
12
12
  */
13
13
  export const CONFIG_FIELDS = Object.freeze([
14
+ {
15
+ key: 'legacyBindingSettings',
16
+ type: 'boolean',
17
+ default: false,
18
+ label: '旧绑定设置迁移状态',
19
+ labelEn: 'Legacy binding settings migration state',
20
+ description: '',
21
+ descriptionEn: '',
22
+ },
14
23
  {
15
24
  key: 'enabled',
16
25
  type: 'boolean',
@@ -29,6 +38,24 @@ export const CONFIG_FIELDS = Object.freeze([
29
38
  description: '开启时使用增强工具卡片;关闭后使用 DSH 原生工具卡片。',
30
39
  descriptionEn: 'Uses enhanced tool cards when enabled and DSH native tool cards when disabled.',
31
40
  },
41
+ {
42
+ key: 'replViewEnabled',
43
+ type: 'boolean',
44
+ default: true,
45
+ label: '显示 REPL 页签',
46
+ labelEn: 'Show REPL tab',
47
+ description: '在 PTC 会话中显示 REPL 工作台;隐藏后仍可从设置管理全局绑定。',
48
+ descriptionEn: 'Shows the REPL workspace in PTC sessions. Global bindings remain manageable in Settings.',
49
+ },
50
+ {
51
+ key: 'bindingAuthorButtonVisible',
52
+ type: 'boolean',
53
+ default: true,
54
+ label: '显示 PTC Plus 快捷入口',
55
+ labelEn: 'Show the PTC Plus shortcut',
56
+ description: '在输入框旁显示 PTC Plus 快捷入口:查看和启停全局绑定、编写新绑定,并直接打开插件设置窗口;隐藏后仍可使用 /binding 命令。',
57
+ descriptionEn: 'Shows the PTC Plus shortcut beside the composer: global binding access and toggles, authoring, and direct access to the plugin settings dialog. Hiding it keeps /binding commands available.',
58
+ },
32
59
  {
33
60
  key: 'autoDescribeRunCode',
34
61
  type: 'boolean',
@@ -38,6 +65,16 @@ export const CONFIG_FIELDS = Object.freeze([
38
65
  description: '允许 run_code 缺少外层 description;关闭后恢复 DSH 校验。模型请求和原始调用参数保持不变。',
39
66
  descriptionEn: 'Allows run_code to omit its outer description; disabling restores DSH validation. Model requests and original call arguments remain unchanged.',
40
67
  },
68
+ {
69
+ key: 'bindingUpdates',
70
+ type: 'enum',
71
+ options: Object.freeze(['stateful', 'protected']),
72
+ default: 'stateful',
73
+ label: '允许重声明和覆盖',
74
+ labelEn: 'Allow redeclarations and overrides',
75
+ description: '同一作用域的声明和赋值可更新变量、函数、类及导入。关闭后检测跨 cell 重声明,并保护新建的 const 和 import;静态 import/export 始终可用。',
76
+ descriptionEn: 'Declarations and assignments update variables, functions, classes and imports in the same scope. Disabling detects cross-cell redeclarations and protects newly created const and import bindings; static import/export remains available.',
77
+ },
41
78
  {
42
79
  key: 'canonicalizeToolCalls',
43
80
  type: 'boolean',
@@ -56,6 +93,15 @@ export const CONFIG_FIELDS = Object.freeze([
56
93
  description: '开启后,PTC agent 可使用官方 Cordis 工具、配套指引和开发 Skill;关闭后移除这些能力。Cordis 工具以 DSH 进程权限运行。',
57
94
  descriptionEn: 'When enabled, PTC agents can use the official Cordis tools, guidance, and development Skill; disabling removes them. Cordis tools run with the DSH process permissions.',
58
95
  },
96
+ {
97
+ key: 'userBindingsEnabled',
98
+ type: 'boolean',
99
+ default: false,
100
+ label: '启用全局用户 Binding',
101
+ labelEn: 'Enable Global User Bindings',
102
+ description: '管理 TypeScript helper,并将已启用条目作为跨会话的默认 REPL 绑定。',
103
+ descriptionEn: 'Manages TypeScript helpers and loads enabled entries as default REPL bindings across sessions.',
104
+ },
59
105
  {
60
106
  key: 'looseTopLevelRedeclarations',
61
107
  type: 'boolean',
@@ -68,7 +114,7 @@ export const CONFIG_FIELDS = Object.freeze([
68
114
  {
69
115
  key: 'looseTopLevelFunctionClassRedeclarations',
70
116
  type: 'boolean',
71
- default: false,
117
+ default: true,
72
118
  label: '允许顶层函数/类重声明',
73
119
  labelEn: 'Allow top-level function/class redeclarations',
74
120
  description: '允许顶层 function 或 class 声明替换已有的可写 binding;不可写或保留 binding 仍会在执行前被拒绝。',
@@ -125,10 +171,10 @@ export const CONFIG_FIELDS = Object.freeze([
125
171
  default: 60_000,
126
172
  min: 1,
127
173
  max: Number.MAX_SAFE_INTEGER,
128
- label: '单 cell CPU 时间上限 (ms)',
129
- labelEn: 'CPU time limit per cell (ms)',
130
- description: '同步计算超过该上限时中断当前 cell。',
131
- descriptionEn: 'Interrupts the current cell when synchronous computation exceeds this limit.',
174
+ label: '单 cell 事件循环活跃时间上限 (ms)',
175
+ labelEn: 'Event-loop active time limit per cell (ms)',
176
+ description: '包含同步阻塞等待,不等同于 CPU 用时;超限时丢弃当前 cell 并重置 worker。',
177
+ descriptionEn: 'Includes synchronous blocking, not just CPU use; exceeding the limit discards the cell and resets the worker.',
132
178
  },
133
179
  {
134
180
  key: 'maxWallMs',
@@ -242,34 +288,46 @@ export const CONFIG_FIELDS = Object.freeze([
242
288
  },
243
289
  ])
244
290
 
245
- /** Presentation groups keep high-attention decisions separate from advanced policy and limits. */
291
+ /** Purpose-based presentation groups are independent of Host schema field order. */
246
292
  export const CONFIG_GROUPS = Object.freeze([
247
293
  {
248
- key: 'core',
249
- label: '常用与兼容性',
250
- labelEn: 'Common and compatibility',
251
- fields: Object.freeze(['enabled', 'enhancedToolView', 'autoDescribeRunCode', 'canonicalizeToolCalls']),
294
+ key: 'switch',
295
+ label: '插件开关',
296
+ labelEn: 'Plugin switch',
297
+ fields: Object.freeze(['enabled']),
252
298
  },
253
299
  {
254
- key: 'optional',
255
- label: '可选能力',
256
- labelEn: 'Optional capabilities',
257
- fields: Object.freeze(['cordisToolsEnabled']),
300
+ key: 'calls',
301
+ label: '调用容错',
302
+ labelEn: 'Tool call tolerance',
303
+ fields: Object.freeze(['autoDescribeRunCode', 'canonicalizeToolCalls']),
258
304
  },
259
305
  {
260
- key: 'advanced',
261
- label: '高级行为',
262
- labelEn: 'Advanced behavior',
306
+ key: 'syntax',
307
+ label: 'REPL 语法',
308
+ labelEn: 'REPL syntax',
263
309
  fields: Object.freeze([
264
- 'looseTopLevelRedeclarations',
265
- 'looseTopLevelFunctionClassRedeclarations',
266
- 'autoRewriteImports',
267
- 'autoStripExports',
268
- 'autoSplitRedeclarations',
269
- 'durableReplay',
270
- 'tipsEnabled',
310
+ 'bindingUpdates',
271
311
  ]),
272
312
  },
313
+ {
314
+ key: 'recovery',
315
+ label: '状态与恢复',
316
+ labelEn: 'State and recovery',
317
+ fields: Object.freeze(['durableReplay', 'tipsEnabled', 'tipCooldownMessages', 'tipEscalationFailures']),
318
+ },
319
+ {
320
+ key: 'extensions',
321
+ label: '工具扩展',
322
+ labelEn: 'Tool extensions',
323
+ fields: Object.freeze(['userBindingsEnabled', 'cordisToolsEnabled']),
324
+ },
325
+ {
326
+ key: 'interface',
327
+ label: '界面显示',
328
+ labelEn: 'Interface display',
329
+ fields: Object.freeze(['enhancedToolView', 'replViewEnabled', 'bindingAuthorButtonVisible']),
330
+ },
273
331
  {
274
332
  key: 'limits',
275
333
  label: '资源限制',
@@ -284,8 +342,6 @@ export const CONFIG_GROUPS = Object.freeze([
284
342
  'maxValueEdges',
285
343
  'maxValueArrayLength',
286
344
  'maxValueBigIntDigits',
287
- 'tipCooldownMessages',
288
- 'tipEscalationFailures',
289
345
  ]),
290
346
  },
291
347
  ])