patchwarden 1.5.1 → 1.6.2

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 (591) hide show
  1. package/PatchWarden.cmd +32 -2
  2. package/README.en.md +158 -26
  3. package/README.md +124 -24
  4. package/dist/assessments/agentAssessor.js +21 -12
  5. package/dist/assessments/assessmentDiagnostics.d.ts +29 -0
  6. package/dist/assessments/assessmentDiagnostics.js +132 -0
  7. package/dist/assessments/assessmentStore.d.ts +39 -0
  8. package/dist/assessments/assessmentStore.js +207 -45
  9. package/dist/assessments/securitySnapshot.d.ts +50 -0
  10. package/dist/assessments/securitySnapshot.js +158 -0
  11. package/dist/config.d.ts +15 -0
  12. package/dist/config.js +66 -13
  13. package/dist/control/fileManager.d.ts +2 -0
  14. package/dist/control/fileManager.js +39 -0
  15. package/dist/control/middleware/auth.d.ts +6 -0
  16. package/dist/control/middleware/auth.js +14 -5
  17. package/dist/control/middleware/static.js +16 -3
  18. package/dist/control/routeTable.d.ts +24 -0
  19. package/dist/control/routeTable.js +263 -0
  20. package/dist/control/routes/audit.js +17 -7
  21. package/dist/control/routes/evidence.js +1 -1
  22. package/dist/control/routes/lineage.js +1 -1
  23. package/dist/control/routes/process.d.ts +7 -0
  24. package/dist/control/routes/process.js +329 -42
  25. package/dist/control/routes/sessions.d.ts +9 -1
  26. package/dist/control/routes/sessions.js +84 -21
  27. package/dist/control/routes/status.d.ts +60 -1
  28. package/dist/control/routes/status.js +94 -15
  29. package/dist/control/routes/taskActions.js +24 -60
  30. package/dist/control/routes/tasks.d.ts +4 -0
  31. package/dist/control/routes/tasks.js +61 -62
  32. package/dist/control/routes/workspace.js +50 -23
  33. package/dist/control/runtime.d.ts +3 -2
  34. package/dist/control/runtime.js +65 -40
  35. package/dist/control/server.js +37 -365
  36. package/dist/control/shared.d.ts +25 -1
  37. package/dist/control/shared.js +64 -11
  38. package/dist/diagnostics/allowedTestCommandSafety.d.ts +1 -0
  39. package/dist/diagnostics/allowedTestCommandSafety.js +11 -0
  40. package/dist/direct/directAudit.js +234 -225
  41. package/dist/direct/directGuards.d.ts +2 -1
  42. package/dist/direct/directGuards.js +42 -29
  43. package/dist/direct/directPatch.d.ts +6 -1
  44. package/dist/direct/directPatch.js +55 -8
  45. package/dist/direct/directSessionStore.d.ts +16 -6
  46. package/dist/direct/directSessionStore.js +128 -35
  47. package/dist/direct/directVerification.js +8 -16
  48. package/dist/doctor.js +65 -57
  49. package/dist/goal/acceptanceEngine.d.ts +1 -1
  50. package/dist/goal/goalProgress.js +75 -69
  51. package/dist/goal/goalReport.js +5 -12
  52. package/dist/goal/goalStatus.d.ts +2 -0
  53. package/dist/goal/goalStatus.js +10 -3
  54. package/dist/goal/goalStore.d.ts +9 -2
  55. package/dist/goal/goalStore.js +152 -45
  56. package/dist/goal/handoffExport.js +6 -6
  57. package/dist/goal/specKitImport.js +97 -96
  58. package/dist/goal/subgoalSync.js +11 -9
  59. package/dist/goal/worktreeManager.d.ts +2 -0
  60. package/dist/goal/worktreeManager.js +209 -136
  61. package/dist/httpServer.js +111 -32
  62. package/dist/logging.js +5 -3
  63. package/dist/policy/projectPolicy.js +5 -2
  64. package/dist/release/releaseGate.d.ts +1 -1
  65. package/dist/release/releaseGate.js +78 -25
  66. package/dist/runner/agentInvocation.d.ts +14 -0
  67. package/dist/runner/agentInvocation.js +96 -4
  68. package/dist/runner/changeCapture.d.ts +13 -5
  69. package/dist/runner/changeCapture.js +243 -61
  70. package/dist/runner/postTaskCleanup.js +48 -19
  71. package/dist/runner/processSecurity.d.ts +56 -0
  72. package/dist/runner/processSecurity.js +373 -0
  73. package/dist/runner/runTask.d.ts +2 -1
  74. package/dist/runner/runTask.js +162 -93
  75. package/dist/runner/simpleProcess.d.ts +3 -0
  76. package/dist/runner/simpleProcess.js +50 -36
  77. package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
  78. package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
  79. package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +3 -1
  80. package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
  81. package/dist/runner/taskStatusStore.d.ts +11 -0
  82. package/dist/runner/taskStatusStore.js +35 -0
  83. package/dist/runner/watch.d.ts +14 -1
  84. package/dist/runner/watch.js +320 -49
  85. package/dist/security/contentRedaction.js +2 -2
  86. package/dist/security/discoveryTokenStore.d.ts +3 -2
  87. package/dist/security/discoveryTokenStore.js +17 -2
  88. package/dist/security/loopbackHost.d.ts +2 -0
  89. package/dist/security/loopbackHost.js +16 -0
  90. package/dist/security/pathGuard.js +32 -17
  91. package/dist/security/planGuard.js +2 -1
  92. package/dist/security/runtimeGuard.js +9 -6
  93. package/dist/security/secretComparison.d.ts +3 -0
  94. package/dist/security/secretComparison.js +11 -0
  95. package/dist/security/sensitiveGuard.d.ts +5 -0
  96. package/dist/security/sensitiveGuard.js +27 -8
  97. package/dist/security/toolInvocationGuard.d.ts +2 -2
  98. package/dist/security/toolInvocationGuard.js +1 -1
  99. package/dist/security/workspaceRootGuard.d.ts +8 -0
  100. package/dist/security/workspaceRootGuard.js +47 -0
  101. package/dist/smoke-test.js +27 -26
  102. package/dist/tools/catalog/index.d.ts +4 -0
  103. package/dist/tools/catalog/index.js +4 -0
  104. package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
  105. package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
  106. package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +6 -15
  107. package/dist/tools/definitions/toolDefs.d.ts +18 -0
  108. package/dist/tools/definitions/toolDefs.js +1177 -0
  109. package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
  110. package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
  111. package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +2 -1
  112. package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +134 -36
  113. package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +18 -6
  114. package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +36 -8
  115. package/dist/tools/diagnostics/index.d.ts +6 -0
  116. package/dist/tools/diagnostics/index.js +6 -0
  117. package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
  118. package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
  119. package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +12 -8
  120. package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +23 -13
  121. package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
  122. package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
  123. package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +6 -6
  124. package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +1 -1
  125. package/dist/tools/direct/finalizeDirectSession.js +86 -0
  126. package/dist/tools/direct/index.d.ts +3 -0
  127. package/dist/tools/direct/index.js +3 -0
  128. package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
  129. package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
  130. package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
  131. package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
  132. package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
  133. package/dist/tools/discovery/index.d.ts +3 -0
  134. package/dist/tools/discovery/index.js +3 -0
  135. package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
  136. package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
  137. package/dist/tools/dispatch/coreDispatch.js +32 -31
  138. package/dist/tools/dispatch/diagnosticDispatch.d.ts +3 -5
  139. package/dist/tools/dispatch/diagnosticDispatch.js +70 -68
  140. package/dist/tools/dispatch/directDispatch.js +11 -10
  141. package/dist/tools/dispatch/goalDispatch.js +5 -4
  142. package/dist/tools/dispatch/releaseDispatch.js +3 -2
  143. package/dist/tools/dispatch/validation.d.ts +7 -0
  144. package/dist/tools/dispatch/validation.js +71 -0
  145. package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
  146. package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +1 -1
  147. package/dist/tools/goals/goalSubgoalTask.js +118 -0
  148. package/dist/tools/goals/index.d.ts +3 -0
  149. package/dist/tools/goals/index.js +3 -0
  150. package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
  151. package/dist/tools/registry.d.ts +7 -11
  152. package/dist/tools/registry.js +17 -1178
  153. package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
  154. package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
  155. package/dist/tools/release/index.d.ts +2 -0
  156. package/dist/tools/release/index.js +2 -0
  157. package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
  158. package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
  159. package/dist/tools/tasks/cancelTask.d.ts +11 -0
  160. package/dist/tools/tasks/cancelTask.js +86 -0
  161. package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +12 -4
  162. package/dist/tools/{createTask.js → tasks/createTask.js} +110 -34
  163. package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
  164. package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +12 -16
  165. package/dist/tools/{evidencePack.js → tasks/evidencePack.js} +34 -22
  166. package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
  167. package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
  168. package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +11 -6
  169. package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
  170. package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +35 -36
  171. package/dist/tools/tasks/index.d.ts +18 -0
  172. package/dist/tools/tasks/index.js +18 -0
  173. package/dist/tools/tasks/killTask.d.ts +1 -0
  174. package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
  175. package/dist/tools/{listTasks.js → tasks/listTasks.js} +5 -4
  176. package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +3 -2
  177. package/dist/tools/tasks/reconcileTasks.js +496 -0
  178. package/dist/tools/tasks/retryTask.js +60 -0
  179. package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
  180. package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +63 -41
  181. package/dist/tools/tasks/runVerification.js +38 -0
  182. package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
  183. package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +2 -2
  184. package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
  185. package/dist/tools/tasks/taskStates.d.ts +6 -0
  186. package/dist/tools/tasks/taskStates.js +52 -0
  187. package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +3 -11
  188. package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
  189. package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
  190. package/dist/tools/workspace/applyPatch.js +53 -0
  191. package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
  192. package/dist/tools/workspace/index.d.ts +10 -0
  193. package/dist/tools/workspace/index.js +10 -0
  194. package/dist/tools/workspace/listAgents.d.ts +23 -0
  195. package/dist/tools/workspace/listAgents.js +56 -0
  196. package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
  197. package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
  198. package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
  199. package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
  200. package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
  201. package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
  202. package/dist/tools/workspace/syncFile.js +134 -0
  203. package/dist/utils/atomicFile.d.ts +7 -0
  204. package/dist/utils/atomicFile.js +67 -0
  205. package/dist/utils/boundedFile.d.ts +8 -0
  206. package/dist/utils/boundedFile.js +93 -0
  207. package/dist/utils/lockedJsonFile.d.ts +15 -0
  208. package/dist/utils/lockedJsonFile.js +224 -0
  209. package/dist/utils/platform.d.ts +11 -0
  210. package/dist/utils/platform.js +26 -0
  211. package/dist/utils/stableJson.d.ts +2 -0
  212. package/dist/utils/stableJson.js +12 -0
  213. package/dist/version.d.ts +3 -2
  214. package/dist/version.js +3 -2
  215. package/dist/watcherStatus.d.ts +2 -2
  216. package/dist/watcherStatus.js +18 -0
  217. package/docs/CODE_WIKI.md +808 -143
  218. package/docs/architecture.md +15 -55
  219. package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
  220. package/docs/control-center/README.md +4 -4
  221. package/docs/dashboard-overview.md +4 -4
  222. package/docs/desktop-app.md +175 -0
  223. package/docs/evidence-pack-schema.md +3 -3
  224. package/docs/open-source-application.md +16 -11
  225. package/docs/release-checklist.md +1 -1
  226. package/docs/release-evidence.md +35 -39
  227. package/docs/task-safe-review-workflow.md +5 -5
  228. package/docs/threat-model.md +19 -1
  229. package/examples/config.example.json +4 -2
  230. package/package.json +27 -10
  231. package/scripts/README.md +15 -6
  232. package/scripts/build.js +11 -0
  233. package/scripts/checks/brand-check.js +3 -0
  234. package/scripts/checks/build-output-check.js +37 -0
  235. package/scripts/checks/control-center-smoke.js +102 -10
  236. package/scripts/checks/control-smoke.js +19 -8
  237. package/scripts/checks/http-mcp-smoke.js +82 -4
  238. package/scripts/checks/lifecycle-smoke.js +15 -12
  239. package/scripts/checks/mcp-manifest-check.js +1 -1
  240. package/scripts/checks/mcp-smoke.js +58 -4
  241. package/scripts/checks/package-manifest-check.js +20 -7
  242. package/scripts/checks/unit-tests.js +3 -5
  243. package/scripts/checks/watcher-supervisor-smoke.js +38 -1
  244. package/scripts/control/get-patchwarden-health.ps1 +1 -1
  245. package/scripts/control/manage-patchwarden.ps1 +69 -4
  246. package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
  247. package/scripts/control/run-background-supervisor.ps1 +41 -0
  248. package/scripts/control/start-patchwarden-tunnel.ps1 +191 -33
  249. package/scripts/e2e/demo-runtime.mjs +153 -0
  250. package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
  251. package/scripts/launchers/PatchWarden-Control.cmd +6 -0
  252. package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
  253. package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
  254. package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
  255. package/scripts/lib/clean-generated-output.js +11 -0
  256. package/scripts/lib/file-discovery.js +12 -0
  257. package/scripts/release/desktop-preflight.js +211 -0
  258. package/scripts/release/pack-clean.js +59 -14
  259. package/src/assessments/agentAssessor.ts +26 -12
  260. package/src/assessments/assessmentDiagnostics.ts +172 -0
  261. package/src/assessments/assessmentStore.ts +288 -51
  262. package/src/assessments/securitySnapshot.ts +231 -0
  263. package/src/config.ts +70 -13
  264. package/src/control/fileManager.ts +40 -0
  265. package/src/control/middleware/auth.ts +22 -4
  266. package/src/control/middleware/static.ts +16 -3
  267. package/src/control/routeTable.ts +301 -0
  268. package/src/control/routes/audit.ts +14 -6
  269. package/src/control/routes/evidence.ts +1 -1
  270. package/src/control/routes/lineage.ts +1 -1
  271. package/src/control/routes/process.ts +341 -40
  272. package/src/control/routes/sessions.ts +88 -25
  273. package/src/control/routes/status.ts +134 -17
  274. package/src/control/routes/taskActions.ts +24 -58
  275. package/src/control/routes/tasks.ts +66 -58
  276. package/src/control/routes/workspace.ts +56 -25
  277. package/src/control/runtime.ts +71 -43
  278. package/src/control/server.ts +37 -342
  279. package/src/control/shared.ts +77 -11
  280. package/src/diagnostics/allowedTestCommandSafety.ts +12 -0
  281. package/src/direct/directAudit.ts +17 -9
  282. package/src/direct/directGuards.ts +72 -44
  283. package/src/direct/directPatch.ts +95 -8
  284. package/src/direct/directSessionStore.ts +213 -55
  285. package/src/direct/directVerification.ts +9 -23
  286. package/src/doctor.ts +76 -64
  287. package/src/goal/acceptanceEngine.ts +1 -1
  288. package/src/goal/goalProgress.ts +17 -13
  289. package/src/goal/goalReport.ts +5 -13
  290. package/src/goal/goalStatus.ts +19 -3
  291. package/src/goal/goalStore.ts +241 -54
  292. package/src/goal/handoffExport.ts +6 -6
  293. package/src/goal/specKitImport.ts +12 -12
  294. package/src/goal/subgoalSync.ts +11 -8
  295. package/src/goal/worktreeManager.ts +139 -22
  296. package/src/httpServer.ts +113 -30
  297. package/src/logging.ts +10 -3
  298. package/src/policy/projectPolicy.ts +5 -2
  299. package/src/release/releaseGate.ts +74 -27
  300. package/src/runner/agentInvocation.ts +126 -4
  301. package/src/runner/changeCapture.ts +291 -57
  302. package/src/runner/postTaskCleanup.ts +41 -17
  303. package/src/runner/processSecurity.ts +433 -0
  304. package/src/runner/runTask.ts +197 -97
  305. package/src/runner/simpleProcess.ts +66 -31
  306. package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
  307. package/src/{taskRuntime.ts → runner/taskRuntime.ts} +6 -3
  308. package/src/runner/taskStatusStore.ts +69 -0
  309. package/src/runner/watch.ts +348 -52
  310. package/src/security/contentRedaction.ts +2 -2
  311. package/src/security/discoveryTokenStore.ts +18 -4
  312. package/src/security/loopbackHost.ts +19 -0
  313. package/src/security/pathGuard.ts +35 -16
  314. package/src/security/planGuard.ts +2 -1
  315. package/src/security/runtimeGuard.ts +9 -6
  316. package/src/security/secretComparison.ts +13 -0
  317. package/src/security/sensitiveGuard.ts +27 -8
  318. package/src/security/toolInvocationGuard.ts +2 -2
  319. package/src/security/workspaceRootGuard.ts +53 -0
  320. package/src/smoke-test.ts +27 -26
  321. package/src/tools/catalog/index.ts +4 -0
  322. package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
  323. package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +7 -16
  324. package/src/tools/definitions/toolDefs.ts +1264 -0
  325. package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
  326. package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +136 -39
  327. package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +37 -9
  328. package/src/tools/diagnostics/index.ts +6 -0
  329. package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
  330. package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +27 -17
  331. package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
  332. package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +6 -6
  333. package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +7 -5
  334. package/src/tools/direct/index.ts +3 -0
  335. package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
  336. package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
  337. package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
  338. package/src/tools/discovery/index.ts +3 -0
  339. package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
  340. package/src/tools/dispatch/coreDispatch.ts +36 -31
  341. package/src/tools/dispatch/diagnosticDispatch.ts +26 -21
  342. package/src/tools/dispatch/directDispatch.ts +11 -10
  343. package/src/tools/dispatch/goalDispatch.ts +5 -4
  344. package/src/tools/dispatch/releaseDispatch.ts +3 -2
  345. package/src/tools/dispatch/validation.ts +78 -0
  346. package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
  347. package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +41 -26
  348. package/src/tools/goals/index.ts +3 -0
  349. package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
  350. package/src/tools/registry.ts +17 -1261
  351. package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
  352. package/src/tools/release/index.ts +2 -0
  353. package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
  354. package/src/tools/tasks/cancelTask.ts +110 -0
  355. package/src/tools/{createTask.ts → tasks/createTask.ts} +161 -33
  356. package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +12 -16
  357. package/src/tools/{evidencePack.ts → tasks/evidencePack.ts} +36 -22
  358. package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
  359. package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +13 -6
  360. package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
  361. package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +46 -44
  362. package/src/tools/tasks/index.ts +18 -0
  363. package/src/tools/{listTasks.ts → tasks/listTasks.ts} +6 -5
  364. package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +228 -77
  365. package/src/tools/tasks/retryTask.ts +69 -0
  366. package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +73 -46
  367. package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
  368. package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
  369. package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
  370. package/src/tools/tasks/taskStates.ts +54 -0
  371. package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +3 -12
  372. package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
  373. package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
  374. package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
  375. package/src/tools/workspace/index.ts +10 -0
  376. package/src/tools/workspace/listAgents.ts +75 -0
  377. package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
  378. package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
  379. package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
  380. package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
  381. package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
  382. package/src/tools/workspace/syncFile.ts +292 -0
  383. package/src/utils/atomicFile.ts +74 -0
  384. package/src/utils/boundedFile.ts +116 -0
  385. package/src/utils/lockedJsonFile.ts +251 -0
  386. package/src/utils/platform.ts +31 -0
  387. package/src/utils/stableJson.ts +12 -0
  388. package/src/version.ts +3 -2
  389. package/src/watcherStatus.ts +19 -1
  390. package/ui/desktop-bootstrap.js +11 -0
  391. package/ui/desktop-bridge.js +36 -0
  392. package/ui/desktop.css +160 -0
  393. package/ui/getting-started.js +93 -0
  394. package/ui/i18n.js +484 -0
  395. package/ui/log-parser.js +30 -0
  396. package/ui/pages/audit.html +12 -0
  397. package/ui/pages/dashboard.html +94 -147
  398. package/ui/pages/direct-sessions.html +123 -26
  399. package/ui/pages/getting-started.html +43 -0
  400. package/ui/pages/logs.html +134 -22
  401. package/ui/pages/settings.html +101 -0
  402. package/ui/pages/task-detail.html +12 -0
  403. package/ui/pages/tasks.html +54 -8
  404. package/ui/pages/workspace.html +38 -1
  405. package/ui/settings.js +254 -0
  406. package/PatchWarden-Control.cmd +0 -6
  407. package/Restart-PatchWarden-Control.cmd +0 -6
  408. package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
  409. package/dist/test/unit/acceptance-engine.test.js +0 -228
  410. package/dist/test/unit/agent-router.test.d.ts +0 -1
  411. package/dist/test/unit/agent-router.test.js +0 -287
  412. package/dist/test/unit/android-doctor.test.d.ts +0 -1
  413. package/dist/test/unit/android-doctor.test.js +0 -118
  414. package/dist/test/unit/apply-patch.test.d.ts +0 -1
  415. package/dist/test/unit/apply-patch.test.js +0 -225
  416. package/dist/test/unit/audit-checks.test.d.ts +0 -1
  417. package/dist/test/unit/audit-checks.test.js +0 -350
  418. package/dist/test/unit/chinese-path.test.d.ts +0 -1
  419. package/dist/test/unit/chinese-path.test.js +0 -91
  420. package/dist/test/unit/command-guard.test.d.ts +0 -1
  421. package/dist/test/unit/command-guard.test.js +0 -160
  422. package/dist/test/unit/create-task.test.d.ts +0 -1
  423. package/dist/test/unit/create-task.test.js +0 -197
  424. package/dist/test/unit/diagnose-task.test.d.ts +0 -1
  425. package/dist/test/unit/diagnose-task.test.js +0 -457
  426. package/dist/test/unit/direct-guards.test.d.ts +0 -1
  427. package/dist/test/unit/direct-guards.test.js +0 -328
  428. package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
  429. package/dist/test/unit/discovery-token-store.test.js +0 -139
  430. package/dist/test/unit/evidence-pack.test.d.ts +0 -1
  431. package/dist/test/unit/evidence-pack.test.js +0 -224
  432. package/dist/test/unit/get-task-status.test.d.ts +0 -1
  433. package/dist/test/unit/get-task-status.test.js +0 -174
  434. package/dist/test/unit/get-task-summary.test.d.ts +0 -1
  435. package/dist/test/unit/get-task-summary.test.js +0 -146
  436. package/dist/test/unit/goal-graph.test.d.ts +0 -1
  437. package/dist/test/unit/goal-graph.test.js +0 -298
  438. package/dist/test/unit/goal-progress.test.d.ts +0 -1
  439. package/dist/test/unit/goal-progress.test.js +0 -381
  440. package/dist/test/unit/goal-report.test.d.ts +0 -1
  441. package/dist/test/unit/goal-report.test.js +0 -159
  442. package/dist/test/unit/goal-status.test.d.ts +0 -1
  443. package/dist/test/unit/goal-status.test.js +0 -215
  444. package/dist/test/unit/goal-store.test.d.ts +0 -1
  445. package/dist/test/unit/goal-store.test.js +0 -253
  446. package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
  447. package/dist/test/unit/goal-subgoal-task.test.js +0 -55
  448. package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
  449. package/dist/test/unit/goal-tools-registry.test.js +0 -192
  450. package/dist/test/unit/handoff-export.test.d.ts +0 -1
  451. package/dist/test/unit/handoff-export.test.js +0 -263
  452. package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
  453. package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
  454. package/dist/test/unit/logging.test.d.ts +0 -1
  455. package/dist/test/unit/logging.test.js +0 -397
  456. package/dist/test/unit/path-guard.test.d.ts +0 -1
  457. package/dist/test/unit/path-guard.test.js +0 -133
  458. package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
  459. package/dist/test/unit/post-task-cleanup.test.js +0 -48
  460. package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
  461. package/dist/test/unit/project-policy-release-mode.test.js +0 -125
  462. package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
  463. package/dist/test/unit/reconcile-tasks.test.js +0 -456
  464. package/dist/test/unit/release-gate.test.d.ts +0 -1
  465. package/dist/test/unit/release-gate.test.js +0 -242
  466. package/dist/test/unit/run-task-loop.test.d.ts +0 -1
  467. package/dist/test/unit/run-task-loop.test.js +0 -380
  468. package/dist/test/unit/safe-status.test.d.ts +0 -1
  469. package/dist/test/unit/safe-status.test.js +0 -165
  470. package/dist/test/unit/safe-views.test.d.ts +0 -1
  471. package/dist/test/unit/safe-views.test.js +0 -171
  472. package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
  473. package/dist/test/unit/schema-drift-check.test.js +0 -176
  474. package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
  475. package/dist/test/unit/sensitive-guard.test.js +0 -104
  476. package/dist/test/unit/spec-kit-import.test.d.ts +0 -1
  477. package/dist/test/unit/spec-kit-import.test.js +0 -341
  478. package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
  479. package/dist/test/unit/subgoal-sync.test.js +0 -183
  480. package/dist/test/unit/sync-file.test.d.ts +0 -1
  481. package/dist/test/unit/sync-file.test.js +0 -154
  482. package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
  483. package/dist/test/unit/tool-invocation-guard.test.js +0 -432
  484. package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
  485. package/dist/test/unit/tool-usage-stats.test.js +0 -300
  486. package/dist/test/unit/toolSearch.test.d.ts +0 -1
  487. package/dist/test/unit/toolSearch.test.js +0 -571
  488. package/dist/test/unit/wait-for-task.test.d.ts +0 -1
  489. package/dist/test/unit/wait-for-task.test.js +0 -144
  490. package/dist/test/unit/watcher-status.test.d.ts +0 -1
  491. package/dist/test/unit/watcher-status.test.js +0 -169
  492. package/dist/test/unit/worktree-manager.test.d.ts +0 -1
  493. package/dist/test/unit/worktree-manager.test.js +0 -176
  494. package/dist/tools/applyPatch.js +0 -41
  495. package/dist/tools/cancelTask.d.ts +0 -30
  496. package/dist/tools/cancelTask.js +0 -64
  497. package/dist/tools/finalizeDirectSession.js +0 -84
  498. package/dist/tools/goalSubgoalTask.js +0 -110
  499. package/dist/tools/killTask.d.ts +0 -15
  500. package/dist/tools/listAgents.d.ts +0 -12
  501. package/dist/tools/listAgents.js +0 -42
  502. package/dist/tools/reconcileTasks.js +0 -352
  503. package/dist/tools/retryTask.js +0 -45
  504. package/dist/tools/runVerification.js +0 -36
  505. package/dist/tools/syncFile.js +0 -65
  506. package/docs/control-center/control-center-daily-driver.md +0 -211
  507. package/docs/control-center/control-center-mvp.md +0 -205
  508. package/docs/control-center/control-center-phase2.md +0 -159
  509. package/docs/execution-plan-2026-07-09.md +0 -315
  510. package/docs/release-v0.6.0.md +0 -71
  511. package/docs/release-v0.6.1.md +0 -75
  512. package/docs/release-v0.6.4.md +0 -45
  513. package/docs/roadmap-execution-and-acceptance.md +0 -365
  514. package/src/test/unit/acceptance-engine.test.ts +0 -261
  515. package/src/test/unit/agent-router.test.ts +0 -342
  516. package/src/test/unit/android-doctor.test.ts +0 -158
  517. package/src/test/unit/apply-patch.test.ts +0 -293
  518. package/src/test/unit/audit-checks.test.ts +0 -567
  519. package/src/test/unit/chinese-path.test.ts +0 -106
  520. package/src/test/unit/command-guard.test.ts +0 -221
  521. package/src/test/unit/create-task.test.ts +0 -255
  522. package/src/test/unit/diagnose-task.test.ts +0 -544
  523. package/src/test/unit/direct-guards.test.ts +0 -467
  524. package/src/test/unit/discovery-token-store.test.ts +0 -181
  525. package/src/test/unit/evidence-pack.test.ts +0 -251
  526. package/src/test/unit/get-task-status.test.ts +0 -203
  527. package/src/test/unit/get-task-summary.test.ts +0 -173
  528. package/src/test/unit/goal-graph.test.ts +0 -347
  529. package/src/test/unit/goal-progress.test.ts +0 -538
  530. package/src/test/unit/goal-report.test.ts +0 -189
  531. package/src/test/unit/goal-status.test.ts +0 -270
  532. package/src/test/unit/goal-store.test.ts +0 -318
  533. package/src/test/unit/goal-subgoal-task.test.ts +0 -72
  534. package/src/test/unit/goal-tools-registry.test.ts +0 -245
  535. package/src/test/unit/handoff-export.test.ts +0 -295
  536. package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
  537. package/src/test/unit/logging.test.ts +0 -497
  538. package/src/test/unit/path-guard.test.ts +0 -180
  539. package/src/test/unit/post-task-cleanup.test.ts +0 -53
  540. package/src/test/unit/project-policy-release-mode.test.ts +0 -156
  541. package/src/test/unit/reconcile-tasks.test.ts +0 -551
  542. package/src/test/unit/release-gate.test.ts +0 -314
  543. package/src/test/unit/run-task-loop.test.ts +0 -425
  544. package/src/test/unit/safe-status.test.ts +0 -187
  545. package/src/test/unit/safe-views.test.ts +0 -184
  546. package/src/test/unit/schema-drift-check.test.ts +0 -260
  547. package/src/test/unit/sensitive-guard.test.ts +0 -124
  548. package/src/test/unit/spec-kit-import.test.ts +0 -429
  549. package/src/test/unit/subgoal-sync.test.ts +0 -236
  550. package/src/test/unit/sync-file.test.ts +0 -231
  551. package/src/test/unit/tool-invocation-guard.test.ts +0 -542
  552. package/src/test/unit/tool-usage-stats.test.ts +0 -384
  553. package/src/test/unit/toolSearch.test.ts +0 -756
  554. package/src/test/unit/wait-for-task.test.ts +0 -176
  555. package/src/test/unit/watcher-status.test.ts +0 -190
  556. package/src/test/unit/worktree-manager.test.ts +0 -247
  557. package/src/tools/cancelTask.ts +0 -70
  558. package/src/tools/listAgents.ts +0 -54
  559. package/src/tools/retryTask.ts +0 -53
  560. package/src/tools/syncFile.ts +0 -122
  561. /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
  562. /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
  563. /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
  564. /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
  565. /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
  566. /package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +0 -0
  567. /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
  568. /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
  569. /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
  570. /package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +0 -0
  571. /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
  572. /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
  573. /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
  574. /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
  575. /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
  576. /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
  577. /package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +0 -0
  578. /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
  579. /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
  580. /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
  581. /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
  582. /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
  583. /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
  584. /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
  585. /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
  586. /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
  587. /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
  588. /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
  589. /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
  590. /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
  591. /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
