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
|
@@ -6,21 +6,23 @@ Each top-level `run_code` executes a JavaScript/TypeScript cell with top-level `
|
|
|
6
6
|
|
|
7
7
|
With the default `bindingUpdates: 'stateful'`, declarations and assignments update one logical identity in the same scope and activation, including local const bindings. An existing closure observes later updates, while a saved function value keeps its own identity. Separate block, function and iteration scopes stay separate. A bare `let x`, `var x` or `const x` preserves an existing value and creates undefined when new. Each declarator publishes its complete candidate only after its initializer and binding pattern succeed. Earlier declarators and ordinary assignment effects remain real if a later operation fails. Unreached lexical declarations do not reserve a name for future cells.
|
|
8
8
|
|
|
9
|
-
An import alias follows its module until an actual successful assignment or declaration supplies a local value.
|
|
9
|
+
An import alias follows its module until an actual successful assignment or declaration supplies a local value. A static import in a later cell switches that same identity back to the module, so existing new-generation closures observe the change. Within one cell, all static imports install their sources before the body; an ordinary declaration or assignment in the body can override them regardless of where the import appears in the text. Named default declarations associate `__default` with the local identity until independently overwritten. Static dependencies link before the body and keep their effects even if a later dependency fails.
|
|
10
10
|
|
|
11
11
|
`bindingUpdates: 'protected'` retains native local restrictions, rejects cross-cell redeclarations, and protects newly created const/import bindings. Switching policy neither resets the worker nor freezes earlier writable identities. Historical cells replay under their recorded language generation; earlier closures retain that generation's behavior. See [ADR 0025](adr/0025-use-versioned-logical-binding-identities.md) for the ownership and compatibility contract.
|
|
12
12
|
|
|
13
13
|
New protected modules retain these native protections and the current callable source reflection contract. Their compilation generation is distinct from historical modules, including when a policy change imports the same source again.
|
|
14
14
|
|
|
15
|
+
Each session kernel owns one native Node realm. Cells, PTC-managed modules, the provided `require`, and activated Global User Binding modules execute in that realm, so Node-produced errors use the same intrinsic constructors as cell code and module evaluation observes cell writes to `globalThis`. Node's `useGlobal` REPL bootstrap is internal: its module shortcuts such as `fs`, `child_process`, and `worker_threads` are removed before code runs, and modules remain available only through the managed import and `require` paths. A binding workbench has the same rule inside its own worker; it does not share state or a realm with an Agent session. A user-created `node:vm` context or independent runtime keeps its own realm and intrinsic identities.
|
|
16
|
+
|
|
15
17
|
Every program namespace is leased to one cell. Namespace objects or member functions captured in the REPL expire when that cell ends. A reusable REPL helper must look up the current namespace inside its body. Global User Binding modules use a dynamic bridge: even a module-captured member resolves the current implementation when invoked by a new cell; a removed member fails until it is available again. Continuations retain their originating cell identity and cannot borrow a later cell's lease.
|
|
16
18
|
|
|
17
19
|
For PTC mode requests using the code-only direct-tool projection, PTC Plus presents two tools in stable order: `run_code` and `edit_run_code`. It recognizes the current Host's `tools:ptc-only` owner section and the preceding Host's `tools:code-only` alias, with the current section authoritative if both appear. The latter tool edits the most recent eligible cell visible when the edit call is dispatched, including a cell that completed successfully but needs a small adjustment. That target remains fixed while the call is in flight; later tool settlements cannot retarget it. The edit accepts exactly one atomic `edits` or `regex_edits` array and an optional `expected_target_call_seq` precondition. Invalid, unavailable, or mismatched-target edits return `{ edited: false, reason }` without executing source or consuming the target. `regex_edits[].replacement` is a JavaScript replacement template: captures are referenced as `$1`, `$2`, ... or `$<name>`, a literal dollar sign is written `$$`, and backslash forms such as `\1` are emitted literally rather than resolved as captures. `pattern` values are JavaScript regular-expression sources without delimiters.
|
|
18
20
|
|
|
19
21
|
`edit_run_code` is a real registered tool call. Session history and later model requests retain its original name and delta arguments. The plugin executes the materialized source as a host-derived `run_code`, returns only the edit status, value, and logs to the model, and keeps the complete source plus journal in private replay metadata. It does not rewrite assistant history or emit edit-specific runtime context.
|
|
20
22
|
|
|
21
|
-
When a live parse error occurs exactly at the cell EOF, PTC Plus checks
|
|
23
|
+
When a live parse error occurs exactly at the cell EOF, PTC Plus checks all 12 suffixes of one or two closing tokens drawn from `}`, `)`, and `]` with the same preparation context. If exactly one correction succeeds, the existing editor can express it from a bounded unique suffix, and the rejected call has a persistent event identity, `PTC-C001` includes a directly callable `edit_run_code({ edits: [...], expected_target_call_seq })` invocation. The guard must match the target captured when the edit call is persisted, so a later editable cell suppresses execution even when the same literal replacement would match it. The plugin does not apply or execute the correction automatically; ambiguous, broader, and unbound repairs keep the ordinary length-adaptive guidance.
|
|
22
24
|
|
|
23
|
-
Use `return` for an explicit result and `console` for logs. Native expression completion can also supply a result value:
|
|
25
|
+
Use `return` for an explicit result and the native Node `console` surface for logs. Its formatting methods, including `dir` options, tables, counters, groups, timers, assertions, and traces, retain Node semantics. `process.stdout/stderr.write`, direct fd 1/2 writes and inherited child stdio are also captured. Console entries retain call order and each descriptor pipe retains byte order; the merged log does not claim a total chronology across stdout, stderr and the private control channel. All forms share the cell's aggregate output budget. Native expression completion can also supply a result value:
|
|
24
26
|
|
|
25
27
|
```ts
|
|
26
28
|
const records = [{ id: 1 }, { id: 2 }]
|
|
@@ -29,6 +31,8 @@ return records.map(record => record.id)
|
|
|
29
31
|
|
|
30
32
|
Parse, filter, and aggregate large results before returning them. Aggregate log/return overflow terminates the worker and discards the cell; its bindings are not available for a later reduction. An encoding-budget rejection (`PTC-O001`, `invalid-output`) instead keeps the worker live, so an already initialized binding can be reduced in a later cell. Neither path undoes external effects.
|
|
31
33
|
|
|
34
|
+
Each physical cell has acknowledged start and end fences on stdout and stderr. Descriptor bytes arriving inside that window belong to the current physical run. The first output observed outside a round, or structured output whose async-local scheduling cell has already settled, produces an output-attribution diagnostic, closes capture and resets the worker rather than disappearing or being silently attached to another cell. If no cell is active, the Host retains that failure and rejects the next execution once instead of continuing to drain an unbounded background producer. Bare descriptor writes do not carry callback provenance; when they arrive inside a later acknowledged window, only that physical-arrival attribution is knowable.
|
|
35
|
+
|
|
32
36
|
Prefer executing work directly in the current cell; reserve `code.run` for source already held as data. When nested source must be written inline, escape quotes, backslashes, and newlines exactly — its parse errors point only at the generated text, not at a position in the outer cell.
|
|
33
37
|
|
|
34
38
|
## Capability Discovery
|
|
@@ -69,7 +73,7 @@ The configuration uses `ptc-plus` as the DSH plugin ID and `dsh-ptc-plus` as the
|
|
|
69
73
|
durableReplay: true
|
|
70
74
|
tipsEnabled: true
|
|
71
75
|
cordisToolsEnabled: false
|
|
72
|
-
userBindingsEnabled:
|
|
76
|
+
userBindingsEnabled: true
|
|
73
77
|
computeMs: 60000
|
|
74
78
|
maxWallMs: 600000
|
|
75
79
|
maxOldGenerationSizeMb: 512
|
|
@@ -85,7 +89,7 @@ The configuration uses `ptc-plus` as the DSH plugin ID and `dsh-ptc-plus` as the
|
|
|
85
89
|
|
|
86
90
|
The five legacy binding and module switches remain migration inputs. Complete enabled/protected choices map to the corresponding new policy; mixed old choices retain their effective controls until the user explicitly selects the new switch. The Host schema preserves an omitted `bindingUpdates` value until migration, and the settings card resolves the same policy. Selecting the switch also clears the compatibility marker.
|
|
87
91
|
|
|
88
|
-
`enabled: false` is the settings-based kill switch: the Host keeps the settings namespace, client card, and passive cleanup that can withdraw old PTC declarations at the next permitted accepted step. It removes execution hooks, prompt sections, and tool surfaces without reading binding storage. Every setting is applied live when its owner can reconcile it. A submitted cell retains one configuration snapshot through preflight, execution, binding calls, completion validation, and diagnostics; an update accepted while it runs applies to cells submitted afterward. Node fixes a worker's V8 old-generation limit at creation, so changing `maxOldGenerationSizeMb` while a session worker is active is rejected and rolled back rather than reported as applied. Other non-`enabled` updates reconfigure existing owners without replacing session-bound bindings. The settings card renders in whichever settings seat the installed DSH declares — the
|
|
92
|
+
`enabled: false` is the settings-based kill switch: the Host keeps the settings namespace, client card, and passive cleanup that can withdraw old PTC declarations at the next permitted accepted step. It removes execution hooks, prompt sections, and tool surfaces without reading binding storage. Every setting is applied live when its owner can reconcile it. A submitted cell retains one configuration snapshot through preflight, execution, binding calls, completion validation, and diagnostics; an update accepted while it runs applies to cells submitted afterward. Node fixes a worker's V8 old-generation limit at creation, so changing `maxOldGenerationSizeMb` while a session worker is active is rejected and rolled back rather than reported as applied. Other non-`enabled` updates reconfigure existing owners without replacing session-bound bindings. The settings card renders in whichever settings seat the installed DSH declares — the sidebar **Plugins → Installed** page per-bundle configuration (`plugins.row.config`), or the preceding Host's **Settings → Plugin configuration** card (`settings.plugin.item`) ([ADR 0019](adr/0019-plugin-settings-and-kill-switch.md)) — shows “已启用” or “已停用”, and disables every control except `enabled` while the plugin is off. The card does not register in General settings; the sparkle menu opens the same complete form in an application dialog. If a live enable or reconfiguration cannot install a complete runtime, PTC Plus unwinds or restores every owner and persists the last applied settings; a failed compensating settings write is surfaced as an activation diagnostic. The TypeScript language check is deferred until runtime activation, so a non-TypeScript host can load the plugin in disabled mode but cannot enable it.
|
|
89
93
|
|
|
90
94
|
`cordisToolsEnabled: true` atomically mounts the official `@deepseek-ai/dsh-tool-cordis` plugin and exactly the shipped `cordis-plugin-development` companion Skill in agent scopes that expose the `run_code` and `skill` tools plus the public preset and Skill services. PTC Plus resolves the official `cordis` preset through DSH's public preset service, lets the maintained filesystem provider own its Skill root, and filters that provider at the public registration boundary so sibling Skills are never published to the PTC scope. It does not copy the Skill or switch the agent's preset. The first request waits until the Cordis tool fiber, owner guidance, exact Skill provider, and scoped Skill load are all ready. An agent scope that omits one of those surfaces is left for later: the owner publishes nothing there, reports nothing, and retries when the tool surface changes or the next prompt is assembled. A scope whose exposed preset, Skill/tool service, declared Cordis service, inspect manifest, or activation contradicts the host contract fails the setting change at installation and removes every provisional contribution; reached through the host's own `agent/created` or assemble call it withdraws from that scope with one warning instead, so this plugin's unavailability never fails an agent another plugin created ([ADR 0029](adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md)). Disable and agent/runtime disposal remove both fibers. Native agents inherit neither the resulting `tools.*` members nor the Skill, and the code-only direct-tool projection remains `[run_code, edit_run_code]`. Cordis can evaluate model-written plugins against the live runtime, so enabling it grants shell-equivalent trust.
|
|
91
95
|
|
|
@@ -95,13 +99,15 @@ Cordis Plugins and Runs are process-local. On a resumed agent or after Cordis is
|
|
|
95
99
|
|
|
96
100
|
## Global User Bindings
|
|
97
101
|
|
|
98
|
-
`userBindingsEnabled` defaults to `false
|
|
102
|
+
`userBindingsEnabled` defaults to `true`; an explicit `false` is preserved. Omitted settings use the current default, including after an upgrade. Individual entry states and user-controlled draft saving are unchanged. While disabled, PTC Plus does not read binding storage, add new declarations, inject values, register the management RPC or `/binding` command, or render Global User Binding controls. The next permitted accepted step can withdraw previously delivered declarations. Enabling it loads the single document at `$DSH_HOME/ptc-plus/bindings.json`; writes use a file lock, atomic replacement, owner-only file permissions, and an expected process-local revision. A stale revision or an external file change rejects the mutation and requires reload rather than overwriting newer content. A damaged document produces an explicit catalog error and remains unwritable until the user repairs it and reloads.
|
|
99
103
|
|
|
100
104
|
Each entry has a stable `id`, display `name`, `namespace` or `top-level` scope, selected symbols, one-line purpose, enabled state, and TypeScript source. A namespace name must be a JavaScript identifier; a top-level entry uses its exported symbols as call identifiers and keeps `name` for display. Source must provide named value exports; default exports and re-exports are rejected. An omitted symbol list derives every named value export, while an explicit list limits the exposed API; clearing the Settings symbol field requests fresh derivation from the edited source. The parser derives declaration kinds, parameter and return annotations, bounded inferred types, and model-visible declarations from the selected source exports. A `namespace` entry contributes one object binding under its name, while a `top-level` entry contributes each selected export. Reserved REPL names and duplicate active identifiers fail validation. The document accepts at most 64 entries, 65,536 UTF-16 code units per source, 262,144 across all sources, and 16,384 across active declarations. Mutations validate the complete enabled declaration set before atomic replacement; an externally written document that exceeds the limit is reported as damaged storage and contributes no active entries.
|
|
101
105
|
|
|
106
|
+
The source-derived interface retains unshadowed environment types, such as `AbortSignal`, `Headers`, and `URL`, and includes the referenced closure of local interfaces, type aliases, enums, and classes. Local type names are isolated per entry so two bindings may expose the same name without colliding. Public class instance fields, constructor parameter properties, methods, and accessors appear in the class shape; private, protected, static, and computed members remain hidden. Getter and setter signatures retain their separate read and write types. An imported type that cannot be represented as a self-contained declaration fails validation instead of being replaced with `unknown`; qualified `import('module').Type` references remain explicit.
|
|
107
|
+
|
|
102
108
|
The current enabled snapshot is the desired input for the next cell. The independent binding API catalog represents `tools:ptc-plus-user-binding-defaults` and supplies configured prompts and selected source-derived interfaces from the first permitted request. One header identifies use inside `run_code` and replacement of the previous global binding API reference, followed only by entry labels and selected documentation. It does not prove successful activation. Successful activation, session-local shadowing and worker reconstruction do not themselves append a new binding context. Unchanged documentation is deduplicated against retained model-visible history; changed or compacted-away configuration is supplied again. Historical configuration and `tools:ptc-plus-user-bindings` snapshot sections remain readable and are withdrawn once by the next permitted accepted recovery snapshot; the current API catalog is delivered separately. The stable `tools:sdk` prefix and direct-tool schemas do not change with binding contents. A request-owned program namespace or error class takes precedence over a same-name user entry; that entry produces an activation diagnostic and is omitted from the settled snapshot without blocking independent code. If a failed initializer issued a program call, the cell becomes volatile because the successful-entry snapshot is not complete replay source for that call transcript.
|
|
103
109
|
|
|
104
|
-
Namespace members and top-level exports preserve ECMAScript module live reads until assignment or a permitted redeclaration creates a session-local shadow. A shadow is not written to the global document and suppresses only the shadowed name from subsequent global activation while the entry's other names keep activating; journals migrated from versions 1 through 7 keep their recorded whole-entry suppression. Updates, disablement, and removal affect unshadowed names from the next submitted cell. Entry imports resolve from the directory containing `bindings.json` during both candidate evaluation and session activation, independently of the session cwd.
|
|
110
|
+
Namespace members and top-level exports preserve ECMAScript module live reads until assignment or a permitted redeclaration creates a session-local shadow. A shadow is not written to the global document and suppresses only the shadowed name from subsequent global activation while the entry's other names keep activating; journals migrated from versions 1 through 7 keep their recorded whole-entry suppression. Updates, disablement, and removal affect unshadowed names from the next submitted cell. Entry imports resolve from the directory containing `bindings.json` during both candidate evaluation and session activation, independently of the session cwd. Current binding modules resolve program namespaces through their compiled logical root, with a namespace view bound to the originating cell lease. Historical `stateful-module-v1` and legacy modules retain their recorded worker-global bridge. Both paths expose newly available namespaces on later requests, stop resolving removed namespaces or members, and prevent expired continuations from borrowing a later cell's authority. When a historical bridge would replace an existing worker global, installation fails before changing that global. Once an exported value may have escaped into an ordinary session binding, its synthetic-module resolution base remains available for that worker lifetime; historical modules also retain their installed bridges. When no historical binding has ever been exposed, disabled or empty activation installs no bridge; if every attempted historical activation fails, any bridge installed for that attempt is removed before the cell executes.
|
|
105
111
|
|
|
106
112
|
The REPL tab and Settings management modal share a workbench for source editing, validation, declaration preview, revision-checked persistence, import of a local `.ts` file as a disabled entry, enablement, removal, and code execution. The code console evaluates the current unsaved source draft in a separate bounded Node REPL worker hosted by the plugin-owned helper process. Named exports can be called directly from TypeScript commands, with top-level `await` and variables retained across executions. It does not access the Agent session kernel or enter its journal. The compatible `run` RPC separately provides single-use candidate evaluation with an optional exported-function name and JSON argument array. Both execution paths retain DSH process authority: source and imports may create irreversible Node/OS effects before cancellation, timeout, or failure. Console controls and resource limits are documented in [Client UI](client-ui.md#全局用户-binding-工作台).
|
|
107
113
|
|
|
@@ -119,18 +125,20 @@ Every completed cell records the exact source-derived active snapshot in private
|
|
|
119
125
|
|
|
120
126
|
`durableReplay: false` starts new kernels without recorded REPL state while preserving live bindings in the current process. It does not delete session logs.
|
|
121
127
|
|
|
122
|
-
With `durableReplay: true`, recovery claims only bindings backed by both verified journal ancestry and exact provenance available to the model that produced the current call. DSH's append-only event log proves reconstructability; its ordered model-visible surface proves awareness. Raw events shadowed from
|
|
128
|
+
With `durableReplay: true`, recovery claims only bindings backed by both verified journal ancestry and exact provenance available to the model that produced the current call. DSH's append-only event log proves reconstructability; its ordered model-visible surface proves awareness. Before every subsequent cell in a structured host session, the runtime revalidates each existing live call against that exact surface even when `replaceGeneration` is unchanged. Raw events shadowed from the surface and UI-only `dshPtcPlusBindings` metadata do not make a binding model-knowable. A result-only replacement may retain a cell when the assistant call containing its source remains visible. If compaction shadows that call, the live worker and cold recovery contract the affected state unless an explicitly selected bounded structured projection exposes the exact bindings in model context. Such a projection is not injected by default merely to retain hidden state. Natural-language summaries are not parsed as state evidence.
|
|
123
129
|
|
|
124
130
|
An invalid historical association, prune replacement, or recovery boundary is also rejected as evidence for its bindings; it is not by itself a reason to reject every later valid `run_code`. Recovery takes the intersection of the model-knowable and structurally verified frontiers, then discards cells and bindings that may depend on an unknown boundary. Because the current journal does not contain a complete per-binding dependency graph, the conservative unit is an affected cell and suffix unless stronger owned evidence exists. If no non-empty frontier is provable, the worker starts from an empty REPL and executes the current cell as a new root.
|
|
125
131
|
|
|
126
132
|
The first continued cell reports `PTC-R002` once so the model can redeclare any missing bindings, and its result persists the contraction for later cold starts. Recovery never redispatches, reverses, or certifies effects from discarded history. This availability fallback applies only to historical PTC Plus recovery data; validation, policy, authority, approval, cancellation, and other failures of the current request retain their normal DSH behavior.
|
|
127
133
|
|
|
128
|
-
PTC dynamic messages carry `source: { kind: 'plugin
|
|
134
|
+
PTC dynamic messages carry `source: { kind: 'plugin:ptc-plus', form: 'snapshot' | 'catalog' | 'notice' }`. Current-state snapshots replace only earlier PTC state, including historical PTC aggregate sections; they do not replace the binding API catalog, tasks, Skill instructions, tool results, or other producers. Only a later binding catalog replaces an earlier catalog, and an explicit empty catalog withdraws its API documentation. Host runtime-context clearance does not invalidate the catalog; suppression gates new delivery. Empty snapshots withdraw earlier state claims. Delivery uses the public accepted pre-step decision and honors `includeRuntimeContext`, scoped suppression, and cancellation through an empty assembly witness. Committed messages and the public ordered surface drive deduplication and reconciliation after compaction or resume. Proposals do not count as delivery; raw history does not establish model knowledge.
|
|
129
135
|
|
|
130
136
|
Recovery tips are disabled with `tipsEnabled: false`. When enabled, a bounded independent PTC notice identified by `tools:ptc-plus-tip/<trigger>/<ordinal>` may appear after a repeated binding failure or a diagnostic that identifies an executable, shell, or path problem in the current execution world. The trigger and per-trigger ordinal are reconstructed from committed PTC notices and canonical historical DSH snapshot sections; each identity counts once across both sources, and visible wording does not advance history. A tip is subject to `tipCooldownMessages` and becomes detailed only after `tipEscalationFailures` unresolved matches; it never changes the code-only direct-tool list or schema. `edit_run_code` does not emit a runtime context because its real call and result already carry the relevant fact.
|
|
131
137
|
|
|
132
138
|
Static and dynamic imports retain Node's resolver from the session cwd, falling back to the worker cwd when none was recorded. Relative files, bare packages, conditional exports, URLs and attributes retain their Node meaning. A missing requested export fails at static linking before that target module evaluates. Namespace property writes still follow the namespace object's own contract; updating an alias does not mutate the namespace. A managed namespace's members are readonly: a member write is refused and leaves the member's live value unchanged, while reflection continues to report that live value. `Reflect.set` returns `false`, and `Object.defineProperty` with a different value throws `TypeError`; a direct assignment from a non-strict cell body is silently discarded, exactly as for any other readonly property.
|
|
133
139
|
|
|
140
|
+
Current `stateful-v1` and `protected-v1` cells expose one mutable, null-prototype `import.meta` object per cell. Its `url` is the file URL of the synthetic `<session cwd>/repl` parent, `filename` is that synthetic path, and `dirname` is the recorded session cwd; when no cwd was recorded, all three use the worker cwd. Relative `new URL(..., import.meta.url)`, static import, dynamic import and provided `require` therefore start from the same parent. Frozen `legacy-v1` cells retain their historical `import.meta` parse rejection. Cell source otherwise has a deliberate CommonJS-like subset: `require`, `require.resolve` and `require.cache` exist; `require.main` is `undefined`; ambient `__dirname`, `__filename` and `module` do not exist. Use `import.meta.dirname`, `import.meta.filename` and `import.meta.url` for cell path metadata.
|
|
141
|
+
|
|
134
142
|
Cell export modifiers retain local declarations; remote re-exports retain dependency loading, type-only exports are erased, and default values use the ordinary `__default` identity. Real modules expose their actual export names through a stable PTC-managed namespace. Member reads follow live sources until actual local override and return original function/object values. A namespace retained by an external function continues to provide live reads. Its readonly properties do not make it a native module namespace object. Opaque code independently using native import on the raw compiled URL, or its own native createRequire, can see the transport representation and does not receive PTC's writable-export interface. PTC-provided imports and require, binding modules, workbench commands and `code.run` children share the managed interface with independent state and lifecycle. The complete contract and acceptance conditions belong to [ADR 0025](adr/0025-use-versioned-logical-binding-identities.md#managed-module-interface).
|
|
135
143
|
|
|
136
144
|
User-selected dynamic compilers retain their native syntax goals and results. Their environments remain part of the source contract: direct eval resolves the caller's logical scope, while indirect eval and Function constructors use their owning realm's root. Environment adaptation must preserve those relationships, ordinary shadowed functions and actual effects. A valid call failing because it sees generated storage names is an implementation defect.
|
|
@@ -141,13 +149,13 @@ Intrinsic interfaces belong to their source generation. Source selects the ownin
|
|
|
141
149
|
|
|
142
150
|
Rewrites are recorded as `meta.dshPtcPlusRewrites` on the tool result (parallel to the journal, a closed schema). Settled rewrites do not emit redundant runtime context: failures already carry execution and retry guidance in their result. Only when the rewritten cell has no valid journal does `tools:ptc-plus-rewrite-info` describe unknown completion in the next model request.
|
|
143
151
|
|
|
144
|
-
`require(...)` is classified exactly like a dynamic import: allowlisted builtins (`node:assert`, `node:buffer`, `node:querystring`, `node:string_decoder`, `node:stream`, `node:util`, `node:url`, `node:zlib`) stay durable, other modules are volatile, `node:worker_threads`/`node:cluster` are rejected
|
|
152
|
+
`require(...)` is classified exactly like a dynamic import: allowlisted builtins (`node:assert`, `node:buffer`, `node:querystring`, `node:string_decoder`, `node:stream`, `node:util`, `node:url`, `node:zlib`) stay durable, other modules are volatile, `node:worker_threads`/`node:cluster` are rejected during preflight (`PTC-C002`), and non-literal arguments are dynamic module resolution. This rejection occurs before any cell statement executes, so a surrounding `try`/`catch` cannot catch it.
|
|
145
153
|
|
|
146
154
|
## Diagnostics
|
|
147
155
|
|
|
148
156
|
| Code | Meaning | State effect |
|
|
149
157
|
| --- | --- | --- |
|
|
150
|
-
| `PTC-C001` | The cell cannot be parsed | Not executed; REPL unchanged; a uniquely validated and target-bound
|
|
158
|
+
| `PTC-C001` | The cell cannot be parsed | Not executed; REPL unchanged; a uniquely validated and target-bound one- or two-token EOF closure includes a directly callable declared `edit_run_code` repair; otherwise retry a short corrected cell with `run_code`, use edit for a localized long-cell correction, and resend with `run_code` for broad, ambiguous, or unbound repairs |
|
|
151
159
|
| `PTC-C002` | Preflight rejected a kernel-control import | Not executed; REPL unchanged |
|
|
152
160
|
| `PTC-N001` | Top-level binding conflict | Not executed; REPL unchanged |
|
|
153
161
|
| `PTC-O001` | Unsupported or over-budget output | Cell executed; earlier mutations may exist |
|
|
@@ -177,7 +185,10 @@ Inside a cell, omitting the JavaScript argument of a native `tools` member is ac
|
|
|
177
185
|
- The runtime is identified as `typescript`. Stateful and protected cells erase type-only syntax and lower enums, namespaces, parameter properties, and decorators through maintained TypeScript and decorator transforms. JSX is outside the cell syntax. Historical cells retain their recorded language generation.
|
|
178
186
|
- `tools.read` is a bounded inspection window in the current DSH tool contract. Whole-file computation in `danger-full-access` should use `node:fs/promises.readFile` or streams and becomes `volatile`.
|
|
179
187
|
- Relative Node filesystem entry points, including `node:fs/promises` helpers and globbing, resolve from the recorded session cwd. Absolute paths and explicit filesystem options remain unchanged; sessions without a recorded cwd use the worker's native cwd and are classified as volatile when the access is ambient.
|
|
188
|
+
- A recorded `process.cwd` and the `process.exit`/`abort`/`kill`/`chdir` lifecycle guards are immutable, non-configurable realm properties. Lifecycle calls throw `Error` with code `ERR_PTC_PROCESS_CONTROL`; assignment cannot replace these surfaces. Plugin-private `AsyncLocalStorage` receivers have immutable captured `getStore`, `enterWith`, and `run` own methods so user prototype changes cannot alter control state. Separately, during bootstrap only, PTC Plus synchronously intercepts the private Node REPL `AsyncLocalStorage.run` call, protects that one platform receiver, and restores the prototype in `finally` before user source or microtasks can execute.
|
|
189
|
+
|
|
190
|
+
`internal/worker-realm-surfaces.js` is the tracked exception registry and write boundary for worker globals, process properties and native prototypes. Every write is classified as a stable native divergence, temporary compiler name, per-cell program binding, user declaration or restoration. A stable write must cite a registry row with the same classification; it cannot borrow a temporary or language-only row. The cwd-projected `node:fs`, `node:fs/promises`, `node:path`, and `node:child_process` callable family is a separate stable surface from `process.cwd`; its verifier compares dynamically enumerated callable descriptors and retained callable properties with a plain Node worker. Private `AsyncLocalStorage` receiver methods are likewise a separate stable surface from the temporary prototype bootstrap. Stable rows name their semantic owner, native or transport reference and executable verifier; a structured source check rejects supported direct `defineProperty`, assignment and deletion forms that bypass the boundary. Module-language behavior remains owned by the compiler/executor contract even when its `require` installation uses the same boundary.
|
|
180
191
|
- The durable import allowlist is `node:assert`, `node:buffer`, `node:querystring`, `node:string_decoder`, `node:stream`, `node:url`, `node:util`, and `node:zlib`. Other Node imports remain usable but make the cell volatile.
|
|
181
|
-
- Direct `node:worker_threads` and `node:cluster`
|
|
192
|
+
- Direct `node:worker_threads` and `node:cluster` references through static import, dynamic import, or unshadowed `require` are rejected during preflight, before any cell statement executes. Calls to `process.exit`, `process.abort`, `process.kill`, and `process.chdir` are rejected through direct `process`, `require`, and dynamic or static `node:process` imports.
|
|
182
193
|
- Cold recovery replays journals from the session log; there are no compressed checkpoints or worker-LRU eviction.
|
|
183
194
|
- DSH services or plugin APIs not exposed as a native tool or owner-provided program binding are not made callable through name-based reflection.
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 语义义务与编译验证
|
|
2
2
|
|
|
3
|
-
`npm run
|
|
3
|
+
[`semantic-obligations.json`](../semantic-obligations.json) 是插件自有语义边界的 tracked owner graph,[ADR 0031](adr/0031-close-semantic-obligations-by-owner.md) 定义其闭合范围。`npm run semantic:check` 要求 `internal/`、`src/`、`index.js`、`client.js` 与 journal migration entry 中的每个受管实现文件恰好归属一个义务,并核对 contract、可执行 evidence、依赖图、journal 连续代际以及 language/module 导出代际。报告分别统计 `preserved`、`intentional-difference`、`bounded-external` 与 `unknown`;只有 `unknown: 0` 才表示声明范围内闭合,不表示对全部 Node 或 DSH 行为的等价证明。
|
|
4
|
+
|
|
5
|
+
每项义务必须记录 owner、实现边界、源 contract、可观察量、入口、生命周期、代际、平台边界、消费者、oracle 与 evidence。新增文件会直接使 source inventory 失败;现有 owner 内新增转换时,维护者还必须判断它是否改变当前义务、依赖或 oracle。能够从中央注册点机械闭合的边界继续使用更强检查,例如 realm mutation 的分类写入入口、journal schema 和 language/module generation set。该图不能替代具体反例、覆盖率或独立 review lane。
|
|
6
|
+
|
|
7
|
+
`npm run test:semantics` 运行三个互补的确定性编译测试层。它们也由 `npm run verify` / `npm run check` 的常规测试发现机制执行,不需要网络或模型调用。定向命令用于快速诊断,不能替代完整检查、资源验收和独立审查。
|
|
4
8
|
|
|
5
9
|
| 层 | Oracle 与执行方式 | 代码 owner |
|
|
6
10
|
| --- | --- | --- |
|
|
@@ -24,6 +28,6 @@ Test262 子集位于 `test/fixtures/test262/`。`manifest.json` 记录上游仓
|
|
|
24
28
|
|
|
25
29
|
## 发布验证边界
|
|
26
30
|
|
|
27
|
-
|
|
31
|
+
完整确定性检查与有效的独立审查 lane 聚合是提交门槛,不代表发布稳定性证明。发布前仍需补齐 Node 22/24 下连续会话、反复创建与释放 worker、覆盖插桩和资源压力组合的稳定性验证。进程级失败必须保留原始退出码、signal 与 stderr;仅有测试文件级 `test failed` 无法区分运行时缺陷、引擎退出或外部终止。
|
|
28
32
|
|
|
29
33
|
Windows Node 24/26 的 worker teardown native 崩溃已由插件自有 helper 进程边界限制在可回收子进程内(见 [ADR 0027](adr/0027-run-the-session-kernel-in-a-killable-helper-process.md));`npm run check` 现在执行一次确定性运行,不再根据 TAP 文件级 abort 自动重试。发布前仍须在受支持 Node 版本上保留原始退出码、signal 与 stderr,并覆盖连续创建/释放 helper、覆盖插桩和资源压力组合。文件级失败仍按实际 owner 修复,不得用重试掩盖。
|
|
@@ -77,10 +77,10 @@ C1–C6 共同约束结果。“没有错误”不能通过破坏 C2/C3/C4/C5
|
|
|
77
77
|
| --- | --- |
|
|
78
78
|
| run_code、edit_run_code 的派生执行 | 同一语言入口、状态机制、原始参数与 call identity。 |
|
|
79
79
|
| 同 cell、跨 cell、函数、块、参数、catch、switch、循环、类初始化 | 全部声明命名空间归一化,保留各自 scope 和 activation。 |
|
|
80
|
-
| 用户绑定 initializer、候选、工作台及插件创建的 worker/bootstrap | 通过 PTC Plus 编译与状态契约适配,拥有独立 root
|
|
80
|
+
| 用户绑定 initializer、候选、工作台及插件创建的 worker/bootstrap | 通过 PTC Plus 编译与状态契约适配,拥有独立 root 和生命周期;同一 worker 内的 REPL 与 Node 模块共享原生 realm。 |
|
|
81
81
|
| 用户主动调用的 eval、Function 家族及其 alias、原型构造器、bound callable | 保留原生语法目标、编译错误与效果;适配其所属逻辑环境和源码反射,具体契约见第 5.7 节。 |
|
|
82
82
|
| 用户自行创建的 vm、新 realm、native addon 或外部引擎 | 保留该引擎的原生编译与所属环境,不把独立环境映射到调用者的会话 root,也不声称 module hook 接管了这些编译器。 |
|
|
83
|
-
| PTC Plus 自有模块加载(静态/动态/data URL、ESM/CJS) | 在 PTC
|
|
83
|
+
| PTC Plus 自有模块加载(静态/动态/data URL、ESM/CJS) | 在 PTC 执行环境内统一接入;与 cell 共享 worker 的 intrinsic identity 和 `globalThis`,不修改磁盘模块或安装包。模块内的 eval/Function 同样保持所属逻辑环境。 |
|
|
84
84
|
| 插件自有子计算、用户绑定 initializer、候选与工作台 | 编译契约一致,状态、权限与生命周期各自独立。 |
|
|
85
85
|
| 失败继续、配置切换、cold replay、模型可见状态收缩 | 实际状态与证据一致,不留下永久占位、混用语义或未知历史门禁。 |
|
|
86
86
|
|
|
@@ -382,6 +382,10 @@ C1/C6 要求扫描所有声明命名空间,不能只处理普通 lexical;C3
|
|
|
382
382
|
|
|
383
383
|
namespace 形式只有一个公开 namespace 名称,覆盖该名称自然替换整个 namespace 入口。对象成员修改按对象契约处理,不自动扩大成全局配置更新。
|
|
384
384
|
|
|
385
|
+
当前 binding module 通过编译后的 logical-root resolver 取得 request program namespace,并为每个 cell 使用绑定原 lease 的 namespace view。记录为 `stateful-module-v1` 或 legacy transform 的历史模块继续使用其 worker-global bridge;恢复必须按 snapshot transform 选择路径。两条路径都不能让过期 continuation 借用后续 cell 的 request authority。
|
|
386
|
+
|
|
387
|
+
模型可见接口由绑定源码派生。公开签名保留未被源码遮蔽的环境类型,并携带引用到的本地 interface、type alias、enum 与 class 声明闭包;每个条目的本地类型位于独立声明 namespace。class shape 包含公开实例字段、constructor parameter property、方法和访问器,并分别保留 getter 与 setter 的读写类型。无法形成自足接口的 imported type 必须在持久化前给出诊断,不能退化为 `unknown`。
|
|
388
|
+
|
|
385
389
|
整条目遮蔽是需要改变的旧语义,见 [ADR 0023](adr/0023-global-user-bindings.md);当前代际的新 cell 已按名称粒度记录覆盖/来源事实。新代际应记录 entry 级激活证据和 name 级覆盖/来源证据,旧 journal 仍保留当时的整条目行为。新代际中条目更新、禁用或删除不得抹去已经明确形成的会话覆盖;未覆盖名称按条目生命周期调整,旧闭包实际持有的值按引用生命周期保留。
|
|
386
390
|
|
|
387
391
|
这不会给模型新增写全局存储、启停条目或执行用户候选的管理权限,也不会把 session runtime value 自动转成持久源码。
|
|
@@ -478,7 +482,7 @@ cell 使用公开 Node 编译能力创建与当前 context 对齐的 async body
|
|
|
478
482
|
| --- | --- |
|
|
479
483
|
| run_code / edit_run_code | 同一 preparation 与 CompiledUnit;保留原始参数、派生关系、call identity 和 cell lease。 |
|
|
480
484
|
| code.run、插件子 worker | bootstrap 安装编译器,拥有独立 root;父子状态与原有能力关系不变。 |
|
|
481
|
-
| 用户绑定 initializer、候选、工作台 | 在类型变换和 native 编译之前接入;工作台独立状态,不写 Agent journal。 |
|
|
485
|
+
| 用户绑定 initializer、候选、工作台 | 在类型变换和 native 编译之前接入;工作台独立状态,不写 Agent journal;其 REPL 与模块共享所在 worker 的原生 realm。 |
|
|
482
486
|
| eval、Function 家族及其间接调用 | 动态环境 owner 保留所属逻辑环境、原生语法目标、转换次序与反射;不把普通同名函数当作原生编译器。 |
|
|
483
487
|
| 用户自行创建的 vm、new realm、native addon 或外部引擎 | 使用独立引擎的原生编译和环境;不继承 PTC 会话 root。 |
|
|
484
488
|
|
|
@@ -622,7 +626,7 @@ C2/C3/C4 要求分别描述:
|
|
|
622
626
|
|
|
623
627
|
### 8.4 journal 代际与旧代码
|
|
624
628
|
|
|
625
|
-
当前封闭 schema 的版本常量与字段集由 [session-journal-schema.js](../internal/session-journal-schema.js) 拥有,JOURNAL_VERSION 为
|
|
629
|
+
当前封闭 schema 的版本常量与字段集由 [session-journal-schema.js](../internal/session-journal-schema.js) 拥有,JOURNAL_VERSION 为 10;schema 包含 languageSemantics、精确的 moduleTransform、bindingPolicy、rewritePolicy、moduleSemantics(含 `importExpressionBoundary`)、userBindingsFingerprint、userBindingsReusePolicy、userBindingsShadowPolicy 与 userBindingNames 等字段。字段校验、journal 创建与旧代际迁移由 [session-journal.js](../internal/session-journal.js) 拥有,事件关联与折叠恢复由 [session-journal-recovery.js](../internal/session-journal-recovery.js) 拥有。旧 ADR 描述其决策发生时的版本,不能用历史版本叙述替代当前 schema 事实。
|
|
626
630
|
|
|
627
631
|
新代际必须区分:所有作用域可写规则、裸声明、声明 pattern 提交、import/default 来源关联、特殊命名空间、动态 grammar goal、独立单元、name 级用户绑定覆盖和实际操作证据。只重解释原有两个布尔值无法表达这些变化。
|
|
628
632
|
|
package/docs/user-bindings.en.md
CHANGED
|
@@ -6,10 +6,11 @@ Global bindings save reusable TypeScript helpers for use across sessions. For ex
|
|
|
6
6
|
|
|
7
7
|
## Create and use a binding
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
Global bindings and the sparkle shortcut default to on; a new installation needs no setup switch. If an existing configuration explicitly disables global bindings, enable them under **Plugins → Installed → dsh-ptc-plus → Configure**. If only the shortcut is hidden, enable **Show the PTC Plus shortcut**. The feature switch does not change saved entries' enabled states.
|
|
10
|
+
|
|
11
|
+
1. In a PTC session, open the sparkle menu by the composer and choose **Write a new binding**, or enter `/binding new <requirement>`.
|
|
12
|
+
2. Inspect the draft's source, interface, and model prompt in the panel above the composer.
|
|
13
|
+
3. Choose **Save and enable**. Subsequent `run_code` calls load the binding; initialization failures appear in execution results.
|
|
13
14
|
|
|
14
15
|
During authoring, the Agent starts with a small in-memory check of the core behavior, then adds normal, edge, and failure assertions with `node:assert/strict`. Bulk tests report totals and a few representative failures instead of printing every successful case into the context. Tests must not modify external files or services. File and network helpers use in-memory substitutes to verify argument forwarding and error propagation; the answer identifies integration behavior that remains untested. Submission delivers a draft for your review. You decide whether to save and enable it.
|
|
15
16
|
|
|
@@ -24,9 +25,9 @@ A new draft opens above the composer. Click the title bar or use Enter/Space to
|
|
|
24
25
|
- **Discard draft**: abandon this unsaved candidate.
|
|
25
26
|
- **Close panel**: hide it without saving or discarding.
|
|
26
27
|
|
|
27
|
-
The sparkle button shows a PTC Plus tooltip
|
|
28
|
+
The sparkle button shows a delayed PTC Plus tooltip identifying it as the global bindings and settings entry; a pending draft changes it to the draft state. The tooltip stays hidden while the menu, management dialog, or settings dialog is open. The button shows a badge for pending drafts. Open its menu by hovering, clicking, or using the keyboard, then select the draft to show it again. Each session retains one current candidate. A confirmed save or discard closes the panel; failures leave the draft available for retry.
|
|
28
29
|
|
|
29
|
-
The sparkle menu is available before the first message
|
|
30
|
+
The sparkle menu is available before the first message and opens once the pointer dwells on the entry; incidental pointer movement across the composer leaves it closed. A hovered menu closes as soon as the pointer leaves it; clicking keeps it open until you click again, click elsewhere, or press Escape. Global bindings show their names, purposes, and enabled states using status text and color. Click an entry to toggle it for all sessions. The catalog refreshes in the background, and the entries stay usable while it does; writes are serialized, so an entry stays usable during an in-flight write and a duplicate toggle is dropped rather than queued, and you reload after a conflict or failure before trying again. **Manage global bindings** opens the full workbench. **Write a new binding** and **Revise a binding** appear when the authoring command is available; the revision step lists existing entries and prefills `/binding edit <id> `. The reusable REPL binding list shows how many later cells reused each binding, with the total in the section title; the count comes from static references in each later cell's compiled source, and a redeclaration counts as neither a reuse nor a reset of the accumulated count.
|
|
30
31
|
|
|
31
32
|
The original binding request retains its requirement, status, and accepted source in history. Historical inspection does not restore permission to save that draft. When another edit changes the catalog, reload its current state before deciding whether to save.
|
|
32
33
|
|
|
@@ -36,11 +37,13 @@ Each entry has two independent settings:
|
|
|
36
37
|
|
|
37
38
|
| Setting | Purpose |
|
|
38
39
|
| --- | --- |
|
|
39
|
-
| Include interface declaration for the model | On by default. Names, parameters, return types, and API comments come from source; no separate declaration is needed |
|
|
40
|
+
| Include interface declaration for the model | On by default. Names, parameters, return types, related types, and API comments come from source; no separate declaration is needed |
|
|
40
41
|
| Prompt for the model | Optional. Add usage conditions, input constraints, or examples missing from the types |
|
|
41
42
|
|
|
42
43
|
For example, a size formatter might add: “Input is in bytes; display using IEC units.” Usage already clear from the interface need not be repeated.
|
|
43
44
|
|
|
45
|
+
The interface retains standard global types used by public signatures and includes the referenced local `interface`, `type`, `enum`, and `class` declarations. A class interface includes public instance fields, parameter properties, methods, accessors, and any self-contained heritage chain while omitting private, protected, and static members; abstract classes keep an abstract construct signature, and same-named local types from different entries remain isolated. An `import('package').Type` reference can be retained. A type or base class that cannot be represented without its source import produces an error before save instead of silently becoming `unknown`.
|
|
46
|
+
|
|
44
47
|
The model receives one line identifying `run_code` and the updated API reference, followed by entry names, configured prompts and selected interfaces. Ordinary calls do not resend unchanged documentation.
|
|
45
48
|
|
|
46
49
|
Omitting the interface leaves a separate prompt available. Omitting both does not disable execution. Enabled entries are described from the first request in a new session. Saving, enabling, disabling, deleting, or editing an entry updates the next permitted request. DSH runtime-context suppression defers delivery.
|
package/docs/user-bindings.md
CHANGED
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
## 创建和使用
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
全局绑定和星光入口默认开启;新安装无需先改设置。若已有配置显式关闭了全局绑定,可从 **插件 → 已安装 → dsh-ptc-plus → 配置** 重新开启;若只隐藏了快捷入口,可打开“显示 PTC Plus 快捷入口”。功能开关不改变已保存条目的启停状态。
|
|
10
|
+
|
|
11
|
+
1. 在 PTC 会话中打开输入框星光按钮的菜单,选择“编写新绑定”,或输入 `/binding new <需求>`。
|
|
12
|
+
2. 等待 Agent 提交草稿,在输入框上方检查源码、接口和给模型的提示词。
|
|
13
|
+
3. 选择“保存并启用”。后续 `run_code` 会加载该绑定;如果初始化失败,执行结果会说明原因。
|
|
13
14
|
|
|
14
15
|
编写过程中,Agent 会先用小型内存样例验证核心行为,再用 `node:assert/strict` 补充正常、边界和失败断言。批量测试只报告总数和少量代表性失败,避免把每个成功样例写入上下文。测试不得修改外部文件或服务;文件和网络 helper 可以用内存替代对象验证参数转发与错误传播,未实际验证的集成部分应在回答中说明。提交草稿只交给你审阅,保存与启用由你决定。
|
|
15
16
|
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
|
|
27
28
|
输入框星光按钮显示待处理草稿的角标。悬停、点击或键盘打开菜单后,选择草稿即可重新显示。每个会话保留一份当前候选。保存或丢弃确认成功后面板关闭;失败时保留草稿供重试。
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
星光按钮的 PTC Plus 提示延迟显示,说明它是全局绑定与设置入口;有待处理草稿时改为提示草稿状态。菜单、管理窗口或设置窗口打开时隐藏提示,避免遮挡。星光菜单在首条消息发出前即可使用,鼠标停留一下才展开,扫过输入区不会弹出。悬停打开后鼠标移开菜单即自动关闭;点击可让菜单保持常开,再点一次、点击别处或按 Escape 关闭。全局绑定按名称和用途列出,状态文字与颜色样式表示启用状态;点击条目切换启停,配置对所有会话生效。目录在后台刷新,刷新期间沿用上一次的列表并可以继续操作;切换写入逐条串行化,写入进行中条目保持可用,重复请求被直接丢弃;发生冲突或失败时可重新加载后再操作。“管理全局绑定”打开完整工作台;编写命令可用时显示“编写新绑定”和“修改绑定”,“修改绑定”第二步从已有条目中选择后预填 `/binding edit <id> `。REPL 可复用绑定列表会显示每项被后续 cell 复用的次数,并在区块标题显示总复用次数;次数按后续 cell 编译后源码中的静态引用统计,重定义或重声明本身不算一次复用,也不会把已累计的次数清零。
|
|
30
31
|
|
|
31
32
|
历史中的“绑定编写”请求保留需求、状态和接受时的源码。它供查看当时内容,不重新获得保存资格。目录发生并发修改时,重新加载最新状态后再决定是否保存。
|
|
32
33
|
|
|
@@ -36,11 +37,13 @@
|
|
|
36
37
|
|
|
37
38
|
| 设置 | 用途 |
|
|
38
39
|
| --- | --- |
|
|
39
|
-
| 将接口声明提供给模型 |
|
|
40
|
+
| 将接口声明提供给模型 | 默认开启。从源码生成名称、参数、返回类型、相关类型和 API 注释,无需另写声明 |
|
|
40
41
|
| 给模型的提示词 | 可留空。补充类型未表达的使用时机、输入约束或示例 |
|
|
41
42
|
|
|
42
43
|
例如,一个接受字节数的格式化函数可补充:“输入单位为字节,显示时使用 IEC 单位。”函数签名已经清楚的用法无需再写一遍。
|
|
43
44
|
|
|
45
|
+
接口会保留公开签名使用的标准全局类型,并带上实际引用的本地 `interface`、`type`、`enum` 和 `class`。类接口包含公开实例字段、参数属性、方法、访问器和可自包含表示的继承链,不暴露 private、protected 或 static 成员;抽象类仍以抽象构造签名公开,不能被模型当作普通构造器,不同条目中的同名本地类型彼此隔离。`import('package').Type` 形式可以保留,无法脱离源码 import 独立表示的类型或基类会在保存前给出错误,不会静默改成 `unknown`。
|
|
46
|
+
|
|
44
47
|
模型收到一行 `run_code` 调用位置和接口参考文档更新说明,以及各条目的名称、已配置提示词和所选接口。内容未变时不会因普通调用重复发送。
|
|
45
48
|
|
|
46
49
|
关闭接口展示不会关闭独立提示词;两者都省略也不会禁用绑定执行。已启用条目的说明在新会话首轮提供,中途保存、启停、删除或修改后在下一次允许的请求中更新。若 DSH 暂停运行时上下文投递,更新会暂缓。
|
package/docs/value-wire.md
CHANGED
|
@@ -38,7 +38,7 @@ wire 从不使用 `eval` 或 `Function` 解码,模型文本也从不作为可
|
|
|
38
38
|
|
|
39
39
|
`Atom` 是 JSON primitive,或封闭 tag:`undefined`、special number、BigInt、node reference。object node 保存有序 `[key, Atom]` entries;array node 保存 `length` 与有序 `[index, Atom]` entries,因此 hole 与显式 `undefined` 不同。decoder 拒绝未知/额外字段、重复 key/index、越界或 dangling reference、不可达 node 和非 canonical 编码;`__proto__` 通过 data descriptor hydrate,不触发 setter。
|
|
40
40
|
|
|
41
|
-
graph 发现顺序与 ECMAScript own-key 顺序共同确定唯一编码。plain JSON tree 保持线性;shared object 只编码一次。结构预算为 `maxValueNodes`、`maxValueEdges`、`maxValueArrayLength` 和 `maxValueBigIntDigits
|
|
41
|
+
graph 发现顺序与 ECMAScript own-key 顺序共同确定唯一编码。plain JSON tree 保持线性;shared object 只编码一次。结构预算为 `maxValueNodes`、`maxValueEdges`、`maxValueArrayLength` 和 `maxValueBigIntDigits`;`maxValueArrayLength` 同时限制单个数组长度与一份 graph 中全部数组声明的累计槽位,decoder 在分配目标数组前完成整个 wire 的结构、预算、可达性与 canonical 校验。总 IPC/journal/render byte ceiling 继续由 `maxOutputBytes` 约束。
|
|
42
42
|
|
|
43
43
|
## Completion 与外层投影
|
|
44
44
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Focused Verification
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
`npm run coverage:focus` provides a bounded diagnostic loop for executable
|
|
6
|
+
changes. It checks selected gate-owned sources with the smallest test set that
|
|
7
|
+
can distinguish a correction before the repository-wide release gate runs.
|
|
8
|
+
|
|
9
|
+
The focused command does not replace `npm run verify` or `npm run check` and
|
|
10
|
+
does not write a verified-tree proof. [Deterministic verification](verification.md)
|
|
11
|
+
owns command syntax, thresholds, generated evidence, and the final gate.
|
|
12
|
+
|
|
13
|
+
## Contract
|
|
14
|
+
|
|
15
|
+
- Every selected source and test must exist inside the checkout.
|
|
16
|
+
- Selected sources must belong to the full coverage gate, and selected tests
|
|
17
|
+
must be `test/*.test.js` files.
|
|
18
|
+
- Selected but unexecuted sources remain in the report as uncovered.
|
|
19
|
+
- The report applies the full gate's 100% line/function and 95% branch
|
|
20
|
+
thresholds.
|
|
21
|
+
- Compiler bytecode preparation, mock-dependent grouping, real Worker
|
|
22
|
+
instrumentation, source-map filtering, TAP diagnostics, and isolated
|
|
23
|
+
coverage collection match the full coverage runner.
|
|
24
|
+
- Node test options may follow a standalone `--` after the focused source and
|
|
25
|
+
test selections.
|
|
26
|
+
|
|
27
|
+
## Workflow
|
|
28
|
+
|
|
29
|
+
Use focused coverage after the nearest behavioral test passes or after a full
|
|
30
|
+
gate identifies a narrow coverage deficit. Select every changed source whose
|
|
31
|
+
threshold matters and the tests that exercise its distinct paths. A passing
|
|
32
|
+
focused run establishes only that selected relation.
|
|
33
|
+
|
|
34
|
+
Run one final `npm run verify` while the local review ledger has unresolved
|
|
35
|
+
findings. Once every finding is terminal, run `npm run check` on a stable tree
|
|
36
|
+
to produce the proof consumed by the commit hook. Do not run `verify`
|
|
37
|
+
immediately before `check` on the same tree because `check` already invokes it.
|
|
38
|
+
|
|
39
|
+
Temporary concurrency overrides change scheduling only. Use one only when
|
|
40
|
+
current evidence identifies scheduling contention, and do not carry it into a
|
|
41
|
+
later run without that condition.
|
package/docs/verification.md
CHANGED
|
@@ -2,7 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
`npm run check` runs `npm run verify`, checks that the source tree and review ledger did not change, and records the verified tree for the commit hook. Run `check` alone when the ledger is absent or resolved; running `verify` immediately before it repeats the full suite. While the ledger has unresolved findings, use `npm run verify` to collect verification evidence.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Incremental independent review
|
|
6
|
+
|
|
7
|
+
Independent review is partitioned before reviewers start. Create the ignored working plan, replace every placeholder, then record it against the commit that defines the change scope:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm run review:plan:new
|
|
11
|
+
npm run review:plan -- --base <base-commit>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The plan uses `dsh-review-plan/v1`, and the ignored root `REVIEW_PLAN.json` is its only active source. All five standard obligations from the template must remain present. Each standard or change-specific obligation is assigned to a lane or excluded with a concrete reason. A lane declares semantic scope, exact file paths or directory prefixes, upstream lanes, owners, consumers, and counterexamples. `.` selects the complete checkout. Paths only determine content inputs and changed-path coverage; they do not replace the semantic declarations. A lane fingerprint covers that declaration, its assigned obligations, selected raw Git entry identities, persistent invalidation generation, and upstream fingerprints. Dependencies must form a DAG. The plan command refuses missing standard obligations, placeholders, unknown obligations, dependency cycles, a non-ancestor base, and changed paths outside every lane.
|
|
15
|
+
|
|
16
|
+
The plan command prints one `review-lane <id> <head> <fingerprint>` line per lane. Lanes may be reviewed concurrently. Record each clean external report with the identity captured before that review:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm run review:lane -- \
|
|
20
|
+
--lane <id> \
|
|
21
|
+
--evidence <report-path> \
|
|
22
|
+
--expect-head <head> \
|
|
23
|
+
--expect-fingerprint <lane-fingerprint>
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
The report's last non-empty line must be `VERDICT: NO FINDINGS`. A readable findings or incomplete report retires the named lane and every declared dependent from the recorded plan before checking whether the current candidate drifted; restoring an earlier tree therefore cannot revive evidence that the report rejected. An unreadable or missing report path is a command-input error and does not retire valid evidence. Unrelated lanes remain effective. A clean report retains the captured `HEAD` as provenance; an unrelated concurrent edit or `HEAD` advance does not prevent recording. Direct input, upstream fingerprint, scope, obligation, owner, consumer, counterexample, or dependency changes do. Put findings in `REVIEW_FINDINGS.md`, fix them, and rerun only the incomplete lanes shown by `npm run review:status`.
|
|
27
|
+
|
|
28
|
+
Review-state mutations and authorization decisions use one atomic lock under checkout-local Git metadata. Plan recording, clean or negative lane recording, finalization, clearing, and pre-commit therefore have one observable order. A negative report queued behind an older clean recorder advances the reported lane's persistent invalidation `{epoch, revision}`, including while that lane is temporarily absent from the current plan, before retiring its current dependent closure. Advancement increments the revision normally and rotates to a new random epoch with revision zero at `Number.MAX_SAFE_INTEGER`, so a valid tuple never becomes unretirable. A temporarily absent lane must already have a retained tuple; unknown or mistyped lane IDs are rejected rather than creating state. Every active lane must have an explicit tuple. The tuple participates in the lane fingerprint and propagates through dependency fingerprints, so an older clean report cannot be submitted after re-addition. It survives normal `review:clear` and temporary lane removal; only a review captured after retirement can authorize the repaired fingerprint. Missing, partial, or malformed generation state blocks status and authorization. Explicit clear preserves valid generations but removes damaged generation state; plan recording then creates a new random epoch, so old reports still cannot match. The lock records a PID and unique release token and bounds acquisition, but never reclaims another owner automatically. If a command crashed, confirm that no review-state command is active, obtain the exact checkout-local path with `git rev-parse --git-path review-findings/state.lock`, remove only that directory, and retry. `review:status` remains a diagnostic snapshot and does not grant authorization. Finalization and pre-commit also re-read the active plan, candidate, proof, lane records, and evidence before they persist or return a decision, so edits made outside the review commands fail closed.
|
|
29
|
+
|
|
30
|
+
Do not mutate a recorded boundary implicitly. Every status, clean lane verdict, finalization, and commit decision compares the normalized active file with the recorded plan. Missing, malformed, or semantically changed active content blocks clean authorization; it does not block a findings or incomplete report from retiring the recorded lane closure. Whitespace and object-key formatting alone do not change plan identity. When evidence reveals a missing path or semantic dependency, edit `REVIEW_PLAN.json` and run `npm run review:plan` without another `--base`; the command reuses the recorded base. The new plan hash invalidates its aggregate verdict, but clean lane records survive when their base, complete declaration, selected Git entries, upstream fingerprints, and evidence hashes are unchanged.
|
|
31
|
+
|
|
32
|
+
After `review:status` reports `clean`, run the deterministic gate once and bind the composite verdict to it:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm run check
|
|
36
|
+
npm run review:finalize
|
|
37
|
+
git diff --check HEAD --
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
The final verdict uses `dsh-review-verdict/v2`. Pre-commit verifies its plan hash, lane fingerprints, evidence hashes, whole source fingerprint, `HEAD`, and prospective index. A later `HEAD` change retires the proof and aggregate verdict. Source or index drift blocks the gate while it differs; restoring the exact finalized candidate preserves those records, while keeping a changed candidate requires another `check` and `review:finalize`. Only lanes whose effective inputs changed need another independent review. `npm run review:clear` abandons the recorded plan, lane records, aggregate verdict, and verification proof while leaving the working `REVIEW_PLAN.json` available for revision; persistent invalidation generations remain so pre-retirement reports cannot revive in a rebuilt plan. Clearing is not a normal retry step. The prior single-report `verdict` command and `dsh-review-verdict/v1` records are not accepted.
|
|
41
|
+
|
|
42
|
+
`npm run verify` and `npm run check` validate the ledger, compare generated bundles, check syntax, run Client tests, and run all backend tests with coverage. Backend test files run in separate Node processes. The default process count is half the available CPUs, rounded down and bounded between one and four; each process can also own runtime Workers. Tests within each file retain their existing ordering. Coverage still requires 100% lines and functions and at least 95% branches, including compiler source remapping. The graded merge additionally asserts that the plugin-source closure it claims — `index.js` and every `internal/*.js` owner — appears in the merged report, so a module no instrumented process loads fails the gate instead of silently leaving it. Generated artifacts stay outside that closure: the root `compiler-*.cjs` bundles and the `internal/*.cjs` shims are remapped onto their original `internal/` sources or verified by the bundle checks, and `scripts/migrate-session-log.mjs` is verified by its own migration suite.
|
|
43
|
+
|
|
44
|
+
Use focused coverage while developing or after a full gate identifies a narrow coverage failure. Select every source whose threshold matters and the smallest test set that can distinguish the correction:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
npm run coverage:focus -- \
|
|
48
|
+
--source internal/source-position-map.js \
|
|
49
|
+
--test test/source-position-map.test.js \
|
|
50
|
+
--test test/compiler-memory-facts.test.js \
|
|
51
|
+
--test test/stateful-source-line-mapping.test.js
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Repeat `--source` and `--test` as needed. Paths must exist inside the checkout; sources must belong to the full coverage gate, and tests must be `test/*.test.js` files. Arguments after a standalone `--` are forwarded as Node test options. The focused runner uses the same compiler bytecode preparation, mock-dependent grouping, real Worker coverage instrumentation, source-map filtering, and 100% line/function plus 95% branch thresholds as the full runner. It includes selected but unexecuted sources as uncovered, so an empty report cannot pass. Its evidence and retained TAP diagnostics use the ignored `coverage/` directory.
|
|
55
|
+
|
|
56
|
+
Focused coverage establishes only the selected source-and-test relation. It does not establish full-suite compatibility and never replaces the final `verify` or `check`. A failed full gate must be diagnosed with the smallest check that reproduces its failure before another full run. Because `check` already invokes `verify`, running both consecutively against an unchanged tree repeats the full suite without adding evidence.
|
|
6
57
|
|
|
7
58
|
Source fingerprints use Git with temporary administrative files, an index and an object directory. Configuration includes and repository attributes preserve canonical content, and newly computed objects stay in the temporary directory. One tagged file inventory identifies tracked, missing, untracked and sparse entries without repeatedly starting Git for each category. The temporary files are written directly, avoiding repeated Git initialization and configuration processes; explicit Git command arguments preserve isolation across Windows/WSL command forwarders.
|
|
8
59
|
|
|
@@ -20,7 +71,7 @@ Remove-Item Env:DSH_PTC_TEST_CONCURRENCY
|
|
|
20
71
|
|
|
21
72
|
Coverage runs additionally set `DSH_PTC_TEST_WORKER_COVERAGE=1` and load `scripts/instrument-worker-coverage.mjs` through Node's `--import`; that test-only seam adds the coverage variable to the helper's inner-Worker launch environment so real kernel, console, and candidate worker branches are measured. Production never sets the marker and continues to project `NODE_V8_COVERAGE` out of the user Worker environment. Because some transport tests install module mocks before importing the real transport, the runner executes two backend groups into the same coverage directory: the mock-dependent files run without the preload, and the remaining files run with it. Each group writes its own `run-*-mock.tap` or `run-*-instrumented.tap` diagnostic, both managed by the same retention and cleanup lifecycle. Test arguments such as `--test-name-pattern` are placed before the selected file list so Node applies them to test selection rather than treating them as file inputs.
|
|
22
73
|
|
|
23
|
-
`npm run coverage`
|
|
74
|
+
`npm run coverage` and `npm run coverage:focus` print their current stage and total elapsed time. Each invocation collects worker coverage in its own temporary directory under `coverage/`, removed after c8 finishes reporting, so simultaneous runs cannot erase or combine each other's evidence. The default report is printed to the terminal. A separate `coverage/run-*.tap` log retains Node's test diagnostics, including process exit codes and signals that the concise terminal reporter can omit. An explicit Node test reporter option replaces these default reporters. Source changes during verification still invalidate a `check` proof; separate coverage directories do not make concurrent source edits safe.
|
|
24
75
|
|
|
25
76
|
Windows Node 24 and 26 reproductions and stacks identify a cppgc finalizer (`node::contextify::ContextifyScript`, or `ContextifyContext` when coverage was enabled) running after the environment that owned its private realm was gone, which wrote through a dangling `node::Realm` during isolate teardown. The reproduction ended the whole DSH process when an in-host session worker was terminated; macOS runners also observed whole-file aborts under coverage, but the available evidence does not establish that those aborts came from the same Windows stack or that the same cause applies across platforms. The session kernel now runs in a plugin-owned helper process (`internal/kernel-child.js`); `IsolatedWorker` sends a cooperative shutdown and, if the helper does not leave within its bound, kills only that helper. DSH is no longer the worker-teardown target on any supported host, so a wedged kernel is contained as a helper failure rather than a host-native crash. `.github/workflows/ci.yml` sets `DSH_PTC_TEST_CONCURRENCY: 1` and runs `npm run check` once; the former file-level retry wrapper is gone, and any failing test or file-level abort fails that run. This boundary removes the plugin's in-host kill exposure; it neither repairs the upstream Node path nor proves the macOS abort shared the Windows cause.
|
|
26
77
|
|