patchwarden 1.5.1 → 1.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 (573) hide show
  1. package/PatchWarden.cmd +32 -2
  2. package/README.en.md +152 -25
  3. package/README.md +120 -23
  4. package/dist/assessments/agentAssessor.js +21 -12
  5. package/dist/assessments/assessmentStore.js +42 -34
  6. package/dist/config.d.ts +15 -0
  7. package/dist/config.js +66 -13
  8. package/dist/control/fileManager.d.ts +2 -0
  9. package/dist/control/fileManager.js +39 -0
  10. package/dist/control/middleware/auth.d.ts +6 -0
  11. package/dist/control/middleware/auth.js +14 -5
  12. package/dist/control/middleware/static.js +16 -3
  13. package/dist/control/routeTable.d.ts +24 -0
  14. package/dist/control/routeTable.js +263 -0
  15. package/dist/control/routes/audit.js +17 -7
  16. package/dist/control/routes/evidence.js +1 -1
  17. package/dist/control/routes/lineage.js +1 -1
  18. package/dist/control/routes/process.d.ts +7 -0
  19. package/dist/control/routes/process.js +329 -42
  20. package/dist/control/routes/sessions.d.ts +9 -1
  21. package/dist/control/routes/sessions.js +84 -21
  22. package/dist/control/routes/status.d.ts +46 -1
  23. package/dist/control/routes/status.js +72 -15
  24. package/dist/control/routes/taskActions.js +24 -60
  25. package/dist/control/routes/tasks.d.ts +4 -0
  26. package/dist/control/routes/tasks.js +61 -62
  27. package/dist/control/routes/workspace.js +50 -23
  28. package/dist/control/runtime.d.ts +3 -2
  29. package/dist/control/runtime.js +63 -30
  30. package/dist/control/server.js +36 -365
  31. package/dist/control/shared.d.ts +25 -1
  32. package/dist/control/shared.js +64 -11
  33. package/dist/direct/directAudit.js +234 -225
  34. package/dist/direct/directGuards.d.ts +2 -1
  35. package/dist/direct/directGuards.js +42 -29
  36. package/dist/direct/directPatch.d.ts +6 -1
  37. package/dist/direct/directPatch.js +55 -8
  38. package/dist/direct/directSessionStore.d.ts +16 -6
  39. package/dist/direct/directSessionStore.js +127 -35
  40. package/dist/direct/directVerification.js +8 -16
  41. package/dist/doctor.js +62 -52
  42. package/dist/goal/acceptanceEngine.d.ts +1 -1
  43. package/dist/goal/goalProgress.js +75 -69
  44. package/dist/goal/goalReport.js +5 -12
  45. package/dist/goal/goalStatus.d.ts +2 -0
  46. package/dist/goal/goalStatus.js +10 -3
  47. package/dist/goal/goalStore.d.ts +9 -2
  48. package/dist/goal/goalStore.js +152 -45
  49. package/dist/goal/handoffExport.js +6 -6
  50. package/dist/goal/specKitImport.js +97 -96
  51. package/dist/goal/subgoalSync.js +11 -9
  52. package/dist/goal/worktreeManager.d.ts +2 -0
  53. package/dist/goal/worktreeManager.js +209 -136
  54. package/dist/httpServer.js +111 -32
  55. package/dist/logging.js +5 -3
  56. package/dist/policy/projectPolicy.js +5 -2
  57. package/dist/release/releaseGate.d.ts +1 -1
  58. package/dist/release/releaseGate.js +78 -25
  59. package/dist/runner/agentInvocation.d.ts +14 -0
  60. package/dist/runner/agentInvocation.js +96 -4
  61. package/dist/runner/changeCapture.d.ts +13 -5
  62. package/dist/runner/changeCapture.js +243 -61
  63. package/dist/runner/postTaskCleanup.js +48 -19
  64. package/dist/runner/processSecurity.d.ts +56 -0
  65. package/dist/runner/processSecurity.js +373 -0
  66. package/dist/runner/runTask.d.ts +1 -1
  67. package/dist/runner/runTask.js +115 -87
  68. package/dist/runner/simpleProcess.d.ts +3 -0
  69. package/dist/runner/simpleProcess.js +50 -36
  70. package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
  71. package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
  72. package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +1 -1
  73. package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
  74. package/dist/runner/taskStatusStore.d.ts +11 -0
  75. package/dist/runner/taskStatusStore.js +24 -0
  76. package/dist/runner/watch.d.ts +14 -1
  77. package/dist/runner/watch.js +256 -48
  78. package/dist/security/contentRedaction.js +2 -2
  79. package/dist/security/discoveryTokenStore.d.ts +3 -2
  80. package/dist/security/discoveryTokenStore.js +17 -2
  81. package/dist/security/loopbackHost.d.ts +2 -0
  82. package/dist/security/loopbackHost.js +16 -0
  83. package/dist/security/pathGuard.js +32 -17
  84. package/dist/security/planGuard.js +2 -1
  85. package/dist/security/runtimeGuard.js +9 -6
  86. package/dist/security/secretComparison.d.ts +3 -0
  87. package/dist/security/secretComparison.js +11 -0
  88. package/dist/security/sensitiveGuard.d.ts +5 -0
  89. package/dist/security/sensitiveGuard.js +27 -8
  90. package/dist/security/toolInvocationGuard.d.ts +2 -2
  91. package/dist/security/toolInvocationGuard.js +1 -1
  92. package/dist/security/workspaceRootGuard.d.ts +8 -0
  93. package/dist/security/workspaceRootGuard.js +47 -0
  94. package/dist/smoke-test.js +24 -23
  95. package/dist/tools/catalog/index.d.ts +4 -0
  96. package/dist/tools/catalog/index.js +4 -0
  97. package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
  98. package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
  99. package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +6 -15
  100. package/dist/tools/definitions/toolDefs.d.ts +18 -0
  101. package/dist/tools/definitions/toolDefs.js +1177 -0
  102. package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
  103. package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
  104. package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +1 -1
  105. package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +99 -29
  106. package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +6 -6
  107. package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +7 -7
  108. package/dist/tools/diagnostics/index.d.ts +6 -0
  109. package/dist/tools/diagnostics/index.js +6 -0
  110. package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
  111. package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
  112. package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +12 -8
  113. package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +23 -13
  114. package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
  115. package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
  116. package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +6 -6
  117. package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +1 -1
  118. package/dist/tools/direct/finalizeDirectSession.js +86 -0
  119. package/dist/tools/direct/index.d.ts +3 -0
  120. package/dist/tools/direct/index.js +3 -0
  121. package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
  122. package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
  123. package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
  124. package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
  125. package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
  126. package/dist/tools/discovery/index.d.ts +3 -0
  127. package/dist/tools/discovery/index.js +3 -0
  128. package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
  129. package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
  130. package/dist/tools/dispatch/coreDispatch.js +32 -31
  131. package/dist/tools/dispatch/diagnosticDispatch.d.ts +3 -5
  132. package/dist/tools/dispatch/diagnosticDispatch.js +70 -68
  133. package/dist/tools/dispatch/directDispatch.js +11 -10
  134. package/dist/tools/dispatch/goalDispatch.js +5 -4
  135. package/dist/tools/dispatch/releaseDispatch.js +3 -2
  136. package/dist/tools/dispatch/validation.d.ts +7 -0
  137. package/dist/tools/dispatch/validation.js +71 -0
  138. package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
  139. package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +1 -1
  140. package/dist/tools/goals/goalSubgoalTask.js +118 -0
  141. package/dist/tools/goals/index.d.ts +3 -0
  142. package/dist/tools/goals/index.js +3 -0
  143. package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
  144. package/dist/tools/registry.d.ts +7 -11
  145. package/dist/tools/registry.js +17 -1178
  146. package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
  147. package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
  148. package/dist/tools/release/index.d.ts +2 -0
  149. package/dist/tools/release/index.js +2 -0
  150. package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
  151. package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
  152. package/dist/tools/tasks/cancelTask.d.ts +11 -0
  153. package/dist/tools/tasks/cancelTask.js +85 -0
  154. package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +10 -2
  155. package/dist/tools/{createTask.js → tasks/createTask.js} +42 -27
  156. package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
  157. package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +8 -8
  158. package/dist/tools/{evidencePack.js → tasks/evidencePack.js} +34 -22
  159. package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
  160. package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
  161. package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +5 -5
  162. package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
  163. package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +33 -26
  164. package/dist/tools/tasks/index.d.ts +18 -0
  165. package/dist/tools/tasks/index.js +18 -0
  166. package/dist/tools/tasks/killTask.d.ts +1 -0
  167. package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
  168. package/dist/tools/{listTasks.js → tasks/listTasks.js} +3 -3
  169. package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +1 -1
  170. package/dist/tools/{reconcileTasks.js → tasks/reconcileTasks.js} +64 -66
  171. package/dist/tools/tasks/retryTask.js +60 -0
  172. package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
  173. package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +58 -30
  174. package/dist/tools/tasks/runVerification.js +38 -0
  175. package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
  176. package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
  177. package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
  178. package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
  179. package/dist/tools/workspace/applyPatch.js +53 -0
  180. package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
  181. package/dist/tools/workspace/index.d.ts +10 -0
  182. package/dist/tools/workspace/index.js +10 -0
  183. package/dist/tools/{listAgents.d.ts → workspace/listAgents.d.ts} +5 -0
  184. package/dist/tools/{listAgents.js → workspace/listAgents.js} +8 -4
  185. package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
  186. package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
  187. package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
  188. package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
  189. package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
  190. package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
  191. package/dist/tools/workspace/syncFile.js +134 -0
  192. package/dist/utils/atomicFile.d.ts +7 -0
  193. package/dist/utils/atomicFile.js +48 -0
  194. package/dist/utils/boundedFile.d.ts +8 -0
  195. package/dist/utils/boundedFile.js +93 -0
  196. package/dist/utils/lockedJsonFile.d.ts +15 -0
  197. package/dist/utils/lockedJsonFile.js +224 -0
  198. package/dist/utils/platform.d.ts +11 -0
  199. package/dist/utils/platform.js +26 -0
  200. package/dist/utils/stableJson.d.ts +2 -0
  201. package/dist/utils/stableJson.js +12 -0
  202. package/dist/version.d.ts +3 -2
  203. package/dist/version.js +3 -2
  204. package/dist/watcherStatus.d.ts +2 -2
  205. package/dist/watcherStatus.js +18 -0
  206. package/docs/CODE_WIKI.md +808 -143
  207. package/docs/architecture.md +15 -55
  208. package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
  209. package/docs/control-center/README.md +4 -4
  210. package/docs/dashboard-overview.md +4 -4
  211. package/docs/desktop-app.md +175 -0
  212. package/docs/evidence-pack-schema.md +3 -3
  213. package/docs/open-source-application.md +17 -11
  214. package/docs/release-checklist.md +1 -1
  215. package/docs/release-evidence.md +39 -29
  216. package/docs/task-safe-review-workflow.md +5 -5
  217. package/docs/threat-model.md +19 -1
  218. package/examples/config.example.json +4 -2
  219. package/package.json +27 -10
  220. package/scripts/README.md +15 -6
  221. package/scripts/build.js +11 -0
  222. package/scripts/checks/brand-check.js +3 -0
  223. package/scripts/checks/build-output-check.js +37 -0
  224. package/scripts/checks/control-center-smoke.js +91 -6
  225. package/scripts/checks/control-smoke.js +19 -8
  226. package/scripts/checks/http-mcp-smoke.js +82 -4
  227. package/scripts/checks/lifecycle-smoke.js +10 -10
  228. package/scripts/checks/mcp-manifest-check.js +1 -1
  229. package/scripts/checks/mcp-smoke.js +27 -3
  230. package/scripts/checks/package-manifest-check.js +20 -7
  231. package/scripts/checks/unit-tests.js +3 -5
  232. package/scripts/checks/watcher-supervisor-smoke.js +9 -0
  233. package/scripts/control/get-patchwarden-health.ps1 +1 -1
  234. package/scripts/control/manage-patchwarden.ps1 +69 -4
  235. package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
  236. package/scripts/control/run-background-supervisor.ps1 +41 -0
  237. package/scripts/control/start-patchwarden-tunnel.ps1 +126 -32
  238. package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
  239. package/scripts/launchers/PatchWarden-Control.cmd +6 -0
  240. package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
  241. package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
  242. package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
  243. package/scripts/lib/clean-generated-output.js +11 -0
  244. package/scripts/lib/file-discovery.js +12 -0
  245. package/scripts/release/desktop-preflight.js +211 -0
  246. package/scripts/release/pack-clean.js +59 -14
  247. package/src/assessments/agentAssessor.ts +26 -12
  248. package/src/assessments/assessmentStore.ts +52 -40
  249. package/src/config.ts +70 -13
  250. package/src/control/fileManager.ts +40 -0
  251. package/src/control/middleware/auth.ts +22 -4
  252. package/src/control/middleware/static.ts +16 -3
  253. package/src/control/routeTable.ts +301 -0
  254. package/src/control/routes/audit.ts +14 -6
  255. package/src/control/routes/evidence.ts +1 -1
  256. package/src/control/routes/lineage.ts +1 -1
  257. package/src/control/routes/process.ts +341 -40
  258. package/src/control/routes/sessions.ts +88 -25
  259. package/src/control/routes/status.ts +97 -17
  260. package/src/control/routes/taskActions.ts +24 -58
  261. package/src/control/routes/tasks.ts +66 -58
  262. package/src/control/routes/workspace.ts +56 -25
  263. package/src/control/runtime.ts +69 -33
  264. package/src/control/server.ts +36 -342
  265. package/src/control/shared.ts +77 -11
  266. package/src/direct/directAudit.ts +17 -9
  267. package/src/direct/directGuards.ts +72 -44
  268. package/src/direct/directPatch.ts +95 -8
  269. package/src/direct/directSessionStore.ts +211 -55
  270. package/src/direct/directVerification.ts +9 -23
  271. package/src/doctor.ts +73 -59
  272. package/src/goal/acceptanceEngine.ts +1 -1
  273. package/src/goal/goalProgress.ts +17 -13
  274. package/src/goal/goalReport.ts +5 -13
  275. package/src/goal/goalStatus.ts +19 -3
  276. package/src/goal/goalStore.ts +241 -54
  277. package/src/goal/handoffExport.ts +6 -6
  278. package/src/goal/specKitImport.ts +12 -12
  279. package/src/goal/subgoalSync.ts +11 -8
  280. package/src/goal/worktreeManager.ts +139 -22
  281. package/src/httpServer.ts +113 -30
  282. package/src/logging.ts +10 -3
  283. package/src/policy/projectPolicy.ts +5 -2
  284. package/src/release/releaseGate.ts +74 -27
  285. package/src/runner/agentInvocation.ts +126 -4
  286. package/src/runner/changeCapture.ts +291 -57
  287. package/src/runner/postTaskCleanup.ts +41 -17
  288. package/src/runner/processSecurity.ts +433 -0
  289. package/src/runner/runTask.ts +138 -91
  290. package/src/runner/simpleProcess.ts +66 -31
  291. package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
  292. package/src/{taskRuntime.ts → runner/taskRuntime.ts} +4 -3
  293. package/src/runner/taskStatusStore.ts +54 -0
  294. package/src/runner/watch.ts +281 -51
  295. package/src/security/contentRedaction.ts +2 -2
  296. package/src/security/discoveryTokenStore.ts +18 -4
  297. package/src/security/loopbackHost.ts +19 -0
  298. package/src/security/pathGuard.ts +35 -16
  299. package/src/security/planGuard.ts +2 -1
  300. package/src/security/runtimeGuard.ts +9 -6
  301. package/src/security/secretComparison.ts +13 -0
  302. package/src/security/sensitiveGuard.ts +27 -8
  303. package/src/security/toolInvocationGuard.ts +2 -2
  304. package/src/security/workspaceRootGuard.ts +53 -0
  305. package/src/smoke-test.ts +25 -24
  306. package/src/tools/catalog/index.ts +4 -0
  307. package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
  308. package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +7 -16
  309. package/src/tools/definitions/toolDefs.ts +1264 -0
  310. package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
  311. package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +99 -32
  312. package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +8 -8
  313. package/src/tools/diagnostics/index.ts +6 -0
  314. package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
  315. package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +27 -17
  316. package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
  317. package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +6 -6
  318. package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +7 -5
  319. package/src/tools/direct/index.ts +3 -0
  320. package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
  321. package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
  322. package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
  323. package/src/tools/discovery/index.ts +3 -0
  324. package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
  325. package/src/tools/dispatch/coreDispatch.ts +36 -31
  326. package/src/tools/dispatch/diagnosticDispatch.ts +26 -21
  327. package/src/tools/dispatch/directDispatch.ts +11 -10
  328. package/src/tools/dispatch/goalDispatch.ts +5 -4
  329. package/src/tools/dispatch/releaseDispatch.ts +3 -2
  330. package/src/tools/dispatch/validation.ts +78 -0
  331. package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
  332. package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +41 -26
  333. package/src/tools/goals/index.ts +3 -0
  334. package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
  335. package/src/tools/registry.ts +17 -1261
  336. package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
  337. package/src/tools/release/index.ts +2 -0
  338. package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
  339. package/src/tools/tasks/cancelTask.ts +109 -0
  340. package/src/tools/{createTask.ts → tasks/createTask.ts} +49 -26
  341. package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +8 -8
  342. package/src/tools/{evidencePack.ts → tasks/evidencePack.ts} +36 -22
  343. package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
  344. package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +7 -5
  345. package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
  346. package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +44 -33
  347. package/src/tools/tasks/index.ts +18 -0
  348. package/src/tools/{listTasks.ts → tasks/listTasks.ts} +4 -4
  349. package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +68 -66
  350. package/src/tools/tasks/retryTask.ts +69 -0
  351. package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +69 -34
  352. package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
  353. package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
  354. package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
  355. package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
  356. package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
  357. package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
  358. package/src/tools/workspace/index.ts +10 -0
  359. package/src/tools/{listAgents.ts → workspace/listAgents.ts} +11 -4
  360. package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
  361. package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
  362. package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
  363. package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
  364. package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
  365. package/src/tools/workspace/syncFile.ts +292 -0
  366. package/src/utils/atomicFile.ts +58 -0
  367. package/src/utils/boundedFile.ts +116 -0
  368. package/src/utils/lockedJsonFile.ts +251 -0
  369. package/src/utils/platform.ts +31 -0
  370. package/src/utils/stableJson.ts +12 -0
  371. package/src/version.ts +3 -2
  372. package/src/watcherStatus.ts +19 -1
  373. package/ui/desktop-bootstrap.js +11 -0
  374. package/ui/desktop-bridge.js +36 -0
  375. package/ui/desktop.css +160 -0
  376. package/ui/getting-started.js +93 -0
  377. package/ui/i18n.js +484 -0
  378. package/ui/log-parser.js +30 -0
  379. package/ui/pages/audit.html +12 -0
  380. package/ui/pages/dashboard.html +90 -147
  381. package/ui/pages/direct-sessions.html +123 -26
  382. package/ui/pages/getting-started.html +43 -0
  383. package/ui/pages/logs.html +105 -22
  384. package/ui/pages/settings.html +101 -0
  385. package/ui/pages/task-detail.html +12 -0
  386. package/ui/pages/tasks.html +54 -8
  387. package/ui/pages/workspace.html +38 -1
  388. package/ui/settings.js +245 -0
  389. package/PatchWarden-Control.cmd +0 -6
  390. package/Restart-PatchWarden-Control.cmd +0 -6
  391. package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
  392. package/dist/test/unit/acceptance-engine.test.js +0 -228
  393. package/dist/test/unit/agent-router.test.d.ts +0 -1
  394. package/dist/test/unit/agent-router.test.js +0 -287
  395. package/dist/test/unit/android-doctor.test.d.ts +0 -1
  396. package/dist/test/unit/android-doctor.test.js +0 -118
  397. package/dist/test/unit/apply-patch.test.d.ts +0 -1
  398. package/dist/test/unit/apply-patch.test.js +0 -225
  399. package/dist/test/unit/audit-checks.test.d.ts +0 -1
  400. package/dist/test/unit/audit-checks.test.js +0 -350
  401. package/dist/test/unit/chinese-path.test.d.ts +0 -1
  402. package/dist/test/unit/chinese-path.test.js +0 -91
  403. package/dist/test/unit/command-guard.test.d.ts +0 -1
  404. package/dist/test/unit/command-guard.test.js +0 -160
  405. package/dist/test/unit/create-task.test.d.ts +0 -1
  406. package/dist/test/unit/create-task.test.js +0 -197
  407. package/dist/test/unit/diagnose-task.test.d.ts +0 -1
  408. package/dist/test/unit/diagnose-task.test.js +0 -457
  409. package/dist/test/unit/direct-guards.test.d.ts +0 -1
  410. package/dist/test/unit/direct-guards.test.js +0 -328
  411. package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
  412. package/dist/test/unit/discovery-token-store.test.js +0 -139
  413. package/dist/test/unit/evidence-pack.test.d.ts +0 -1
  414. package/dist/test/unit/evidence-pack.test.js +0 -224
  415. package/dist/test/unit/get-task-status.test.d.ts +0 -1
  416. package/dist/test/unit/get-task-status.test.js +0 -174
  417. package/dist/test/unit/get-task-summary.test.d.ts +0 -1
  418. package/dist/test/unit/get-task-summary.test.js +0 -146
  419. package/dist/test/unit/goal-graph.test.d.ts +0 -1
  420. package/dist/test/unit/goal-graph.test.js +0 -298
  421. package/dist/test/unit/goal-progress.test.d.ts +0 -1
  422. package/dist/test/unit/goal-progress.test.js +0 -381
  423. package/dist/test/unit/goal-report.test.d.ts +0 -1
  424. package/dist/test/unit/goal-report.test.js +0 -159
  425. package/dist/test/unit/goal-status.test.d.ts +0 -1
  426. package/dist/test/unit/goal-status.test.js +0 -215
  427. package/dist/test/unit/goal-store.test.d.ts +0 -1
  428. package/dist/test/unit/goal-store.test.js +0 -253
  429. package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
  430. package/dist/test/unit/goal-subgoal-task.test.js +0 -55
  431. package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
  432. package/dist/test/unit/goal-tools-registry.test.js +0 -192
  433. package/dist/test/unit/handoff-export.test.d.ts +0 -1
  434. package/dist/test/unit/handoff-export.test.js +0 -263
  435. package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
  436. package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
  437. package/dist/test/unit/logging.test.d.ts +0 -1
  438. package/dist/test/unit/logging.test.js +0 -397
  439. package/dist/test/unit/path-guard.test.d.ts +0 -1
  440. package/dist/test/unit/path-guard.test.js +0 -133
  441. package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
  442. package/dist/test/unit/post-task-cleanup.test.js +0 -48
  443. package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
  444. package/dist/test/unit/project-policy-release-mode.test.js +0 -125
  445. package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
  446. package/dist/test/unit/reconcile-tasks.test.js +0 -456
  447. package/dist/test/unit/release-gate.test.d.ts +0 -1
  448. package/dist/test/unit/release-gate.test.js +0 -242
  449. package/dist/test/unit/run-task-loop.test.d.ts +0 -1
  450. package/dist/test/unit/run-task-loop.test.js +0 -380
  451. package/dist/test/unit/safe-status.test.d.ts +0 -1
  452. package/dist/test/unit/safe-status.test.js +0 -165
  453. package/dist/test/unit/safe-views.test.d.ts +0 -1
  454. package/dist/test/unit/safe-views.test.js +0 -171
  455. package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
  456. package/dist/test/unit/schema-drift-check.test.js +0 -176
  457. package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
  458. package/dist/test/unit/sensitive-guard.test.js +0 -104
  459. package/dist/test/unit/spec-kit-import.test.d.ts +0 -1
  460. package/dist/test/unit/spec-kit-import.test.js +0 -341
  461. package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
  462. package/dist/test/unit/subgoal-sync.test.js +0 -183
  463. package/dist/test/unit/sync-file.test.d.ts +0 -1
  464. package/dist/test/unit/sync-file.test.js +0 -154
  465. package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
  466. package/dist/test/unit/tool-invocation-guard.test.js +0 -432
  467. package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
  468. package/dist/test/unit/tool-usage-stats.test.js +0 -300
  469. package/dist/test/unit/toolSearch.test.d.ts +0 -1
  470. package/dist/test/unit/toolSearch.test.js +0 -571
  471. package/dist/test/unit/wait-for-task.test.d.ts +0 -1
  472. package/dist/test/unit/wait-for-task.test.js +0 -144
  473. package/dist/test/unit/watcher-status.test.d.ts +0 -1
  474. package/dist/test/unit/watcher-status.test.js +0 -169
  475. package/dist/test/unit/worktree-manager.test.d.ts +0 -1
  476. package/dist/test/unit/worktree-manager.test.js +0 -176
  477. package/dist/tools/applyPatch.js +0 -41
  478. package/dist/tools/cancelTask.d.ts +0 -30
  479. package/dist/tools/cancelTask.js +0 -64
  480. package/dist/tools/finalizeDirectSession.js +0 -84
  481. package/dist/tools/goalSubgoalTask.js +0 -110
  482. package/dist/tools/killTask.d.ts +0 -15
  483. package/dist/tools/retryTask.js +0 -45
  484. package/dist/tools/runVerification.js +0 -36
  485. package/dist/tools/syncFile.js +0 -65
  486. package/docs/control-center/control-center-daily-driver.md +0 -211
  487. package/docs/control-center/control-center-mvp.md +0 -205
  488. package/docs/control-center/control-center-phase2.md +0 -159
  489. package/docs/execution-plan-2026-07-09.md +0 -315
  490. package/docs/release-v0.6.0.md +0 -71
  491. package/docs/release-v0.6.1.md +0 -75
  492. package/docs/release-v0.6.4.md +0 -45
  493. package/docs/roadmap-execution-and-acceptance.md +0 -365
  494. package/src/test/unit/acceptance-engine.test.ts +0 -261
  495. package/src/test/unit/agent-router.test.ts +0 -342
  496. package/src/test/unit/android-doctor.test.ts +0 -158
  497. package/src/test/unit/apply-patch.test.ts +0 -293
  498. package/src/test/unit/audit-checks.test.ts +0 -567
  499. package/src/test/unit/chinese-path.test.ts +0 -106
  500. package/src/test/unit/command-guard.test.ts +0 -221
  501. package/src/test/unit/create-task.test.ts +0 -255
  502. package/src/test/unit/diagnose-task.test.ts +0 -544
  503. package/src/test/unit/direct-guards.test.ts +0 -467
  504. package/src/test/unit/discovery-token-store.test.ts +0 -181
  505. package/src/test/unit/evidence-pack.test.ts +0 -251
  506. package/src/test/unit/get-task-status.test.ts +0 -203
  507. package/src/test/unit/get-task-summary.test.ts +0 -173
  508. package/src/test/unit/goal-graph.test.ts +0 -347
  509. package/src/test/unit/goal-progress.test.ts +0 -538
  510. package/src/test/unit/goal-report.test.ts +0 -189
  511. package/src/test/unit/goal-status.test.ts +0 -270
  512. package/src/test/unit/goal-store.test.ts +0 -318
  513. package/src/test/unit/goal-subgoal-task.test.ts +0 -72
  514. package/src/test/unit/goal-tools-registry.test.ts +0 -245
  515. package/src/test/unit/handoff-export.test.ts +0 -295
  516. package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
  517. package/src/test/unit/logging.test.ts +0 -497
  518. package/src/test/unit/path-guard.test.ts +0 -180
  519. package/src/test/unit/post-task-cleanup.test.ts +0 -53
  520. package/src/test/unit/project-policy-release-mode.test.ts +0 -156
  521. package/src/test/unit/reconcile-tasks.test.ts +0 -551
  522. package/src/test/unit/release-gate.test.ts +0 -314
  523. package/src/test/unit/run-task-loop.test.ts +0 -425
  524. package/src/test/unit/safe-status.test.ts +0 -187
  525. package/src/test/unit/safe-views.test.ts +0 -184
  526. package/src/test/unit/schema-drift-check.test.ts +0 -260
  527. package/src/test/unit/sensitive-guard.test.ts +0 -124
  528. package/src/test/unit/spec-kit-import.test.ts +0 -429
  529. package/src/test/unit/subgoal-sync.test.ts +0 -236
  530. package/src/test/unit/sync-file.test.ts +0 -231
  531. package/src/test/unit/tool-invocation-guard.test.ts +0 -542
  532. package/src/test/unit/tool-usage-stats.test.ts +0 -384
  533. package/src/test/unit/toolSearch.test.ts +0 -756
  534. package/src/test/unit/wait-for-task.test.ts +0 -176
  535. package/src/test/unit/watcher-status.test.ts +0 -190
  536. package/src/test/unit/worktree-manager.test.ts +0 -247
  537. package/src/tools/cancelTask.ts +0 -70
  538. package/src/tools/retryTask.ts +0 -53
  539. package/src/tools/syncFile.ts +0 -122
  540. /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
  541. /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
  542. /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
  543. /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
  544. /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
  545. /package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +0 -0
  546. /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
  547. /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
  548. /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
  549. /package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +0 -0
  550. /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
  551. /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
  552. /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
  553. /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
  554. /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
  555. /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
  556. /package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +0 -0
  557. /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
  558. /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
  559. /package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +0 -0
  560. /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
  561. /package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +0 -0
  562. /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
  563. /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
  564. /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
  565. /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
  566. /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
  567. /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
  568. /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
  569. /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
  570. /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
  571. /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
  572. /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
  573. /package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "patchwarden",
