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,27 @@
1
+ # 0030 Serve Both TYPERT Codec Generations from One Codec
2
+
3
+ Date: 2026-09-18
4
+
5
+ ## Problem
6
+
7
+ PTC Plus publishes its Remote services through DSH's TYPERT registry, and that registry validates every strict codec it is handed before any endpoint exists. The codec carries the decoder for one wire member, and DSH changed where the host reads it: the preceding generation keeps the decoder on `codec.schema` and evaluates `codec.schema.parse(value)`, while the current generation keeps a `create()` factory, rejects a codec without it, and evaluates `codec.create().parse(value)`. The plugin published only the preceding shape, so a release that requires `create` fails registration inside the plugin's own activation: the Host entry never activates and the Client entry reports a failed fiber, although every import, load check, and type-level use still succeeds.
8
+
9
+ ## Decision
10
+
11
+ `internal/typert-codec-compat.js` owns the codec shape PTC Plus publishes. `strictCodec({ typeSymbol, schema })` returns one codec that carries both members — `schema` for the preceding generation and `create()` for the current one — and both resolve to the same decoder object, which presents the maintained schema runtime as the `parse` member each generation evaluates.
12
+
13
+ Each generation validates only the member it owns and ignores the other, so one published contract serves whichever shape the installed host implements. Compatibility follows the live acceptance behavior of the registry rather than a release version, and the decoder is published once, so a host that reads both members cannot obtain two different decoders for one wire member.
14
+
15
+ CI registers the packed contract with the installed host's own registry on both the stable and alpha channels (`scripts/dsh-rpc-contract-smoke.mjs`), so a generation that changes this validation fails the packaging check instead of reaching users.
16
+
17
+ ## Alternatives Considered
18
+
19
+ 1. **Detect the installed generation and publish the matching member.** Rejected: the registry exposes no capability flag or version-free signal for this, so detection would end up as a DSH version gate — the compatibility mechanism [ADR 0017](0017-track-the-latest-dsh-public-surface.md) replaces. The two shapes are also not mutually exclusive, so nothing forces a choice.
20
+ 2. **Publish only `create()` and drop `schema`.** Rejected: the preceding generation rejects a codec without `schema.parse`, so that trades one release's compatibility for another's instead of covering both.
21
+ 3. **Keep a second descriptor builder for the current generation.** Rejected: two builders would drift, and the wire contract — type symbols, parameter names, wire fields, the shared result envelope — is one contract that must stay identical for both generations.
22
+ 4. **Rely on the CI import and load check to catch this.** Rejected: both pass with an unacceptable codec. The failure appears only when the registry validates a registration, which happens inside plugin activation in the Host and in the browser.
23
+ 5. **Publish the codec members lazily through getters that probe the host.** Rejected: a getter would have to resolve the host's validation rule per access, and a codec is read while the host builds its own records — a probe there is both fragile and unnecessary when both members can simply be correct.
24
+
25
+ ## Consequences
26
+
27
+ One plugin build serves the stable and alpha channels for this surface, and the compatibility rule lives in a single module with the decoder published once. A future generation that requires another member, or that rejects a codec carrying a member it does not know, needs this owner updated; the regression test is CI's registration against the installed registry, which fails on the channel that changed instead of on the user's machine. The decoder keeps the project's maintained schema runtime, so a host that validates payloads itself still evaluates the same semantics the plugin's own tests exercise through both members.
@@ -9,9 +9,12 @@ PTC Plus 把 DSH PTC 模式的顶层 `run_code` 变成与 session 绑定的连
9
9
  | Authority / policy | DSH / 宿主 | 不复制;每次 native tool dispatch 仍经过原流水线 |
10
10
  | Capability view | DSH 当前 scope | 保留 native typed `tools.*`,为一个 cell 建立统一 lease |
11
11
  | Evaluation | session worker | 连续求值、顶层 binding、预算与输出编码 |
12
+ | User-global defaults | PTC Plus Host + session worker | 原子存储、源码派生快照、请求激活与 session-local shadow |
12
13
  | Journal / replay | PTC Plus + session log | 记录 call transcript、settlement、completion 和恢复边界 |
13
14
  | Presentation | DSH + PTC Plus | 保留 native guidance,并追加 REPL 指引与最小 explorer 声明 |
14
15
 
16
+ 求值层由插件自有的 helper 进程承载:Host 只持有 `IsolatedWorker` transport,真实 `node:worker_threads` session worker 与其私有 `MessagePort` 都留在 helper 内,IPC 只传输 plain data。宿主回收卡住的计算时只强杀自己的 helper process,DSH 进程内没有需要终止的 session worker,因此不会触达已测得会落入 Node 24/26 cppgc teardown fault 的 in-host worker 强杀路径;`IsolatedOwner` 只在该实例的 real exit、output close 和 cleanup 都完成后释放。kernel、console、candidate 三个入口各自拥有 owner。helper 的 `init` 携带 fork 前 snapshot 的投影环境,user Worker 及其子进程保持原 env 契约,不会继承 `NODE_V8_COVERAGE` 等宿主 instrumentation;Electron Host 只在 helper fork 环境覆盖 `ELECTRON_RUN_AS_NODE=1`,该启动变量不进入 user Worker。inner Worker 的 compute budget 在每次请求提交时通过 helper 的 on-demand sample 取新鲜 `eventLoopUtilization` baseline,ready handshake 另有启动样本;采样失败按 worker-exit 有界失败且不派发 prepare/run。唯一例外由 [ADR 0024](adr/0024-repl-console-observation.md) 所有:同一 worker 已确认存在未完成的 observation 时,prepare 可先于预算启动,确认 observation 完成后才开始计时。
17
+
15
18
  主入口接管模型直接发起的顶层 `run_code`,并通过 DSH tool registry 真实注册 `edit_run_code`。
16
19
  使用 code-only direct-tool projection 的 PTC request 始终按固定顺序暴露 `[run_code, edit_run_code]`;插件用 agent scope 的
17
20
  `tools.register()` 真实注册 edit transport,并用同一 scope 的 `tools.presentAs('both')` 放行这两个 provider tool call,再把其他 native tool 保留在 program SDK。首次可判定的 prompt assembly 在安装这项 presentation effect 前建立 agent composition owner;注册与 mode 记录都在所属 session、agent 或插件释放时撤销,native-mode 与无关 agent scope 不继承 `edit_run_code`。
@@ -31,32 +34,63 @@ DSH 为一个 agent composition 固定选择 `native`、`ptc` 或 `both`。首
31
34
 
32
35
  `internal/session-log-view.js` 单次前向扫描 session events,分别投影最新执行、可编辑目标、rewrite metadata、规范 journal 中的 Cordis transcript 计数和恢复 tip
33
36
  所需事实。`edit_run_code` 不产生专用 runtime context:真实 call/result 已完整表达操作身份和结果,额外 contribution
34
- 只会触发 DSH 聚合 runtime-context 全量快照并重复无关 policy 文本。只有失败或完成状态不可信的 rewrite feedback 才保留独立生命周期;成功的透明改写不产生 runtime context。
37
+ 会重复已有事实;此类信息不进入独立 PTC 消息。只有缺少有效 journal、无法确认完成状态的 rewrite feedback 才保留独立生命周期;已结算失败的恢复指引由当前结果表达;成功的透明改写不产生 runtime context。
35
38
 
36
- 插件卸载时恢复仍由自己持有的 `CodeRuntime.run` 与 `presentationMeta` 属性;若外层插件仍持有旧 wrapper,已卸载 wrapper 会透明委托原 provider,不会恢复已释放的 session 状态。
37
- 稳定 REPL 指引说明 cell 是 async function body、module 使用 dynamic import 或 require,并要求显式
38
- return 或打印需要展示的值。失败恢复先按状态分类:解析或 preflight 失败且 `state: unchanged`、无外部效果证据时,
39
- 禁止重发完整源码,优先使用 `edit_run_code` 做精确修正并重放完整 cell;`state: partially-applied` 或可能已有外部 effect 时新建短
40
- `run_code` 并复用已有 binding,完整重写只保留给结构性改动或超出编辑预算的修正。能力和命令执行依赖当前 request
39
+ 插件卸载时恢复仍由自己持有的执行缝 `run` 与 `presentationMeta` 属性;执行缝由 `internal/execution-seam-compat.js` 按宿主注册的服务选定,并同时收回该插件无法兑现的 provider 描述符(见 [ADR 0028](adr/0028-attach-to-the-host-ptc-execution-seam.md))。若外层插件仍持有旧 wrapper,已卸载 wrapper 会透明委托原 provider,不会恢复已释放的 session 状态。
40
+ 稳定 REPL 指引与执行共同从 `binding-update-policy.js` 取得语言代际。新代际说明 TypeScript、顶层 await/return、静态 import/export 与所选绑定更新策略;旧兼容态才按其独立开关说明支持的模块语法。显式结果使用 return,日志使用 console;原生表达式 completion 同样可以提供结果值。失败恢复先按状态分类:result 已证明解析或 preflight 未执行且提供符合任务意图的 validated repair 时,
41
+ 优先直接使用带目标保护的 `edit_run_code`,无需等待 recovery context;该验证只证明语法/preflight 接受。其他小型修正可用 edit 执行完整 cell;
42
+ 已执行或可能产生外部 effect 的目标,则必须依据操作 owner 的 retry/idempotence 契约和执行事实判断重跑。短 `run_code` 可以复用仍存活的 binding,但缩短源码不能证明幂等。能力和命令执行依赖当前 request
41
43
  与 execution world,模型必须先探查 live binding、实际 executable 和路径语义,不假设某个平台、shell 或 package runner。
42
44
 
43
45
  live `PTC-C001` 若精确落在源码 EOF,独立的 bounded analyzer 只把追加单个 `}`、`)`、`]` 的三个源码分别送入该 cell 提交时的同一 preparation context。仅当唯一候选通过、无 binding collision,现有 exact editor 能从不超过固定预算的唯一尾部物化同一源码,并且 runtime 已取得该 rejected `run_code` 的持久 call sequence 时,诊断才输出一行可直接调用的 `edit_run_code({ edits: [...], expected_target_call_seq })`。edit transport 把该 sequence 与其 call event 捕获的目标比较,目标已变化时不编辑也不派生执行。这项 validated repair 优先于长度阈值,但只证明语法/preflight 接受;插件不自动 dispatch,也不改写原始 `run_code`。非 EOF、多候选、多 token、超预算、缺少目标身份或后续 preparation 拒绝均使用 length-adaptive help。
44
46
 
45
- 稳定指引保留这些跨任务不变量和失败恢复的优先动作。长 cell 失败的短提示直接作为当前 `PTC-X001` 的结构化 `help` 输出,避免一次性建议触发完整 runtime-context 快照;重复绑定失败和当前 execution world 中由诊断确认的 executable、shell 或 path 错误仍由当前 session log 派生为 `tools:ptc-plus-tip/<trigger>/<ordinal>` runtime context,分别提示能力探查或重新确认环境。投影只接受 DSH system-prompt owner 的规范快照,并按命名 section 的有效状态变化重建提示;聚合快照重复同一 section 不增加次数,正文不参与身份判断。
47
+ 稳定指引保留这些跨任务不变量和失败恢复的优先动作。长 cell 失败的短提示直接作为当前 `PTC-X001` 的结构化 `help` 输出;重复绑定失败和当前 execution world 中由诊断确认的 executable、shell 或 path 错误仍由当前 session log 派生为以 `tools:ptc-plus-tip/<trigger>/<ordinal>` 标识的独立 notice,词法失败指向可见源码与初始化,worker-owned capability 失败才指向能力探查,平台错误则提示重新确认环境。投影合并规范 PTC notice 与历史 DSH system-prompt snapshot sections,同一已投递 identity 跨两种来源只计一次,正文不参与身份判断。
46
48
  相同提示受 `tipCooldownMessages` 间隔约束,连续未解决时才升级为详细版本,成功 cell 会重置未解决计数;提示不会改变
