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
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync } from "node:fs";
1
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { getConfig, getTasksDir, type PatchWardenConfig } from "./config.js";
4
4
 
@@ -24,6 +24,7 @@ export interface WatcherStatusSnapshot {
24
24
  instance_id: string | null;
25
25
  launcher_pid: number | null;
26
26
  reason: string | null;
27
+ activity: string | null;
27
28
  }
28
29
 
29
30
  export function getWatcherHeartbeatPath(config: PatchWardenConfig = getConfig()): string {
@@ -37,6 +38,22 @@ export function readWatcherStatus(
37
38
  const staleAfterSeconds = config.watcherStaleSeconds;
38
39
  const heartbeatPath = getWatcherHeartbeatPath(config);
39
40
  if (!existsSync(heartbeatPath)) {
41
+ // Even if watcher heartbeat is missing, check if a task is actively running
42
+ const taskFallback = checkRunningTaskHeartbeat(config, nowMs, staleAfterSeconds);
43
+ if (taskFallback) {
44
+ return {
45
+ status: "healthy",
46
+ available: true,
47
+ stale_after_seconds: staleAfterSeconds,
48
+ last_heartbeat_at: taskFallback.heartbeat_at,
49
+ heartbeat_age_seconds: taskFallback.age_seconds,
50
+ heartbeat_pid: null,
51
+ instance_id: null,
52
+ launcher_pid: null,
53
+ reason: null,
54
+ activity: taskFallback.activity,
55
+ };
56
+ }
40
57
  return {
41
58
  status: "missing",
42
59
  available: false,
@@ -47,6 +64,7 @@ export function readWatcherStatus(
47
64
  instance_id: null,
48
65
  launcher_pid: null,
49
66
  reason: "Watcher heartbeat has not been observed. Start or restart the PatchWarden watcher.",
67
+ activity: null,
50
68
  };
51
69
  }
52
70
 
@@ -58,16 +76,47 @@ export function readWatcherStatus(
58
76
  const ageMs = Math.max(0, nowMs - heartbeatMs);
59
77
  const ageSeconds = Math.round(ageMs / 1000);
60
78
  const healthy = ageMs < staleAfterSeconds * 1000;
79
+ if (healthy) {
80
+ return {
81
+ status: "healthy",
82
+ available: true,
83
+ stale_after_seconds: staleAfterSeconds,
84
+ last_heartbeat_at: String(data.last_heartbeat_at),
85
+ heartbeat_age_seconds: ageSeconds,
86
+ heartbeat_pid: Number.isInteger(Number(data.pid)) ? Number(data.pid) : null,
87
+ instance_id: typeof data.instance_id === "string" ? data.instance_id : null,
88
+ launcher_pid: Number.isInteger(Number(data.launcher_pid)) ? Number(data.launcher_pid) : null,
89
+ reason: null,
90
+ activity: null,
91
+ };
92
+ }
93
+ // Watcher heartbeat is stale — check if a task is actively running
94
+ const taskFallback = checkRunningTaskHeartbeat(config, nowMs, staleAfterSeconds);
95
+ if (taskFallback) {
96
+ return {
97
+ status: "healthy",
98
+ available: true,
99
+ stale_after_seconds: staleAfterSeconds,
100
+ last_heartbeat_at: taskFallback.heartbeat_at,
101
+ heartbeat_age_seconds: taskFallback.age_seconds,
102
+ heartbeat_pid: Number.isInteger(Number(data.pid)) ? Number(data.pid) : null,
103
+ instance_id: typeof data.instance_id === "string" ? data.instance_id : null,
104
+ launcher_pid: Number.isInteger(Number(data.launcher_pid)) ? Number(data.launcher_pid) : null,
105
+ reason: null,
106
+ activity: taskFallback.activity,
107
+ };
108
+ }
61
109
  return {
62
- status: healthy ? "healthy" : "stale",
63
- available: healthy,
110
+ status: "stale",
111
+ available: false,
64
112
  stale_after_seconds: staleAfterSeconds,
65
113
  last_heartbeat_at: String(data.last_heartbeat_at),
66
114
  heartbeat_age_seconds: ageSeconds,
67
115
  heartbeat_pid: Number.isInteger(Number(data.pid)) ? Number(data.pid) : null,
68
116
  instance_id: typeof data.instance_id === "string" ? data.instance_id : null,
69
117
  launcher_pid: Number.isInteger(Number(data.launcher_pid)) ? Number(data.launcher_pid) : null,
70
- reason: healthy ? null : "Watcher heartbeat is stale. Restart the PatchWarden watcher.",
118
+ reason: "Watcher heartbeat is stale. Restart the PatchWarden watcher.",
119
+ activity: null,
71
120
  };
72
121
  } catch {
73
122
  return {
@@ -80,10 +129,58 @@ export function readWatcherStatus(
80
129
  instance_id: null,
81
130
  launcher_pid: null,
82
131
  reason: "Watcher heartbeat file is unreadable.",
132
+ activity: null,
83
133
  };
84
134
  }
85
135
  }
86
136
 
137
+ interface TaskHeartbeatFallback {
138
+ heartbeat_at: string;
139
+ age_seconds: number;
140
+ activity: string;
141
+ }
142
+
143
+ function checkRunningTaskHeartbeat(
144
+ config: PatchWardenConfig,
145
+ nowMs: number,
146
+ staleAfterSeconds: number
147
+ ): TaskHeartbeatFallback | null {
148
+ const tasksDir = getTasksDir(config);
149
+ if (!existsSync(tasksDir)) return null;
150
+ let entries;
151
+ try {
152
+ entries = readdirSync(tasksDir, { withFileTypes: true });
153
+ } catch {
154
+ return null;
155
+ }
156
+ for (const entry of entries) {
157
+ if (!entry.isDirectory()) continue;
158
+ const taskDir = join(tasksDir, entry.name);
159
+ const statusFile = join(taskDir, "status.json");
160
+ const runtimeFile = join(taskDir, "runtime.json");
161
+ if (!existsSync(statusFile) || !existsSync(runtimeFile)) continue;
162
+ try {
163
+ const status = JSON.parse(readFileSync(statusFile, "utf-8"));
164
+ if (status.status !== "running") continue;
165
+ const runtime = JSON.parse(readFileSync(runtimeFile, "utf-8"));
166
+ const heartbeatAt = String(runtime.last_heartbeat_at || "");
167
+ const heartbeatMs = Date.parse(heartbeatAt);
168
+ if (!Number.isFinite(heartbeatMs)) continue;
169
+ const ageMs = Math.max(0, nowMs - heartbeatMs);
170
+ if (ageMs < staleAfterSeconds * 1000) {
171
+ return {
172
+ heartbeat_at: heartbeatAt,
173
+ age_seconds: Math.round(ageMs / 1000),
174
+ activity: `watcher busy executing task ${entry.name}`,
175
+ };
176
+ }
177
+ } catch {
178
+ continue;
179
+ }
180
+ }
181
+ return null;
182
+ }
183
+
87
184
  export function derivePendingReason(
88
185
  task: { status?: string; phase?: string },
89
186
  watcher: WatcherStatusSnapshot
package/tsconfig.json CHANGED
@@ -1,17 +1,18 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "ES2022",
5
- "moduleResolution": "node",
6
- "outDir": "dist",
7
- "rootDir": "src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "forceConsistentCasingInFileNames": true,
11
- "resolveJsonModule": true,
12
- "declaration": true,
13
- "skipLibCheck": true
14
- },
15
- "include": ["src/**/*.ts"],
16
- "exclude": ["node_modules", "dist"]
17
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "types": ["node"],
7
+ "outDir": "dist",
8
+ "rootDir": "src",
9
+ "strict": true,
10
+ "esModuleInterop": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "declaration": true,
14
+ "skipLibCheck": true
15
+ },
16
+ "include": ["src/**/*.ts"],
17
+ "exclude": ["node_modules", "dist"]
18
+ }
@@ -1,6 +0,0 @@
1
- @echo off
2
- setlocal
3
- cd /d "%~dp0"
4
- powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\get-patchwarden-health.ps1"
5
- echo.
6
- pause
@@ -1,6 +0,0 @@
1
- @echo off
2
- setlocal
3
- cd /d "%~dp0"
4
- powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\start-patchwarden-tunnel.ps1" -ForgetSavedApiKey
5
- echo.
6
- pause
@@ -1,19 +0,0 @@
1
- @echo off
2
- setlocal
3
- cd /d "%~dp0"
4
- echo.
5
- echo ========================================
6
- echo PatchWarden One-Click Restart
7
- echo ========================================
8
- echo.
9
- echo This will:
10
- echo 1. Stop only processes owned by the current PatchWarden launcher
11
- echo 2. Rebuild the project
12
- echo 3. Start a fresh tunnel launcher window
13
- echo.
14
- echo Close this window to cancel, or
15
- pause
16
- powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\restart-patchwarden.ps1"
17
- echo.
18
- echo Restart script finished.
19
- pause
@@ -1,7 +0,0 @@
1
- @echo off
2
- setlocal
3
- cd /d "%~dp0"
4
- powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\start-patchwarden-tunnel.ps1"
5
- echo.
6
- echo PatchWarden tunnel launcher exited.
7
- pause
@@ -1,43 +0,0 @@
1
- # Safe-Bifrost v0.3.0
2
-
3
- Safe-Bifrost v0.3.0 makes ChatGPT-managed local agent work easier to monitor,
4
- verify, and accept without weakening the workspace and command boundaries.
5
-
6
- ## Highlights
7
-
8
- - Adds `wait_for_task` so ChatGPT can stay in the tool loop until a task is
9
- terminal, plus `get_task_summary` for one-call acceptance evidence.
10
- - Requires an explicit existing repository directory and supports both
11
- workspace-relative and absolute `repo_path` values.
12
- - Adds independent multi-command `verify_commands` while keeping
13
- `test_command` compatibility.
14
- - Generates structured `result.json`, `verify.json`, readable `verify.log`,
15
- and a complete `diff.patch` for every terminal task.
16
- - Adds task-scoped file statistics, clear large/no-diff responses, and avoids
17
- including unchanged pre-existing workspace files in task diff evidence.
18
- - Detects changes outside `resolved_repo_path`, marks the task
19
- `failed_scope_violation`, invalidates verification acceptance, and creates a
20
- review-only `rollback_scope_violation_plan.md`.
21
- - Allows ordinary long build/test/release plans while blocking explicit
22
- credential theft, destructive disk deletion, and malicious persistence.
23
- - Redacts secret-like values in ordinary task artifacts instead of rejecting
24
- the entire read.
25
- - Expands `doctor`, stdio/HTTP MCP smoke tests, lifecycle coverage, packaging
26
- checks, and ChatGPT workflow documentation.
27
-
28
- ## Compatibility note
29
-
30
- `create_task` now requires `repo_path`. Existing clients that omitted it must
31
- pass an existing directory under `workspaceRoot`. `test_command` remains
32
- supported and is converted into a one-entry verification list.
33
-
34
- ## Verification
35
-
36
- - `npm test`: 63 security tests, 14 lifecycle tests, and doctor smoke passed
37
- - `npm run test:mcp`: passed
38
- - `npm run test:http-mcp`: 11 passed
39
- - `npm run doctor`: 47 OK, 0 WARN, 0 FAIL
40
- - `npm run pack:clean`: passed
41
- - `npm run verify:package`: passed
42
-
43
- Tracked in [issue #1](https://github.com/jiezeng2004-design/safe-bifrost/issues/1).
@@ -1,74 +0,0 @@
1
- # PatchWarden v0.4.0
2
-
3
- PatchWarden v0.4.0 hardens the ChatGPT-to-local-agent task loop without
4
- weakening workspace, command, or sensitive-file boundaries.
5
-
6
- This release also completes the project rename from Safe-Bifrost to
7
- PatchWarden. The npm package is now `patchwarden`; the old package is retained
8
- only to point existing users to the new name.
9
-
10
- ## Highlights
11
-
12
- - Adds supervised Windows tunnel recovery with local readiness probes,
13
- structured failure categories, capped retry backoff, and redacted runtime
14
- state under `%LOCALAPPDATA%\patchwarden\runtime`.
15
- - Adds `Check-PatchWarden-Health.cmd` for diagnostics when the MCP tunnel itself
16
- is unreachable.
17
- - Expands `health_check` with workspace, tasks directory, watcher, agent, tunnel,
18
- and last-error evidence; local HTTP `/healthz` and `/readyz` are also available.
19
- - Lets `create_task` use exactly one of a saved `plan_id`, persisted
20
- `inline_plan`, or a guarded task template.
21
- - Adds `inspect_only`, `feature_small`, `fix_tests`, `release_check`, and safe
22
- review-only `rollback_scope_violation` templates.
23
- - Enforces no-change templates with `failed_policy_violation`.
24
- - Adds deterministic failure guidance through `failure_reason`,
25
- `failed_command`, `suggested_next_action`, and `safe_followup_prompt`.
26
- - Adds standalone `file-stats.json` while preserving complete `diff.patch`,
27
- `changed-files.json`, and the v0.3.0 acceptance contract.
28
- - Adds deterministic `full` and `chatgpt_core` tool profiles. Tunnel stdio uses
29
- an exact 16-tool core manifest while ordinary local launches remain on the
30
- 22-tool full profile.
31
- - Adds schema-inclusive tool manifest hashing, `schema_epoch`, server version,
32
- and a real MCP stdio preflight before tunnel startup.
33
- - Adds structured `create_task.next_tool_call`, preferred
34
- `wait_for_task(timeout_seconds)`, legacy `wait_seconds` compatibility, and a
35
- complete terminal summary in the wait response.
36
- - Adds recursive redaction for structured result/verification summaries and
37
- concise verification counts/headlines such as `166 passed`.
38
- - Adds explicit `get_diff.patch_mode` values for textual, no-change, and
39
- hash-only evidence, including a reason when a textual patch is unavailable.
40
- - Enhances the local health report with process source/version evidence and
41
- mixed-version warnings without automatically ending any process.
42
- - Adds first-class watcher stale/missing evidence, structured pending artifact
43
- responses, and controlled recovery for launcher-owned watcher processes.
44
- - Reports stale client catalogs as `tool_catalog_mismatch` with the active
45
- profile, schema epoch, manifest hash, and Connector refresh guidance.
46
- - Fixes a plan-guard bypass where generic security wording could suppress a
47
- later credential-access instruction. Every dangerous occurrence is now
48
- evaluated independently and only directly negated actions are allowed.
49
-
50
- ## Compatibility
51
-
52
- The MCP tool names and `save_plan` -> `create_task` workflow remain stable, but
53
- the product rename is intentionally breaking: old CLI names, `SAFE_BIFROST_*`
54
- variables, `safe-bifrost.config.json`, `.safe-bifrost/`, and legacy AppData
55
- paths are not loaded. Follow the migration guide before replacing an existing
56
- installation. `repo_path`, configured agent validation, and exact
57
- verification-command allowlists remain mandatory.
58
-
59
- ## Verification
60
-
61
- Run the following from Windows PowerShell:
62
-
63
- ```powershell
64
- npm.cmd test
65
- npm.cmd run test:mcp
66
- npm.cmd run test:http-mcp
67
- npm.cmd run doctor
68
- npm.cmd run check:tool-manifest
69
- npm.cmd run check:brand
70
- npm.cmd run test:tunnel-supervisor
71
- npm.cmd run test:watcher-supervisor
72
- npm.cmd run pack:clean
73
- npm.cmd run verify:package
74
- ```