patchwarden 0.4.0 → 0.6.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 (189) hide show
  1. package/PatchWarden.cmd +51 -0
  2. package/README.en.md +1022 -0
  3. package/README.md +897 -358
  4. package/dist/assessments/agentAssessor.d.ts +15 -0
  5. package/dist/assessments/agentAssessor.js +293 -0
  6. package/dist/assessments/assessmentStore.d.ts +133 -0
  7. package/dist/assessments/assessmentStore.js +238 -0
  8. package/dist/assessments/confirmCli.d.ts +9 -0
  9. package/dist/assessments/confirmCli.js +26 -0
  10. package/dist/config.d.ts +22 -1
  11. package/dist/config.js +156 -3
  12. package/dist/direct/directAudit.d.ts +23 -0
  13. package/dist/direct/directAudit.js +309 -0
  14. package/dist/direct/directGuards.d.ts +20 -0
  15. package/dist/direct/directGuards.js +137 -0
  16. package/dist/direct/directPatch.d.ts +17 -0
  17. package/dist/direct/directPatch.js +113 -0
  18. package/dist/direct/directSessionStore.d.ts +63 -0
  19. package/dist/direct/directSessionStore.js +192 -0
  20. package/dist/direct/directVerification.d.ts +12 -0
  21. package/dist/direct/directVerification.js +96 -0
  22. package/dist/doctor.js +73 -5
  23. package/dist/logging.d.ts +52 -0
  24. package/dist/logging.js +123 -0
  25. package/dist/runner/agentInvocation.d.ts +23 -0
  26. package/dist/runner/agentInvocation.js +106 -0
  27. package/dist/runner/changeCapture.d.ts +70 -0
  28. package/dist/runner/changeCapture.js +278 -6
  29. package/dist/runner/runTask.js +271 -65
  30. package/dist/runner/simpleProcess.d.ts +21 -0
  31. package/dist/runner/simpleProcess.js +206 -0
  32. package/dist/runner/watch.js +17 -2
  33. package/dist/security/commandGuard.d.ts +2 -1
  34. package/dist/security/commandGuard.js +25 -3
  35. package/dist/security/riskEngine.d.ts +27 -0
  36. package/dist/security/riskEngine.js +118 -0
  37. package/dist/security/runtimeGuard.d.ts +6 -0
  38. package/dist/security/runtimeGuard.js +28 -0
  39. package/dist/smoke-test.js +1353 -7
  40. package/dist/test/unit/android-doctor.test.d.ts +1 -0
  41. package/dist/test/unit/android-doctor.test.js +118 -0
  42. package/dist/test/unit/chinese-path.test.d.ts +1 -0
  43. package/dist/test/unit/chinese-path.test.js +91 -0
  44. package/dist/test/unit/command-guard.test.d.ts +1 -0
  45. package/dist/test/unit/command-guard.test.js +160 -0
  46. package/dist/test/unit/direct-guards.test.d.ts +1 -0
  47. package/dist/test/unit/direct-guards.test.js +213 -0
  48. package/dist/test/unit/logging.test.d.ts +1 -0
  49. package/dist/test/unit/logging.test.js +275 -0
  50. package/dist/test/unit/path-guard.test.d.ts +1 -0
  51. package/dist/test/unit/path-guard.test.js +109 -0
  52. package/dist/test/unit/safe-status.test.d.ts +1 -0
  53. package/dist/test/unit/safe-status.test.js +165 -0
  54. package/dist/test/unit/sensitive-guard.test.d.ts +1 -0
  55. package/dist/test/unit/sensitive-guard.test.js +104 -0
  56. package/dist/test/unit/sync-file.test.d.ts +1 -0
  57. package/dist/test/unit/sync-file.test.js +154 -0
  58. package/dist/test/unit/watcher-status.test.d.ts +1 -0
  59. package/dist/test/unit/watcher-status.test.js +169 -0
  60. package/dist/tools/androidDoctor.d.ts +38 -0
  61. package/dist/tools/androidDoctor.js +391 -0
  62. package/dist/tools/applyPatch.d.ts +16 -0
  63. package/dist/tools/applyPatch.js +41 -0
  64. package/dist/tools/auditSession.d.ts +5 -0
  65. package/dist/tools/auditSession.js +12 -0
  66. package/dist/tools/auditTask.d.ts +7 -0
  67. package/dist/tools/auditTask.js +105 -7
  68. package/dist/tools/createDirectSession.d.ts +14 -0
  69. package/dist/tools/createDirectSession.js +54 -0
  70. package/dist/tools/createTask.d.ts +48 -1
  71. package/dist/tools/createTask.js +298 -47
  72. package/dist/tools/finalizeDirectSession.d.ts +19 -0
  73. package/dist/tools/finalizeDirectSession.js +84 -0
  74. package/dist/tools/getTaskSummary.d.ts +50 -0
  75. package/dist/tools/getTaskSummary.js +79 -2
  76. package/dist/tools/healthCheck.d.ts +27 -12
  77. package/dist/tools/healthCheck.js +44 -6
  78. package/dist/tools/readWorkspaceFile.d.ts +7 -1
  79. package/dist/tools/readWorkspaceFile.js +48 -2
  80. package/dist/tools/registry.js +270 -19
  81. package/dist/tools/runVerification.d.ts +16 -0
  82. package/dist/tools/runVerification.js +32 -0
  83. package/dist/tools/safeStatus.d.ts +19 -0
  84. package/dist/tools/safeStatus.js +72 -0
  85. package/dist/tools/savePlan.d.ts +1 -0
  86. package/dist/tools/savePlan.js +38 -7
  87. package/dist/tools/searchWorkspace.d.ts +19 -0
  88. package/dist/tools/searchWorkspace.js +205 -0
  89. package/dist/tools/syncFile.d.ts +18 -0
  90. package/dist/tools/syncFile.js +65 -0
  91. package/dist/tools/taskOutputs.d.ts +2 -2
  92. package/dist/tools/taskTemplates.js +2 -1
  93. package/dist/tools/toolCatalog.d.ts +4 -3
  94. package/dist/tools/toolCatalog.js +34 -5
  95. package/dist/tools/waitForTask.d.ts +2 -2
  96. package/dist/tools/waitForTask.js +1 -1
  97. package/dist/version.d.ts +2 -2
  98. package/dist/version.js +2 -2
  99. package/dist/watcherStatus.d.ts +1 -0
  100. package/dist/watcherStatus.js +96 -4
  101. package/docs/chatgpt-usage.md +101 -0
  102. package/docs/performance-notes.md +55 -0
  103. package/docs/release-checklist.md +14 -0
  104. package/docs/release-v0.6.0.md +71 -0
  105. package/docs/release-v0.6.1.md +75 -0
  106. package/examples/config.example.json +5 -0
  107. package/examples/openai-tunnel/README.md +11 -4
  108. package/examples/openai-tunnel/chatgpt-test-prompt.md +18 -14
  109. package/examples/openai-tunnel/tunnel-client.example.yaml +8 -0
  110. package/package.json +13 -8
  111. package/scripts/brand-check.js +58 -12
  112. package/scripts/control-smoke.js +206 -0
  113. package/scripts/http-mcp-smoke.js +10 -2
  114. package/scripts/launchers/Check-PatchWarden-Health.cmd +6 -0
  115. package/scripts/launchers/Reset-PatchWarden-Tunnel-Key.cmd +6 -0
  116. package/scripts/launchers/Restart-PatchWarden.cmd +6 -0
  117. package/scripts/launchers/Start-PatchWarden-Direct-Tunnel.cmd +7 -0
  118. package/scripts/launchers/Start-PatchWarden-Tunnel.cmd +7 -0
  119. package/scripts/lifecycle-smoke.js +402 -8
  120. package/scripts/manage-patchwarden.ps1 +639 -0
  121. package/scripts/mcp-manifest-check.js +123 -58
  122. package/scripts/mcp-smoke.js +160 -2
  123. package/scripts/pack-clean.js +160 -5
  124. package/scripts/package-manifest-check.js +78 -0
  125. package/scripts/patchwarden-mcp-direct.cmd +7 -0
  126. package/scripts/patchwarden-mcp-stdio.cmd +1 -1
  127. package/scripts/restart-patchwarden.ps1 +5 -4
  128. package/scripts/start-patchwarden-tunnel.ps1 +261 -30
  129. package/scripts/tunnel-supervisor-smoke.js +36 -4
  130. package/scripts/unit-tests.js +36 -0
  131. package/scripts/watcher-supervisor-smoke.js +10 -6
  132. package/src/assessments/agentAssessor.ts +324 -0
  133. package/src/assessments/assessmentStore.ts +426 -0
  134. package/src/assessments/confirmCli.ts +29 -0
  135. package/src/config.ts +178 -4
  136. package/src/direct/directAudit.ts +400 -0
  137. package/src/direct/directGuards.ts +279 -0
  138. package/src/direct/directPatch.ts +258 -0
  139. package/src/direct/directSessionStore.ts +345 -0
  140. package/src/direct/directVerification.ts +138 -0
  141. package/src/doctor.ts +103 -7
  142. package/src/logging.ts +152 -0
  143. package/src/runner/agentInvocation.ts +125 -0
  144. package/src/runner/changeCapture.ts +352 -6
  145. package/src/runner/runTask.ts +279 -63
  146. package/src/runner/simpleProcess.ts +223 -0
  147. package/src/runner/watch.ts +18 -2
  148. package/src/security/commandGuard.ts +46 -4
  149. package/src/security/riskEngine.ts +160 -0
  150. package/src/security/runtimeGuard.ts +41 -0
  151. package/src/smoke-test.ts +1291 -4
  152. package/src/test/unit/android-doctor.test.ts +158 -0
  153. package/src/test/unit/chinese-path.test.ts +106 -0
  154. package/src/test/unit/command-guard.test.ts +221 -0
  155. package/src/test/unit/direct-guards.test.ts +297 -0
  156. package/src/test/unit/logging.test.ts +325 -0
  157. package/src/test/unit/path-guard.test.ts +150 -0
  158. package/src/test/unit/safe-status.test.ts +187 -0
  159. package/src/test/unit/sensitive-guard.test.ts +124 -0
  160. package/src/test/unit/sync-file.test.ts +231 -0
  161. package/src/test/unit/watcher-status.test.ts +190 -0
  162. package/src/tools/androidDoctor.ts +424 -0
  163. package/src/tools/applyPatch.ts +86 -0
  164. package/src/tools/auditSession.ts +28 -0
  165. package/src/tools/auditTask.ts +111 -7
  166. package/src/tools/createDirectSession.ts +113 -0
  167. package/src/tools/createTask.ts +405 -55
  168. package/src/tools/finalizeDirectSession.ts +144 -0
  169. package/src/tools/getTaskSummary.ts +133 -2
  170. package/src/tools/healthCheck.ts +45 -6
  171. package/src/tools/readWorkspaceFile.ts +85 -2
  172. package/src/tools/registry.ts +305 -19
  173. package/src/tools/runVerification.ts +58 -0
  174. package/src/tools/safeStatus.ts +96 -0
  175. package/src/tools/savePlan.ts +57 -7
  176. package/src/tools/searchWorkspace.ts +275 -0
  177. package/src/tools/syncFile.ts +122 -0
  178. package/src/tools/taskTemplates.ts +2 -1
  179. package/src/tools/toolCatalog.ts +37 -6
  180. package/src/tools/waitForTask.ts +3 -3
  181. package/src/version.ts +2 -2
  182. package/src/watcherStatus.ts +101 -4
  183. package/tsconfig.json +18 -17
  184. package/Check-PatchWarden-Health.cmd +0 -6
  185. package/Reset-PatchWarden-Tunnel-Key.cmd +0 -6
  186. package/Restart-PatchWarden.cmd +0 -19
  187. package/Start-PatchWarden-Tunnel.cmd +0 -7
  188. package/docs/release-v0.3.0.md +0 -43
  189. package/docs/release-v0.4.0.md +0 -74
