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
@@ -1,242 +0,0 @@
1
- import { describe, it } from "node:test";
2
- import { strict as assert } from "node:assert";
3
- import { runReleaseGateCheck, checkPublishedVerified, checkGitHubReleaseVerified, checkCiVerified, computeTokenDigest, } from "../../release/releaseGate.js";
4
- // ── Mock helpers ───────────────────────────────────────────────────
5
- /**
6
- * Build a mock httpGet that responds based on the URL.
7
- * Each responder returns an HttpResponse synchronously (wrapped in a Promise).
8
- */
9
- function mockHttpGet(responder) {
10
- return async (url) => responder(url);
11
- }
12
- /**
13
- * Build a mock httpGet that captures headers (for token-leak assertions).
14
- */
15
- function mockHttpGetCapture(responder, capture) {
16
- return async (url, headers) => {
17
- capture.headers = { ...(headers || {}) };
18
- return responder(url);
19
- };
20
- }
21
- /**
22
- * Build a mock httpGet that always throws (simulates network error).
23
- */
24
- function mockHttpGetError(error) {
25
- return async () => {
26
- throw error;
27
- };
28
- }
29
- // ── 1. checkPublishedVerified ──────────────────────────────────────
30
- describe("checkPublishedVerified", () => {
31
- it("version exists → passed", async () => {
32
- const httpGet = mockHttpGet(() => ({
33
- statusCode: 200,
34
- data: { versions: { "1.0.0": {}, "0.9.0": {} } },
35
- }));
36
- const result = await checkPublishedVerified("patchwarden", "1.0.0", httpGet);
37
- assert.equal(result.status, "passed");
38
- });
39
- it("version does not exist → failed", async () => {
40
- const httpGet = mockHttpGet(() => ({
41
- statusCode: 200,
42
- data: { versions: { "0.9.0": {} } },
43
- }));
44
- const result = await checkPublishedVerified("patchwarden", "9.9.9", httpGet);
45
- assert.equal(result.status, "failed");
46
- assert.ok(result.reason?.includes("9.9.9"));
47
- });
48
- it("network error → not_checked", async () => {
49
- const httpGet = mockHttpGetError(new Error("connect ECONNREFUSED"));
50
- const result = await checkPublishedVerified("patchwarden", "1.0.0", httpGet);
51
- assert.equal(result.status, "not_checked");
52
- assert.ok(result.reason?.includes("Network error"));
53
- });
54
- it("package 404 → failed", async () => {
55
- const httpGet = mockHttpGet(() => ({
56
- statusCode: 404,
57
- data: { error: "Not found" },
58
- }));
59
- const result = await checkPublishedVerified("nonexistent-pkg", "1.0.0", httpGet);
60
- assert.equal(result.status, "failed");
61
- });
62
- });
63
- // ── 2. checkGitHubReleaseVerified ──────────────────────────────────
64
- describe("checkGitHubReleaseVerified", () => {
65
- it("200 → passed", async () => {
66
- const httpGet = mockHttpGet(() => ({
67
- statusCode: 200,
68
- data: { tag_name: "v1.0.0" },
69
- }));
70
- const result = await checkGitHubReleaseVerified("user/repo", "v1.0.0", httpGet);
71
- assert.equal(result.status, "passed");
72
- });
73
- it("404 → failed", async () => {
74
- const httpGet = mockHttpGet(() => ({
75
- statusCode: 404,
76
- data: { message: "Not Found" },
77
- }));
78
- const result = await checkGitHubReleaseVerified("user/repo", "v1.0.0", httpGet);
79
- assert.equal(result.status, "failed");
80
- assert.ok(result.reason?.includes("v1.0.0"));
81
- });
82
- it("network error → not_checked", async () => {
83
- const httpGet = mockHttpGetError(new Error("connect ETIMEDOUT"));
84
- const result = await checkGitHubReleaseVerified("user/repo", "v1.0.0", httpGet);
85
- assert.equal(result.status, "not_checked");
86
- });
87
- it("token is used as Bearer but never appears in result", async () => {
88
- const TOKEN = "test-token";
89
- process.env.GITHUB_TOKEN = TOKEN;
90
- const capture = {};
91
- const httpGet = mockHttpGetCapture(() => ({ statusCode: 200, data: { tag_name: "v1.0.0" } }), capture);
92
- try {
93
- const result = await checkGitHubReleaseVerified("user/repo", "v1.0.0", httpGet);
94
- assert.equal(result.status, "passed");
95
- // Authorization header was set correctly (token used internally)
96
- assert.equal(capture.headers?.["Authorization"], `Bearer ${TOKEN}`);
97
- // Raw token must NOT appear anywhere in the serialized result
98
- const resultStr = JSON.stringify(result);
99
- assert.ok(!resultStr.includes(TOKEN), "raw GITHUB_TOKEN must not leak into the result object");
100
- // The token digest is different from the raw token
101
- const digest = computeTokenDigest(TOKEN);
102
- assert.ok(digest !== TOKEN, "digest must differ from raw token");
103
- assert.ok(digest.startsWith("sha256:"));
104
- }
105
- finally {
106
- delete process.env.GITHUB_TOKEN;
107
- }
108
- });
109
- });
110
- // ── 3. checkCiVerified ─────────────────────────────────────────────
111
- describe("checkCiVerified", () => {
112
- it("conclusion=success → passed", async () => {
113
- const httpGet = mockHttpGet(() => ({
114
- statusCode: 200,
115
- data: { workflow_runs: [{ conclusion: "success" }] },
116
- }));
117
- const result = await checkCiVerified("user/repo", "main", httpGet);
118
- assert.equal(result.status, "passed");
119
- });
120
- it("conclusion=failure → failed", async () => {
121
- const httpGet = mockHttpGet(() => ({
122
- statusCode: 200,
123
- data: { workflow_runs: [{ conclusion: "failure" }] },
124
- }));
125
- const result = await checkCiVerified("user/repo", "main", httpGet);
126
- assert.equal(result.status, "failed");
127
- });
128
- it("conclusion=null → not_checked", async () => {
129
- const httpGet = mockHttpGet(() => ({
130
- statusCode: 200,
131
- data: { workflow_runs: [{ conclusion: null }] },
132
- }));
133
- const result = await checkCiVerified("user/repo", "main", httpGet);
134
- assert.equal(result.status, "not_checked");
135
- });
136
- it("network error → not_checked", async () => {
137
- const httpGet = mockHttpGetError(new Error("connect ECONNREFUSED"));
138
- const result = await checkCiVerified("user/repo", "main", httpGet);
139
- assert.equal(result.status, "not_checked");
140
- });
141
- });
142
- // ── 4. runReleaseGateCheck orchestration ───────────────────────────
143
- describe("runReleaseGateCheck", () => {
144
- it("target=local_ready passed → local_ready=passed, rest not_checked, no blocked_reason", async () => {
145
- const deps = {
146
- checkLocalReady: () => ({ status: "passed" }),
147
- };
148
- const result = await runReleaseGateCheck("/fake/repo", "local_ready", {}, deps);
149
- assert.equal(result.target_stage, "local_ready");
150
- assert.equal(result.stages.local_ready, "passed");
151
- assert.equal(result.stages.packed_ready, "not_checked");
152
- assert.equal(result.stages.published_verified, "not_checked");
153
- assert.equal(result.stages.github_release_verified, "not_checked");
154
- assert.equal(result.stages.ci_verified, "not_checked");
155
- assert.equal(result.blocked_reason, undefined);
156
- });
157
- it("local_ready failed → subsequent stages all not_checked, blocked_reason non-empty", async () => {
158
- const deps = {
159
- checkLocalReady: () => ({ status: "failed", reason: "build exited with code 1" }),
160
- };
161
- const result = await runReleaseGateCheck("/fake/repo", "ci_verified", {
162
- packageName: "patchwarden",
163
- version: "1.0.0",
164
- githubRepo: "user/repo",
165
- branch: "main",
166
- }, deps);
167
- assert.equal(result.stages.local_ready, "failed");
168
- assert.equal(result.stages.packed_ready, "not_checked");
169
- assert.equal(result.stages.published_verified, "not_checked");
170
- assert.equal(result.stages.github_release_verified, "not_checked");
171
- assert.equal(result.stages.ci_verified, "not_checked");
172
- assert.ok(result.blocked_reason, "blocked_reason should be non-empty");
173
- assert.ok(result.blocked_reason.includes("local_ready"), "blocked_reason should mention the failed stage");
174
- });
175
- it("full pass-through: all stages passed up to ci_verified", async () => {
176
- const deps = {
177
- checkLocalReady: () => ({ status: "passed" }),
178
- checkPackedReady: () => ({ status: "passed", manifestPath: "/fake/release-artifact-manifest.json" }),
179
- checkPublishedVerified: async () => ({ status: "passed" }),
180
- checkGitHubReleaseVerified: async () => ({ status: "passed" }),
181
- checkCiVerified: async () => ({ status: "passed" }),
182
- };
183
- const result = await runReleaseGateCheck("/fake/repo", "ci_verified", {
184
- packageName: "patchwarden",
185
- version: "1.0.0",
186
- githubRepo: "user/repo",
187
- branch: "main",
188
- }, deps);
189
- assert.equal(result.stages.local_ready, "passed");
190
- assert.equal(result.stages.packed_ready, "passed");
191
- assert.equal(result.stages.published_verified, "passed");
192
- assert.equal(result.stages.github_release_verified, "passed");
193
- assert.equal(result.stages.ci_verified, "passed");
194
- assert.equal(result.blocked_reason, undefined);
195
- });
196
- it("missing options for a required stage → failed with clear reason", async () => {
197
- const deps = {
198
- checkLocalReady: () => ({ status: "passed" }),
199
- checkPackedReady: () => ({ status: "passed" }),
200
- };
201
- // published_verified needs packageName + version, neither provided
202
- const result = await runReleaseGateCheck("/fake/repo", "published_verified", {}, deps);
203
- assert.equal(result.stages.local_ready, "passed");
204
- assert.equal(result.stages.packed_ready, "passed");
205
- assert.equal(result.stages.published_verified, "failed");
206
- assert.ok(result.blocked_reason?.includes("published_verified"));
207
- });
208
- });
209
- // ── 5. Function name spelling (Verified, not Verfied) ─────────────
210
- describe("function name spelling", () => {
211
- it("checkPublishedVerified is a function (not Verfied)", () => {
212
- assert.equal(typeof checkPublishedVerified, "function");
213
- });
214
- it("checkGitHubReleaseVerified is a function", () => {
215
- assert.equal(typeof checkGitHubReleaseVerified, "function");
216
- });
217
- it("checkCiVerified is a function", () => {
218
- assert.equal(typeof checkCiVerified, "function");
219
- });
220
- it("runReleaseGateCheck is a function", () => {
221
- assert.equal(typeof runReleaseGateCheck, "function");
222
- });
223
- });
224
- // ── 6. computeTokenDigest ──────────────────────────────────────────
225
- describe("computeTokenDigest", () => {
226
- it("returns sha256: prefix with hex digest", () => {
227
- const digest = computeTokenDigest("test-token");
228
- assert.ok(digest.startsWith("sha256:"));
229
- // sha256 hex is 64 chars + "sha256:" prefix = 71 chars
230
- assert.equal(digest.length, 71);
231
- });
232
- it("does not contain the raw token", () => {
233
- const TOKEN = "test-token";
234
- const digest = computeTokenDigest(TOKEN);
235
- assert.ok(!digest.includes(TOKEN), "digest must not contain the raw token");
236
- });
237
- it("is deterministic for the same input", () => {
238
- const d1 = computeTokenDigest("abc");
239
- const d2 = computeTokenDigest("abc");
240
- assert.equal(d1, d2);
241
- });
242
- });
@@ -1 +0,0 @@
1
- export {};
@@ -1,380 +0,0 @@
1
- import { describe, it, beforeEach, afterEach } from "node:test";
2
- import { strict as assert } from "node:assert";
3
- import { mkdtempSync, rmSync, writeFileSync, readFileSync } from "node:fs";
4
- import { join, normalize } from "node:path";
5
- import { tmpdir } from "node:os";
6
- import { reloadConfig } from "../../config.js";
7
- import { runTaskLoopWithDeps } from "../../tools/runTaskLoop.js";
8
- import { getTaskLineage, writeTaskLineage } from "../../tools/taskLineage.js";
9
- let tempDir;
10
- let prevConfigEnv;
11
- function writeConfig() {
12
- const configPath = join(tempDir, "patchwarden.config.json");
13
- writeFileSync(configPath, JSON.stringify({
14
- workspaceRoot: tempDir,
15
- tasksDir: ".patchwarden/tasks",
16
- plansDir: ".patchwarden/plans",
17
- assessmentsDir: ".patchwarden/assessments",
18
- agents: {
19
- fake: { command: "fake-agent", args: [] },
20
- },
21
- allowedTestCommands: ["npm test", "npm run build"],
22
- directAllowedCommands: ["npm test", "npm run build"],
23
- defaultTaskTimeoutSeconds: 30,
24
- maxTaskTimeoutSeconds: 120,
25
- enableDirectProfile: true,
26
- }), "utf-8");
27
- prevConfigEnv = process.env.PATCHWARDEN_CONFIG;
28
- process.env.PATCHWARDEN_CONFIG = configPath;
29
- reloadConfig();
30
- }
31
- function depsFor(options) {
32
- const decisions = [...(options.decisions || ["allow"])];
33
- const tasks = [...(options.tasks || ["task-main"])];
34
- const calls = [];
35
- const deps = {
36
- createTask: ((input) => {
37
- calls.push(input.execution_mode === "assess_only" ? "assess" : "execute");
38
- if (input.execution_mode === "assess_only") {
39
- const decision = decisions.shift() || "allow";
40
- return {
41
- assessment_id: `assessment-${calls.length}`,
42
- decision,
43
- reason_codes: decision === "allow" ? ["repo_scoped"] : ["release_template_needs_confirm"],
44
- };
45
- }
46
- return { task_id: tasks.shift() || `task-${calls.length}`, status: "pending" };
47
- }),
48
- waitForTask: (async (taskId) => ({
49
- task_id: taskId,
50
- status: options.statuses?.[taskId] || "done_by_agent",
51
- phase: options.statuses?.[taskId] || "done_by_agent",
52
- terminal: true,
53
- continuation_required: false,
54
- next_action: "safe_audit",
55
- })),
56
- safeResult: ((taskId) => ({
57
- task_id: taskId,
58
- status: options.statuses?.[taskId] || "done_by_agent",
59
- terminal: true,
60
- verification: { status: options.verifications?.[taskId] || "passed" },
61
- next_action: "audit_or_accept",
62
- })),
63
- safeTestSummary: ((taskId) => ({
64
- task_id: taskId,
65
- status: options.verifications?.[taskId] || "passed",
66
- commands: [{ command: "npm test", status: options.verifications?.[taskId] || "passed", exit_code: 0 }],
67
- })),
68
- safeAudit: ((taskId) => {
69
- const audit = options.audits?.[taskId] || { verdict: "pass" };
70
- return {
71
- task_id: taskId,
72
- verdict: audit.verdict,
73
- fail_checks: (audit.fail || []).map((name) => ({ name, result: "fail" })),
74
- warn_checks: (audit.warn || []).map((name) => ({ name, result: "warn" })),
75
- recommended_next_actions: ["accept"],
76
- };
77
- }),
78
- createDirectSession: ((input) => ({
79
- session_id: "direct-test",
80
- repo_path: input.repo_path,
81
- resolved_repo_path: tempDir,
82
- workspace_clean: true,
83
- allowed_commands: ["npm test", "npm run build"],
84
- expires_at: "2026-07-04T13:00:00.000Z",
85
- next_action: "run_verification",
86
- })),
87
- runDirectVerificationBundle: (async () => ({
88
- session_id: "direct-test",
89
- status: options.directBundleStatus || "passed",
90
- command_count: 1,
91
- passed_commands: (options.directBundleStatus || "passed") === "passed" ? 1 : 0,
92
- failed_commands: (options.directBundleStatus || "passed") === "passed" ? 0 : 1,
93
- timed_out_commands: 0,
94
- commands: [{
95
- command: "npm test",
96
- passed: (options.directBundleStatus || "passed") === "passed",
97
- exit_code: (options.directBundleStatus || "passed") === "passed" ? 0 : 1,
98
- timed_out: false,
99
- redacted: false,
100
- redaction_categories: [],
101
- started_at: "2026-07-04T12:00:00.000Z",
102
- finished_at: "2026-07-04T12:00:01.000Z",
103
- }],
104
- large_logs_omitted: true,
105
- next_action: "safe_finalize_direct_session",
106
- })),
107
- safeFinalizeDirectSession: (() => ({
108
- session_id: "direct-test",
109
- finalized: true,
110
- changed_files_total: 0,
111
- next_action: "safe_audit_direct_session",
112
- })),
113
- safeAuditDirectSession: (() => ({
114
- session_id: "direct-test",
115
- decision: options.directAuditDecision || "pass",
116
- reason_codes: [],
117
- blocking_findings: [],
118
- warnings: [],
119
- evidence: { changed_files_total: 0, verification_runs: [] },
120
- next_action: "accept",
121
- })),
122
- writeTaskLineage,
123
- createLineageId: (() => "lineage_20260704_test"),
124
- recommendAgentForTask: ((input) => ({
125
- repo_path: input.repo_path,
126
- resolved_repo_path: tempDir,
127
- recommended_agent: "fake",
128
- fallback_agent: null,
129
- fallback: false,
130
- reason: "test route",
131
- risk_notes: [],
132
- suggested_verify_commands: ["npm test"],
133
- bounded: true,
134
- })),
135
- createWorktree: ((goalId, subgoalId, workspaceRoot) => {
136
- calls.push(`worktree:${workspaceRoot}`);
137
- return {
138
- worktreeId: "wt-test",
139
- worktreePath: tempDir,
140
- branch: "pw-test",
141
- };
142
- }),
143
- now: () => new Date("2026-07-04T12:00:00.000Z"),
144
- sleep: async () => { },
145
- };
146
- return { deps, calls };
147
- }
148
- describe("runTaskLoop", () => {
149
- beforeEach(() => {
150
- tempDir = mkdtempSync(join(tmpdir(), "pw-loop-"));
151
- writeConfig();
152
- });
153
- afterEach(() => {
154
- if (prevConfigEnv === undefined)
155
- delete process.env.PATCHWARDEN_CONFIG;
156
- else
157
- process.env.PATCHWARDEN_CONFIG = prevConfigEnv;
158
- reloadConfig();
159
- rmSync(tempDir, { recursive: true, force: true });
160
- });
161
- it("returns success with a bounded lineage summary", async () => {
162
- const { deps } = depsFor({});
163
- const result = await runTaskLoopWithDeps({
164
- repo_path: ".",
165
- goal: "Make a safe change",
166
- agent: "fake",
167
- verify_commands: ["npm test"],
168
- }, deps);
169
- assert.equal(result.stop_reason, "success");
170
- assert.equal(result.final_status, "accepted");
171
- assert.equal(result.tasks.main, "task-main");
172
- const payload = JSON.stringify(result);
173
- assert.ok(!payload.includes("stdout"));
174
- assert.ok(!payload.includes("stderr"));
175
- assert.ok(!payload.includes("diff.patch"));
176
- });
177
- it("keeps v1.3 behavior when direct_verify is false", async () => {
178
- const { deps } = depsFor({});
179
- const result = await runTaskLoopWithDeps({
180
- repo_path: ".",
181
- goal: "Run without Direct",
182
- agent: "fake",
183
- verify_commands: ["npm test"],
184
- direct_verify: false,
185
- }, deps);
186
- assert.equal(result.stop_reason, "success");
187
- assert.equal(result.direct_verify, false);
188
- assert.deepEqual(result.tasks.direct_sessions, []);
189
- assert.equal(result.isolation_mode, "current_repo");
190
- assert.equal(result.worktree.status, "not_used");
191
- });
192
- it("records bounded agent routing when agent is auto", async () => {
193
- const { deps } = depsFor({});
194
- const result = await runTaskLoopWithDeps({
195
- repo_path: ".",
196
- goal: "Pick a safe agent",
197
- agent: "auto",
198
- verify_commands: ["npm test"],
199
- scope_files: ["src/index.ts"],
200
- }, deps);
201
- assert.equal(result.stop_reason, "success");
202
- assert.equal(result.agent_routing?.requested_agent, "auto");
203
- assert.equal(result.agent_routing?.selected_agent, "fake");
204
- assert.equal(result.agent_routing?.reason, "test route");
205
- });
206
- it("uses worktree isolation for task execution and records worktree evidence", async () => {
207
- const { deps, calls } = depsFor({});
208
- const result = await runTaskLoopWithDeps({
209
- repo_path: "child-repo",
210
- goal: "Run in a worktree",
211
- agent: "fake",
212
- verify_commands: ["npm test"],
213
- isolation_mode: "worktree",
214
- worktree_cleanup: "keep",
215
- }, deps);
216
- assert.equal(result.stop_reason, "success");
217
- assert.equal(result.isolation_mode, "worktree");
218
- assert.equal(result.worktree.worktree_id, "wt-test");
219
- assert.equal(result.worktree.branch, "pw-test");
220
- assert.equal(result.worktree.status, "active");
221
- assert.ok(calls.includes(`worktree:${normalize(join(tempDir, "child-repo"))}`));
222
- });
223
- it("records Direct verification evidence when direct_verify succeeds", async () => {
224
- const { deps } = depsFor({});
225
- const result = await runTaskLoopWithDeps({
226
- repo_path: ".",
227
- goal: "Run with Direct verification",
228
- agent: "fake",
229
- verify_commands: ["npm test"],
230
- direct_verify: true,
231
- }, deps);
232
- assert.equal(result.stop_reason, "success");
233
- assert.equal(result.direct_verify, true);
234
- assert.equal(result.tasks.direct_sessions.length, 1);
235
- assert.equal(result.tasks.direct_sessions[0].session_id, "direct-test");
236
- assert.equal(result.tasks.direct_sessions[0].status, "passed");
237
- assert.equal(result.tasks.direct_sessions[0].audit_decision, "pass");
238
- const payload = JSON.stringify(result);
239
- assert.ok(!payload.includes("stdout_tail"));
240
- assert.ok(!payload.includes("stderr_tail"));
241
- assert.ok(!payload.includes("diff.patch"));
242
- });
243
- it("stops clearly when direct_verify is requested but Direct profile is disabled", async () => {
244
- const configPath = join(tempDir, "patchwarden.config.json");
245
- const raw = JSON.parse(readFileSync(configPath, "utf-8"));
246
- raw.enableDirectProfile = false;
247
- writeFileSync(configPath, JSON.stringify(raw), "utf-8");
248
- reloadConfig();
249
- const { deps } = depsFor({});
250
- const result = await runTaskLoopWithDeps({
251
- repo_path: ".",
252
- goal: "Run with unavailable Direct",
253
- agent: "fake",
254
- verify_commands: ["npm test"],
255
- direct_verify: true,
256
- }, deps);
257
- assert.equal(result.stop_reason, "direct_profile_disabled");
258
- assert.equal(result.final_status, "blocked");
259
- assert.equal(result.tasks.main, "task-main");
260
- assert.equal(result.tasks.direct_sessions[0].session_id, "not_created");
261
- });
262
- it("returns direct_verification_failed without leaking Direct logs", async () => {
263
- const { deps } = depsFor({ directBundleStatus: "failed" });
264
- const result = await runTaskLoopWithDeps({
265
- repo_path: ".",
266
- goal: "Run with failing Direct verification",
267
- agent: "fake",
268
- verify_commands: ["npm test"],
269
- direct_verify: true,
270
- }, deps);
271
- assert.equal(result.stop_reason, "direct_verification_failed");
272
- assert.equal(result.final_status, "needs_fix");
273
- assert.equal(result.tasks.direct_sessions[0].failed_commands, 1);
274
- const payload = JSON.stringify(result);
275
- assert.ok(!payload.includes("stdout_tail"));
276
- assert.ok(!payload.includes("stderr_tail"));
277
- });
278
- it("returns direct_audit_failed when Direct audit fails", async () => {
279
- const { deps } = depsFor({ directAuditDecision: "fail" });
280
- const result = await runTaskLoopWithDeps({
281
- repo_path: ".",
282
- goal: "Run with failing Direct audit",
283
- agent: "fake",
284
- verify_commands: ["npm test"],
285
- direct_verify: true,
286
- }, deps);
287
- assert.equal(result.stop_reason, "direct_audit_failed");
288
- assert.equal(result.final_status, "blocked");
289
- assert.equal(result.tasks.direct_sessions[0].audit_decision, "fail");
290
- });
291
- it("creates a fix_tests follow-up after failed verification", async () => {
292
- const { deps } = depsFor({
293
- tasks: ["task-main", "task-fix"],
294
- statuses: { "task-main": "failed_verification", "task-fix": "done_by_agent" },
295
- verifications: { "task-main": "failed", "task-fix": "passed" },
296
- audits: {
297
- "task-main": { verdict: "warn", warn: ["test_exit_code"] },
298
- "task-fix": { verdict: "pass" },
299
- },
300
- });
301
- const result = await runTaskLoopWithDeps({
302
- repo_path: ".",
303
- goal: "Repair tests",
304
- agent: "fake",
305
- verify_commands: ["npm test"],
306
- max_iterations: 2,
307
- }, deps);
308
- assert.equal(result.stop_reason, "success");
309
- assert.equal(result.tasks.main, "task-main");
310
- assert.deepEqual(result.tasks.fix, ["task-fix"]);
311
- assert.equal(result.rounds.length, 2);
312
- });
313
- it("stops before execution when assessment needs confirmation", async () => {
314
- const { deps, calls } = depsFor({ decisions: ["needs_confirm"] });
315
- const result = await runTaskLoopWithDeps({
316
- repo_path: ".",
317
- goal: "Release-like work",
318
- agent: "fake",
319
- verify_commands: ["npm test"],
320
- }, deps);
321
- assert.equal(result.stop_reason, "user_confirmation_required");
322
- assert.equal(result.stopped_before_execution, true);
323
- assert.deepEqual(calls, ["assess"]);
324
- });
325
- it("returns max_iterations_reached when verification keeps failing", async () => {
326
- const { deps } = depsFor({
327
- statuses: { "task-main": "failed_verification" },
328
- verifications: { "task-main": "failed" },
329
- audits: { "task-main": { verdict: "warn", warn: ["test_exit_code"] } },
330
- });
331
- const result = await runTaskLoopWithDeps({
332
- repo_path: ".",
333
- goal: "Fix tests",
334
- agent: "fake",
335
- verify_commands: ["npm test"],
336
- max_iterations: 1,
337
- }, deps);
338
- assert.equal(result.stop_reason, "max_iterations_reached");
339
- assert.equal(result.final_status, "needs_fix");
340
- });
341
- it("writes BOM-free lineage JSON readable through get_task_lineage", async () => {
342
- const { deps } = depsFor({});
343
- const result = await runTaskLoopWithDeps({
344
- repo_path: ".",
345
- goal: "Persist lineage",
346
- agent: "fake",
347
- verify_commands: ["npm test"],
348
- }, deps);
349
- const lineagePath = join(tempDir, ".patchwarden", "lineages", result.lineage_id, "lineage.json");
350
- const raw = readFileSync(lineagePath);
351
- assert.notEqual(raw[0], 0xef);
352
- const parsed = JSON.parse(raw.toString("utf-8"));
353
- assert.equal(parsed.lineage_id, result.lineage_id);
354
- const safe = getTaskLineage(result.lineage_id);
355
- assert.equal(safe.lineage_id, result.lineage_id);
356
- assert.equal(safe.rounds.length, 1);
357
- });
358
- it("reads legacy string direct_sessions as bounded evidence", () => {
359
- const safe = writeTaskLineage({
360
- lineage_id: "lineage_legacy_direct",
361
- goal: "Legacy lineage",
362
- repo_path: ".",
363
- created_at: "2026-07-04T12:00:00.000Z",
364
- updated_at: "2026-07-04T12:00:00.000Z",
365
- final_status: "accepted",
366
- stop_reason: "success",
367
- next_action: "accept",
368
- main_task: "task-main",
369
- fix_tasks: [],
370
- cleanup_tasks: [],
371
- direct_sessions: ["direct-old"],
372
- rounds: [],
373
- warnings: [],
374
- errors: [],
375
- });
376
- assert.equal(safe.tasks.direct_sessions[0].session_id, "direct-old");
377
- const readBack = getTaskLineage("lineage_legacy_direct");
378
- assert.equal(readBack.tasks.direct_sessions[0].session_id, "direct-old");
379
- });
380
- });
@@ -1 +0,0 @@
1
- export {};