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
@@ -1,9 +1,9 @@
1
- import { getConfig } from "../config.js";
2
- import { guardWorkspacePath } from "../security/pathGuard.js";
1
+ import { getConfig } from "../../config.js";
2
+ import { guardWorkspacePath } from "../../security/pathGuard.js";
3
3
  import {
4
4
  runReleaseGateCheck,
5
5
  type ReleaseStage,
6
- } from "../release/releaseGate.js";
6
+ } from "../../release/releaseGate.js";
7
7
 
8
8
  export interface CheckReleaseGateInput {
9
9
  repo_path: string;
@@ -0,0 +1,2 @@
1
+ export * from "./checkReleaseGate.js";
2
+ export * from "./releaseMode.js";
@@ -1,7 +1,7 @@
1
- import { execFileSync, execSync } from "node:child_process";
2
- import { existsSync, mkdirSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
1
+ import { execFileSync } from "node:child_process";
2
+ import { existsSync, mkdirSync, readdirSync, rmSync, statSync } from "node:fs";
3
3
  import { join, relative, resolve, sep, isAbsolute } from "node:path";
4
- import { getConfig } from "../config.js";
4
+ import { getConfig } from "../../config.js";
5
5
  import {
6
6
  checkCiVerified,
7
7
  checkGitHubReleaseVerified,
@@ -9,9 +9,12 @@ import {
9
9
  runReleaseGateCheck,
10
10
  type ReleaseStage,
11
11
  type ReleaseStageStatus,
12
- } from "../release/releaseGate.js";
13
- import { guardTestCommand } from "../security/commandGuard.js";
14
- import { guardWorkspacePath } from "../security/pathGuard.js";
12
+ } from "../../release/releaseGate.js";
13
+ import { guardTestCommand } from "../../security/commandGuard.js";
14
+ import { guardWorkspacePath } from "../../security/pathGuard.js";
15
+ import { resolveTrustedCommandLine, buildGitEnvironment, resolveTrustedExecutable } from "../../runner/processSecurity.js";
16
+ import { atomicWriteJsonFileSync } from "../../utils/atomicFile.js";
17
+ import { runSimpleProcessSync } from "../../runner/simpleProcess.js";
15
18
  import {
16
19
  commandAllowedByProjectPolicy,
17
20
  getProjectPolicySummary,
@@ -19,7 +22,7 @@ import {
19
22
  readPackageJson,
20
23
  resolveVersionFromPolicy,
21
24
  type ProjectPolicySummary,
22
- } from "../policy/projectPolicy.js";
25
+ } from "../../policy/projectPolicy.js";
23
26
 
24
27
  export interface ReleaseCheckInput {
25
28
  repo_path: string;
@@ -146,12 +149,19 @@ export function releasePrepare(input: ReleasePrepareInput): ReleaseModeResult {
146
149
  continue;
147
150
  }
148
151
  try {
149
- execSync(command, {
152
+ const invocation = resolveTrustedCommandLine(command, repoPath);
153
+ const execution = runSimpleProcessSync({
154
+ command: invocation.command,
155
+ args: invocation.argsPrefix,
150
156
  cwd: repoPath,
151
- encoding: "utf-8",
152
- timeout: timeoutMs,
153
- stdio: ["ignore", "pipe", "pipe"],
157
+ timeoutMs,
154
158
  });
159
+ if (execution.spawnError) throw new Error(execution.spawnError);
160
+ if (execution.timedOut) throw new Error(`Command timed out after ${timeoutMs}ms`);
161
+ if (execution.exitCode !== 0) {
162
+ const status = execution.exitCode ?? -1;
163
+ throw Object.assign(new Error(`Command exited with code ${status}`), { status });
164
+ }
155
165
  results.push({ command, status: "passed", exit_code: 0, reason: null });
156
166
  } catch (err) {
157
167
  const code = err && typeof err === "object" && "status" in err
@@ -280,7 +290,7 @@ export function releaseCleanup(input: ReleaseCleanupInput): ReleaseModeResult {
280
290
  const reportDir = join(repoPath, CLEANUP_REPORT_DIR);
281
291
  mkdirSync(reportDir, { recursive: true });
282
292
  const reportPath = join(reportDir, `${report.generated_at.replace(/[-:.TZ]/g, "").slice(0, 14)}.json`);
283
- writeFileSync(reportPath, JSON.stringify(report, null, 2) + "\n", "utf-8");
293
+ atomicWriteJsonFileSync(reportPath, report);
284
294
 
285
295
  return {
286
296
  ok: skipped.length === 0 || dryRun,
@@ -379,10 +389,12 @@ function walkFrom(base: string, dir: string, visit: (path: string, relPath: stri
379
389
  function isTrackedByGit(root: string, relPath: string): boolean {
380
390
  if (!isGitWorktree(root)) return false;
381
391
  try {
382
- execFileSync("git", ["ls-files", "--error-unmatch", "--", relPath], {
392
+ const env = buildGitEnvironment(root);
393
+ execFileSync(resolveTrustedExecutable("git", root, { pathValue: env.PATH }), ["ls-files", "--error-unmatch", "--", relPath], {
383
394
  cwd: root,
384
395
  stdio: "ignore",
385
396
  windowsHide: true,
397
+ env,
386
398
  });
387
399
  return true;
388
400
  } catch {
@@ -393,32 +405,38 @@ function isTrackedByGit(root: string, relPath: string): boolean {
393
405
  function isIgnoredOrUntracked(root: string, relPath: string): boolean {
394
406
  if (!isGitWorktree(root)) return true;
395
407
  try {
396
- execFileSync("git", ["check-ignore", "-q", "--", relPath], {
397
- cwd: root,
398
- stdio: "ignore",
399
- windowsHide: true,
400
- });
401
- return true;
402
- } catch {
408
+ const env = buildGitEnvironment(root);
409
+ const git = resolveTrustedExecutable("git", root, { pathValue: env.PATH });
403
410
  try {
404
- const output = execFileSync("git", ["ls-files", "--others", "--exclude-standard", "--", relPath], {
411
+ execFileSync(git, ["check-ignore", "-q", "--", relPath], {
412
+ cwd: root,
413
+ stdio: "ignore",
414
+ windowsHide: true,
415
+ env,
416
+ });
417
+ return true;
418
+ } catch {
419
+ const output = execFileSync(git, ["ls-files", "--others", "--exclude-standard", "--", relPath], {
405
420
  cwd: root,
406
421
  encoding: "utf-8",
407
422
  windowsHide: true,
423
+ env,
408
424
  });
409
425
  return output.trim().split(/\r?\n/).filter(Boolean).includes(relPath);
410
- } catch {
411
- return false;
412
426
  }
427
+ } catch {
428
+ return false;
413
429
  }
414
430
  }
415
431
 
416
432
  function isGitWorktree(root: string): boolean {
417
433
  try {
418
- return execFileSync("git", ["rev-parse", "--is-inside-work-tree"], {
434
+ const env = buildGitEnvironment(root);
435
+ return execFileSync(resolveTrustedExecutable("git", root, { pathValue: env.PATH }), ["rev-parse", "--is-inside-work-tree"], {
419
436
  cwd: root,
420
437
  encoding: "utf-8",
421
438
  windowsHide: true,
439
+ env,
422
440
  }).trim() === "true";
423
441
  } catch {
424
442
  return false;
@@ -0,0 +1,109 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { getTasksDir, getConfig } from "../../config.js";
4
+ import { guardReadPath } from "../../security/pathGuard.js";
5
+ import { writeTaskProgress } from "../../runner/taskProgress.js";
6
+ import { mutateTaskStatus } from "../../runner/taskStatusStore.js";
7
+ import type { TaskStatus } from "./createTask.js";
8
+
9
+ export interface TaskTerminationResponse {
10
+ task_id: string;
11
+ previous_status: TaskStatus;
12
+ new_status: TaskStatus;
13
+ message: string;
14
+ cancel_requested?: boolean;
15
+ force_kill_requested?: boolean;
16
+ }
17
+
18
+ interface TaskTerminationOutcome {
19
+ response: TaskTerminationResponse;
20
+ progress: {
21
+ phase: "canceled" | "canceling" | "terminating";
22
+ note: string;
23
+ } | null;
24
+ }
25
+
26
+ export function cancelTask(taskId: string) {
27
+ return requestTaskTermination(taskId, false);
28
+ }
29
+
30
+ export function requestTaskTermination(taskId: string, force: boolean) {
31
+ const config = getConfig();
32
+ const taskDir = join(getTasksDir(config), taskId);
33
+ const statusFile = join(taskDir, "status.json");
34
+ guardReadPath(statusFile, config.workspaceRoot, config.tasksDir);
35
+
36
+ if (!existsSync(statusFile)) throw new Error(`Task not found: "${taskId}"`);
37
+
38
+ const now = new Date().toISOString();
39
+ const outcome = mutateTaskStatus<TaskTerminationOutcome>(statusFile, (current) => {
40
+ const currentStatus = current.status as TaskStatus;
41
+ if (["done", "done_by_agent", "failed", "failed_verification", "failed_scope_violation", "failed_policy_violation", "canceled"].includes(currentStatus)) {
42
+ return { result: {
43
+ response: {
44
+ task_id: taskId,
45
+ previous_status: currentStatus,
46
+ new_status: currentStatus,
47
+ message: `Task is already ${currentStatus}. No action taken.`,
48
+ },
49
+ progress: null,
50
+ } };
51
+ }
52
+
53
+ if (currentStatus === "pending") {
54
+ const reason = force ? "Killed before execution by user request." : "Canceled by user request.";
55
+ const next = {
56
+ ...current,
57
+ status: "canceled",
58
+ phase: "canceled",
59
+ canceled_at: now,
60
+ cancel_reason: reason,
61
+ updated_at: now,
62
+ };
63
+ return { next, result: {
64
+ response: {
65
+ task_id: taskId,
66
+ previous_status: "pending" as const,
67
+ new_status: "canceled" as const,
68
+ message: "Pending task canceled. It will not be executed by watcher.",
69
+ },
70
+ progress: { phase: "canceled" as const, note: reason },
71
+ } };
72
+ }
73
+
74
+ const phase = force ? "terminating" as const : "canceling" as const;
75
+ const next = {
76
+ ...current,
77
+ cancel_requested: true,
78
+ cancel_requested_at: now,
79
+ force_kill_requested: force,
80
+ ...(force ? { kill_requested_at: now } : {}),
81
+ phase,
82
+ updated_at: now,
83
+ };
84
+ return { next, result: {
85
+ response: {
86
+ task_id: taskId,
87
+ previous_status: "running" as const,
88
+ new_status: "running" as const,
89
+ cancel_requested: true,
90
+ force_kill_requested: force,
91
+ message: force
92
+ ? "Kill requested. The runner that owns the child process will terminate it."
93
+ : "Cancel requested. The runner will stop the child process safely.",
94
+ },
95
+ progress: {
96
+ phase,
97
+ note: force ? "Immediate termination requested." : "Graceful cancellation requested.",
98
+ },
99
+ } };
100
+ });
101
+
102
+ if (outcome.progress) {
103
+ writeTaskProgress(taskDir, outcome.progress.phase, {
104
+ note: outcome.progress.note,
105
+ heartbeatAt: now,
106
+ });
107
+ }
108
+ return outcome.response;
109
+ }
@@ -2,12 +2,12 @@ import { mkdirSync, writeFileSync, existsSync, statSync, readFileSync } from "no
2
2
  import { randomBytes } from "node:crypto";
3
3
  import { resolve, join, dirname } from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { getTasksDir, getPlansDir, getConfig } from "../config.js";
6
- import { guardPath, guardWorkspacePath, guardReadPath } from "../security/pathGuard.js";
7
- import { guardTestCommand } from "../security/commandGuard.js";
8
- import { guardRuntimeSelfModification } from "../security/runtimeGuard.js";
9
- import { guardPlanContent } from "../security/planGuard.js";
10
- import { assessRisk } from "../security/riskEngine.js";
5
+ import { getTasksDir, getPlansDir, getConfig } from "../../config.js";
6
+ import { guardPath, guardWorkspacePath, guardReadPath } from "../../security/pathGuard.js";
7
+ import { guardTestCommand } from "../../security/commandGuard.js";
8
+ import { guardRuntimeSelfModification } from "../../security/runtimeGuard.js";
9
+ import { guardPlanContent } from "../../security/planGuard.js";
10
+ import { assessRisk } from "../../security/riskEngine.js";
11
11
  import {
12
12
  createAssessment,
13
13
  readAssessment,
@@ -16,27 +16,29 @@ import {
16
16
  createAssessmentDir,
17
17
  type AssessmentRecord,
18
18
  type AgentAssessmentSummary,
19
- } from "../assessments/assessmentStore.js";
20
- import { runAgentAssessment } from "../assessments/agentAssessor.js";
21
- import { captureRepoSnapshot } from "../runner/changeCapture.js";
22
- import { writeTaskProgress } from "../taskProgress.js";
23
- import { PatchWardenError } from "../errors.js";
24
- import { savePlan } from "./savePlan.js";
19
+ } from "../../assessments/assessmentStore.js";
20
+ import { runAgentAssessment } from "../../assessments/agentAssessor.js";
21
+ import { captureRepoSnapshot } from "../../runner/changeCapture.js";
22
+ import { writeTaskProgress } from "../../runner/taskProgress.js";
23
+ import { PatchWardenError } from "../../errors.js";
24
+ import { savePlan } from "../goals/savePlan.js";
25
25
  import {
26
26
  expandTaskTemplate,
27
27
  TASK_TEMPLATE_NAMES,
28
28
  type ChangePolicy,
29
29
  type TaskTemplateName,
30
- } from "./taskTemplates.js";
31
- import { PATCHWARDEN_VERSION } from "../version.js";
32
- import { getLastToolCatalogSnapshot, resolveToolProfile } from "./toolCatalog.js";
30
+ } from "../taskTemplates.js";
31
+ import { PATCHWARDEN_VERSION, ARTIFACT_SCHEMA_VERSION } from "../../version.js";
32
+ import { getLastToolCatalogSnapshot, resolveToolProfile } from "../catalog/toolCatalog.js";
33
33
  import {
34
34
  derivePendingReason,
35
35
  readWatcherStatus,
36
36
  type PendingReason,
37
37
  type WatcherStatusSnapshot,
38
- } from "../watcherStatus.js";
39
- import { routeAgent, type AgentRouteResult } from "../agents/agentRouter.js";
38
+ } from "../../watcherStatus.js";
39
+ import { routeAgent, type AgentRouteResult } from "../../agents/agentRouter.js";
40
+ import { redactSensitiveValue } from "../../security/contentRedaction.js";
41
+ import { atomicWriteJsonFileSync } from "../../utils/atomicFile.js";
40
42
 
41
43
  export type TaskStatus =
42
44
  | "pending"
@@ -110,6 +112,14 @@ export interface CreateTaskInput {
110
112
  // v0.8.0: Goal Session 关联
111
113
  goal_id?: string;
112
114
  subgoal_id?: string;
115
+ /** Internal provenance supplied by retry_task; not exposed in MCP schemas. */
116
+ retry_metadata?: {
117
+ retry_of: string;
118
+ retry_count: number;
119
+ plan_source: "saved" | "inline" | "template";
120
+ template: string | null;
121
+ change_policy: ChangePolicy;
122
+ };
113
123
  }
114
124
 
115
125
  export interface AssessOnlyOutput {
@@ -181,9 +191,9 @@ export interface CreateTaskOutput {
181
191
  };
182
192
  }
183
193
 
184
- export function createTask(input: CreateTaskInput & { execution_mode: "assess_only" }): AssessOnlyOutput;
185
- export function createTask(input: CreateTaskInput): CreateTaskOutput;
186
- export function createTask(input: CreateTaskInput): CreateTaskResult {
194
+ export function createTask(input: CreateTaskInput & { execution_mode: "assess_only" }): Promise<AssessOnlyOutput>;
195
+ export function createTask(input: CreateTaskInput): Promise<CreateTaskOutput>;
196
+ export async function createTask(input: CreateTaskInput): Promise<CreateTaskResult> {
187
197
  const config = getConfig();
188
198
  const tasksDir = getTasksDir(config);
189
199
  const plansDir = getPlansDir(config);
@@ -243,7 +253,7 @@ export function createTask(input: CreateTaskInput): CreateTaskResult {
243
253
 
244
254
  // Resolve repo alias if configured
245
255
  let resolvedRepoPath = effectiveInput.repo_path?.trim() || "";
246
- const aliases = (config as any).repoAliases as Record<string, string> | undefined;
256
+ const aliases = config.repoAliases;
247
257
  if (aliases && resolvedRepoPath && aliases[resolvedRepoPath]) {
248
258
  resolvedRepoPath = aliases[resolvedRepoPath];
249
259
  }
@@ -382,7 +392,7 @@ export function createTask(input: CreateTaskInput): CreateTaskResult {
382
392
  planBlockReason = e instanceof PatchWardenError ? e.reason : "plan_content_blocked";
383
393
  }
384
394
 
385
- const snapshot = captureRepoSnapshot(safeRepoPath);
395
+ const snapshot = await captureRepoSnapshot(safeRepoPath);
386
396
  const snapshotTruncated = snapshot.warnings.some((w) => w.includes("snapshot limited"));
387
397
 
388
398
  let riskResult;
@@ -441,7 +451,7 @@ export function createTask(input: CreateTaskInput): CreateTaskResult {
441
451
  preGeneratedAssessmentDir = createAssessmentDir(preGeneratedAssessmentId);
442
452
 
443
453
  const assessorAgentName = config.agentAssessmentAgentName || effectiveInput.agent;
444
- agentAssessmentSummary = runAgentAssessment({
454
+ agentAssessmentSummary = await runAgentAssessment({
445
455
  assessmentId: preGeneratedAssessmentId,
446
456
  assessmentDir: preGeneratedAssessmentDir,
447
457
  agentName: assessorAgentName,
@@ -572,7 +582,7 @@ export function createTask(input: CreateTaskInput): CreateTaskResult {
572
582
 
573
583
  // ── execute mode with assessment_id: validate freshness ──
574
584
  if (assessmentRecord) {
575
- const snapshot = captureRepoSnapshot(safeRepoPath);
585
+ const snapshot = await captureRepoSnapshot(safeRepoPath);
576
586
  const validation = validateAssessmentFreshness(input.assessment_id!, snapshot);
577
587
  if (!validation.valid) {
578
588
  throw new PatchWardenError(
@@ -589,12 +599,25 @@ export function createTask(input: CreateTaskInput): CreateTaskResult {
589
599
 
590
600
  const status: TaskStatus = "pending";
591
601
  const statusFile = join(taskDir, "status.json");
602
+ const retryMetadata = effectiveInput.retry_metadata;
603
+ const safeAcceptance = redactSensitiveValue({
604
+ goal: effectiveInput.goal || null,
605
+ scope: effectiveInput.scope ?? null,
606
+ forbidden: effectiveInput.forbidden ?? null,
607
+ verification: effectiveInput.verification ?? null,
608
+ done_evidence: effectiveInput.done_evidence ?? null,
609
+ }).value;
592
610
  const statusData = {
611
+ schema_version: ARTIFACT_SCHEMA_VERSION,
593
612
  task_id: taskId,
594
613
  plan_id: planId,
595
- plan_source: planSource,
596
- template: effectiveInput.template || null,
597
- change_policy: changePolicy,
614
+ plan_source: retryMetadata?.plan_source ?? planSource,
615
+ template: retryMetadata?.template ?? effectiveInput.template ?? null,
616
+ change_policy: retryMetadata?.change_policy ?? changePolicy,
617
+ ...(retryMetadata ? {
618
+ retry_of: retryMetadata.retry_of,
619
+ retry_count: retryMetadata.retry_count,
620
+ } : {}),
598
621
  agent: effectiveInput.agent,
599
622
  workspace_root: resolve(config.workspaceRoot),
600
623
  repo_path: resolvedRepoPath,
@@ -611,11 +634,11 @@ export function createTask(input: CreateTaskInput): CreateTaskResult {
611
634
  current_command: null as string | null,
612
635
  error: null as string | null,
613
636
  // v0.7.2: 验收标准绑定到任务创建
614
- goal: effectiveInput.goal || null,
615
- scope: effectiveInput.scope ?? null,
616
- forbidden: effectiveInput.forbidden ?? null,
617
- verification: effectiveInput.verification ?? null,
618
- done_evidence: effectiveInput.done_evidence ?? null,
637
+ goal: safeAcceptance.goal,
638
+ scope: safeAcceptance.scope,
639
+ forbidden: safeAcceptance.forbidden,
640
+ verification: safeAcceptance.verification,
641
+ done_evidence: safeAcceptance.done_evidence,
619
642
  acceptance_status: null as AcceptanceStatus,
620
643
  // v0.8.0: Goal Session 关联
621
644
  goal_id: effectiveInput.goal_id ?? null,
@@ -624,7 +647,7 @@ export function createTask(input: CreateTaskInput): CreateTaskResult {
624
647
  ...(agentSelectionReason ? { agent_selection_reason: agentSelectionReason } : {}),
625
648
  };
626
649
 
627
- writeFileSync(statusFile, JSON.stringify(statusData, null, 2), "utf-8");
650
+ atomicWriteJsonFileSync(statusFile, statusData);
628
651
  writeTaskProgress(taskDir, "queued", {
629
652
  heartbeatAt: statusData.last_heartbeat_at,
630
653
  note: `Waiting for watcher. Timeout: ${timeoutSeconds} seconds.`,
@@ -1,11 +1,12 @@
1
1
  import { existsSync, readFileSync, statSync } from "node:fs";
2
2
  import { join, resolve } from "node:path";
3
- import { getTasksDir, getConfig, type PatchWardenConfig } 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
- import { readTaskRuntime } from "../taskRuntime.js";
8
- import { isWatcherOwningTask, readWatcherInstanceId } from "../watcherStatus.js";
3
+ import { getTasksDir, getConfig, type PatchWardenConfig } 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
+ import { readTextFileTailLinesSync } from "../../utils/boundedFile.js";
8
+ import { readTaskRuntime } from "../../runner/taskRuntime.js";
9
+ import { isWatcherOwningTask, readWatcherInstanceId } from "../../watcherStatus.js";
9
10
 
10
11
  // ── v0.7.0: Task diagnosis types ──────────────────────────────────
11
12
 
@@ -118,8 +119,7 @@ function fileAgeSeconds(filePath: string, nowMs: number): { age: number; size: n
118
119
  function readTailLines(filePath: string, lines: number): string | null {
119
120
  if (!existsSync(filePath)) return null;
120
121
  try {
121
- const raw = readFileSync(filePath, "utf-8");
122
- const tail = raw.split("\n").slice(-lines).join("\n");
122
+ const tail = readTextFileTailLinesSync(filePath, lines, 512 * 1024);
123
123
  return redactSensitiveContent(tail).content;
124
124
  } catch {
125
125
  return null;