@@ -0,0 +1,101 @@
1
+ # ChatGPT 调用规范 / ChatGPT usage guide
2
+
3
+ ## 中文
4
+
5
+ 这套约定用于降低长参数、长轮询、构建产物和完整日志触发连接器误拦截的概率,同时保留 PatchWarden 的本地安全边界和完整证据。
6
+
7
+ 1. 一个任务只处理一个目标;功能实现、耗时构建和 Git/发布收尾分开执行。
8
+ 2. 计划标题使用短英文 slug,详细说明放在目标或计划正文中。
9
+ 3. ChatGPT 优先使用守护模板:只读诊断用 `inspect_only`,小范围修改用 `feature_small`,修复已知失败用 `fix_tests`。模板不够表达目标时才使用 `inline_plan` 或保存的长计划。
10
+ 4. 创建任务时优先采用 assess → execute 两步流程。execute 必须直接使用 assess 返回的 `next_tool_call`,不要重复发送 goal、plan、repo、agent 或验证命令。
11
+ 5. 短任务可以调用 `wait_for_task(timeout_seconds: 25)`;长任务使用 `list_tasks(repo_path=..., active_only=true)` 和 `get_task_status`。
12
+ 6. 终态先读取 `get_task_summary(view: "compact")` 和 `audit_task`;证据不足时才读取 standard 摘要、完整 diff 或日志。
13
+ 7. 构建验证与源码任务分开。`artifact_hygiene` 会区分源码、已跟踪构建物、忽略产物、运行态文件和可疑变更。
14
+ 8. PatchWarden 保留未提交改动供人工审核;提交、推送和发布不属于普通任务范围。
15
+
16
+ ### assess → execute
17
+
18
+ 第一步发送完整目标:
19
+
20
+ ```json
21
+ {
22
+ "tool": "create_task",
23
+ "execution_mode": "assess_only",
24
+ "template": "feature_small",
25
+ "goal": "Add a bounded activity timeline UI",
26
+ "agent": "opencode",
27
+ "repo_path": "my-project",
28
+ "verify_commands": ["npm test"]
29
+ }
30
+ ```
31
+
32
+ 当 `decision` 为 `allow` 时,响应会包含结构化的最小调用:
33
+
34
+ ```json
35
+ {
36
+ "next_tool_call": {
37
+ "name": "create_task",
38
+ "arguments": {
39
+ "execution_mode": "execute",
40
+ "assessment_id": "assessment_20260622_143000_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
41
+ }
42
+ }
43
+ }
44
+ ```
45
+
46
+ 请原样调用 `next_tool_call`。完整的 128-bit `assessment_id` 用于执行;`assessment_short_id` 仅用于展示。工作区、计划、策略或工具清单变化后会返回 `assessment_stale_*`,此时必须重新 assess。
47
+
48
+ 当 `decision` 为 `needs_confirm` 时,用户需要在使用同一份本地配置的终端运行:
49
+
50
+ ```powershell
51
+ patchwarden-confirm assessment_20260622_143000_a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
52
+ ```
53
+
54
+ 确认入口不属于 MCP 工具,远程调用者不能自行确认。确认后再原样调用返回的 `next_tool_call`;`blocked` 票据不能确认或执行。
55
+
56
+ ### audit_task 结果解释
57
+
58
+ - `confirmed_failures`:证据已经明确的失败,例如非零测试退出码、越界变更或失败状态。
59
+ - `possible_false_positives`:启发式规则可能产生的误报,例如文档属于其他包、构建物是有意跟踪的发布资产。
60
+ - `manual_verification_required` / `manual_verification_items`:需要人工或远程权威来源核实的事项。
61
+
62
+ 因此 `verdict: "warn"` 不等于任务一定有错。应先核实上述字段,再决定是否接受结果。
63
+
64
+ 仓库专属验证命令只能配置在本机可信的 `patchwarden.config.json` 中:
65
+
66
+ ```json
67
+ {
68
+ "repoAllowedTestCommands": {
69
+ "desktop-app": ["npm run release:check"]
70
+ }
71
+ }
72
+ ```
73
+
74
+ 路径和命令都采用精确匹配,不支持通配符,也不会读取目标仓库的 `package.json` 自动授权。
75
+
76
+ ## English
77
+
78
+ These conventions reduce connector false positives while preserving local
79
+ safety boundaries and complete evidence.
80
+
81
+ 1. Keep one goal per task; separate feature work, expensive builds, and
82
+ Git/release handoff.
83
+ 2. Use a short English slug for the title.
84
+ 3. Prefer guarded templates: `inspect_only` for diagnosis, `feature_small` for
85
+ a scoped change, and `fix_tests` for a known failure. Use a long plan only
86
+ when a template cannot express the goal.
87
+ 4. Prefer assess → execute. Invoke the returned `next_tool_call` unchanged and
88
+ do not resend goal, plan, repository, agent, or verification arguments.
89
+ 5. Poll long tasks with `list_tasks` and `get_task_status`; inspect
90
+ `get_task_summary(view: "compact")` before full logs or diffs.
91
+ 6. Run build/package validation separately from source implementation.
92
+ 7. Changes remain uncommitted for review; commit, push, and publish are outside
93
+ the ordinary task scope.
94
+
95
+ `needs_confirm` assessments must be confirmed locally with
96
+ `patchwarden-confirm <full_assessment_id>`. The confirmation command is not an
97
+ MCP tool. A `blocked` assessment cannot be confirmed.
98
+
99
+ In `audit_task`, evidence-backed failures appear in `confirmed_failures`,
100
+ heuristic warnings in `possible_false_positives`, and unresolved checks in
101
+ `manual_verification_items`. A warning is not automatically a confirmed error.
@@ -0,0 +1,55 @@
1
+ # PatchWarden Performance Notes
2
+
3
+ ## Current State (v0.6.1)
4
+
5
+ ### Identified Optimization Opportunities
6
+
7
+ The following performance optimizations have been identified for future implementation. They are documented here rather than implemented in v0.6.1 to avoid introducing risk to the core task execution path.
8
+
9
+ ### 1. Async Git Operations in changeCapture.ts
10
+
11
+ **Current**: `runGit()` uses `spawnSync()` which blocks the event loop during git operations.
12
+
13
+ **Proposed**: Replace with `execFile()` (async) and use `Promise.all()` for independent git queries in `captureRepoSnapshot()`.
14
+
15
+ **Risk**: Medium — changes the core change capture path. Requires careful testing of all snapshot/diff/scope scenarios.
16
+
17
+ **Expected Benefit**: ~200-500ms improvement per task for repos with many files, as multiple git queries can run concurrently.
18
+
19
+ ### 2. Streaming File Hash
20
+
21
+ **Current**: `computeFileSha256()` reads the entire file into memory with `readFileSync()`.
22
+
23
+ **Proposed**: Use `createReadStream()` + `crypto.createHash()` for streaming hash computation.
24
+
25
+ **Risk**: Low — isolated to hash computation, no semantic change.
26
+
27
+ **Expected Benefit**: Reduces peak memory usage for large files (e.g., release artifacts > 5MB).
28
+
29
+ ### 3. Workspace Snapshot Caching
30
+
31
+ **Current**: `walkWorkspace()` traverses the entire workspace directory tree on every snapshot.
32
+
33
+ **Proposed**: Cache the directory listing and invalidate on file modification events.
34
+
35
+ **Risk**: High — requires file system watchers and cache invalidation logic. Could introduce stale data bugs.
36
+
37
+ **Expected Benefit**: ~100-1000ms improvement for large workspaces with many repos.
38
+
39
+ ### 4. Parallel Task Status Reads
40
+
41
+ **Current**: `listTasks()` reads each task's `status.json` sequentially.
42
+
43
+ **Proposed**: Use `Promise.all()` to read multiple task status files concurrently.
44
+
45
+ **Risk**: Low — read-only operation, no semantic change.
46
+
47
+ **Expected Benefit**: ~50-200ms improvement when listing 10+ tasks.
48
+
49
+ ## Decision for v0.6.1
50
+
51
+ All four optimizations are deferred to a future release. The current synchronous implementation is correct and well-tested. Changing the core paths would require extensive regression testing that is beyond the scope of this stability release.
52
+
53
+ ## Monitoring
54
+
55
+ The structured logging module (`src/logging.ts`) added in v0.6.1 provides the infrastructure to measure tool call durations (`duration_ms` in audit logs). Once deployed, real-world timing data can be collected to prioritize which optimization to implement first.
@@ -0,0 +1,14 @@
1
+ # Manual release checklist
2
+
3
+ PatchWarden releases remain confirmation-gated. Creating a tag or GitHub Release does not publish npm automatically.
4
+
5
+ 1. Work on a release branch and update `package.json`, changelog/release notes, README, examples, and tool manifests together.
6
+ 2. Run the complete local quality gates from `AGENTS.md`.
7
+ 3. Open a pull request, wait for `CI gate`, review the diff and package contents, then merge.
8
+ 4. Create the version tag from the verified merge commit.
9
+ 5. Create the GitHub Release and attach only reviewed release artifacts and checksums.
10
+ 6. Publish `patchwarden` to npm using process-scoped authentication; never store the raw token in the repository.
11
+ 7. Verify `gh release view`, the remote tag, `npm.cmd view patchwarden version`, and `dist-tags.latest`.
12
+ 8. Update or close the associated issue only after remote verification succeeds.
13
+
14
+ Do not publish new versions under the frozen pre-rename package name.
@@ -0,0 +1,71 @@
1
+ # PatchWarden v0.6.0
2
+
3
+ PatchWarden v0.6.0 在保持 `chatgpt_core` 固定 16 工具兼容的同时,加入默认关闭的
4
+ `chatgpt_direct` 安全直接开发模式、本地 assess → confirm → execute 闭环,以及更可靠的
5
+ Windows Core/Direct 双通道运行管理。
6
+
7
+ ## 主要更新
8
+
9
+ ### ChatGPT Core 安全体验
10
+
11
+ - `assess_only` 返回最小化的结构化 `next_tool_call`;execute 只需
12
+ `execution_mode` 和完整 `assessment_id`,不再重复传输目标、计划和仓库参数。
13
+ - 中风险票据通过本地 `patchwarden-confirm <full_assessment_id>` 确认。该入口不是 MCP
14
+ 工具,远程调用者不能自行放行。
15
+ - 确认和执行会重新校验票据时效、工作区、计划、策略和工具 Manifest。
16
+ - `audit_task` 将已确认失败、可能误报和人工核查项分开呈现。
17
+ - `get_task_summary(view: "compact")` 和终态 `wait_for_task` 返回有界验收证据,避免长任务
18
+ 结果淹没客户端上下文。
19
+
20
+ ### ChatGPT Direct 模式
21
+
22
+ - 默认关闭;启用需设置 `enableDirectProfile: true` 并使用 `chatgpt_direct` Profile。
23
+ - 固定 9 工具:健康检查、工作区列表、会话创建、搜索、文件读取、JSON 补丁、白名单
24
+ 验证、会话完成和独立审计。
25
+ - 所有写操作绑定 Direct session 和内容哈希;不支持任意 shell、删除/重命名、Git 推送、
26
+ npm 发布或远程部署。
27
+
28
+ ### Windows Core/Direct 控制与可观测性
29
+
30
+ - 根目录统一使用 `PatchWarden.cmd`,支持 Core、Direct 或两者的
31
+ `start`、`stop`、`restart`、`status`、`health` 和受限 `kill`。
32
+ - Core 和 Direct 分别使用 `127.0.0.1:8080` 与 `127.0.0.1:8081`,并自动校正各自
33
+ tunnel profile 的 health 地址。
34
+ - supervisor 将 stdout/stderr 写入各自 runtime 目录;非零退出时显示 stderr 最后 30 行,
35
+ 并把退出码、脱敏 tail 和日志路径写入 `tunnel-status.json`。
36
+ - 修复 Core watcher 的 `XDG_CONFIG_HOME` 泄漏到 tunnel-client,导致 Core 错误读取
37
+ `%LOCALAPPDATA%\patchwarden\opencode-config\tunnel-client\patchwarden.yaml` 并反复退出的问题。
38
+ - `stop` / `restart` 可清理 Profile 精确匹配的遗留 tunnel-client;无关端口占用只报告、不误杀。
39
+ - `status` 支持 health endpoint fallback,陈旧 JSON 不再把实际 ready 的实例误报为 stopped。
40
+ - 旧的单用途入口迁入 `scripts/launchers/`;个人 `.local/launchers/`、运行时配置、凭据和日志
41
+ 不进入 Git、npm 包或 GitHub 发布资产。
42
+
43
+ ## 兼容性
44
+
45
+ - `chatgpt_core` 仍为固定 16 工具;`chatgpt_direct` 为固定 9 工具。
46
+ - schema epoch 为 `2026-06-22-v6`。
47
+ - `assess_only`、`execute`、`assessment_id`、`plan_ref` 和既有任务记录保持兼容。
48
+ - npm 包名保持 `patchwarden`;旧的 `safe-bifrost` 包继续冻结在 v0.3.0。
49
+
50
+ ## 验证
51
+
52
+ 发布候选通过以下门禁:
53
+
54
+ ```powershell
55
+ npm.cmd run build
56
+ npm.cmd test
57
+ npm.cmd run check:tool-manifest
58
+ npm.cmd run check:direct-tool-manifest
59
+ npm.cmd run test:mcp
60
+ npm.cmd run test:http-mcp
61
+ npm.cmd run doctor:ci
62
+ npm.cmd run pack:clean
63
+ npm.cmd run verify:package
64
+ git diff --check
65
+ ```
66
+
67
+ 本机双通道验收确认 Core 16 工具和 Direct 9 工具均为 `running`、`ready=true`,8080/8081
68
+ 由对应 `tunnel-client.exe` 监听,两个 `/readyz` 均返回 `ready`。
69
+
70
+ GitHub Release 与 npm Registry 是独立发布面。创建 Tag/Release 不会自动发布 npm;npm 发布后
71
+ 仍需单独核对 `patchwarden@latest`、版本时间、dist-tag 和包完整性。
@@ -0,0 +1,75 @@
1
+ # PatchWarden v0.6.1 Release Notes
2
+
3
+ **Release Date**: 2026-06-25
4
+
5
+ ## Overview
6
+
7
+ PatchWarden v0.6.1 is a stability and observability release. It addresses watcher heartbeat false positives, adds Chinese path reliability, introduces two new tools (`safe_status` and `sync_file`), and adds comprehensive security guard unit tests.
8
+
9
+ ## New Features
10
+
11
+ ### safe_status Tool
12
+
13
+ A minimal task lifecycle status tool that returns task state without exposing diff, log content, or file contents. Useful when upper-layer security policies block content-bearing tools.
14
+
15
+ ```json
16
+ {
17
+ "task_id": "task-001",
18
+ "status": "running",
19
+ "phase": "executing_agent",
20
+ "last_heartbeat_at": "2026-06-24T10:00:12Z",
21
+ "current_command": "codex exec",
22
+ "watcher_state": "healthy"
23
+ }
24
+ ```
25
+
26
+ ### sync_file Tool
27
+
28
+ Copy a file from source to target within a Direct session repo. Both paths must be inside the session's `repo_path`. Supports optional sha256 verification for both source and target.
29
+
30
+ ### Android Build Doctor
31
+
32
+ When a managed project contains an `android_app` directory, the health check now includes Android build environment diagnostics: Java version, JAVA_HOME, ANDROID_HOME, SDK platform, build-tools, Gradle wrapper, and APK output path.
33
+
34
+ ## Bug Fixes
35
+
36
+ - **Watcher stale false positive**: Long-running tasks no longer cause the watcher to be incorrectly reported as stale. The watcher status now falls back to checking running task heartbeats.
37
+ - **Chinese path encoding**: All file I/O operations verified to use UTF-8 encoding. Health check now reports `path_encoding` status.
38
+ - **Tracked external dirty detection**: `captureRepoSnapshot` now correctly identifies tracked-but-modified external files via `dirty_paths` field parsed from `git status --porcelain`. The regex now includes `R` (rename) status, fixing dead code that previously never executed for renamed files.
39
+ - **Release zip path separators**: The packaging script (`pack-clean.js`) now creates zip archives with POSIX `/` path separators instead of Windows backslashes. Linux `unzip` no longer reports `warning: appears to use backslashes as path separators`.
40
+
41
+ ## Security
42
+
43
+ - 136 unit tests covering all security guards (path guard, sensitive guard, command guard, direct guards)
44
+ - Tests use Node's built-in `node:test` — zero new dependencies
45
+
46
+ ## Observability
47
+
48
+ - Structured JSON logging to stderr (never stdout, to avoid polluting MCP JSON-RPC)
49
+ - Tool call audit logs with duration tracking
50
+ - Global `unhandledRejection` and `uncaughtException` handlers
51
+
52
+ ## Tool Profile Changes
53
+
54
+ | Profile | v0.6.0 | v0.6.1 |
55
+ |---------|--------|--------|
56
+ | full | 28 | 30 |
57
+ | chatgpt_core | 16 | 17 |
58
+ | chatgpt_direct | 9 | 10 |
59
+
60
+ ## Migration
61
+
62
+ No breaking changes. All new fields are optional. New tools are additive and do not affect existing tools.
63
+
64
+ ## Verification
65
+
66
+ - TypeScript compilation: PASS
67
+ - Unit tests: 136 pass, 0 fail, 1 skipped (Windows symlink)
68
+ - Smoke tests: 139 pass, 0 fail
69
+ - Lifecycle tests: 22 pass, 0 fail (includes tracked external file rename regression test)
70
+ - Doctor CI: PASS (81 OK, 0 WARN, 0 FAIL on the release check host)
71
+ - Tool manifest check: PASS
72
+ - Package manifest check: PASS (260 files)
73
+ - Brand check: PASS (128 tracked files)
74
+ - MCP HTTP tests: 13 pass, 0 fail
75
+ - Release zip: POSIX path separators verified (261 entries, no backslashes)
@@ -33,6 +33,11 @@
33
33
  "cargo test",
