# DESIGN — 设计溯源 本插件是一次有明确出处的组合式设计,不是闭门造车。三个来源、三种角色: ## 1. [codex-bridge-chatgpt](https://github.com/anightmonarch/codex-bridge-chatgpt)(MIT)— 机制蓝本 职责拆分哲学原样保留:**网页 AI 提方案,本地 Agent 验证、修改、测试**。以下机制自该项目移植并适配 dsh(代码为本项目原创 MIT 实现,字段命名按 dsh 语境调整): | 机制 | 原项目 | 本项目 | | --- | --- | --- | | Context Packet 契约(标记 + 六章节 + 3K token 上限) | `validate-handoff.mjs` | `validate.mjs`(同构移植,新增 gitlab/slack token 模式) | | Reasoning Result 契约(七章节 + packet_id 绑定) | 同上 | 同上 | | 本地采纳门(accepted / rejected / deferred + 本地证据) | references/ + SKILL.md | `references/adoption-gate.md` | | 运行回执(schema_version 2 + 哈希绑定 + 隐私审查字段) | `codex_model` / `chatgpt_model` | `local_model` / `web_model`,新增 `target` 字段 | | complete 闸门(全字段 passed + 产物哈希重算) | 同上 | 同上 | | 版本化风险授权状态机(disclosure_version + 精确确认令牌 + 原子写) | `automation-consent.mjs` | `consent.mjs`(确认令牌与状态路径改为 dsh 约定) | | Doctor 分层预检(安装层 → 授权层 → 浏览器层) | `doctor.mjs` + references/doctor.md | `doctor.mjs` + `references/doctor.md` | | 传输纪律:只发一次、不确定即停、可见取回、不碰私有端点 | browser-transport.md | `references/transport.md` + 各目标适配器 | 核心差异是**传输层**:原项目依赖 Codex 桌面 App 的 in-app Browser;dsh 本身内置 CDP 浏览器工具(`browser_launch` 复用日常 Chrome 登录态),登录问题天然缓解, 因此预检简化为 `NEEDS_BROWSER / NEEDS_LOGIN / NEEDS_MODEL_SELECTION / NEEDS_SITE_PERMISSION`, 并把"只许 in-app Browser"改写为"只许 dsh 内置调试实例、只做用户可见等价操作"。 ## 2. [ShunCode](https://github.com/ZS520L/shuncode) — 设计理念参照 ShunCode(README-only 理念仓库)对本项目的影响是取向而非代码: - **桥接复用网页订阅**:不把网页 AI 当复制粘贴对象,而是受控、契约化的协作方; ShunCode 用 MCP Bridge 把本地工作区暴露给网页 AI,本项目选择反方向—— 浏览器把 Packet 推给网页 AI、把结论带回本地验证(无需公网隧道,攻击面更小)。 - **权限分层**:Ask / Plan / Code 的分层思想体现在 consent → preflight → adoption 三道门上:未授权不碰浏览器,未预检不发 Packet,未过采纳门不动仓库。 - **按需上下文**:Packet 只装"会改变决策的信息",默认摘要、必要时最小摘录, 与 ShunCode 的上下文经济原则一致。 - **安全边界白纸黑字**:环回/最小化/脱敏/免责声明不弱化,回执可审计但明确 "哈希只绑定本地产物,不是远端模型证明"。 ## 3. dsh 插件体系 — 宿主事实 - 技能注册:`ctx.skills.register(...)`(`@deepseek-ai/dsh-skill` 运行时技能, `resourceBase: { kind: 'directory' }` 让 references/scripts 随技能目录解析) - 提示注入:`ctx.systemPrompt.section(...)`;生命周期:`ctx.effect(fn, label)` (与 `dsh-vision` 插件同款用法) - 打包分发:`dsh.plugin.json` + `dsh plugin --profile web add ` - 零依赖、零构建:`lib/` + `skills/` 即产物(`dsh-versions` 先例),全部确定性逻辑 用 node:test 覆盖 ## 4. 传输层 v2(0.2.0)— 从散文到可执行代码 0.1.0 的传输只有 `transport-chatgpt.md` 里给 agent 照抄的 `browser_eval` 片段。 对照真实工具面(`dsh-browser-control@0.1.0`)发现两处硬伤,片段根本跑不通: 1. **每次求值都重新导航**:`browser_eval {url, expression}` 底层 `drive.mjs` 先 `Page.navigate` 再求值——发送后的标签页会被后续调用清掉,无法分步操作同一页面。 2. **异步结果丢失**:`Runtime.evaluate` 未设 `awaitPromise`,文档里所有 `(async () => …)()` 只返回 `"Promise"` 字符串——composer 等待、流式结束检测、 剪贴板读取全部拿不到值。 3. **启动器仅 macOS**:`launch.sh` 硬编码 `$HOME/Library/...`,Windows 上 `browser_launch` 必然失败,流程永远停在 `NEEDS_BROWSER`。 0.2.0 的对策:插件自带**零依赖 CDP 驱动**(`scripts/lib/cdp.mjs`,Node ≥ 22 原生 WebSocket),附着到 dsh 调试 Chrome 同一个 :9222 实例,一次连接内完成 navigate → `evaluate(awaitPromise)` → 截图;页面阶段(probe/send/fetch)是 `scripts/lib/page-chatgpt.mjs` 里可测试的表达式构建器,选择器多候选、失败映射 `why` 码,禁触 Cookie/存储/网络由单元测试守卫。纪律不降级:仍是一次发送、 可见等价操作、经站点自身 copy 控件 + 剪贴板取回(`Browser.grantPermissions` 授权,失败降级为可见 DOM 文本并如实标注 `extraction: "dom"`)、不碰私有端点。 传输驱动的角色边界:**不接管生命周期**——macOS 上仍优先 dsh `browser_launch` (登录态复用);Windows 兜底 `transport.mjs launch` 用专用独立 profile 启动, 不拷贝任何凭据文件(登录态拷贝属于 browser-control 的职责,本插件的纪律禁止 触碰 Cookie 等凭据文件),首次在该可见窗口人工登录一次。 ## 何时扩展新目标 新增一个网页 AI 目标 = `scripts/targets-table.mjs` 加一行(target.mjs 与 validate.mjs 共享此表,不会漂移)+ `scripts/lib/page-.mjs` 写该站点的 选择器集与阶段表达式 + `references/transport-.md` 按适配器契约写清 登录探测 / 模型校验 / 一次性发送 / 可见取回 / 阻断态 / 证据。 Packet、Result、采纳门、回执契约不需要任何改动。 页面模块需自带 `INPUT_MODE`(`paste-event` 或 `insert-text`)与对应阶段函数: `paste-event` 导出 `buildSendExpression`,`insert-text` 导出 `buildComposerFocusExpression` + `buildSendAfterInsertExpression`;两者都必须导出 `buildProbeExpression` 与 `buildFetchExpression`。`tests/transport.test.mjs` 会断言 「表里的目标」与「page-*.mjs 文件」一一对应,并逐个检查导出契约——少写一边 CI 就红。 ## 5. 0.4.0 审计:把「宣称」与「机制」分开 0.4.0 之前,README 的多条承诺(采纳门、发送前脱敏、consent 闸门)**只有散文、 没有代码**。根因是结构性的:`dsh.plugin.json` 声明 `"tools": []`,插件不注册任何 工具,因此**无法拦截**模型对 `pwsh`/`edit`/`write` 的调用——采纳门在设计上就只能 是「请求模型遵守」。 审计(一次 README-vs-实现 走查 + 两次独立子审计:采纳门绕过、敏感外发)的处置原则: - **能变机制的立刻变机制**:consent 前置闸门(`open|probe|send`)、发送前凭据扫描 (`send` 命中即拒)、`complete` 复扫产物内容、采纳记录非空要求、面板端口解析修复。 - **变不成机制的诚实标注**:README 增「强制执行 vs. 纪律约定」表, `adoption-gate.md`、`reasoning-result.md` 明写「校验通过=结构合规,不等于安全」。 - **顺手修掉的确定性缺陷**:扫描器从 7 条扩到 20 类(JWT/云密钥/连接串/webhook/.env 原先全漏,且 `sk_live_` 与 `\b` 两处正则本身写错);测试守卫从 5 字符串扩到覆盖 `sendBeacon`/`cookieStore`/`WebSocket`/`import()` 等绕过面;`checkNodeRuntime` 从死配置变成真闸门;`.gitignore` 补上运行产物。 教训记在这里:**任何「我们把 X 关在门外」的表述,都要能指向一行拒绝执行的代码**, 否则就写成纪律,并说明它依赖遵守。