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,128 @@
1
+ /**
2
+ * Dispatch handlers for Goal Session tools (v0.8.0+).
3
+ *
4
+ * Covers goal lifecycle, subgoal management, Spec Kit import,
5
+ * worktree merge/discard, and goal reporting.
6
+ */
7
+
8
+ import { createGoal, listGoals, readGoal, readGoalStatus } from "../../goal/goalStore.js";
9
+ import { suggestNextSubgoal } from "../../goal/goalGraph.js";
10
+ import { exportHandoff } from "../../goal/handoffExport.js";
11
+ import { acceptSubgoal, rejectSubgoal, summarizeGoalProgress } from "../../goal/goalProgress.js";
12
+ import { exportGoalReport } from "../../goal/goalReport.js";
13
+ import { importSpecKitTasks, parseSpecKitJson } from "../../goal/specKitImport.js";
14
+ import { createSubgoalTask } from "../goals/goalSubgoalTask.js";
15
+ import { mergeWorktreeTool } from "../workspace/mergeWorktree.js";
16
+ import { discardWorktreeTool } from "../workspace/discardWorktree.js";
17
+ import type { ToolHandlerMap } from "./types.js";
18
+ import { toResult } from "./types.js";
19
+ import { parseOptionalTaskTemplate } from "./validation.js";
20
+
21
+ export const goalHandlers: ToolHandlerMap = {
22
+ create_goal: async (args) => {
23
+ return toResult(
24
+ createGoal(
25
+ String(args?.repo_path ?? ""),
26
+ String(args?.title ?? ""),
27
+ String(args?.goal_description ?? ""),
28
+ ),
29
+ );
30
+ },
31
+
32
+ list_goals: async () => {
33
+ return toResult({ goals: listGoals() });
34
+ },
35
+
36
+ read_goal: async (args) => {
37
+ return toResult(readGoal(String(args?.goal_id ?? "")));
38
+ },
39
+
40
+ create_subgoal_task: async (args) => {
41
+ return toResult(
42
+ await createSubgoalTask({
43
+ goal_id: String(args?.goal_id ?? ""),
44
+ subgoal_title: String(args?.subgoal_title ?? ""),
45
+ depends_on: Array.isArray(args?.depends_on) ? args.depends_on.map(String) : undefined,
46
+ plan_id: args?.plan_id ? String(args.plan_id) : undefined,
47
+ inline_plan: args?.inline_plan ? String(args.inline_plan) : undefined,
48
+ plan_title: args?.plan_title ? String(args.plan_title) : undefined,
49
+ template: parseOptionalTaskTemplate(args?.template),
50
+ goal: args?.goal ? String(args.goal) : undefined,
51
+ agent: args?.agent ? String(args.agent) : undefined,
52
+ repo_path: String(args?.repo_path ?? ""),
53
+ test_command: args?.test_command ? String(args.test_command) : undefined,
54
+ verify_commands: Array.isArray(args?.verify_commands)
55
+ ? args.verify_commands.map(String)
56
+ : undefined,
57
+ timeout_seconds: args?.timeout_seconds ? Number(args.timeout_seconds) : undefined,
58
+ scope: Array.isArray(args?.scope) ? args.scope.map(String) : undefined,
59
+ forbidden: Array.isArray(args?.forbidden) ? args.forbidden.map(String) : undefined,
60
+ verification: Array.isArray(args?.verification) ? args.verification.map(String) : undefined,
61
+ done_evidence: Array.isArray(args?.done_evidence) ? args.done_evidence.map(String) : undefined,
62
+ isolate_worktree:
63
+ args?.isolate_worktree === undefined ? undefined : Boolean(args.isolate_worktree),
64
+ }),
65
+ );
66
+ },
67
+
68
+ accept_subgoal: async (args) => {
69
+ return toResult(
70
+ acceptSubgoal(String(args?.goal_id ?? ""), String(args?.subgoal_id ?? "")),
71
+ );
72
+ },
73
+
74
+ reject_subgoal: async (args) => {
75
+ return toResult(
76
+ rejectSubgoal(
77
+ String(args?.goal_id ?? ""),
78
+ String(args?.subgoal_id ?? ""),
79
+ String(args?.reason ?? ""),
80
+ ),
81
+ );
82
+ },
83
+
84
+ suggest_next_subgoal: async (args) => {
85
+ const goalStatus = readGoalStatus(String(args?.goal_id ?? ""));
86
+ return toResult(suggestNextSubgoal(goalStatus));
87
+ },
88
+
89
+ summarize_goal_progress: async (args) => {
90
+ return toResult(summarizeGoalProgress(String(args?.goal_id ?? "")));
91
+ },
92
+
93
+ export_handoff: async (args) => {
94
+ const goalId = String(args?.goal_id ?? "");
95
+ const goalStatus = readGoalStatus(goalId);
96
+ return toResult(exportHandoff(goalId, goalStatus));
97
+ },
98
+
99
+ export_goal_report: async (args) => {
100
+ const goalId = String(args?.goal_id ?? "");
101
+ return toResult(exportGoalReport(goalId));
102
+ },
103
+
104
+ import_speckit_tasks: async (args) => {
105
+ const goalId = String(args?.goal_id ?? "");
106
+ const jsonText = String(args?.spec_kit_json ?? "");
107
+ const input = parseSpecKitJson(jsonText);
108
+ return toResult(importSpecKitTasks(goalId, input));
109
+ },
110
+
111
+ merge_worktree: async (args) => {
112
+ return toResult(
113
+ mergeWorktreeTool({
114
+ worktree_id: String(args?.worktree_id ?? ""),
115
+ repo_path: String(args?.repo_path ?? ""),
116
+ }),
117
+ );
118
+ },
119
+
120
+ discard_worktree: async (args) => {
121
+ return toResult(
122
+ discardWorktreeTool({
123
+ worktree_id: String(args?.worktree_id ?? ""),
124
+ repo_path: String(args?.repo_path ?? ""),
125
+ }),
126
+ );
127
+ },
128
+ };
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Dispatch handlers for release-mode tools (v1.3.0+).
3
+ *
4
+ * Wraps releaseCheck, releasePrepare, releaseVerify, and releaseCleanup
5
+ * from releaseMode.ts.
6
+ */
7
+
8
+ import {
9
+ releaseCheck,
10
+ releasePrepare,
11
+ releaseVerify,
12
+ releaseCleanup,
13
+ } from "../release/releaseMode.js";
14
+ import type { ToolHandlerMap } from "./types.js";
15
+ import { toResult } from "./types.js";
16
+ import { parseReleaseStage } from "./validation.js";
17
+
18
+ export const releaseHandlers: ToolHandlerMap = {
19
+ release_check: async (args) => {
20
+ return toResult(
21
+ await releaseCheck({
22
+ repo_path: String(args?.repo_path ?? ""),
23
+ target_stage: parseReleaseStage(args?.target_stage),
24
+ package_name: args?.package_name ? String(args.package_name) : undefined,
25
+ version: args?.version ? String(args.version) : undefined,
26
+ github_repo: args?.github_repo ? String(args.github_repo) : undefined,
27
+ branch: args?.branch ? String(args.branch) : undefined,
28
+ }),
29
+ );
30
+ },
31
+
32
+ release_prepare: async (args) => {
33
+ return toResult(
34
+ releasePrepare({
35
+ repo_path: String(args?.repo_path ?? ""),
36
+ required_commands: Array.isArray(args?.required_commands)
37
+ ? args.required_commands.map(String)
38
+ : undefined,
39
+ timeout_seconds:
40
+ args?.timeout_seconds !== undefined ? Number(args.timeout_seconds) : undefined,
41
+ }),
42
+ );
43
+ },
44
+
45
+ release_verify: async (args) => {
46
+ return toResult(
47
+ await releaseVerify({
48
+ repo_path: String(args?.repo_path ?? ""),
49
+ package_name: args?.package_name ? String(args.package_name) : undefined,
50
+ version: args?.version ? String(args.version) : undefined,
51
+ github_repo: args?.github_repo ? String(args.github_repo) : undefined,
52
+ branch: args?.branch ? String(args.branch) : undefined,
53
+ }),
54
+ );
55
+ },
56
+
57
+ release_cleanup: async (args) => {
58
+ return toResult(
59
+ releaseCleanup({
60
+ repo_path: String(args?.repo_path ?? ""),
61
+ dry_run: args?.dry_run !== undefined ? Boolean(args.dry_run) : undefined,
62
+ patterns: Array.isArray(args?.patterns) ? args.patterns.map(String) : undefined,
63
+ }),
64
+ );
65
+ },
66
+ };
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Shared types and helpers for the dispatch map.
3
+ *
4
+ * Each domain dispatch file exports a `ToolHandlerMap` whose handlers
5
+ * directly call the existing tool functions — no logic is rewritten.
6
+ */
7
+
8
+ export type ToolHandler = (
9
+ args: Record<string, unknown> | undefined,
10
+ ) => Promise<{ content: Array<{ type: string; text: string }> }>;
11
+
12
+ export type ToolHandlerMap = Record<string, ToolHandler>;
13
+
14
+ /**
15
+ * Wrap a plain data value into the MCP CallToolResult content envelope.
16
+ * Mirrors the original `toResult` helper from registry.ts.
17
+ */
18
+ export function toResult(data: unknown): {
19
+ content: Array<{ type: string; text: string }>;
20
+ } {
21
+ return {
22
+ content: [{ type: "text" as const, text: JSON.stringify(data, null, 2) }],
23
+ };
24
+ }
@@ -0,0 +1,78 @@
1
+ import type { PatchOperation, PatchOperationType } from "../../direct/directPatch.js";
2
+ import type { ReleaseStage } from "../../release/releaseGate.js";
3
+ import { TASK_TEMPLATE_NAMES, type TaskTemplateName } from "../taskTemplates.js";
4
+
5
+ const RELEASE_STAGES: ReadonlySet<ReleaseStage> = new Set([
6
+ "local_ready",
7
+ "packed_ready",
8
+ "published_verified",
9
+ "github_release_verified",
10
+ "ci_verified",
11
+ ]);
12
+ const PATCH_OPERATION_TYPES: ReadonlySet<PatchOperationType> = new Set([
13
+ "replace_exact",
14
+ "insert_before",
15
+ "insert_after",
16
+ "replace_whole_file",
17
+ ]);
18
+ const PATCH_OCCURRENCES = new Set(["first", "all", "exactly_once"]);
19
+ const TASK_LOG_FILES = new Set(["stdout", "stderr", "test", "verify"]);
20
+
21
+ export function parseOptionalTaskTemplate(value: unknown): TaskTemplateName | undefined {
22
+ if (value === undefined || value === null || value === "") return undefined;
23
+ if (typeof value !== "string" || !TASK_TEMPLATE_NAMES.includes(value as TaskTemplateName)) {
24
+ throw new Error(`template must be one of: ${TASK_TEMPLATE_NAMES.join(", ")}`);
25
+ }
26
+ return value as TaskTemplateName;
27
+ }
28
+
29
+ export function parseReleaseStage(value: unknown): ReleaseStage {
30
+ const stage = value === undefined || value === null || value === ""
31
+ ? "local_ready"
32
+ : String(value);
33
+ if (!RELEASE_STAGES.has(stage as ReleaseStage)) {
34
+ throw new Error(`target_stage must be one of: ${[...RELEASE_STAGES].join(", ")}`);
35
+ }
36
+ return stage as ReleaseStage;
37
+ }
38
+
39
+ export function parseTaskLogFile(value: unknown): "stdout" | "stderr" | "test" | "verify" {
40
+ const file = value === undefined || value === null || value === "" ? "stdout" : String(value);
41
+ if (!TASK_LOG_FILES.has(file)) {
42
+ throw new Error(`file must be one of: ${[...TASK_LOG_FILES].join(", ")}`);
43
+ }
44
+ return file as "stdout" | "stderr" | "test" | "verify";
45
+ }
46
+
47
+ export function parsePatchOperations(value: unknown): PatchOperation[] {
48
+ if (!Array.isArray(value)) throw new Error("operations must be an array");
49
+ return value.map((entry, index) => {
50
+ if (!entry || typeof entry !== "object" || Array.isArray(entry)) {
51
+ throw new Error(`operations[${index}] must be an object`);
52
+ }
53
+ const record = entry as Record<string, unknown>;
54
+ if (typeof record.type !== "string" || !PATCH_OPERATION_TYPES.has(record.type as PatchOperationType)) {
55
+ throw new Error(`operations[${index}].type is invalid`);
56
+ }
57
+ if (typeof record.new_text !== "string") {
58
+ throw new Error(`operations[${index}].new_text must be a string`);
59
+ }
60
+ if (record.old_text !== undefined && typeof record.old_text !== "string") {
61
+ throw new Error(`operations[${index}].old_text must be a string`);
62
+ }
63
+ if (
64
+ record.occurrence !== undefined
65
+ && (typeof record.occurrence !== "string" || !PATCH_OCCURRENCES.has(record.occurrence))
66
+ ) {
67
+ throw new Error(`operations[${index}].occurrence is invalid`);
68
+ }
69
+ return {
70
+ type: record.type as PatchOperationType,
71
+ new_text: record.new_text,
72
+ ...(record.old_text === undefined ? {} : { old_text: record.old_text }),
73
+ ...(record.occurrence === undefined
74
+ ? {}
75
+ : { occurrence: record.occurrence as PatchOperation["occurrence"] }),
76
+ };
77
+ });
78
+ }
@@ -1,9 +1,9 @@
1
1
  import { readFileSync, existsSync } from "node:fs";