34
34
  "go test ./..."
35
35
  ],
36
+ "repoAllowedTestCommands": {
37
+ "desktop-app": [
38
+ "npm run release:check"
39
+ ]
40
+ },
36
41
  "maxReadFileBytes": 200000,
37
42
  "defaultTaskTimeoutSeconds": 900,
38
43
  "maxTaskTimeoutSeconds": 3600,
@@ -17,21 +17,28 @@ or local private paths.
17
17
  2. Run `npm.cmd run build`.
18
18
  3. Use `scripts/patchwarden-mcp-stdio.cmd` as the tunnel MCP command.
19
19
  4. Start `npm.cmd run watch` in a separate terminal.
20
- 5. Start `tunnel-client run` or use `Start-PatchWarden-Tunnel.cmd`.
20
+ 5. Start `tunnel-client run` or use `PatchWarden.cmd start core`.
21
21
  6. Create a ChatGPT Connector using the tunnel channel.
22
22
  7. After a tunnel/schema refresh, reconnect the Connector and validate from a
23
23
  new ChatGPT conversation; an already-open conversation may retain its older
24
24
  tool catalog.
25
25
 
26
+ For ChatGPT Direct editing, set `enableDirectProfile: true` in the trusted
27
+ local config and run `PatchWarden.cmd start direct`. It uses
28
+ `scripts/patchwarden-mcp-direct.cmd`, the separate `patchwarden-direct` Tunnel
29
+ Client profile, no Watcher, and an isolated `runtime-direct` status directory.
30
+ Use a separate Direct Connector/Tunnel ID so the fixed 16-tool Core catalog and
31
+ the 9-tool Direct catalog never overwrite each other's cached schema.
32
+
26
33
  The Windows launcher prompts for the runtime API key once and stores only a