47
49
  system sections、tool schema 或 tool order,也不假设 Windows、WSL、POSIX、shell 或 package runner。
48
50
 
49
- 当前策略位于独立的 `internal/recovery-tips.js` local provider,核心只消费其有界的 named context。另一个固定名称 `tools:ptc-plus-cordis-recovery` 只在新 agent 或 Cordis 重新启用代际观察到历史 Cordis transcript 时出现,将 replay value 限定为历史数据,并保持到 session log 出现新的成功 `cordis_inspect*` settlement;它不受疲劳阈值控制、不重放调用,也不推断 live process 是否实际丢失。外部决策插件必须提供稳定的 facts/decision contract 才能接入;缺少该契约时,核心不猜测跨插件 API,并继续使用 local provider。
51
+ 当前策略位于独立的 `internal/recovery-tips.js` local provider,核心消费其有界 named tip,并按 ADR 0010 的独立消息契约投递。另一个固定名称 `tools:ptc-plus-cordis-recovery` 只在新 agent 或 Cordis 重新启用代际观察到历史 Cordis transcript 时出现,将 replay value 限定为历史数据,并保持到 session log 出现新的成功 `cordis_inspect*` settlement;它不受疲劳阈值控制、不重放调用,也不推断 live process 是否实际丢失。外部决策插件必须提供稳定的 facts/decision contract 才能接入;缺少该契约时,核心不猜测跨插件 API,并继续使用 local provider。
50
52
 
51
53
  ## 设置与启用开关
52
54
 
53
55
  Host half 通过 DSH 公共 settings 服务注册 `ptc-plus` 命名空间,优先使用 provider-owned `installSection()`,并兼容根模块的 `installSettingsSection()`;两条路径共享同一 fallback、watch、rollback 与 disposal 语义。字段清单、默认值与校验来自 `internal/config-spec.js`。
54
- Client half 通过 `settings.plugin.item` 卡片呈现全部配置。`enabled` 是 kill switch:关闭时只保留 settings 注册和设置卡片;`enhancedToolView` 是默认开启的正文展示开关,关闭时只交还 DSH 原生 `run_code`/`edit_run_code` generic row,
55
- 不注册 runtime、hook、tool surface 或 system prompt section;`ptc` 与兼容 `code` preset 会话在头部单独显示 `PTC Plus` 指示器。设置卡片显示“已启用/已停用”,稳定指引不包含 UI 品牌名。
56
+ Client half 通过宿主当前代的设置座位呈现全部配置:旧代际是 `settings.plugin.item`(keyed,按 namespace),当前 DSH 是 Plugins 页面的 `plugins.row.config`(keyed,键 `<包名>#<行 id>`),两者由 `src/client-host-compat.js` 同一次发布、由声明槽位的一代渲染,页面按 `summary`/`page` 视图分别取一句描述与完整表单([ADR 0019](adr/0019-plugin-settings-and-kill-switch.md))。`enabled` 是 kill switch:关闭时保留 settings 注册、设置卡片与撤销旧 PTC 声明所需的被动 presentation cleanup;`enhancedToolView` 是默认开启的正文展示开关,关闭时只交还 DSH 原生 `run_code`/`edit_run_code` generic row,
57
+ 总开关关闭时不注册 runtime、执行 hook、tool surface 或 system prompt section,也不读取 binding 存储;`ptc` 与兼容 `code` preset 会话在头部单独显示 `PTC Plus` 指示器。设置卡片显示“已启用/已停用”,稳定指引不包含 UI 品牌名。
56
58
  `autoDescribeRunCode` 默认开启且只控制请求绑定的本地执行策略。开启时,缺少外层 `run_code.description` 的调用使用派生参数通过本地 DSH 校验,备用摘要仅进入 presentation metadata;关闭时由 DSH 校验原始参数。两种状态的模型可见 tool schema、tool order 和 system sections 保持字节稳定并包含 required `description`;原始调用参数、cell 与嵌套 native 参数保持不变。
57
59
  所有字段都由 settings watch 即时交给各自 owner,且不替换已有 session-bound binding。每个已提交 cell 固定其提交时的配置代际,timer、worker 消息、program binding bridge、结果校验和诊断共同消费该快照;重配置更新随后提交 cell 的默认值。`maxOldGenerationSizeMb` 在活动 worker 存在时因 Node 的创建期限制而拒绝并回滚。settings 服务缺失时 Host 回退到 composition config,并保持相同的运行时语义。
58
60
 
