patchwarden 1.5.0 → 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 (597) hide show
  1. package/PatchWarden.cmd +32 -2
  2. package/README.en.md +194 -26
  3. package/README.md +160 -22
  4. package/dist/assessments/agentAssessor.d.ts +1 -1
  5. package/dist/assessments/agentAssessor.js +24 -15
  6. package/dist/assessments/assessmentStore.d.ts +1 -1
  7. package/dist/assessments/assessmentStore.js +44 -36
  8. package/dist/assessments/confirmCli.js +5 -4
  9. package/dist/config.d.ts +22 -0
  10. package/dist/config.js +98 -11
  11. package/dist/control/fileManager.d.ts +2 -0
  12. package/dist/control/fileManager.js +39 -0
  13. package/dist/control/middleware/auth.d.ts +16 -0
  14. package/dist/control/middleware/auth.js +17 -0
  15. package/dist/control/middleware/static.d.ts +3 -0
  16. package/dist/control/middleware/static.js +78 -0
  17. package/dist/control/routeTable.d.ts +24 -0
  18. package/dist/control/routeTable.js +263 -0
  19. package/dist/control/routes/audit.d.ts +15 -0
  20. package/dist/control/routes/audit.js +287 -0
  21. package/dist/control/routes/evidence.d.ts +4 -0
  22. package/dist/control/routes/evidence.js +96 -0
  23. package/dist/control/routes/lineage.d.ts +3 -0
  24. package/dist/control/routes/lineage.js +71 -0
  25. package/dist/control/routes/policy.d.ts +3 -0
  26. package/dist/control/routes/policy.js +81 -0
  27. package/dist/control/routes/process.d.ts +12 -0
  28. package/dist/control/routes/process.js +487 -0
  29. package/dist/control/routes/sessions.d.ts +30 -0
  30. package/dist/control/routes/sessions.js +287 -0
  31. package/dist/control/routes/status.d.ts +51 -0
  32. package/dist/control/routes/status.js +307 -0
  33. package/dist/control/routes/taskActions.d.ts +21 -0
  34. package/dist/control/routes/taskActions.js +197 -0
  35. package/dist/control/routes/tasks.d.ts +24 -0
  36. package/dist/control/routes/tasks.js +309 -0
  37. package/dist/control/routes/workspace.d.ts +15 -0
  38. package/dist/control/routes/workspace.js +220 -0
  39. package/dist/control/runtime.d.ts +92 -0
  40. package/dist/control/runtime.js +425 -0
  41. package/dist/control/server.d.ts +13 -0
  42. package/dist/control/server.js +150 -0
  43. package/dist/control/shared.d.ts +59 -0
  44. package/dist/control/shared.js +341 -0
  45. package/dist/controlCenter.d.ts +6 -0
  46. package/dist/controlCenter.js +7 -2197
  47. package/dist/direct/directAudit.js +234 -225
  48. package/dist/direct/directGuards.d.ts +2 -1
  49. package/dist/direct/directGuards.js +72 -37
  50. package/dist/direct/directPatch.d.ts +6 -1
  51. package/dist/direct/directPatch.js +55 -8
  52. package/dist/direct/directSessionStore.d.ts +16 -6
  53. package/dist/direct/directSessionStore.js +127 -35
  54. package/dist/direct/directVerification.js +8 -16
  55. package/dist/doctor.d.ts +18 -1
  56. package/dist/doctor.js +614 -373
  57. package/dist/goal/acceptanceEngine.d.ts +1 -1
  58. package/dist/goal/goalProgress.js +75 -69
  59. package/dist/goal/goalReport.d.ts +54 -0
  60. package/dist/goal/goalReport.js +197 -0
  61. package/dist/goal/goalStatus.d.ts +8 -0
  62. package/dist/goal/goalStatus.js +10 -3
  63. package/dist/goal/goalStore.d.ts +9 -2
  64. package/dist/goal/goalStore.js +152 -45
  65. package/dist/goal/handoffExport.js +6 -6
  66. package/dist/goal/specKitImport.d.ts +63 -0
  67. package/dist/goal/specKitImport.js +221 -0
  68. package/dist/goal/subgoalSync.js +13 -10
  69. package/dist/goal/worktreeManager.d.ts +2 -0
  70. package/dist/goal/worktreeManager.js +209 -136
  71. package/dist/httpServer.js +126 -44
  72. package/dist/index.js +7 -4
  73. package/dist/logging.d.ts +7 -1
  74. package/dist/logging.js +13 -3
  75. package/dist/policy/projectPolicy.js +5 -2
  76. package/dist/release/releaseGate.d.ts +1 -1
  77. package/dist/release/releaseGate.js +78 -25
  78. package/dist/runner/agentInvocation.d.ts +14 -0
  79. package/dist/runner/agentInvocation.js +96 -4
  80. package/dist/runner/changeCapture.d.ts +14 -6
  81. package/dist/runner/changeCapture.js +287 -81
  82. package/dist/runner/cli.js +7 -6
  83. package/dist/runner/postTaskCleanup.js +60 -7
  84. package/dist/runner/processSecurity.d.ts +56 -0
  85. package/dist/runner/processSecurity.js +373 -0
  86. package/dist/runner/runTask.d.ts +1 -1
  87. package/dist/runner/runTask.js +339 -287
  88. package/dist/runner/simpleProcess.d.ts +3 -0
  89. package/dist/runner/simpleProcess.js +52 -38
  90. package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
  91. package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
  92. package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +1 -1
  93. package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
  94. package/dist/runner/taskStatusStore.d.ts +11 -0
  95. package/dist/runner/taskStatusStore.js +24 -0
  96. package/dist/runner/watch.d.ts +14 -1
  97. package/dist/runner/watch.js +265 -54
  98. package/dist/security/contentRedaction.d.ts +6 -0
  99. package/dist/security/contentRedaction.js +24 -2
  100. package/dist/security/discoveryTokenStore.d.ts +3 -2
  101. package/dist/security/discoveryTokenStore.js +17 -2
  102. package/dist/security/loopbackHost.d.ts +2 -0
  103. package/dist/security/loopbackHost.js +16 -0
  104. package/dist/security/pathGuard.js +32 -17
  105. package/dist/security/planGuard.js +2 -1
  106. package/dist/security/runtimeGuard.js +9 -6
  107. package/dist/security/secretComparison.d.ts +3 -0
  108. package/dist/security/secretComparison.js +11 -0
  109. package/dist/security/sensitiveGuard.d.ts +5 -0
  110. package/dist/security/sensitiveGuard.js +27 -8
  111. package/dist/security/toolInvocationGuard.d.ts +2 -2
  112. package/dist/security/toolInvocationGuard.js +1 -1
  113. package/dist/security/workspaceRootGuard.d.ts +8 -0
  114. package/dist/security/workspaceRootGuard.js +47 -0
  115. package/dist/smoke-test.js +280 -273
  116. package/dist/tools/catalog/index.d.ts +4 -0
  117. package/dist/tools/catalog/index.js +4 -0
  118. package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
  119. package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
  120. package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +28 -15
  121. package/dist/tools/definitions/toolDefs.d.ts +18 -0
  122. package/dist/tools/definitions/toolDefs.js +1177 -0
  123. package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
  124. package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
  125. package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +8 -63
  126. package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +111 -37
  127. package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +6 -6
  128. package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +10 -10
  129. package/dist/tools/diagnostics/index.d.ts +6 -0
  130. package/dist/tools/diagnostics/index.js +6 -0
  131. package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
  132. package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
  133. package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +14 -10
  134. package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +25 -15
  135. package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
  136. package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
  137. package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +1 -1
  138. package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +8 -8
  139. package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +2 -2
  140. package/dist/tools/direct/finalizeDirectSession.js +86 -0
  141. package/dist/tools/direct/index.d.ts +3 -0
  142. package/dist/tools/direct/index.js +3 -0
  143. package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
  144. package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
  145. package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
  146. package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
  147. package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
  148. package/dist/tools/discovery/index.d.ts +3 -0
  149. package/dist/tools/discovery/index.js +3 -0
  150. package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
  151. package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
  152. package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
  153. package/dist/tools/dispatch/coreDispatch.js +283 -0
  154. package/dist/tools/dispatch/diagnosticDispatch.d.ts +12 -0
  155. package/dist/tools/dispatch/diagnosticDispatch.js +80 -0
  156. package/dist/tools/dispatch/directDispatch.d.ts +8 -0
  157. package/dist/tools/dispatch/directDispatch.js +116 -0
  158. package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
  159. package/dist/tools/dispatch/goalDispatch.js +92 -0
  160. package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
  161. package/dist/tools/dispatch/releaseDispatch.js +46 -0
  162. package/dist/tools/dispatch/types.d.ts +23 -0
  163. package/dist/tools/dispatch/types.js +15 -0
  164. package/dist/tools/dispatch/validation.d.ts +7 -0
  165. package/dist/tools/dispatch/validation.js +71 -0
  166. package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
  167. package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +2 -2
  168. package/dist/tools/goals/goalSubgoalTask.js +118 -0
  169. package/dist/tools/goals/index.d.ts +3 -0
  170. package/dist/tools/goals/index.js +3 -0
  171. package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
  172. package/dist/tools/registry.d.ts +10 -14
  173. package/dist/tools/registry.js +47 -1651
  174. package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
  175. package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
  176. package/dist/tools/release/index.d.ts +2 -0
  177. package/dist/tools/release/index.js +2 -0
  178. package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
  179. package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
  180. package/dist/tools/tasks/cancelTask.d.ts +11 -0
  181. package/dist/tools/tasks/cancelTask.js +85 -0
  182. package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +12 -4
  183. package/dist/tools/{createTask.js → tasks/createTask.js} +46 -31
  184. package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
  185. package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +8 -8
  186. package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +6 -0
  187. package/dist/tools/tasks/evidencePack.js +387 -0
  188. package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
  189. package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
  190. package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +5 -5
  191. package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
  192. package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +33 -26
  193. package/dist/tools/tasks/index.d.ts +18 -0
  194. package/dist/tools/tasks/index.js +18 -0
  195. package/dist/tools/tasks/killTask.d.ts +1 -0
  196. package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
  197. package/dist/tools/{listTasks.js → tasks/listTasks.js} +3 -3
  198. package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +1 -1
  199. package/dist/tools/{reconcileTasks.js → tasks/reconcileTasks.js} +64 -66
  200. package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +2 -2
  201. package/dist/tools/tasks/retryTask.js +60 -0
  202. package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
  203. package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +59 -31
  204. package/dist/tools/tasks/runVerification.js +38 -0
  205. package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
  206. package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
  207. package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
  208. package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
  209. package/dist/tools/workspace/applyPatch.js +53 -0
  210. package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
  211. package/dist/tools/workspace/index.d.ts +10 -0
  212. package/dist/tools/workspace/index.js +10 -0
  213. package/dist/tools/{listAgents.d.ts → workspace/listAgents.d.ts} +5 -0
  214. package/dist/tools/{listAgents.js → workspace/listAgents.js} +8 -4
  215. package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
  216. package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
  217. package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
  218. package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
  219. package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
  220. package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
  221. package/dist/tools/workspace/syncFile.js +134 -0
  222. package/dist/utils/atomicFile.d.ts +7 -0
  223. package/dist/utils/atomicFile.js +48 -0
  224. package/dist/utils/boundedFile.d.ts +8 -0
  225. package/dist/utils/boundedFile.js +93 -0
  226. package/dist/utils/lockedJsonFile.d.ts +15 -0
  227. package/dist/utils/lockedJsonFile.js +224 -0
  228. package/dist/utils/platform.d.ts +11 -0
  229. package/dist/utils/platform.js +26 -0
  230. package/dist/utils/stableJson.d.ts +2 -0
  231. package/dist/utils/stableJson.js +12 -0
  232. package/dist/version.d.ts +3 -2
  233. package/dist/version.js +3 -2
  234. package/dist/watcherStatus.d.ts +2 -2
  235. package/dist/watcherStatus.js +18 -0
  236. package/docs/CODE_WIKI.md +1648 -0
  237. package/docs/agentseal-integration.md +150 -0
  238. package/docs/architecture.md +23 -0
  239. package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
  240. package/docs/assets/patchwarden-oss-demo.gif +0 -0
  241. package/docs/control-center/README.md +4 -4
  242. package/docs/dashboard-overview.md +86 -0
  243. package/docs/demo.md +8 -0
  244. package/docs/desktop-app.md +175 -0
  245. package/docs/direct-session-workflow.md +98 -0
  246. package/docs/evidence-pack-schema.md +215 -0
  247. package/docs/lineage-evidence-pack-workflow.md +127 -0
  248. package/docs/mcp-inspector-testing.md +200 -0
  249. package/docs/open-source-application.md +168 -0
  250. package/docs/opencode-worker.md +151 -0
  251. package/docs/openhands-worker.md +181 -0
  252. package/docs/release-checklist.md +1 -1
  253. package/docs/release-evidence.md +82 -0
  254. package/docs/spec-kit-integration.md +131 -0
  255. package/docs/task-safe-review-workflow.md +98 -0
  256. package/docs/threat-model.md +97 -0
  257. package/docs/user-feedback.md +40 -0
  258. package/docs/why-patchwarden.md +110 -0
  259. package/examples/config.example.json +4 -2
  260. package/package.json +28 -11
  261. package/scripts/README.md +15 -6
  262. package/scripts/build.js +11 -0
  263. package/scripts/checks/brand-check.js +3 -0
  264. package/scripts/checks/build-output-check.js +37 -0
  265. package/scripts/checks/control-center-smoke.js +447 -6
  266. package/scripts/checks/control-smoke.js +19 -8
  267. package/scripts/checks/http-mcp-smoke.js +82 -4
  268. package/scripts/checks/lifecycle-smoke.js +39 -33
  269. package/scripts/checks/mcp-manifest-check.js +1 -1
  270. package/scripts/checks/mcp-smoke.js +30 -4
  271. package/scripts/checks/package-manifest-check.js +20 -7
  272. package/scripts/checks/unit-tests.js +3 -5
  273. package/scripts/checks/watcher-supervisor-smoke.js +9 -0
  274. package/scripts/control/get-patchwarden-health.ps1 +1 -1
  275. package/scripts/control/manage-patchwarden.ps1 +69 -4
  276. package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
  277. package/scripts/control/run-background-supervisor.ps1 +41 -0
  278. package/scripts/control/start-patchwarden-tunnel.ps1 +126 -32
  279. package/scripts/generate-demo-gif.py +320 -0
  280. package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
  281. package/scripts/launchers/PatchWarden-Control.cmd +6 -0
  282. package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
  283. package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
  284. package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
  285. package/scripts/lib/clean-generated-output.js +11 -0
  286. package/scripts/lib/file-discovery.js +12 -0
  287. package/scripts/release/desktop-preflight.js +211 -0
  288. package/scripts/release/pack-clean.js +59 -14
  289. package/src/assessments/agentAssessor.ts +29 -15
  290. package/src/assessments/assessmentStore.ts +55 -43
  291. package/src/assessments/confirmCli.ts +5 -4
  292. package/src/config.ts +105 -11
  293. package/src/control/fileManager.ts +40 -0
  294. package/src/control/middleware/auth.ts +35 -0
  295. package/src/control/middleware/static.ts +84 -0
  296. package/src/control/routeTable.ts +301 -0
  297. package/src/control/routes/audit.ts +329 -0
  298. package/src/control/routes/evidence.ts +107 -0
  299. package/src/control/routes/lineage.ts +92 -0
  300. package/src/control/routes/policy.ts +81 -0
  301. package/src/control/routes/process.ts +505 -0
  302. package/src/control/routes/sessions.ts +314 -0
  303. package/src/control/routes/status.ts +405 -0
  304. package/src/control/routes/taskActions.ts +214 -0
  305. package/src/control/routes/tasks.ts +331 -0
  306. package/src/control/routes/workspace.ts +234 -0
  307. package/src/control/runtime.ts +508 -0
  308. package/src/control/server.ts +165 -0
  309. package/src/control/shared.ts +360 -0
  310. package/src/controlCenter.ts +7 -2347
  311. package/src/direct/directAudit.ts +17 -9
  312. package/src/direct/directGuards.ts +100 -51
  313. package/src/direct/directPatch.ts +95 -8
  314. package/src/direct/directSessionStore.ts +211 -55
  315. package/src/direct/directVerification.ts +9 -23
  316. package/src/doctor.ts +766 -492
  317. package/src/goal/acceptanceEngine.ts +1 -1
  318. package/src/goal/goalProgress.ts +17 -13
  319. package/src/goal/goalReport.ts +263 -0
  320. package/src/goal/goalStatus.ts +25 -3
  321. package/src/goal/goalStore.ts +241 -54
  322. package/src/goal/handoffExport.ts +6 -6
  323. package/src/goal/specKitImport.ts +355 -0
  324. package/src/goal/subgoalSync.ts +15 -10
  325. package/src/goal/worktreeManager.ts +139 -22
  326. package/src/httpServer.ts +130 -44
  327. package/src/index.ts +7 -4
  328. package/src/logging.ts +20 -4
  329. package/src/policy/projectPolicy.ts +5 -2
  330. package/src/release/releaseGate.ts +74 -27
  331. package/src/runner/agentInvocation.ts +126 -4
  332. package/src/runner/changeCapture.ts +342 -80
  333. package/src/runner/cli.ts +7 -6
  334. package/src/runner/postTaskCleanup.ts +55 -7
  335. package/src/runner/processSecurity.ts +433 -0
  336. package/src/runner/runTask.ts +441 -292
  337. package/src/runner/simpleProcess.ts +68 -33
  338. package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
  339. package/src/{taskRuntime.ts → runner/taskRuntime.ts} +4 -3
  340. package/src/runner/taskStatusStore.ts +54 -0
  341. package/src/runner/watch.ts +290 -57
  342. package/src/security/contentRedaction.ts +31 -2
  343. package/src/security/discoveryTokenStore.ts +18 -4
  344. package/src/security/loopbackHost.ts +19 -0
  345. package/src/security/pathGuard.ts +35 -16
  346. package/src/security/planGuard.ts +2 -1
  347. package/src/security/runtimeGuard.ts +9 -6
  348. package/src/security/secretComparison.ts +13 -0
  349. package/src/security/sensitiveGuard.ts +27 -8
  350. package/src/security/toolInvocationGuard.ts +2 -2
  351. package/src/security/workspaceRootGuard.ts +53 -0
  352. package/src/smoke-test.ts +276 -273
  353. package/src/tools/catalog/index.ts +4 -0
  354. package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
  355. package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +29 -16
  356. package/src/tools/definitions/toolDefs.ts +1264 -0
  357. package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
  358. package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +196 -89
  359. package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +11 -11
  360. package/src/tools/diagnostics/index.ts +6 -0
  361. package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
  362. package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +29 -19
  363. package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
  364. package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +9 -9
  365. package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +11 -9
  366. package/src/tools/direct/index.ts +3 -0
  367. package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
  368. package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
  369. package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
  370. package/src/tools/discovery/index.ts +3 -0
  371. package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
  372. package/src/tools/dispatch/coreDispatch.ts +379 -0
  373. package/src/tools/dispatch/diagnosticDispatch.ts +106 -0
  374. package/src/tools/dispatch/directDispatch.ts +168 -0
  375. package/src/tools/dispatch/goalDispatch.ts +128 -0
  376. package/src/tools/dispatch/releaseDispatch.ts +66 -0
  377. package/src/tools/dispatch/types.ts +24 -0
  378. package/src/tools/dispatch/validation.ts +78 -0
  379. package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
  380. package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +43 -28
  381. package/src/tools/goals/index.ts +3 -0
  382. package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
  383. package/src/tools/registry.ts +54 -1858
  384. package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
  385. package/src/tools/release/index.ts +2 -0
  386. package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
  387. package/src/tools/tasks/cancelTask.ts +109 -0
  388. package/src/tools/{createTask.ts → tasks/createTask.ts} +56 -33
  389. package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +8 -8
  390. package/src/tools/tasks/evidencePack.ts +504 -0
  391. package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
  392. package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +7 -5
  393. package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
  394. package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +44 -33
  395. package/src/tools/tasks/index.ts +18 -0
  396. package/src/tools/{listTasks.ts → tasks/listTasks.ts} +4 -4
  397. package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +68 -66
  398. package/src/tools/tasks/retryTask.ts +69 -0
  399. package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +70 -35
  400. package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
  401. package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
  402. package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
  403. package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
  404. package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
  405. package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
  406. package/src/tools/workspace/index.ts +10 -0
  407. package/src/tools/{listAgents.ts → workspace/listAgents.ts} +11 -4
  408. package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
  409. package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
  410. package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
  411. package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
  412. package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
  413. package/src/tools/workspace/syncFile.ts +292 -0
  414. package/src/utils/atomicFile.ts +58 -0
  415. package/src/utils/boundedFile.ts +116 -0
  416. package/src/utils/lockedJsonFile.ts +251 -0
  417. package/src/utils/platform.ts +31 -0
  418. package/src/utils/stableJson.ts +12 -0
  419. package/src/version.ts +3 -2
  420. package/src/watcherStatus.ts +19 -1
  421. package/ui/desktop-bootstrap.js +11 -0
  422. package/ui/desktop-bridge.js +36 -0
  423. package/ui/desktop.css +160 -0
  424. package/ui/getting-started.js +93 -0
  425. package/ui/i18n.js +484 -0
  426. package/ui/log-parser.js +30 -0
  427. package/ui/pages/audit.html +204 -3
  428. package/ui/pages/dashboard.html +937 -79
  429. package/ui/pages/direct-sessions.html +609 -60
  430. package/ui/pages/getting-started.html +43 -0
  431. package/ui/pages/logs.html +105 -22
  432. package/ui/pages/settings.html +101 -0
  433. package/ui/pages/task-detail.html +468 -438
  434. package/ui/pages/tasks.html +648 -65
  435. package/ui/pages/workspace.html +38 -1
  436. package/ui/settings.js +245 -0
  437. package/PatchWarden-Control.cmd +0 -6
  438. package/Restart-PatchWarden-Control.cmd +0 -6
  439. package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
  440. package/dist/test/unit/acceptance-engine.test.js +0 -228
  441. package/dist/test/unit/agent-router.test.d.ts +0 -1
  442. package/dist/test/unit/agent-router.test.js +0 -287
  443. package/dist/test/unit/android-doctor.test.d.ts +0 -1
  444. package/dist/test/unit/android-doctor.test.js +0 -118
  445. package/dist/test/unit/audit-checks.test.d.ts +0 -1
  446. package/dist/test/unit/audit-checks.test.js +0 -350
  447. package/dist/test/unit/chinese-path.test.d.ts +0 -1
  448. package/dist/test/unit/chinese-path.test.js +0 -91
  449. package/dist/test/unit/command-guard.test.d.ts +0 -1
  450. package/dist/test/unit/command-guard.test.js +0 -160
  451. package/dist/test/unit/diagnose-task.test.d.ts +0 -1
  452. package/dist/test/unit/diagnose-task.test.js +0 -457
  453. package/dist/test/unit/direct-guards.test.d.ts +0 -1
  454. package/dist/test/unit/direct-guards.test.js +0 -213
  455. package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
  456. package/dist/test/unit/discovery-token-store.test.js +0 -139
  457. package/dist/test/unit/evidence-pack.test.d.ts +0 -1
  458. package/dist/test/unit/evidence-pack.test.js +0 -130
  459. package/dist/test/unit/goal-graph.test.d.ts +0 -1
  460. package/dist/test/unit/goal-graph.test.js +0 -298
  461. package/dist/test/unit/goal-progress.test.d.ts +0 -1
  462. package/dist/test/unit/goal-progress.test.js +0 -381
  463. package/dist/test/unit/goal-status.test.d.ts +0 -1
  464. package/dist/test/unit/goal-status.test.js +0 -215
  465. package/dist/test/unit/goal-store.test.d.ts +0 -1
  466. package/dist/test/unit/goal-store.test.js +0 -253
  467. package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
  468. package/dist/test/unit/goal-subgoal-task.test.js +0 -55
  469. package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
  470. package/dist/test/unit/goal-tools-registry.test.js +0 -190
  471. package/dist/test/unit/handoff-export.test.d.ts +0 -1
  472. package/dist/test/unit/handoff-export.test.js +0 -263
  473. package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
  474. package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
  475. package/dist/test/unit/logging.test.d.ts +0 -1
  476. package/dist/test/unit/logging.test.js +0 -397
  477. package/dist/test/unit/path-guard.test.d.ts +0 -1
  478. package/dist/test/unit/path-guard.test.js +0 -109
  479. package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
  480. package/dist/test/unit/post-task-cleanup.test.js +0 -48
  481. package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
  482. package/dist/test/unit/project-policy-release-mode.test.js +0 -125
  483. package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
  484. package/dist/test/unit/reconcile-tasks.test.js +0 -456
  485. package/dist/test/unit/release-gate.test.d.ts +0 -1
  486. package/dist/test/unit/release-gate.test.js +0 -242
  487. package/dist/test/unit/run-task-loop.test.d.ts +0 -1
  488. package/dist/test/unit/run-task-loop.test.js +0 -380
  489. package/dist/test/unit/safe-status.test.d.ts +0 -1
  490. package/dist/test/unit/safe-status.test.js +0 -165
  491. package/dist/test/unit/safe-views.test.d.ts +0 -1
  492. package/dist/test/unit/safe-views.test.js +0 -171
  493. package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
  494. package/dist/test/unit/schema-drift-check.test.js +0 -176
  495. package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
  496. package/dist/test/unit/sensitive-guard.test.js +0 -104
  497. package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
  498. package/dist/test/unit/subgoal-sync.test.js +0 -183
  499. package/dist/test/unit/sync-file.test.d.ts +0 -1
  500. package/dist/test/unit/sync-file.test.js +0 -154
  501. package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
  502. package/dist/test/unit/tool-invocation-guard.test.js +0 -432
  503. package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
  504. package/dist/test/unit/tool-usage-stats.test.js +0 -300
  505. package/dist/test/unit/toolSearch.test.d.ts +0 -1
  506. package/dist/test/unit/toolSearch.test.js +0 -571
  507. package/dist/test/unit/watcher-status.test.d.ts +0 -1
  508. package/dist/test/unit/watcher-status.test.js +0 -169
  509. package/dist/test/unit/worktree-manager.test.d.ts +0 -1
  510. package/dist/test/unit/worktree-manager.test.js +0 -176
  511. package/dist/tools/applyPatch.js +0 -41
  512. package/dist/tools/cancelTask.d.ts +0 -30
  513. package/dist/tools/cancelTask.js +0 -64
  514. package/dist/tools/evidencePack.js +0 -168
  515. package/dist/tools/finalizeDirectSession.js +0 -84
  516. package/dist/tools/goalSubgoalTask.js +0 -110
  517. package/dist/tools/killTask.d.ts +0 -15
  518. package/dist/tools/retryTask.js +0 -45
  519. package/dist/tools/runVerification.js +0 -36
  520. package/dist/tools/syncFile.js +0 -65
  521. package/docs/control-center/control-center-daily-driver.md +0 -211
  522. package/docs/control-center/control-center-mvp.md +0 -205
  523. package/docs/control-center/control-center-phase2.md +0 -159
  524. package/docs/release-v0.6.0.md +0 -71
  525. package/docs/release-v0.6.1.md +0 -75
  526. package/docs/release-v0.6.4.md +0 -45
  527. package/src/test/unit/acceptance-engine.test.ts +0 -261
  528. package/src/test/unit/agent-router.test.ts +0 -342
  529. package/src/test/unit/android-doctor.test.ts +0 -158
  530. package/src/test/unit/audit-checks.test.ts +0 -567
  531. package/src/test/unit/chinese-path.test.ts +0 -106
  532. package/src/test/unit/command-guard.test.ts +0 -221
  533. package/src/test/unit/diagnose-task.test.ts +0 -544
  534. package/src/test/unit/direct-guards.test.ts +0 -297
  535. package/src/test/unit/discovery-token-store.test.ts +0 -181
  536. package/src/test/unit/evidence-pack.test.ts +0 -142
  537. package/src/test/unit/goal-graph.test.ts +0 -347
  538. package/src/test/unit/goal-progress.test.ts +0 -538
  539. package/src/test/unit/goal-status.test.ts +0 -270
  540. package/src/test/unit/goal-store.test.ts +0 -318
  541. package/src/test/unit/goal-subgoal-task.test.ts +0 -72
  542. package/src/test/unit/goal-tools-registry.test.ts +0 -243
  543. package/src/test/unit/handoff-export.test.ts +0 -295
  544. package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
  545. package/src/test/unit/logging.test.ts +0 -497
  546. package/src/test/unit/path-guard.test.ts +0 -150
  547. package/src/test/unit/post-task-cleanup.test.ts +0 -53
  548. package/src/test/unit/project-policy-release-mode.test.ts +0 -156
  549. package/src/test/unit/reconcile-tasks.test.ts +0 -551
  550. package/src/test/unit/release-gate.test.ts +0 -314
  551. package/src/test/unit/run-task-loop.test.ts +0 -425
  552. package/src/test/unit/safe-status.test.ts +0 -187
  553. package/src/test/unit/safe-views.test.ts +0 -184
  554. package/src/test/unit/schema-drift-check.test.ts +0 -260
  555. package/src/test/unit/sensitive-guard.test.ts +0 -124
  556. package/src/test/unit/subgoal-sync.test.ts +0 -236
  557. package/src/test/unit/sync-file.test.ts +0 -231
  558. package/src/test/unit/tool-invocation-guard.test.ts +0 -542
  559. package/src/test/unit/tool-usage-stats.test.ts +0 -384
  560. package/src/test/unit/toolSearch.test.ts +0 -756
  561. package/src/test/unit/watcher-status.test.ts +0 -190
  562. package/src/test/unit/worktree-manager.test.ts +0 -247
  563. package/src/tools/cancelTask.ts +0 -70
  564. package/src/tools/evidencePack.ts +0 -205
  565. package/src/tools/retryTask.ts +0 -53
  566. package/src/tools/syncFile.ts +0 -122
  567. /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
  568. /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
  569. /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
  570. /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
  571. /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
  572. /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
  573. /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
  574. /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
  575. /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
  576. /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
  577. /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
  578. /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
  579. /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
  580. /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
  581. /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
  582. /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
  583. /package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +0 -0
  584. /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
  585. /package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +0 -0
  586. /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
  587. /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
  588. /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
  589. /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
  590. /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
  591. /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
  592. /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
  593. /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
  594. /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
  595. /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
  596. /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
  597. /package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +0 -0
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Control Center routes — audit aggregation, warnings, and log tails.
3
+ *
4
+ * `handleAudit` joins independent-review.md + audit.json across tasks and
5
+ * direct sessions. `handleWarnings` buckets audit/stale/verification warnings
6
+ * by type. `handleLogs` returns redacted stdout/stderr tails for core, direct,
7
+ * watcher, and control-center log categories.
8
+ */
9
+ import { existsSync, readdirSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { listTasks } from "../../tools/tasks/listTasks.js";
12
+ import { redactSensitiveContent } from "../../security/contentRedaction.js";
13
+ import { getDirectSessionsDir, getTasksDir } from "../../config.js";
14
+ import { classifyStaleTask, fileMtimeIso, parseReviewVerdict, readWatcherStatusSafe, } from "../runtime.js";
15
+ import { config, errorMessage, findLatestLog, guardControlPath, getControlCenterLogDir, getRuntimeRoot, readFileTail, readJsonFileSafe, readTextFileSafe, sendJson, } from "../shared.js";
16
+ export function handleLogs(res, category, tailLines) {
17
+ try {
18
+ let dir;
19
+ let stdoutPath;
20
+ let stderrPath;
21
+ let stdoutExists;
22
+ let stderrExists;
23
+ if (category === "control-center") {
24
+ dir = getControlCenterLogDir();
25
+ stdoutPath = join(dir, "control-center.stdout.log");
26
+ stderrPath = join(dir, "control-center.stderr.log");
27
+ stdoutExists = existsSync(stdoutPath);
28
+ stderrExists = existsSync(stderrPath);
29
+ }
30
+ else if (category === "watcher") {
31
+ dir = getRuntimeRoot(false);
32
+ const sp = findLatestLog(dir, /^watcher-.*\.stdout\.log$/);
33
+ const ep = findLatestLog(dir, /^watcher-.*\.stderr\.log$/);
34
+ stdoutPath = sp ?? "";
35
+ stderrPath = ep ?? "";
36
+ stdoutExists = sp !== null;
37
+ stderrExists = ep !== null;
38
+ }
39
+ else {
40
+ // core | direct -> tunnel client logs in the matching runtime dir
41
+ dir = getRuntimeRoot(category === "direct");
42
+ stdoutPath = join(dir, "tunnel-client.stdout.log");
43
+ stderrPath = join(dir, "tunnel-client.stderr.log");
44
+ stdoutExists = existsSync(stdoutPath);
45
+ stderrExists = existsSync(stderrPath);
46
+ }
47
+ if (!stdoutExists && !stderrExists) {
48
+ sendJson(res, 200, {
49
+ stdout: "",
50
+ stderr: "",
51
+ category,
52
+ tail: tailLines,
53
+ historical_snapshot: true,
54
+ redacted: true,
55
+ reason: "log file not found",
56
+ });
57
+ return;
58
+ }
59
+ const stdoutRaw = stdoutExists ? readFileTail(stdoutPath, tailLines) : "";
60
+ const stderrRaw = stderrExists ? readFileTail(stderrPath, tailLines) : "";
61
+ const stdout = redactSensitiveContent(stdoutRaw).content;
62
+ const stderr = redactSensitiveContent(stderrRaw).content;
63
+ sendJson(res, 200, { stdout, stderr, category, tail: tailLines, historical_snapshot: true, redacted: true, reason: null });
64
+ }
65
+ catch (err) {
66
+ sendJson(res, 200, { stdout: "", stderr: "", category, tail: tailLines, historical_snapshot: true, redacted: true, reason: errorMessage(err) });
67
+ }
68
+ }
69
+ export function handleAudit(res) {
70
+ try {
71
+ const audits = [];
72
+ // 1. tasks/*/independent-review.md (written by audit_task — the primary audit artifact)
73
+ // 2. tasks/*/audit.json (legacy/explicit JSON audit, if present)
74
+ const tasksDir = getTasksDir(config);
75
+ if (existsSync(tasksDir)) {
76
+ let taskEntries = [];
77
+ try {
78
+ taskEntries = readdirSync(tasksDir, { withFileTypes: true }).filter((e) => e.isDirectory());
79
+ }
80
+ catch {
81
+ taskEntries = [];
82
+ }
83
+ for (const entry of taskEntries) {
84
+ const taskDir = guardControlPath(join(tasksDir, entry.name), config.tasksDir);
85
+ if (!taskDir)
86
+ continue;
87
+ // independent-review.md
88
+ const reviewFile = join(taskDir, "independent-review.md");
89
+ if (existsSync(reviewFile)) {
90
+ const content = readTextFileSafe(reviewFile) ?? "";
91
+ audits.push({
92
+ task_id: entry.name,
93
+ source: "independent-review.md",
94
+ verdict: parseReviewVerdict(content),
95
+ checked_at: fileMtimeIso(reviewFile),
96
+ content_excerpt: content.slice(0, 500),
97
+ });
98
+ }
99
+ // audit.json (explicit JSON audit if present)
100
+ const auditFile = join(taskDir, "audit.json");
101
+ if (existsSync(auditFile)) {
102
+ const data = readJsonFileSafe(auditFile);
103
+ if (data) {
104
+ audits.push({
105
+ task_id: entry.name,
106
+ source: "audit.json",
107
+ checked_at: data.checked_at ?? fileMtimeIso(auditFile),
108
+ ...data,
109
+ });
110
+ }
111
+ }
112
+ }
113
+ }
114
+ // 3. direct-sessions/*/audit.json (written by Direct audit_session)
115
+ const sessionsDir = getDirectSessionsDir(config);
116
+ if (existsSync(sessionsDir)) {
117
+ let sessionEntries = [];
118
+ try {
119
+ sessionEntries = readdirSync(sessionsDir, { withFileTypes: true }).filter((e) => e.isDirectory());
120
+ }
121
+ catch {
122
+ sessionEntries = [];
123
+ }
124
+ for (const entry of sessionEntries) {
125
+ const sessionDir = guardControlPath(join(sessionsDir, entry.name), config.directSessionsDir);
126
+ if (!sessionDir)
127
+ continue;
128
+ const auditFile = join(sessionDir, "audit.json");
129
+ if (!existsSync(auditFile))
130
+ continue;
131
+ const data = readJsonFileSafe(auditFile);
132
+ if (data) {
133
+ audits.push({
134
+ source: "direct-session",
135
+ session_id: data.session_id ?? entry.name,
136
+ checked_at: fileMtimeIso(auditFile),
137
+ ...data,
138
+ });
139
+ }
140
+ }
141
+ }
142
+ // Sort by checked_at descending (missing timestamps sort last).
143
+ audits.sort((a, b) => {
144
+ const ac = String(a.checked_at ?? "");
145
+ const bc = String(b.checked_at ?? "");
146
+ return bc.localeCompare(ac);
147
+ });
148
+ const limited = audits.slice(0, 50);
149
+ sendJson(res, 200, { audits: limited, total: limited.length });
150
+ }
151
+ catch (err) {
152
+ sendJson(res, 200, { audits: [], reason: errorMessage(err) });
153
+ }
154
+ }
155
+ /**
156
+ * Aggregate warnings from multiple sources:
157
+ * - audit.json warnings/fail_checks/possible_false_positives/manual_verification_required
158
+ * - stale task classification (heartbeat stale, collecting_artifacts stale, etc.)
159
+ * - task status=failed_verification
160
+ *
161
+ * Each warning type is grouped into a bucket with affected task IDs. The
162
+ * handler is fault-tolerant: any per-task read failure is skipped, and a
163
+ * top-level failure returns an empty warnings array (never 500).
164
+ */
165
+ export function handleWarnings(res) {
166
+ try {
167
+ const buckets = {
168
+ unrecorded_command_execution: new Set(),
169
+ artifact_hygiene: new Set(),
170
+ scope_changes: new Set(),
171
+ release_publish_claim: new Set(),
172
+ manual_verification_required: new Set(),
173
+ stale_task: new Set(),
174
+ failed_verification: new Set(),
175
+ };
176
+ const tasksDir = getTasksDir(config);
177
+ let taskList = [];
178
+ let watcher;
179
+ try {
180
+ const result = listTasks({ limit: 100 });
181
+ taskList = result.tasks;
182
+ watcher = result.watcher;
183
+ }
184
+ catch (err) {
185
+ watcher = readWatcherStatusSafe();
186
+ }
187
+ const now = Date.now();
188
+ for (const task of taskList) {
189
+ const taskId = task.task_id;
190
+ // 1. Read audit.json for warning strings
191
+ const taskDir = guardControlPath(join(tasksDir, taskId), config.tasksDir);
192
+ if (!taskDir)
193
+ continue;
194
+ const auditFile = join(taskDir, "audit.json");
195
+ const audit = readJsonFileSafe(auditFile);
196
+ if (audit) {
197
+ const warningTexts = [];
198
+ const collectStrings = (field) => {
199
+ if (Array.isArray(field)) {
200
+ for (const w of field) {
201
+ if (typeof w === "string") {
202
+ warningTexts.push(w);
203
+ }
204
+ else if (w && typeof w === "object") {
205
+ const obj = w;
206
+ if (typeof obj.message === "string")
207
+ warningTexts.push(obj.message);
208
+ else if (typeof obj.description === "string")
209
+ warningTexts.push(obj.description);
210
+ else if (typeof obj.warning === "string")
211
+ warningTexts.push(obj.warning);
212
+ else
213
+ warningTexts.push(JSON.stringify(obj));
214
+ }
215
+ }
216
+ }
217
+ else if (typeof field === "string") {
218
+ warningTexts.push(field);
219
+ }
220
+ };
221
+ collectStrings(audit.warnings);
222
+ collectStrings(audit.fail_checks);
223
+ collectStrings(audit.possible_false_positives);
224
+ for (const text of warningTexts) {
225
+ const lower = text.toLowerCase();
226
+ if (lower.includes("unrecorded") || lower.includes("command execution")) {
227
+ buckets.unrecorded_command_execution.add(taskId);
228
+ }
229
+ if (lower.includes("artifact") || lower.includes("hygiene")) {
230
+ buckets.artifact_hygiene.add(taskId);
231
+ }
232
+ if (lower.includes("scope") || lower.includes("out_of_scope")) {
233
+ buckets.scope_changes.add(taskId);
234
+ }
235
+ if (lower.includes("release") || lower.includes("publish")) {
236
+ buckets.release_publish_claim.add(taskId);
237
+ }
238
+ }
239
+ // manual_verification_required flag
240
+ if (audit.manual_verification_required === true) {
241
+ buckets.manual_verification_required.add(taskId);
242
+ }
243
+ }
244
+ // 2. Stale tasks
245
+ try {
246
+ const cls = classifyStaleTask(task, watcher, now);
247
+ if (cls.is_stale) {
248
+ buckets.stale_task.add(taskId);
249
+ }
250
+ }
251
+ catch {
252
+ // skip stale classification failure
253
+ }
254
+ // 3. Failed verification
255
+ if (task.status === "failed_verification") {
256
+ buckets.failed_verification.add(taskId);
257
+ }
258
+ }
259
+ const warnings = [];
260
+ const addWarning = (type, severity, likelyFalsePositive, needsFix, blocked, recommendedAction) => {
261
+ const tasks = buckets[type];
262
+ if (tasks.size === 0)
263
+ return;
264
+ warnings.push({
265
+ type,
266
+ severity,
267
+ affected_tasks_count: tasks.size,
268
+ affected_tasks: Array.from(tasks),
269
+ likely_false_positive: likelyFalsePositive,
270
+ needs_fix: needsFix,
271
+ blocked,
272
+ recommended_action: recommendedAction,
273
+ });
274
+ };
275
+ addWarning("failed_verification", "error", false, true, false, "Re-run verification or fix the failing checks before retrying.");
276
+ addWarning("stale_task", "warning", false, false, false, "Reconcile or recreate stale tasks.");
277
+ addWarning("manual_verification_required", "warning", false, false, false, "Review the audit findings and manually verify the changes.");
278
+ addWarning("unrecorded_command_execution", "info", false, true, false, "Investigate unrecorded command executions; ensure watcher captures all commands.");
279
+ addWarning("release_publish_claim", "info", false, false, true, "Verify the release/publish claim against actual release artifacts before proceeding.");
280
+ addWarning("artifact_hygiene", "info", true, false, false, "Review artifact hygiene warnings; many are likely false positives.");
281
+ addWarning("scope_changes", "info", true, false, false, "Review scope changes; verify they are intentional before accepting.");
282
+ sendJson(res, 200, { warnings, total: warnings.length });
283
+ }
284
+ catch (err) {
285
+ sendJson(res, 200, { warnings: [], total: 0, error: errorMessage(err) });
286
+ }
287
+ }
@@ -0,0 +1,4 @@
1
+ import { type ServerResponse } from "node:http";
2
+ export declare function handleEvidencePacks(res: ServerResponse): void;
3
+ export declare function handleEvidencePackDetail(res: ServerResponse, lineageId: string): void;
4
+ export declare function handleEvidencePackExport(res: ServerResponse, lineageId: string): void;
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Control Center routes — evidence packs (/api/evidence-packs/*).
3
+ *
4
+ * Lists exported evidence packs (bounded to 50), reads a single pack detail,
5
+ * and exports a pack for a lineage on demand. The export endpoint is a POST
6
+ * route gated by the control token in the server router.
7
+ */
8
+ import { existsSync, readdirSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { exportTaskEvidencePack, listEvidencePacks, readEvidencePack, } from "../../tools/tasks/evidencePack.js";
11
+ import { errorMessage, sendJson, config } from "../shared.js";
12
+ function augmentEvidencePackSummary(pack) {
13
+ const jsonExists = existsSync(pack.files.json);
14
+ const mdExists = existsSync(pack.files.markdown);
15
+ return {
16
+ ...pack,
17
+ export_status: jsonExists ? "exported" : "pending",
18
+ evidence_json_exists: jsonExists,
19
+ evidence_md_exists: mdExists,
20
+ exported_at: pack.generated_at,
21
+ };
22
+ }
23
+ export function handleEvidencePacks(res) {
24
+ try {
25
+ const list = listEvidencePacks({ max_items: 50 });
26
+ const packs = list.evidence_packs.map((pack) => augmentEvidencePackSummary(pack));
27
+ // Detect lineages that exist but have no exported evidence pack yet, so the
28
+ // dashboard can show an "Export evidence pack" action for the most recent one.
29
+ const lineagesRoot = join(config.workspaceRoot, ".patchwarden", "lineages");
30
+ let lineageCount = 0;
31
+ const exportedIds = new Set(packs.map((p) => p.lineage_id));
32
+ const pendingLineageIds = [];
33
+ if (existsSync(lineagesRoot)) {
34
+ const dirs = readdirSync(lineagesRoot, { withFileTypes: true }).filter((e) => e.isDirectory());
35
+ lineageCount = dirs.length;
36
+ for (const dir of dirs) {
37
+ if (!exportedIds.has(dir.name))
38
+ pendingLineageIds.push(dir.name);
39
+ }
40
+ }
41
+ sendJson(res, 200, {
42
+ evidence_packs: packs,
43
+ total: packs.length,
44
+ truncated: list.truncated,
45
+ has_lineages: lineageCount > 0,
46
+ lineage_count: lineageCount,
47
+ pending_lineage_ids: pendingLineageIds.slice(0, 20),
48
+ reason: null,
49
+ });
50
+ }
51
+ catch (err) {
52
+ sendJson(res, 200, { evidence_packs: [], total: 0, reason: errorMessage(err) });
53
+ }
54
+ }
55
+ export function handleEvidencePackDetail(res, lineageId) {
56
+ try {
57
+ if (!/^[A-Za-z0-9_-]+$/.test(lineageId)) {
58
+ sendJson(res, 400, { error: "Invalid lineage id" });
59
+ return;
60
+ }
61
+ const pack = readEvidencePack(lineageId);
62
+ if (!pack) {
63
+ sendJson(res, 404, { error: "Evidence pack not found" });
64
+ return;
65
+ }
66
+ sendJson(res, 200, augmentEvidencePackSummary(pack));
67
+ }
68
+ catch (err) {
69
+ sendJson(res, 200, { lineage_id: lineageId, error: errorMessage(err), bounded: true });
70
+ }
71
+ }
72
+ export function handleEvidencePackExport(res, lineageId) {
73
+ try {
74
+ if (!/^[A-Za-z0-9_-]+$/.test(lineageId)) {
75
+ sendJson(res, 400, { error: "Invalid lineage id" });
76
+ return;
77
+ }
78
+ // Check lineage exists.
79
+ const lineageFile = join(config.workspaceRoot, ".patchwarden", "lineages", lineageId, "lineage.json");
80
+ if (!existsSync(lineageFile)) {
81
+ sendJson(res, 404, { error: "Lineage not found" });
82
+ return;
83
+ }
84
+ // Check if already exported.
85
+ const evidenceJsonPath = join(config.workspaceRoot, ".patchwarden", "evidence-packs", lineageId, "evidence.json");
86
+ if (existsSync(evidenceJsonPath)) {
87
+ sendJson(res, 200, { ok: true, already_exported: true, lineage_id: lineageId });
88
+ return;
89
+ }
90
+ const pack = exportTaskEvidencePack({ lineage_id: lineageId });
91
+ sendJson(res, 200, { ok: true, exported: true, lineage_id: lineageId, evidence_pack_id: pack.evidence_pack_id });
92
+ }
93
+ catch (err) {
94
+ sendJson(res, 200, { ok: false, lineage_id: lineageId, error: errorMessage(err) });
95
+ }
96
+ }
@@ -0,0 +1,3 @@
1
+ import { type ServerResponse } from "node:http";
2
+ export declare function handleLineages(res: ServerResponse): void;
3
+ export declare function handleLineageDetail(res: ServerResponse, lineageId: string): void;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Control Center routes — task lineage (/api/lineages/*).
3
+ *
4
+ * Lists all lineages under .patchwarden/lineages (bounded to 50, most recently
5
+ * updated first) and serves a single lineage detail. Each record is projected
6
+ * through `toSafeTaskLineage` so full artifact content is bounded.
7
+ */
8
+ import { existsSync, readdirSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ import { toSafeTaskLineage } from "../../tools/tasks/taskLineage.js";
11
+ import { config, errorMessage, readJsonFileSafeUnder, sendJson } from "../shared.js";
12
+ function augmentLineageSummary(safe, record) {
13
+ const directSessions = safe.tasks.direct_sessions;
14
+ const firstDirect = directSessions.length > 0 ? directSessions[0] : null;
15
+ const directVerification = firstDirect
16
+ ? {
17
+ session_id: firstDirect.session_id,
18
+ status: firstDirect.status || "unknown",
19
+ audit_decision: firstDirect.audit_decision || "not_run",
20
+ command_count: firstDirect.command_count ?? 0,
21
+ passed_commands: firstDirect.passed_commands ?? 0,
22
+ failed_commands: firstDirect.failed_commands ?? 0,
23
+ }
24
+ : null;
25
+ return {
26
+ ...safe,
27
+ iterations: record.rounds.length,
28
+ main_task_count: record.main_task ? 1 : 0,
29
+ fix_task_count: record.fix_tasks.length,
30
+ cleanup_task_count: record.cleanup_tasks.length,
31
+ direct_verification: directVerification,
32
+ warnings_count: record.warnings.length,
33
+ };
34
+ }
35
+ export function handleLineages(res) {
36
+ try {
37
+ const root = join(config.workspaceRoot, ".patchwarden", "lineages");
38
+ if (!existsSync(root)) {
39
+ sendJson(res, 200, { lineages: [], total: 0, reason: null });
40
+ return;
41
+ }
42
+ const lineages = readdirSync(root, { withFileTypes: true })
43
+ .filter((entry) => entry.isDirectory())
44
+ .map((entry) => readJsonFileSafeUnder(root, join(entry.name, "lineage.json")))
45
+ .filter((entry) => entry !== null)
46
+ .map((entry) => augmentLineageSummary(toSafeTaskLineage(entry, 6), entry))
47
+ .sort((a, b) => b.updated_at.localeCompare(a.updated_at))
48
+ .slice(0, 50);
49
+ sendJson(res, 200, { lineages, total: lineages.length, reason: null });
50
+ }
51
+ catch (err) {
52
+ sendJson(res, 200, { lineages: [], total: 0, reason: errorMessage(err) });
53
+ }
54
+ }
55
+ export function handleLineageDetail(res, lineageId) {
56
+ try {
57
+ if (!/^[A-Za-z0-9_-]+$/.test(lineageId)) {
58
+ sendJson(res, 400, { error: "Invalid lineage id" });
59
+ return;
60
+ }
61
+ const data = readJsonFileSafeUnder(join(config.workspaceRoot, ".patchwarden", "lineages"), join(lineageId, "lineage.json"));
62
+ if (!data) {
63
+ sendJson(res, 404, { error: "Lineage not found" });
64
+ return;
65
+ }
66
+ sendJson(res, 200, augmentLineageSummary(toSafeTaskLineage(data, 20), data));
67
+ }
68
+ catch (err) {
69
+ sendJson(res, 200, { lineage_id: lineageId, error: errorMessage(err) });
70
+ }
71
+ }
@@ -0,0 +1,3 @@
1
+ import { type ServerResponse } from "node:http";
2
+ export declare function handleProjectPolicy(res: ServerResponse, repoPath: string): void;
3
+ export declare function handleReleaseStatus(res: ServerResponse, repoPath: string): void;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Control Center routes — project policy + release status.
3
+ *
4
+ * Read-only wrappers around `getProjectPolicySummary` that surface release
5
+ * readiness, blocked commands, and version consistency for the dashboard's
6
+ * release panel. Never performs remote writes (`remote_write_performed` is
7
+ * always false).
8
+ */
9
+ import { existsSync } from "node:fs";
10
+ import { join } from "node:path";
11
+ import { getProjectPolicySummary } from "../../policy/projectPolicy.js";
12
+ import { errorMessage, sendJson } from "../shared.js";
13
+ export function handleProjectPolicy(res, repoPath) {
14
+ try {
15
+ sendJson(res, 200, getProjectPolicySummary(repoPath || "."));
16
+ }
17
+ catch (err) {
18
+ sendJson(res, 200, {
19
+ repo_path: repoPath || ".",
20
+ valid: false,
21
+ issues: [{ code: "policy_unavailable", severity: "error", field: "repo_path", message: errorMessage(err) }],
22
+ });
23
+ }
24
+ }
25
+ export function handleReleaseStatus(res, repoPath) {
26
+ try {
27
+ const policy = getProjectPolicySummary(repoPath || ".");
28
+ const readiness = policy.release_readiness;
29
+ const requiredCommands = readiness.required_commands.map((c) => ({
30
+ command: c.command,
31
+ allowed: c.allowed,
32
+ blocked_reason: c.allowed ? null : (c.reason || "not_allowed"),
33
+ }));
34
+ const commandsBlockedCount = requiredCommands.filter((c) => !c.allowed).length;
35
+ const hasPackageJson = existsSync(join(policy.resolved_repo_path, "package.json"));
36
+ const versionSource = hasPackageJson
37
+ ? "package.json"
38
+ : (repoPath || ".") === "."
39
+ ? "workspace_root"
40
+ : "unknown";
41
+ let readyState;
42
+ if (!policy.valid || commandsBlockedCount > 0) {
43
+ readyState = "blocked";
44
+ }
45
+ else if (readiness.version === null) {
46
+ readyState = "unknown";
47
+ }
48
+ else if (readiness.version_consistent === true) {
49
+ readyState = "ready";
50
+ }
51
+ else {
52
+ readyState = "blocked";
53
+ }
54
+ sendJson(res, 200, {
55
+ repo_path: repoPath || ".",
56
+ resolved_repo_path: policy.resolved_repo_path,
57
+ policy_valid: policy.valid,
58
+ policy_issue_count: policy.issues.length,
59
+ policy_issues: policy.issues.slice(0, 10),
60
+ release_readiness: readiness,
61
+ package_name: readiness.package_name,
62
+ version_source: versionSource,
63
+ version_consistent: readiness.version_consistent,
64
+ required_commands: requiredCommands,
65
+ commands_blocked_count: commandsBlockedCount,
66
+ ready_state: readyState,
67
+ next_action: policy.valid && readiness.version_consistent !== false
68
+ ? "Run release_check via create_task template, or run_task_loop with template=release_check."
69
+ : "Fix project-policy or version consistency issues before release preparation.",
70
+ remote_write_performed: false,
71
+ });
72
+ }
73
+ catch (err) {
74
+ sendJson(res, 200, {
75
+ repo_path: repoPath || ".",
76
+ policy_valid: false,
77
+ error: errorMessage(err),
78
+ remote_write_performed: false,
79
+ });
80
+ }
81
+ }
@@ -0,0 +1,12 @@
1
+ import { type ServerResponse } from "node:http";
2
+ type ControlMode = "core" | "direct";
3
+ export declare function resolveManageProfiles(mode: string, action: string, directEnabled: boolean): {
4
+ selected: ControlMode[];
5
+ skipped: ControlMode[];
6
+ };
7
+ declare function findTunnelClientExecutable(): string | null;
8
+ export declare function buildManageEnvironment(): NodeJS.ProcessEnv;
9
+ export { findTunnelClientExecutable };
10
+ export declare function classifySupervisorFailure(diagnosticText: string): string;
11
+ export declare function handleManageAction(res: ServerResponse, action: string, mode: string): Promise<void>;
12
+ export declare function handleOpenLogsFolder(res: ServerResponse): void;