27
34
  Windows DPAPI-encrypted value under `%APPDATA%\patchwarden`. Use
28
- `Reset-PatchWarden-Tunnel-Key.cmd` to remove the saved credential.
35
+ `PatchWarden.cmd reset-key` to remove the saved credential.
29
36
 
30
37
  Before the launcher starts the tunnel it performs a real MCP stdio handshake
31
38
  and requires the exact `chatgpt_core` manifest. Run
32
- `Check-PatchWarden-Health.cmd` to see the version, profile, tool names, schema
39
+ `PatchWarden.cmd health` to see the version, profile, tool names, schema
33
40
  hash, process sources, and any mixed-version warnings. The check is read-only.
34
- The v0.4.0 core manifest contains 16 tools. A different count or schema hash
41
+ The v0.4.1 core manifest contains 16 tools. A different count or schema hash
35
42
  requires a Connector refresh and validation from a new ChatGPT conversation.
36
43
 
37
44
  ## Architecture
@@ -9,7 +9,7 @@ Use the patchwarden connector tools to verify the workflow.
9
9
  Step 1:
10
10
  Call health_check and list_agents. Continue only if the watcher and selected
11
11
  agent are available. Then call list_workspace for the configured workspace.
12
- Confirm schema_epoch is 2026-06-20-v2, tool_profile is chatgpt_core, and
12
+ Confirm schema_epoch is 2026-06-22-v6, tool_profile is chatgpt_core, and
13
13
  tool_count is 16. If the watcher is stale or missing, stop the task flow and