59
- `cordisToolsEnabled` 默认关闭且即时生效。Host 只在可见 `run_code` 的 agent scope 中挂载官方 `@deepseek-ai/dsh-tool-cordis`,并通过公共 `agentPresets` service 定位 shipped `cordis` preset,再用维护中的 Skill filesystem plugin 把其 companion Skill 目录发布到同一 scope。两个 child fiber、tool guidance 与 `cordis-plugin-development` Skill 是一个 mount;首轮 request 等待完整发布和 scoped Skill load 验证,关闭、agent/runtime 释放或任一激活失败时逆序卸载。工具名、数量、schema 和 guidance 直接来自 official tool fiber,Skill 内容直接来自 shipped preset,Host 均不复制。官方插件同时向 process-global `cordisInspect` 注册 Host provider;owner 将 manifest 相同的 per-agent 注册合并为引用计数 lease,查询委托给当前仍存活的官方 registration,最后一份 lease 释放后才注销 provider。manifest 不一致时启用失败。该开关不切换 preset,也不改变 code-only direct-tool projection。
61
+ `bindingUpdates` 是新配置的统一入口,默认 `stateful`,也可选择 `protected`。Host schema 保留该字段原始缺省状态,再由 `runtime-config.js` 把完整旧策略映射到相应新策略;混合旧开关保留显式 `legacyBindingSettings` 兼容态。Client 复用同一 resolver,仅在兼容态展示旧开关;用户选择统一开关时,一次 settings update 同时写入新策略并清除兼容标记。
62
+
63
+ `cordisToolsEnabled` 默认关闭且即时生效。Host 只在同时暴露 `run_code`、`skill` 工具与 `agentPresets`/`skills` service 的 agent scope 中挂载官方 `@deepseek-ai/dsh-tool-cordis`,并通过公共 `agentPresets` service 定位 shipped `cordis` preset,再用维护中的 Skill filesystem plugin 把其 companion Skill 目录发布到同一 scope。两个 child fiber、tool guidance 与 `cordis-plugin-development` Skill 是一个 mount;首轮 request 等待完整发布和 scoped Skill load 验证,关闭、agent/runtime 释放或任一激活失败时逆序卸载。缺少其中任一 surface 的 scope 不是错误:owner 保持 pending、不在该 scope 发布内容,并在工具 surface 变化或下一次 prompt assembly 时重试;由宿主自身调用触达的不可用 scope 只从该 scope 撤出并记一条 warning,不使 `agents.create()` 或 prompt assembly 失败([ADR 0029](adr/0029-keep-plugin-unavailability-out-of-the-host-agent-lifecycle.md))。工具名、数量、schema 和 guidance 直接来自 official tool fiber,Skill 内容直接来自 shipped preset,Host 均不复制。官方插件同时向 process-global `cordisInspect` 注册 Host provider;owner 将 manifest 相同的 per-agent 注册合并为引用计数 lease,查询委托给当前仍存活的官方 registration,最后一份 lease 释放后才注销 provider。manifest 不一致时启用失败。该开关不切换 preset,也不改变 code-only direct-tool projection。
64
+
65
+ ## Global User Bindings
66
+
67
+ `internal/user-bindings.js` 是条目、文档、请求快照和有界声明的严格规范化 owner。它从命名 value export 的 TypeScript 源码派生 symbols、binding kind、body-free declaration、durability 与 fingerprint,并封闭校验所有衍生字段;调用方不能提交一份与源码不一致的声明或 snapshot。源码声明保留未被遮蔽的环境类型,并收集公开签名引用的本地 interface、type alias 与 class 闭包;各条目使用独立声明 namespace,公开 class shape 包含实例字段与 constructor parameter property。无法形成自足声明的 imported type 在持久化前拒绝,不能静默替换为 `unknown`。`namespace` scope 产生一个条目名对象,`top-level` scope 产生选定导出;保留名称和启用集合中的调用标识符冲突在持久化或请求激活前拒绝。
68
+
69
+ 可选 `modelContext` 与源码一起持久化,包含默认开启的接口注入开关 `includeDeclaration` 和独立注入的提示词 `instructions`。声明只有源码派生这一份,不另行编写。非空 metadata 参与条目 fingerprint;旧条目省略该字段时保持原序列化与 fingerprint,存储文档无需迁移。此前保存的 `enabled` / `declaration` 字段保留规范化形式以验证旧 fingerprint,但旧自定义声明不用于展示或注入;旧关闭状态映射为声明关闭、提示词为空,下一次编辑保存使用新字段。Client 安全的结构校验和偏好映射由 `internal/user-binding-model-context.js` 复用,预算和完整 schema 见 [ADR 0023](adr/0023-global-user-bindings.md)。
70
+
71
+ `internal/user-bindings-store.js` 独占 `$DSH_HOME/ptc-plus/bindings.json`。单一 JSON 文档避免源码与 metadata 双源;进程内队列、file lock、磁盘文本比较、expected revision 和 atomic replacement 共同防止并发覆盖。每次 mutation 在替换前验证完整 enabled snapshot 的声明预算;外部写入的超限文档按损坏输入处理。损坏输入保持显式 error,不会被空文档静默覆盖。候选与正式激活的相对 import 都以该文件所在目录为基准,因此 session cwd 不会改变 helper 的依赖解析。
72
+
73
+ prompt assembly 为每个 PTC request 取得一次当前启用条目快照,作为随后 dispatch 的期望集合。`tools:ptc-plus-user-binding-defaults` 从首轮通过追加的 PTC API catalog 展示条目提示词及按开关选择的源码派生接口,按稳定 ID 排序,只描述配置 API 与执行时初始化契约;组装不执行源码,也不读取激活状态或加入 revision。`/binding` 保存并启用、会话中途启停、删除或修改模型上下文后,下一次宿主允许且接受的步骤追加当前说明或撤销旧说明,无需等待激活。条目变化不改写 system、tool schema、顺序或旧消息;未变说明按已提交日志与公共 ordered surface 去重,重启后继续使用相同证据。停用条目不贡献内容,关闭声明且提示词为空的条目同样省略。
74
+
75
+ 配置段是全局绑定提示词与接口的唯一注入来源,不包含实现源码;成功初始化、session-local shadow 和 worker 重建本身不生成活动公告,也不触发相同配置重发。执行结果与诊断拥有实际行为证据;需要验证可用性时只对已知名称做无副作用观察。历史 `tools:ptc-plus-user-bindings` 活动段保留读取支持,下一次允许且接受的快照撤销旧活动声明一次。`tools:sdk` 与 direct-tool schema 不随条目内容改变。配置 API 不证明当前值,也不延长被 compaction 遮蔽的 session-local 状态。runtime 在 cell preflight 前把期望集合映射到 BindingCatalog,再由 worker 激活:当前覆盖粒度为 `per-name`,同名 session-local binding 只覆盖对应全局名称,同条目的其他名称继续激活;v1-v7 历史 cell 保留整条 entry 退出的旧粒度。条目级失败产生诊断并从该 cell 排除,不阻塞独立代码。失败 initializer 一旦发起 program call,整个 cell 进入 volatile,因此只包含成功条目的结果 snapshot 不会被误作该调用的 cold replay source。
76
+
77
+ 每个 session kernel 和 binding workbench 各自使用所在 worker 的原生 Node realm。cell、PTC 管理模块、provided `require` 与 binding module 因而共享 intrinsic identity 和 `globalThis`;用户显式创建的 `node:vm` context 或独立运行时保留自己的 realm。
78
+
79
+ worker 对 namespace 成员和 top-level 导出保留 ECMAScript module live read;对顶层名称的赋值或重声明将该名称转换为 session-local binding,并使该名称在后续全局激活中保持 session-local 覆盖,同一条目的其他名称不受影响;v1-v7 历史 cell 仍按整条来源条目退出。当前 `stateful-module-v2` binding module 通过编译后的 logical-root resolver 取得 program namespace,并为每个 cell 建立绑定原 lease 的 namespace view。`stateful-module-v1` 与 legacy binding module 保留其记录代际的 worker-global bridge。两条路径都使旧 continuation 无法借用后续 cell 的 authority,并在后续 request 反映 namespace 的新增与移除。需要安装历史 bridge 且名称与既有 worker global 冲突时,安装在写入前整体失败,避免覆盖 Node intrinsic 或留下部分 namespace。一个导出闭包一旦可能被普通 session binding 保存,worker 就无法证明其不可达,因此相应 synthetic-module 解析基准与历史 bridge 保守保留到 worker 结束。worker 从未成功暴露过需要 bridge 的条目时,disabled 或 empty activation 不安装 bridge;若本次尝试全部失败,则在执行 cell 前移除本次安装的 bridge。
80
+
81
+ 配置段以消息文本直接投递,不进入 system renderer;提示词与声明中的 `{{...}}` 保持字面量,不被解释为宿主变量。投递遵守 runtime-context suppression、取消和步骤准入,解除屏蔽后的下一请求同步当前说明。worker 对同一条目 ID 只比较源码、scope、namespace 调用名和有序导出列表来决定模块复用;模型上下文、purpose 或 top-level 显示名称变化不重置模块状态,也不重复初始化。
82
+
83
+ 每个结算 cell 把实际激活的完整 snapshot 放入私有 `meta.dshPtcPlusUserBindings`。包含模型上下文的完整 fingerprint 继续拥有快照校验与 provenance。snapshot v2 的 `transform` 由固定版本的 `internal/typescript-transform.js` 编译器 owner 提供,并参与快照 fingerprint;恢复先验证转换代际,不能用当前编译器替代未知历史转换器。未记录该代际的非空 v1 snapshot 按 unknown-boundary 规则收缩,空 v1 snapshot 保持原 fingerprint 和恢复资格。journal 的 `userBindingsReusePolicy` 为新 cell 记录 `implementation-v1`;v1-v5 则迁移为 `fingerprint-v1`,v6 保留其记录值。覆盖粒度与复用代际相互独立:`userBindingsShadowPolicy` 为新 cell 记录 `per-name`,v1-v7 迁移为 `whole-entry`;`userBindingNames` 按名称记录该 cell 结算时的 provider/local/absent/unknown 事实,provider 事实另带 `entryId`,`whole-entry`、noop 与 discarded cell 为显式 `null`,并与并行快照共同校验名称证据的完整性与来源。对仍可证明的历史,cold replay 重新验证源码及其所有派生字段,逐 cell 应用记录的复用策略,保留因 purpose 或 top-level 显示名称变化而发生的模块重置;接续的 live cell 使用新策略,不因策略切换本身重置模块。恢复不读取当前文件来替换过去状态,也不重新派发初始化中的宿主调用。缺失或未知策略与其他无法证明的 metadata 一样,按 session recovery 的 unknown-boundary 规则收缩。
84
+
85
+ `internal/user-bindings-owner.js` 只在 `userBindingsEnabled` 开启时经 `internal/host-rpc.js` 注册由宿主 Gateway、Host/Origin fence 与浏览器认证保护的管理 Remote。它从精确 agent scope 的公共 `run_code` tool view 判断资格,在 agent 创建和 `tools/change` 时协调 `/binding`,不依赖 preset 名称。命令 registration 由该 agent 的注入 fiber 持有;命令服务迟到时保留 pending fiber,回调若已失去资格则失败并清理占位。生命周期监听的安装代际独立于请求与 projection 代际,不能因 projection 就绪而跳过注册。Agent disposal 只清理该精确 Agent 的资源,session disposal 才按 session ID 清空。Client 从 Host command directory 判断首轮前的 composer 编写入口,已有文本不被覆盖。REPL 全局绑定区和 Settings 管理弹窗复用完整工作台,通过 RPC 管理持久条目,不依赖当前存在 PTC 会话;会话观察及其独立 UI metadata 边界见 [ADR 0024](adr/0024-repl-console-observation.md)。
86
+
87
+ `/binding new` 与 `/binding edit` 经 `agent.steer` 追加完整编写指引并启动普通 turn 后完成 admission;该成功不宣称草稿已生成。`internal/user-binding-authoring.js` 拥有稳定 `code.submitBindingDraft({requestId, entry})` SDK、发现 schema 与字段说明,候选校验仍由 `user-bindings.js` normalizer 拥有。runtime bridge 在 cell 创建时捕获请求,提交时核验精确 agent、requestId、代际、lease 与单次提交资格,并在异步验证后重查。SDK 存在性由配置决定,瞬时资格不通过挂卸 tool 或 Skill 表达。program transcript 的 cold replay 只返回旧交接结果,不再提交或恢复草稿。
88
+
89
+ 接受结果的私有 metadata 同时保留 opaque locator 与完整 source-owned candidate,后者携带 requestId 和 commandId。`ptcPlusBindingDraft` projection 从真实 command、turn 和接受结果派生当前编写状态,并独立保存只读历史;历史可跨重挂载、seed 和 owner 代际重建,旧 locator 不恢复。管理 Remote 不提供 caller/session identity,因此草稿 RPC 只接受 capability。用户保存或丢弃完成后,Host 消费可写 locator,并用公共 `Session.append` 追加引用 accepting result 的结构化 action notice;正文只含身份与保存/启停事实,不含源码或 locator,也不宣称激活。回执 append 失败不能撤销已完成写入或恢复保存资格。`draft-review` 提供当前生命周期内的只读结果,持久关系由 projection 的精确 source relation 验证;不能用后来修改的同 ID 存储条目替换历史源码。完整格式由 [ADR 0023](adr/0023-global-user-bindings.md) 拥有。
90
+
91
+ Client 遇到冲突后重读 catalog、draft 和 review;只有权威空 draft 才撤销操作,仍有效的候选保留供用户决定重试。new draft 使用 create-only write,edit 保持原 ID;用户保存为停用或保存并启用都原子认领草稿并校验 revision,并发 discard 返回 busy。Agent、session、功能或 owner 结束撤销相关 locator 与内存 review,迟到的存储结算不能复活它们。仅撤销未保存草稿不追加持久化回执。
92
+
93
+ 全局绑定代码控制台通过 `internal/user-binding-console.js` 按需创建 Node REPL worker,直接运行当前源码草稿并跨命令保留临时变量;普通错误保留此前状态。Host 生成 opaque handle,限制同时存在的环境和单环境并发,沿用执行时间、输出与内存预算;连续 10 分钟未执行、源码替换、离开工作台、停止或 owner 释放时终止环境。旧候选 `run` RPC 保持兼容。两条路径都不连接 Agent kernel 或写入 session journal;源码和 import 仍拥有 DSH 进程的 Node/OS 权限,外部 effect 不能回滚。`replViewEnabled` 与 `bindingAuthorButtonVisible` 仅控制各自 UI 入口,`userBindingsEnabled` 仍拥有整个全局绑定能力。模型没有常驻 binding 管理 API,插件也不从 session binding 反推模块源码:缺少完整源码 provenance 时,session-to-global promotion 无法无损实现。
60
94
 
61
95
  ## Prompt 前缀稳定性
62
96
 
@@ -69,27 +103,37 @@ Client half 通过 `settings.plugin.item` 卡片呈现全部配置。`enabled`
69
103
  | Replacement | 只有 DSH 拥有的 compaction 或其他显式 surface replacement 可以替换已保留历史;PTC Plus 不用 replacement 表达瞬时状态。 |
70
104
  | Independent request | 新的辅助模型调用必须单独说明 route、prefix 和 token 影响,不能用它的缓存表现证明主会话前缀稳定。当前插件不发起辅助模型请求。 |
71
105
 
72
- 一次性或会变化的 session 状态必须作为 `PromptAssembly.contexts` 的命名贡献交给 DSH。DSH 将完整快照记录为带来源的 `user/message` 并追加到历史尾部;值未变时不重复,值变化或全部消失时追加更新或 clearance。完整快照携带当时所有 owner 的命名 context,因此任一贡献变化都会使未变化贡献在新的尾部消息中再次出现;这会增加 append-only history token,但不会改写已有前缀。PTC Plus 不通过绕过 prompt assembly 的私有消息通道规避这项宿主聚合成本。Cordis 恢复 context 使用规范 journal 的历史 transcript 与当前 agent/enable generation 作为事实源,不能从进程内 Plugin registry 直接生成未记录输入。此类状态不得进入 `PromptAssembly.sections`,也不得通过增删 tool、改变 schema 字段或调整 tool order 传递。
106
+ PTC 动态状态通过 DSH 公共 `agent/pre-step` 追加为 `source.plugin: ptc-plus` 的独立 `user/message`。未知完成状态的 rewrite feedback 与 Cordis recovery 构成有界 `snapshot`;全局绑定 API 说明使用独立 `catalog`;恢复 tip 是以 trigger/ordinal 为 identity 的 `notice`。恢复快照只替代 PTC 旧状态,空快照撤销旧状态,不替代绑定目录、authoring task、Skill、tool result 或其他 producer。PTC 更新不重发其他 owner 文本,其他 owner 的 aggregate 更新也不重发未变 PTC 信息。`systemPrompt.context` 中的空 witness 受 `includeRuntimeContext` 与 scoped suppression 管理且不渲染 aggregate 文本;assembly 捕获精确请求事实,pre-step 委托宿主 waterfall 后只对匹配且未取消的 accepted step 提议消息。已提交记录与公共 ordered surface 共同决定去重和状态重申;缺少公共 surface 时不推断可见状态,不投递。raw history 只可用于 tip identity/cooldown,不能让隐藏 binding 变成模型知识。关闭 PTC 后仅保留撤销旧声明所需的被动 presentation cleanup,不安装 runtime 或读取 binding 存储。Cordis 恢复使用规范 journal 与当前 agent/enable generation;绑定目录只描述当前启用配置,不要求激活证明。目录和恢复快照分别去重与撤销,Host aggregate 的撤销不适用于目录;暂停只限制新投递。历史快照中的绑定段由一次恢复快照退役。此类状态不得进入 `PromptAssembly.sections`,也不得通过 tool/schema/order 变化传递。来源、边界与历史兼容由 [ADR 0010](adr/0010-session-log-derived-recovery-tips.md) 拥有。
73
107
 