3
- "version": "1.5.1",
3
+ "version": "1.6.1",
4
4
  "description": "Secure local MCP bridge for ChatGPT and local agents, with workspace-scoped task loops, safe summaries, audits, and Direct editing.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,9 +12,12 @@
12
12
  },
13
13
  "files": [
14
14
  "dist/",
15
+ "!dist/test/",
15
16
  "docs/",
17
+ "!docs/archive/",
16
18
  "!docs/optimization-proposal.md",
17
19
  "src/",
20
+ "!src/test/",
18
21
  "examples/",
19
22
  "scripts/",
20
23
  "!scripts/control/kill-patchwarden.ps1",
@@ -22,18 +25,14 @@
22
25
  "!.local/",
23
26
  "ui/",
24
27
  "PatchWarden.cmd",
25
- "PatchWarden-Control.cmd",
26
- "PatchWarden-Control-Tray.cmd",
27
- "PatchWarden-Desktop.cmd",
28
- "Restart-PatchWarden-Control.cmd",
29
- "Stop-PatchWarden.cmd",
30
28
  "README.md",
31
29
  "README.en.md",
32
30
  "LICENSE",
33
31
  "tsconfig.json"
34
32
  ],
35
33
  "scripts": {
36
- "build": "node ./node_modules/typescript/bin/tsc",
34
+ "build": "node scripts/build.js",
35
+ "check:build-output": "node scripts/checks/build-output-check.js",
37
36
  "start": "node dist/index.js",
38
37
  "start:http": "node dist/httpServer.js",
39
38
  "start:control": "node dist/controlCenter.js",
@@ -43,7 +42,7 @@
43
42
  "doctor": "node dist/doctor.js",
44
43
  "doctor:ci": "node dist/doctor.js --allow-default-config",
45
44
  "test:unit": "node scripts/checks/unit-tests.js",
46
- "test": "node dist/smoke-test.js && node scripts/checks/unit-tests.js && node scripts/checks/lifecycle-smoke.js && node scripts/checks/doctor-smoke.js && node scripts/checks/tunnel-supervisor-smoke.js && node scripts/checks/watcher-supervisor-smoke.js && node scripts/checks/control-smoke.js && node scripts/checks/mcp-manifest-check.js && node scripts/checks/brand-check.js && node scripts/checks/control-center-smoke.js",
45
+ "test": "node scripts/checks/build-output-check.js && node dist/smoke-test.js && node scripts/checks/unit-tests.js && node scripts/checks/lifecycle-smoke.js && node scripts/checks/doctor-smoke.js && node scripts/checks/tunnel-supervisor-smoke.js && node scripts/checks/watcher-supervisor-smoke.js && node scripts/checks/control-smoke.js && node scripts/checks/mcp-manifest-check.js && node scripts/checks/brand-check.js && node scripts/checks/control-center-smoke.js",
47
46
  "test:lifecycle": "npm run build && node scripts/checks/lifecycle-smoke.js",
48
47
  "test:doctor": "npm run build && node scripts/checks/doctor-smoke.js",
49
48
  "test:tunnel-supervisor": "npm run build && node scripts/checks/tunnel-supervisor-smoke.js",
@@ -53,18 +52,36 @@
53
52
  "check:search-tool-manifest": "npm run build && node scripts/checks/mcp-manifest-check.js --profile chatgpt_search",
54
53
  "check:brand": "node scripts/checks/brand-check.js",
55
54
  "test:mcp": "npm run build && node scripts/checks/mcp-smoke.js",
55
+ "test:mcp:built": "node scripts/checks/mcp-smoke.js",
56
56
  "test:http-mcp": "npm run build && node scripts/checks/http-mcp-smoke.js",
57
+ "test:http-mcp:built": "node scripts/checks/http-mcp-smoke.js",
57
58
  "pretest": "npm run build",
58
59
  "pack:clean": "npm run build && node scripts/release/pack-clean.js",
59
- "verify:package": "npm run build && node scripts/checks/package-manifest-check.js"
60
+ "pack:clean:built": "node scripts/release/pack-clean.js",
61
+ "verify:package": "npm run build && node scripts/checks/package-manifest-check.js",
62
+ "verify:package:built": "node scripts/checks/package-manifest-check.js",
63
+ "desktop:install": "npm.cmd --prefix desktop install --cache ..\\.npm-cache",
64
+ "desktop:test": "npm.cmd --prefix desktop test",
65
+ "desktop:smoke:unpacked": "npm.cmd --prefix desktop run smoke:unpacked --",
66
+ "desktop:stage": "npm run build && npm.cmd --prefix desktop run stage",
67
+ "desktop:dev": "npm run build && npm.cmd --prefix desktop run dev",
68
+ "desktop:package:dir": "npm run build && npm.cmd --prefix desktop run build:dir",
69
+ "desktop:package": "npm run build && npm.cmd --prefix desktop run build",
70
+ "desktop:preflight": "node scripts/release/desktop-preflight.js",
71
+ "desktop:preflight:release": "node scripts/release/desktop-preflight.js --require-clean"
60
72
  },