package/src/doctor.ts CHANGED
@@ -10,20 +10,23 @@
10
10
 
11
11
  import { existsSync, statSync, readFileSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
12
12
  import { isAbsolute, resolve, normalize, join } from "node:path";
13
- import { execSync } from "node:child_process";
14
13
  import { createServer } from "node:net";
15
14
  import { getConfig, type PatchWardenConfig } from "./config.js";
16
15
  import { guardPath, guardWorkspacePath } from "./security/pathGuard.js";
17
16
  import { isSensitivePath } from "./security/sensitiveGuard.js";
18
17
  import { guardPlanContent } from "./security/planGuard.js";
19
- import { TASK_READ_ONLY_FILES } from "./tools/getTaskFile.js";
18
+ import { TASK_READ_ONLY_FILES } from "./tools/tasks/getTaskFile.js";
20
19
  import { getToolDefs } from "./tools/registry.js";
21
- import { CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES, selectToolsForProfile } from "./tools/toolCatalog.js";
22
- import { buildToolRegistry } from "./tools/toolRegistry.js";
23
- import { runAllSchemaDriftChecks } from "./tools/schemaDriftCheck.js";
20
+ import { CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES, selectToolsForProfile } from "./tools/catalog/toolCatalog.js";
21
+ import { buildToolRegistry } from "./tools/catalog/toolRegistry.js";
22
+ import { runAllSchemaDriftChecks } from "./tools/diagnostics/schemaDriftCheck.js";
24
23
  import { runReleaseGateCheck } from "./release/releaseGate.js";
25
24
  import { PATCHWARDEN_VERSION } from "./version.js";
26
25
  import { logger } from "./logging.js";
26
+ import { unsafeWorkspaceRootLabel } from "./security/workspaceRootGuard.js";
27
+ import { runSimpleProcessSync } from "./runner/simpleProcess.js";
28
+ import { resolveAgentLaunch } from "./runner/agentInvocation.js";
29
+ import { isDangerousAllowedTestCommand } from "./diagnostics/allowedTestCommandSafety.js";
27
30
 
28
31
  // ── Types ──────────────────────────────────────────────────────────
29
32
 
@@ -50,13 +53,18 @@ export interface DoctorContext {
50
53
 
51
54
  // ── Helpers ────────────────────────────────────────────────────────
52
55
 
53
- function cmd(cmdStr: string): string {
56
+ function cmd(command: string, args: readonly string[] = []): string {
54
57
  try {
55
- return execSync(cmdStr, {
56
- encoding: "utf-8",
57
- timeout: 5000,
58
- stdio: ["ignore", "pipe", "ignore"], // suppress stdin and stderr
59
- }).trim();
58
+ const result = runSimpleProcessSync({
59
+ command,
60
+ args: [...args],
61
+ cwd: process.cwd(),
62
+ timeoutMs: 5000,
63
+ maxStdoutBytes: 64 * 1024,
64
+ maxStderrBytes: 64 * 1024,
65
+ });
66
+ if (result.exitCode !== 0) return "";
67
+ return `${result.stdout}${result.stderr}`.trim();
60
68
  } catch {
61
69
  return "";
62
70
  }
@@ -109,7 +117,7 @@ const checkNpmAvailable: DoctorCheck = {
109
117
  id: "npm-available",
110
118
  description: "npm available",
111
119
  run() {
112
- const npmVer = cmd("npm --version");
120
+ const npmVer = cmd(process.platform === "win32" ? "npm.cmd" : "npm", ["--version"]);
113
121
  return [checkResult("npm available", npmVer !== "", npmVer || "npm not found in PATH")];
114
122
  },
115
123
  };
@@ -144,7 +152,7 @@ const checkGitAvailable: DoctorCheck = {
144
152
  id: "git-available",
145
153
  description: "Git available",
146
154
  run() {
147
- const gitVer = cmd("git --version");
155
+ const gitVer = cmd("git", ["--version"]);
148
156
  return [warnCheckResult("Git available", gitVer !== "", gitVer || "git not found — runner git.diff will not work")];
149
157
  },
150
158
  };
@@ -199,18 +207,9 @@ const checkWorkspaceRoot: DoctorCheck = {
199
207
  try { isDir = statSync(ws).isDirectory(); } catch {}
200
208
  results.push(checkResult("workspaceRoot is directory", isDir, ws));
201
209
 
202
- const dangerousRoots = [
203
- { pattern: /^[A-Za-z]:\\?$/, label: "drive root" },
204
- { pattern: /\\Users\\[^\\]+$/, label: "user home directory" },
205
- { pattern: /\\Desktop$/, label: "Desktop" },
206
- { pattern: /\\Downloads$/, label: "Downloads" },
207
- { pattern: /\\Documents$/, label: "Documents" },
208
- ];
209
-
210
- for (const { pattern, label } of dangerousRoots) {
211
- if (pattern.test(ws)) {
212
- results.push(warnResult(`workspaceRoot is ${label}: ${ws} — consider narrowing to a project directory`));
213
- }
210
+ const unsafeLabel = unsafeWorkspaceRootLabel(ws);
211
+ if (unsafeLabel) {
212
+ results.push(warnResult(`workspaceRoot is ${unsafeLabel}: ${ws} consider narrowing to a project directory`));
214
213
  }
215
214
  return results;
216
215
  },
@@ -312,11 +311,13 @@ const checkServerVersion: DoctorCheck = {
312
311
  packageJson.version === PATCHWARDEN_VERSION,
313
312
  `${PATCHWARDEN_VERSION} vs ${packageJson.version}`,
314
313
  ),
315
- checkResult(
316
- "Manifest preflight script exists",
317
- existsSync(resolve(process.cwd(), "scripts/checks/mcp-manifest-check.js")),
318
- "scripts/checks/mcp-manifest-check.js",
319
- ),
314
+ process.env.PATCHWARDEN_DESKTOP_RUNTIME === "1"
315
+ ? okResult("Manifest preflight covered by compiled desktop runtime checks")
316
+ : checkResult(
317
+ "Manifest preflight script exists",
318
+ existsSync(resolve(process.cwd(), "scripts/checks/mcp-manifest-check.js")),
319
+ "scripts/checks/mcp-manifest-check.js",
320
+ ),
320
321
  ];
321
322
  },
322
323
  };
@@ -331,8 +332,8 @@ const checkToolProfiles: DoctorCheck = {
331
332
  process.env.PATCHWARDEN_TOOL_PROFILE = "full";
332
333
  const fullTools = getToolDefs();
333
334
  const coreTools = selectToolsForProfile(fullTools, "chatgpt_core", context.config?.enableDirectProfile);
334
- const createSchema = coreTools.find((tool) => tool.name === "create_task")?.inputSchema as any;
335
- const waitSchema = coreTools.find((tool) => tool.name === "wait_for_task")?.inputSchema as any;
335
+ const createSchema = coreTools.find((tool) => tool.name === "create_task")?.inputSchema;
336
+ const waitSchema = coreTools.find((tool) => tool.name === "wait_for_task")?.inputSchema;
336
337
  results.push(checkResult("Full tool profile exposes 66 tools", fullTools.length === 66, `${fullTools.length} tools`));
337
338
  results.push(
338
339
  checkResult(
@@ -463,23 +464,23 @@ const checkToolModules: DoctorCheck = {
463
464
  description: "Tool module checks",
464
465
  run() {
465
466
  const newTools = [
466
- "listTasks",
467
- "listAgents",
468
- "cancelTask",
469
- "killTask",
470
- "retryTask",
471
- "getTaskProgress",
472
- "getTaskSummary",
473
- "waitForTask",
474
- "getTaskStdoutTail",
475
- "healthCheck",
476
- "auditTask",
467
+ { name: "listTasks", subdir: "tasks" },
468
+ { name: "listAgents", subdir: "workspace" },
469
+ { name: "cancelTask", subdir: "tasks" },
470
+ { name: "killTask", subdir: "tasks" },
471
+ { name: "retryTask", subdir: "tasks" },
472
+ { name: "getTaskProgress", subdir: "tasks" },
473
+ { name: "getTaskSummary", subdir: "tasks" },
474
+ { name: "waitForTask", subdir: "tasks" },
475
+ { name: "getTaskStdoutTail", subdir: "tasks" },
476
+ { name: "healthCheck", subdir: "diagnostics" },
477
+ { name: "auditTask", subdir: "diagnostics" },
477
478
  ];
478
479
  const results: DoctorCheckResult[] = [];
479
480
  for (const t of newTools) {
480
- const compiled = resolve(process.cwd(), "dist/tools", `${t}.js`);
481
+ const compiled = resolve(process.cwd(), "dist/tools", t.subdir, `${t.name}.js`);
481
482
  const exists = existsSync(compiled);
482
- results.push(checkResult(`Tool module: ${t}`, exists, exists ? "compiled" : "missing"));
483
+ results.push(checkResult(`Tool module: ${t.name}`, exists, exists ? "compiled" : "missing"));
483
484
  }
484
485
  return results;
485
486
  },
@@ -490,18 +491,18 @@ const checkDirectToolModules: DoctorCheck = {
490
491
  description: "Direct tool module checks",
491
492
  run() {
492
493
  const directToolModules = [
493
- "createDirectSession",
494
- "searchWorkspace",
495
- "applyPatch",
496
- "runVerification",
497
- "finalizeDirectSession",
498
- "auditSession",
494
+ { name: "createDirectSession", subdir: "direct" },
495
+ { name: "searchWorkspace", subdir: "workspace" },
496
+ { name: "applyPatch", subdir: "workspace" },
497
+ { name: "runVerification", subdir: "tasks" },
498
+ { name: "finalizeDirectSession", subdir: "direct" },
499
+ { name: "auditSession", subdir: "diagnostics" },
499
500
  ];
500
501
  const results: DoctorCheckResult[] = [];
501
502
  for (const t of directToolModules) {
502
- const compiled = resolve(process.cwd(), "dist/tools", `${t}.js`);
503
+ const compiled = resolve(process.cwd(), "dist/tools", t.subdir, `${t.name}.js`);
503
504
  const exists = existsSync(compiled);
504
- results.push(checkResult(`Direct tool module: ${t}`, exists, exists ? "compiled" : "missing"));
505
+ results.push(checkResult(`Direct tool module: ${t.name}`, exists, exists ? "compiled" : "missing"));
505
506
  }
506
507
  return results;
507
508
  },
@@ -612,8 +613,7 @@ const checkAgentCommands: DoctorCheck = {
612
613
  run(context) {
613
614
  if (!context.config) return [];
614
615
  const results: DoctorCheckResult[] = [];
615
- const agents = context.config.agents || {};
616
- for (const [name, agentCfg] of Object.entries(agents) as [string, any][]) {
616
+ for (const [name, agentCfg] of Object.entries(context.config.agents)) {
617
617
  const cmdName = agentCfg.command;
618
618
  const looksLikePath = isAbsolute(cmdName) || cmdName.includes("/") || cmdName.includes("\\");
619
619
  if (looksLikePath) {
@@ -621,11 +621,26 @@ const checkAgentCommands: DoctorCheck = {
621
621
  results.push(warnCheckResult(`Agent "${name}" command available`, agentExists, agentExists ? `Found: ${cmdName}` : `"${cmdName}" does not exist — agent tasks will fail`));
622
622
  continue;
623
623
  }
624
- // Platform-appropriate lookup: 'where' on Windows, 'command -v' on Unix
624
+ // Use an argumentized lookup utility; never interpolate config into a shell.
625
625
  const isWin = process.platform === "win32";
626
- const lookupCmd = isWin ? `where ${cmdName}` : `command -v ${cmdName}`;
627
- const fallbackCmd = isWin ? `command -v ${cmdName}` : `which ${cmdName}`;
628
- const found = cmd(lookupCmd) || cmd(fallbackCmd);
626
+ let found = "";
627
+ if (isWin) {
628
+ try {
629
+ found = resolveAgentLaunch(
630
+ name,
631
+ cmdName,
632
+ process.platform,
633
+ process.env.PATH || "",
634
+ existsSync,
635
+ context.config.workspaceRoot,
636
+ typeof agentCfg.adapter === "string" ? agentCfg.adapter : name,
637
+ ).command;
638
+ } catch {
639
+ found = "";
640
+ }
641
+ } else {
642
+ found = cmd("which", [cmdName]);
643
+ }
629
644
  results.push(warnCheckResult(`Agent "${name}" command available`, found !== "", found ? `Found: ${found.split("\n")[0]}` : `"${cmdName}" not in PATH — agent tasks will fail`));
630
645
  }
631
646
  return results;
@@ -641,12 +656,9 @@ const checkAllowedTestCommandsSafety: DoctorCheck = {
641
656
  const testCmds = context.config.allowedTestCommands || [];
642
657
  results.push(checkResult("allowedTestCommands is non-empty", testCmds.length > 0, testCmds.length > 0 ? `${testCmds.length} commands` : "No test commands configured"));
643
658
 
644
- const dangerous = ["rm -rf", "del /s", "format", "shutdown", "curl |", "wget |"];
645
659
  for (const cmdStr of testCmds) {
646
- for (const danger of dangerous) {
647
- if (cmdStr.toLowerCase().includes(danger)) {
648
- results.push(warnResult(`allowedTestCommands contains dangerous pattern: "${cmdStr}"`));
649
- }
660
+ if (isDangerousAllowedTestCommand(cmdStr)) {
661
+ results.push(warnResult(`allowedTestCommands contains dangerous pattern: "${cmdStr}"`));
650
662
  }
651
663
  }
652
664
  return results;
@@ -13,7 +13,7 @@
13
13
  * 4. 所有检查通过 → ACCEPTED
14
14
  */
15
15
 
16
- import type { AcceptanceStatus } from "../tools/createTask.js";
16
+ import type { AcceptanceStatus } from "../tools/tasks/createTask.js";
17
17
 
18
18
  // ── 类型定义 ──────────────────────────────────────────────────────
19
19
 
@@ -15,7 +15,7 @@ import { existsSync, readFileSync } from "node:fs";
15
15
  import { isAbsolute, join } from "node:path";
16
16
  import { getConfig } from "../config.js";
17
17
  import { PatchWardenError } from "../errors.js";
18
- import { readGoalStatus, writeGoalStatus } from "./goalStore.js";
18
+ import { mutateGoalStatus, readGoalStatus } from "./goalStore.js";
19
19
  import { updateSubgoalStatus, type GoalStatus, type Subgoal } from "./goalStatus.js";
20
20
  import { getBlockedSubgoals } from "./goalGraph.js";
21
21
 
@@ -93,7 +93,7 @@ export function acceptSubgoal(
93
93
  subgoalId: string,
94
94
  workspaceRoot?: string
95
95
  ): { subgoal_id: string; status: "accepted"; accepted_at: string } {
96
- const goalStatus = readGoalStatus(goalId, workspaceRoot);
96
+ return mutateGoalStatus(goalId, (goalStatus) => {
97
97
 
98
98
  const subgoal = goalStatus.subgoals.find((s) => s.id === subgoalId);
99
99
  if (!subgoal) {
@@ -146,14 +146,16 @@ export function acceptSubgoal(
146
146
  // 校验 3:通过状态机转换(要求 subgoal 当前为 done_by_agent)
147
147
  const updatedGoalStatus = updateSubgoalStatus(goalStatus, subgoalId, "accepted");
148
148
 
149
- writeGoalStatus(goalId, updatedGoalStatus, workspaceRoot);
150
-
151
149
  const updatedSubgoal = updatedGoalStatus.subgoals.find((s) => s.id === subgoalId)!;
152
150
  return {
153
- subgoal_id: subgoalId,
154
- status: "accepted",
155
- accepted_at: updatedSubgoal.accepted_at!,
151
+ next: updatedGoalStatus,
152
+ result: {
153
+ subgoal_id: subgoalId,
154
+ status: "accepted" as const,
155
+ accepted_at: updatedSubgoal.accepted_at!,
156
+ },
156
157
  };
158
+ }, workspaceRoot);
157
159
  }
158
160
 
159
161
  /**
@@ -175,7 +177,7 @@ export function rejectSubgoal(
175
177
  reason: string,
176
178
  workspaceRoot?: string
177
179
  ): { subgoal_id: string; status: "rejected"; rejected_reason: string } {
178
- const goalStatus = readGoalStatus(goalId, workspaceRoot);
180
+ return mutateGoalStatus(goalId, (goalStatus) => {
179
181
 
180
182
  const index = goalStatus.subgoals.findIndex((s) => s.id === subgoalId);
181
183
  if (index === -1) {
@@ -222,13 +224,15 @@ export function rejectSubgoal(
222
224
  updated_at: new Date().toISOString(),
223
225
  };
224
226
 
225
- writeGoalStatus(goalId, updatedGoalStatus, workspaceRoot);
226
-
227
227
  return {
228
- subgoal_id: subgoalId,
229
- status: "rejected",
230
- rejected_reason: reason,
228
+ next: updatedGoalStatus,
229
+ result: {
230
+ subgoal_id: subgoalId,
231
+ status: "rejected" as const,
232
+ rejected_reason: reason,
233
+ },
231
234
  };
235
+ }, workspaceRoot);
232
236
  }
233
237
 
234
238
  /**
@@ -6,11 +6,12 @@
6
6
  * 所有写入操作使用原子写(.tmp + rename),所有字符串内容经 redactSensitiveValue 脱敏。
7
7
  */
8
8
 
9
- import { mkdirSync, renameSync, writeFileSync } from "node:fs";
9
+ import { mkdirSync } from "node:fs";
10
10
  import { join, resolve } from "node:path";
11
11
  import { getConfig } from "../config.js";
12
12
  import { redactSensitiveValue } from "../security/contentRedaction.js";
13
- import { listEvidencePacks } from "../tools/evidencePack.js";
13
+ import { listEvidencePacks } from "../tools/tasks/evidencePack.js";
14
+ import { atomicWriteFileSync } from "../utils/atomicFile.js";
14
15
  import { summarizeGoalProgress, type GoalProgressSummary } from "./goalProgress.js";
15
16
  import { readGoalStatus } from "./goalStore.js";
16
17
 
@@ -45,15 +46,6 @@ function resolveWorkspaceRoot(workspaceRoot?: string): string {
45
46
  return workspaceRoot ?? getConfig().workspaceRoot;
46
47
  }
47
48
 
48
- /**
49
- * 原子写文件:先写到 .tmp 文件,再 renameSync 到目标路径。
50
- */
51
- function atomicWriteFile(filePath: string, content: string): void {
52
- const tmpPath = filePath + ".tmp";
53
- writeFileSync(tmpPath, content, "utf-8");
54
- renameSync(tmpPath, filePath);
55
- }
56
-
57
49
  /**
58
50
  * 将百分比字符串(如 "100%")解析为数字。
59
51
  */
@@ -261,11 +253,11 @@ export function exportGoalReport(
261
253
  const safeReport = redactSensitiveValue(rawReport).value as SafeGoalReport;
262
254
 
263
255
  // 原子写 JSON(机器可读)
264
- atomicWriteFile(reportJsonPath, JSON.stringify(safeReport, null, 2) + "\n");
256
+ atomicWriteFileSync(reportJsonPath, JSON.stringify(safeReport, null, 2) + "\n");
265
257
 
266
258
  // 原子写 Markdown(人类可读,从脱敏后的对象生成)
267
259
  const markdown = buildReportMarkdown(safeReport, { noSubgoals, incomplete });
268
- atomicWriteFile(reportMdPath, markdown);
260
+ atomicWriteFileSync(reportMdPath, markdown);
269
261
 
270
262
  return safeReport;
271
263
  }
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import { PatchWardenError } from "../errors.js";
15
+ import { redactSensitiveContent } from "../security/contentRedaction.js";
15
16
 
16
17
  // ── 类型定义 ──────────────────────────────────────────────────────
17
18
 
@@ -35,6 +36,8 @@ export interface Subgoal {
35
36
  external_ref?: string;
36
37
  /** Spec Kit task.files 提示(作用域文件路径列表) */
37
38
  scope_hints?: string[];
39
+ /** Managed git worktree associated with an isolated subgoal task. */
40
+ worktree_id?: string;
38
41
  }
39
42
 
40
43
  export interface GoalStatus {
@@ -74,7 +77,7 @@ export function createInitialGoalStatus(
74
77
  const now = new Date().toISOString();
75
78
  return {
76
79
  goal_id: goalId,
77
- title,
80
+ title: redactGoalText(title, 500),
78
81
  status: "active",
79
82
  repo_path: repoPath,
80
83
  created_at: now,
@@ -94,6 +97,15 @@ export function addSubgoal(
94
97
  title: string,
95
98
  dependsOn: string[] = []
96
99
  ): { goalStatus: GoalStatus; subgoalId: string } {
100
+ if (goalStatus.status !== "active") {
101
+ throw new PatchWardenError(
102
+ "goal_not_active",
103
+ `Goal "${goalStatus.goal_id}" is ${goalStatus.status} and cannot accept new subgoals.`,
104
+ "Create a new Goal Session for additional work.",
105
+ true,
106
+ { goal_id: goalStatus.goal_id, status: goalStatus.status },
107
+ );
108
+ }
97
109
  const existingIds = new Set(goalStatus.subgoals.map((s) => s.id));
98
110
  for (const depId of dependsOn) {
99
111
  if (!existingIds.has(depId)) {
@@ -111,7 +123,7 @@ export function addSubgoal(
111
123
  const subgoalId = `subgoal-${String(nextNumber).padStart(3, "0")}`;
112
124
  const newSubgoal: Subgoal = {
113
125
  id: subgoalId,
114
- title,
126
+ title: redactGoalText(title, 500),
115
127
  status: "ready",
116
128
  depends_on: [...dependsOn],
117
129
  task_ids: [],
@@ -185,7 +197,7 @@ export function updateSubgoalStatus(
185
197
  { subgoal_id: subgoalId, from_status: current.status, to_status: newStatus }
186
198
  );
187
199
  }
188
- updatedSubgoal.rejected_reason = options.rejected_reason;
200
+ updatedSubgoal.rejected_reason = redactGoalText(options.rejected_reason, 2000);
189
201
  }
190
202
 
191
203
  const newSubgoals = [...goalStatus.subgoals];
@@ -198,6 +210,10 @@ export function updateSubgoalStatus(
198
210
  };
199
211
  }
200
212
 
213
+ function redactGoalText(value: string, maxChars: number): string {
214
+ return redactSensitiveContent(String(value || "")).content.slice(0, maxChars);
215
+ }
216
+
201
217
  /**
202
218
  * 将 taskId 关联到指定 subgoal(去重)。
203
219
  * 不可变更新:返回新的 GoalStatus 对象。