74
108
  所有模型可见输入都必须能从 session log 重建。静态 system/schema 由 `request/header` 保存,动态 context 由带来源的 `user/message` 保存;进程内临时状态不能直接成为未记录的模型输入。在同一插件版本与配置下,普通执行结果、可编辑目标、诊断和其他插件拥有的运行期变化都不得改变 header;`edit_run_code` 的身份与结果由真实 call/result 表达,不生成 edit feedback context。插件升级、显式配置变化、provider/model route 变化、真实 native capability schema 变化,以及 DSH 拥有的 history replacement 可以使缓存从首个变化 token 起失效。
75
109
 
110
+ 全局绑定条目属于可变的用户计算输入;修改其提示词、接口、源码或启用集合通过上述追加通道同步,不能套用静态插件配置变化的例外来重写 header。配置说明可从已提交 PTC catalog 重建,且不为保留隐藏的 session-local 状态提供额外证明。
111
+
76
112
  缓存稳定性必须有 keyless contract test:跨每个相关生命周期状态序列化并比较完整 system text 与有序 tool schemas,同时断言 edit 不增加 runtime context。真实模型的 `cacheReadTokens` 只作为端到端补充;“不破坏缓存”表示插件保留已有可复用前缀,不承诺 provider 建立、保留或命中缓存。
77
113
 
78
114
  ## 能力表面
79
115
 
80
- cell 直接使用 DSH 为当前 request 提供的 `tools.*`,不按工具名过滤,不翻译已提供的 program-call 参数或 canonical result。只有完全省略参数且 DSH 的 live object schema 验证 `{}` 合法时,worker 才在 encoding 前把 omission 规范为 `{}`;显式 `undefined`、需要输入的 member 与其他 namespace 不变,调用方携带的内部 metadata 不能扩大这项集合。模型 direct-call 边界与这个 data-plane contract 分离:声明的顶层 transport 是 `run_code` 和 `edit_run_code`;可证明的误发 native call 可先规范为 `run_code`,native member 随后在 cell 内 nested dispatch。所有 native member、`capabilities.*`、`repl.state` 和 `code.run` 共享 cell lease;cell 结束后,捕获的函数统一失效。调用时仍由 DSH 检查 scope、policy、取消和 scheduler。
116
+ cell 直接使用 DSH 为当前 request 提供的 `tools.*`,不按工具名过滤,不翻译已提供的 program-call 参数或 canonical result。只有完全省略参数且 DSH 的 live object schema 验证 `{}` 合法时,worker 才在 encoding 前把 omission 规范为 `{}`;显式 `undefined`、需要输入的 member 与其他 namespace 不变,调用方携带的内部 metadata 不能扩大这项集合。模型 direct-call 边界与这个 data-plane contract 分离:声明的顶层 transport 是 `run_code` 和 `edit_run_code`;可证明的误发 native call 可先规范为 `run_code`,native member 随后在 cell 内 nested dispatch。所有 native member、`capabilities.*`、`repl.state` 和 `code.*` 共享 cell lease;cell 结束后,捕获的函数统一失效。调用时仍由 DSH 检查 scope、policy、取消和 scheduler。
81
117
 
82
- `capabilities.tree/find/inspect` 是描述 API,不是反射调用入口。默认 SDK 只展开这个导航器;`repl.state` 与 `code.run` 保持可调用,但其完整契约只在 explorer 中按需返回。explorer 合并 live tool schema 与插件自有 program-binding 描述;可证明的 metadata 包括名称、描述、输入/输出 schema、authority 和 replay。effect 与 result completeness 没有 owner 证据时保持 `unknown`。探索不会授予权限或触发额外模型调用。
118
+ `capabilities.tree/find/inspect` 是描述 API,不是反射调用入口。默认 SDK 展开这个导航器,Global User Bindings 开启时另声明稳定的 `code.submitBindingDraft`;`repl.state` 与 `code.run` 保持可调用,但其完整契约只在 explorer 中按需返回。explorer 合并 live tool schema 与插件自有 program-binding 描述;可证明的 metadata 包括名称、描述、输入/输出 schema、authority 和 replay。effect 与 result completeness 没有 owner 证据时保持 `unknown`。探索不会授予权限或触发额外模型调用。
83
119
 
84
120
  当前公共扩展面没有跨 prompt assembly 与 cell dispatch 的冻结 view token。PTC Plus 使用同一 agent scope 分别读取 prompt 和 runtime view,并让实际 request binding 成为执行事实;能力在两阶段之间变化时,不伪造原子快照保证。
85
121
 
86
- CodeRuntime request 已携带的 owner-provided program namespace 会被原样保留并共享 cell lease,PTC Plus 不翻译其参数或结果。与插件保留的 `capabilities`、`code` 或 `repl` 同名时 request fail-fast,避免主线程与 worker 绑定分叉;普通 cell 局部变量允许自然 shadow 这三个低频 namespace,必要时可通过 `globalThis` 访问。`tools` 仍是保留名称,因为 shadow 它会切断主要能力面。当前公共扩展面没有用于发现额外服务的 program-binding registry;插件不提供名称分发总线或私有 provider registry。若 DSH 以后提供统一 registry,PTC Plus 只消费实际 request 中的 live binding,不复制 authority 或 discovery。
122
+ 执行缝 request 已携带的 owner-provided program namespace 会被原样保留并共享 cell lease,PTC Plus 不翻译其参数或结果。与插件保留的 `capabilities`、`code` 或 `repl` 同名时 request fail-fast,避免主线程与 worker 绑定分叉;普通 cell 局部变量允许自然 shadow 这三个低频 namespace,必要时可通过 `globalThis` 访问。`tools` 仍是保留名称,因为 shadow 它会切断主要能力面。当前公共扩展面没有用于发现额外服务的 program-binding registry;插件不提供名称分发总线或私有 provider registry。若 DSH 以后提供统一 registry,PTC Plus 只消费实际 request 中的 live binding,不复制 authority 或 discovery。
87
123
 
88
124
  ## REPL 生命周期
89
125
 
90
- 每个顶层 `run_code` 是同一 session kernel 的下一格。顶层 binding 跨 cell 保留;默认开启的变量策略允许一个完整 declarator 全部替换已有变量,关闭时拒绝变量重声明,关闭 `autoSplitRedeclarations` 时混合新旧名称的解构也在执行前拒绝。独立的 `looseTopLevelFunctionClassRedeclarations` 默认关闭;开启后,重复的 named function/class 声明只在已有 binding 经源码 provenance 证明可写时,于声明位置 lowering 为赋值。函数使用匿名 function expression,使递归读取可替换的 outer binding;class 使用 named class expression,保留内部 self-reference,且 class 求值失败不会覆盖旧值。该 lowering 不保留函数声明 hoisting;不可写 const/import、保留名称与来源不明目标在执行前拒绝。cell 始终作为 async function body 求值,支持 block scope、top-level `await` 和普通控制流 return;return lowering 通过顶层 `this` receiver 访问每个 cell 独立生成并在 settlement 清理的 worker-global signal property,因此 lexical `globalThis` 与 `with` object environment 都不能重定向控制流。worker 启动时验证该 receiver 指向 evaluator 的 global context。跨 cell 重声明是 REPL 便利策略,由 `internal/repl-convenience.js` 独立实现;它不是 cell 语言或原生 JavaScript 语义的组成部分。
126
+ 每个顶层 `run_code` 在独立 native frame 中执行,session root 的逻辑身份跨 cell 保留。`repl-scope-normalizer.js` 用正式作用域归属归一化局部 activation;`stateful-root-compiler.js` 生成 root 读写、候选提交、模块依赖和源码映射,`stateful-root-runtime.js` 持有实际来源和值。`stateful` 下同 scope 的声明与赋值更新同一身份,包括 const、function、class 和 import;不同 block、function 与 iteration 保留各自身份。完整 declarator 成功后才发布,普通赋值保留真实部分写入。旧闭包观察同一逻辑身份的新值,保存的函数值保持自身身份。`protected` 保留原生局部限制并检测跨 cell 覆盖。详细语言与代际契约由 [ADR 0025](adr/0025-use-versioned-logical-binding-identities.md) 拥有。
91
127
 