61
73
  "dependencies": {
62
- "@modelcontextprotocol/sdk": "^1.0.0"
74
+ "@modelcontextprotocol/sdk": "^1.29.0"
63
75
  },
64
76
  "devDependencies": {
65
77
  "@types/node": "^26.1.0",
66
78
  "typescript": "^6.0.3"
67
79
  },
80
+ "overrides": {
81
+ "@hono/node-server": "2.0.11",
82
+ "hono": "4.12.31",
83
+ "fast-uri": "4.1.1"
84
+ },
68
85
  "engines": {
69
86
  "node": ">=18.0.0"
70
87
  },
package/scripts/README.md CHANGED
@@ -4,13 +4,18 @@ This directory keeps implementation scripts out of the root folder. Normal
4
4
  desktop use should start from the root entrypoints:
5
5
 
6
6
  ```powershell
7
- .\PatchWarden-Desktop.cmd
8
- .\PatchWarden-Control.cmd
9
- .\PatchWarden-Control-Tray.cmd --foreground
10
- .\Stop-PatchWarden.cmd
7
+ .\scripts\launchers\PatchWarden-Desktop.cmd
8
+ .\scripts\launchers\PatchWarden-Control.cmd
9
+ .\scripts\launchers\PatchWarden-Control-Tray.cmd --foreground
10
+ .\scripts\launchers\Stop-PatchWarden.cmd
11
11
  .\PatchWarden.cmd status all
12
12
  ```
