dsh-ptc-plus 0.4.8 → 0.4.10
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 +11 -3
- package/README.md +11 -3
- package/client.js +1151 -529
- package/cordis.patch.yml +12 -2
- package/docs/README.md +1 -0
- package/docs/adr/0005-temporary-rejected-cell-edit-transport.md +19 -0
- package/docs/adr/0019-plugin-settings-and-kill-switch.md +13 -2
- package/docs/adr/0020-optional-cordis-tools-in-ptc-mode.md +1 -1
- package/docs/adr/0023-global-user-bindings.md +1 -1
- package/docs/adr/0028-attach-to-the-host-ptc-execution-seam.md +82 -18
- package/docs/adr/0030-serve-both-typert-codec-generations-from-one-codec.md +3 -3
- package/docs/adr/0032-own-session-log-facts-in-a-host-only-projection.md +27 -0
- package/docs/adr/0033-gate-client-visual-usability-in-a-browser.md +23 -0
- package/docs/architecture.md +3 -3
- package/docs/binding-review-placement-design.md +29 -21
- package/docs/client-ui.md +20 -8
- package/docs/client-visual-contract.md +48 -0
- package/docs/durability-design.md +12 -0
- package/docs/installation.md +27 -6
- package/docs/runtime-reference.md +1 -1
- package/docs/user-bindings.en.md +2 -2
- package/docs/user-bindings.md +3 -3
- package/docs/verification-optimization-work.md +26 -0
- package/docs/verification.md +2 -0
- package/index.js +28 -7
- package/internal/compiler-platform.js +5 -3
- package/internal/compiler-service.js +2 -9
- package/internal/cordis-tools-owner.js +22 -19
- package/internal/direct-surface-owner.js +2 -0
- package/internal/edit-transport-owner.js +8 -5
- package/internal/execution-provider-owner.js +157 -0
- package/internal/execution-seam-compat.js +69 -113
- package/internal/isolated-worker.js +12 -8
- package/internal/recovery-tips.js +50 -21
- package/internal/runtime-bridge-owner.js +88 -57
- package/internal/runtime-contexts.js +13 -13
- package/internal/session-events.js +40 -4
- package/internal/session-journal-recovery.js +678 -181
- package/internal/session-log-view.js +189 -43
- package/internal/session-runtime.js +58 -10
- package/internal/settings-compat.js +12 -2
- package/internal/user-bindings-owner.js +6 -5
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +13 -14
- package/src/client-authoring-view.js +222 -141
- package/src/client-binding-review.js +2 -0
- package/src/client-code-editor.js +6 -0
- package/src/client-copy.js +10 -0
- package/src/client-feature-gates.js +12 -5
- package/src/client-host-compat.js +23 -2
- package/src/client-primitives.js +249 -0
- package/src/client-repl-view.js +3 -3
- package/src/client-settings-view.js +2 -29
- package/src/client-styles.js +92 -33
- package/src/client-tool-view.js +8 -3
- package/src/client-workbench.js +3 -3
- package/src/client.js +72 -46
- package/assets/ptc-plus-bindings-en.png +0 -0
- package/assets/ptc-plus-bindings-zh.png +0 -0
- package/assets/ptc-plus-repair-en.png +0 -0
- package/assets/ptc-plus-repair-zh.png +0 -0
package/docs/client-ui.md
CHANGED
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
# Client UI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
标准 `verify`、`check` 与 CI 的 `verify:ci` 均执行 `test:client:visual`,在一次 Client 测试生成的实际 renderer 夹具上检查关键控件的尺寸、可读性、悬停、键盘焦点、禁用反馈及布局。浏览器准备、覆盖清单、故障反例与官方宿主验收边界见 [Client visual contract](client-visual-contract.md)。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
PTC Plus 提供**插件设置卡片**。卡片座位由宿主代际决定:更早、未冻结的代际在 DSH Web/Desktop 的 Settings → Plugin configuration 中以 `settings.plugin.item` 渲染,当前代际在侧栏 Plugins → Installed 页面以 `plugins.row.config`(键 `<包名>#<行 id>`)渲染该 bundle 自己的配置;General 设置不是本卡片的座位,`src/client-host-compat.js` 只发布到这两个插件配置座位,由声明了槽位的那一代决定哪个生效,卡片按座位提供的 `summary`/`page` 视图分别渲染一句描述与完整表单。输入框旁的星光菜单还直接打开复用同一表单的应用内设置窗口,不依赖宿主页面的局部导航状态;菜单项悬浮提示保留原生设置座位的路径。
|
|
6
|
+
|
|
7
|
+
Client 根入口只依赖 `slots`、`locale`、`connection` 和 `remote`;settings transport 由当前代的 `configForms` 或更早未冻结兼容支的 `settingsScope` 可选注入提供,两者都缺席时不再等待某个名字出现:插件以 `internal/config-spec.js` 的默认值参与订阅,transport 出现时自动接管,因此改名或裁剪设置传输只会降级设置面,不会让根入口在注册任何贡献之前挂起。功能资格只被显式关闭:可读快照按字段判定,不可读快照按同一份默认值判定,`enabled: false` 才关闭。头部贡献直接消费公开 session slot 提供的 `useProjection`;REPL 注册另依赖 `sessions` 的当前选择和 projection face。命令卡片等待公开 command slot,composer 管理入口直接消费现有管理 Remote;其中的编写动作再等待 `remote.commands` 与公开输入 hooks,不依赖已改名的 conversation registry 或未使用的 `ui-session` 模块。缺失、卸载或迟到的 slot/provider 只影响需要它的贡献;没有 `useProjection` 时不挂载依赖它的会话视图,命令卡片保留宿主结果但不提供草稿操作。没有输入 hooks 时不显示编写动作,已有全局绑定仍可查看和启停。preset 优先读取 `agentPreset` projection,缺失时依次读取会话公开摘要里的 projection 值与旧宿主的 `agentPreset` 字段;binding 值和草稿资格不采用该回退。当前会话身份取宿主已发布的选中证据:更早未冻结的选择形状在会话列表上投影 `current`,当前代际把视图选择留在 controller 之外、以主视图持有的会话表达。两者都不读取私有 store。设置和独立正文 tool view 继续可用,不读取私有 store 或自行重建会话状态。
|
|
6
8
|
|
|
7
9
|
组件通过 renderer 提供的 `useProjection`、旧宿主的公开 `useSessions` 和注入 `hooks` 读取外部状态,设置写入与 RPC 由 apply 层注入 callback。业务组件不自行构造 external-store hook。设置、slot、provider 与插件释放共同拥有注册和订阅的生命周期;开关关闭时撤销相关贡献。
|
|
8
10
|
|
|
11
|
+
设置 transport 各自拥有 injection registration 和订阅,即使两者返回同一个 preference face 也不共享释放身份。`configForms` 优先,仍存活的 `settingsScope` 保持备用;优先项移除后读写回到备用项,不以默认开启覆盖其显式关闭值。移除备用项不得撤销当前项,插件释放回收所有订阅。
|
|
12
|
+
|
|
9
13
|
REPL 对 composer 的接管优先使用当前公开 `sessionId`/`pendingInteraction` 参数;旧宿主仅在 `session.sessionId` 匹配且 `interactions` 为空数组时允许接管。审批、提问和无法确认的交互状态继续显示宿主 composer,不通过 DOM 隐藏输入框。
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
冻结 Host 图只证明当前成员;更早回退的 fixture 证据和误删后果见[安装:兼容证据](installation.md#compatibility-evidence)。这些接口形状差异由 `src/client-host-compat.js` 集中处理:组件使用 `useSessionPreset`,注册层使用 `watchCurrentSessionPreset` 跟随当前会话及其 projection,并用 `isIdleSessionComposer` 判断 composer 资格。适配模块负责证据优先级与订阅切换、释放;`src/client.js` 负责设置开关、PTC 功能资格和 slot 生命周期。当前会话变化时重新读取公共能力,不缓存全局宿主版本或会话能力。
|
|
16
|
+
|
|
17
|
+
Client 按数据、传输、注册与视图分文件,沿用既有 `createX(React, deps)` 工厂:`src/client-copy.js` 拥有双语字典,`src/client-styles.js` 拥有样式数据、样式表的 DSH 归属(创建时即写 `data-plugin`/`data-plugin-css`,因此不会被后物化的插件认领,也不会随别的插件被删除)以及对依赖方挂载的全局样式表(CodeMirror 的 style-mod)的收编,`src/client-primitives.js` 拥有“宿主 primitive → 可用组件”的唯一解析与缺失兜底,`src/client-rpc.js` 与 `src/client-transport.js` 拥有 Remote 调用和观察传输,`src/client-feature-gates.js` 拥有“设置快照 → 功能资格”的唯一映射与受门控注册,`src/client-catalog.js` 拥有全局目录读取,`src/client-workbench.js` 拥有工作台状态迁移与视图,`src/client-settings-view.js`、`src/client-tool-view.js`、`src/client-repl-view.js`、`src/client-authoring-view.js`、`src/client-indicator-view.js` 各自拥有一个 slot 的视图。`src/client.js` 只做装配与注册,不持有业务状态。设置快照到功能布尔只有一个纯函数(`featureEnabled`),受门控贡献共用一个“订阅 → 判定 → 注册/注销 → 回滚”实现(`registerGated`);preset、projection 和公共能力仍由各自 owner 判定,在调用点与设置资格组合。
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
## 缺失组件回退
|
|
20
|
+
|
|
21
|
+
回退菜单和弹窗的输入法 guard 覆盖 compositionstart 到 compositionend 后的 closing key;该 key 被消费或 keyup/window blur 释放后,独立普通 Escape 才能关闭。每次按下 Escape 只关闭一层,repeat 事件仍被消费但不再次关闭外层弹窗。该边界与原生 primitive 的生命周期一致,保留尚未保存的草稿。
|
|
22
|
+
|
|
23
|
+
缺失 primitive 包或 `Menu.children` 时,插件自有菜单保留入口的正常布局,列表通过 React DOM 基线 portal 到 `document.body`,只用公开 `getAnchorRect` 与 viewport 为自己的列表定位和限制高度。自有 Modal 的普通与 `headless` 模式共用 portal、mask 和焦点层;`headless` 只移除默认标题与正文装饰,不取消模态遮罩。`npm run test:client:fallback` 在隔离 Chromium fixture 中验证小视口菜单操作、背景 pointer 阻挡与关闭后的焦点返回;它不替代 packed Host 的完整浏览器验证。
|
|
14
24
|
|
|
15
25
|
## 设置命名空间
|
|
16
26
|
|
|
17
|
-
Host half
|
|
27
|
+
当前 Host half 的 `Config` 文档由 DSH 公共 `settings` 服务按 owning Loader entry 的 profile ID 寻址;更早 section installer 兼容支仍注册 `ptc-plus` 命名空间。失败补偿由 settings compatibility owner 绑定同一写入身份,不把固定 namespace 当作 profile entry ID。字段清单、默认值和校验来自 `internal/config-spec.js`,
|
|
18
28
|
由 `index.js` 的 `Config` schema 与设置注册共用;client half 构建时把同一份字段清单打进 bundle,不在 UI 中复制默认值。`CONFIG_GROUPS` 独立拥有按用途排列的展示顺序:插件总开关单独置顶,其后为“调用容错”“REPL 语法”“状态与恢复”“工具扩展”“界面显示”“资源限制”。每个字段只展示一次,各组使用独立标题、留白与分隔线。
|
|
19
29
|
|
|
20
30
|
## 可用设置
|
|
@@ -47,7 +57,7 @@ Host half 通过 DSH 公共 `settings` 服务注册命名空间 `ptc-plus`。字
|
|
|
47
57
|
|
|
48
58
|
## 全局用户 Binding 工作台
|
|
49
59
|
|
|
50
|
-
`/binding new` 和 `/binding edit` 的历史命令处保留原始需求、状态和错误说明。候选被接受后,完整源码、模型上下文与保存/启用/丢弃操作由官方 `conversation.input.dock`
|
|
60
|
+
`/binding new` 和 `/binding edit` 的历史命令处保留原始需求、状态和错误说明。候选被接受后,完整源码、模型上下文与保存/启用/丢弃操作由官方 `conversation.input.dock` 在当前输入框上方承载;历史条目只提供该请求自己的只读来源。公开 dock 内的零高度自有锚点定位 Portal 内的 fixed 悬浮预览,避免宿主裁切与层叠覆盖;只在预览可见时跟踪自有锚点和 visualViewport 的几何变化,可用高度不足时收为标题栏,仍可放大审阅,不测量或改写宿主祖先与滚动容器;展开和折叠不改变对话或输入框高度。该贡献排在普通 dock 内容之前,预览向上展开。放大通过公共 Modal 或既有回退弹窗承载同一个候选内容与操作区;正文独立滚动,标题与底栏保持可达,Escape、遮罩或独立缩小按钮返回预览,关闭按钮则隐藏面板;尺寸切换和关闭按钮之间留有间距。弹窗只在当前输入入口可见时显示,宿主接管时隐藏并保留展示选择。整条标题按钮支持点击与 Enter/Space,箭头随折叠状态变化;菜单条目与焦点恢复只操作插件自有内容节点,定位由公开 Menu 的 anchor/getAnchorRect/portal 契约承担;没有 children 的历史 primitive 使用自有菜单兜底。设置窗口的初始焦点使用 `data-modal-autofocus`,焦点回环交给 Modal;没有 composer 焦点接口时返回自有入口,不寻找宿主编辑器。输入框只保留一个星光入口:首轮前即可通过官方 Menu 悬停、点击或键盘查看全局绑定、切换启停及打开完整工作台;设置条目直接打开复用设置卡片表单的应用内窗口,关闭后将焦点还给仍可用的星光按钮;编写命令可用时显示“编写新绑定”,并在同一个 Menu 内提供“修改绑定”第二步来选择已有条目。该入口与头部标识、REPL 页签同属 PTC surface:只在当前会话使用 `ptc` 或兼容 `code` preset 时注册,其他 preset 既不显示入口也不读取该会话的命令目录。该入口以插件署名提示说明来源与用途,有草稿时改为提示待处理草稿。有草稿时显示数量角标,草稿在独立分组中选择。当前 Host 每会话只保留一份候选,菜单不列出过期历史;隐藏编写快捷入口或命令服务缺席不影响已有草稿的访问。关闭和重新打开只改变展示,不撤销候选或待决 RPC。保存或丢弃确认成功后面板自动关闭;失败和结果待确认时保持用户的显隐选择。候选身份、写资格和异步结算由一个 Client review controller 复用 draft projection 与现有 RPC owner,页头不再提供第二套当前写操作。实现细节与验收证据见[Binding 审阅位置设计](binding-review-placement-design.md)。
|
|
51
61
|
|
|
52
62
|
`userBindingsEnabled` 关闭时不渲染任何 Global User Binding 管理界面,Host 也不注册对应 RPC 或 Agent 命令。开启后,REPL 页签中的“全局绑定”和设置管理按钮打开的大尺寸应用内弹窗复用同一个 `UserBindingsWorkbench`。设置卡片保留开关与管理按钮,不嵌入编辑器。普通管理不依赖当前存在 PTC 会话;Agent 辅助编写仍使用当前可用会话的 `/binding` 入口。
|
|
53
63
|
|
|
@@ -81,7 +91,9 @@ PTC session 的头部弹窗在功能启用时增加 Session 与 Global 页签。
|
|
|
81
91
|
|
|
82
92
|
`enhancedToolView` 默认开启并即时生效。开启时 PTC Plus 通过公共 keyed tool-view surface 为 `run_code` 与 `edit_run_code` 提供增强行,并在可用时使用 DSH 公共 `DisclosureRow`/`CodeBlock` primitive,缺少某项 capability 时使用插件自有的等价降级;关闭时立即注销这两个 keyed view,由 DSH 原生 generic row 负责布局、状态、代码高亮和输入/输出卡片。该开关只影响 Client 展示,不改变工具、prompt、runtime 或 session 语义。composer 星光入口使用公共 `Menu`、`Tooltip`、`Toast`、`Modal` 和 `IconSparkle16`;设置窗口复用设置卡片的完整表单与写入 callback,星光菜单的“修改绑定”第二步继续使用同一公共 `Menu` 的条目、滚动与键盘语义。缺失 `IconSparkle16` 时降级为纯文本按钮,缺失 `Toast` 时使用插件自有的内联状态提示;缺失 `Tooltip` 时悬浮说明由原生 `title` 承载。
|
|
83
93
|
|
|
84
|
-
|
|
94
|
+
星光菜单的自有内容根拥有 13px/18px 基础字号与行高,停用组标题和绑定名称使用 13px,说明使用 12px、启停状态使用 11px;通过 portal 挂载后也不继承宿主的字号与行高。长名称和说明保留单行省略及完整 `title`。星光菜单通过公开 `Menu.children` 将目录滚动区与不收缩的底部操作区分开;只有目录滚动,四个操作和修改步骤的“返回”保持可见。启用条目优先显示,启用与停用标题带数量,停用组每次打开默认折叠;折叠行不渲染。启停后焦点跟随同一条目,条目进入折叠停用组时返回该组按钮,菜单关闭或外部已有焦点时不抢焦点。菜单实际获取和离开焦点的事件拥有恢复资格,待决请求期间关闭再重开也遵循当前资格;初次打开、步骤切换和归组恢复共用自有目录内的焦点显示操作,只调整该目录的 `scrollTop`,不调用祖先 `scrollIntoView`。短视口隐藏底栏的编写文字标题,保留分组的可访问名称和按钮。星光入口的四个动作(编写新绑定、修改绑定、管理全局绑定、PTC Plus 设置)由插件自己的动作区承载:`Agent 编写` 分组标题、两列网格及工具入口。公开 `Menu` 能挂载 `children` 时,该动作区放入其 `children`;缺少 Menu primitive 或已确认不挂载 `children` 时,同一份动作区交给 `src/client-primitives.js` 的自有 `MenuFallback`。列表通过 React DOM portal 呈现,以公开 `getAnchorRect` 和视口预算定位,保留分组、文案、顺序、设置座位提示与可用操作。
|
|
95
|
+
|
|
96
|
+
`src/client-host-compat.js` 以实际挂载输出判定 `children` 能力:首个 composer 入口在隐藏、非 portal 的 Menu 中放入插件自己的哨兵子节点,读取后丢弃探测。答案只记录一次,后续会话入口复用;未挂载或探测失败时不记录能力结论。该探测只读取插件创建的节点,fallback 的定位、滚动与焦点也由自有节点承担,具体边界见前述 primitive 降级契约。
|
|
85
97
|
|
|
86
98
|
悬浮窗里的条目启停不改变列表的可用性:写入由 catalog source 串行化、重复请求被丢弃,因此请求期间行不会被禁用(宿主会给禁用行降透明度)也不会插入“正在保存”行,避免整个悬浮窗在每次切换时闪一下;只有尚无目录可操作或读取失败时行才不可用。
|
|
87
99
|
|
|
@@ -95,7 +107,7 @@ PTC session 的头部弹窗在功能启用时增加 Session 与 Global 页签。
|
|
|
95
107
|
|
|
96
108
|
投影通过 DSH 正式的 `tool/call.data.callId` / `tool/result.data.message.source.callId` 身份配对 `run_code` 与 `edit_run_code`,不依赖可选 `sourceEventSeqs`。它只接受当前 runtime generation 的 envelope,并在 `session/end-seed` 清除旧 lifecycle 的 live 证明;缺少、损坏、其他 generation 的 metadata、无关 tool result 与不影响 binding provenance 的 result-only replacement 都不能覆盖仍有效的最后已证明清单。若 surface replacement 遮蔽了声明 provenance,runtime 与 projection 共用的 model-visible frontier 判定会让相关 inventory 失效。缺少有效 metadata、projection service 或兼容 registration contract 时只显示不可确认,不主动读取历史、不迁移日志,也不影响继续会话。来源跳转要求 Host 提供打开 tool call 或 source location 的公共 capability;缺少该 capability 时,卡片只提供内联检查,不访问私有 store 或宿主 DOM。
|
|
97
109
|
|
|
98
|
-
`enhancedToolView` 开启且插件启用时,Client 通过公共 keyed `tool.call.toolview` 注册 `run_code` 与 `edit_run_code`;任一开关关闭时实时 dispose 两个注册,让 owner 恢复 DSH 原生 fallback。这个正文 slot 只依赖 Host 提供的 key、`toolName`、`sessionId`、`useSessions`、运行中/已结算 `block` 与 `inspect` 公共契约。增强行保留 Code / Code edit 标题、可展开的原始源码(`arguments` 与 `argsRaw` 任一公共形态均可读)、结果、可见且可访问的运行/失败/中断状态和 Inspect 入口;在提供时优先使用公共 `DisclosureRow` 与 `CodeBlock`,缺少 `DisclosureRow` 时回退到插件自有行,缺少 `CodeBlock` 时回退为纯文本源码。`DisclosureRow`
|
|
110
|
+
`enhancedToolView` 开启且插件启用时,Client 通过公共 keyed `tool.call.toolview` 注册 `run_code` 与 `edit_run_code`;任一开关关闭时实时 dispose 两个注册,让 owner 恢复 DSH 原生 fallback。这个正文 slot 只依赖 Host 提供的 key、`toolName`、`sessionId`、`useSessions`、运行中/已结算 `block` 与 `inspect` 公共契约。增强行保留 Code / Code edit 标题、可展开的原始源码(`arguments` 与 `argsRaw` 任一公共形态均可读)、结果、可见且可访问的运行/失败/中断状态和 Inspect 入口;在提供时优先使用公共 `DisclosureRow` 与 `CodeBlock`,缺少 `DisclosureRow` 时回退到插件自有行,缺少 `CodeBlock` 时回退为纯文本源码。`DisclosureRow` 路径把运行/失败/中断状态、摘要和已证明的功能标记放进始终可见的预览区,摘要可换行,功能标记独立排列在其下方;完成态由标题与摘要表达,运行/失败/中断状态由文字 chip 承担并保持可访问。插件通过公共 class 槽位让标题行按内容高度伸展,标题和图标与预览首行顶端对齐,摘要与功能标记之间保留 4px 间距;Host 继续拥有展开交互。源码、结果和 Inspect 只出现在展开主体。结果内容与原生 ioCard 采用相同的灰色圆角背景(`--dsw-alias-markdown-code-block` 加 12px 圆角与边框),失败态使用错误色文字;代码块的语言/复制栏保持原生 CodeBlock 的常亮可见;`检查调用` 入口采用原生 inspectButton 同款胶囊样式,默认 opacity 0,仅在卡片 `:hover` 或 `:focus-visible` 时淡入(opacity .1s),不触发任何布局位移。窄屏下回退路径的摘要允许换行。
|
|
99
111
|
|
|
100
112
|
功能标记不是计数,也不把“插件已启用”冒充成一次功能收益。Client 只在完整 v1-v10 journal 和对应附属 metadata 能证明时显示:自动改写 import(附模块名)、自动剥离 export、自动拆分混合重声明(附已有 binding)、带完整 target/derived-run/non-noop/可选恢复边界关系且与调用目标前置条件一致的安全编辑执行、成功的 `code.run`、由 `PTC-R002` 的 `warning/recover/rolled-back` 语义元组证明本次确实发生的持久重放,以及 `repl.state` 操作。Client 对 v4 同时封闭校验 `bindingPolicy`、`rewritePolicy` 与 `moduleSemantics`,对 v5 还要求 `userBindingsFingerprint`,对 v6 进一步要求 `userBindingsReusePolicy` 为 `fingerprint-v1` 或 `implementation-v1`,对 v7 还要求 `moduleSemantics` 携带可识别的 `importExpressionBoundary`(v1-v6 的 `moduleSemantics` 保持只含 `defaultExportBinding` 的封闭字段集),对 v8 还要求 `userBindingsShadowPolicy` 与 `userBindingNames` 通过封闭校验,对 v9 进一步要求已知的 `languageSemantics`,对 v10 还要求 `moduleTransform` 与语言契约匹配;任一缺失或畸形都不产生功能标记。进程保留或 discarded 状态不作为正文功能标记。普通变量或 function/class 重声明、顶层 native 调用是否来自 canonicalizer、`cordis_*` 成员是否由官方可选 Cordis mount 提供,以及是否实际选择了 prompt 恢复提示没有独立的 Client-only 事实,因此不根据可复制的代码形状、工具名前缀或设置默认值推测;恢复边界本身不展示。
|
|
101
113
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Client visual contract
|
|
2
|
+
|
|
3
|
+
The Client must expose readable, distinguishable and reachable computation controls. DOM classes and functioning RPC handlers do not establish that obligation. `scripts/client-visual-contract.mjs` owns a bounded browser oracle used by deterministic fixtures and packed official-Host acceptance. This is a usability contract, not a pixel snapshot of DSH.
|
|
4
|
+
|
|
5
|
+
## Gate and prerequisites
|
|
6
|
+
|
|
7
|
+
Install the lockfile dependencies and the matching Playwright browser before verification:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npx playwright install --with-deps chromium
|
|
11
|
+
npm run test:client:visual
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`test:client:visual` runs the Client suite once, exporting actual renderer DOM and current plugin, public primitive and CodeMirror CSS to a newly created ignored directory. The layout runner consumes that invocation's fixtures; missing fixtures, unavailable browsers and failing children fail the command. Its temporary HTML is removed afterwards. The standalone layout entry also removes its own directory after fixture failure, browser-launch failure or completion; an explicitly supplied fixtures directory remains owned by its caller. Screenshots and measurements remain under ignored `artifacts/binding-layout` and `artifacts/button-styles` as diagnostics; screenshots alone are not acceptance assertions. `verify`, `check` through `verify`, and every `verify:ci` matrix entry include this command. CI installs Chromium explicitly and does not download browsers inside the gate. An installed compatible Chromium channel can be selected for focused diagnostics with `--browser-channel msedge`.
|
|
15
|
+
|
|
16
|
+
## Coverage
|
|
17
|
+
|
|
18
|
+
All fixture families exercise light and dark reference palettes, English and Chinese, and widths 320, 390 and 1440 px. Reference tokens deliberately exercise both foreground polarities; they do not claim to reproduce official or customized themes. The separate model-free packed acceptance uses DSH's public theme settings on an unmodified official Host, reuses the oracle for dock actions and the global workbench, and retains its existing actual editor, permission, session-log and layout assertions.
|
|
19
|
+
|
|
20
|
+
| Surface | Actual controls | Visual states and evidence |
|
|
21
|
+
| --- | --- | --- |
|
|
22
|
+
| Settings and settings dialog | Disclosure, action, numeric input, select, checkbox switch | Normal, keyboard focus, disabled feedback; hover for commands/disclosure; dialog containment |
|
|
23
|
+
| Global workbench and dialog | Selection, enable switch, icon commands, action buttons, input, instructions, search | Normal, focus, hover where the control or its owner supplies it, disabled feedback, long-label geometry |
|
|
24
|
+
| Draft dock and enlarged review | All three actions, disclosure, separate resize/close icon controls, author attention badge | Native and absent-Button fallback matrix; normal, hover, focus, disabled, actual busy rendering; Enter saves exactly once; combined 320×240/320/400 short-width cases with long source and RPC errors, expanded reading thresholds and near-top anchors |
|
|
25
|
+
| REPL | Observation selection, search, tabs, definition disclosure, four binding-name kinds | Normal and keyboard focus, definition hover, light/dark name readability, long inventory and source geometry |
|
|
26
|
+
| Sparkle menu | Binding rows, disabled-group disclosure, authoring/revision/management/settings and fixed Back | 48 mixed entries; enabled-first counts and default collapse; native/fallback, English/Chinese, light/dark at 390×600, 320×420 and 320×240; independently scrolling catalog, fixed footer, actual action hits and keyboard access; single disabled entry with long purpose, 14px/21px and 24px/36px carrier typography |
|
|
27
|
+
| Command card | Action and native source disclosure | Readable/reachable actions, focus, disabled feedback; saved card remains compact |
|
|
28
|
+
| Tool row | Official DisclosureRow and fallback summary, inspection action, running/error/stopped status and description | Typography hierarchy, long descriptions, absent/multiple feature labels and long details; text containment, nonoverlap, preview spacing and separation from the following message; Enter expansion and inspection, focused inspection becomes visible |
|
|
29
|
+
|
|
30
|
+
Tool previews may contain multiple lines. The plugin's public DisclosureRow class slots size the header to its content and align the title with the first preview line; the Host retains the component and interaction behavior. The browser oracle measures text ranges against the card, header and clipping ancestors within the card, rejects intersecting text and requires a readable gap before feature labels. Horizontal ellipsis remains valid for descriptions and feature details; it does not allow vertical text clipping or lost titles, states or feature names. Injected fixed-height clipping and removed preview spacing must fail on the real renderer. Packed acceptance with `--binding-workflow` produces recorded import/export features through the official execution pipeline and checks the actual collapsed and expanded tool row at narrow and wide widths. The default packed smoke's synthetic typography probe establishes only that the shipped CSS is installed.
|
|
31
|
+
|
|
32
|
+
The oracle requires actionable button padding of at least 10 px and height of at least 28 px, other controls of at least 16 px height, viewport containment and center hit reachability after scrolling. Enabled text (including nonempty input/textarea values and selected options) and relevant icon foregrounds must have at least 3:1 contrast against the alpha-composited ancestor background; primary actions must retain a nontransparent fill. Hover feedback must change a painted foreground, background, border or shadow without resizing. Keyboard focus must establish `:focus-visible` and a contrasted outline, a changed contrasted border or solid outer shadow ring of at least 1 px (zero offset and blur, positive spread), or the search owner's contrasted `:focus-within` outline. Disabled controls must change opacity/color, retain the disabled cursor and reject focus. Presentation probes restore the previous disabled property without dispatching business events. The dynamic dock additionally obtains disabled state from its real busy view; recorded callbacks prove the probes do not save or inspect accidentally.
|
|
33
|
+
|
|
34
|
+
Each declared responsibility must occur in the generated layout inventory. Repeated rows share one style owner and are sampled; four REPL name kinds are checked individually. Selected binding rows may retain their selected background on hover, while readability and geometry remain required; an unselected row independently exercises hover feedback. Padding removal, primary-fill removal, same foreground/background, zero opacity, removed hover/focus cues and removed disabled feedback are injected into the real fallback action DOM without replacing its classes or handlers. Each fault must fail its corresponding assertion and is removed afterwards. Additional real-control probes reject white-on-white input values, unreadable selected-row hover and transparent focus outlines and transparent, inset or negative-spread shadows; a contrasted shadow remains a legal focus cue. Error and stopped tool summaries use the public state-error-primary and state-warn-primary tokens; the shared warning foreground mixes the latter with label-primary for light/dark readability, and attention badges use the theme background as foreground; reference palettes do not supply the unsupported danger/warning aliases.
|
|
35
|
+
|
|
36
|
+
The draft oracle measures the CSS-owned preview budget and compact header controls separately from expanded content. Compact body/actions remain measurable for stable classification but are hidden and inert. When the full header cannot fit above the owned anchor, the preview is hidden and inert; manual review always opens the enlarged surface independently of hidden-period geometry, closing returns to the owned entry, and a neighboring native dock action must retain its actual center hit. Expanded previews retain at least 40 px of source space; enlarged reviews retain at least 24 px even in the narrow/short cases, with larger reading areas at normal viewport sizes. Source scrolling must leave footer actions fixed, and all visible header/footer controls must pass actual hit testing. Resize and close remain separate header controls with at least 12 px between their hit targets; shrink returns to preview while close hides the panel. Return-focus tests interleave exact cloned candidate refresh with modal closure and retain stale, hidden, completed, unreachable and disposed counterexamples.
|
|
37
|
+
|
|
38
|
+
The sparkle-menu typography oracle requires a plugin-owned 13px/18px content base, 13px disclosure captions and binding names, 12px purposes and 11px states, all with 18px line-height and the inherited font family. It measures text ranges within their row for vertical clipping and checks the caret center against the caption line center, rather than its potentially stretched flex box; injected caption stretching must fail. Horizontal name/purpose ellipsis remains valid. Native/fallback fixtures reproduce a single disabled binding under larger carrier typography, preserve the full purpose title, reject injected inherited font-size and line-height, and accept a smaller carrier. The mixed-catalog root and revision paths and packed official-Host acceptance share the same oracle.
|
|
39
|
+
|
|
40
|
+
The sparkle-menu oracle requires at least 24 px of catalog reading space, viewport containment, nonoverlapping catalog and footer, no outer scrolling, and fully reachable footer actions of at least 24 px height. Scrolling the expanded mixed catalog and the revision list in both directions must leave footer geometry unchanged. Injecting a shared outer scroll container must fail the oracle; restoring the layout must pass. Actual catalog writes must retain a focused control whose center is inside the catalog clip and passes hit testing: collapsed disable, expanded enable, revision Back, and pending close/reopen are covered. Removing the reveal by resetting only the catalog scrollTop must fail this focus oracle; restoring it must pass. Page scroll and footer geometry remain unchanged. Packed official-Host acceptance repeats the mixed-catalog checks through the isolated profile and exercises actual management and settings actions.
|
|
41
|
+
|
|
42
|
+
## Limits
|
|
43
|
+
|
|
44
|
+
Static DOM exports establish presentation, not live RPC, editor, switch or permission behavior; Client interaction tests and packed acceptance own those facts. Disabled presentation is sampled on supported HTML form controls; tabs, disclosures and read-only observations have no disabled/busy product state. Native tool hover remains the official DisclosureRow's responsibility and is not required to paint the plugin fallback title. Static settings/workbench fixtures use public native primitives; the shared ActionButton fallback is tested dynamically in the dock, while fallback menu/modal keyboard, portal, mask, composition and focus-return behavior remain in the same browser runner. Dynamic busy checks cover draft actions and a pending workbench catalog reload. Workbench buttons may retain full opacity when a readable status and wait cursor identify the pending request; they must still reject focus. Request sequencing remains covered by Client interaction tests.
|
|
45
|
+
|
|
46
|
+
The 3:1 floor detects loss of readability and does not claim full WCAG conformance. Empty input placeholder paint and native select popups are outside this bounded text oracle. Shadow evidence is limited to contrasted solid outer rings; arbitrary blur, offset and inset effects are not accepted as proof of visible focus. No pixel baseline freezes typography, animation, every CodeMirror token, offscreen content, antialiasing, arbitrary third-party themes or future CSS properties. New controls or new state owners require updating the responsibility inventory and executable evidence. Backend coverage cannot substitute for this browser contract, and fixture success cannot substitute for official-Host delivery evidence.
|
|
47
|
+
|
|
48
|
+
Draft review checks measure viewport bounds, header/body/action separation, actual control hit targets, independently scrolling source, and the enlarged reading height. Packed Host acceptance compares composer geometry and transcript extent across disclosure and enlargement; native/fallback fixtures exercise the same layout oracle.
|
|
@@ -4,6 +4,18 @@
|
|
|
4
4
|
|
|
5
5
|
本文拥有 `dsh-ptc-plus` 的 journal、两阶段确认和冷恢复契约;`internal/session-journal-schema.js` 拥有封闭字段集合与版本常量,`internal/session-journal.js` 拥有校验、迁移与创建,`internal/session-journal-recovery.js` 拥有事件关联与分支折叠,`internal/session-runtime.js` 拥有 live kernel;它们提供实现证据。
|
|
6
6
|
|
|
7
|
+
## 日志读取与派生事实
|
|
8
|
+
|
|
9
|
+
当前 Host 的历史读取由 `sessionQuery.observeSession` 提供。runtime bridge 为一次顶层调用取得一个不可变 event/cursor/header 切点,释放 observation lease 后仍消费其不可变 events;派生 edit 把该切点传给内层执行,恢复、call identity、provenance 和 no-op 确认不在运行中重读变化的 live log。观察切点与当前 surface 不同时,按该切点的公开 surface operations 重建顺序,而不是用较新的 replacement 撤销较早观察的证据。生产路径不调用 `snapshotEvents`、`eventAt` 或 `ownEvents`。
|
|
10
|
+
|
|
11
|
+
同步 presentation 从 host-only `ptcPlusSessionLog` 单元读取。该单元与批量 journal fold 共用单事件 timeline 转移;checkpoint 仅保存关联所需的最小 call、规范 journal、身份及当前/历史 runtime records,不复制原始事件日志。pruned result 的非 content 身份保存为确定性 SHA-256 摘要。提示的已见身份、最高 ordinal、cooldown 和成功后的未解决计数在事件进入时更新;装配不扫描历史提示。checkpoint 是可丢弃的派生缓存,不证明 model knowledge、成功 initialization 或 cold replay。状态版本、schema 和 Host 的 watermark/restore 规则共同限定缓存使用,损坏或过时缓存必须重新折叠原日志。
|
|
12
|
+
|
|
13
|
+
旧 array-backed session 使用同一转移的批量读取回退。缺少当前公开 reader/投影或历史 events 不是数组时明确诊断,不静默宣称空历史;不存在 session 的非会话调用仍委托其原 owner。投影注册随插件/controller 生命周期释放,运行时关闭后只保留日志事实以撤回旧 PTC 消息,不保留 worker、工具或默认模型状态投影。具体决策见 [ADR 0032](adr/0032-own-session-log-facts-in-a-host-only-projection.md)。
|
|
14
|
+
|
|
15
|
+
结果的 content-only 重发布保留原 settlement 的位置与规范证据,不重新结算 edit claim,也不生成新的成功或编辑目标。原结果缺失时,已有 call 位置限制重建事实的 chronology,不能越过较新的执行。提示身份保留原投递位置,因此后获知的较早成功不能清空其后的未解决提示。
|
|
16
|
+
|
|
17
|
+
checkpoint 准入由 timeline 表示 owner 校验 typed payload、call/entry 对应、edit claim、规范 journal、派生 run 与 transcript 计数,再由投影复用。损坏嵌套状态在 suffix apply 前拒绝;Host 的水位不能替插件证明这些内容。
|
|
18
|
+
|
|
7
19
|
## 恢复承诺
|
|
8
20
|
|
|
9
21
|
PTC Plus 的正确承诺是:
|
package/docs/installation.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Installation
|
|
2
2
|
|
|
3
|
-
PTC Plus requires Node.js `^22.19.0 || >=24.0.0` and targets the latest available DSH release with TypeScript PTC mode.
|
|
3
|
+
PTC Plus requires Node.js `^22.19.0 || >=24.0.0` and targets the latest available DSH release with TypeScript PTC mode. Historical interface branches are retained through capability detection, without promising a fully verified earlier Host installation; when both generations expose competing presentation evidence, the current DSH contract wins. Compatibility follows those live extension surfaces rather than a version allowlist.
|
|
4
4
|
|
|
5
5
|
The worker uses the Host's Node executable. Startup verifies native REPL framing, imports, syntax failures, synchronous throws, awaited rejections, and original return values. The adapter combines public eval callbacks with domain error events before REPL formatting; a source-end witness distinguishes empty completion from falsy rejection. A failed or timed-out probe reports a runtime prerequisite failure before user code executes. The engine range follows DSH; CI exercises Node 22.19, 24, and 26, without claiming that untested future releases have already passed.
|
|
6
6
|
|
|
@@ -18,20 +18,41 @@ Install the plugin into the profile that actually runs the target DSH surface. D
|
|
|
18
18
|
|
|
19
19
|
`danger-full-access` is the primary supported experience. The worker isolates the REPL lifecycle; it is not a malicious-code sandbox. DSH continues to own native-tool scope, policy, approval, cancellation, sandboxing, and scheduling. Narrower profiles expose only their available capabilities; PTC Plus does not simulate missing authority or add another permission system.
|
|
20
20
|
|
|
21
|
-
The optional `cordisToolsEnabled` integration requires the current DSH installation to provide its shipped `cordis` preset plus the public preset, Skill, Cordis, settings, and tool-runtime services. PTC Plus declares the shared service packages as unrestricted required peers instead of installing private runtime copies. For a pathless preset it asks the Host's `pluginPackages.packageOf` service for the active generation's official preset package and requires the exact `cordis-plugin-development/SKILL.md` before mounting it; an older generation with no package service may resolve only its historical plural preset package relative to the Host's `ctx.baseUrl`. This compatibility path is disabled whenever `pluginPackages` exists, so packages merely reachable from the plugin profile cannot override an active Host result. Runtime capability validation owns compatibility, and CI loads the packed plugin against frozen official `latest` and `next` DSH graphs. That load step mounts the pathless Cordis companion from a separated active-host resource while a resolvable stale package is present beside the packed plugin, runs `scripts/dsh-execution-seam-smoke.mjs` to
|
|
21
|
+
The optional `cordisToolsEnabled` integration requires the current DSH installation to provide its shipped `cordis` preset plus the public preset, Skill, Cordis, settings, and tool-runtime services. PTC Plus declares the shared service packages as unrestricted required peers instead of installing private runtime copies. For a pathless preset it asks the Host's `pluginPackages.packageOf` service for the active generation's official preset package and requires the exact `cordis-plugin-development/SKILL.md` before mounting it; an older generation with no package service may resolve only its historical plural preset package relative to the Host's `ctx.baseUrl`. This compatibility path is disabled whenever `pluginPackages` exists, so packages merely reachable from the plugin profile cannot override an active Host result. Runtime capability validation owns compatibility, and CI loads the packed plugin against frozen official `latest` and `next` DSH graphs. That load step mounts the pathless Cordis companion from a separated active-host resource while a resolvable stale package is present beside the packed plugin, runs `scripts/dsh-execution-seam-smoke.mjs` to exercise public provider composition around the execution service the installed tool runtime uses, and runs `scripts/dsh-rpc-contract-smoke.mjs` to register the packed Remote descriptors with the installed TYPERT registry and evaluate the decoder that generation reads ([ADR 0030](adr/0030-serve-both-typert-codec-generations-from-one-codec.md)); an import alone cannot distinguish a loaded plugin from one whose injection is unsatisfied, because Cordis leaves the latter pending without an error, and it cannot show that the Host accepts a wire contract it validates only at registration. The same suite round-trips argument diagnostics through the selected Host's compressed JSONL Session persistence. Service packages retain the dependency graph selected by their Host distribution rather than independently selecting each service's release tag. DSH's profile module fallback must resolve the peers, while `pluginPackages` identifies the official preset resource from an active installation that publishes the service. Do not copy `SKILL.md` or add the Cordis preset's Skill directory to global roots. If the host surface is incomplete, plugin activation or enabling the setting fails instead of loading a second DSH core.
|
|
22
22
|
|
|
23
23
|
The plugin attaches to whichever program-execution service the installed DSH registers, and it presents the capabilities of the execution it performs ([ADR 0028](adr/0028-attach-to-the-host-ptc-execution-seam.md)). Cells run in the session kernel under the session's configured budgets, so `run_code` advertises neither a per-call deadline nor a file sandbox, and DSH rejects `timeoutMs` and `sandbox_permissions` with its own message instead of the plugin accepting an input it would then ignore.
|
|
24
24
|
|
|
25
|
+
Install the complete `cordis.patch.yml` bundle, not only its main plugin row. The bundle preserves the original `ptc-runtime` module and configuration, isolates its `ptcRuntime` service as `ptc-plus-original`, and adds the independent `dsh-ptc-plus/execution-provider` row before the main row. A custom composition must set that provider row's `originalEntryId` to its actual source row ID relative to the provider row's Loader tree (the profile Include subtree in standard installations) and its `isolation` to the same value as the source row's `isolate.ptcRuntime`; keep PTC Plus runtime settings on the main row. The adapter registers its own public provider and never writes to the original instance. Disabling the main row restores native delegation through the adapter; removing the complete bundle also restores the original global service. An uncomposed original produces an explicit composition diagnostic rather than a mutation fallback.
|
|
26
|
+
|
|
25
27
|
Supported installations use an unmodified official DSH release. Local plugin development packages this checkout. The release development launcher uses the published Host; the opt-in [upstream source launcher](#upstream-source-development-launcher-windows) builds the unmodified official repository for testing unreleased changes. Neither path patches the Host. Missing public layout interfaces remain a feature limitation, not an instruction to customize DSH. See [ADR 0017](adr/0017-track-the-latest-dsh-public-surface.md) for distribution and acceptance requirements.
|
|
26
28
|
|
|
27
|
-
The Client root requires `slots`, `locale`, `connection`, and `remote`; it
|
|
29
|
+
The Client root requires `slots`, `locale`, `connection`, and `remote`; it adopts whichever public settings transport the installed Host exposes (`configForms` or `settingsScope`) through an optional injection and keeps its shipped `CONFIG_FIELDS` defaults while neither is available, so a renamed or withdrawn transport degrades the settings surface instead of suspending activation. Feature eligibility follows those defaults: only an explicit `enabled: false` withdraws a contribution. Contributions wait for their public slots and consume the supplied session hooks; the composer action additionally requires `remote.commands`. Neither an unused `ui-session` module nor a renamed conversation registry gates activation. Preset selection prefers `agentPreset` projection evidence, falling back only to a historical public session summary field when that projection is absent. Binding values and draft capabilities always require their own projections. No private store or raw-log fallback is used. Slot and provider disposal withdraw the contributions they own.
|
|
30
|
+
|
|
31
|
+
### Compatibility Evidence
|
|
32
|
+
|
|
33
|
+
The two frozen dependency graphs are installation cohorts, not proof of two distinct capability generations. `compat/latest/package-lock.json` and the root `package-lock.json` record the releases each smoke actually installs; their channel names do not prove the live npm dist-tags or compatibility with an adjacent earlier release. Both recorded cohorts exercise `ptcRuntime`, `configForms`, `plugins.row.config`, volatile configuration and `codec.create()`. `npm run host:baseline:verify` checks frozen graph consistency, not every historical fallback or current registry availability.
|
|
34
|
+
|
|
35
|
+
| Retained interface | Evidence and consequence of removal |
|
|
36
|
+
| --- | --- |
|
|
37
|
+
| `retainedBy.mainView`, `plugins.row.config`, volatile updates, `codec.create()`, composer props carrying their own `sessionId` | Required by the frozen graphs; these are current paths, not optional historical fallbacks. |
|
|
38
|
+
| `settingsScope`, `settings.plugin.item`, section-installer variants | Historical, unfrozen Host shapes, covered with fixtures. Removal loses their live settings, card seat or reconfiguration path. |
|
|
39
|
+
| `snapshot.current`, bare summary `agentPreset` | Historical, unfrozen selection and preset shapes. Removal can strand their session-specific views or PTC eligibility. Binding and draft evidence never use the preset fallback. |
|
|
40
|
+
| Historical icon names and missing primitives | Fixtures establish component fallback, not a complete earlier Client. Removal of icon candidates loses native glyphs; usable text/component fallbacks must remain. |
|
|
41
|
+
| Menu without a `children` region | Rendering probe plus a plugin-owned fallback. Removal makes binding actions unreachable on that historical primitive; JSX is not passed through the Host's string-only label field. |
|
|
42
|
+
| `codec.schema` | Historical, unfrozen registry shape. Removal rejects Remote registration on schema-only Hosts. The factory and schema share one decoder. |
|
|
43
|
+
| `codeRuntime.run(request)` | Historical, unfrozen execution shape. Removal leaves that Host without a session REPL attachment. Fixture tests preserve it; both frozen graphs exercise resolve/run instead. |
|
|
44
|
+
| Plural preset-package layout and Host-anchored resolution | Historical Hosts without `pluginPackages` need this companion-resource path. Removal breaks their Cordis companion; it must never override an available active-Host package service. |
|
|
45
|
+
| `sessionQuery.observeSession` and host-only `sessionProjections` | Current history and presentation owners; missing services are diagnosed, not treated as empty recovery evidence. The projection publishes no Client wire view. |
|
|
46
|
+
| Legacy session event arrays and V0 boundary migration | Read-only fixtures preserve historical ancestry and file conversion through the shared event transition. Removal can discard reconstructable older sessions; malformed arrays are diagnosed, and format conversion does not prove a complete older Host's live behavior. |
|
|
47
|
+
|
|
48
|
+
Capabilities select behavior, never a release number. Historical fixture success is not packed-Host evidence. Full Host smoke is bounded to its selected graph, and a clean build is not live browser activation. Public provider composition supports frozen original execution instances without changing their descriptors. Two integration boundaries are accepted: the result bridge requires mutable registered tool definitions ([ADR 0028](adr/0028-attach-to-the-host-ptc-execution-seam.md)), and the two-tool model projection retains a complete native registry and SDK through scoped `both` presentation plus assembly projection ([ADR 0005](adr/0005-temporary-rejected-cell-edit-transport.md)). Proven native miscalls are normalized before Host dispatch; an unnormalized root call can reach approval before the plugin rejects it. Frozen tool definitions remain unsupported. Acceptance preserves current behavior and DSH governance; it does not claim that the missing public metadata or independent direct-admission contracts have been implemented.
|
|
28
49
|
|
|
29
50
|
## npm Release
|
|
30
51
|
|
|
31
52
|
Use this form after the selected version is available from the npm registry:
|
|
32
53
|
|
|
33
54
|
```sh
|
|
34
|
-
dsh plugin --profile <profile> add dsh-ptc-plus@0.4.
|
|
55
|
+
dsh plugin --profile <profile> add dsh-ptc-plus@0.4.10
|
|
35
56
|
dsh --profile <profile> --dump-config
|
|
36
57
|
```
|
|
37
58
|
|
|
@@ -68,7 +89,7 @@ pnpm dsh --profile <profile> --dump-config
|
|
|
68
89
|
|
|
69
90
|
```sh
|
|
70
91
|
npm pack
|
|
71
|
-
dsh plugin --profile <profile> add /absolute/path/to/dsh-ptc-plus-0.4.
|
|
92
|
+
dsh plugin --profile <profile> add /absolute/path/to/dsh-ptc-plus-0.4.10.tgz
|
|
72
93
|
dsh --profile <profile> --dump-config
|
|
73
94
|
```
|
|
74
95
|
|
|
@@ -124,7 +145,7 @@ dsh plugin add github:muyuanjin/dsh-ptc-plus#main
|
|
|
124
145
|
dsh --dump-config
|
|
125
146
|
```
|
|
126
147
|
|
|
127
|
-
After an npm release, the package spec may instead be `dsh-ptc-plus@0.4.
|
|
148
|
+
After an npm release, the package spec may instead be `dsh-ptc-plus@0.4.10`. For a local package, use its absolute tarball path. Restart DSH Desktop after installation. Linux Desktop is not a current DSH Desktop release target; use DSH CLI/Web on Linux.
|
|
128
149
|
|
|
129
150
|
## Upgrades
|
|
130
151
|
|
|
@@ -93,7 +93,7 @@ Missing-description diagnostics append a complete DSH user message to `additiona
|
|
|
93
93
|
|
|
94
94
|
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.
|
|
95
95
|
|
|
96
|
-
`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.
|
|
96
|
+
`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 or a submitted cell is preparing to execute 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.
|
|
97
97
|
|
|
98
98
|
`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 read its Skill root as an immutable bundled Host resource, 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.
|
|
99
99
|
|
package/docs/user-bindings.en.md
CHANGED
|
@@ -18,7 +18,7 @@ To revise a saved binding, use `/binding edit <id> <requirement>`. Its storage `
|
|
|
18
18
|
|
|
19
19
|
## Draft panel
|
|
20
20
|
|
|
21
|
-
A new draft
|
|
21
|
+
A new draft floats above the composer. Click the title bar or use Enter/Space to collapse and expand it without moving the conversation or composer. Long content scrolls inside the panel. When space above the composer is limited, the preview shows only its header and enlarge action. If even the header cannot fit, the composer menu and historical request keep the draft entry; manual draft entries always open the large dialog. Choose **Enlarge binding draft** for a large review dialog with independently scrolling content and save/discard actions kept at the bottom. The header keeps resize and close controls spaced apart. Escape, the backdrop, or **Shrink binding draft** returns to preview without saving or discarding; if preview cannot fit, focus returns to the composer entry. The separate close button hides the draft panel, which can be reopened from the sparkle menu.
|
|
22
22
|
|
|
23
23
|
- **Save as disabled**: keep the entry in the global list without loading it.
|
|
24
24
|
- **Save and enable**: save it and allow subsequent calls to load it.
|
|
@@ -27,7 +27,7 @@ A new draft opens above the composer. Click the title bar or use Enter/Space to
|
|
|
27
27
|
|
|
28
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.
|
|
29
29
|
|
|
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
|
|
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 are grouped by enabled state with counts. Enabled entries appear first; each menu opening starts with the disabled group collapsed. Click the group or press Enter/Space to expand it. Entries retain their names, purposes, and status text. Only the catalog scrolls; authoring, revision, management, and settings actions stay at the bottom, as does Back in the revision step. 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. After a toggle, focus follows the regrouped entry, or returns to the disabled group button if that group hides the entry; focus outside the menu is left alone. Recovery scrolls only the binding list to reveal the target, leaving the footer and conversation in place. **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.
|
|
31
31
|
|
|
32
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.
|
|
33
33
|
|
package/docs/user-bindings.md
CHANGED
|
@@ -18,16 +18,16 @@
|
|
|
18
18
|
|
|
19
19
|
## 草稿面板
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
新草稿自动悬浮在输入框上方。点击标题栏或使用 Enter/Space 折叠、展开,不挤动对话和输入框;长内容可在面板内滚动;输入框上方空间不足时只显示标题栏,仍可放大查看;连标题也放不下时保留星光菜单和历史请求的草稿入口,手动草稿入口始终直接打开大窗口。点击 **放大查看绑定草稿** 打开大尺寸审阅窗口,正文独立滚动,底部始终保留保存与丢弃按钮。标题栏的尺寸切换与关闭按钮之间留有间距。按 Escape、点击遮罩或 **缩小显示绑定草稿** 返回预览;预览没有可用空间时焦点回到星光入口,不保存或丢弃草稿。独立关闭按钮隐藏草稿面板,可从星光菜单重新打开。
|
|
22
22
|
|
|
23
23
|
- **保存为停用**:保存到全局列表,暂不加载。
|
|
24
24
|
- **保存并启用**:保存并允许后续调用加载。
|
|
25
25
|
- **丢弃草稿**:放弃这份未保存候选。
|
|
26
26
|
- **关闭面板**:只隐藏面板,不保存或丢弃。
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
输入框星光按钮显示待处理草稿的角标。悬停、点击或键盘打开菜单后,选择草稿即可在大窗口中重新审阅。每个会话保留一份当前候选。保存或丢弃确认成功后面板关闭;失败时保留草稿供重试。
|
|
29
29
|
|
|
30
|
-
星光按钮的 PTC Plus 提示延迟显示,说明它是全局绑定与设置入口;有待处理草稿时改为提示草稿状态。菜单、管理窗口或设置窗口打开时隐藏提示,避免遮挡。星光菜单在首条消息发出前即可使用,鼠标停留一下才展开,扫过输入区不会弹出。悬停打开后鼠标移开菜单即自动关闭;点击可让菜单保持常开,再点一次、点击别处或按 Escape
|
|
30
|
+
星光按钮的 PTC Plus 提示延迟显示,说明它是全局绑定与设置入口;有待处理草稿时改为提示草稿状态。菜单、管理窗口或设置窗口打开时隐藏提示,避免遮挡。星光菜单在首条消息发出前即可使用,鼠标停留一下才展开,扫过输入区不会弹出。悬停打开后鼠标移开菜单即自动关闭;点击可让菜单保持常开,再点一次、点击别处或按 Escape 关闭。全局绑定按启用、停用分组并显示数量,已启用条目优先展示,停用组每次打开菜单时默认折叠,可点击或用 Enter/Space 展开;条目保留名称、用途与状态文字。只有绑定列表滚动,底部编写、修改、管理与设置操作固定可见,“修改绑定”第二步的“返回”也固定在底部;点击条目切换启停,配置对所有会话生效。目录在后台刷新,刷新期间沿用上一次的列表并可以继续操作;切换写入逐条串行化,写入进行中条目保持可用,重复请求被直接丢弃;发生冲突或失败时可重新加载后再操作。启停后条目进入对应分组;焦点仍在菜单中时跟随该条目,若条目进入折叠的停用组则回到组按钮,不抢走菜单外的焦点。焦点恢复仅滚动绑定列表来显示目标,不移动底栏或对话。“管理全局绑定”打开完整工作台;编写命令可用时显示“编写新绑定”和“修改绑定”,“修改绑定”第二步从已有条目中选择后预填 `/binding edit <id> `。REPL 可复用绑定列表会显示每项被后续 cell 复用的次数,并在区块标题显示总复用次数;次数按后续 cell 编译后源码中的静态引用统计,重定义或重声明本身不算一次复用,也不会把已累计的次数清零。
|
|
31
31
|
|
|
32
32
|
历史中的“绑定编写”请求保留需求、状态和接受时的源码。它供查看当时内容,不重新获得保存资格。目录发生并发修改时,重新加载最新状态后再决定是否保存。
|
|
33
33
|
|
|
@@ -24,6 +24,32 @@ owns command syntax, thresholds, generated evidence, and the final gate.
|
|
|
24
24
|
- Node test options may follow a standalone `--` after the focused source and
|
|
25
25
|
test selections.
|
|
26
26
|
|
|
27
|
+
Compiler instrumentation belongs to the test runner, not the compiler service.
|
|
28
|
+
The runner prepares bytecode without coverage, then preloads
|
|
29
|
+
`scripts/instrument-compiler-coverage.mjs` before the compiler captures Node's
|
|
30
|
+
`Script` constructor. Only the exact compiler bundle bypasses cached bytecode
|
|
31
|
+
consumption during that run; cache export uses the prepared, uninstrumented
|
|
32
|
+
bytes. The real-worker testing entry installs the same seam before importing
|
|
33
|
+
the production worker, removes its private entry locator and bytecode-path
|
|
34
|
+
environment variable, restores the ordinary worker's `process.argv[1]` through
|
|
35
|
+
the worker realm restoration boundary, and then runs the unchanged worker. Production compilation
|
|
36
|
+
does not read `NODE_V8_COVERAGE` or `DSH_PTC_COMPILER_BYTECODE` and never opens a
|
|
37
|
+
file selected by those variables.
|
|
38
|
+
|
|
39
|
+
The testing `Script` seam preserves the compiler's option prototype and property
|
|
40
|
+
descriptors while disabling only `cachedData`. Ordinary scripts keep their
|
|
41
|
+
original options. Descriptor conversion uses the shared compiler descriptor
|
|
42
|
+
owner; the seam captures its required primordials before user execution so
|
|
43
|
+
caller prototype and static-method mutations cannot reach private compilation.
|
|
44
|
+
Prepared cache export copies typed-array internal data through a captured native
|
|
45
|
+
constructor, without invoking public length getters on its private snapshot.
|
|
46
|
+
The shared compiler platform also uses captured native byte operations for
|
|
47
|
+
encoding and decoding, so first-use TypeScript lowering cannot invoke a caller's
|
|
48
|
+
replacement typed-array length getter in either ordinary or covered execution.
|
|
49
|
+
Covered and ordinary workers use the same absolute entry
|
|
50
|
+
normalization for URL objects, file-URL strings, and filenames; the testing
|
|
51
|
+
preload does not independently reinterpret a caller's entry.
|
|
52
|
+
|
|
27
53
|
## Workflow
|
|
28
54
|
|
|
29
55
|
Use focused coverage after the nearest behavioral test passes or after a full
|
package/docs/verification.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
## Incremental independent review
|
|
6
6
|
|
|
7
|
+
The standard local and CI gates run `test:client:visual`: one Client suite exports fresh renderer fixtures, followed by deterministic browser layout and visual assertions. Install its locked browser first with `npx playwright install --with-deps chromium`; missing browsers fail verification. The [Client visual contract](client-visual-contract.md) owns the bounded control/state inventory, reference palettes, fault counterexamples and official-Host evidence limits. Focused diagnostics may run `npm run test:client:visual` independently; they do not replace the final gate.
|
|
8
|
+
|
|
7
9
|
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
10
|
|
|
9
11
|
```bash
|
package/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import Schema from '@deepseek-ai/schemastery'
|
|
|
10
10
|
import { randomUUID } from 'node:crypto'
|
|
11
11
|
import { createDirectSurfaceOwner } from './internal/direct-surface-owner.js'
|
|
12
12
|
import { createRuntimeMessageOwner } from './internal/runtime-contexts.js'
|
|
13
|
+
import { createSessionLogOwner } from './internal/session-log-view.js'
|
|
13
14
|
import { PTC_DELIVERY_CONTEXT } from './internal/runtime-messages.js'
|
|
14
15
|
import { createCordisToolsOwner } from './internal/cordis-tools-owner.js'
|
|
15
16
|
import { createEditTransportOwner, EDIT_RUN_CODE } from './internal/edit-transport-owner.js'
|
|
@@ -50,7 +51,7 @@ export const Config = Schema.object(Object.fromEntries(
|
|
|
50
51
|
* it under the service name of one generation, so `installExecutionSeam`
|
|
51
52
|
* selects the live one.
|
|
52
53
|
*/
|
|
53
|
-
export const inject = ['tools', 'systemPrompt', 'agents'
|
|
54
|
+
export const inject = ['tools', 'systemPrompt', 'agents']
|
|
54
55
|
|
|
55
56
|
function replGuidance({ bindingPolicy, rewritesEnabled, languageSemantics, durableReplay, cordisToolsEnabled }) {
|
|
56
57
|
const looseTopLevelRedeclarations = bindingPolicy.variableRedeclarations
|
|
@@ -100,7 +101,7 @@ Native tool availability, executable names, shells, and path syntax depend on th
|
|
|
100
101
|
}
|
|
101
102
|
|
|
102
103
|
/** Register the session-bound REPL runtime. */
|
|
103
|
-
function installPtCRuntime(ctx, resolvedConfig, seam, toolSchemasForAgent, sessionId) {
|
|
104
|
+
function installPtCRuntime(ctx, resolvedConfig, seam, toolSchemasForAgent, sessionId, sessionLog) {
|
|
104
105
|
const presentationGeneration = randomUUID()
|
|
105
106
|
const replMemoryProjection = createReplMemoryProjection(presentationGeneration)
|
|
106
107
|
const userBindingDraftProjection = createUserBindingDraftProjection(presentationGeneration)
|
|
@@ -331,6 +332,7 @@ function installPtCRuntime(ctx, resolvedConfig, seam, toolSchemasForAgent, sessi
|
|
|
331
332
|
ready = awaitCordisToolsOwner(initialCordisTools, new Promise(() => {}))
|
|
332
333
|
}
|
|
333
334
|
userBindings = createUserBindingsOwner(ctx, {
|
|
335
|
+
readSessionLog: sessionLog.read,
|
|
334
336
|
enabled: activeConfig.userBindingsEnabled,
|
|
335
337
|
draftProjectionAvailable,
|
|
336
338
|
maxWallMs: activeConfig.maxWallMs,
|
|
@@ -342,6 +344,7 @@ function installPtCRuntime(ctx, resolvedConfig, seam, toolSchemasForAgent, sessi
|
|
|
342
344
|
ctx,
|
|
343
345
|
seam,
|
|
344
346
|
observeSession: id => observationInterest.has(id),
|
|
347
|
+
readSessionLog: sessionLog.read,
|
|
345
348
|
sessionConfig: activeConfig,
|
|
346
349
|
userBindingsCwd: userBindings.cwd,
|
|
347
350
|
maxNestedRunCodeDepth: activeConfig.maxNestedRunCodeDepth,
|
|
@@ -352,6 +355,8 @@ function installPtCRuntime(ctx, resolvedConfig, seam, toolSchemasForAgent, sessi
|
|
|
352
355
|
bindingSubmissionForAgent: (agent, ensureLease, onAccepted) => userBindings.submissionForAgent(agent, ensureLease, onAccepted),
|
|
353
356
|
})
|
|
354
357
|
editTransport = createEditTransportOwner(ctx, {
|
|
358
|
+
readSessionLog: runtimeBridge.readSubmissionLog,
|
|
359
|
+
sessionLogView: sessionLog.project,
|
|
355
360
|
durableReplay: activeConfig.durableReplay,
|
|
356
361
|
executeTentative: runtimeBridge.executeTentative,
|
|
357
362
|
presentationGeneration,
|
|
@@ -359,6 +364,7 @@ function installPtCRuntime(ctx, resolvedConfig, seam, toolSchemasForAgent, sessi
|
|
|
359
364
|
toolSchemasForAgent,
|
|
360
365
|
})
|
|
361
366
|
directSurface = createDirectSurfaceOwner({
|
|
367
|
+
sessionLogView: sessionLog.project,
|
|
362
368
|
editTransport,
|
|
363
369
|
runtimeConfig: activeConfig,
|
|
364
370
|
canonicalizeToolCalls: activeConfig.canonicalizeToolCalls,
|
|
@@ -395,6 +401,7 @@ function installPtCRuntime(ctx, resolvedConfig, seam, toolSchemasForAgent, sessi
|
|
|
395
401
|
))
|
|
396
402
|
.then(result => directSurface.argumentDiagnostic(exec, result))
|
|
397
403
|
}
|
|
404
|
+
if (exec.name === EDIT_RUN_CODE) return runtimeBridge.withSubmission(exec, next)
|
|
398
405
|
return next()
|
|
399
406
|
}))
|
|
400
407
|
disposers.push(ctx.on('tools/result', (exec, result) => {
|
|
@@ -527,6 +534,7 @@ export const apply = (ctx, config = {}) => {
|
|
|
527
534
|
|
|
528
535
|
/** Install the plugin into the scope of the seam the host registered. */
|
|
529
536
|
function applyWithExecutionSeam(ctx, resolvedConfig, seam, volatileHost, volatileConfig) {
|
|
537
|
+
const sessionLog = createSessionLogOwner(ctx)
|
|
530
538
|
const toolSchemasForAgent = agent => typeof ctx.tools.schemas === 'function'
|
|
531
539
|
? ctx.tools.schemas(agent)
|
|
532
540
|
: []
|
|
@@ -613,7 +621,7 @@ function applyWithExecutionSeam(ctx, resolvedConfig, seam, volatileHost, volatil
|
|
|
613
621
|
}
|
|
614
622
|
let candidate
|
|
615
623
|
try {
|
|
616
|
-
candidate = installPtCRuntime(ctx, record.config, seam, toolSchemasForAgent, sessionId)
|
|
624
|
+
candidate = installPtCRuntime(ctx, record.config, seam, toolSchemasForAgent, sessionId, sessionLog)
|
|
617
625
|
record.runtime = candidate
|
|
618
626
|
} catch (error) {
|
|
619
627
|
const failedRuntime = error?.[INSTALL_CLEANUP]
|
|
@@ -757,7 +765,7 @@ function applyWithExecutionSeam(ctx, resolvedConfig, seam, volatileHost, volatil
|
|
|
757
765
|
|
|
758
766
|
const messageOwner = createRuntimeMessageOwner(context => (
|
|
759
767
|
committed?.retiring ? [] : committed?.runtime.contextsForRequest(context) ?? []
|
|
760
|
-
))
|
|
768
|
+
), sessionLog.project)
|
|
761
769
|
ctx.effect(() => ctx.systemPrompt.context({
|
|
762
770
|
name: PTC_DELIVERY_CONTEXT, order: 98, text: '',
|
|
763
771
|
}), 'ptc-plus dynamic message delivery witness')
|
|
@@ -788,7 +796,7 @@ function applyWithExecutionSeam(ctx, resolvedConfig, seam, volatileHost, volatil
|
|
|
788
796
|
? { enabled: false }
|
|
789
797
|
: Object.fromEntries(CONFIG_FIELDS.map(field => [field.key, previousConfig[field.key]]))
|
|
790
798
|
try {
|
|
791
|
-
await settingsWriter.update(
|
|
799
|
+
await settingsWriter.update(patch)
|
|
792
800
|
} catch (rollbackError) {
|
|
793
801
|
reportActivationFailure(new Error(
|
|
794
802
|
`ptc-plus: failed to roll back runtime configuration: ${rollbackError.message}`,
|
|
@@ -840,11 +848,24 @@ function applyWithExecutionSeam(ctx, resolvedConfig, seam, volatileHost, volatil
|
|
|
840
848
|
},
|
|
841
849
|
onChange: reconcile,
|
|
842
850
|
},
|
|
843
|
-
onProvider(
|
|
844
|
-
settingsWriter =
|
|
851
|
+
onProvider(_provider, writer) {
|
|
852
|
+
settingsWriter = writer
|
|
853
|
+
return () => { if (settingsWriter === writer) settingsWriter = undefined }
|
|
845
854
|
},
|
|
846
855
|
})
|
|
847
856
|
}
|
|
857
|
+
ctx.effect(() => seam.onSourceChange(() => {
|
|
858
|
+
const current = resolveConfig(configSource())
|
|
859
|
+
if (!current.enabled) return undefined
|
|
860
|
+
if (seam.language !== 'typescript') {
|
|
861
|
+
const language = seam.language
|
|
862
|
+
const cleanup = controller.uninstall()
|
|
863
|
+
reportActivationFailure(new Error('ptc-plus: unsupported code runtime language '
|
|
864
|
+
+ JSON.stringify(language) + '; only "typescript" is supported'))
|
|
865
|
+
return cleanup
|
|
866
|
+
}
|
|
867
|
+
return reconcile(true)
|
|
868
|
+
}), 'ptc-plus original language lifecycle')
|
|
848
869
|
watchVolatileConfig(volatileHost, ctx, volatileConfig, () => reconcile())
|
|
849
870
|
if (configurationGeneration === 0) return reconcile(settingsWriter === undefined)
|
|
850
871
|
}
|
|
@@ -20,6 +20,7 @@ const nativePathToFileURL = pathToFileURL
|
|
|
20
20
|
const nativeStripTypeScriptTypes = stripTypeScriptTypes
|
|
21
21
|
const runInContext = Script.prototype.runInContext
|
|
22
22
|
const NativeUint8Array = Uint8Array
|
|
23
|
+
const typedArrayLength = descriptor(Object.getPrototypeOf(NativeUint8Array.prototype), 'length').get
|
|
23
24
|
const NativeWeakRef = WeakRef, deref = WeakRef.prototype.deref
|
|
24
25
|
const NativeError = Error
|
|
25
26
|
const parseJson = JSON.parse
|
|
@@ -65,11 +66,12 @@ export const compilerPlatformBridge = {
|
|
|
65
66
|
fileURLToPath: input => nativeFileURLToPath(nativeUrl(input)),
|
|
66
67
|
pathToFileURL: input => ownUrl(nativePathToFileURL(input)),
|
|
67
68
|
encode(source, encoding) {
|
|
68
|
-
const
|
|
69
|
-
const
|
|
69
|
+
const size = byteLength(source, encoding)
|
|
70
|
+
const buffer = new NativeUint8Array(size)
|
|
71
|
+
const length = apply(codecs[encoding].write, buffer, [source, 0, size])
|
|
70
72
|
return { buffer, length }
|
|
71
73
|
},
|
|
72
|
-
decode: (buffer, encoding) => apply(codecs[encoding].slice, buffer, [0, buffer
|
|
74
|
+
decode: (buffer, encoding) => apply(codecs[encoding].slice, buffer, [0, apply(typedArrayLength, buffer, [])]),
|
|
73
75
|
textEncoder() {
|
|
74
76
|
const encoder = new NativeTextEncoder()
|
|
75
77
|
return { encode: source => apply(encoderEncode, encoder, [source]),
|
|
@@ -2,7 +2,6 @@ import { readFileSync } from 'node:fs'
|
|
|
2
2
|
import { constants, createContext, Script } from 'node:vm'
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
4
|
import { workerData } from 'node:worker_threads'
|
|
5
|
-
import { deserialize } from 'node:v8'
|
|
6
5
|
import { copyCompilerData } from './compiler-data.js'
|
|
7
6
|
import { PreflightError } from './cell-analysis-contract.js'
|
|
8
7
|
import { ModuleRewriteError } from './cell-error.js'
|
|
@@ -29,10 +28,7 @@ const define = compilerDescriptors.defineProperty
|
|
|
29
28
|
const keys = Object.keys
|
|
30
29
|
let compiler
|
|
31
30
|
let compilerScript
|
|
32
|
-
|
|
33
|
-
const bytecodeFile = process.env.DSH_PTC_COMPILER_BYTECODE
|
|
34
|
-
let workerCache = bytecodeFile ? deserialize(readFileSync(bytecodeFile)) : undefined
|
|
35
|
-
if (workerCache?.source !== compilerSource) workerCache = undefined
|
|
31
|
+
let workerCache
|
|
36
32
|
// Bytecode contains no compiler realm or program state. Match the complete
|
|
37
33
|
// source: V8's cache validation alone does not prove source text equality.
|
|
38
34
|
let cachedData = workerData?.compilerCache?.source === compilerSource
|
|
@@ -43,9 +39,6 @@ if (workerData !== null && typeof workerData === 'object') delete workerData.com
|
|
|
43
39
|
/** Reuse compiled compiler code across fresh workers, never their realm state. */
|
|
44
40
|
export function compilerWorkerCache() {
|
|
45
41
|
if (compilerScript === undefined) return undefined
|
|
46
|
-
// Instrumented compiler instances neither produce nor consume bytecode.
|
|
47
|
-
// Coverage's runner supplies a snapshot from its uninstrumented preparation.
|
|
48
|
-
if (workerCache === undefined && coverageEnabled) return undefined
|
|
49
42
|
workerCache ??= { source: compilerSource, data: apply(createCachedData, compilerScript, []) }
|
|
50
43
|
return { source: workerCache.source, data: new NativeUint8Array(workerCache.data) }
|
|
51
44
|
}
|
|
@@ -58,7 +51,7 @@ function compilerEntry() {
|
|
|
58
51
|
// Workers can execute host-prepared cells without compiling dynamic source.
|
|
59
52
|
// Capture source and platform before user code, but parse only on first use.
|
|
60
53
|
compilerScript = new NativeScript(compilerSource, { __proto__: null, filename, displayErrors: false,
|
|
61
|
-
cachedData
|
|
54
|
+
cachedData })
|
|
62
55
|
cachedData = undefined
|
|
63
56
|
const context = nativeCreateContext(dontContextify)
|
|
64
57
|
define(context, '__compilerBaseUrl', { value: import.meta.url })
|