14
14
  report the health_check recovery instruction.
15
15
 
@@ -17,30 +17,33 @@ Step 2:
17
17
  Call read_workspace_file for README.md.
18
18
 
19
19
  Step 3:
20
- Call save_plan with:
21
-
22
- title: Add Usage Section
23
-
24
- content:
20
+ Prefer the feature_small template for this bounded change. Use goal:
25
21
  Add a "## Usage" section to the end of README.md. The section should include
26
22
  one sentence: "This repository was updated through PatchWarden."
27
23
  Do not modify other files. After the change, run the configured test command.
28
24
 
29
25
  Step 4:
30
- Call create_task with the returned plan_id, agent "opencode", an explicit
31
- repo_path for the target repository, and verify_commands ["npm test"]. Set
32
- timeout_seconds to 600.
26
+ Call create_task with execution_mode "assess_only", template "feature_small",
27
+ the goal above, agent "opencode", an explicit repo_path, verify_commands
28
+ ["npm test"], and timeout_seconds 600. If the decision is allow, invoke the
29
+ returned next_tool_call exactly as provided. Do not resend the goal, plan,
30
+ repository, agent, or verification arguments. If needs_confirm, stop and ask
31
+ the user to run the returned local patchwarden-confirm command. Never execute
32
+ a blocked assessment.
33
33
 