13
13
 
14
+ The installable Windows desktop shell is built separately with
15
+ `npm.cmd run desktop:package`. It preserves these source/npm entrypoints and
16
+ uses the same Control Center API rather than adding another process-management
17
+ surface. See `docs/desktop-app.md`.
18
+
14
19
  ## Control Scripts
15
20
 
16
21
  - `control/manage-patchwarden.ps1`: backing implementation for `PatchWarden.cmd`.
@@ -34,11 +39,15 @@ desktop use should start from the root entrypoints:
34
39
  - `checks/mcp-manifest-check.js`: validates MCP manifest expectations.
35
40
  - `brand-check.js`: checks public brand strings.
36
41
  - `checks/package-manifest-check.js`: verifies package contents.
42
+ - `checks/build-output-check.js`: verifies clean-output confinement and exact recursive unit-test compilation.
43
+ - `release/desktop-preflight.js`: builds an isolated Windows directory package and writes a bounded preflight receipt.
37
44
 
38
45
  ## Release Helpers
39
46
 
40
- - `release/pack-clean.js`: rebuilds `release/`, `patchwarden-release.tar.gz`, and the
41
- versioned `PatchWarden-v*.zip` artifact.
47
+ - `release/pack-clean.js`: rebuilds the isolated `release/package/` staging
48
+ directory, `patchwarden-release.tar.gz`, and the versioned
49
+ `PatchWarden-v*.zip` artifact. Desktop and preflight siblings under
50
+ `release/` are preserved.
42
51
 