92
- 包裹前的 AST 重写适配模块语法(cell 是 async function body,模块声明在函数体内非法):全部默认开启且可用 config 关闭(`autoRewriteImports` / `autoStripExports` / `autoSplitRedeclarations`)。原始 Babel Program 在任何 lowering 或 preload 前完成 scope validation;同一 cell 的 value import 与 lexical、hoisted `var`、function 或其他 import 重名会按模块 binding 规则拒绝,block shadow 和 type-only 名称仍合法。静态 `import` 声明产生有序 module preload record;worker 通过短生命周期 ESM adapter 让 Node 从 session cwd 完成解析和 export linkage,再在 cell 编译前通过生成的临时 global identifier 把 namespace 交给另一个持久 lexical identifier。两者都避开当前源码、持久 binding、program binding 与活跃 private namespace,生成的 prologue 直接引用临时 identifier,因此 lexical `globalThis` shadowing 不参与 host capture;临时 global 在 cell settlement 清理。session 未记录 cwd 时,解析基准回退到 worker process cwd;目标模块的依赖保持各自的自然 parent。scope-aware alias lowering 保留 named/default binding 的 live read、只读、shadowing 和跨 cell 重放语义。`export default` 的固定公开名 `__default` 通过同一 alias lowering 指向持久 private slot;只有既有 binding 明确带有 synthetic-default provenance 时才可复用该 slot,普通 binding、import alias 或 reserved name 冲突都在执行前拒绝。后续合法 default export 在原声明位置更新该 slot,不依赖变量重声明开关,并且只有 worker 在更新后发出 commit signal,BindingCatalog 才更新公开定义来源。function/class replacement 的 commit identity 进一步绑定到每个 declaration occurrence,同一 cell 的同名后续声明若因 return 或异常未执行,不会覆盖 inventory 中最后实际提交的定义。提前 return 或 class 求值失败因此不会发布未执行的 alias 或 replacement 更新。value alias 活跃时,原始 Program 上的 direct `eval` 与 `WithStatement` 在任何 preload record 生效前拒绝,因为生成的 namespace property read 无法复现它们的动态 lexical resolution;没有 value alias 的非严格 `with`、type-only import 和局部 shadow 的 `eval` 仍使用普通 JavaScript 语义。顶层 `export` 修饰符剥离(声明保留、`export default` 转为 `__default` 绑定、re-export 转预加载的副作用模块、type-only 擦除);REPL 便利层在 `autoSplitRedeclarations` 开启时按插件定义的兼容规则 lowering 混合新旧名称的顶层解构,关闭时保持原文走既有解析失败路径。无法精确适配的形态在执行前拒绝。改写来源以 `meta.dshPtcPlusRewrites` 平行记录(journal schema 封闭)。成功改写不改变下一步决策,因此不产生 runtime context;改写后失败或缺少有效 journal 时,`tools:ptc-plus-rewrite-info` 才在下一轮说明恢复边界。
128
+ `compiler-service.js` 是 cell、模块、动态源码、工作台 completion 与 binding-source metadata 的同步准备入口。编译器及其维护中的 JavaScript 依赖在私有 VM realm 中运行;`compiler-data.js` 复制数据集合与紧凑 source map,服务重建调用方诊断,`compiler-platform.js` 和 realm 内的 factory 只提供编译所需的捕获操作。平台原语在用户执行前固定,路径和压缩由编译器私有依赖处理,转换不发现外部配置。该 realm 不持有用户程序值、模块图、journal 或权限,源码反射查询只允许同步的字符串回调;编译仍受既有 worker 预算和生命周期约束。
129
+
130
+ 纯模块转换由 `module-compilation.js` 返回代码、映射、导出描述和静态 link/source-registration 事实;`stateful-module-compiler.js` 在编译器外消费这些事实,负责 Node 公共 hooks、文件格式判定和运行时注册。`compiler-operations.js` 每次编译建立一次绑定索引,各 AST 分区独立记录新增名称、私有传输操作、生成调用外壳与用户值边界。静态和动态调用适配消费同一 planner;helper 参数中的用户表达式仍按源码处理,生成操作不会被重复当作用户调用适配。运行时的模块图、逻辑 root 和 legacy adapter 通过 `compiler-intrinsics.js` 消费内部事实,不重新进入用户的集合协议。可选 TypeScript 编译依赖由私有平台按需加载到同一 realm;平台成员、产物一致性和原预算下的实际执行分别由构建契约与行为测试核验,详细生命周期见 ADR 0025。
131
+
132
+ cell 的静态 import 与 remote re-export 产生有序 preload,Node 继续拥有解析、链接、attributes、缓存和模块效果。import 为逻辑身份提供 live 来源;成功写入形成局部覆盖,重新导入恢复模块来源。模块、绑定候选、正式激活、工作台和隔离 `code.run` 接入共同编译契约,各自保留独立状态与生命周期。模块公开接口选择 PTC 管理的稳定 namespace:读取沿正式来源关系取得逻辑值,原生导出仅承担所需传输,不把 provider 的动态来源复制成值镜像。传给外部函数的 namespace 同样保持实时读取;外部代码独立原生导入 compiled URL 的传输接口不承诺同一可写语义。实例化、TDZ、反射、全部入口与原生获取边界由 [ADR 0025](adr/0025-use-versioned-logical-binding-identities.md#managed-module-interface) 拥有。
133
+
134
+ 用户主动动态编译保留原生语法目标与结果;调用环境仍须与源码一致。直接 eval 解析到调用处逻辑作用域,间接 eval 和 Function 家族使用各自 realm 的 root。`dynamic-scope-analysis.js` 为归一化和编译提供共同的声明归属、初始化查找与 eval activation 路径事实;`dynamic-environment-compiler.js`、`dynamic-environment-runtime.js` 与入口适配负责实际环境,`dynamic-binding-evidence.js` 核验动态声明的来源。这些职责不能用“外部编译”豁免,尚未通过的动态反例仍是实现缺陷。
135
+
136
+ `dynamic-native-runtime.js` 为 eval、四种 Function 构造器和 Function.prototype.toString 持有每个 owned realm 与语言代际的稳定接口。`dynamic-native-calls.js` 在源码的取值与调用边界选取接口,包括属性读取、原生调用结果和异步恢复结果;源码传出的接口在原生或不透明回调中继续使用所属环境和源码事实。`native-root-dynamic.js` 在冻结的 legacy 声明转换之后准备动态入口,通过既有 import namespace owner 保留 helper ancestry:legacy 动态源码使用原生 REPL 环境,并为缺少已初始化原生 lexical 存储的名称桥接目录证明的逻辑绑定;新代使用逻辑 root,两者均消费 managed module namespace。legacy 的实际初始化与结算同样回传逻辑来源和写入证据。全部全局与原型属性保持原生,kernel ambient getter 也只返回原值并记录 volatile 读取,因此旧闭包跨模式、异步与模块继续执行时仍保留原来的环境和已保存的接口身份。direct eval 以原始 intrinsic 执行显式调用环境;普通用户函数保持 canonical identity,用户改写不被接口准备覆盖。`callable-source-facts.js` 的编译器源码事实和已拥有 realm 的 intrinsic 关联跨 realm 共享;另外创建的用户 realm 保持独立。未编译 VM 源码自行读取原生 toString 时仍由原生引擎返回源码;要由不透明 observer 观察原始源码,可以向其传入所属代际的源码观察接口。
93
137
 
94
138
  可确定的计算和 recorded-value capability call 可以推进 durable head。未进入 journal 的 Node/OS 能力、环境输入、时钟、随机数和 timer 进入 sticky `volatile`;live worker 继续可用,cold replay 回到最后 durable frontier。`require(...)` 与动态导入按同一白名单分类:白名单内置模块(assert/buffer/querystring/string_decoder/stream/util/url/zlib)保持 durable,其余 volatile,`worker_threads`/`cluster` 等内核控制模块在执行前以 PTC-C002 拒绝。durable 只描述冷恢复对已结算历史的重放能力;失败 cell 仍可能已经修改 binding 或产生外部 effect,不能由 durability 推导出安全重试。worker thread 是生命周期隔离,不是安全沙箱。
95
139
 
@@ -101,13 +145,23 @@ CodeRuntime request 已携带的 owner-provided program namespace 会被原样
101
145
 
102
146
  ```ts
103
147
  {
104
- version: 4,
148
+ version: 10,
149
+ languageSemantics: "legacy-v1" | "stateful-v1" | "protected-v1",
150
+ moduleTransform: "amaro@1.1.11" | "stateful-module-v1+amaro@1.1.11" |
151
+ "stateful-module-v2+amaro@1.1.11" | "protected-module-v1+amaro@1.1.11",
105
152
  bindingPolicy: {
106
153
  variableRedeclarations: boolean,
107
154
  functionClassRedeclarations: boolean
108
155
  },
109
156
  rewritePolicy: { autoRewriteImports, autoStripExports, autoSplitRedeclarations },
110
- moduleSemantics: { defaultExportBinding: "legacy-variable" | "live-readonly" },
157
+ moduleSemantics: {
158
+ defaultExportBinding: "legacy-variable" | "live-readonly",
159
+ importExpressionBoundary: "legacy" | "statement-safe"
160
+ },
161
+ userBindingsFingerprint: string | null,
162
+ userBindingsReusePolicy: "fingerprint-v1" | "implementation-v1",
163
+ userBindingsShadowPolicy: "whole-entry" | "per-name",
164
+ userBindingNames: { name, state, entryId? }[] | null,
111
165
  status: "durable" | "volatile" | "discarded" | "noop",
112
166
  calls: CallTranscript[],
113
167
  operations: StateOperation[],
@@ -118,9 +172,9 @@ CodeRuntime request 已携带的 owner-provided program namespace 会被原样
118
172
  }
119
173
  ```
120
174
 
121
- `bindingPolicy` 与 `rewritePolicy` 固化可配置的 cell 语言行为;`moduleSemantics` 固化不可配置的 lowering 代际。当前 journal 写入 `live-readonly` default-export alias,v1-v3 迁移为 `legacy-variable`,因此 cold replay 不从当前实现或源码猜测历史 `__default` 的可写性。`calls` 只保存 global、member、PTC Value Graph 编码的 args/result 或 error,以及 settlement 序号。cold replay 校验调用名称、参数、数量和提交顺序,并按 recorded settlement order 释放 recorded result;不会重新 dispatch program binding 或重做外部 effect。该规则同样适用于 native tools、owner-provided namespace 和 `code.run`,不按名称分支。Cordis 的进程内对象不会因此被宣称已恢复;presentation 可以从已验证 transcript 派生重新检查要求,但不能改变 replay。若基础设施终止时仍有未结算 binding,heap 回滚到 durable frontier,discarded journal 以最先观察到的 `global.member` 保留 possible-effect boundary。effect、completeness 和 source metadata 属于 capability explorer,不伪装成 journal 字段。
175
+ `languageSemantics` 选择语言契约,`moduleTransform` 选择确切 parser、compiler 与 lowering generation;两者必须是允许的配对。v1–v8 固定迁移为 legacy transform,v9 按发布时映射恢复,其中 `stateful-v1` 使用 `stateful-module-v1`,不能按当前 transform 重解释。`bindingPolicy`、`rewritePolicy` 与 `moduleSemantics` 保留历史细分契约;新代际从统一策略派生它们,旧代际由冻结编译器消费。`userBindingsFingerprint` 以 `null` 证明不存在 Global User Binding 输入,或以 SHA-256 绑定并行私有快照;声明存在但快照缺失或不一致时,node 形成 unknown boundary。`userBindingsShadowPolicy` 固化该 cell 的 session-local 覆盖粒度,`userBindingNames` 以按名称排序的 `{name, state}` 记录结算时的 provider/local/absent/unknown 事实,因此 cold replay 按历史粒度重放覆盖关系,不从当前实现推断 v1-v7 cell 的整条 entry 语义;provider 事实必须对应并行快照的条目 ID,并覆盖该快照公开的每个名称,否则 node 形成 unknown boundary。`calls` 只保存 global、member、PTC Value Graph 编码的 args/result 或 error,以及 settlement 序号。cold replay 校验调用名称、参数、数量和提交顺序,并按 recorded settlement order 释放 recorded result;不会重新 dispatch program binding 或重做外部 effect。该规则同样适用于 native tools、owner-provided namespace 和 `code.run`,不按名称分支。Cordis 的进程内对象不会因此被宣称已恢复;presentation 可以从已验证 transcript 派生重新检查要求,但不能改变 replay。若基础设施终止时仍有未结算 binding,heap 回滚到 durable frontier,discarded journal 以最先观察到的 `global.member` 保留 possible-effect boundary。effect、completeness 和 source metadata 属于 capability explorer,不伪装成 journal 字段。
122
176
 
123
- journal 通过 `run_code.output.presentationMeta` 附着到最终 result,再由 `tools/result` 做两阶段确认。缺失、损坏或被替换的 journal 形成 unknown/volatile 边界;未进入 runtime 的 call 由后续 `confirms` 以对应 `tool/call.seq` 证明为 no-op。volatile 源码保留在原 session log,但不参与 cold replay。
177
+ journal 通过 `run_code.output.presentationMeta` 附着到最终 result,再由 `tools/result` 做两阶段确认。live binding catalog 在 worker 结算时随实际状态更新,下一条排队 cell 使用这份目录准备;journal 确认只推进持久历史,迟到或逆序的确认不能覆盖较新的 live 目录,也不能恢复已重置的状态。缺失、损坏或被替换的 journal 形成 unknown/volatile 边界;未进入 runtime 的 call 由后续 `confirms` 以对应 `tool/call.seq` 证明为 no-op。volatile 源码保留在原 session log,但不参与 cold replay。
124
178
 
125
179
  恢复从当前请求对应的 head 沿 parent 关系向更早状态收缩,而不是越过损坏记录继续假定原 heap 存在。候选 frontier 同时受两种证据约束:append-only session log 中的 journal 证明状态可重建;生成当前调用的 DSH ordered surface/derived request history 证明模型可以知道其精确 binding provenance。raw event 未删除不等于模型仍可见,Client 的 `dshPtcPlusBindings` inventory 也只是 UI presentation。只裁剪 tool result、仍把携带源码的 assistant call 留在模型 surface 中时不必删除对应状态;assistant provenance 被遮蔽且没有显式、有界、模型可见的结构化状态投影时,live worker 与 cold replay 都必须收缩。插件不从自然语言 compaction summary 推断 binding。
126
180
 
@@ -143,3 +197,5 @@ kernel 重置 worker 并逐级验证更早 frontier;最大非空 frontier 仍
143
197
  - [Plugin Settings UI and Enabled Kill Switch](adr/0019-plugin-settings-and-kill-switch.md)
144
198
  - [Optional Cordis Tools in PTC Mode](adr/0020-optional-cordis-tools-in-ptc-mode.md)
145
199
  - [Separate Host Bootstrap From Session Runtime](adr/0021-separate-host-bootstrap-from-session-runtime.md)
200
+
201
+ - [Use Versioned Logical Binding Identities](adr/0025-use-versioned-logical-binding-identities.md)
@@ -0,0 +1,200 @@
1
+ # Binding 草稿在当前输入框上方展示
2
+
3
+ 状态:完整草稿由已发布的 `conversation.input.dock` 承载;历史命令位置只保留请求和只读来源。面板采用输入区上方的悬浮布局,验收以正式打包后的浏览器实际行为为准。
4
+
5
+ ## 产品目标与分发边界
6
+
7
+ `/binding new` 和 `/binding edit` 产生的完整草稿应直接出现在当前会话的最新操作位置,即普通用户输入框上方。每份新候选首次接受后自动展开,用户无需滚回命令起点、悬停或先打开弹窗,就能阅读源码、模型上下文并保存或丢弃草稿;此后可以主动折叠或关闭面板。
8
+
9
+ 卡片是插件自己的当前草稿审阅区,可以是独立面板;不要求成为某个历史 Turn 内的消息节点,也不要求复用原生回答 renderer。后续回答继续追加时,未处理的当前草稿仍跟随输入区。历史记录用于追溯,当前操作区用于处理草稿,两者的位置不必相同。
10
+
11
+ 会话历史中的 `/binding` 编写请求始终保留原来的初始样式:标题、状态标识、原始命令与需求、适用的失败说明。草稿生成后,该条目只更新状态,不再自动长成带源码和保存操作的完整卡片。迁移到 dock 的是接受候选后的详细内容与操作区,不是编写请求本身。
12
+
13
+ PTC Plus 必须独立安装到未经修改的官方 DSH,不能修改宿主源码或安装包、要求定制宿主,或把自行新增的宿主接口当作已发布能力。[CONTEXT.md](../CONTEXT.md) 与 [ADR 0017](adr/0017-track-the-latest-dsh-public-surface.md) 拥有此边界。插件自有组件、独立 div、CSS、Portal、页面浮层和公共 renderer 替换都是 UI 工具,不因偏离原生消息布局而被排除;选择依据是实际位置、可分发性、生命周期和宿主职责是否得到保留。
14
+
15
+ 本功能的成功条件是:完整草稿默认展开、输入框仍可用、当前候选不会串会话或恢复过期操作权限、官方内容与其他插件继续共存。插件不额外接管审批、取消或绑定持久化,不为移动 UI 改变模型请求、journal 或绑定执行。
16
+
17
+ ## 选定落点:`conversation.input.dock`
18
+
19
+ 官方声明把该 slot 定义为 **“Full-width entries above the composer card”**:`kind: list`、`scope: session`,owner 为 `InputZone { session, input }`。原生 `ConversationRoot` 在普通 composer 栈中先渲染 dock,再渲染输入框。官方 Todo、Goal 和输入队列都通过独立 id 贡献到这里。
20
+
21
+ ```text
22
+ 会话历史
23
+ 绑定编写:/binding new 或 edit 的原始请求(保留初始样式,更新状态)
24
+ 后续正文与工具过程
25
+ 原生回答尾部、文件产物与操作
26
+ ──────────────────────────
27
+ 当前输入区
28
+ PTC Plus 完整 Binding 草稿悬浮面板(不占正文布局高度)
29
+ 名称、用途、导出信息
30
+ 完整源码与模型上下文(默认展开,内部可滚动)
31
+ 保存为停用 / 保存并启用 / 丢弃
32
+ Todo / Goal / 输入队列等 dock 内容
33
+ 用户输入框
34
+ ```
35
+
36
+ 插件以独立 id `ptc-plus-binding-review` 注册,初始 `order: 30`。slot 内的零高度锚点承载脱离文档流的面板;以普通 composer 整体的顶部为几何边界,面板悬浮在其他 dock 与输入框上方。展开、折叠不增加正文的布局高度,也不拉高宿主底部遮罩。它会覆盖其后方的部分历史内容;用户可折叠或关闭以阅读,输入框和其他 dock 仍可用。该注册不独占 list,也不重排其他贡献。
37
+
38
+ 该落点不参与 Chat 节点排序,不占用 `turnTail` 的 chain,也不需要调用原生 renderer 再拆解其结果。宿主继续拥有正文、原生尾部、文件产物、分支和滚动容器;插件拥有面板内部渲染与样式。不得用额外的虚假事件把 UI 布局写进 session log。
39
+
40
+ | 方案 | 适用性与本次选择 |
41
+ | --- | --- |
42
+ | `conversation.input.dock` 中锚定的悬浮面板 | 已发布的 session list 提供会话生命周期和输入区位置;采用插件自己的浮层布局和有界几何测量。 |
43
+ | 页面级 Portal | 本需求不需要脱离普通 composer 的可见性边界;留在 dock 内可随宿主接管自动隐藏。 |
44
+ | 替换公开 renderer,再组合公开组件 | 公共契约支持时可以使用;本需求无需接管原生回答渲染。没有公开的“下一个 renderer”入口时,不假定可以组合任意注册项。 |
45
+ | 独立 Conversation 节点 | 适合需要历史位置的业务内容;当前目标不需要,而且同轮尾部节点可能改变原生分支资格。 |
46
+ | 命令位置或原生操作行 | 前者位置过早,后者是紧凑操作区;不作为当前完整审阅的落点。 |
47
+
48
+ ## 数据来源与当前草稿选择
49
+
50
+ 复用 `internal/user-binding-draft-projection.js` 的 `ptcPlusBindingDraft`,以及 `internal/user-bindings-owner.js` 现有 RPC。当前 view 包含 `phase`、`capability`、`commandId` 和可选 `history`;历史记录保存 `acceptedSeq`、精确 candidate 及 action 的正式来源关系。源码、请求身份、版本和 `modelContext` 都已有 owner。
51
+
52
+ 面板选择当前 projection 标识的编写请求。`commandId` 关联命令;candidate 的 `requestId` 和 `version` 区分草稿;当前 `capability` 仅用于现有 Host RPC。不能通过“history 最后一条尚未保存”或原始日志扫描推测可操作候选,也不能把历史 request 身份当作 locator。
53
+
54
+ 匹配当前请求的已接受 history 可以立即提供只读完整内容;`draft` 与 `draft-review` RPC 则确认当前候选及操作状态,`list` 提供 catalog revision。RPC 返回的请求、命令和版本必须与正在展示的候选一致,才能启用写操作;不一致时刷新现有 owner 的证据,不能在 A 的源码下面放 B 的保存按钮。旧 metadata 没有历史源码时使用现有 RPC 读取路径,不从模型正文提取代码补齐。
55
+
56
+ 草稿一旦被 Host 接受并投影即可显示,即使模型还在输出。`command/done` 只表达命令处理,不证明有草稿;`turn/end` 继续由既有 projection 用于编写失败等状态判断,不是面板出现的前置条件。成功接受后的输出、普通工具调用、无最终正文或后续取消,都不由 Client 自行推断为撤销草稿。
57
+
58
+ 历史请求的状态与当前可操作草稿分别按证据派生。请求条目复用原有外观,但状态文案必须表达已有证据,不能为保留外观继续显示无法证明的“正在编写”或“编写失败”:
59
+
60
+ | 精确关联到该请求的证据 | 可展示的事实 |
61
+ | --- | --- |
62
+ | CommandNode 的命令处理错误 | 命令处理失败与宿主提供的错误;它不代表其他请求的草稿状态。 |
63
+ | CommandNode 的命令处理成功 | 请求已受理;单凭这一结果不能判定草稿已生成。 |
64
+ | 当前 projection 的 `commandId` 匹配,且 `phase` 为 `pending` 或 `failed` | 分别显示正在编写或未生成可保存草稿;该当前状态不能归到其他历史请求。 |
65
+ | 对应的已接受 candidate/history | 草稿已生成及其精确内容;没有当前 locator 时仍只是只读证据。 |
66
+ | 对应的 Host action 回执 | 已保存或已丢弃;跨重建只使用现有 RPC 或带正式来源关系的历史回执,不由 locator 消失推断结果。 |
67
+ | 没有候选或回执,当前 projection 也不再标识该请求 | 保留可证明的命令处理结果;编写结果显示未知,不推断仍在运行、已失败或已被替换。 |
68
+
69
+ 已接受 candidate 和 action 分别拥有生成与处理结果;当前 projection 拥有当前编写状态和 locator。命令准入结果不覆盖这些事实。当前 RPC 确认的结果沿用既有展示规则,不被提升为已经持久化的历史回执。
70
+
71
+ 例如 A 已有草稿,B 命令成功准入后整轮未接受候选,既有 projection 会恢复到 `A.ready`,并不保留 B 的编写终态。此时 A 按原展示选择恢复;B 在缺少独立终态证据时显示“请求已受理,编写结果未知”。重新挂载、分页和重连采用相同规则,不能通过 A 恢复、B 不在 history 中或临时 Client 缓存来证明 B 失败。此需求按现有证据明确表达未知即可,不新增日志事件或投影字段来补造结论。
72
+
73
+ 本次位置调整不需要 `acceptedTurn`、新 Conversation Definition、额外位置 metadata、projection 升版或 journal 迁移。若实施发现现有数据不足以满足上述选择规则,先记录具体反例和最小 owner 修正,再调整计划;不能为布局预先增加恢复协议。
74
+
75
+ ## 展示与操作生命周期
76
+
77
+ | 状态或事件 | 当前输入区的行为 |
78
+ | --- | --- |
79
+ | 没有可展示的当前候选或已确认回执 | dock 不占空间;历史请求及其已有候选仍可只读查看,不从历史挑一份升级为当前草稿。 |
80
+ | 编写中 | 原命令条目保留已有编写状态;dock 不重复展示一份编写请求,也不把上一份草稿冒充本次结果。 |
81
+ | 已接受,正在确认操作资格 | 新候选首次在 dock 展开,操作按钮暂不可用并说明正在载入。目录读取慢不应让已知源码消失;用户主动折叠或关闭后,读取完成不强制展开。 |
82
+ | 当前草稿可用 | 按用户选择保持展开、折叠或关闭;展开时显示完整内容和模型上下文,保留保存为停用、保存并启用、丢弃及既有 revision 冲突处理。 |
83
+ | 保存或丢弃成功 | 确认精确候选的处理结果后自动关闭面板;历史保留精确候选和有证据的 action。保存不等于会话已激活。 |
84
+ | 编写失败或旧草稿恢复 | 原请求只显示上述证据规则支持的状态;缺少证据时显示编写结果未知。没有已接受候选就不产生完整 dock 卡片。Host 恢复旧草稿时沿用该候选的展示选择,不自行改变 fallback 规则。 |
85
+ | 资格撤销、Host 重启或只剩历史证据 | 对仍能证明属于当前显示内容的候选保留只读查看;撤下写操作。没有当前身份时不把历史重新挑成活动草稿。 |
86
+ | 开始下一次编写 | 当前区跟随新的 projection;旧候选留在历史位置,不能跨请求沿用 busy、错误、回执或 locator。 |
87
+ | 切换会话、断线重连、分支或 seed | 按新会话 projection 重建;加载期间禁止沿用旧会话内容和写权限。历史可见性与当前资格分别判断。 |
88
+ | 禁用功能、释放 slot 或卸载插件 | 释放本功能拥有的订阅、计时器和面板;不自动保存、丢弃或执行候选。 |
89
+
90
+ 同一会话只保留一个当前完整审阅 controller,按会话、请求、版本和 locator 隔离异步读取与动作。`conversation.chat.commandview` 的 `binding` key 继续渲染原有编写请求,不能因 dock 已注册、已出现或被关闭而返回空内容。保留 `BindingCommandCard` 的请求外观和状态区,只移走候选详细内容及写操作。所需展示能力可用且该请求精确对应尚未处理的当前候选时,必须提供“打开草稿”入口,用于展开 dock,不重新执行 `/binding`;隐藏编写按钮的设置不影响该入口。历史主动查看仍可展开只读源码,但接受候选不得自动展开历史详情,也不能在历史中恢复保存或丢弃按钮。
91
+
92
+ 现有页头 popover 的候选展示与保存/丢弃入口也应收拢:保留状态与管理入口,不再创建第二套当前草稿写入流程。历史只读内容可以复用展示组件,但不能恢复控制器或写权限。
93
+
94
+ 抽取现有 `BindingCommandCard` 的展示和 RPC 行为时,分别保留请求条目、纯候选内容组件与当前审阅 controller。不要仅把依赖 `node.commandId` 的原组件直接塞入没有 Command node 的 dock,再伪造 node 参数。未处理草稿不因超时或下一条普通消息自动消失;用户主动调整面板只改变本地展示。
95
+
96
+ 写操作仍使用 `save-draft` / `discard-draft`,传递现有 capability、version 及适用的 expected revision。请求切换、组件卸载或资格变动后的迟到响应不能恢复旧按钮;一次失败读取不证明候选已被撤销。待决写入按精确候选隔离:同一候选不重复提交,接受新候选后可独立读取资格和操作,旧响应不能阻塞新候选或清除其 busy 状态。已有必要的资格刷新可以复用,但不能为确定位置或等待回答结束新增轮询、事件订阅或第二套状态机。
97
+
98
+ ## 折叠、展开、关闭与重新打开
99
+
100
+ 除独立关闭按钮外,整条标题栏是一个原生折叠/展开按钮,标题、状态与箭头区域都可以点击;Enter 和 Space 使用原生按钮语义。展开时箭头朝下表示收起,折叠时朝上表示展开,状态与 `aria-expanded` 一致,并遵循减少动画的系统偏好。完整内容默认展开不等于禁止用户收起。
101
+
102
+ | 用户操作 | 展示结果与草稿状态 |
103
+ | --- | --- |
104
+ | 折叠 | dock 保留名称、状态、展开和关闭按钮,收起正文及保存/丢弃操作;不改变候选或编写事务。 |
105
+ | 展开 | 未处理候选在原 dock 位置恢复完整内容;已处理候选仅从历史请求查看。写操作仍以当前 Host 证据为准。 |
106
+ | 关闭 | 隐藏整个 dock 面板,不保存、不丢弃、不取消编写,也不删除历史请求。 |
107
+ | 重新打开 | 输入框星光按钮的草稿菜单或当前历史请求的“打开草稿”展开同一当前候选;不重新发命令、生成候选或创建第二个操作 controller。 |
108
+ | 丢弃草稿 | 仅明确点击“丢弃”才调用既有 Host RPC;它与关闭面板是不同操作。 |
109
+
110
+ 公开 `conversation.input.left` 只注册一个星光图标,统一插件设置快捷访问、全局绑定管理、编写与当前草稿访问。图标在悬浮或聚焦时以插件署名提示说明来源与用途,有未处理候选时改为提示草稿状态。首条消息前即可通过悬停、点击或方向键打开官方 `Menu`;设置条目直接打开复用完整设置表单的应用内窗口,悬浮提示保留宿主原生设置路径;全局绑定展示名称、用途及启用状态,点击条目切换对所有会话生效的启用配置,并可打开既有完整工作台。有未处理候选时显示数量角标,菜单中单独分组,按名称与状态选择候选后展开面板。菜单中的“编写新绑定”沿用既有命令可用性与输入保护;“修改绑定”是同一个 `Menu` 的第二个步骤,列出已有全局条目,选择后以相同保护预填 `/binding edit <id> `。当前 Host 每会话只保留一份当前草稿,因此角标为 `1`,不把历史候选计为待处理草稿。草稿访问不依赖命令服务;隐藏编写快捷入口时保留已有草稿的星光图标,但不显示全局目录、管理与新建操作。插件与全局绑定功能开关仍统一控制整个入口。
111
+
112
+ 菜单使用公共 Portal 和 `getAnchorRect`,以触发按钮自身为锚点定位,按按钮上沿之上的实际可用空间限制列表高度;全局绑定与新建、修改、管理操作共享原生滚动区域,较矮视口下仍可逐项访问。悬停停留 150ms 的意图延迟后才打开菜单,指针扫过输入区不弹出菜单;点击与方向键路径不受延迟影响。菜单由外部点击或 Escape 关闭。悬停打开的菜单在指针离开触发器与列表 200ms 后关闭,重新进入列表或触发器即取消;该宽限覆盖指针短暂离开整个菜单的瞬间,因此越过输入区选择条目仍然可行。点击打开的菜单保持到显式关闭。点击与方向键打开时聚焦首个可用操作,Tab 可到达新建、修改和管理操作;进入“修改绑定”步骤后焦点移到第一个条目。候选变化、会话切换、功能关闭、卸载或普通输入区被接管时关闭菜单;普通刷新不关闭菜单。菜单选择必须向同一 review controller 传递精确候选,不能把旧项点击重定向到新候选。原请求条目中的入口也只能打开其精确对应的当前候选;旧请求只允许查看自己的只读历史。展示能力暂不可用时,不提供实际无法打开面板的操作。
113
+
114
+ 全局目录由现有 `list` Remote 按菜单打开动作读取,不轮询;读取在后台进行,期间菜单沿用上一次已确认的目录并保持条目可操作,只有写入进行中才禁用切换。显式“重新加载”调用 `reload` 重新读取存储文件并清除已修复的读取错误。启停沿用 `enable`/`disable` 与 `expectedRevision`。写入期间禁用重复切换,关闭菜单不取消已发出的操作。冲突或失败后撤下过期目录,用户重新读取后再决定是否重试,不自动重发写入。重连和组件释放使旧响应失效;菜单读取、显示和启停配置不执行绑定源码。菜单明确区分全局启用配置与待处理草稿,角标只统计草稿。
115
+
116
+ 展示选择以 `(sessionId, requestId, candidateVersion)` 归属,只有 `expanded`、`collapsed`、`hidden` 三种本地状态。当前 Client 内切换会话再返回、RPC 刷新、重连、普通消息追加以及审批临时接管,不重置同一候选的选择;真正接受的新候选默认展开,并从该候选的内容顶部开始阅读;同一候选的普通刷新保留滚动位置。刷新页面或重新加载插件后按当前有效候选恢复默认展开,不要求把展示偏好写入持久存储。共享此选择只协调插件视图,不承载 locator 或 Host 事务资格,也不增加 session log、模型消息或管理 RPC。
117
+
118
+ 显隐选择不影响业务操作;精确候选一旦确认保存或丢弃成功,当前面板自动关闭。失败或结果待确认时保留用户的显隐选择:
119
+
120
+ | 结算时的展示选择 | 保存或丢弃已确认成功 | 写入失败或结果待确认 |
121
+ | --- | --- | --- |
122
+ | `expanded` | 自动关闭;回执与精确源码从原请求只读查看。 | 保留完整面板并展示错误或待确认状态;仅在重新证明可写后允许手动重试。 |
123
+ | `collapsed` | 自动关闭;原请求显示处理结果。 | 保持折叠,标题提示有错误或结果待确认,允许用户展开查看。 |
124
+ | `hidden` | 保持关闭,不弹回执;原请求展示有证据的处理结果。 | 保持关闭,保留就近重新打开入口并提示有待查看状态,不自动展开或重试。 |
125
+
126
+ 关闭或折叠待决操作中的面板不取消已发出的保存/丢弃 RPC;操作结算仍由同一 controller 接收。未确认处理结果时保留当前候选的访问入口,但入口不证明可以再次写入;一次网络错误不能触发重新提交。已确认保存或丢弃后移除两个当前草稿打开入口,结果和精确候选继续从原历史请求只读查看。确认结果统一由当前 controller 收敛:保存响应、精确 review RPC 或 projection 回执均关闭匹配候选,普通刷新不能重新打开;旧候选的迟到结果不能关闭新草稿。locator 撤销本身不证明处理成功。
127
+
128
+ 用户关闭时,焦点移到就近的星光按钮,聚焦本身不弹出菜单;没有该入口时回到输入框。成功后自动关闭仅在面板原本持有焦点时恢复焦点,不能打断用户在其他区域的操作。异步成功移除当前聚焦的打开入口时也应保持合理焦点,不能将其留在已移除节点;宿主接管时不从审批界面抢焦点。折叠按钮提供 `aria-expanded`,被隐藏的内容不得继续接受键盘焦点。
129
+
130
+ ## 输入区接管与布局边界
131
+
132
+ 官方普通 composer 是 `conversation.composer` chain 的 fallback。当前实现使用 `overlay: true`:其他 contribution 被选中时,fallback 保持挂载但被 `display:none` 隐藏,因此 input dock 也会隐藏。**注册成功不等于任何时候都可见;隐藏也不等于已卸载。**
133
+
134
+ 审批或其他宿主交互接管输入区时,草稿区和重新打开入口随普通输入框一起暂时让位,不通过 Portal 把保存按钮强行叠到审批上。PTC Plus 的 REPL 视图接管 composer 时也按此规则隐藏;回到普通输入区后恢复同一份有效草稿及其原有展开、折叠或关闭选择。重建时读取 projection 和 RPC,不依靠隐藏 DOM 保留权限。长驻 controller 必须能处理隐藏期间的撤销;用于刷新资格的任务仍受功能和会话生命周期约束,不能只依赖 unmount 清理。
135
+
136
+ 普通对话中的正文继续流式输出、产生工具结果或开始下一轮,不是隐藏卡片的理由。所需边界是“普通输入区是否被宿主接管”,不能把 `input` 的任意 busy 状态当作隐藏条件,也不要求用户等待真实轮次结束。
137
+
138
+ 面板采用不透明主题底色、细边框与阴影,明确表达临时浮层;插件拥有的标题、滚动正文和操作区以分隔线区分。名称只在标题出现,正文保留导出信息、用途、完整源码及模型上下文;丢弃与保存动作分置两侧,窄屏允许换行。面板在 dock 内居中并以 `44rem` 限制阅读宽度,两侧至少留出 `16px`,避免控件跨入会话两侧的原生拖拽区域,不固定到 `document.body` 坐标。
139
+
140
+ 长内容必须保留完整文本并在内部滚动,不能以截断源码换取高度。通常正文区以 `min(32dvh, 20rem)` 为上限,标题和操作区保持可见。标准 DOM 几何、`ResizeObserver` 和 visual viewport 事件共同拥有定位与空间测量:面板底部位于整个普通 composer 上方 `8px`,顶部在 scrollport 内留出 `8px`。多行输入或其他 dock 占用较多空间、正文剩余不足 `80px` 时,改为整张面板单层滚动,使源码、模型上下文与操作均可通过滚动或键盘到达,不把源码区压成零高度。面板本身始终受实际剩余空间限制。折叠时仍需要定位观察;隐藏、处理成功和卸载释放观察。只写入插件元素的样式,不改宿主布局,不持续滚动正文。浏览器验收同时检查实际点击命中、折叠前后的 composer 坐标与正文滚动范围,不能仅凭注册成功或静态截图证明可用。不要把宿主未公开的 CSS 变量或私有类名提升为必需契约。
141
+
142
+ 源码和模型上下文默认展开。历史详情和 dock 共用只读模型上下文区,以“接口声明”状态标签说明是否向模型提供,并单独呈现完整提示词或空状态;不使用禁用的表单控件表示配置。当前卡片不采用 hover 才显现的布局,不自动抢焦点或持续调用 `scrollIntoView`。键盘可进入内容滚动区和所有动作,窄屏操作行允许换行,动态视口下仍能访问输入框与审批。共享 list 的顺序只管理本插件贡献,不重排其他插件。
143
+
144
+ ## 集中兼容与实施顺序
145
+
146
+ 一项公共能力由一个执行环境中的 owner 管理。Client 入口通过既有 `ctx.slots.inject` 等待 `conversation.input.dock`,沿用 `src/client-feature-gates.js` 的 `registerGated`(订阅设置 → 判定资格 → 注册/注销 → 回滚)、`ctx.effect()` 与 disposer 释放注册。root `apply` 注册 session-scoped contribution,由 renderer 的公共会话 props、projection hooks 和现有 RPC 注入提供数据;不另起 session coordinator。
147
+
148
+ 本方案不消费 Conversation event registry,因此无需为了旧 `conversationEvents` 与后续 `uiConversation.events` 增加适配。确有公共 props 形态差异时集中到 `src/client-host-compat.js`,组件使用统一语义;不能以 DSH 版本号分支,也不为没有差异的 dock 包一层泛化框架。
149
+
150
+ slot 的迟到、释放、再次声明和功能开关必须测试。缺少所需展示能力时,历史中仍保留紧凑的编写请求与已有的只读历史,并显示“草稿审阅面板暂不可用”;不恢复历史里的完整操作卡片,不伪装成用户主动关闭,也不自动保存、丢弃或执行草稿。重新打开入口只在实际能打开面板时提供,能力恢复后按同一候选原有展示选择恢复。审批接管属于普通输入区暂时隐藏,不是公共能力缺失,不显示能力错误。
151
+
152
+ 展示能力的就绪与释放由一处 Client 注册 owner 协调,包括 dock、重新打开入口和所需公共 props,不在组件中分别猜测能力或自行声明宿主落点。在目标官方分发中缺少这些能力意味着本方案尚不能通过产品验收;保留请求与提示不可用不等于已交付输入框上方的审阅功能。
153
+
154
+ 实施记录:
155
+
156
+ 1. 已在未经修改的官方 `0.1.3-alpha.2` 安装中注册最小 dock,并以真实浏览器确认其位于输入框上方。
157
+ 2. 已复用 draft projection 与现有 RPC owner,历史命令卡片保留请求和只读候选,当前候选由单一 Client review controller 管理;页头不再提供第二套写操作。
158
+ 3. 已实现折叠、展开、关闭、输入框旁重新打开、迟到响应隔离、跨会话隔离、待决写操作和 composer takeover 生命周期。
159
+ 4. 已以最终 tarball 运行官方 Web smoke,覆盖长内容、窄屏、低视口、隐藏编写按钮和展示操作的 session-log 不变性,并同步更新 ADR、Client UI 与用户文档。
160
+
161
+ ## 验收与交付证据
162
+
163
+ | 验收项 | 必须观察的结果 |
164
+ | --- | --- |
165
+ | 官方安装 | 正式 tarball 安装成功,Host 源码和安装文件不变,实际加载最终插件 bundle。测试 fixture 自行声明 slot 不能替代此项。 |
166
+ | 请求与位置 | `/binding new`、`edit` 发出时保留历史中原有的绑定编写请求样式;接受后只更新请求状态,完整详情和写操作首次在 dock 展开,原条目不消失也不变成完整操作卡片。 |
167
+ | 展示控制 | 点击折叠态的标题文字即可展开,Enter/Space 同样可用,箭头随状态变化;展开/折叠不改变 composer 坐标或正文滚动范围。关闭仅隐藏,输入框旁与当前请求都能重新打开;同一候选的 RPC 更新、重连、普通消息和审批接管不覆盖用户选择,新候选首次展开。 |
168
+ | 内容与操作 | 精确源码和模型上下文默认可读;保存为停用、保存并启用、丢弃、busy、冲突、失败及回执正确。 |
169
+ | 结算与显隐 | 保存或丢弃过程中分别保持展开、折叠和关闭,验证成功、失败及结果待确认组合。已确认成功自动关闭面板;已处理后的两个当前入口移除,回执与源码从原请求只读访问。 |
170
+ | 请求状态证据 | A 已有草稿,B 命令成功准入后未接受候选,projection 回到 A;B 在重新挂载、分页和重连后显示准入成功及编写结果未知,不能冒用 A 的 ready 或推断失败。命令处理错误、匹配 projection 的 failed、接受及 action 各自只归到对应请求。 |
171
+ | 候选与异步 | 新请求、旧请求恢复、跨会话、迟到 RPC、断线、重启、分支和 seed 不串候选,不以历史或旧 locator 恢复写权限。 |
172
+ | 唯一控制器 | 命令处和页头不再同时出现另一套当前保存控件;折叠或关闭期间的写操作不会丢失结算或重复提交。主动展开历史仅只读,分页不重新挂载活动控制器。 |
173
+ | 宿主共存 | 官方文件产物、Todo、Goal、队列和另一插件的 dock 内容继续显示;原生分支资格、目标与草稿 UI 无关。 |
174
+ | 接管与恢复 | 宿主审批及 REPL 接管时不遮挡接管界面,恢复普通输入框后草稿仍可读;隐藏期间撤销不会恢复旧操作权限。 |
175
+ | 浏览器 | 桌面、窄屏、中英文、长源码、键盘和焦点、多 dock 与小视口下内容和输入框可达,无强制滚动或页面溢出。 |
176
+ | 日志与请求 | 展示、展开、隐藏和历史查看不新增 event、模型提示词或声明,不影响前缀稳定性、journal 或模块初始化;真实保存沿用已有 notice/catalog 契约。 |
177
+ | 能力生命周期 | 验证既有与当前契约、迟到声明、释放、重挂载和开关。能力缺失时保留紧凑请求与明确不可用提示,没有历史写操作或无效的打开入口;恢复后沿用候选和显隐选择。审批接管不误报能力缺失,不以版本号或新造 slot 代替能力证明。 |
178
+
179
+ 按项目 ledger 流程记录实施发现,最终在稳定树上运行 `npm run check` 和 `git diff --check HEAD --`。独立 reviewer 无缺陷、确定性测试通过、实际 UI 验收是不同证据;不能把其中任一项替代其余。提交与发布仍遵循用户授权及独立审查条件。
180
+
181
+ ## 公共契约与历史证据
182
+
183
+ 已核对官方源码中的 slot 声明、原生根布局和贡献实例,以及已安装官方包的类型声明与实际 Client bundle 中的 dock 渲染。它们证明接口存在及设计落点可用,尚不证明 PTC Plus 面板已实现或完成浏览器验收。
184
+
185
+ 以下标签仅标识只读历史源码样本,不定义运行分支、测试白名单或当前兼容目标:
186
+
187
+ | 历史样本 | 与本方案相关的事实 |
188
+ | --- | --- |
189
+ | `dsh-v0.1.1-rc.2` | ui-conversation 声明 session/list 的 `conversation.input.dock`,根布局在输入框之前渲染它。 |
190
+ | `dsh-v0.1.2-rc.1` | 相同的公共 dock 与相对输入框位置;不依赖 Chat 拆包后的 registry。 |
191
+ | `dsh-v0.1.3-alpha.2` | 相同的公共 dock 与位置;已安装官方分发也包含该 slot。 |
192
+
193
+ 公开规则与受检源码入口:
194
+
195
+ - [Slots 扩展规则](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.3-alpha.2/docs/subsystems/slots.zh.md):基数、scope、selector 与生命周期。
196
+ - [输入区插槽声明](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.3-alpha.2/packages/client/ui-conversation/src/client/contract/slots.ts):`conversation.input.dock` 和 `InputZone`。
197
+ - [原生会话根布局](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.3-alpha.2/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx):dock、普通输入框与 composer chain 的组合。
198
+ - [Slot 渲染契约](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.3-alpha.2/packages/client/ui-slots/src/index.ts):`overlay` 隐藏而不卸载 fallback。
199
+ - [Todo](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.3-alpha.2/packages/client/ui-conversation/src/client/skeleton/TodoPanel.tsx)、[Goal](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.3-alpha.2/packages/client/ui-goal/src/client/index.ts)、[输入队列](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.3-alpha.2/packages/client/ui-conversation/src/client/queue/QueueDock.tsx):官方独立 list contribution 的实际用法。
200
+ - [早期根布局](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.1-rc.2/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx)与[后续根布局](https://github.com/deepseek-ai/deepseek-harness/blob/dsh-v0.1.2-rc.1/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.tsx):既有公开 dock 的位置证据。
@@ -43,6 +43,6 @@ explorer 不调用 capability、不提升 authority、不读取隐藏服务、
43
43
 
44
44
  ## Non-tool APIs
45
45
 
46
- CodeRuntime request 已携带的 owner-provided program namespace 会原样进入 cell,并与 native tools 共享 lease;插件不翻译其领域契约。与插件保留的 `capabilities`、`code` 或 `repl` 同名时 request 明确失败,避免两套 binding 静默分叉;普通 cell 局部变量可以 shadow 这些低频 namespace,需要时从 `globalThis` 访问。`tools` 仍保持保留,因为 shadow 它会移除主要 typed 能力面。`code.run` 只隔离执行已经作为数据持有的 source;当前 cell 能直接完成的 Node、fetch 或 native tool 工作不需要嵌套。当前公共扩展面没有发现额外 DSH/插件服务的 registry,PTC Plus 不猜测隐藏服务,也不保留未来脚手架。显式注册、生成 manifest、装饰器或扫描只是可能的发现机制,不能替代类型、authority、lease 和 settlement 契约。
46
+ 执行缝 request 已携带的 owner-provided program namespace 会原样进入 cell,并与 native tools 共享 lease;插件不翻译其领域契约。与插件保留的 `capabilities`、`code` 或 `repl` 同名时 request 明确失败,避免两套 binding 静默分叉;普通 cell 局部变量可以 shadow 这些低频 namespace,需要时从 `globalThis` 访问。`tools` 仍保持保留,因为 shadow 它会移除主要 typed 能力面。`code.run` 只隔离执行已经作为数据持有的 source;当前 cell 能直接完成的 Node、fetch 或 native tool 工作不需要嵌套。当前公共扩展面没有发现额外 DSH/插件服务的 registry,PTC Plus 不猜测隐藏服务,也不保留未来脚手架。显式注册、生成 manifest、装饰器或扫描只是可能的发现机制,不能替代类型、authority、lease 和 settlement 契约。
47
47
 
48
48
  explorer 本身只做 deterministic inspection,不调用模型。任何 Agent 生成的语义摘要都必须由用户主动触发,或由用户预先授权且有硬预算、用量记录和取消能力的 policy 触发;它不属于当前运行时。