34
34
  Step 5:
35
- Immediately call wait_for_task with timeout_seconds 25. If it returns
36
- continuation_required: true, call wait_for_task again in this same assistant
37
- turn. Do not stop or reply to the user until terminal is true.
35
+ For this short task, call wait_for_task with timeout_seconds 25. If it returns
36
+ continuation_required: true, call it again in this same assistant turn. For a
37
+ long task, prefer list_tasks(repo_path=..., active_only=true) and
38
+ get_task_status instead of an extended wait loop.
38
39
  If execution_blocked is true or next_tool_call is health_check, do not keep
39
40
  polling; report the watcher recovery requirement.
40
41
 
41
42
  Step 6:
42
- When terminal is true, review the included summary, call get_task_summary and
43
- audit_task, then call get_diff, get_test_log, and get_result_json as needed.
43
+ When terminal is true, review the included compact summary, call
44
+ get_task_summary with view "compact", and call audit_task. Request the
45
+ standard summary, diff, test log, or result JSON only when compact evidence is
46
+ insufficient.
44
47
 
45
48
  Step 7:
46
49
  Summarize:
@@ -49,5 +52,6 @@ Summarize:
49
52
  - whether tests passed
50
53
  - whether any out-of-scope changes were detected
51
54
  - acceptance_status and audit verdict
