# 参与开发
本文面向 `dsh-web-review` 的维护者和贡献者,介绍本地开发、技术架构、验证与公开发布流程。普通用户请阅读 [README.md](./README.md)。
## 发布边界
- 源码包保持 `private: true`。
- npm 包名保持 `@canglongcl/dsh-web-review`,正式 tarball 的发布访问级别必须为 `public`。
- 不要在仓库文件、命令参数、日志或截图中写入真实令牌和 provider 凭据。
完整且具有约束力的工程规则见 [AGENTS.md](./AGENTS.md)。修改协议、加载方式或安全边界前必须先阅读该文件。
## 环境准备
### 1. 安装依赖
直接从公共 npm registry 安装依赖,无需配置 `@deepseek-ai` 只读令牌:
```sh
pnpm install
```
安装过程会配置仓库的 pre-commit hook。普通的类型检查、构建、单元测试、打包和 npm 发布使用锁定的公共 npm 依赖,不要求本地存在 Harness checkout。
### 2. 准备 Harness
开发、手动验收和 E2E 需要外部 DeepSeek Harness checkout。当前兼容基线是:
```text
snapshot-20260812T172954Z-final-unwatermarked-5fa48343c7
7b9644f2b664e46c9518506035aa6c8d5af4d8e8
```
Harness 必须位于本仓库之外,不要为本插件修改 Harness 源码:
```sh
export DSH_HARNESS='/绝对路径/deepseek-harness'
pnpm setup:harness
```
`setup:harness` 会检查目标 commit、构建状态和必需产物,并生成本机专用、已被 gitignore 的 `cordis.yml` 与 `packages/dsh-web-review/entry-name.json`。
## 开发流程
启动完整开发环境:
```sh
pnpm dev
```
它会同时启动 Harness Web profile 和本包的客户端 bundle watch。浏览器端修改可通过刷新应用,Node 端修改需要重启 Web 进程。
启动演示页面:
```sh
pnpm demo
```
演示页默认地址为 `http://127.0.0.1:5173`。
需要可重复的隔离验收环境时运行:
```sh
pnpm dev:acceptance
```
该命令使用 `.artifacts/acceptance/` 下的独立 profile、固定端口和持久测试会话,不修改日常 DSH profile。测试凭据不会进入日志或版本库。
## 技术架构
插件由一个双面 package 和一个隔离 frame artifact 组成:
| 部分 | 主要职责 |
|---|---|
| Node 端 | 创建和撤销预览会话、运行 loopback 代理、校验批注快照、准备 Agent 上下文 |
| DSH 浏览器端 | 注册网页预览标签、宿主层编辑器、批注胶囊和发送确认 |
| 隔离 frame bridge | 在预览页面内执行元素选择、序列化 DOM 信息、临时样式预览与精确回滚 |
| Agent 协作 | 在 `agent/pre-step` 中追加独立的 Browser Comments 消息,使用现有工作区工具修改源码 |
### 加载方式
- 开发环境通过 profile-local alias `@dsh-web-review-dev/plugin` 加载外部 checkout。
- `scripts/profile-plugin-link.ts` 在 Web profile 下维护对应 symlink;非 symlink 占用该路径时会失败,不会覆盖。
- `cordis.yml` 只通过 `dsh web --patch` 增加本插件,不修改 Harness profile 或源码。
- 开发 bundle 和正式 bundle 使用不同的 loader ID,不能混用。
- Node bundle 必须自包含,运行时不能依赖本 checkout 的 `node_modules`。
### 预览隔离
- DSH host 只提供预览会话控制接口,不在宿主 Origin 返回目标页面内容。
- 每个顶层目标使用随机、短生命周期的 `*.localhost` Preview Origin。
- 会话绑定目标 Origin,并固定首次 DNS 解析,防止 rebinding。
- 代理只转发受支持的方法与有界请求,绝不转发浏览器 Cookie 或 Authorization。
- HTML 使用解析器改写,并在页面脚本之前注入 ``、bridge 配置与 bridge bundle。
- Host 与 frame 只通过严格校验的 `postMessage` 协议通信;生产代码不得直接读取 iframe DOM。
### 元素选择与临时编辑
- bridge 独占页面中的实时元素引用和回滚记录,React store 只保存可序列化快照。
- 元素快照、选择器、页面 URL 和 framework anchor 都是不可信页面证据。
- 评论、请求的样式值和文本替换属于用户输入,但仍需通过长度、数量和属性白名单校验。
- 临时样式修改前必须记录精确的原始 inline value 与 priority。
- 重置、取消、移除、清空、发送成功、导航和卸载都必须恢复页面原状。
### 批注与发送
- 浏览器发送结构化 `{ sessionId, page, comments[] }`,不在客户端拼接模型提示词。
- Node 端严格校验后生成稳定的 `# Browser comments` 上下文。
- 批注以独立的 plugin-sourced user message 追加,不得改写用户输入框原文。
- 只有带有匹配 `snapshotId` 的持久 Context 记录才能清除胶囊,失败或被拒绝的发送必须保留批注以供重试。
- 插件不注册新的模型工具;Agent 使用会话已有的文件和 Shell 工具修改工作区。
## 代码约定
- 仓库全部使用 TypeScript,包括 `scripts/`、`demo/` 与测试。
- 产品文案使用中文;代码注释、JSDoc 和协议上下文使用英文。
- 业务状态放在 `createWebviewStore()` 中,组件只通过 props 接收数据。
- 生产 host 代码不得保存 iframe 内的 `Element`,也不得调用页面函数。
- HTML 改写必须使用 `parse5`,不得用正则表达式处理 HTML。
- `cordis.yml`、`entry-name.json`、`lib/`、`dist/` 和测试产物均为生成文件,不得提交。
- 提交信息遵循仓库现有风格。
## 验证
提交前至少运行:
```sh
pnpm check
```
涉及 UI、预览代理、bridge 或批注发送链路时,还需运行:
```sh
DSH_HARNESS='/绝对路径/deepseek-harness' pnpm test:e2e
```
也可以执行完整门禁:
```sh
DSH_HARNESS='/绝对路径/deepseek-harness' pnpm check:e2e
```
主要命令:
| 命令 | 用途 |
|---|---|
| `pnpm typecheck` | TypeScript 项目检查 |
| `pnpm test` | 构建并运行 Vitest |
| `pnpm check` | 类型、测试、配置契约、bundle 与包白名单门禁 |
| `pnpm test:e2e` | 真实 DSH GUI、隔离 Origin、点选与发送链路 |
| `pnpm package:official` | 生成正式安装包 |
| `pnpm release:verify` | 校验待发布产物 |
pre-commit hook 会运行快速门禁,不包含需要启动服务和 provider 配置的浏览器 E2E。
## 打包与发布
构建正式安装包:
```sh
pnpm package:official
```
产物位于 `dist/`,仅包含白名单内的 manifest、自包含 bundles、bridge、Skills、README 和演示资源。
正式 npm 发布只通过 `.github/workflows/release-npm.yml`:
1. PR 与 `main` 运行 npm-only 质量门禁。
2. 与 `package.json` 版本完全一致的 `v*` tag 才能触发发布。
3. 发布 Job 使用前一 Job 已校验的 tarball,不重新构建。
4. 发布 Job 通过 npm Trusted Publishing 使用短期 GitHub OIDC 身份,并显式保持 `public`。
dist-tag 规则:`x.y.z-beta.N` 发布到 `beta`,其他候选版本(如 `-rc`)发布到 `next`,稳定版本发布到 `latest`。创建 tag 前必须单独完成显式 Harness E2E:
```sh
DSH_HARNESS='/绝对路径/deepseek-harness' pnpm check:e2e
git tag -a v -m "dsh-web-review v"
git push personal v
```
### Beta 渠道
`pnpm release:beta [基础版本] [--dry-run]` 完成 beta 发布的本地前置步骤:
- 校验两份 manifest 版本一致且为合法 semver,工作区干净;
- 计算下一个 beta 版本:当前是 `x.y.z-beta.N` 时递增为 `x.y.z-beta.(N+1)`;否则从当前稳定版本的下一个 minor(或显式给出的基础版本)开始,即 `x.y.z-beta.0`;
- 校验新版本高于 npm 上已发布的 `beta` / `latest`;
- 写入两份 manifest,运行 `pnpm release:verify`,提交 `release: bump `,打 `v` 注释 tag 并推送到 origin。
tag 推送后 CI 自动打包并发布到 `beta` dist-tag,用户可用 `npm i @canglongcl/dsh-web-review@beta` 安装。`--dry-run` 只打印计划,不修改任何文件。
Trusted Publisher 与 CI 边界的详细配置以 [AGENTS.md](./AGENTS.md) 为准。发布 workflow 不保存 npm 写令牌。
## 提交变更
提交前确认:
1. 改动未突破 Preview Origin、消息信任边界或公开发布约束。
2. 没有提交生成文件、凭据、日志、截图或构建产物。
3. `pnpm check` 通过;相关 UI 或发送路径的 E2E 也已通过。
4. 用户可见行为和限制已同步更新到 [README.md](./README.md)。