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.
Files changed (217) hide show
  1. package/README.en.md +43 -2
  2. package/README.md +43 -2
  3. package/dist/assessments/agentAssessor.d.ts +1 -1
  4. package/dist/assessments/agentAssessor.js +3 -3
  5. package/dist/assessments/assessmentStore.d.ts +1 -1
  6. package/dist/assessments/assessmentStore.js +2 -2
  7. package/dist/assessments/confirmCli.js +5 -4
  8. package/dist/config.d.ts +7 -0
  9. package/dist/config.js +34 -0
  10. package/dist/control/middleware/auth.d.ts +10 -0
  11. package/dist/control/middleware/auth.js +8 -0
  12. package/dist/control/middleware/static.d.ts +3 -0
  13. package/dist/control/middleware/static.js +65 -0
  14. package/dist/control/routes/audit.d.ts +15 -0
  15. package/dist/control/routes/audit.js +277 -0
  16. package/dist/control/routes/evidence.d.ts +4 -0
  17. package/dist/control/routes/evidence.js +96 -0
  18. package/dist/control/routes/lineage.d.ts +3 -0
  19. package/dist/control/routes/lineage.js +71 -0
  20. package/dist/control/routes/policy.d.ts +3 -0
  21. package/dist/control/routes/policy.js +81 -0
  22. package/dist/control/routes/process.d.ts +5 -0
  23. package/dist/control/routes/process.js +200 -0
  24. package/dist/control/routes/sessions.d.ts +22 -0
  25. package/dist/control/routes/sessions.js +224 -0
  26. package/dist/control/routes/status.d.ts +6 -0
  27. package/dist/control/routes/status.js +250 -0
  28. package/dist/control/routes/taskActions.d.ts +21 -0
  29. package/dist/control/routes/taskActions.js +233 -0
  30. package/dist/control/routes/tasks.d.ts +20 -0
  31. package/dist/control/routes/tasks.js +310 -0
  32. package/dist/control/routes/workspace.d.ts +15 -0
  33. package/dist/control/routes/workspace.js +193 -0
  34. package/dist/control/runtime.d.ts +91 -0
  35. package/dist/control/runtime.js +392 -0
  36. package/dist/control/server.d.ts +13 -0
  37. package/dist/control/server.js +479 -0
  38. package/dist/control/shared.d.ts +35 -0
  39. package/dist/control/shared.js +288 -0
  40. package/dist/controlCenter.d.ts +6 -0
  41. package/dist/controlCenter.js +7 -2197
  42. package/dist/direct/directGuards.js +30 -8
  43. package/dist/doctor.d.ts +18 -1
  44. package/dist/doctor.js +579 -348
  45. package/dist/goal/goalReport.d.ts +54 -0
  46. package/dist/goal/goalReport.js +204 -0
  47. package/dist/goal/goalStatus.d.ts +6 -0
  48. package/dist/goal/specKitImport.d.ts +63 -0
  49. package/dist/goal/specKitImport.js +220 -0
  50. package/dist/goal/subgoalSync.js +2 -1
  51. package/dist/httpServer.js +15 -12
  52. package/dist/index.js +7 -4
  53. package/dist/logging.d.ts +7 -1
  54. package/dist/logging.js +8 -0
  55. package/dist/runner/changeCapture.d.ts +3 -3
  56. package/dist/runner/changeCapture.js +63 -39
  57. package/dist/runner/cli.js +7 -6
  58. package/dist/runner/postTaskCleanup.js +26 -2
  59. package/dist/runner/runTask.js +245 -221
  60. package/dist/runner/simpleProcess.js +4 -4
  61. package/dist/runner/watch.js +17 -14
  62. package/dist/security/contentRedaction.d.ts +6 -0
  63. package/dist/security/contentRedaction.js +22 -0
  64. package/dist/smoke-test.js +257 -251
  65. package/dist/test/unit/apply-patch.test.d.ts +1 -0
  66. package/dist/test/unit/apply-patch.test.js +225 -0
  67. package/dist/test/unit/create-task.test.d.ts +1 -0
  68. package/dist/test/unit/create-task.test.js +197 -0
  69. package/dist/test/unit/direct-guards.test.js +124 -9
  70. package/dist/test/unit/evidence-pack.test.js +95 -1
  71. package/dist/test/unit/get-task-status.test.d.ts +1 -0
  72. package/dist/test/unit/get-task-status.test.js +174 -0
  73. package/dist/test/unit/get-task-summary.test.d.ts +1 -0
  74. package/dist/test/unit/get-task-summary.test.js +146 -0
  75. package/dist/test/unit/goal-report.test.d.ts +1 -0
  76. package/dist/test/unit/goal-report.test.js +159 -0
  77. package/dist/test/unit/goal-subgoal-task.test.js +6 -6
  78. package/dist/test/unit/goal-tools-registry.test.js +6 -4
  79. package/dist/test/unit/path-guard.test.js +24 -0
  80. package/dist/test/unit/spec-kit-import.test.d.ts +1 -0
  81. package/dist/test/unit/spec-kit-import.test.js +341 -0
  82. package/dist/test/unit/wait-for-task.test.d.ts +1 -0
  83. package/dist/test/unit/wait-for-task.test.js +144 -0
  84. package/dist/tools/auditTask.d.ts +8 -63
  85. package/dist/tools/auditTask.js +12 -8
  86. package/dist/tools/createDirectSession.d.ts +1 -1
  87. package/dist/tools/createDirectSession.js +2 -2
  88. package/dist/tools/createTask.d.ts +2 -2
  89. package/dist/tools/createTask.js +4 -4
  90. package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
  91. package/dist/tools/dispatch/coreDispatch.js +282 -0
  92. package/dist/tools/dispatch/diagnosticDispatch.d.ts +14 -0
  93. package/dist/tools/dispatch/diagnosticDispatch.js +78 -0
  94. package/dist/tools/dispatch/directDispatch.d.ts +8 -0
  95. package/dist/tools/dispatch/directDispatch.js +115 -0
  96. package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
  97. package/dist/tools/dispatch/goalDispatch.js +91 -0
  98. package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
  99. package/dist/tools/dispatch/releaseDispatch.js +45 -0
  100. package/dist/tools/dispatch/types.d.ts +23 -0
  101. package/dist/tools/dispatch/types.js +15 -0
  102. package/dist/tools/evidencePack.d.ts +6 -0
  103. package/dist/tools/evidencePack.js +213 -6
  104. package/dist/tools/finalizeDirectSession.d.ts +1 -1
  105. package/dist/tools/finalizeDirectSession.js +3 -3
  106. package/dist/tools/goalSubgoalTask.d.ts +1 -1
  107. package/dist/tools/goalSubgoalTask.js +2 -2
  108. package/dist/tools/healthCheck.js +3 -3
  109. package/dist/tools/registry.d.ts +3 -3
  110. package/dist/tools/registry.js +60 -503
  111. package/dist/tools/retryTask.d.ts +2 -2
  112. package/dist/tools/retryTask.js +2 -2
  113. package/dist/tools/runTaskLoop.js +4 -4
  114. package/dist/tools/safeViews.d.ts +2 -2
  115. package/dist/tools/safeViews.js +2 -2
  116. package/dist/tools/toolRegistry.js +22 -0
  117. package/dist/version.d.ts +1 -1
  118. package/dist/version.js +1 -1
  119. package/docs/CODE_WIKI.md +983 -0
  120. package/docs/agentseal-integration.md +150 -0
  121. package/docs/architecture.md +63 -0
  122. package/docs/assets/patchwarden-oss-demo.gif +0 -0
  123. package/docs/dashboard-overview.md +86 -0
  124. package/docs/demo.md +8 -0
  125. package/docs/direct-session-workflow.md +98 -0
  126. package/docs/evidence-pack-schema.md +215 -0
  127. package/docs/execution-plan-2026-07-09.md +315 -0
  128. package/docs/lineage-evidence-pack-workflow.md +127 -0
  129. package/docs/mcp-inspector-testing.md +200 -0
  130. package/docs/open-source-application.md +162 -0
  131. package/docs/opencode-worker.md +151 -0
  132. package/docs/openhands-worker.md +181 -0
  133. package/docs/release-evidence.md +72 -0
  134. package/docs/roadmap-execution-and-acceptance.md +365 -0
  135. package/docs/spec-kit-integration.md +131 -0
  136. package/docs/task-safe-review-workflow.md +98 -0
  137. package/docs/threat-model.md +79 -0
  138. package/docs/user-feedback.md +40 -0
  139. package/docs/why-patchwarden.md +110 -0
  140. package/package.json +2 -2
  141. package/scripts/checks/control-center-smoke.js +356 -0
  142. package/scripts/checks/lifecycle-smoke.js +29 -23
  143. package/scripts/checks/mcp-smoke.js +3 -1
  144. package/scripts/generate-demo-gif.py +320 -0
  145. package/src/assessments/agentAssessor.ts +3 -3
  146. package/src/assessments/assessmentStore.ts +2 -2
  147. package/src/assessments/confirmCli.ts +5 -4
  148. package/src/config.ts +37 -0
  149. package/src/control/middleware/auth.ts +17 -0
  150. package/src/control/middleware/static.ts +71 -0
  151. package/src/control/routes/audit.ts +321 -0
  152. package/src/control/routes/evidence.ts +107 -0
  153. package/src/control/routes/lineage.ts +92 -0
  154. package/src/control/routes/policy.ts +81 -0
  155. package/src/control/routes/process.ts +204 -0
  156. package/src/control/routes/sessions.ts +251 -0
  157. package/src/control/routes/status.ts +325 -0
  158. package/src/control/routes/taskActions.ts +248 -0
  159. package/src/control/routes/tasks.ts +323 -0
  160. package/src/control/routes/workspace.ts +203 -0
  161. package/src/control/runtime.ts +472 -0
  162. package/src/control/server.ts +471 -0
  163. package/src/control/shared.ts +294 -0
  164. package/src/controlCenter.ts +7 -2347
  165. package/src/direct/directGuards.ts +28 -7
  166. package/src/doctor.ts +741 -481
  167. package/src/goal/goalReport.ts +271 -0
  168. package/src/goal/goalStatus.ts +6 -0
  169. package/src/goal/specKitImport.ts +355 -0
  170. package/src/goal/subgoalSync.ts +4 -2
  171. package/src/httpServer.ts +17 -14
  172. package/src/index.ts +7 -4
  173. package/src/logging.ts +10 -1
  174. package/src/runner/changeCapture.ts +70 -42
  175. package/src/runner/cli.ts +7 -6
  176. package/src/runner/postTaskCleanup.ts +26 -2
  177. package/src/runner/runTask.ts +325 -223
  178. package/src/runner/simpleProcess.ts +4 -4
  179. package/src/runner/watch.ts +17 -14
  180. package/src/security/contentRedaction.ts +29 -0
  181. package/src/smoke-test.ts +252 -250
  182. package/src/test/unit/apply-patch.test.ts +293 -0
  183. package/src/test/unit/create-task.test.ts +255 -0
  184. package/src/test/unit/direct-guards.test.ts +178 -8
  185. package/src/test/unit/evidence-pack.test.ts +110 -1
  186. package/src/test/unit/get-task-status.test.ts +203 -0
  187. package/src/test/unit/get-task-summary.test.ts +173 -0
  188. package/src/test/unit/goal-report.test.ts +189 -0
  189. package/src/test/unit/goal-subgoal-task.test.ts +6 -6
  190. package/src/test/unit/goal-tools-registry.test.ts +7 -5
  191. package/src/test/unit/path-guard.test.ts +30 -0
  192. package/src/test/unit/spec-kit-import.test.ts +429 -0
  193. package/src/test/unit/wait-for-task.test.ts +176 -0
  194. package/src/tools/auditTask.ts +99 -59
  195. package/src/tools/createDirectSession.ts +3 -3
  196. package/src/tools/createTask.ts +7 -7
  197. package/src/tools/dispatch/coreDispatch.ts +374 -0
  198. package/src/tools/dispatch/diagnosticDispatch.ts +101 -0
  199. package/src/tools/dispatch/directDispatch.ts +167 -0
  200. package/src/tools/dispatch/goalDispatch.ts +127 -0
  201. package/src/tools/dispatch/releaseDispatch.ts +65 -0
  202. package/src/tools/dispatch/types.ts +24 -0
  203. package/src/tools/evidencePack.ts +291 -6
  204. package/src/tools/finalizeDirectSession.ts +4 -4
  205. package/src/tools/goalSubgoalTask.ts +2 -2
  206. package/src/tools/healthCheck.ts +3 -3
  207. package/src/tools/registry.ts +68 -628
  208. package/src/tools/retryTask.ts +2 -2
  209. package/src/tools/runTaskLoop.ts +4 -4
  210. package/src/tools/safeViews.ts +2 -2
  211. package/src/tools/toolRegistry.ts +22 -0
  212. package/src/version.ts +1 -1
  213. package/ui/pages/audit.html +192 -3
  214. package/ui/pages/dashboard.html +959 -44
  215. package/ui/pages/direct-sessions.html +505 -53
  216. package/ui/pages/task-detail.html +456 -438
  217. 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 兼容(进程管理、路径处理、命令包装)