2
2
  import { resolve, join } from "node:path";
3
- import { getPlansDir, getConfig } from "../config.js";
4
- import { guardReadPath } from "../security/pathGuard.js";
5
- import { guardSensitivePath } from "../security/sensitiveGuard.js";
6
- import { redactSensitiveContent } from "../security/contentRedaction.js";
3
+ import { getPlansDir, getConfig } from "../../config.js";
4
+ import { guardReadPath } from "../../security/pathGuard.js";
5
+ import { guardSensitivePath } from "../../security/sensitiveGuard.js";
6
+ import { redactSensitiveContent } from "../../security/contentRedaction.js";
7
7
 
8
8
  export interface GetPlanInput {
9
9
  plan_id: string;
@@ -14,12 +14,14 @@
14
14
  * - createTask 内部使用 getConfig(),因此 workspaceRoot 由全局配置决定。
15
15
  */
16
16
 
17
- import { readGoalStatus, writeGoalStatus } from "../goal/goalStore.js";
18
- import { addSubgoal, linkTaskToSubgoal, updateSubgoalStatus, type Subgoal } from "../goal/goalStatus.js";
19
- import { createTask, type CreateTaskInput } from "./createTask.js";
20
- import { createWorktree, discardWorktree } from "../goal/worktreeManager.js";
21
- import { getConfig } from "../config.js";
22
- import { PatchWardenError } from "../errors.js";
17
+ import { mutateGoalStatusAsync } from "../../goal/goalStore.js";
18
+ import { addSubgoal, linkTaskToSubgoal, updateSubgoalStatus, type Subgoal } from "../../goal/goalStatus.js";
19
+ import { createTask, type CreateTaskInput } from "../tasks/createTask.js";
20
+ import { createWorktree, discardWorktree } from "../../goal/worktreeManager.js";
21
+ import { getConfig } from "../../config.js";
22
+ import { PatchWardenError } from "../../errors.js";
23
+ import { guardWorkspacePath } from "../../security/pathGuard.js";
24
+ import { resolve } from "node:path";
23
25
 
24
26
  // ── 类型定义 ──────────────────────────────────────────────────────
25
27
 
@@ -64,7 +66,7 @@ export interface CreateSubgoalTaskOutput {
64
66
  * @throws PatchWardenError("invalid_dependency") 当 depends_on 引用不存在的 subgoal
65
67
  * @throws PatchWardenError("invalid_execution_mode") 当 execution_mode 为 "assess_only"
66
68
  */
67
- export function createSubgoalTask(input: CreateSubgoalTaskInput): CreateSubgoalTaskOutput {
69
+ export async function createSubgoalTask(input: CreateSubgoalTaskInput): Promise<CreateSubgoalTaskOutput> {
68
70
  // assess_only 不产生 task,无法关联到 subgoal
69
71
  if (input.execution_mode === "assess_only") {
70
72
  throw new PatchWardenError(
@@ -76,17 +78,30 @@ export function createSubgoalTask(input: CreateSubgoalTaskInput): CreateSubgoalT
76
78
  );
77
79
  }
78
80
 
79
- // 1. 读取 goal_status.json,如果不存在抛 goal_not_found
80
- let goalStatus;
81
- try {
82
- goalStatus = readGoalStatus(input.goal_id);
83
- } catch {
81
+ const config = getConfig();
82
+ return mutateGoalStatusAsync(input.goal_id, async (goalStatus) => {
83
+ if (goalStatus.status !== "active") {
84
+ throw new PatchWardenError(
85
+ "goal_not_active",
86
+ `Goal "${input.goal_id}" is ${goalStatus.status} and cannot accept new subgoals.`,
87
+ "Create a new Goal Session for additional work.",
88
+ true,
89
+ { goal_id: input.goal_id, status: goalStatus.status },
90
+ );
91
+ }
92
+
93
+ const goalRepoPath = guardWorkspacePath(goalStatus.repo_path, config.workspaceRoot);
94
+ const requestedRepoPath = guardWorkspacePath(input.repo_path, config.workspaceRoot);
95
+ const sameRepo = process.platform === "win32"
96
+ ? resolve(goalRepoPath).toLowerCase() === resolve(requestedRepoPath).toLowerCase()
97
+ : resolve(goalRepoPath) === resolve(requestedRepoPath);
98
+ if (!sameRepo) {
84
99
  throw new PatchWardenError(
85
- "goal_not_found",
86
- `Goal "${input.goal_id}" not found`,
87
- "Call list_goals to see available goals.",
100
+ "goal_repo_mismatch",
101
+ `Subgoal repo_path does not match Goal "${input.goal_id}".`,
102
+ "Use the repo_path recorded on the Goal Session.",
88
103
  true,
89
- { goal_id: input.goal_id }
104
+ { goal_id: input.goal_id },
90
105
  );
91
106
  }
92
107
 
@@ -101,11 +116,10 @@ export function createSubgoalTask(input: CreateSubgoalTaskInput): CreateSubgoalT
101
116
  // 用 worktree 路径作为 createTask 的 repo_path,避免并发 task 互相污染。
102
117
  // isolate_worktree === false 时退化为原行为(使用 input.repo_path)。
103
118
  const isolate = input.isolate_worktree !== false;
104
- let repoPathForTask = input.repo_path;
119
+ let repoPathForTask = goalRepoPath;
105
120
  let worktreeId: string | null = null;
106
121
  if (isolate) {
107
- const workspaceRoot = getConfig().workspaceRoot;
108
- const wt = createWorktree(input.goal_id, subgoalId, workspaceRoot);
122
+ const wt = createWorktree(input.goal_id, subgoalId, goalRepoPath);
109
123
  repoPathForTask = wt.worktreePath;
110
124
  worktreeId = wt.worktreeId;
111
125
  }
@@ -113,7 +127,7 @@ export function createSubgoalTask(input: CreateSubgoalTaskInput): CreateSubgoalT
113
127
  // 3. 调用 createTask 创建关联任务(强制 execute 模式,确保返回 CreateTaskOutput)
114
128
  let taskId: string;
115
129
  try {
116
- const taskResult = createTask({
130
+ const taskResult = await createTask({
117
131
  plan_id: input.plan_id,
118
132
  inline_plan: input.inline_plan,
119
133
  plan_title: input.plan_title,
@@ -139,7 +153,7 @@ export function createSubgoalTask(input: CreateSubgoalTaskInput): CreateSubgoalT
139
153
  // createTask 失败:清理已创建的隔离 worktree,避免遗留半成品(best effort)
140
154
  if (isolate && worktreeId) {
141
155
  try {
142
- discardWorktree(worktreeId, getConfig().workspaceRoot);
156
+ discardWorktree(worktreeId, goalRepoPath);
143
157
  } catch { /* ignore cleanup failure,向上抛出原始 createTask 错误 */ }
144
158
  }
145
159
  throw createTaskErr;
@@ -153,18 +167,19 @@ export function createSubgoalTask(input: CreateSubgoalTaskInput): CreateSubgoalT
153
167
  if (isolate && worktreeId) {
154
168
  const newSubgoals: Subgoal[] = withRunning.subgoals.map((s) =>
155
169
  s.id === subgoalId
156
- ? ({ ...s, worktree_id: worktreeId } as Subgoal)
170
+ ? { ...s, worktree_id: worktreeId }
157
171
  : s
158
172
  );
159
173
  withRunning = { ...withRunning, subgoals: newSubgoals };
160
174
  }
161
175
 
162
- // 5. 写回 goal_status.json
163
- writeGoalStatus(input.goal_id, withRunning);
164
-
165
176
  return {
166
- subgoal_id: subgoalId,
167
- task_id: taskId,
168
- subgoal_status: "running",
177
+ next: withRunning,
178
+ result: {
179
+ subgoal_id: subgoalId,
180
+ task_id: taskId,
181
+ subgoal_status: "running" as const,
182
+ },
169
183
  };
184
+ });
170
185
  }
@@ -0,0 +1,3 @@
1
+ export * from "./getPlan.js";
2
+ export * from "./goalSubgoalTask.js";
3
+ export * from "./savePlan.js";
@@ -1,9 +1,15 @@
1
- import { mkdirSync, writeFileSync, existsSync, readFileSync } from "node:fs";
1
+ import { mkdirSync, existsSync, readFileSync, statSync } from "node:fs";
2
2
  import { resolve, join, relative } from "node:path";
3
- import { getPlansDir, getConfig } from "../config.js";
4
- import { guardPath } from "../security/pathGuard.js";
5
- import { guardPlanContent } from "../security/planGuard.js";
6
- import { PatchWardenError } from "../errors.js";
3
+ import { randomBytes } from "node:crypto";
4
+ import { getPlansDir, getConfig } from "../../config.js";
5
+ import { guardPath } from "../../security/pathGuard.js";
6
+ import { guardPlanContent } from "../../security/planGuard.js";
7
+ import { PatchWardenError } from "../../errors.js";
8
+ import { redactSensitiveContent } from "../../security/contentRedaction.js";
9
+ import { atomicWriteFileSync } from "../../utils/atomicFile.js";
10
+
11
+ const MAX_PLAN_BYTES = 1024 * 1024;
12
+ const MAX_PLAN_TITLE_CHARS = 500;
7
13
 
8
14
  export interface SavePlanInput {
9
15
  title: string;
@@ -49,6 +55,14 @@ export function savePlan(input: SavePlanInput): SavePlanOutput {
49
55
  { plan_ref: input.plan_ref }
50
56
  );
51
57
  }
58
+ const planMetadata = statSync(targetPath);
59
+ if (!planMetadata.isFile() || planMetadata.size > MAX_PLAN_BYTES) {
60
+ throw new PatchWardenError(
61
+ "plan_content_too_large",
62
+ `plan_ref must point to a regular file no larger than ${MAX_PLAN_BYTES} bytes.`,
63
+ "Use a smaller plan file under .patchwarden/plans/.",
64
+ );
65
+ }
52
66
  content = readFileSync(targetPath, "utf-8");
53
67
  if (!title || title.trim() === "") {
54
68
  title = "Plan from file";
@@ -71,16 +85,32 @@ export function savePlan(input: SavePlanInput): SavePlanOutput {
71
85
 
72
86
  guardPlanContent(title, content);
73
87
 
74
- const planId = `plan_${Date.now()}_${sanitizeTitle(title)}`;
88
+ if (Buffer.byteLength(content, "utf-8") > MAX_PLAN_BYTES) {
89
+ throw new PatchWardenError(
90
+ "plan_content_too_large",
91
+ `Plan content exceeds the ${MAX_PLAN_BYTES}-byte limit.`,
92
+ "Split the work into smaller plans.",
93
+ );
94
+ }
95
+ title = redactSensitiveContent(title)
96
+ .content
97
+ .replace(/[\r\n\t]+/g, " ")
98
+ .trim()
99
+ .slice(0, MAX_PLAN_TITLE_CHARS) || "Inline plan";
100
+ content = redactSensitiveContent(content).content;
101
+
102
+ const planId = `plan_${Date.now()}_${sanitizeTitle(title)}_${randomBytes(4).toString("hex")}`;
75
103
  const planDir = resolve(plansDir, planId);
76
104
 
77
105
  // Guards: plan dir & file must stay inside workspace
106
+ guardPath(plansDir, config.workspaceRoot, config.plansDir);
107
+ mkdirSync(plansDir, { recursive: true });
78
108
  guardPath(planDir, config.workspaceRoot, config.plansDir);
79
- mkdirSync(planDir, { recursive: true });
109
+ mkdirSync(planDir);
80
110
 
81
111
  const planFile = join(planDir, "plan.md");
82
112
  const header = `# ${title}\n\n> Plan ID: ${planId}\n> Created: ${new Date().toISOString()}\n\n`;
83
- writeFileSync(planFile, header + content, "utf-8");
113
+ atomicWriteFileSync(planFile, header + content);
84
114
 
85
115
  return {
86
116
  plan_id: planId,