patchwarden 1.5.0 → 1.5.1
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 +43 -2
- package/README.md +43 -2
- package/dist/assessments/agentAssessor.d.ts +1 -1
- package/dist/assessments/agentAssessor.js +3 -3
- package/dist/assessments/assessmentStore.d.ts +1 -1
- package/dist/assessments/assessmentStore.js +2 -2
- package/dist/assessments/confirmCli.js +5 -4
- package/dist/config.d.ts +7 -0
- package/dist/config.js +34 -0
- package/dist/control/middleware/auth.d.ts +10 -0
- package/dist/control/middleware/auth.js +8 -0
- package/dist/control/middleware/static.d.ts +3 -0
- package/dist/control/middleware/static.js +65 -0
- package/dist/control/routes/audit.d.ts +15 -0
- package/dist/control/routes/audit.js +277 -0
- package/dist/control/routes/evidence.d.ts +4 -0
- package/dist/control/routes/evidence.js +96 -0
- package/dist/control/routes/lineage.d.ts +3 -0
- package/dist/control/routes/lineage.js +71 -0
- package/dist/control/routes/policy.d.ts +3 -0
- package/dist/control/routes/policy.js +81 -0
- package/dist/control/routes/process.d.ts +5 -0
- package/dist/control/routes/process.js +200 -0
- package/dist/control/routes/sessions.d.ts +22 -0
- package/dist/control/routes/sessions.js +224 -0
- package/dist/control/routes/status.d.ts +6 -0
- package/dist/control/routes/status.js +250 -0
- package/dist/control/routes/taskActions.d.ts +21 -0
- package/dist/control/routes/taskActions.js +233 -0
- package/dist/control/routes/tasks.d.ts +20 -0
- package/dist/control/routes/tasks.js +310 -0
- package/dist/control/routes/workspace.d.ts +15 -0
- package/dist/control/routes/workspace.js +193 -0
- package/dist/control/runtime.d.ts +91 -0
- package/dist/control/runtime.js +392 -0
- package/dist/control/server.d.ts +13 -0
- package/dist/control/server.js +479 -0
- package/dist/control/shared.d.ts +35 -0
- package/dist/control/shared.js +288 -0
- package/dist/controlCenter.d.ts +6 -0
- package/dist/controlCenter.js +7 -2197
- package/dist/direct/directGuards.js +30 -8
- package/dist/doctor.d.ts +18 -1
- package/dist/doctor.js +579 -348
- package/dist/goal/goalReport.d.ts +54 -0
- package/dist/goal/goalReport.js +204 -0
- package/dist/goal/goalStatus.d.ts +6 -0
- package/dist/goal/specKitImport.d.ts +63 -0
- package/dist/goal/specKitImport.js +220 -0
- package/dist/goal/subgoalSync.js +2 -1
- package/dist/httpServer.js +15 -12
- package/dist/index.js +7 -4
- package/dist/logging.d.ts +7 -1
- package/dist/logging.js +8 -0
- package/dist/runner/changeCapture.d.ts +3 -3
- package/dist/runner/changeCapture.js +63 -39
- package/dist/runner/cli.js +7 -6
- package/dist/runner/postTaskCleanup.js +26 -2
- package/dist/runner/runTask.js +245 -221
- package/dist/runner/simpleProcess.js +4 -4
- package/dist/runner/watch.js +17 -14
- package/dist/security/contentRedaction.d.ts +6 -0
- package/dist/security/contentRedaction.js +22 -0
- package/dist/smoke-test.js +257 -251
- package/dist/test/unit/apply-patch.test.d.ts +1 -0
- package/dist/test/unit/apply-patch.test.js +225 -0
- package/dist/test/unit/create-task.test.d.ts +1 -0
- package/dist/test/unit/create-task.test.js +197 -0
- package/dist/test/unit/direct-guards.test.js +124 -9
- package/dist/test/unit/evidence-pack.test.js +95 -1
- package/dist/test/unit/get-task-status.test.d.ts +1 -0
- package/dist/test/unit/get-task-status.test.js +174 -0
- package/dist/test/unit/get-task-summary.test.d.ts +1 -0
- package/dist/test/unit/get-task-summary.test.js +146 -0
- package/dist/test/unit/goal-report.test.d.ts +1 -0
- package/dist/test/unit/goal-report.test.js +159 -0
- package/dist/test/unit/goal-subgoal-task.test.js +6 -6
- package/dist/test/unit/goal-tools-registry.test.js +6 -4
- package/dist/test/unit/path-guard.test.js +24 -0
- package/dist/test/unit/spec-kit-import.test.d.ts +1 -0
- package/dist/test/unit/spec-kit-import.test.js +341 -0
- package/dist/test/unit/wait-for-task.test.d.ts +1 -0
- package/dist/test/unit/wait-for-task.test.js +144 -0
- package/dist/tools/auditTask.d.ts +8 -63
- package/dist/tools/auditTask.js +12 -8
- package/dist/tools/createDirectSession.d.ts +1 -1
- package/dist/tools/createDirectSession.js +2 -2
- package/dist/tools/createTask.d.ts +2 -2
- package/dist/tools/createTask.js +4 -4
- package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
- package/dist/tools/dispatch/coreDispatch.js +282 -0
- package/dist/tools/dispatch/diagnosticDispatch.d.ts +14 -0
- package/dist/tools/dispatch/diagnosticDispatch.js +78 -0
- package/dist/tools/dispatch/directDispatch.d.ts +8 -0
- package/dist/tools/dispatch/directDispatch.js +115 -0
- package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
- package/dist/tools/dispatch/goalDispatch.js +91 -0
- package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
- package/dist/tools/dispatch/releaseDispatch.js +45 -0
- package/dist/tools/dispatch/types.d.ts +23 -0
- package/dist/tools/dispatch/types.js +15 -0
- package/dist/tools/evidencePack.d.ts +6 -0
- package/dist/tools/evidencePack.js +213 -6
- package/dist/tools/finalizeDirectSession.d.ts +1 -1
- package/dist/tools/finalizeDirectSession.js +3 -3
- package/dist/tools/goalSubgoalTask.d.ts +1 -1
- package/dist/tools/goalSubgoalTask.js +2 -2
- package/dist/tools/healthCheck.js +3 -3
- package/dist/tools/registry.d.ts +3 -3
- package/dist/tools/registry.js +60 -503
- package/dist/tools/retryTask.d.ts +2 -2
- package/dist/tools/retryTask.js +2 -2
- package/dist/tools/runTaskLoop.js +4 -4
- package/dist/tools/safeViews.d.ts +2 -2
- package/dist/tools/safeViews.js +2 -2
- package/dist/tools/toolRegistry.js +22 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/CODE_WIKI.md +983 -0
- package/docs/agentseal-integration.md +150 -0
- package/docs/architecture.md +63 -0
- package/docs/assets/patchwarden-oss-demo.gif +0 -0
- package/docs/dashboard-overview.md +86 -0
- package/docs/demo.md +8 -0
- package/docs/direct-session-workflow.md +98 -0
- package/docs/evidence-pack-schema.md +215 -0
- package/docs/execution-plan-2026-07-09.md +315 -0
- package/docs/lineage-evidence-pack-workflow.md +127 -0
- package/docs/mcp-inspector-testing.md +200 -0
- package/docs/open-source-application.md +162 -0
- package/docs/opencode-worker.md +151 -0
- package/docs/openhands-worker.md +181 -0
- package/docs/release-evidence.md +72 -0
- package/docs/roadmap-execution-and-acceptance.md +365 -0
- package/docs/spec-kit-integration.md +131 -0
- package/docs/task-safe-review-workflow.md +98 -0
- package/docs/threat-model.md +79 -0
- package/docs/user-feedback.md +40 -0
- package/docs/why-patchwarden.md +110 -0
- package/package.json +2 -2
- package/scripts/checks/control-center-smoke.js +356 -0
- package/scripts/checks/lifecycle-smoke.js +29 -23
- package/scripts/checks/mcp-smoke.js +3 -1
- package/scripts/generate-demo-gif.py +320 -0
- package/src/assessments/agentAssessor.ts +3 -3
- package/src/assessments/assessmentStore.ts +2 -2
- package/src/assessments/confirmCli.ts +5 -4
- package/src/config.ts +37 -0
- package/src/control/middleware/auth.ts +17 -0
- package/src/control/middleware/static.ts +71 -0
- package/src/control/routes/audit.ts +321 -0
- package/src/control/routes/evidence.ts +107 -0
- package/src/control/routes/lineage.ts +92 -0
- package/src/control/routes/policy.ts +81 -0
- package/src/control/routes/process.ts +204 -0
- package/src/control/routes/sessions.ts +251 -0
- package/src/control/routes/status.ts +325 -0
- package/src/control/routes/taskActions.ts +248 -0
- package/src/control/routes/tasks.ts +323 -0
- package/src/control/routes/workspace.ts +203 -0
- package/src/control/runtime.ts +472 -0
- package/src/control/server.ts +471 -0
- package/src/control/shared.ts +294 -0
- package/src/controlCenter.ts +7 -2347
- package/src/direct/directGuards.ts +28 -7
- package/src/doctor.ts +741 -481
- package/src/goal/goalReport.ts +271 -0
- package/src/goal/goalStatus.ts +6 -0
- package/src/goal/specKitImport.ts +355 -0
- package/src/goal/subgoalSync.ts +4 -2
- package/src/httpServer.ts +17 -14
- package/src/index.ts +7 -4
- package/src/logging.ts +10 -1
- package/src/runner/changeCapture.ts +70 -42
- package/src/runner/cli.ts +7 -6
- package/src/runner/postTaskCleanup.ts +26 -2
- package/src/runner/runTask.ts +325 -223
- package/src/runner/simpleProcess.ts +4 -4
- package/src/runner/watch.ts +17 -14
- package/src/security/contentRedaction.ts +29 -0
- package/src/smoke-test.ts +252 -250
- package/src/test/unit/apply-patch.test.ts +293 -0
- package/src/test/unit/create-task.test.ts +255 -0
- package/src/test/unit/direct-guards.test.ts +178 -8
- package/src/test/unit/evidence-pack.test.ts +110 -1
- package/src/test/unit/get-task-status.test.ts +203 -0
- package/src/test/unit/get-task-summary.test.ts +173 -0
- package/src/test/unit/goal-report.test.ts +189 -0
- package/src/test/unit/goal-subgoal-task.test.ts +6 -6
- package/src/test/unit/goal-tools-registry.test.ts +7 -5
- package/src/test/unit/path-guard.test.ts +30 -0
- package/src/test/unit/spec-kit-import.test.ts +429 -0
- package/src/test/unit/wait-for-task.test.ts +176 -0
- package/src/tools/auditTask.ts +99 -59
- package/src/tools/createDirectSession.ts +3 -3
- package/src/tools/createTask.ts +7 -7
- package/src/tools/dispatch/coreDispatch.ts +374 -0
- package/src/tools/dispatch/diagnosticDispatch.ts +101 -0
- package/src/tools/dispatch/directDispatch.ts +167 -0
- package/src/tools/dispatch/goalDispatch.ts +127 -0
- package/src/tools/dispatch/releaseDispatch.ts +65 -0
- package/src/tools/dispatch/types.ts +24 -0
- package/src/tools/evidencePack.ts +291 -6
- package/src/tools/finalizeDirectSession.ts +4 -4
- package/src/tools/goalSubgoalTask.ts +2 -2
- package/src/tools/healthCheck.ts +3 -3
- package/src/tools/registry.ts +68 -628
- package/src/tools/retryTask.ts +2 -2
- package/src/tools/runTaskLoop.ts +4 -4
- package/src/tools/safeViews.ts +2 -2
- package/src/tools/toolRegistry.ts +22 -0
- package/src/version.ts +1 -1
- package/ui/pages/audit.html +192 -3
- package/ui/pages/dashboard.html +959 -44
- package/ui/pages/direct-sessions.html +505 -53
- package/ui/pages/task-detail.html +456 -438
- package/ui/pages/tasks.html +598 -61
|
@@ -0,0 +1,983 @@
|
|
|
1
|
+
# PatchWarden Code Wiki
|
|
2
|
+
|
|
3
|
+
> 本文档是对 PatchWarden 仓库的结构化代码导览,覆盖项目整体架构、主要模块职责、关键类与函数说明、依赖关系及运行方式。
|
|
4
|
+
> 源码版本:**v1.5.1** · Schema Epoch:`2026-07-05-v13` · License:MIT
|
|
5
|
+
|
|
6
|
+
## 目录
|
|
7
|
+
|
|
8
|
+
- [1. 项目概览](#1-项目概览)
|
|
9
|
+
- [2. 整体架构](#2-整体架构)
|
|
10
|
+
- [3. 目录结构](#3-目录结构)
|
|
11
|
+
- [4. 核心模块职责](#4-核心模块职责)
|
|
12
|
+
- [5. 关键类与函数说明](#5-关键类与函数说明)
|
|
13
|
+
- [6. 数据流与状态机](#6-数据流与状态机)
|
|
14
|
+
- [7. 依赖关系](#7-依赖关系)
|
|
15
|
+
- [8. 项目运行方式](#8-项目运行方式)
|
|
16
|
+
- [9. 安全设计](#9-安全设计)
|
|
17
|
+
- [10. 测试与发布](#10-测试与发布)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 1. 项目概览
|
|
22
|
+
|
|
23
|
+
PatchWarden 是一个面向本地编程 Agent 的**安全 MCP(Model Context Protocol)桥接器**。上游的 ChatGPT、Codex、OpenCode 或其他 MCP 客户端负责规划与验收,PatchWarden 负责把计划保存成工作区内任务,再由预先配置的本地 Agent 执行,并返回结果、代码差异和独立测试记录。
|
|
24
|
+
|
|
25
|
+
**核心定位**:
|
|
26
|
+
|
|
27
|
+
> PatchWarden is a local-first MCP safety and verification layer for AI coding agents, with workspace confinement, command allowlists, scope-violation detection, and auditable task evidence.
|
|
28
|
+
|
|
29
|
+
**关键特性**:
|
|
30
|
+
|
|
31
|
+
- MCP 工具不提供通用 Shell,上游模型只能调用明确的 MCP 工具
|
|
32
|
+
- 每个任务必须指定位于 `workspaceRoot` 内的 `repo_path`
|
|
33
|
+
- Agent 启动命令来自本地配置,不来自模型输入
|
|
34
|
+
- 测试命令必须精确匹配 `allowedTestCommands` 白名单
|
|
35
|
+
- 任务完成后保存结构化结果、完整差异、文件统计和独立验证记录
|
|
36
|
+
- 工作区外出现变化时标记为作用域违规,而非悄悄接受
|
|
37
|
+
- `.env`、Token、SSH 密钥、Cookie、凭据文件等敏感路径默认不可读
|
|
38
|
+
|
|
39
|
+
**技术栈**:TypeScript + Node.js(≥18)+ `@modelcontextprotocol/sdk`,无任何运行时第三方依赖。
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. 整体架构
|
|
44
|
+
|
|
45
|
+
### 2.1 角色与数据流
|
|
46
|
+
|
|
47
|
+
```text
|
|
48
|
+
ChatGPT / Codex / OpenCode / 其他 MCP 客户端
|
|
49
|
+
│
|
|
50
|
+
▼
|
|
51
|
+
PatchWarden MCP Server(stdio / HTTP)
|
|
52
|
+
│
|
|
53
|
+
save_plan / create_task / run_task_loop
|
|
54
|
+
│
|
|
55
|
+
▼
|
|
56
|
+
.patchwarden/tasks/<task_id>/
|
|
57
|
+
│
|
|
58
|
+
Watcher 发现任务
|
|
59
|
+
│
|
|
60
|
+
▼
|
|
61
|
+
本地 Agent(OpenCode / Codex)
|
|
62
|
+
│
|
|
63
|
+
▼
|
|
64
|
+
result.json / diff.patch / verify.json / status.json
|
|
65
|
+
│
|
|
66
|
+
▼
|
|
67
|
+
MCP 客户端读取 safe 摘要、审计证据并人工验收
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2.2 三种运行角色
|
|
71
|
+
|
|
72
|
+
一次完整运行通常包含三个独立角色:
|
|
73
|
+
|
|
74
|
+
| 角色 | 职责 | 入口 |
|
|
75
|
+
| --- | --- | --- |
|
|
76
|
+
| **MCP Server** | 暴露受限的 planning/task/summary/audit 工具 | `dist/index.js`(stdio)或 `dist/httpServer.js`(HTTP) |
|
|
77
|
+
| **Watcher** | 轮询 queued 任务并启动本地 Agent | `dist/runner/watch.js` |
|
|
78
|
+
| **本地 Agent** | 真正修改代码,必须在配置中预先登记 | 由 Watcher 通过 `spawn` 启动 |
|
|
79
|
+
|
|
80
|
+
> ⚠️ "MCP 已连接"不等于"任务一定会执行"。如果 Watcher 没有运行,`create_task` 仍能保存任务,但任务会保持 `queued` 并返回 `execution_blocked: true`。
|
|
81
|
+
|
|
82
|
+
### 2.3 三种工具 Profile
|
|
83
|
+
|
|
84
|
+
| Profile | 工具数 | 用途 |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| `full` | 64 | 本地完整开发目录,包含核心、管理、Direct 工具 |
|
|
87
|
+
| `chatgpt_core` | 26 | ChatGPT Tunnel 固定的核心工具集 |
|
|
88
|
+
| `chatgpt_direct` | 14 | ChatGPT 直接编辑模式,需 `enableDirectProfile: true` |
|
|
89
|
+
| `chatgpt_search` | 5 | 动态工具发现场景(discover/explain/invoke) |
|
|
90
|
+
|
|
91
|
+
### 2.4 两种执行模式
|
|
92
|
+
|
|
93
|
+
| 模式 | 流程 |
|
|
94
|
+
| --- | --- |
|
|
95
|
+
| **Agent 委托模式** | ChatGPT 编写计划 → 本地 Agent 执行 → PatchWarden 审计 |
|
|
96
|
+
| **Direct 模式** | ChatGPT 创建 session → 读取/搜索文件 → 应用 JSON 补丁 → 运行白名单验证 → finalize → audit |
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 3. 目录结构
|
|
101
|
+
|
|
102
|
+
```text
|
|
103
|
+
PatchWarden/
|
|
104
|
+
├── src/ # TypeScript 源码
|
|
105
|
+
│ ├── index.ts # stdio MCP Server 入口
|
|
106
|
+
│ ├── httpServer.ts # HTTP MCP Server 入口(127.0.0.1 only)
|
|
107
|
+
│ ├── controlCenter.ts # 本地 Control Center Dashboard
|
|
108
|
+
│ ├── doctor.ts # 只读诊断脚本
|
|
109
|
+
│ ├── config.ts # 配置加载与校验
|
|
110
|
+
│ ├── errors.ts # PatchWardenError 错误模型
|
|
111
|
+
│ ├── logging.ts # 审计日志
|
|
112
|
+
│ ├── version.ts # 版本与 Schema Epoch
|
|
113
|
+
│ ├── taskRuntime.ts # runtime.json 状态读写
|
|
114
|
+
│ ├── taskProgress.ts # progress.md 生成
|
|
115
|
+
│ ├── watcherStatus.ts # Watcher 心跳状态
|
|
116
|
+
│ ├── smoke-test.ts # 烟雾测试入口
|
|
117
|
+
│ ├── agents/ # Agent 路由
|
|
118
|
+
│ │ └── agentRouter.ts
|
|
119
|
+
│ ├── assessments/ # 风险评估
|
|
120
|
+
│ │ ├── agentAssessor.ts
|
|
121
|
+
│ │ ├── assessmentStore.ts
|
|
122
|
+
│ │ └── confirmCli.ts
|
|
123
|
+
│ ├── direct/ # Direct 直接编辑模式
|
|
124
|
+
│ │ ├── directSessionStore.ts
|
|
125
|
+
│ │ ├── directGuards.ts
|
|
126
|
+
│ │ ├── directPatch.ts
|
|
127
|
+
│ │ ├── directAudit.ts
|
|
128
|
+
│ │ └── directVerification.ts
|
|
129
|
+
│ ├── goal/ # Goal Session 多任务编排
|
|
130
|
+
│ │ ├── goalStore.ts
|
|
131
|
+
│ │ ├── goalGraph.ts
|
|
132
|
+
│ │ ├── goalStatus.ts
|
|
133
|
+
│ │ ├── goalProgress.ts
|
|
134
|
+
│ │ ├── goalReport.ts
|
|
135
|
+
│ │ ├── handoffExport.ts
|
|
136
|
+
│ │ ├── specKitImport.ts
|
|
137
|
+
│ │ ├── subgoalSync.ts
|
|
138
|
+
│ │ ├── acceptanceEngine.ts
|
|
139
|
+
│ │ ├── acceptanceTemplate.ts
|
|
140
|
+
│ │ └── worktreeManager.ts
|
|
141
|
+
│ ├── policy/ # 项目级策略
|
|
142
|
+
│ │ └── projectPolicy.ts
|
|
143
|
+
│ ├── release/ # 发布门控
|
|
144
|
+
│ │ └── releaseGate.ts
|
|
145
|
+
│ ├── runner/ # 任务执行核心
|
|
146
|
+
│ │ ├── cli.ts
|
|
147
|
+
│ │ ├── runTask.ts
|
|
148
|
+
│ │ ├── watch.ts
|
|
149
|
+
│ │ ├── agentInvocation.ts
|
|
150
|
+
│ │ ├── changeCapture.ts
|
|
151
|
+
│ │ ├── postTaskCleanup.ts
|
|
152
|
+
│ │ └── simpleProcess.ts
|
|
153
|
+
│ ├── security/ # 纵深防御守卫
|
|
154
|
+
│ │ ├── commandGuard.ts
|
|
155
|
+
│ │ ├── pathGuard.ts
|
|
156
|
+
│ │ ├── sensitiveGuard.ts
|
|
157
|
+
│ │ ├── planGuard.ts
|
|
158
|
+
│ │ ├── riskEngine.ts
|
|
159
|
+
│ │ ├── runtimeGuard.ts
|
|
160
|
+
│ │ ├── contentRedaction.ts
|
|
161
|
+
│ │ ├── toolInvocationGuard.ts
|
|
162
|
+
│ │ └── discoveryTokenStore.ts
|
|
163
|
+
│ ├── tools/ # MCP 工具实现
|
|
164
|
+
│ │ ├── registry.ts # 工具注册中枢
|
|
165
|
+
│ │ ├── toolCatalog.ts # Profile 与 Manifest
|
|
166
|
+
│ │ ├── toolRegistry.ts # 工具元数据
|
|
167
|
+
│ │ ├── toolSearch.ts # 工具搜索
|
|
168
|
+
│ │ ├── createTask.ts
|
|
169
|
+
│ │ ├── runTaskLoop.ts # 安全编排入口
|
|
170
|
+
│ │ ├── taskLineage.ts # 链路记录
|
|
171
|
+
│ │ ├── evidencePack.ts # 证据包导出
|
|
172
|
+
│ │ ├── auditTask.ts # 独立审计
|
|
173
|
+
│ │ ├── safeViews.ts # safe_* 系列摘要
|
|
174
|
+
│ │ ├── healthCheck.ts
|
|
175
|
+
│ │ ├── waitForTask.ts
|
|
176
|
+
│ │ └── ... (50+ 工具文件)
|
|
177
|
+
│ └── test/unit/ # 单元测试
|
|
178
|
+
├── ui/ # Control Center 前端
|
|
179
|
+
│ ├── pages/ # dashboard/tasks/audit 等页面
|
|
180
|
+
│ ├── partials/
|
|
181
|
+
│ └── vendor/ # tailwindcss / lucide
|
|
182
|
+
├── scripts/ # 运维脚本
|
|
183
|
+
│ ├── checks/ # 烟雾测试与 manifest 校验
|
|
184
|
+
│ ├── control/ # PowerShell 进程管理
|
|
185
|
+
│ ├── launchers/ # Windows 一键启动器
|
|
186
|
+
│ ├── mcp/ # MCP 启动包装
|
|
187
|
+
│ └── release/ # 发布打包
|
|
188
|
+
├── docs/ # 文档
|
|
189
|
+
├── examples/ # 配置与 Tunnel 示例
|
|
190
|
+
├── package.json
|
|
191
|
+
├── tsconfig.json
|
|
192
|
+
└── PatchWarden.cmd # Windows 统一控制入口
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## 4. 核心模块职责
|
|
198
|
+
|
|
199
|
+
### 4.1 入口层
|
|
200
|
+
|
|
201
|
+
| 文件 | 职责 |
|
|
202
|
+
| --- | --- |
|
|
203
|
+
| [src/index.ts](../src/index.ts) | stdio MCP Server 入口,加载配置、注册工具、连接 StdioServerTransport |
|
|
204
|
+
| [src/httpServer.ts](../src/httpServer.ts) | HTTP MCP Server,绑定 `127.0.0.1:7331`,每请求独立 MCP 实例,支持 owner token 与 `/admin/tasks/:id/accept` 验收端点 |
|
|
205
|
+
| [src/controlCenter.ts](../src/controlCenter.ts) | 本地 Dashboard HTTP 服务(默认 `127.0.0.1:8090`),服务 `ui/` 静态资源,提供任务/会话/lineage/证据包 JSON API,并代理 `manage-patchwarden.ps1` 管理进程生命周期 |
|
|
206
|
+
| [src/doctor.ts](../src/doctor.ts) | 只读诊断脚本,检查 15+ 项:Node/npm/Git 版本、配置、工作区、路径保护、敏感文件、Agent 命令、工具 Manifest、HTTP 端口、Watcher 目录、构建产物 |
|
|
207
|
+
|
|
208
|
+
### 4.2 配置与基础
|
|
209
|
+
|
|
210
|
+
| 文件 | 职责 |
|
|
211
|
+
| --- | --- |
|
|
212
|
+
| [src/config.ts](../src/config.ts) | 加载并校验 `patchwarden.config.json`,提供 `loadConfig`/`getConfig`/`getTasksDir`/`getPlansDir` 等路径解析;严格校验 `workspaceRoot`、`agents`、`allowedTestCommands`、`watcherStaleSeconds`、`toolProfile` 等字段 |
|
|
213
|
+
| [src/errors.ts](../src/errors.ts) | 定义 `PatchWardenError`(含 `reason`/`suggestion`/`blocked`/`details`)与 `errorPayload` 序列化 |
|
|
214
|
+
| [src/version.ts](../src/version.ts) | 导出 `PATCHWARDEN_VERSION = "1.5.1"` 与 `TOOL_SCHEMA_EPOCH = "2026-07-05-v13"` |
|
|
215
|
+
| [src/logging.ts](../src/logging.ts) | `Logger` 类输出 stderr JSON 日志,记录 `audit`/`info`/`warn`/`error`;`logToolInvocation` 仅写参数 digest,不写原参数;`installGlobalHandlers` 捕获未处理异常但不吞错 |
|
|
216
|
+
|
|
217
|
+
### 4.3 安全模块(src/security/)
|
|
218
|
+
|
|
219
|
+
PatchWarden 的纵深防御核心,所有写操作前都会经过这些守卫。
|
|
220
|
+
|
|
221
|
+
| 文件 | 职责 |
|
|
222
|
+
| --- | --- |
|
|
223
|
+
| [commandGuard.ts](../src/security/commandGuard.ts) | 命令白名单守卫:`guardAgentCommand` 校验 agent 已配置且命令无 shell 元字符;`guardTestCommand` 精确匹配测试白名单;`guardDirectCommand` 校验 Direct 白名单;`sanitizePromptArg` 清洗控制字符 |
|
|
224
|
+
| [pathGuard.ts](../src/security/pathGuard.ts) | 路径横移守卫:`guardPath`/`guardReadPath`/`guardWorkspacePath` 确保路径解析后都在 `workspaceRoot` 内,用 `realpath` 防符号链接逃逸,Windows 下做盘符一致性检查 |
|
|
225
|
+
| [sensitiveGuard.ts](../src/security/sensitiveGuard.ts) | 敏感文件守卫:`isSensitivePath` 匹配 `.env`/SSH 私钥/`credentials`/`.npmrc`/`cookies`/`.kube/config` 等;`.patchwarden/` 前缀豁免 |
|
|
226
|
+
| [planGuard.ts](../src/security/planGuard.ts) | 计划内容守卫:`guardPlanContent` 扫描 plan 文本,拦截"读取密钥/破坏性删除/植入后门"等危险指令,支持中英文否定语境检测 |
|
|
227
|
+
| [riskEngine.ts](../src/security/riskEngine.ts) | 综合风险评估:`assessRisk` 串联各 guard 输出 `risk_level`(low/medium/high)+ `decision`(allow/needs_confirm/blocked)+ `reason_codes`;`collectRiskHints` 仅做关键词提示,不影响决策 |
|
|
228
|
+
| [runtimeGuard.ts](../src/security/runtimeGuard.ts) | 阻止任务把 `repo_path` 指向运行中的 PatchWarden 自身目录(`dist`/`src`/`scripts`/`release`) |
|
|
229
|
+
| [contentRedaction.ts](../src/security/contentRedaction.ts) | 输出脱敏:`redactSensitiveContent`/`redactSensitiveValue` 按正则替换私钥、bearer token、npm token、凭据赋值、已知 token 格式 |
|
|
230
|
+
| [toolInvocationGuard.ts](../src/security/toolInvocationGuard.ts) | `invoke_discovered_tool` 调用前 8 项校验:token 匹配、profile 允许、风险等级、敏感路径、assessment 必需、命令元字符、release 确认、credential 拒绝 |
|
|
231
|
+
| [discoveryTokenStore.ts](../src/security/discoveryTokenStore.ts) | 服务端 discovery token 存储:`issueToken`/`consumeToken`(单次使用)/`peekToken`/`revokeToken`,纯内存、10 分钟 TTL、不持久化 |
|
|
232
|
+
|
|
233
|
+
### 4.4 Runner 模块(src/runner/)
|
|
234
|
+
|
|
235
|
+
任务执行的核心,编排从启动到产出 artifact 的完整生命周期。
|
|
236
|
+
|
|
237
|
+
| 文件 | 职责 |
|
|
238
|
+
| --- | --- |
|
|
239
|
+
| [cli.ts](../src/runner/cli.ts) | Runner 子进程入口,从 argv 或 `PATCHWARDEN_TASK_ID` 读取 taskId 并调用 `runTask` |
|
|
240
|
+
| [runTask.ts](../src/runner/runTask.ts) | **执行主循环**:`runTask(taskId)` 编排 preparing → executing_agent → running_tests → collecting_artifacts → done/failed;管理心跳(2s)、超时、cancel/kill;产出 16+ artifact 文件;区分 `failed_scope_violation`/`failed_policy_violation` |
|
|
241
|
+
| [watch.ts](../src/runner/watch.ts) | 常驻 watcher,每 4 秒轮询 `pending` 任务,执行 pre-flight 安全校验后调用 `runTask`;原子写心跳文件;通过 env 注入 `WATCHER_INSTANCE_ID`/`WATCHER_LAUNCHER_PID` 支持所有权判定 |
|
|
242
|
+
| [agentInvocation.ts](../src/runner/agentInvocation.ts) | 构建 agent 调用参数与 prompt:`buildAgentInvocation`/`buildExecutionPrompt`/`buildAssessmentPrompt`;占位符 `{repo}`/`{prompt}`/`{prompt_file}` 替换 |
|
|
243
|
+
| [changeCapture.ts](../src/runner/changeCapture.ts) | 仓库快照与变更证据:`captureRepoSnapshot` 并行跑 5 个 git 命令;`buildChangeArtifacts` 比对快照生成 diff;`extractExternalDirtyFiles` 建立外部脏文件基线;`buildArtifactManifest` 生成带 sha256 的产物清单 |
|
|
244
|
+
| [postTaskCleanup.ts](../src/runner/postTaskCleanup.ts) | 任务后清理:仅删除未被 git 跟踪且被忽略的临时产物(`__pycache__`/`dist`/`*.pyc`),三道闸门保护受控文件 |
|
|
245
|
+
| [simpleProcess.ts](../src/runner/simpleProcess.ts) | 轻量进程执行器:`runSimpleProcess`/`runSimpleProcessSync`,带输出上限(512KB/128KB)、超时、截断标志,供 `run_verification` 等非任务流程使用 |
|
|
246
|
+
|
|
247
|
+
### 4.5 Tools 模块(src/tools/)
|
|
248
|
+
|
|
249
|
+
MCP 工具实现与注册中枢。
|
|
250
|
+
|
|
251
|
+
| 文件 | 职责 |
|
|
252
|
+
| --- | --- |
|
|
253
|
+
| [registry.ts](../src/tools/registry.ts) | **工具注册中枢**:`getToolDefs` 生成完整工具定义(含 inputSchema);`registerTools` 绑定 `ListToolsRequestSchema`/`CallToolRequestSchema`;`handleToolCall` 分发 60+ 工具调用;保证 list/call 一致性,附 `_meta`(server_version/schema_epoch/tool_manifest_sha256) |
|
|
254
|
+
| [toolCatalog.ts](../src/tools/toolCatalog.ts) | Profile 与 Manifest:`resolveToolProfile`/`selectToolsForProfile` 按 profile 过滤工具;`buildToolCatalogSnapshot` 计算 `tool_manifest_sha256` 用于漂移检测 |
|
|
255
|
+
| [toolRegistry.ts](../src/tools/toolRegistry.ts) | 工具元数据(risk/tags/aliases/profiles/modes) |
|
|
256
|
+
| [toolSearch.ts](../src/tools/toolSearch.ts) | 自然语言工具搜索(中英文) |
|
|
257
|
+
| [createTask.ts](../src/tools/createTask.ts) | `createTask` 任务创建:支持 `plan_id`/`inline_plan`/`template` 三种来源;`assess_only` 模式预评估风险;产出 `task_id` 与 `execution_blocked` 状态 |
|
|
258
|
+
| [runTaskLoop.ts](../src/tools/runTaskLoop.ts) | **安全编排入口**:`runTaskLoop` 组合 create_task → wait_for_task → safe summaries → audit_task,最多 5 轮迭代;支持 worktree 隔离、Direct 验证、自动修复失败测试 |
|
|
259
|
+
| [taskLineage.ts](../src/tools/taskLineage.ts) | 链路记录:`createLineageId`/`writeTaskLineage`/`getTaskLineage`/`toSafeTaskLineage`,写入 `.patchwarden/lineages/<lineage_id>/` |
|
|
260
|
+
| [evidencePack.ts](../src/tools/evidencePack.ts) | 证据包导出:`exportTaskEvidencePack` 写 `evidence.json` + `EVIDENCE.md`,不含 stdout/stderr/full diff/sensitive content |
|
|
261
|
+
| [auditTask.ts](../src/tools/auditTask.ts) | 独立审计:`auditTask` 执行 16+ 确定性检查(status/result/diff/repo_path/package.json/sensitive path/unrecorded command),区分 `confirmed_failures`/`possible_false_positives`/`manual_verification_items` |
|
|
262
|
+
| [safeViews.ts](../src/tools/safeViews.ts) | `safe_*` 系列只读摘要:`safeResult`/`safeAudit`/`safeTestSummary`/`safeDiffSummary`/`safeDirectSummary` 等,返回有界结构化证据 |
|
|
263
|
+
| [healthCheck.ts](../src/tools/healthCheck.ts) | `healthCheck` 返回 MCP catalog 一致性、watcher 心跳、workspace、agents 状态;`self_diagnostic` 模式扩展证据 |
|
|
264
|
+
| [waitForTask.ts](../src/tools/waitForTask.ts) | 长轮询任务(最多 30s),返回 `continuation_required` 或终态 acceptance 证据 |
|
|
265
|
+
| [discoverTools.ts](../src/tools/discoverTools.ts) | 自然语言工具发现,返回压缩摘要与 risk level |
|
|
266
|
+
| [invokeDiscoveredTool.ts](../src/tools/invokeDiscoveredTool.ts) | 凭 discoveryToken 调用工具,强制 10 项安全检查 |
|
|
267
|
+
|
|
268
|
+
### 4.6 Goal 模块(src/goal/)
|
|
269
|
+
|
|
270
|
+
v0.8.0 引入的多任务编排层。
|
|
271
|
+
|
|
272
|
+
| 文件 | 职责 |
|
|
273
|
+
| --- | --- |
|
|
274
|
+
| [goalStore.ts](../src/goal/goalStore.ts) | Goal Session 目录 CRUD:`createGoal`/`listGoals`/`readGoal`/`writeGoalStatus`/`readGoalStatus`;目录结构 `.patchwarden/goals/{goal_id}/` 含 `GOAL.md`/`GOALS.md`/`goal_status.json`/`tasks/`/`artifacts/` |
|
|
275
|
+
| [goalGraph.ts](../src/goal/goalGraph.ts) | 依赖图:`suggestNextSubgoal` 返回依赖已满足的下一个子目标 |
|
|
276
|
+
| [goalStatus.ts](../src/goal/goalStatus.ts) | `GoalStatus`/`Subgoal` 类型与 `createInitialGoalStatus` |
|
|
277
|
+
| [goalProgress.ts](../src/goal/goalProgress.ts) | `acceptSubgoal`/`rejectSubgoal`/`summarizeGoalProgress` |
|
|
278
|
+
| [goalReport.ts](../src/goal/goalReport.ts) | `exportGoalReport` 导出结构化最终报告 |
|
|
279
|
+
| [handoffExport.ts](../src/goal/handoffExport.ts) | `exportHandoff` 导出 `handoff.md` 用于会话交接 |
|
|
280
|
+
| [specKitImport.ts](../src/goal/specKitImport.ts) | `parseSpecKitJson`/`importSpecKitTasks` 导入 Spec Kit 任务 |
|
|
281
|
+
| [subgoalSync.ts](../src/goal/subgoalSync.ts) | 子目标与任务关联同步 |
|
|
282
|
+
| [acceptanceEngine.ts](../src/goal/acceptanceEngine.ts) | 验收引擎 |
|
|
283
|
+
| [worktreeManager.ts](../src/goal/worktreeManager.ts) | `createWorktree`/`mergeWorktree`/`discardWorktree` 管理 git worktree 隔离 |
|
|
284
|
+
|
|
285
|
+
### 4.7 Direct 模块(src/direct/)
|
|
286
|
+
|
|
287
|
+
v0.6.0 引入的 ChatGPT 直接编辑模式。
|
|
288
|
+
|
|
289
|
+
| 文件 | 职责 |
|
|
290
|
+
| --- | --- |
|
|
291
|
+
| [directSessionStore.ts](../src/direct/directSessionStore.ts) | Direct Session CRUD:`createDirectSession`/`readDirectSession`/`updateDirectSession`/`finalizeDirectSessionRecord`;记录 operations/verification_runs;`computeWorkspaceFingerprint` |
|
|
292
|
+
| [directGuards.ts](../src/direct/directGuards.ts) | Direct 守卫:`guardDirectSessionActive`/`guardDirectSessionFinalized`/`guardDirectPath`/`guardDirectReadPath`/`guardDirectWritePath`/`guardDirectPatchSize`/`isBinaryFile` |
|
|
293
|
+
| [directPatch.ts](../src/direct/directPatch.ts) | JSON patch 应用:支持 `replace_exact`/`insert_before`/`insert_after`/`replace_whole_file`,校验 `expected_sha256` |
|
|
294
|
+
| [directAudit.ts](../src/direct/directAudit.ts) | 16 项确定性审计,返回 pass/warn/fail |
|
|
295
|
+
| [directVerification.ts](../src/direct/directVerification.ts) | 白名单验证命令执行 |
|
|
296
|
+
|
|
297
|
+
### 4.8 其他模块
|
|
298
|
+
|
|
299
|
+
| 文件 | 职责 |
|
|
300
|
+
| --- | --- |
|
|
301
|
+
| [src/agents/agentRouter.ts](../src/agents/agentRouter.ts) | Agent 路由:`routeAgent` 按 scope 文件数与关键词推荐 agent(largeScope→opencode、singleFile→direct、audit→patchwarden-audit、refactor→codex、documentation→claude) |
|
|
302
|
+
| [src/policy/projectPolicy.ts](../src/policy/projectPolicy.ts) | 仓库级策略:`getProjectPolicySummary` 解析 `.patchwarden/project-policy.json`;`commandAllowedByProjectPolicy`/`isProtectedByProjectPolicy`;含 `DANGEROUS_COMMAND_RE` 防护 |
|
|
303
|
+
| [src/release/releaseGate.ts](../src/release/releaseGate.ts) | v1.0.0 五阶段发布门:`local_ready` → `packed_ready` → `published_verified` → `github_release_verified` → `ci_verified`;远程阶段仅用 `node:https` GET,网络错误返回 `not_checked` |
|
|
304
|
+
| [src/assessments/agentAssessor.ts](../src/assessments/agentAssessor.ts) | `runAgentAssessment` 调用 agent 执行只读风险评估,输出 `===ASSESSMENT_JSON===` 标记后的结构化结果 |
|
|
305
|
+
| [src/assessments/assessmentStore.ts](../src/assessments/assessmentStore.ts) | Assessment 记录存储与 freshness 校验 |
|
|
306
|
+
| [src/taskRuntime.ts](../src/taskRuntime.ts) | `runtime.json` 浅合并读写,含 v0.7.0 PID 重用与孤儿任务检测字段 |
|
|
307
|
+
| [src/taskProgress.ts](../src/taskProgress.ts) | `progress.md` 生成,6 阶段标记(`[x]`/`[>]`/`[ ]`) |
|
|
308
|
+
| [src/watcherStatus.ts](../src/watcherStatus.ts) | `readWatcherStatus` 心跳读取 + task heartbeat fallback + watcher ownership 检测 |
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## 5. 关键类与函数说明
|
|
313
|
+
|
|
314
|
+
### 5.1 核心类型
|
|
315
|
+
|
|
316
|
+
#### `PatchWardenConfig`([src/config.ts](../src/config.ts))
|
|
317
|
+
|
|
318
|
+
```typescript
|
|
319
|
+
interface PatchWardenConfig {
|
|
320
|
+
workspaceRoot: string; // 工作区根目录(唯一允许访问)
|
|
321
|
+
plansDir: string; // 计划目录,相对 workspaceRoot
|
|
322
|
+
tasksDir: string; // 任务目录,相对 workspaceRoot
|
|
323
|
+
assessmentsDir: string; // 评估目录
|
|
324
|
+
assessmentTtlSeconds: number; // 评估 TTL(60-86400)
|
|
325
|
+
agents: Record<string, AgentConfig>; // Agent 白名单
|
|
326
|
+
allowedTestCommands: string[]; // 全局测试命令白名单(精确匹配)
|
|
327
|
+
repoAllowedTestCommands?: Record<string, string[]>; // 仓库专属命令
|
|
328
|
+
maxReadFileBytes: number; // 单次文件读取上限
|
|
329
|
+
defaultTaskTimeoutSeconds: number; // 默认任务超时
|
|
330
|
+
maxTaskTimeoutSeconds: number; // 最大任务超时
|
|
331
|
+
watcherStaleSeconds: number; // Watcher 心跳过期阈值(5-3600)
|
|
332
|
+
toolProfile?: "full" | "chatgpt_core" | "chatgpt_direct" | "chatgpt_search";
|
|
333
|
+
enableDirectProfile?: boolean; // 是否启用 Direct 模式
|
|
334
|
+
directSessionsDir: string;
|
|
335
|
+
directSessionTtlSeconds: number;
|
|
336
|
+
directMaxPatchBytes: number;
|
|
337
|
+
directMaxFileBytes: number;
|
|
338
|
+
directAllowedCommands?: string[];
|
|
339
|
+
repoDirectAllowedCommands?: Record<string, string[]>;
|
|
340
|
+
// ... 其他可选字段
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
#### `TaskStatus`([src/tools/createTask.ts](../src/tools/createTask.ts))
|
|
345
|
+
|
|
346
|
+
```typescript
|
|
347
|
+
type TaskStatus =
|
|
348
|
+
| "pending" | "running" | "collecting_artifacts"
|
|
349
|
+
| "done_by_agent" // agent 自报完成,待验收
|
|
350
|
+
| "accepted" | "rejected" | "needs_fix" | "blocked" // v0.7.2 验收状态
|
|
351
|
+
| "done" // legacy 终态
|
|
352
|
+
| "failed" | "failed_verification"
|
|
353
|
+
| "failed_scope_violation" | "failed_policy_violation"
|
|
354
|
+
| "failed_stale" | "orphaned" // v0.7.0 进程死亡/孤儿
|
|
355
|
+
| "canceled";
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### `PatchWardenError`([src/errors.ts](../src/errors.ts))
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
class PatchWardenError extends Error {
|
|
362
|
+
constructor(
|
|
363
|
+
public readonly reason: string, // 机器可读的错误码,如 "workspace_path_escape"
|
|
364
|
+
message: string, // 人类可读描述
|
|
365
|
+
public readonly suggestion: string, // 修复建议
|
|
366
|
+
public readonly blocked = true, // 是否阻断操作
|
|
367
|
+
public readonly details: Record<string, unknown> = {}
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
#### `ToolCatalogSnapshot`([src/tools/toolCatalog.ts](../src/tools/toolCatalog.ts))
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
interface ToolCatalogSnapshot {
|
|
376
|
+
server_version: string; // PATCHWARDEN_VERSION
|
|
377
|
+
schema_epoch: string; // TOOL_SCHEMA_EPOCH
|
|
378
|
+
tool_profile: ToolProfile;
|
|
379
|
+
tool_count: number;
|
|
380
|
+
tool_names: string[];
|
|
381
|
+
tool_manifest_sha256: string; // 工具清单哈希,用于漂移检测
|
|
382
|
+
}
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### 5.2 核心函数
|
|
386
|
+
|
|
387
|
+
#### 配置加载
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
// src/config.ts
|
|
391
|
+
function loadConfig(configPath?: string): PatchWardenConfig; // 单例加载
|
|
392
|
+
function reloadConfig(configPath?: string): PatchWardenConfig; // 强制重载
|
|
393
|
+
function getConfig(): PatchWardenConfig;
|
|
394
|
+
function getTasksDir(config: PatchWardenConfig): string;
|
|
395
|
+
function getPlansDir(config: PatchWardenConfig): string;
|
|
396
|
+
function getRepoAllowedTestCommands(config, repoPath): string[];
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
#### 安全守卫
|
|
400
|
+
|
|
401
|
+
```typescript
|
|
402
|
+
// src/security/commandGuard.ts
|
|
403
|
+
function guardAgentCommand(agent: string, config: PatchWardenConfig): AllowedCommand;
|
|
404
|
+
function guardTestCommand(testCommand: string, config, repoPath?): string;
|
|
405
|
+
function guardDirectCommand(command: string, config, repoPath?): string;
|
|
406
|
+
function sanitizePromptArg(prompt: string): string;
|
|
407
|
+
|
|
408
|
+
// src/security/pathGuard.ts
|
|
409
|
+
function guardPath(requestedPath, workspaceRoot, allowedPrefix?): string;
|
|
410
|
+
function guardReadPath(requestedPath, workspaceRoot, allowedPrefix?): string;
|
|
411
|
+
function guardWorkspacePath(inputPath, workspaceRoot): string; // 用于 repo_path
|
|
412
|
+
|
|
413
|
+
// src/security/sensitiveGuard.ts
|
|
414
|
+
function isSensitivePath(filePath: string): boolean;
|
|
415
|
+
function guardSensitivePath(filePath: string): void;
|
|
416
|
+
|
|
417
|
+
// src/security/planGuard.ts
|
|
418
|
+
function guardPlanContent(title: string, content: string): void;
|
|
419
|
+
|
|
420
|
+
// src/security/riskEngine.ts
|
|
421
|
+
function assessRisk(input: RiskAssessmentInput): RiskAssessmentResult;
|
|
422
|
+
function collectRiskHints(input: RiskAssessmentInput): string[];
|
|
423
|
+
|
|
424
|
+
// src/security/contentRedaction.ts
|
|
425
|
+
function redactSensitiveContent(input: string): RedactionResult;
|
|
426
|
+
function redactSensitiveValue<T>(input: T): StructuredRedactionResult<T>;
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
#### 任务执行
|
|
430
|
+
|
|
431
|
+
```typescript
|
|
432
|
+
// src/runner/runTask.ts
|
|
433
|
+
async function runTask(taskId: string): Promise<TaskRunResult>;
|
|
434
|
+
// 编排完整生命周期,产出 16+ artifact
|
|
435
|
+
|
|
436
|
+
// src/runner/watch.ts(脚本入口,无导出)
|
|
437
|
+
// 每 4 秒轮询 pending 任务,pre-flight 校验后调用 runTask
|
|
438
|
+
|
|
439
|
+
// src/runner/changeCapture.ts
|
|
440
|
+
async function captureRepoSnapshot(repoPath: string): Promise<RepoSnapshot>;
|
|
441
|
+
async function buildChangeArtifacts(repoPath, before, after): Promise<ChangeArtifacts>;
|
|
442
|
+
function extractExternalDirtyFiles(snapshot, repoPath, workspaceRoot): ExternalDirtyFile[];
|
|
443
|
+
function findNewExternalDirtyFiles(baseline, current): ExternalDirtyFile[];
|
|
444
|
+
async function buildArtifactManifest(changedFiles, repoPath, taskId?): Promise<ArtifactManifest>;
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
#### MCP 工具
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
// src/tools/registry.ts
|
|
451
|
+
function getToolDefs(): ToolDef[]; // 生成完整工具定义
|
|
452
|
+
function registerTools(server: Server): void; // 绑定到 MCP Server
|
|
453
|
+
async function handleToolCall(name: string, args?): Promise<{ content }>;
|
|
454
|
+
function getToolCatalogSnapshot(): ToolCatalogSnapshot;
|
|
455
|
+
|
|
456
|
+
// src/tools/createTask.ts
|
|
457
|
+
async function createTask(input: CreateTaskInput): Promise<CreateTaskResult>;
|
|
458
|
+
// 支持 assess_only 预评估与 execute 执行
|
|
459
|
+
|
|
460
|
+
// src/tools/runTaskLoop.ts
|
|
461
|
+
async function runTaskLoop(input: RunTaskLoopInput): Promise<RunTaskLoopOutput>;
|
|
462
|
+
// 安全编排入口,最多 5 轮迭代
|
|
463
|
+
|
|
464
|
+
// src/tools/auditTask.ts
|
|
465
|
+
function auditTask(taskId: string): AuditTaskOutput;
|
|
466
|
+
// 16+ 确定性检查,区分 confirmed_failures/possible_false_positives
|
|
467
|
+
|
|
468
|
+
// src/tools/waitForTask.ts
|
|
469
|
+
async function waitForTask(taskId: string, waitSeconds?: number): Promise<WaitResult>;
|
|
470
|
+
// 长轮询,返回 continuation_required 或终态证据
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
#### Goal Session
|
|
474
|
+
|
|
475
|
+
```typescript
|
|
476
|
+
// src/goal/goalStore.ts
|
|
477
|
+
function createGoal(repoPath, title, description, workspaceRoot?): { goal_id, goal_dir };
|
|
478
|
+
function listGoals(workspaceRoot?): GoalSummary[];
|
|
479
|
+
function readGoal(goalId, workspaceRoot?): GoalDetail;
|
|
480
|
+
function writeGoalStatus(goalId, status, workspaceRoot?): void;
|
|
481
|
+
function readGoalStatus(goalId, workspaceRoot?): GoalStatus;
|
|
482
|
+
function generateGoalId(title: string, existingIds: string[]): string; // goal_{YYYYMMDD}_{slug}
|
|
483
|
+
|
|
484
|
+
// src/goal/goalGraph.ts
|
|
485
|
+
function suggestNextSubgoal(goalStatus: GoalStatus): SubgoalSuggestion;
|
|
486
|
+
|
|
487
|
+
// src/goal/worktreeManager.ts
|
|
488
|
+
function createWorktree(repoPath, baseBranch?, workspaceRoot?): WorktreeInfo;
|
|
489
|
+
function mergeWorktree(worktreeId, repoPath): MergeResult;
|
|
490
|
+
function discardWorktree(worktreeId, repoPath): DiscardResult;
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
#### Direct Session
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
// src/direct/directSessionStore.ts
|
|
497
|
+
function generateDirectSessionId(): string; // ds_{YYYYMMDD}_{randomHex}
|
|
498
|
+
function createDirectSession(input: DirectSessionCreateInput): Promise<DirectSessionRecord>;
|
|
499
|
+
function readDirectSession(sessionId: string): DirectSessionRecord;
|
|
500
|
+
function updateDirectSession(sessionId, patch): void;
|
|
501
|
+
function appendDirectSessionOperation(sessionId, operation): void;
|
|
502
|
+
function finalizeDirectSessionRecord(sessionId, artifacts): DirectSessionRecord;
|
|
503
|
+
function validateDirectSessionFreshness(session): DirectSessionValidationResult;
|
|
504
|
+
|
|
505
|
+
// src/direct/directGuards.ts
|
|
506
|
+
function guardDirectSessionActive(session: DirectSessionRecord): void;
|
|
507
|
+
function guardDirectPath(session, requestedPath, allowSensitive): string;
|
|
508
|
+
function guardDirectReadPath(session, requestedPath): string;
|
|
509
|
+
function guardDirectWritePath(session, requestedPath): string;
|
|
510
|
+
function guardDirectPatchSize(patchBytes: number): void;
|
|
511
|
+
function isBinaryFile(filePath: string): boolean;
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
#### Discovery Token
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
// src/security/discoveryTokenStore.ts
|
|
518
|
+
function issueToken(input: IssueTokenInput): string; // dst_{YYYYMMDD}_{randomHex12}
|
|
519
|
+
function consumeToken(tokenId: string): DiscoveryTokenRecord; // 单次使用,消费后删除
|
|
520
|
+
function peekToken(tokenId: string): DiscoveryTokenRecord | null;
|
|
521
|
+
function revokeToken(tokenId: string): boolean;
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## 6. 数据流与状态机
|
|
527
|
+
|
|
528
|
+
### 6.1 标准任务工作流
|
|
529
|
+
|
|
530
|
+
```text
|
|
531
|
+
1. health_check → 确认版本、工作区、Watcher、工具目录
|
|
532
|
+
2. list_agents → 确认本地 Agent 命令可用
|
|
533
|
+
3. list_workspace → 确定 repo_path
|
|
534
|
+
4. save_plan → 保存计划(或使用 inline_plan/template)
|
|
535
|
+
5. create_task → 明确 Agent、仓库、验证命令
|
|
536
|
+
6. wait_for_task → 短任务用 timeout_seconds:25;长任务用 list_tasks 轮询
|
|
537
|
+
7. get_task_summary(compact) → 先看有界结构化总结
|
|
538
|
+
8. get_result_json / get_diff / get_test_log → 按需查看细节
|
|
539
|
+
9. audit_task → 独立核对执行结果
|
|
540
|
+
10. 人工决定接受/提交/发布
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### 6.2 任务状态机
|
|
544
|
+
|
|
545
|
+
```text
|
|
546
|
+
pending ──(Watcher 拉取)──▶ running ──(agent 退出)──▶ collecting_artifacts
|
|
547
|
+
│
|
|
548
|
+
┌───────────────────────────────┤
|
|
549
|
+
▼ ▼
|
|
550
|
+
done_by_agent failed / failed_verification
|
|
551
|
+
│ │
|
|
552
|
+
┌───────────────┼───────────────┐ │
|
|
553
|
+
▼ ▼ ▼ ▼
|
|
554
|
+
accepted rejected needs_fix failed_scope_violation
|
|
555
|
+
failed_policy_violation
|
|
556
|
+
failed_stale / orphaned
|
|
557
|
+
canceled
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### 6.3 任务产物
|
|
561
|
+
|
|
562
|
+
| 文件 | 用途 |
|
|
563
|
+
| --- | --- |
|
|
564
|
+
| `status.json` | 当前状态、阶段、心跳和错误信息 |
|
|
565
|
+
| `progress.md` | Agent 写入的进度记录 |
|
|
566
|
+
| `result.md` | 人类可读的执行报告 |
|
|
567
|
+
| `result.json` | 结构化结果、路径、变更、警告和后续建议 |
|
|
568
|
+
| `diff.patch` | 完整任务差异证据 |
|
|
569
|
+
| `artifact_manifest.json` | 构建或发布产物的路径、类型、大小与 SHA-256 |
|
|
570
|
+
| `file-stats.json` | 文件级增删统计 |
|
|
571
|
+
| `verify.json` | 每条独立验证命令的结构化记录 |
|
|
572
|
+
| `verify.log` | 独立验证的可读日志 |
|
|
573
|
+
| `test.log` | Agent 执行过程中产生的测试输出 |
|
|
574
|
+
| `git-before.json` / `git-after.json` | 任务前后仓库快照 |
|
|
575
|
+
| `changed-files.json` | 变更文件列表 |
|
|
576
|
+
| `independent-review.md` | `audit_task` 写入的独立审计报告 |
|
|
577
|
+
| `runtime.json` | 子进程 PID、心跳、deadline |
|
|
578
|
+
| `error.log` | 错误日志 |
|
|
579
|
+
| `post-task-cleanup.json` | 清理报告 |
|
|
580
|
+
|
|
581
|
+
### 6.4 run_task_loop 编排流
|
|
582
|
+
|
|
583
|
+
`run_task_loop` 是 v1.2 引入的安全编排入口,它只组合现有工具,不绕过任何守卫:
|
|
584
|
+
|
|
585
|
+
```text
|
|
586
|
+
runTaskLoop(input)
|
|
587
|
+
│
|
|
588
|
+
├─ guardWorkspacePath(repo_path)
|
|
589
|
+
├─ resolveAgentRouting(agent="auto" → recommendAgentForTask)
|
|
590
|
+
├─ createLineageId + 初始化 lineage 记录
|
|
591
|
+
│
|
|
592
|
+
└─ for round in 1..max_iterations:
|
|
593
|
+
├─ create_task(template, goal, verify_commands, agent)
|
|
594
|
+
├─ waitForTask(task_id, timeout)
|
|
595
|
+
├─ safeResult + safeTestSummary + safeAudit
|
|
596
|
+
│
|
|
597
|
+
├─ if high_risk && stop_on_high_risk → break
|
|
598
|
+
├─ if failed_verification && auto_fix_tests → 下一轮用 fix_tests 模板
|
|
599
|
+
├─ if done_by_agent/accepted → break
|
|
600
|
+
└─ writeTaskLineage(round_record)
|
|
601
|
+
│
|
|
602
|
+
├─ if direct_verify: createDirectSession → runDirectVerificationBundle → safeFinalize → safeAudit
|
|
603
|
+
└─ writeTaskLineage(final) → 返回 SafeTaskLineage
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
## 7. 依赖关系
|
|
609
|
+
|
|
610
|
+
### 7.1 外部依赖
|
|
611
|
+
|
|
612
|
+
```json
|
|
613
|
+
{
|
|
614
|
+
"dependencies": {
|
|
615
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
616
|
+
},
|
|
617
|
+
"devDependencies": {
|
|
618
|
+
"@types/node": "^20.0.0",
|
|
619
|
+
"typescript": "^6.0.3"
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
**运行时仅依赖 MCP SDK**,所有其他功能使用 Node.js 内置模块:
|
|
625
|
+
|
|
626
|
+
- `node:fs` / `node:path` / `node:crypto` / `node:http` / `node:child_process` / `node:os` / `node:url` / `node:net` / `node:timers/promises`
|
|
627
|
+
|
|
628
|
+
### 7.2 模块依赖图(简化)
|
|
629
|
+
|
|
630
|
+
```text
|
|
631
|
+
index.ts / httpServer.ts
|
|
632
|
+
│
|
|
633
|
+
▼
|
|
634
|
+
tools/registry.ts ──────────┬── tools/createTask.ts
|
|
635
|
+
│ ├── tools/runTaskLoop.ts
|
|
636
|
+
│ ├── tools/auditTask.ts
|
|
637
|
+
│ ├── tools/safeViews.ts
|
|
638
|
+
│ ├── tools/taskLineage.ts
|
|
639
|
+
│ ├── tools/evidencePack.ts
|
|
640
|
+
│ ├── direct/* (Direct 工具)
|
|
641
|
+
│ ├── goal/* (Goal 工具)
|
|
642
|
+
│ └── release/releaseGate.ts
|
|
643
|
+
│
|
|
644
|
+
▼
|
|
645
|
+
config.ts ──── security/* (所有守卫)
|
|
646
|
+
│
|
|
647
|
+
▼
|
|
648
|
+
runner/watch.ts ──▶ runner/runTask.ts ──▶ runner/changeCapture.ts
|
|
649
|
+
├── runner/agentInvocation.ts
|
|
650
|
+
├── runner/postTaskCleanup.ts
|
|
651
|
+
└── runner/simpleProcess.ts
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
### 7.3 关键依赖关系
|
|
655
|
+
|
|
656
|
+
- **所有写操作** → 必须经 `security/*` 守卫
|
|
657
|
+
- **`createTask`** → `riskEngine.assessRisk` → `pathGuard` + `commandGuard` + `planGuard` + `runtimeGuard` + `sensitiveGuard`
|
|
658
|
+
- **`runTask`** → `agentInvocation.buildAgentInvocation` → `commandGuard.guardAgentCommand`
|
|
659
|
+
- **`runTask`** → `changeCapture.captureRepoSnapshot` + `buildChangeArtifacts`
|
|
660
|
+
- **`runTaskLoop`** → 组合 `createTask` + `waitForTask` + `safeViews` + `auditTask`,不直接调用 `runTask`
|
|
661
|
+
- **`watch.ts`** → pre-flight 调用 `guardWorkspacePath` + `guardAgentCommand` + `guardTestCommand` 后才调用 `runTask`
|
|
662
|
+
- **`invokeDiscoveredTool`** → `discoveryTokenStore.consumeToken` + `toolInvocationGuard.checkInvocation` + 实际 handler 内二次校验
|
|
663
|
+
|
|
664
|
+
---
|
|
665
|
+
|
|
666
|
+
## 8. 项目运行方式
|
|
667
|
+
|
|
668
|
+
### 8.1 环境要求
|
|
669
|
+
|
|
670
|
+
- Node.js ≥ 18
|
|
671
|
+
- npm
|
|
672
|
+
- Git(可选,但无 Git 无法生成可靠 `git.diff`)
|
|
673
|
+
- 至少一个本地编程 Agent(OpenCode 或 Codex CLI)
|
|
674
|
+
- Windows Tunnel 模式还需 `tunnel-client.exe`、Tunnel ID、运行时 API Key
|
|
675
|
+
|
|
676
|
+
### 8.2 从源码运行(推荐)
|
|
677
|
+
|
|
678
|
+
```powershell
|
|
679
|
+
git clone https://github.com/jiezeng2004-design/PatchWarden.git
|
|
680
|
+
cd .\PatchWarden
|
|
681
|
+
npm.cmd ci
|
|
682
|
+
npm.cmd run build
|
|
683
|
+
Copy-Item .\examples\config.example.json .\patchwarden.config.json
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
编辑 `patchwarden.config.json`,至少修改 `workspaceRoot`、`agents`、`allowedTestCommands`。
|
|
687
|
+
|
|
688
|
+
### 8.3 配置文件
|
|
689
|
+
|
|
690
|
+
配置路径通过 `PATCHWARDEN_CONFIG` 环境变量指定:
|
|
691
|
+
|
|
692
|
+
```powershell
|
|
693
|
+
$env:PATCHWARDEN_CONFIG = "D:\path\to\patchwarden.config.json"
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
查找顺序:
|
|
697
|
+
1. `PATCHWARDEN_CONFIG` 环境变量指定的路径
|
|
698
|
+
2. `{cwd}/patchwarden.config.json`
|
|
699
|
+
3. `{cwd}/.patchwarden.json`
|
|
700
|
+
|
|
701
|
+
最小配置示例:
|
|
702
|
+
|
|
703
|
+
```json
|
|
704
|
+
{
|
|
705
|
+
"workspaceRoot": "D:/ai_agent/codex_program",
|
|
706
|
+
"plansDir": ".patchwarden/plans",
|
|
707
|
+
"tasksDir": ".patchwarden/tasks",
|
|
708
|
+
"toolProfile": "full",
|
|
709
|
+
"agents": {
|
|
710
|
+
"opencode": { "command": "opencode", "args": ["run", "{prompt}"] },
|
|
711
|
+
"codex": { "command": "codex", "args": ["exec", "--cd", "{repo}", "{prompt}"] }
|
|
712
|
+
},
|
|
713
|
+
"allowedTestCommands": ["npm test", "npm run build", "npm run lint", "pytest"],
|
|
714
|
+
"maxReadFileBytes": 200000,
|
|
715
|
+
"defaultTaskTimeoutSeconds": 900,
|
|
716
|
+
"maxTaskTimeoutSeconds": 3600,
|
|
717
|
+
"watcherStaleSeconds": 30,
|
|
718
|
+
"httpPort": 7331
|
|
719
|
+
}
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### 8.4 核心命令
|
|
723
|
+
|
|
724
|
+
| 命令 | 用途 |
|
|
725
|
+
| --- | --- |
|
|
726
|
+
| `npm.cmd run build` | TypeScript 编译到 `dist/` |
|
|
727
|
+
| `npm.cmd run doctor` | 只读诊断(检查 15+ 项) |
|
|
728
|
+
| `npm.cmd run doctor:ci` | CI 诊断(允许默认配置) |
|
|
729
|
+
| `npm.cmd run watch` | 启动 Watcher(轮询 pending 任务) |
|
|
730
|
+
| `npm.cmd start` | 启动 stdio MCP Server |
|
|
731
|
+
| `npm.cmd run start:http` | 启动 HTTP MCP Server(127.0.0.1:7331) |
|
|
732
|
+
| `npm.cmd run start:control` | 启动 Control Center Dashboard(127.0.0.1:8090) |
|
|
733
|
+
| `npm.cmd test` | 完整测试链(smoke + unit + lifecycle + doctor + tunnel + watcher + control + mcp + brand) |
|
|
734
|
+
| `npm.cmd run test:mcp` | MCP 烟雾测试 |
|
|
735
|
+
| `npm.cmd run test:http-mcp` | HTTP MCP 烟雾测试 |
|
|
736
|
+
| `npm.cmd run pack:clean` | 打包清理 |
|
|
737
|
+
| `npm.cmd run verify:package` | 包清单校验 |
|
|
738
|
+
|
|
739
|
+
### 8.5 启动顺序
|
|
740
|
+
|
|
741
|
+
完整链路需要三个独立进程:
|
|
742
|
+
|
|
743
|
+
**终端 1 — Watcher**:
|
|
744
|
+
|
|
745
|
+
```powershell
|
|
746
|
+
$env:PATCHWARDEN_CONFIG = (Resolve-Path .\patchwarden.config.json)
|
|
747
|
+
npm.cmd run watch
|
|
748
|
+
```
|
|
749
|
+
|
|
750
|
+
**终端 2 — MCP Server**(stdio 或 HTTP 二选一):
|
|
751
|
+
|
|
752
|
+
```powershell
|
|
753
|
+
# stdio(供 OpenCode/Codex 直接连)
|
|
754
|
+
$env:PATCHWARDEN_CONFIG = (Resolve-Path .\patchwarden.config.json)
|
|
755
|
+
npm.cmd start
|
|
756
|
+
|
|
757
|
+
# 或 HTTP(供 Tunnel 或远程客户端)
|
|
758
|
+
npm.cmd run start:http
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
**终端 3 — Control Center**(可选):
|
|
762
|
+
|
|
763
|
+
```powershell
|
|
764
|
+
npm.cmd run start:control
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
### 8.6 Windows 一键启动
|
|
768
|
+
|
|
769
|
+
```text
|
|
770
|
+
PatchWarden.cmd start core # 启动 Core Agent 模式(chatgpt_core + Watcher + Tunnel)
|
|
771
|
+
PatchWarden.cmd start direct # 启动 Direct 模式(chatgpt_direct + Tunnel,无 Watcher)
|
|
772
|
+
PatchWarden.cmd stop all # 停止所有受控进程
|
|
773
|
+
PatchWarden.cmd restart all # 重启所有受控进程
|
|
774
|
+
PatchWarden.cmd status all # 查看运行状态
|
|
775
|
+
PatchWarden.cmd health # 深度健康检查
|
|
776
|
+
PatchWarden.cmd kill all # 强制清理
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
### 8.7 MCP 客户端接入
|
|
780
|
+
|
|
781
|
+
**OpenCode**(`%USERPROFILE%\.config\opencode\opencode.jsonc`):
|
|
782
|
+
|
|
783
|
+
```jsonc
|
|
784
|
+
{
|
|
785
|
+
"mcp": {
|
|
786
|
+
"patchwarden": {
|
|
787
|
+
"type": "local",
|
|
788
|
+
"command": ["node", "D:/path/to/PatchWarden/dist/index.js"],
|
|
789
|
+
"environment": {
|
|
790
|
+
"PATCHWARDEN_CONFIG": "D:/path/to/PatchWarden/patchwarden.config.json",
|
|
791
|
+
"PATCHWARDEN_TOOL_PROFILE": "full"
|
|
792
|
+
},
|
|
793
|
+
"enabled": true
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
**Codex**(`%USERPROFILE%\.codex\config.toml`):
|
|
800
|
+
|
|
801
|
+
```toml
|
|
802
|
+
[mcp_servers.patchwarden]
|
|
803
|
+
command = "node"
|
|
804
|
+
args = ["D:\\path\\to\\PatchWarden\\dist\\index.js"]
|
|
805
|
+
|
|
806
|
+
[mcp_servers.patchwarden.env]
|
|
807
|
+
PATCHWARDEN_CONFIG = "D:\\path\\to\\patchwarden.config.json"
|
|
808
|
+
PATCHWARDEN_TOOL_PROFILE = "full"
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### 8.8 HTTP MCP 端点
|
|
812
|
+
|
|
813
|
+
| 端点 | 方法 | 用途 |
|
|
814
|
+
| --- | --- | --- |
|
|
815
|
+
| `/mcp` | POST | MCP 请求(需 owner token) |
|
|
816
|
+
| `/healthz` | GET | 健康检查 |
|
|
817
|
+
| `/readyz` | GET | 就绪检查(不就绪返回 503) |
|
|
818
|
+
| `/admin/tasks/:id/accept` | POST | 人工接受任务 |
|
|
819
|
+
| `/admin/tasks/:id/reject` | POST | 人工拒绝任务 |
|
|
820
|
+
| `/admin/tasks/:id/acceptance` | GET | 读取验收状态 |
|
|
821
|
+
|
|
822
|
+
---
|
|
823
|
+
|
|
824
|
+
## 9. 安全设计
|
|
825
|
+
|
|
826
|
+
### 9.1 安全分层
|
|
827
|
+
|
|
828
|
+
```text
|
|
829
|
+
┌─────────────────────────────────────────────────┐
|
|
830
|
+
│ MCP 客户端(ChatGPT/Codex/OpenCode) │ ← 模型指令被视为不可信输入
|
|
831
|
+
├─────────────────────────────────────────────────┤
|
|
832
|
+
│ tools/registry.ts │ ← 工具注册 + Profile 过滤
|
|
833
|
+
│ toolInvocationGuard (8 项调用前校验) │
|
|
834
|
+
├─────────────────────────────────────────────────┤
|
|
835
|
+
│ security/pathGuard ← 路径横移防护 │
|
|
836
|
+
│ security/commandGuard ← 命令白名单 │
|
|
837
|
+
│ security/sensitiveGuard ← 敏感文件阻断 │
|
|
838
|
+
│ security/planGuard ← 计划内容审查 │
|
|
839
|
+
│ security/runtimeGuard ← 运行时自修改阻断 │
|
|
840
|
+
│ security/riskEngine ← 综合风险评估 │
|
|
841
|
+
├─────────────────────────────────────────────────┤
|
|
842
|
+
│ runner/runTask.ts ← 心跳/超时/cancel │
|
|
843
|
+
│ runner/changeCapture.ts ← 作用域违规检测 │
|
|
844
|
+
│ runner/postTaskCleanup.ts ← 受控清理 │
|
|
845
|
+
├─────────────────────────────────────────────────┤
|
|
846
|
+
│ security/contentRedaction ← 输出脱敏 │
|
|
847
|
+
│ tools/safeViews.ts ← safe_* 有界摘要 │
|
|
848
|
+
└─────────────────────────────────────────────────┘
|
|
849
|
+
```
|
|
850
|
+
|
|
851
|
+
### 9.2 安全不变量
|
|
852
|
+
|
|
853
|
+
PatchWarden 的硬性约束(在 `watch.ts` 与 `runTask.ts` 中声明):
|
|
854
|
+
|
|
855
|
+
- `repo_path` 必须在 `workspaceRoot` 内,不能通过 `..` 跳出
|
|
856
|
+
- Agent 必须在 `agents` 配置白名单中,命令来自本地配置而非模型输入
|
|
857
|
+
- `test_command` / `verify_commands` 必须逐字匹配全局或仓库专属白名单
|
|
858
|
+
- 每个任务最多运行一次(无自动重试循环)
|
|
859
|
+
- 不自动 commit、不自动 push、不删除文件、不发布、不重置仓库
|
|
860
|
+
- 敏感文件名(`.env`/SSH 私钥/`credentials`/`cookies` 等)默认不可读
|
|
861
|
+
- 任务产物中的疑似密钥值会被脱敏
|
|
862
|
+
- HTTP Server 只绑定 `127.0.0.1`
|
|
863
|
+
- Windows DPAPI 加密 Tunnel 凭据,不写入仓库
|
|
864
|
+
|
|
865
|
+
### 9.3 作用域违规检测
|
|
866
|
+
|
|
867
|
+
`changeCapture.ts` 实现"双快照 + 外部脏文件基线"机制:
|
|
868
|
+
|
|
869
|
+
1. 任务执行前:`captureRepoSnapshot(repoPath)` + `extractExternalDirtyFiles(workspaceSnapshot)` 建立基线
|
|
870
|
+
2. 任务执行后:`captureRepoSnapshot(repoPath)` + `buildChangeArtifacts`
|
|
871
|
+
3. `findNewExternalDirtyFiles(baseline, current)` 只标记任务期间**新增**的外部脏文件
|
|
872
|
+
4. 任务期间新增越界改动 → `failed_scope_violation`,写入 rollback 计划但**不自动回滚**
|
|
873
|
+
5. `change_policy: "no_changes"` 模式下出现任何改动 → `failed_policy_violation`
|
|
874
|
+
|
|
875
|
+
### 9.4 capability 模型(v0.8.1)
|
|
876
|
+
|
|
877
|
+
`invoke_discovered_tool` 采用"discover 发 token、invoke 凭 token 调用"的模型:
|
|
878
|
+
|
|
879
|
+
```text
|
|
880
|
+
discover_tools(query) ──▶ issueToken(toolName, risk, profile)
|
|
881
|
+
│
|
|
882
|
+
▼
|
|
883
|
+
invoke_discovered_tool(toolName, args, discoveryToken)
|
|
884
|
+
│
|
|
885
|
+
┌───────────────┤
|
|
886
|
+
▼ ▼
|
|
887
|
+
consumeToken toolInvocationGuard.checkInvocation
|
|
888
|
+
(单次使用) (8 项校验)
|
|
889
|
+
│
|
|
890
|
+
▼
|
|
891
|
+
handler 内二次校验
|
|
892
|
+
(如 commandGuard)
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
### 9.5 需要保护的本地路径
|
|
896
|
+
|
|
897
|
+
| 路径 | 内容 | 是否应提交 Git |
|
|
898
|
+
| --- | --- | --- |
|
|
899
|
+
| `patchwarden.config.json` | 私人路径、Agent 和命令白名单 | 否 |
|
|
900
|
+
| `.patchwarden/` | 计划、任务、差异和日志 | 否 |
|
|
901
|
+
| `%APPDATA%\patchwarden` | DPAPI 加密的 Tunnel 凭据 | 否 |
|
|
902
|
+
| `%LOCALAPPDATA%\patchwarden` | 运行时状态和隔离配置 | 否 |
|
|
903
|
+
|
|
904
|
+
---
|
|
905
|
+
|
|
906
|
+
## 10. 测试与发布
|
|
907
|
+
|
|
908
|
+
### 10.1 测试体系
|
|
909
|
+
|
|
910
|
+
| 测试类型 | 命令 | 覆盖范围 |
|
|
911
|
+
| --- | --- | --- |
|
|
912
|
+
| 完整测试链 | `npm.cmd test` | smoke + unit + lifecycle + doctor + tunnel + watcher + control + mcp + brand |
|
|
913
|
+
| 单元测试 | `npm.cmd run test:unit` | `src/test/unit/*.test.ts`(40+ 测试文件) |
|
|
914
|
+
| MCP 烟雾测试 | `npm.cmd run test:mcp` | stdio MCP 工具调用 |
|
|
915
|
+
| HTTP MCP 烟雾测试 | `npm.cmd run test:http-mcp` | HTTP MCP 端点 |
|
|
916
|
+
| 生命周期测试 | `npm.cmd run test:lifecycle` | 任务完整生命周期 |
|
|
917
|
+
| Doctor 烟雾测试 | `npm.cmd run test:doctor` | 诊断脚本 |
|
|
918
|
+
| Tunnel 监督测试 | `npm.cmd run test:tunnel-supervisor` | Tunnel 启动器 |
|
|
919
|
+
| Watcher 监督测试 | `npm.cmd run test:watcher-supervisor` | Watcher 心跳与所有权 |
|
|
920
|
+
| Control 烟雾测试 | `npm.cmd run test:control` | Control Center API |
|
|
921
|
+
| 工具 Manifest 校验 | `npm.cmd run check:tool-manifest` | 工具清单一致性 |
|
|
922
|
+
| 品牌检查 | `npm.cmd run check:brand` | 品牌命名一致性 |
|
|
923
|
+
|
|
924
|
+
### 10.2 发布验证流程
|
|
925
|
+
|
|
926
|
+
发布前必须依次完成:
|
|
927
|
+
|
|
928
|
+
```powershell
|
|
929
|
+
npm.cmd run build
|
|
930
|
+
npm.cmd test
|
|
931
|
+
npm.cmd run test:mcp
|
|
932
|
+
npm.cmd run test:http-mcp
|
|
933
|
+
npm.cmd run doctor
|
|
934
|
+
npm.cmd run check:tool-manifest
|
|
935
|
+
npm.cmd run check:brand
|
|
936
|
+
npm.cmd run test:tunnel-supervisor
|
|
937
|
+
npm.cmd run test:watcher-supervisor
|
|
938
|
+
npm.cmd run pack:clean
|
|
939
|
+
npm.cmd run verify:package
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
发布后还需分别核验:
|
|
943
|
+
- npm Registry(`patchwarden` 包)
|
|
944
|
+
- GitHub Release 与 Tag
|
|
945
|
+
- `dist-tags.latest`
|
|
946
|
+
|
|
947
|
+
### 10.3 发布门控(Release Gate)
|
|
948
|
+
|
|
949
|
+
`releaseGate.ts` 实现五阶段顺序校验:
|
|
950
|
+
|
|
951
|
+
| 阶段 | 检查内容 | 远程? |
|
|
952
|
+
| --- | --- | --- |
|
|
953
|
+
| `local_ready` | 本地构建、版本、Git 状态、配置 | 否 |
|
|
954
|
+
| `packed_ready` | 打包产物完整性、SHA-256 | 否 |
|
|
955
|
+
| `published_verified` | npm Registry 包与版本存在 | 是(`node:https` GET) |
|
|
956
|
+
| `github_release_verified` | GitHub Release 与资产存在 | 是(`node:https` GET) |
|
|
957
|
+
| `ci_verified` | CI 工作流状态 | 是(`node:https` GET) |
|
|
958
|
+
|
|
959
|
+
远程阶段网络错误返回 `not_checked`(不是 `failed`),不执行 shell 命令。
|
|
960
|
+
|
|
961
|
+
### 10.4 打包排除
|
|
962
|
+
|
|
963
|
+
`pack:clean` 与 `verify:package` 会排除:
|
|
964
|
+
|
|
965
|
+
- `node_modules/`
|
|
966
|
+
- `.patchwarden/`
|
|
967
|
+
- `*.log`
|
|
968
|
+
- `.env`
|
|
969
|
+
- `patchwarden.config.json`
|
|
970
|
+
- 本地凭据和运行时状态
|
|
971
|
+
|
|
972
|
+
---
|
|
973
|
+
|
|
974
|
+
## 附录:关键设计原则
|
|
975
|
+
|
|
976
|
+
1. **最小权限**:MCP 工具不提供通用 Shell,每个工具只做一件事
|
|
977
|
+
2. **纵深防御**:多层守卫串联,任一层失效不导致整体失守
|
|
978
|
+
3. **不可信输入**:模型指令始终被视为不可信,本地配置才是信任源
|
|
979
|
+
4. **可审计性**:所有任务产出结构化证据,支持独立验收
|
|
980
|
+
5. **不自动破坏**:不自动 commit/push/publish/tag/release,需人工决策
|
|
981
|
+
6. **有界输出**:`safe_*` 系列工具返回有界摘要,避免触发平台内容过滤
|
|
982
|
+
7. **零运行时依赖**:仅依赖 MCP SDK,其他全部使用 Node.js 内置模块
|
|
983
|
+
8. **跨平台**:Windows 与 POSIX 兼容(进程管理、路径处理、命令包装)
|