55
+ - confirmed_failures, possible_false_positives, and manual verification items
52
56
  - whether the diff is acceptable
53
57
  ```
@@ -14,6 +14,14 @@
14
14
  # --tunnel-id tunnel_xxx \
15
15
  # --mcp-command "C:/path/to/patchwarden/scripts/patchwarden-mcp-stdio.cmd"
16
16
 
17
+ # Direct mode uses a separate profile and command:
18
+ #
19
+ # tunnel-client init \
20
+ # --sample sample_mcp_stdio_local \
21
+ # --profile patchwarden-direct \
22
+ # --tunnel-id tunnel_xxx \
23
+ # --mcp-command "C:/path/to/patchwarden/scripts/patchwarden-mcp-direct.cmd"
24
+
17
25
  mcp:
18
26
  commands:
19
27
  - channel: main
package/package.json CHANGED
@@ -1,25 +1,27 @@
1
1
  {
2
2
  "name": "patchwarden",
3
- "version": "0.4.0",
3
+ "version": "0.6.1",
4
4
  "description": "A secure local MCP bridge: clients save plans, local agents execute tasks, and results are returned through workspace-scoped files.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "bin": {
9
9
  "patchwarden": "dist/index.js",
10
+ "patchwarden-confirm": "dist/assessments/confirmCli.js",
10
11
  "patchwarden-runner": "dist/runner/cli.js"
11
12
  },
12
13
  "files": [
13
14
  "dist/",
14
15
  "docs/",
16
+ "!docs/optimization-proposal.md",
15
17
  "src/",
16
18
  "examples/",
17
19
  "scripts/",
18
- "Start-PatchWarden-Tunnel.cmd",
19
- "Restart-PatchWarden.cmd",
20
- "Check-PatchWarden-Health.cmd",
21
- "Reset-PatchWarden-Tunnel-Key.cmd",
20
+ "!scripts/kill-patchwarden.ps1",
21
+ "!scripts/launchers/Kill-PatchWarden.cmd",
22
+ "PatchWarden.cmd",
22
23
  "README.md",
24
+ "README.en.md",
23
25
  "LICENSE",
24
26
  "tsconfig.json"
25
27
  ],
@@ -31,25 +33,28 @@
31
33
  "runner": "node dist/runner/cli.js",
32
34
  "watch": "node dist/runner/watch.js",
33
35
  "doctor": "node dist/doctor.js",
34
- "test": "node dist/smoke-test.js && node scripts/lifecycle-smoke.js && node scripts/doctor-smoke.js && node scripts/tunnel-supervisor-smoke.js && node scripts/watcher-supervisor-smoke.js && node scripts/mcp-manifest-check.js && node scripts/brand-check.js",
36
+ "doctor:ci": "node dist/doctor.js --allow-default-config",
37
+ "test:unit": "node scripts/unit-tests.js",
38
+ "test": "node dist/smoke-test.js && node scripts/unit-tests.js && node scripts/lifecycle-smoke.js && node scripts/doctor-smoke.js && node scripts/tunnel-supervisor-smoke.js && node scripts/watcher-supervisor-smoke.js && node scripts/control-smoke.js && node scripts/mcp-manifest-check.js && node scripts/brand-check.js",
35
39
  "test:lifecycle": "npm run build && node scripts/lifecycle-smoke.js",
36
40
  "test:doctor": "npm run build && node scripts/doctor-smoke.js",
37
41
  "test:tunnel-supervisor": "npm run build && node scripts/tunnel-supervisor-smoke.js",
38
42
  "test:watcher-supervisor": "npm run build && node scripts/watcher-supervisor-smoke.js",
39
43
  "check:tool-manifest": "npm run build && node scripts/mcp-manifest-check.js",
44
+ "check:direct-tool-manifest": "npm run build && node scripts/mcp-manifest-check.js --profile chatgpt_direct",
40
45
  "check:brand": "node scripts/brand-check.js",
41
46
  "test:mcp": "npm run build && node scripts/mcp-smoke.js",
42
47
  "test:http-mcp": "npm run build && node scripts/http-mcp-smoke.js",
43
48
  "pretest": "npm run build",
44
49
  "pack:clean": "npm run build && node scripts/pack-clean.js",
45
- "verify:package": "npm run build && npm pack --dry-run"
50
+ "verify:package": "npm run build && node scripts/package-manifest-check.js"
46
51
  },
47
52
  "dependencies": {
48
53
  "@modelcontextprotocol/sdk": "^1.0.0"
49
54
  },
50
55
  "devDependencies": {
51
56
  "@types/node": "^20.0.0",
52
- "typescript": "^5.0.0"
57
+ "typescript": "^6.0.3"
53
58
  },
54
59
  "engines": {
55
60
  "node": ">=18.0.0"
@@ -1,25 +1,45 @@
1
1
  #!/usr/bin/env node
2
2
  import { execFileSync } from "node:child_process";
3
- import { readFileSync } from "node:fs";
3
+ import { readFileSync, readdirSync, statSync } from "node:fs";
4
+ import { join, relative } from "node:path";
4
5
 
5
6
  const allowedLegacyFiles = new Set([
6
7
  ".gitignore",
7
8
  ".npmignore",
8
9
  "README.md",
10
+ "README.en.md",
9
11
  "docs/migration-from-safe-bifrost.md",
10
12
  "docs/release-v0.3.0.md",
11
13
  "docs/release-v0.4.0.md",
14
+ "docs/release-v0.6.0.md",
12
15
  "scripts/brand-check.js",
13
16
  "scripts/pack-clean.js",
14
17
  ]);
15
18
  const legacyPattern = /safe-bifrost|Safe-Bifrost|SAFE_BIFROST|SafeBifrost|safe_bifrost/;
16
- const trackedFiles = execFileSync(
17
- "git",
18
- ["ls-files", "--cached", "--others", "--exclude-standard"],
19
- { encoding: "utf-8" }
20
- )
21
- .split(/\r?\n/)
22
- .filter(Boolean);
19
+
20
+ const EXCLUDE_DIRS = new Set(["node_modules", ".npm-cache", "dist", "release", ".patchwarden", ".git", "logs", "tmp", "coverage", "build", "out", ".next"]);
21
+
22
+ let trackedFiles;
23
+ let inGit = false;
24
+ try {
25
+ trackedFiles = execFileSync(
26
+ "git",
27
+ ["ls-files", "--cached", "--others", "--exclude-standard"],
28
+ { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
29
+ )
30
+ .split(/\r?\n/)
31
+ .filter(Boolean);
32
+ inGit = true;
33
+ } catch {
34
+ // Not a git repository — fall back to filesystem walk
35
+ console.warn("[brand-check] Not a Git repository; using filesystem walk.");
36
+ trackedFiles = walkFiles(".");
37
+ if (trackedFiles.length === 0) {
38
+ console.warn("[brand-check] WARNING: no files found in non-Git walk. Exiting cleanly.");
39
+ process.exit(0);
40
+ }
41
+ }
42
+
23
43
  const failures = [];
24
44
 
25
45
  for (const file of trackedFiles) {
@@ -29,9 +49,13 @@ for (const file of trackedFiles) {
29
49
  failures.push(`${normalized}: legacy brand in path`);
30
50
  continue;
31
51
  }
32
- const content = readFileSync(file);
33
- if (!content.includes(0) && legacyPattern.test(content.toString("utf-8"))) {
34
- failures.push(`${normalized}: legacy brand in content`);
52
+ try {
53
+ const content = readFileSync(file);
54
+ if (!content.includes(0) && legacyPattern.test(content.toString("utf-8"))) {
55
+ failures.push(`${normalized}: legacy brand in content`);
56
+ }
57
+ } catch {
58
+ // skip unreadable files
35
59
  }
36
60
  }
37
61
 
@@ -41,4 +65,26 @@ if (failures.length > 0) {
41
65
  process.exit(1);
42
66
  }
43
67
 
44
- console.log(`[brand-check] OK: ${trackedFiles.length} tracked files checked.`);
68
+ const label = inGit ? "tracked files checked" : "files scanned (non-Git fallback)";
69
+ console.log(`[brand-check] OK: ${trackedFiles.length} ${label}.`);
70
+
71
+ function walkFiles(root) {
72
+ const results = [];
73
+ const visit = (dir) => {
74
+ if (results.length > 10000) return;
75
+ let entries;
76
+ try { entries = readdirSync(dir, { withFileTypes: true }); } catch { return; }
77
+ for (const e of entries) {
78
+ if (results.length > 10000) break;
79
+ if (e.isDirectory()) {
80
+ if (EXCLUDE_DIRS.has(e.name)) continue;
81
+ visit(join(dir, e.name));
82
+ } else if (e.isFile()) {
83
+ const rel = relative(root, join(dir, e.name)).replace(/\\/g, "/");
84
+ results.push(rel);
85
+ }
86
+ }
87
+ };
88
+ visit(root);
89
+ return results;
90
+ }