patchwarden 0.6.4 → 1.1.0
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 +18 -18
- package/README.md +20 -20
- package/dist/agents/agentRouter.d.ts +40 -0
- package/dist/agents/agentRouter.js +95 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.js +6 -2
- package/dist/controlCenter.js +15 -2
- package/dist/doctor.js +32 -1
- package/dist/goal/acceptanceEngine.d.ts +62 -0
- package/dist/goal/acceptanceEngine.js +103 -0
- package/dist/goal/acceptanceTemplate.d.ts +10 -0
- package/dist/goal/acceptanceTemplate.js +104 -0
- package/dist/goal/goalGraph.d.ts +58 -0
- package/dist/goal/goalGraph.js +189 -0
- package/dist/goal/goalProgress.d.ts +81 -0
- package/dist/goal/goalProgress.js +216 -0
- package/dist/goal/goalStatus.d.ts +60 -0
- package/dist/goal/goalStatus.js +137 -0
- package/dist/goal/goalStore.d.ts +79 -0
- package/dist/goal/goalStore.js +211 -0
- package/dist/goal/handoffExport.d.ts +34 -0
- package/dist/goal/handoffExport.js +183 -0
- package/dist/goal/subgoalSync.d.ts +40 -0
- package/dist/goal/subgoalSync.js +72 -0
- package/dist/goal/worktreeManager.d.ts +96 -0
- package/dist/goal/worktreeManager.js +292 -0
- package/dist/logging.d.ts +44 -0
- package/dist/logging.js +68 -0
- package/dist/release/releaseGate.d.ts +99 -0
- package/dist/release/releaseGate.js +475 -0
- package/dist/runner/postTaskCleanup.d.ts +13 -0
- package/dist/runner/postTaskCleanup.js +147 -0
- package/dist/runner/runTask.js +50 -10
- package/dist/security/discoveryTokenStore.d.ts +62 -0
- package/dist/security/discoveryTokenStore.js +100 -0
- package/dist/security/toolInvocationGuard.d.ts +35 -0
- package/dist/security/toolInvocationGuard.js +153 -0
- package/dist/smoke-test.js +18 -10
- package/dist/taskRuntime.d.ts +17 -0
- package/dist/test/unit/acceptance-engine.test.d.ts +1 -0
- package/dist/test/unit/acceptance-engine.test.js +228 -0
- package/dist/test/unit/agent-router.test.d.ts +1 -0
- package/dist/test/unit/agent-router.test.js +287 -0
- package/dist/test/unit/audit-checks.test.d.ts +1 -0
- package/dist/test/unit/audit-checks.test.js +350 -0
- package/dist/test/unit/diagnose-task.test.d.ts +1 -0
- package/dist/test/unit/diagnose-task.test.js +457 -0
- package/dist/test/unit/discovery-token-store.test.d.ts +1 -0
- package/dist/test/unit/discovery-token-store.test.js +139 -0
- package/dist/test/unit/goal-graph.test.d.ts +1 -0
- package/dist/test/unit/goal-graph.test.js +298 -0
- package/dist/test/unit/goal-progress.test.d.ts +1 -0
- package/dist/test/unit/goal-progress.test.js +381 -0
- package/dist/test/unit/goal-status.test.d.ts +1 -0
- package/dist/test/unit/goal-status.test.js +215 -0
- package/dist/test/unit/goal-store.test.d.ts +1 -0
- package/dist/test/unit/goal-store.test.js +253 -0
- package/dist/test/unit/goal-subgoal-task.test.d.ts +1 -0
- package/dist/test/unit/goal-subgoal-task.test.js +55 -0
- package/dist/test/unit/goal-tools-registry.test.d.ts +1 -0
- package/dist/test/unit/goal-tools-registry.test.js +190 -0
- package/dist/test/unit/handoff-export.test.d.ts +1 -0
- package/dist/test/unit/handoff-export.test.js +263 -0
- package/dist/test/unit/invoke-discovered-tool.test.d.ts +1 -0
- package/dist/test/unit/invoke-discovered-tool.test.js +167 -0
- package/dist/test/unit/logging.test.js +127 -5
- package/dist/test/unit/post-task-cleanup.test.d.ts +1 -0
- package/dist/test/unit/post-task-cleanup.test.js +48 -0
- package/dist/test/unit/reconcile-tasks.test.d.ts +1 -0
- package/dist/test/unit/reconcile-tasks.test.js +456 -0
- package/dist/test/unit/release-gate.test.d.ts +1 -0
- package/dist/test/unit/release-gate.test.js +242 -0
- package/dist/test/unit/safe-views.test.d.ts +1 -0
- package/dist/test/unit/safe-views.test.js +171 -0
- package/dist/test/unit/schema-drift-check.test.d.ts +1 -0
- package/dist/test/unit/schema-drift-check.test.js +175 -0
- package/dist/test/unit/subgoal-sync.test.d.ts +1 -0
- package/dist/test/unit/subgoal-sync.test.js +183 -0
- package/dist/test/unit/tool-invocation-guard.test.d.ts +1 -0
- package/dist/test/unit/tool-invocation-guard.test.js +432 -0
- package/dist/test/unit/tool-usage-stats.test.d.ts +1 -0
- package/dist/test/unit/tool-usage-stats.test.js +300 -0
- package/dist/test/unit/toolSearch.test.d.ts +1 -0
- package/dist/test/unit/toolSearch.test.js +571 -0
- package/dist/test/unit/worktree-manager.test.d.ts +1 -0
- package/dist/test/unit/worktree-manager.test.js +176 -0
- package/dist/tools/auditTask.d.ts +103 -1
- package/dist/tools/auditTask.js +461 -8
- package/dist/tools/cancelTask.js +1 -1
- package/dist/tools/checkReleaseGate.d.ts +21 -0
- package/dist/tools/checkReleaseGate.js +22 -0
- package/dist/tools/createTask.d.ts +18 -2
- package/dist/tools/createTask.js +29 -1
- package/dist/tools/diagnoseTask.d.ts +45 -0
- package/dist/tools/diagnoseTask.js +347 -0
- package/dist/tools/discardWorktree.d.ts +24 -0
- package/dist/tools/discardWorktree.js +27 -0
- package/dist/tools/discoverTools.d.ts +11 -0
- package/dist/tools/discoverTools.js +39 -0
- package/dist/tools/explainTool.d.ts +11 -0
- package/dist/tools/explainTool.js +21 -0
- package/dist/tools/getTaskSummary.js +2 -1
- package/dist/tools/goalSubgoalTask.d.ts +51 -0
- package/dist/tools/goalSubgoalTask.js +110 -0
- package/dist/tools/healthCheck.d.ts +1 -0
- package/dist/tools/healthCheck.js +5 -1
- package/dist/tools/invokeDiscoveredTool.d.ts +37 -0
- package/dist/tools/invokeDiscoveredTool.js +112 -0
- package/dist/tools/listTasks.d.ts +3 -1
- package/dist/tools/listTasks.js +14 -1
- package/dist/tools/mergeWorktree.d.ts +24 -0
- package/dist/tools/mergeWorktree.js +27 -0
- package/dist/tools/reconcileTasks.d.ts +41 -0
- package/dist/tools/reconcileTasks.js +352 -0
- package/dist/tools/registry.js +550 -0
- package/dist/tools/safeStatus.d.ts +31 -1
- package/dist/tools/safeStatus.js +43 -1
- package/dist/tools/safeViews.d.ts +256 -0
- package/dist/tools/safeViews.js +250 -0
- package/dist/tools/schemaDriftCheck.d.ts +46 -0
- package/dist/tools/schemaDriftCheck.js +80 -0
- package/dist/tools/toolCatalog.d.ts +4 -3
- package/dist/tools/toolCatalog.js +33 -11
- package/dist/tools/toolRegistry.d.ts +61 -0
- package/dist/tools/toolRegistry.js +724 -0
- package/dist/tools/toolSearch.d.ts +110 -0
- package/dist/tools/toolSearch.js +331 -0
- package/dist/tools/toolUsageStats.d.ts +41 -0
- package/dist/tools/toolUsageStats.js +116 -0
- package/dist/tools/waitForTask.js +1 -0
- package/dist/version.d.ts +2 -2
- package/dist/version.js +2 -2
- package/dist/watcherStatus.d.ts +29 -0
- package/dist/watcherStatus.js +92 -1
- package/package.json +3 -2
- package/scripts/checks/control-smoke.js +2 -2
- package/scripts/checks/doctor-smoke.js +1 -0
- package/scripts/checks/lifecycle-smoke.js +13 -9
- package/scripts/checks/mcp-manifest-check.js +53 -6
- package/scripts/checks/mcp-smoke.js +36 -9
- package/scripts/checks/watcher-supervisor-smoke.js +2 -2
- package/src/agents/agentRouter.ts +149 -0
- package/src/config.ts +9 -3
- package/src/controlCenter.ts +17 -3
- package/src/doctor.ts +36 -1
- package/src/goal/acceptanceEngine.ts +160 -0
- package/src/goal/acceptanceTemplate.ts +121 -0
- package/src/goal/goalGraph.ts +225 -0
- package/src/goal/goalProgress.ts +301 -0
- package/src/goal/goalStatus.ts +234 -0
- package/src/goal/goalStore.ts +306 -0
- package/src/goal/handoffExport.ts +211 -0
- package/src/goal/subgoalSync.ts +82 -0
- package/src/goal/worktreeManager.ts +404 -0
- package/src/logging.ts +91 -0
- package/src/release/releaseGate.ts +567 -0
- package/src/runner/postTaskCleanup.ts +154 -0
- package/src/runner/runTask.ts +49 -10
- package/src/security/discoveryTokenStore.ts +157 -0
- package/src/security/toolInvocationGuard.ts +251 -0
- package/src/smoke-test.ts +15 -7
- package/src/taskRuntime.ts +17 -0
- package/src/test/unit/acceptance-engine.test.ts +261 -0
- package/src/test/unit/agent-router.test.ts +342 -0
- package/src/test/unit/audit-checks.test.ts +567 -0
- package/src/test/unit/diagnose-task.test.ts +544 -0
- package/src/test/unit/discovery-token-store.test.ts +181 -0
- package/src/test/unit/goal-graph.test.ts +347 -0
- package/src/test/unit/goal-progress.test.ts +538 -0
- package/src/test/unit/goal-status.test.ts +270 -0
- package/src/test/unit/goal-store.test.ts +318 -0
- package/src/test/unit/goal-subgoal-task.test.ts +72 -0
- package/src/test/unit/goal-tools-registry.test.ts +243 -0
- package/src/test/unit/handoff-export.test.ts +295 -0
- package/src/test/unit/invoke-discovered-tool.test.ts +216 -0
- package/src/test/unit/logging.test.ts +177 -5
- package/src/test/unit/post-task-cleanup.test.ts +53 -0
- package/src/test/unit/reconcile-tasks.test.ts +551 -0
- package/src/test/unit/release-gate.test.ts +314 -0
- package/src/test/unit/safe-views.test.ts +184 -0
- package/src/test/unit/schema-drift-check.test.ts +258 -0
- package/src/test/unit/subgoal-sync.test.ts +236 -0
- package/src/test/unit/tool-invocation-guard.test.ts +542 -0
- package/src/test/unit/tool-usage-stats.test.ts +384 -0
- package/src/test/unit/toolSearch.test.ts +756 -0
- package/src/test/unit/worktree-manager.test.ts +247 -0
- package/src/tools/auditTask.ts +831 -402
- package/src/tools/cancelTask.ts +1 -1
- package/src/tools/checkReleaseGate.ts +45 -0
- package/src/tools/createTask.ts +64 -6
- package/src/tools/diagnoseTask.ts +460 -0
- package/src/tools/discardWorktree.ts +42 -0
- package/src/tools/discoverTools.ts +51 -0
- package/src/tools/explainTool.ts +26 -0
- package/src/tools/getTaskSummary.ts +2 -1
- package/src/tools/goalSubgoalTask.ts +170 -0
- package/src/tools/healthCheck.ts +4 -1
- package/src/tools/invokeDiscoveredTool.ts +163 -0
- package/src/tools/listTasks.ts +16 -2
- package/src/tools/mergeWorktree.ts +42 -0
- package/src/tools/reconcileTasks.ts +464 -0
- package/src/tools/registry.ts +618 -1
- package/src/tools/safeStatus.ts +73 -2
- package/src/tools/safeViews.ts +271 -0
- package/src/tools/schemaDriftCheck.ts +120 -0
- package/src/tools/toolCatalog.ts +34 -11
- package/src/tools/toolRegistry.ts +786 -0
- package/src/tools/toolSearch.ts +464 -0
- package/src/tools/toolUsageStats.ts +151 -0
- package/src/tools/waitForTask.ts +1 -0
- package/src/version.ts +2 -2
- package/src/watcherStatus.ts +97 -1
package/README.en.md
CHANGED
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
[](https://nodejs.org/)
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
|
|
11
|
-
Current
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[GitHub Release](https://github.com/jiezeng2004-design/PatchWarden/releases/tag/v0.6.4).
|
|
11
|
+
Current source version: **v1.1.0**. See the
|
|
12
|
+
[CHANGELOG](CHANGELOG.md), [migration guide](docs/migration-from-safe-bifrost.md), and
|
|
13
|
+
[release checklist](docs/release-checklist.md). Verify GitHub Release / npm publication separately before release.
|
|
15
14
|
|
|
16
15
|
PatchWarden is a local-first MCP safety and verification layer for AI coding
|
|
17
16
|
agents, with workspace confinement, command allowlists, scope-violation
|
|
@@ -266,7 +265,7 @@ execution still requires a separate Watcher.
|
|
|
266
265
|
New-Item -ItemType Directory .\patchwarden-runtime
|
|
267
266
|
Set-Location .\patchwarden-runtime
|
|
268
267
|
npm.cmd init -y
|
|
269
|
-
npm.cmd install patchwarden
|
|
268
|
+
npm.cmd install patchwarden@<published-version>
|
|
270
269
|
Copy-Item .\node_modules\patchwarden\examples\config.example.json .\patchwarden.config.json
|
|
271
270
|
$env:PATCHWARDEN_CONFIG = (Resolve-Path .\patchwarden.config.json)
|
|
272
271
|
node .\node_modules\patchwarden\dist\runner\watch.js
|
|
@@ -275,10 +274,10 @@ node .\node_modules\patchwarden\dist\runner\watch.js
|
|
|
275
274
|
An MCP client can launch:
|
|
276
275
|
|
|
277
276
|
```text
|
|
278
|
-
npx.cmd -y patchwarden
|
|
277
|
+
npx.cmd -y patchwarden@<published-version>
|
|
279
278
|
```
|
|
280
279
|
|
|
281
|
-
|
|
280
|
+
Replace `<published-version>` with a version that exists on npm/GitHub, and pin that version in important environments instead of using `latest`
|
|
282
281
|
unconditionally.
|
|
283
282
|
|
|
284
283
|
## Complete configuration guide
|
|
@@ -331,7 +330,7 @@ Configuration fields:
|
|
|
331
330
|
| `workspaceRoot` | Yes | The only workspace root PatchWarden may access. |
|
|
332
331
|
| `plansDir` | Yes | Plan directory, normally `.patchwarden/plans`. |
|
|
333
332
|
| `tasksDir` | Yes | Task and result directory, normally `.patchwarden/tasks`. |
|
|
334
|
-
| `toolProfile` | No | `full` or `
|
|
333
|
+
| `toolProfile` | No | `full`, `chatgpt_core`, `chatgpt_direct`, or `chatgpt_search`; use `full` for local clients and `chatgpt_search` for compact discovery-driven clients. |
|
|
335
334
|
| `agents` | Yes | Execution-agent allowlist; supports `{repo}` and `{prompt}` placeholders. |
|
|
336
335
|
| `allowedTestCommands` | Yes | Exact allowlist for independent verification commands. |
|
|
337
336
|
| `repoAllowedTestCommands` | No | Extra exact commands keyed by workspace-relative repository path; wildcards are unsupported. |
|
|
@@ -434,7 +433,7 @@ Pinned npm configuration:
|
|
|
434
433
|
```toml
|
|
435
434
|
[mcp_servers.patchwarden]
|
|
436
435
|
command = "npx.cmd"
|
|
437
|
-
args = ["-y", "patchwarden
|
|
436
|
+
args = ["-y", "patchwarden@<published-version>"]
|
|
438
437
|
|
|
439
438
|
[mcp_servers.patchwarden.env]
|
|
440
439
|
PATCHWARDEN_CONFIG = "D:\\path\\to\\patchwarden.config.json"
|
|
@@ -494,7 +493,7 @@ PatchWarden.cmd start core
|
|
|
494
493
|
The launcher:
|
|
495
494
|
|
|
496
495
|
- Builds `dist/index.js` if it is missing.
|
|
497
|
-
- Verifies
|
|
496
|
+
- Verifies v1.1.0, the fixed 21-tool `chatgpt_core` catalog, and its schema
|
|
498
497
|
manifest.
|
|
499
498
|
- Reads or prompts for the Tunnel ID.
|
|
500
499
|
- Reads or prompts for the runtime API key.
|
|
@@ -742,7 +741,7 @@ Optional token configuration:
|
|
|
742
741
|
Set the token in the PowerShell process that starts the server:
|
|
743
742
|
|
|
744
743
|
```powershell
|
|
745
|
-
$env:PATCHWARDEN_OWNER_TOKEN = "
|
|
744
|
+
$env:PATCHWARDEN_OWNER_TOKEN = "<token>"
|
|
746
745
|
```
|
|
747
746
|
|
|
748
747
|
Clients can send `Authorization: Bearer ...` or `x-patchwarden-token`. Never
|
|
@@ -931,13 +930,13 @@ names.
|
|
|
931
930
|
|
|
932
931
|
## MCP tools and profiles
|
|
933
932
|
|
|
934
|
-
`chatgpt_core` is the fixed
|
|
933
|
+
`chatgpt_core` is the fixed 21-tool profile used by the ChatGPT tunnel:
|
|
935
934
|
|
|
936
935
|
`health_check`, `list_agents`, `list_workspace`,
|
|
937
936
|
`read_workspace_file`, `save_plan`, `create_task`,
|
|
938
937
|
`wait_for_task`, `get_task_summary`, `get_diff`, `get_result`,
|
|
939
938
|
`get_result_json`, `get_test_log`, `get_task_status`, `list_tasks`,
|
|
940
|
-
`cancel_task`, `audit_task`, and `
|
|
939
|
+
`cancel_task`, `audit_task`, `safe_status`, `safe_result`, `safe_audit`, `safe_test_summary`, and `safe_diff_summary`.
|
|
941
940
|
|
|
942
941
|
`get_task_summary` keeps the backward-compatible `standard` view by default.
|
|
943
942
|
ChatGPT should request `view: "compact"` first; terminal `wait_for_task`
|
|
@@ -957,7 +956,7 @@ to `full`.
|
|
|
957
956
|
|
|
958
957
|
### ChatGPT Direct mode
|
|
959
958
|
|
|
960
|
-
Direct mode exposes
|
|
959
|
+
Direct mode exposes thirteen guarded tools so ChatGPT can create an editing
|
|
961
960
|
session, read and search source files, apply hash-bound JSON patches, run
|
|
962
961
|
exactly allowlisted verification commands, finalize the evidence, and audit
|
|
963
962
|
the result without a local execution agent.
|
|
@@ -981,7 +980,7 @@ On first use, provide the `tunnel-client.exe` path and a Tunnel ID dedicated
|
|
|
981
980
|
to the Direct Connector. The launcher uses the `patchwarden-direct` profile,
|
|
982
981
|
stores runtime state under `%LOCALAPPDATA%\patchwarden\runtime-direct`, skips
|
|
983
982
|
the Watcher, and retains the existing DPAPI credential handling. In a fresh
|
|
984
|
-
ChatGPT conversation, `health_check` should report `chatgpt_direct`,
|
|
983
|
+
ChatGPT conversation, `health_check` should report `chatgpt_direct`, thirteen
|
|
985
984
|
tools, and `direct_profile_enabled=true`.
|
|
986
985
|
|
|
987
986
|
## Security boundaries and local data
|
|
@@ -1017,7 +1016,7 @@ Start with a dedicated test workspace and a repository you can recover.
|
|
|
1017
1016
|
Upgrade a pinned npm installation:
|
|
1018
1017
|
|
|
1019
1018
|
```powershell
|
|
1020
|
-
npm.cmd install patchwarden
|
|
1019
|
+
npm.cmd install patchwarden@<published-version>
|
|
1021
1020
|
```
|
|
1022
1021
|
|
|
1023
1022
|
Upgrade a source checkout:
|
|
@@ -1101,8 +1100,9 @@ and release-asset checksums independently.
|
|
|
1101
1100
|
- [x] ChatGPT Connector / tunnel
|
|
1102
1101
|
- [x] Doctor and runtime health checks
|
|
1103
1102
|
- [x] Tool manifest and schema-drift detection
|
|
1104
|
-
- [
|
|
1105
|
-
- [
|
|
1103
|
+
- [x] Release Gate (five-stage pre-release verification)
|
|
1104
|
+
- [x] Worktree isolation
|
|
1105
|
+
- [x] Multi-agent routing
|
|
1106
1106
|
- [ ] Local dashboard
|
|
1107
1107
|
|
|
1108
1108
|
## License
|
package/README.md
CHANGED
|
@@ -8,10 +8,9 @@
|
|
|
8
8
|
[](https://nodejs.org/)
|
|
9
9
|
[](LICENSE)
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[GitHub Release](https://github.com/jiezeng2004-design/PatchWarden/releases/tag/v0.6.4)。
|
|
11
|
+
当前源码版本:**v1.1.0**。查看
|
|
12
|
+
[CHANGELOG](CHANGELOG.md)、[迁移指南](docs/migration-from-safe-bifrost.md)和
|
|
13
|
+
[发布检查清单](docs/release-checklist.md)。GitHub Release / npm 发布状态需要在发布前单独核对。
|
|
15
14
|
|
|
16
15
|
PatchWarden 是一个面向本地编程 Agent 的安全 MCP 桥接器。上游的
|
|
17
16
|
ChatGPT、Codex、OpenCode 或其他 MCP 客户端负责规划与验收,
|
|
@@ -180,7 +179,7 @@ npm 包适合让 MCP 客户端通过固定版本启动 PatchWarden。为了执
|
|
|
180
179
|
New-Item -ItemType Directory .\patchwarden-runtime
|
|
181
180
|
Set-Location .\patchwarden-runtime
|
|
182
181
|
npm.cmd init -y
|
|
183
|
-
npm.cmd install patchwarden
|
|
182
|
+
npm.cmd install patchwarden@<published-version>
|
|
184
183
|
Copy-Item .\node_modules\patchwarden\examples\config.example.json .\patchwarden.config.json
|
|
185
184
|
$env:PATCHWARDEN_CONFIG = (Resolve-Path .\patchwarden.config.json)
|
|
186
185
|
node .\node_modules\patchwarden\dist\runner\watch.js
|
|
@@ -189,10 +188,10 @@ node .\node_modules\patchwarden\dist\runner\watch.js
|
|
|
189
188
|
MCP 客户端可以使用:
|
|
190
189
|
|
|
191
190
|
```text
|
|
192
|
-
npx.cmd -y patchwarden
|
|
191
|
+
npx.cmd -y patchwarden@<published-version>
|
|
193
192
|
```
|
|
194
193
|
|
|
195
|
-
|
|
194
|
+
将 `<published-version>` 替换为已经在 npm/GitHub 上确认存在的版本;不要在重要环境中无条件使用 `latest`。
|
|
196
195
|
|
|
197
196
|
## 完整配置说明
|
|
198
197
|
|
|
@@ -244,7 +243,7 @@ Copy-Item .\examples\config.example.json .\patchwarden.config.json
|
|
|
244
243
|
| `workspaceRoot` | 是 | PatchWarden 唯一允许访问的工作区根目录。 |
|
|
245
244
|
| `plansDir` | 是 | 计划目录,通常使用 `.patchwarden/plans`。 |
|
|
246
245
|
| `tasksDir` | 是 | 任务和结果目录,通常使用 `.patchwarden/tasks`。 |
|
|
247
|
-
| `toolProfile` | 否 | `full` 或 `
|
|
246
|
+
| `toolProfile` | 否 | `full`、`chatgpt_core`、`chatgpt_direct` 或 `chatgpt_search`;本地客户端推荐 `full`,动态工具发现场景使用 `chatgpt_search`。 |
|
|
248
247
|
| `agents` | 是 | 可执行 Agent 白名单;支持 `{repo}` 和 `{prompt}` 占位符。 |
|
|
249
248
|
| `allowedTestCommands` | 是 | 独立验证命令白名单,调用时必须精确匹配。 |
|
|
250
249
|
| `repoAllowedTestCommands` | 否 | 按工作区相对仓库路径增加精确验证命令;不支持通配符。 |
|
|
@@ -342,7 +341,7 @@ npm.cmd run watch
|
|
|
342
341
|
```toml
|
|
343
342
|
[mcp_servers.patchwarden]
|
|
344
343
|
command = "npx.cmd"
|
|
345
|
-
args = ["-y", "patchwarden
|
|
344
|
+
args = ["-y", "patchwarden@<published-version>"]
|
|
346
345
|
|
|
347
346
|
[mcp_servers.patchwarden.env]
|
|
348
347
|
PATCHWARDEN_CONFIG = "D:\\path\\to\\patchwarden.config.json"
|
|
@@ -400,7 +399,7 @@ PatchWarden.cmd start core
|
|
|
400
399
|
启动器会:
|
|
401
400
|
|
|
402
401
|
- 检查 `dist/index.js`,缺失时自动构建。
|
|
403
|
-
- 校验 `chatgpt_core` 的版本、
|
|
402
|
+
- 校验 `chatgpt_core` 的版本、21 个核心工具和 Schema Manifest。
|
|
404
403
|
- 读取或提示输入 Tunnel ID。
|
|
405
404
|
- 读取或提示输入运行时 API Key。
|
|
406
405
|
- 使用 Windows DPAPI 保存凭据到 `%APPDATA%\patchwarden`。
|
|
@@ -837,18 +836,18 @@ PatchWarden v0.4.0 不自动读取旧 CLI、旧环境变量、旧 Header、旧
|
|
|
837
836
|
|
|
838
837
|
## MCP 工具与 Profile
|
|
839
838
|
|
|
840
|
-
`chatgpt_core` 是固定的
|
|
839
|
+
`chatgpt_core` 是固定的 21 工具 Profile,适合 ChatGPT Tunnel:
|
|
841
840
|
|
|
842
841
|
`health_check`、`list_agents`、`list_workspace`、
|
|
843
842
|
`read_workspace_file`、`save_plan`、`create_task`、
|
|
844
843
|
`wait_for_task`、`get_task_summary`、`get_diff`、`get_result`、
|
|
845
844
|
`get_result_json`、`get_test_log`、`get_task_status`、`list_tasks`、
|
|
846
|
-
`cancel_task`、`audit_task`、`safe_status`。
|
|
845
|
+
`cancel_task`、`audit_task`、`safe_status`、`safe_result`、`safe_audit`、`safe_test_summary`、`safe_diff_summary`。
|
|
847
846
|
|
|
848
847
|
`get_task_summary` 默认保留兼容的 `standard` 视图;ChatGPT 应优先使用
|
|
849
848
|
`view: "compact"`,终态 `wait_for_task` 也只内嵌 compact 验收证据。
|
|
850
849
|
|
|
851
|
-
`full` 提供完整
|
|
850
|
+
`full` 提供完整 54 工具本地开发目录,包含核心工具、管理工具和 Direct
|
|
852
851
|
工具。除 `chatgpt_core` 外,常用额外管理工具包括:
|
|
853
852
|
|
|
854
853
|
- `get_plan`
|
|
@@ -858,15 +857,15 @@ PatchWarden v0.4.0 不自动读取旧 CLI、旧环境变量、旧 Header、旧
|
|
|
858
857
|
- `get_task_stdout_tail`
|
|
859
858
|
- `get_task_log_tail`
|
|
860
859
|
|
|
861
|
-
`chatgpt_direct` 是 v0.6.0 新增的 Direct 直接开发 Profile,
|
|
860
|
+
`chatgpt_direct` 是 v0.6.0 新增的 Direct 直接开发 Profile,v1.1 包含 13 个工具:
|
|
862
861
|
|
|
863
862
|
`health_check`、`list_workspace`、`create_direct_session`、
|
|
864
863
|
`search_workspace`、`read_workspace_file`、`apply_patch`、
|
|
865
|
-
`run_verification`、`finalize_direct_session`、`audit_session`、`sync_file`。
|
|
864
|
+
`run_verification`、`finalize_direct_session`、`audit_session`、`safe_direct_summary`、`safe_finalize_direct_session`、`safe_audit_direct_session`、`sync_file`。
|
|
866
865
|
|
|
867
866
|
`chatgpt_direct` 默认关闭,需要通过 `enableDirectProfile: true` 或
|
|
868
867
|
`PATCHWARDEN_TOOL_PROFILE=chatgpt_direct` 显式启用。`chatgpt_core` 保持
|
|
869
|
-
|
|
868
|
+
21 工具清单。
|
|
870
869
|
|
|
871
870
|
Tunnel 包装脚本会强制使用 `chatgpt_core`;普通本地开发默认使用 `full`。
|
|
872
871
|
|
|
@@ -921,7 +920,7 @@ Tunnel ID。启动器使用 `patchwarden-direct` Profile、独立的
|
|
|
921
920
|
Tunnel API Key 仍通过现有 Windows DPAPI 缓存处理,不会写入仓库。
|
|
922
921
|
|
|
923
922
|
连接 ChatGPT 后新建对话并先调用 `health_check`。预期
|
|
924
|
-
`tool_profile=chatgpt_direct`、`tool_count=
|
|
923
|
+
`tool_profile=chatgpt_direct`、`tool_count=13`、
|
|
925
924
|
`direct_profile_enabled=true`。已有对话可能缓存旧工具清单,需要重新连接
|
|
926
925
|
Connector 后再新建对话。
|
|
927
926
|
|
|
@@ -984,7 +983,7 @@ PatchWarden 能降低误操作风险,但不能替代人工审查。第一次
|
|
|
984
983
|
升级 npm 固定版本:
|
|
985
984
|
|
|
986
985
|
```powershell
|
|
987
|
-
npm.cmd install patchwarden
|
|
986
|
+
npm.cmd install patchwarden@<published-version>
|
|
988
987
|
```
|
|
989
988
|
|
|
990
989
|
源码升级:
|
|
@@ -1067,8 +1066,9 @@ Release 和发布资产校验值。
|
|
|
1067
1066
|
- [x] ChatGPT Connector / Tunnel
|
|
1068
1067
|
- [x] Doctor 与运行时健康检查
|
|
1069
1068
|
- [x] Tool Manifest 与 Schema 漂移检测
|
|
1070
|
-
- [
|
|
1071
|
-
- [
|
|
1069
|
+
- [x] Release Gate(发布前五阶段校验)
|
|
1070
|
+
- [x] Worktree 隔离
|
|
1071
|
+
- [x] 多 Agent 路由
|
|
1072
1072
|
- [ ] 本地 Dashboard
|
|
1073
1073
|
|
|
1074
1074
|
## License
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export interface AgentRouteInput {
|
|
2
|
+
goal?: string;
|
|
3
|
+
scope?: string[];
|
|
4
|
+
inline_plan?: string;
|
|
5
|
+
template?: string;
|
|
6
|
+
configuredAgents: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface AgentRouteResult {
|
|
9
|
+
recommended_agent: string;
|
|
10
|
+
reason: string;
|
|
11
|
+
fallback: boolean;
|
|
12
|
+
}
|
|
13
|
+
export declare const AGENT_ROUTING_RULES: {
|
|
14
|
+
/** 大规模代码修改 → opencode */
|
|
15
|
+
readonly largeScope: {
|
|
16
|
+
readonly agent: "opencode";
|
|
17
|
+
readonly threshold: 10;
|
|
18
|
+
};
|
|
19
|
+
/** 单文件修改 → patchwarden-direct */
|
|
20
|
+
readonly singleFile: {
|
|
21
|
+
readonly agent: "patchwarden-direct";
|
|
22
|
+
};
|
|
23
|
+
/** 验收审计 → patchwarden-audit */
|
|
24
|
+
readonly audit: {
|
|
25
|
+
readonly agent: "patchwarden-audit";
|
|
26
|
+
readonly keywords: readonly ["审计", "audit", "验收", "verify"];
|
|
27
|
+
};
|
|
28
|
+
/** 复杂推理和重构 → codex */
|
|
29
|
+
readonly refactor: {
|
|
30
|
+
readonly agent: "codex";
|
|
31
|
+
readonly keywords: readonly ["重构", "refactor", "跨模块", "redesign"];
|
|
32
|
+
};
|
|
33
|
+
/** 文档整理 → claude(fallback 到 opencode) */
|
|
34
|
+
readonly documentation: {
|
|
35
|
+
readonly agent: "claude";
|
|
36
|
+
readonly fallbackAgent: "opencode";
|
|
37
|
+
readonly keywords: readonly ["文档", "readme", "changelog", "doc"];
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
export declare function routeAgent(input: AgentRouteInput): AgentRouteResult;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { PatchWardenError } from "../errors.js";
|
|
2
|
+
// ── Routing rules (roadmap 9.3) ───────────────────────────────────
|
|
3
|
+
export const AGENT_ROUTING_RULES = {
|
|
4
|
+
/** 大规模代码修改 → opencode */
|
|
5
|
+
largeScope: {
|
|
6
|
+
agent: "opencode",
|
|
7
|
+
threshold: 10, // scope.length > threshold
|
|
8
|
+
},
|
|
9
|
+
/** 单文件修改 → patchwarden-direct */
|
|
10
|
+
singleFile: {
|
|
11
|
+
agent: "patchwarden-direct",
|
|
12
|
+
},
|
|
13
|
+
/** 验收审计 → patchwarden-audit */
|
|
14
|
+
audit: {
|
|
15
|
+
agent: "patchwarden-audit",
|
|
16
|
+
keywords: ["审计", "audit", "验收", "verify"],
|
|
17
|
+
},
|
|
18
|
+
/** 复杂推理和重构 → codex */
|
|
19
|
+
refactor: {
|
|
20
|
+
agent: "codex",
|
|
21
|
+
keywords: ["重构", "refactor", "跨模块", "redesign"],
|
|
22
|
+
},
|
|
23
|
+
/** 文档整理 → claude(fallback 到 opencode) */
|
|
24
|
+
documentation: {
|
|
25
|
+
agent: "claude",
|
|
26
|
+
fallbackAgent: "opencode",
|
|
27
|
+
keywords: ["文档", "readme", "changelog", "doc"],
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
// ── Helpers ───────────────────────────────────────────────────────
|
|
31
|
+
function containsAny(text, keywords) {
|
|
32
|
+
return keywords.some((keyword) => text.includes(keyword));
|
|
33
|
+
}
|
|
34
|
+
function resolveRoute(preferred, reason, configuredAgents) {
|
|
35
|
+
if (configuredAgents.includes(preferred)) {
|
|
36
|
+
return { recommended_agent: preferred, reason, fallback: false };
|
|
37
|
+
}
|
|
38
|
+
const fallback = configuredAgents[0];
|
|
39
|
+
return {
|
|
40
|
+
recommended_agent: fallback,
|
|
41
|
+
reason: `fallback: ${preferred} not configured, using ${fallback}`,
|
|
42
|
+
fallback: true,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
// ── Route agent ───────────────────────────────────────────────────
|
|
46
|
+
export function routeAgent(input) {
|
|
47
|
+
if (!input.configuredAgents || input.configuredAgents.length === 0) {
|
|
48
|
+
throw new PatchWardenError("no_agent_configured", "No agent is configured for routing.", "Configure at least one agent in patchwarden.config.json under the agents field.");
|
|
49
|
+
}
|
|
50
|
+
const scopeCount = input.scope?.length ?? 0;
|
|
51
|
+
const text = `${input.goal || ""} ${input.inline_plan || ""}`.toLowerCase();
|
|
52
|
+
// Rule 1: 大规模代码修改 → opencode (scope files > 10)
|
|
53
|
+
if (scopeCount > AGENT_ROUTING_RULES.largeScope.threshold) {
|
|
54
|
+
return resolveRoute(AGENT_ROUTING_RULES.largeScope.agent, `large scope (${scopeCount} files)`, input.configuredAgents);
|
|
55
|
+
}
|
|
56
|
+
// Rule 2: 单文件修改 → patchwarden-direct (scope files === 1)
|
|
57
|
+
if (scopeCount === 1) {
|
|
58
|
+
return resolveRoute(AGENT_ROUTING_RULES.singleFile.agent, "single file scope", input.configuredAgents);
|
|
59
|
+
}
|
|
60
|
+
// Rule 3: 验收审计 → patchwarden-audit
|
|
61
|
+
if (containsAny(text, AGENT_ROUTING_RULES.audit.keywords)) {
|
|
62
|
+
return resolveRoute(AGENT_ROUTING_RULES.audit.agent, "audit keywords", input.configuredAgents);
|
|
63
|
+
}
|
|
64
|
+
// Rule 4: 复杂推理和重构 → codex
|
|
65
|
+
if (containsAny(text, AGENT_ROUTING_RULES.refactor.keywords)) {
|
|
66
|
+
return resolveRoute(AGENT_ROUTING_RULES.refactor.agent, "refactor keywords", input.configuredAgents);
|
|
67
|
+
}
|
|
68
|
+
// Rule 5: 文档整理 → claude(fallback 到 opencode)
|
|
69
|
+
if (containsAny(text, AGENT_ROUTING_RULES.documentation.keywords)) {
|
|
70
|
+
const preferred = AGENT_ROUTING_RULES.documentation.agent;
|
|
71
|
+
const fallbackAgent = AGENT_ROUTING_RULES.documentation.fallbackAgent;
|
|
72
|
+
if (input.configuredAgents.includes(preferred)) {
|
|
73
|
+
return { recommended_agent: preferred, reason: "documentation keywords", fallback: false };
|
|
74
|
+
}
|
|
75
|
+
if (input.configuredAgents.includes(fallbackAgent)) {
|
|
76
|
+
return {
|
|
77
|
+
recommended_agent: fallbackAgent,
|
|
78
|
+
reason: `fallback: ${preferred} not configured, using ${fallbackAgent}`,
|
|
79
|
+
fallback: true,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const firstAgent = input.configuredAgents[0];
|
|
83
|
+
return {
|
|
84
|
+
recommended_agent: firstAgent,
|
|
85
|
+
reason: `fallback: ${preferred} not configured, using ${firstAgent}`,
|
|
86
|
+
fallback: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// Rule 6: 无匹配 → fallback 到 configuredAgents[0]
|
|
90
|
+
return {
|
|
91
|
+
recommended_agent: input.configuredAgents[0],
|
|
92
|
+
reason: `no specific routing rule matched, using default agent ${input.configuredAgents[0]}`,
|
|
93
|
+
fallback: true,
|
|
94
|
+
};
|
|
95
|
+
}
|
package/dist/config.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface PatchWardenConfig {
|
|
|
15
15
|
defaultTaskTimeoutSeconds: number;
|
|
16
16
|
maxTaskTimeoutSeconds: number;
|
|
17
17
|
watcherStaleSeconds: number;
|
|
18
|
-
toolProfile?: "full" | "chatgpt_core" | "chatgpt_direct";
|
|
18
|
+
toolProfile?: "full" | "chatgpt_core" | "chatgpt_direct" | "chatgpt_search";
|
|
19
19
|
repoAliases?: Record<string, string>;
|
|
20
20
|
enableAgentAssessment?: boolean;
|
|
21
21
|
agentAssessmentTimeoutSeconds?: number;
|
package/dist/config.js
CHANGED
|
@@ -175,8 +175,12 @@ function normalizeConfig(config) {
|
|
|
175
175
|
if (!Number.isInteger(config.watcherStaleSeconds) || config.watcherStaleSeconds < 5 || config.watcherStaleSeconds > 3600) {
|
|
176
176
|
throw new Error("watcherStaleSeconds must be an integer from 5 to 3600");
|
|
177
177
|
}
|
|
178
|
-
if (config.toolProfile !== undefined &&
|
|
179
|
-
|
|
178
|
+
if (config.toolProfile !== undefined &&
|
|
179
|
+
config.toolProfile !== "full" &&
|
|
180
|
+
config.toolProfile !== "chatgpt_core" &&
|
|
181
|
+
config.toolProfile !== "chatgpt_direct" &&
|
|
182
|
+
config.toolProfile !== "chatgpt_search") {
|
|
183
|
+
throw new Error('toolProfile must be "full", "chatgpt_core", "chatgpt_direct", or "chatgpt_search"');
|
|
180
184
|
}
|
|
181
185
|
if (config.enableAgentAssessment !== undefined && typeof config.enableAgentAssessment !== "boolean") {
|
|
182
186
|
throw new Error("enableAgentAssessment must be a boolean");
|
package/dist/controlCenter.js
CHANGED
|
@@ -419,6 +419,7 @@ function resolveWorkspaceRootSafe() {
|
|
|
419
419
|
}
|
|
420
420
|
const TERMINAL_TASK_STATUSES = new Set([
|
|
421
421
|
"done",
|
|
422
|
+
"done_by_agent",
|
|
422
423
|
"failed",
|
|
423
424
|
"failed_verification",
|
|
424
425
|
"failed_scope_violation",
|
|
@@ -928,13 +929,19 @@ function handleReconcile(res, taskId) {
|
|
|
928
929
|
const statusData = readJsonFileSafe(statusPath) ?? {};
|
|
929
930
|
const runtimeData = readJsonFileSafe(runtimePath) ?? {};
|
|
930
931
|
const watcher = readWatcherStatusSafe();
|
|
932
|
+
const VALID_ACCEPTANCE = ["pending", "accepted", "rejected", "needs_fix", "blocked"];
|
|
933
|
+
const taskStatus = String(statusData.status || "pending");
|
|
934
|
+
const taskAcceptanceStatus = taskStatus === "done_by_agent"
|
|
935
|
+
? (typeof statusData.acceptance_status === "string" && VALID_ACCEPTANCE.includes(statusData.acceptance_status) ? statusData.acceptance_status : "pending")
|
|
936
|
+
: null;
|
|
931
937
|
const taskEntry = {
|
|
932
938
|
task_id: taskId,
|
|
933
939
|
plan_id: String(statusData.plan_id || ""),
|
|
934
940
|
title: "",
|
|
935
941
|
agent: String(statusData.agent || ""),
|
|
936
|
-
status:
|
|
942
|
+
status: taskStatus,
|
|
937
943
|
phase: String(runtimeData.phase || statusData.phase || "queued"),
|
|
944
|
+
acceptance_status: taskAcceptanceStatus,
|
|
938
945
|
created_at: String(statusData.created_at || ""),
|
|
939
946
|
updated_at: String(statusData.updated_at || ""),
|
|
940
947
|
workspace_root: String(statusData.workspace_root || config.workspaceRoot),
|
|
@@ -1072,13 +1079,19 @@ function handleTaskDetail(res, taskId) {
|
|
|
1072
1079
|
let stale = null;
|
|
1073
1080
|
if (statusData) {
|
|
1074
1081
|
const watcher = readWatcherStatusSafe();
|
|
1082
|
+
const VALID_ACCEPTANCE2 = ["pending", "accepted", "rejected", "needs_fix", "blocked"];
|
|
1083
|
+
const taskStatus2 = String(statusData.status || "pending");
|
|
1084
|
+
const taskAcceptanceStatus2 = taskStatus2 === "done_by_agent"
|
|
1085
|
+
? (typeof statusData.acceptance_status === "string" && VALID_ACCEPTANCE2.includes(statusData.acceptance_status) ? statusData.acceptance_status : "pending")
|
|
1086
|
+
: null;
|
|
1075
1087
|
const entry = {
|
|
1076
1088
|
task_id: taskId,
|
|
1077
1089
|
plan_id: String(statusData.plan_id || ""),
|
|
1078
1090
|
title: "",
|
|
1079
1091
|
agent: String(statusData.agent || ""),
|
|
1080
|
-
status:
|
|
1092
|
+
status: taskStatus2,
|
|
1081
1093
|
phase: String(runtimeData?.phase || statusData.phase || "queued"),
|
|
1094
|
+
acceptance_status: taskAcceptanceStatus2,
|
|
1082
1095
|
created_at: String(statusData.created_at || ""),
|
|
1083
1096
|
updated_at: String(statusData.updated_at || ""),
|
|
1084
1097
|
workspace_root: String(statusData.workspace_root || config.workspaceRoot),
|
package/dist/doctor.js
CHANGED
|
@@ -18,6 +18,9 @@ import { guardPlanContent } from "./security/planGuard.js";
|
|
|
18
18
|
import { TASK_READ_ONLY_FILES } from "./tools/getTaskFile.js";
|
|
19
19
|
import { getToolDefs } from "./tools/registry.js";
|
|
20
20
|
import { CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES, selectToolsForProfile } from "./tools/toolCatalog.js";
|
|
21
|
+
import { buildToolRegistry } from "./tools/toolRegistry.js";
|
|
22
|
+
import { runAllSchemaDriftChecks } from "./tools/schemaDriftCheck.js";
|
|
23
|
+
import { runReleaseGateCheck } from "./release/releaseGate.js";
|
|
21
24
|
import { PATCHWARDEN_VERSION } from "./version.js";
|
|
22
25
|
// ── State ──────────────────────────────────────────────────────────
|
|
23
26
|
let ok = 0;
|
|
@@ -218,7 +221,7 @@ async function main() {
|
|
|
218
221
|
const coreTools = selectToolsForProfile(fullTools, "chatgpt_core", config?.enableDirectProfile);
|
|
219
222
|
const createSchema = coreTools.find((tool) => tool.name === "create_task")?.inputSchema;
|
|
220
223
|
const waitSchema = coreTools.find((tool) => tool.name === "wait_for_task")?.inputSchema;
|
|
221
|
-
check("Full tool profile exposes
|
|
224
|
+
check("Full tool profile exposes 54 tools", fullTools.length === 54, `${fullTools.length} tools`);
|
|
222
225
|
check(`chatgpt_core profile exposes the exact ${CHATGPT_CORE_TOOL_NAMES.length}-tool manifest`, JSON.stringify(coreTools.map((tool) => tool.name)) === JSON.stringify(CHATGPT_CORE_TOOL_NAMES), coreTools.map((tool) => tool.name).join(", "));
|
|
223
226
|
check("Core task schemas expose inline_plan, verify_commands, and wait aliases", Boolean(createSchema?.properties?.inline_plan &&
|
|
224
227
|
createSchema?.properties?.verify_commands &&
|
|
@@ -235,6 +238,25 @@ async function main() {
|
|
|
235
238
|
results.push(`[OK] chatgpt_direct enabled check skipped (enableDirectProfile=false)`);
|
|
236
239
|
ok++;
|
|
237
240
|
}
|
|
241
|
+
// 16. Schema drift 检查(v0.9.0)—— warn 级别,不阻断 doctor:ci
|
|
242
|
+
// 用 fullTools 同时构建 registry 和 toolDefs Map,确保 schema digest 比对基准一致。
|
|
243
|
+
const driftRegistry = buildToolRegistry(fullTools);
|
|
244
|
+
const driftToolDefs = new Map();
|
|
245
|
+
for (const tool of fullTools) {
|
|
246
|
+
driftToolDefs.set(tool.name, { inputSchema: tool.inputSchema });
|
|
247
|
+
}
|
|
248
|
+
const driftResult = runAllSchemaDriftChecks(driftRegistry, driftToolDefs);
|
|
249
|
+
if (driftResult.ok) {
|
|
250
|
+
results.push(`[OK] Schema drift check — no drift detected`);
|
|
251
|
+
ok++;
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// 每个 warning 单独输出为 WARN,与其他自检项的多警告模式一致
|
|
255
|
+
for (const w of driftResult.warnings) {
|
|
256
|
+
results.push(`[WARN] Schema drift: ${w}`);
|
|
257
|
+
warn++;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
238
260
|
}
|
|
239
261
|
finally {
|
|
240
262
|
if (previousProfile === undefined)
|
|
@@ -242,6 +264,15 @@ async function main() {
|
|
|
242
264
|
else
|
|
243
265
|
process.env.PATCHWARDEN_TOOL_PROFILE = previousProfile;
|
|
244
266
|
}
|
|
267
|
+
// 17. Release gate module loadable (v1.0.0) — module integrity only.
|
|
268
|
+
// Does NOT execute local_ready (would recurse into doctor:ci).
|
|
269
|
+
try {
|
|
270
|
+
const releaseGateReady = typeof runReleaseGateCheck === "function";
|
|
271
|
+
check("Release gate module loadable", releaseGateReady, releaseGateReady ? "runReleaseGateCheck exported" : "runReleaseGateCheck missing or invalid");
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
check("Release gate module loadable", false, error instanceof Error ? error.message : String(error));
|
|
275
|
+
}
|
|
245
276
|
// 9. HTTP port check
|
|
246
277
|
const httpPort = config?.http?.port || 7331;
|
|
247
278
|
try {
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v0.7.2: 验收引擎 — 基于证据推导 4 级验收结论。
|
|
3
|
+
*
|
|
4
|
+
* 输入:status.json、task_meta(goal/scope/forbidden/verification/done_evidence)、
|
|
5
|
+
* audit checks(pass/warn/fail)、release claims、artifact 信息
|
|
6
|
+
* 输出:ACCEPTED / NEEDS_FIX / REJECTED / BLOCKED_BY_APPROVAL
|
|
7
|
+
* + reasons + required_evidence + next_suggested_task
|
|
8
|
+
*
|
|
9
|
+
* 决策规则:
|
|
10
|
+
* 1. 存在 fail 级检查项 → REJECTED
|
|
11
|
+
* 2. 存在 release claims 但无法验证远端 → BLOCKED_BY_APPROVAL
|
|
12
|
+
* 3. 存在 warn 级检查项或文档不同步 → NEEDS_FIX
|
|
13
|
+
* 4. 所有检查通过 → ACCEPTED
|
|
14
|
+
*/
|
|
15
|
+
import type { AcceptanceStatus } from "../tools/createTask.js";
|
|
16
|
+
export type AcceptanceVerdict = "ACCEPTED" | "NEEDS_FIX" | "REJECTED" | "BLOCKED_BY_APPROVAL";
|
|
17
|
+
export interface AcceptanceCheck {
|
|
18
|
+
name: string;
|
|
19
|
+
result: "pass" | "warn" | "fail";
|
|
20
|
+
detail: string;
|
|
21
|
+
}
|
|
22
|
+
export interface AcceptanceEvidence {
|
|
23
|
+
task_id: string;
|
|
24
|
+
task_status: string;
|
|
25
|
+
result_md_exists: boolean;
|
|
26
|
+
result_json_exists: boolean;
|
|
27
|
+
verify_json_exists: boolean;
|
|
28
|
+
test_log_exists: boolean;
|
|
29
|
+
git_diff_exists: boolean;
|
|
30
|
+
verify_status: "passed" | "failed" | "skipped" | null;
|
|
31
|
+
new_out_of_scope_changes: Array<{
|
|
32
|
+
path: string;
|
|
33
|
+
change: string;
|
|
34
|
+
}>;
|
|
35
|
+
goal: string | null;
|
|
36
|
+
scope: string[] | null;
|
|
37
|
+
forbidden: string[] | null;
|
|
38
|
+
verification: string[] | null;
|
|
39
|
+
done_evidence: string[] | null;
|
|
40
|
+
artifact_status: string | null;
|
|
41
|
+
release_claims_unverified: boolean;
|
|
42
|
+
checks: AcceptanceCheck[];
|
|
43
|
+
}
|
|
44
|
+
export interface AcceptanceResult {
|
|
45
|
+
verdict: AcceptanceVerdict;
|
|
46
|
+
acceptance_status: AcceptanceStatus;
|
|
47
|
+
reason: string;
|
|
48
|
+
reasons: string[];
|
|
49
|
+
required_evidence: string[];
|
|
50
|
+
next_suggested_task: string;
|
|
51
|
+
fail_checks: AcceptanceCheck[];
|
|
52
|
+
warn_checks: AcceptanceCheck[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 核心验收决策函数。
|
|
56
|
+
* 输入所有证据,输出 4 级验收结论。
|
|
57
|
+
*/
|
|
58
|
+
export declare function evaluateAcceptance(evidence: AcceptanceEvidence): AcceptanceResult;
|
|
59
|
+
/**
|
|
60
|
+
* 将 AcceptanceVerdict 映射到 AcceptanceStatus(用于回写 status.json)。
|
|
61
|
+
*/
|
|
62
|
+
export declare function verdictToStatus(verdict: AcceptanceVerdict): AcceptanceStatus;
|