# 开发、验证和限制

[English](development.en.md) · [返回 README](../README.md)

## 架构

- Host：`src/index.ts` 连接 `tools/pre-execute` 和 `approval/request`，并挂载 `AutoReviewLiveRemote`；`orchestrator.ts` 管理 Guardian、原生人工审批、审计和生命周期；`LiveReviewHub` 保存有界 watcher 队列和每 Session 最近快照，Remote 可从当前审计 JSONL 恢复已持久化终态；`audit.ts` 写最终 JSONL。
- Client：设置卡注册到 `settings.plugin.item`；插件 `apply()` 捕获生成的 Typert Remote 与 timer 回调，再通过 `conversation.input.dock` 的 inject face 交给 `LiveAutoReviewCard` 约每 250 ms 轮询。React 组件不持有 Cordis `ctx`，session 切换后的重新挂载不会越过插件 inject 上下文；Card 与设置共用的样式由 `apply()` 独立安装，不依赖当前禁用的旧 presentation registration；输入框上方的 Card 使用与内置任务卡片相同的 dock 列宽、边框层级和 tip 背景。
- Host/Client 仅通过 Remote 传递最小 JSON。`src/client/review.ts`、Chat/Tool View/Trajectory registration 和 Host Session append 仍保留并测试，但生产入口已注释并标记 `TODO(dsh-session-events)`。

## TypeScript-only 工作流

要求 Node `^22.19.0 || >=24`：

```bash
pnpm install
pnpm typecheck
pnpm lint
pnpm test
pnpm coverage
pnpm publint
pnpm check:no-js
npm pack --dry-run
```

`pnpm verify` 执行发布门禁。Git 不跟踪 `.js/.mjs/.cjs`；运行时产物仅生成到被忽略但会发布的 `lib/`。

Client bundle 使用 DSH ModuleLoader，React 为 external；Typert generator 在 Client typecheck/bundle 前生成 `./typert` 与 `./remote` artifacts，`zod` 随 Client bundle 打包。Cordis patch 必须用 manifest package identity `dsh-auto-review-plugin`，Host loader 才能发现契约。

## pnpm 依赖构建脚本审批

pnpm 11 会阻止尚未明确批准的依赖在安装阶段运行 `preinstall`、`install`、`postinstall` 等生命周期脚本。看到以下输出不表示 lockfile 或包内容损坏：

```text
[ERR_PNPM_IGNORED_BUILDS] Ignored build scripts:
@deepseek-ai/dsh-subprocess-local, koffi
```

`koffi` 是原生 FFI 依赖，通常需要选择或构建当前平台的二进制文件；DSH 的本地 subprocess 路径会间接引入它。脚本被忽略后，普通 TypeScript 构建可能仍能通过，但依赖本地 subprocess、终端或 native FFI 的运行时路径可能失败。

审核包名、版本和来源后，只批准明确需要的依赖：

```bash
pnpm approve-builds @deepseek-ai/dsh-subprocess-local koffi
pnpm rebuild @deepseek-ai/dsh-subprocess-local koffi
```

也可以运行交互式 `pnpm approve-builds` 逐项选择。不要在未审核全部候选依赖时使用 `pnpm approve-builds --all`。

安装日志中的 `Packages: +N -M` 只是 pnpm 按当前 `package.json` 与 lockfile 重新协调 `node_modules`：增加当前依赖图需要的包，并删除不再需要的包；它与构建脚本审批是两件独立的事。

## CI 与 npm 发布

- `.github/workflows/ci.yml` 在目标为 `main`/`master` 的 Pull Request，以及这两个分支的新 push 上执行 `pnpm verify` 和 coverage。
- `.github/workflows/publish.yml` 响应严格稳定语义版本 tag `vX.Y.Z`。tag 必须与 `package.json` 版本一致，验证通过后使用仓库 Secret `TOKEN` 发布 `dsh-auto-review-plugin`，npm dist-tag 固定为 `latest`。

## 测试重点

- Shell/network/MCP/extension target 分类和一次性 `session + callId + live signal` correlation；
- Guardian 输出、风险策略、取消和 disposal；
- 原生 approval waterfall 的 allow/reject/cancel/unavailable；
- audit-before-allow、JSONL 修复/轮转/并发序列；
- live watcher 最近快照回放、Session/permission 隔离、有界队列与快照、TTL、审计恢复，以及 `start → status → end`；
- 不追加自定义 Session 事件，实时 payload 字段白名单和判断原因脱敏；
- 设置卡默认折叠、保存/重置/回滚，Trajectory 控件隐藏；
- 保留的 legacy Chat node 合并、折叠卡和 Trajectory RunningToolCall → ToolResultNode。

## 本地安装验证

```bash
pnpm build
dsh plugin --profile <isolated-profile> add "$PWD"
dsh --profile <isolated-profile> --dump-config
```

Web 变更需要重建实际 GUI 使用的 Client artifact，并刷新现有 DSH Web 页面。不要启动一个独立 Vite 页面替代 `dsh web`，因为 Web shell 依赖 `window.__DSH_BOOT__`。

## 已知限制

- 插件不能拦截绕过 ToolRuntime 的原生网络连接，也不能制造 DSH 未提供的可信网络/MCP provenance。
- Shell 分类有意保守；复杂但安全的命令仍可能被审查。
- Guardian 无法调用只读工具继续调查，只能使用 Host 给出的有界证据。
- JSONL writer 没有跨进程文件锁。
- 最近卡片不写入 Session；Host 重启恢复依赖当前审计路径中的 final record。关闭审计、审计失败或审计路径变更后不可从旧路径恢复。
- 当前不写第三方 Session UI 事件；旧 Session 中已有的不兼容事件不会自动修复。
- Settings card 需要 Host Settings namespace 与 Plugins Settings Slot；实时卡片还需要 Remote、timer 和 `conversation.input.dock`。
- 当前 DSH 将内置 permission preset SVG 按名称硬编码，`PresetSpec` 没有 icon 字段。plugin-only 版本无法为 `auto-review` 注册一致图标；需要上游图标扩展点后再实现。