43
52
  ## Compatibility Launchers
44
53
 
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { cleanGeneratedOutput } from "./lib/clean-generated-output.js";
5
+
6
+ const root = resolve(fileURLToPath(new URL("..", import.meta.url)));
7
+ const dist = resolve(root, "dist");
8
+
9
+ cleanGeneratedOutput(root, dist);
10
+ process.chdir(root);
11
+ await import("../node_modules/typescript/lib/tsc.js");
@@ -12,6 +12,9 @@ const allowedLegacyFiles = new Set([
12
12
  "docs/release-v0.3.0.md",
13
13
  "docs/release-v0.4.0.md",
14
14
  "docs/release-v0.6.0.md",
15
+ "docs/archive/releases/release-v0.6.0.md",
16
+ "docs/archive/releases/release-v0.6.1.md",
17
+ "docs/archive/releases/release-v0.6.4.md",
15
18
  "scripts/checks/brand-check.js",
16
19
  "scripts/release/pack-clean.js",
17
20
  ]);
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env node
2
+ import assert from "node:assert/strict";
3
+ import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { relative, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { cleanGeneratedOutput } from "../lib/clean-generated-output.js";
8
+ import { collectMatchingFiles } from "../lib/file-discovery.js";
9
+
10
+ const root = resolve(fileURLToPath(new URL("../..", import.meta.url)));
11
+ const sourceRoot = resolve(root, "src", "test", "unit");
12
+ const compiledRoot = resolve(root, "dist", "test", "unit");
13
+
14
+ const sourceTests = collectMatchingFiles(sourceRoot, (name) => name.endsWith(".test.ts"))
15
+ .map((path) => relative(sourceRoot, path).replace(/\\/g, "/").replace(/\.ts$/, ".js"));
16
+ const compiledTests = collectMatchingFiles(compiledRoot, (name) => name.endsWith(".test.js"))
17
+ .map((path) => relative(compiledRoot, path).replace(/\\/g, "/"));
18
+
19
+ assert.deepEqual(compiledTests, sourceTests, "compiled unit tests must exactly match source test paths");
20
+ assert.ok(compiledTests.some((path) => path.includes("/")), "unit discovery must include nested tests");
21
+
22
+ const fixtureRoot = mkdtempSync(resolve(tmpdir(), "patchwarden-clean-build-"));
23
+ try {
24
+ const fixtureDist = resolve(fixtureRoot, "dist");
25
+ const outside = resolve(fixtureRoot, "keep.txt");
26
+ mkdirSync(fixtureDist);
27
+ writeFileSync(resolve(fixtureDist, "stale.js"), "stale\n", "utf8");
28
+ writeFileSync(outside, "keep\n", "utf8");
29
+ cleanGeneratedOutput(fixtureRoot, fixtureDist);
30
+ assert.equal(existsSync(fixtureDist), false, "clean build must remove stale dist contents");
31
+ assert.equal(existsSync(outside), true, "clean build must preserve files outside dist");
32
+ assert.throws(() => cleanGeneratedOutput(fixtureRoot, resolve(fixtureRoot, "release")), /Refusing/);
33
+ } finally {
34
+ rmSync(fixtureRoot, { recursive: true, force: true });
35
+ }
36
+
37
+ console.log(`[build-output-check] OK: ${sourceTests.length} source tests match ${compiledTests.length} compiled tests.`);
@@ -121,9 +121,9 @@ process.on("SIGTERM", () => {
121
121
  process.exit(143);
122
122
  });
123
123
 
124
- function httpGet(url) {
124
+ function httpGet(url, headers = {}) {
125
125
  return new Promise((resolve, reject) => {
126
- const req = http.get(url, (res) => {
126
+ const req = http.get(url, { headers }, (res) => {
127
127
  let data = "";
128
128
  res.on("data", (chunk) => (data += chunk));
129
129
  res.on("end", () => resolve({ status: res.statusCode, headers: res.headers, body: data }));
@@ -133,6 +133,34 @@ function httpGet(url) {
133
133
  });
134
134
  }
135
135
 
136
+ async function testLoopbackHostBoundary() {
137
+ const name = "Control Center rejects DNS-rebinding Host headers and cannot be framed";
138
+ try {
139
+ const hostileToken = await httpGet(`${BASE_URL}/control-token.json`, {
140
+ Host: "patchwarden.attacker.invalid",
141
+ });
142
+ const hostilePage = await httpGet(`${BASE_URL}/`, {
143
+ Host: "127.0.0.1.attacker.invalid",
144
+ });
145
+ const localPage = await httpGet(`${BASE_URL}/`);
146
+ const problems = [];
147
+ if (hostileToken.status !== 421 || hostileToken.body.includes("token")) {
148
+ problems.push(`hostile token request returned ${hostileToken.status}: ${hostileToken.body.slice(0, 120)}`);
149
+ }
150
+ if (hostilePage.status !== 421) problems.push(`hostile page request returned ${hostilePage.status}`);
151
+ if (localPage.status !== 200) problems.push(`loopback page returned ${localPage.status}`);
152
+ if (String(localPage.headers["x-frame-options"] || "").toUpperCase() !== "DENY") {
153
+ problems.push("X-Frame-Options is not DENY");
154
+ }
155
+ if (!String(localPage.headers["content-security-policy"] || "").includes("frame-ancestors 'none'")) {
156
+ problems.push("CSP does not deny frame ancestors");
157
+ }
158
+ record(name, problems.length === 0, problems.join("; "));
159
+ } catch (err) {
160
+ record(name, false, `error: ${err.message}`);
161
+ }
162
+ }
163
+
136
164
  function httpPost(url, headers = {}) {
137
165
  return new Promise((resolve, reject) => {
138
166
  const parsed = new URL(url);
@@ -221,6 +249,12 @@ async function testStaticFiles() {
221
249
  const root = await httpGet(`${BASE_URL}/`);
222
250
  const vendor = await httpGet(`${BASE_URL}/vendor/tailwindcss-browser.js`);
223
251
  const css = await httpGet(`${BASE_URL}/colors_and_type.css`);
252
+ const desktopCss = await httpGet(`${BASE_URL}/desktop.css`);
253
+ const desktopBridge = await httpGet(`${BASE_URL}/desktop-bridge.js`);
254
+ const i18n = await httpGet(`${BASE_URL}/i18n.js`);
255
+ const gettingStarted = await httpGet(`${BASE_URL}/pages/getting-started.html`);
256
+ const gettingStartedJs = await httpGet(`${BASE_URL}/getting-started.js`);
257
+ const settings = await httpGet(`${BASE_URL}/pages/settings.html`);
224
258
  const favicon = await httpGet(`${BASE_URL}/favicon.ico`);
225
259
 
226
260
  const checks = [];
@@ -228,7 +262,8 @@ async function testStaticFiles() {
228
262
  const rootCt = root.headers["content-type"] || "";
229
263
  if (!rootCt.includes("text/html")) checks.push(`GET / -> Content-Type ${rootCt} (expected text/html)`);
230
264
  if (!root.body.includes("setup-checklist-card")) checks.push("dashboard missing setup checklist card");
231
- if (!root.body.includes("Show Core / Direct log tails")) checks.push("dashboard activity log is not collapsed behind a summary");
265
+ if (!root.body.includes("查看 Core / Direct 本次日志尾部")) checks.push("dashboard activity log is not collapsed behind a summary");
266
+ if (!root.body.includes("pw-dashboard-toolbar")) checks.push("dashboard missing stable desktop toolbar layout");
232
267
  if (!root.body.includes("evidence-pack-card")) checks.push("dashboard missing v1.5 evidence pack card");
233
268
 
234
269
  if (vendor.status !== 200) checks.push(`GET /vendor/tailwindcss-browser.js -> status ${vendor.status}`);
@@ -239,6 +274,31 @@ async function testStaticFiles() {
239
274
  const cssCt = css.headers["content-type"] || "";
240
275
  if (!cssCt.includes("text/css")) checks.push(`GET /colors_and_type.css -> Content-Type ${cssCt}`);
241
276
 
277
+ if (desktopCss.status !== 200 || !(desktopCss.headers["content-type"] || "").includes("text/css")) {
278
+ checks.push("desktop refinement stylesheet is not served as CSS");
279
+ }
280
+ if (desktopBridge.status !== 200 || !(desktopBridge.headers["content-type"] || "").includes("javascript")) {
281
+ checks.push("desktop bridge is not served as JavaScript");
282
+ }
283
+ if (i18n.status !== 200 || !i18n.body.includes("applyTranslations") || !i18n.body.includes('"zh-CN"') || !i18n.body.includes("en:")) {
284
+ checks.push("shared Chinese/English translation dictionary is unavailable");
285
+ }
286
+ if (gettingStarted.status !== 200 || (gettingStarted.body.match(/class="readiness-item"/g) || []).length !== 4 || !gettingStarted.body.includes("home.manual")) {
287
+ checks.push("desktop getting-started page is missing its four readiness checks or manual ChatGPT state");
288
+ }
289
+ if (gettingStartedJs.status !== 200 || !gettingStartedJs.body.includes('fetchJson("/api/status")') || !gettingStartedJs.body.includes("health_check")) {
290
+ checks.push("getting-started controller is missing bounded Tunnel status or health_check guidance");
291
+ }
292
+ if (settings.status !== 200 || !settings.body.includes("/settings.js")) {
293
+ checks.push("desktop settings page is unavailable or missing its bounded bridge");
294
+ }
295
+ for (const marker of ["detectTunnel", "chooseTunnel", "enableDirectProfile", "proxyScope", "saveRuntime", "tunnelId", "runtimeKey", "provisionTunnel", "forgetCredential", "language"]) {
296
+ if (!settings.body.includes(marker)) checks.push(`desktop settings missing runtime control: ${marker}`);
297
+ }
298
+ if (!desktopBridge.body.includes("patchwardenApplyTheme") || !desktopBridge.body.includes("请求超过 10 秒")) {
299
+ checks.push("desktop bridge is missing renderer theme propagation or bounded loading timeout");
300
+ }
301
+
242
302
  if (favicon.status !== 200) checks.push(`GET /favicon.ico -> status ${favicon.status}`);
243
303
  const faviconCt = favicon.headers["content-type"] || "";
244
304
  if (!faviconCt.includes("image/svg+xml")) checks.push(`GET /favicon.ico -> Content-Type ${faviconCt}`);
@@ -268,6 +328,9 @@ async function testPageNavigationRoutes() {
268
328
  "/pages/workspace.html",
269
329
  "/pages/audit.html",
270
330
  "/pages/task-detail.html?id=smoke",
331
+ "/settings.html",
332
+ "/pages/settings.html",
333
+ "/pages/getting-started.html",
271
334
  ];
272
335
 
273
336
  for (const route of routes) {
@@ -411,6 +474,13 @@ async function testTasksJson() {
411
474
  if (!Array.isArray(json.tasks)) problems.push("'tasks' is not an array");
412
475
  if (typeof json.total !== "number") problems.push("'total' is not a number");
413
476
  if (typeof json.returned !== "number") problems.push("'returned' is not a number");
477
+ if (!(json.nextCursor === null || typeof json.nextCursor === "string")) problems.push("'nextCursor' is neither null nor string");
478
+ if (!isObject(json.filters) || !isObject(json.filters.applied) || !isObject(json.filters.options)) problems.push("'filters' contract is missing");
479
+
480
+ const traversal = await httpGet(`${BASE_URL}/api/tasks/..%2Foutside`);
481
+ if (traversal.status !== 400) {
482
+ problems.push(`encoded task traversal returned ${traversal.status} (expected 400)`);
483
+ }
414
484
 
415
485
  if (problems.length === 0) {
416
486
  record(name, true);
@@ -823,7 +893,7 @@ async function testStaleTasksApi() {
823
893
 
824
894
  // ── Test 12: GET /api/workspace/<traversal>/status -> 400 ───────
825
895
  async function testWorkspaceRepoPathTraversal() {
826
- const name = "Test 12: /api/workspace/<traversal>/status rejected with 400";
896
+ const name = "Test 12: workspace status rejects traversal without rejecting dotted names";
827
897
  // Use percent-encoded dots to bypass URL-parser segment normalization;
828
898
  // after decode the repoParam is "../secret" which contains ".." and is
829
899
  // rejected by the server's traversal guard.
@@ -833,7 +903,12 @@ async function testWorkspaceRepoPathTraversal() {
833
903
  if (res.status === 400) {
834
904
  const json = tryJson(res.body);
835
905
  if (json && typeof json.error === "string" && /traversal/i.test(json.error)) {
836
- record(name, true);
906
+ const dotted = await httpGet(`${BASE_URL}/api/workspace/release..candidate/status`);
907
+ if (dotted.status === 404) {
908
+ record(name, true);
909
+ } else {
910
+ record(name, false, `valid dotted repo name returned ${dotted.status} (expected 404 for missing directory)`);
911
+ }
837
912
  } else {
838
913
  record(name, false, `status 400 but error field missing/invalid: ${res.body.slice(0, 200)}`);
839
914
  }
@@ -882,10 +957,17 @@ async function testDirectSessionsEmptyList() {
882
957
  const problems = [];
883
958
  if (!Array.isArray(json.sessions)) problems.push("'sessions' is not an array");
884
959
  if (typeof json.total !== "number") problems.push("'total' is not a number");
960
+ if (!(json.nextCursor === null || typeof json.nextCursor === "string")) problems.push("'nextCursor' is neither null nor string");
961
+ if (!isObject(json.filters) || !isObject(json.filters.options)) problems.push("'filters' contract is missing");
962
+ if (typeof json.direct_profile_enabled !== "boolean") problems.push("'direct_profile_enabled' is not a boolean");
885
963
  if (json.reason !== null && typeof json.reason !== "string") problems.push("'reason' is neither null nor string");
886
964
  if (Array.isArray(json.sessions) && json.sessions.length !== json.total) {
887
965
  problems.push(`sessions.length (${json.sessions.length}) != total (${json.total})`);
888
966
  }
967
+ const invalidDetail = await httpGet(`${BASE_URL}/api/direct-sessions/invalid.id`);
968
+ const invalidSummary = await httpGet(`${BASE_URL}/api/direct-sessions/invalid.id/summary`);
969
+ if (invalidDetail.status !== 400) problems.push(`invalid detail id returned ${invalidDetail.status} (expected 400)`);
970
+ if (invalidSummary.status !== 400) problems.push(`invalid summary id returned ${invalidSummary.status} (expected 400)`);
889
971
  if (problems.length === 0) {
890
972
  record(name, true);
891
973
  } else {
@@ -915,6 +997,8 @@ async function testLogsTailParam() {
915
997
  if (typeof json.stderr !== "string") problems.push("'stderr' is not a string");
916
998
  if (json.tail !== 300) problems.push(`'tail' is ${json.tail} (expected 300)`);
917
999
  if (json.category !== "core") problems.push(`'category' is ${json.category} (expected "core")`);
1000
+ if (json.historical_snapshot !== true) problems.push("'historical_snapshot' is not true");
1001
+ if (json.redacted !== true) problems.push("'redacted' is not true");
918
1002
  if (problems.length === 0) {
919
1003
  record(name, true);
920
1004
  } else {
@@ -1440,7 +1524,7 @@ async function main() {
1440
1524
  process.exit(1);
1441
1525
  }
1442
1526
 
1443
- child = spawn("node", [serverPath], {
1527
+ child = spawn(process.execPath, [serverPath], {
1444
1528
  cwd: projectRoot,
1445
1529
  env: {
1446
1530
  ...process.env,
@@ -1480,6 +1564,7 @@ async function main() {
1480
1564
  console.log(`[control-center-smoke] server ready at ${BASE_URL}`);
1481
1565
 
1482
1566
  await testStaticFiles();
1567
+ await testLoopbackHostBoundary();
1483
1568
  await testPageNavigationRoutes();
1484
1569
  await testStatusJson();
1485
1570
  await testTasksJson();
@@ -139,12 +139,13 @@ try {
139
139
 
140
140
  const expectedFiles = [
141
141
  "PatchWarden.cmd",
142
- "PatchWarden-Control.cmd",
143
- "PatchWarden-Control-Tray.cmd",
144
- "PatchWarden-Desktop.cmd",
145
- "Restart-PatchWarden-Control.cmd",
146
- "Stop-PatchWarden.cmd",
142
+ "scripts/launchers/PatchWarden-Control.cmd",
143
+ "scripts/launchers/PatchWarden-Control-Tray.cmd",
144
+ "scripts/launchers/PatchWarden-Desktop.cmd",
145
+ "scripts/launchers/Restart-PatchWarden-Control.cmd",
146
+ "scripts/launchers/Stop-PatchWarden.cmd",
147
147
  "scripts/control/manage-patchwarden.ps1",
148
+ "scripts/control/run-background-supervisor.ps1",
148
149
  "scripts/control/stop-patchwarden.ps1",
149
150
  "scripts/launchers/Start-PatchWarden-Tunnel.cmd",
150
151
  "scripts/launchers/Start-PatchWarden-Direct-Tunnel.cmd",
@@ -158,14 +159,24 @@ try {
158
159
  if (!rootEntry.includes("manage-patchwarden.ps1")) {
159
160
  throw new Error("PatchWarden.cmd does not invoke the consolidated manager");
160
161
  }
161
- const stopEntry = readFileSync(join(root, "Stop-PatchWarden.cmd"), "utf8");
162
- if (!stopEntry.includes("scripts\\control\\stop-patchwarden.ps1")) {
162
+ const stopEntry = readFileSync(join(root, "scripts", "launchers", "Stop-PatchWarden.cmd"), "utf8");
163
+ if (!stopEntry.includes("control\\stop-patchwarden.ps1")) {
163
164
  throw new Error("Stop-PatchWarden.cmd does not invoke the one-click shutdown script");
164
165
  }
165
- const desktopEntry = readFileSync(join(root, "PatchWarden-Desktop.cmd"), "utf8");
166
+ const desktopEntry = readFileSync(join(root, "scripts", "launchers", "PatchWarden-Desktop.cmd"), "utf8");
166
167
  if (!desktopEntry.includes("control-center-tray.ps1") || !desktopEntry.includes("WindowStyle Hidden")) {
167
168
  throw new Error("PatchWarden-Desktop.cmd must launch the tray hidden as the daily desktop entry");
168
169
  }
170
+ const managerSource = readFileSync(manager, "utf8");
171
+ const wrapperSource = readFileSync(join(root, "scripts", "control", "run-background-supervisor.ps1"), "utf8");
172
+ for (const expected of ["supervisor-status.json", "supervisor.stdout.log", "supervisor.stderr.log", "run-background-supervisor.ps1", "Write-BackgroundStartingState"]) {
173
+ if (!managerSource.includes(expected)) {
174
+ throw new Error(`background manager is missing supervisor observability: ${expected}`);
175
+ }
176
+ }
177
+ if (!wrapperSource.includes("1> $stdout 2> $stderr") || wrapperSource.includes("CONTROL_PLANE_API_KEY")) {
178
+ throw new Error("background wrapper must redirect supervisor logs without credential arguments");
179
+ }
169
180
  console.log("ok - control handles orphan cleanup, scoped kill, port conflicts, health fallback, and Core/Direct lifecycle actions");
170
181
  } finally {
171
182
  if (fakeTunnel?.exitCode === null) fakeTunnel.kill();
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
  import { spawn } from "node:child_process";
3
+ import http from "node:http";
3
4
  import {
4
5
  existsSync,
5
6
  mkdirSync,
6
7
  mkdtempSync,
8
+ readFileSync,
7
9
  rmSync,
8
10
  writeFileSync,
9
11
  } from "node:fs";
@@ -11,7 +13,7 @@ import { tmpdir } from "node:os";
11
13
  import { dirname, join, resolve } from "node:path";
12
14
  import { fileURLToPath } from "node:url";
13
15
  import { setTimeout as sleep } from "node:timers/promises";
14
- import { CHATGPT_CORE_TOOL_NAMES } from "../../dist/tools/toolCatalog.js";
16
+ import { CHATGPT_CORE_TOOL_NAMES } from "../../dist/tools/catalog/toolCatalog.js";
15
17
 
16
18
  const __dirname = dirname(fileURLToPath(import.meta.url));
17
19
  const root = resolve(__dirname, "..", "..");
@@ -96,6 +98,25 @@ function toolJson(result) {
96
98
  return JSON.parse(toolText(result));
97
99
  }
98
100
 
101
+ function requestWithHost(path, hostHeader) {
102
+ return new Promise((resolvePromise, rejectPromise) => {
103
+ const request = http.request({
104
+ hostname: host,
105
+ port,
106
+ path,
107
+ method: "GET",
108
+ headers: { Host: hostHeader },
109
+ }, (response) => {
110
+ let body = "";
111
+ response.setEncoding("utf-8");
112
+ response.on("data", (chunk) => { body += chunk; });
113
+ response.on("end", () => resolvePromise({ status: response.statusCode, body }));
114
+ });
115
+ request.on("error", rejectPromise);
116
+ request.end();
117
+ });
118
+ }
119
+
99
120
  console.log("\n=== PatchWarden HTTP MCP Smoke Tests ===\n");
100
121
 
101
122
  try {
@@ -126,7 +147,7 @@ try {
126
147
  );
127
148
 
128
149
  console.log(`Starting HTTP MCP server on ${mcpUrl}...`);
129
- serverProcess = spawn("node", [serverPath], {
150
+ serverProcess = spawn(process.execPath, [serverPath], {
130
151
  cwd: root,
131
152
  env: {
132
153
  ...process.env,
@@ -163,6 +184,13 @@ try {
163
184
  }
164
185
  });
165
186
 
187
+ await test("HTTP MCP rejects DNS-rebinding Host headers", async () => {
188
+ const response = await requestWithHost("/healthz", "patchwarden.attacker.invalid");
189
+ if (response.status !== 421 || !response.body.includes("Untrusted Host")) {
190
+ throw new Error(`Unexpected hostile Host response: ${JSON.stringify(response)}`);
191
+ }
192
+ });
193
+
166
194
  await test("wrong endpoint returns structured 404 guidance", async () => {
167
195
  const response = await fetch(`http://${host}:${port}/wrong-path`);
168
196
  const data = await response.json();
@@ -262,7 +290,7 @@ try {
262
290
 
263
291
  // Start server WITH owner token
264
292
  console.log("\n Starting server with owner token...");
265
- serverProcess = spawn("node", [serverPath], {
293
+ serverProcess = spawn(process.execPath, [serverPath], {
266
294
  cwd: root,
267
295
  env: {
268
296
  ...process.env,
@@ -278,7 +306,7 @@ try {
278
306
  // Wait for server to be ready
279
307
  for (let i = 0; i < 10; i++) {
280
308
  try {
281
- const r = await fetch(`${mcpUrl}/healthz`);
309
+ const r = await fetch(`http://${host}:${port}/healthz`);
282
310
  if (r.status === 200) break;
283
311
  } catch {}
284
312
  await sleep(500);
@@ -328,6 +356,56 @@ try {
328
356
  }
329
357
  });
330
358
 
359
+ const acceptanceTaskId = "task_http_acceptance";
360
+ const acceptanceTaskDir = join(workspaceRoot, ".patchwarden", "tasks", acceptanceTaskId);
361
+ mkdirSync(acceptanceTaskDir, { recursive: true });
362
+ writeFileSync(join(acceptanceTaskDir, "status.json"), JSON.stringify({
363
+ task_id: acceptanceTaskId,
364
+ status: "done_by_agent",
365
+ acceptance_status: "pending",
366
+ }), "utf-8");
367
+
368
+ await test("admin acceptance requires the owner token", async () => {
369
+ const response = await fetch(`http://${host}:${port}/admin/tasks/${acceptanceTaskId}/accept`, {
370
+ method: "POST",
371
+ headers: { "content-type": "application/json" },
372
+ body: JSON.stringify({ notes: "reviewed" }),
373
+ });
374
+ if (response.status !== 401) throw new Error(`Expected 401, got ${response.status}`);
375
+ });
376
+
377
+ await test("admin acceptance writes bounded atomic evidence", async () => {
378
+ const secret = `ghp_${"a".repeat(24)}`;
379
+ const response = await fetch(`http://${host}:${port}/admin/tasks/${acceptanceTaskId}/accept`, {
380
+ method: "POST",
381
+ headers: {
382
+ "content-type": "application/json",
383
+ Authorization: `Bearer ${OWNER_TOKEN}`,
384
+ },
385
+ body: JSON.stringify({ notes: `reviewed ${secret}` }),
386
+ });
387
+ if (response.status !== 200) throw new Error(`Expected 200, got ${response.status}: ${await response.text()}`);
388
+ const acceptance = JSON.parse(readFileSync(join(acceptanceTaskDir, "acceptance.json"), "utf-8"));
389
+ const status = JSON.parse(readFileSync(join(acceptanceTaskDir, "status.json"), "utf-8"));
390
+ if (acceptance.status !== "accepted" || status.acceptance_status !== "accepted") {
391
+ throw new Error("Acceptance state was not persisted consistently");
392
+ }
393
+ if (JSON.stringify(acceptance).includes(secret)) throw new Error("Acceptance notes persisted a token");
394
+ if (existsSync(join(acceptanceTaskDir, "status.json.lock"))) throw new Error("Status lock was not released");
395
+ });
396
+
397
+ await test("admin acceptance rejects oversized request bodies", async () => {
398
+ const response = await fetch(`http://${host}:${port}/admin/tasks/${acceptanceTaskId}/reject`, {
399
+ method: "POST",
400
+ headers: {
401
+ "content-type": "application/json",
402
+ Authorization: `Bearer ${OWNER_TOKEN}`,
403
+ },
404
+ body: JSON.stringify({ reason: "x".repeat(70 * 1024) }),
405
+ });
406
+ if (response.status !== 413) throw new Error(`Expected 413, got ${response.status}`);
407
+ });
408
+
331
409
  } catch (error) {
332
410
  fail("HTTP MCP smoke setup", error);
333
411
  } finally {
@@ -152,16 +152,16 @@ try {
152
152
  );
153
153
  process.env.PATCHWARDEN_CONFIG = configPath;
154
154
 
155
- const { savePlan } = await import("../../dist/tools/savePlan.js");
156
- const { createTask } = await import("../../dist/tools/createTask.js");
157
- const { getTaskStatus } = await import("../../dist/tools/getTaskStatus.js");
158
- const { cancelTask } = await import("../../dist/tools/cancelTask.js");
159
- const { killTask } = await import("../../dist/tools/killTask.js");
160
- const { getDiff } = await import("../../dist/tools/taskOutputs.js");
161
- const { listAgents } = await import("../../dist/tools/listAgents.js");
162
- const { getTaskSummary } = await import("../../dist/tools/getTaskSummary.js");
163
- const { auditTask } = await import("../../dist/tools/auditTask.js");
164
- const { waitForTask } = await import("../../dist/tools/waitForTask.js");
155
+ const { savePlan } = await import("../../dist/tools/goals/savePlan.js");
156
+ const { createTask } = await import("../../dist/tools/tasks/createTask.js");
157
+ const { getTaskStatus } = await import("../../dist/tools/tasks/getTaskStatus.js");
158
+ const { cancelTask } = await import("../../dist/tools/tasks/cancelTask.js");
159
+ const { killTask } = await import("../../dist/tools/tasks/killTask.js");
160
+ const { getDiff } = await import("../../dist/tools/tasks/taskOutputs.js");
161
+ const { listAgents } = await import("../../dist/tools/workspace/listAgents.js");
162
+ const { getTaskSummary } = await import("../../dist/tools/tasks/getTaskSummary.js");
163
+ const { auditTask } = await import("../../dist/tools/diagnostics/auditTask.js");
164
+ const { waitForTask } = await import("../../dist/tools/tasks/waitForTask.js");
165
165
  const { runTask } = await import("../../dist/runner/runTask.js");
166
166
  const { reloadConfig } = await import("../../dist/config.js");
167
167
 
@@ -4,7 +4,7 @@ import { resolve } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
6
6
  import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
7
- import { CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES, CHATGPT_SEARCH_TOOL_NAMES } from "../../dist/tools/toolCatalog.js";
7
+ import { CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES, CHATGPT_SEARCH_TOOL_NAMES } from "../../dist/tools/catalog/toolCatalog.js";
8
8
 
9
9
  const root = resolve(fileURLToPath(new URL("../..", import.meta.url)));
10
10
  const jsonOnly = process.argv.includes("--json");