patchwarden 1.5.1 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (573) hide show
  1. package/PatchWarden.cmd +32 -2
  2. package/README.en.md +152 -25
  3. package/README.md +120 -23
  4. package/dist/assessments/agentAssessor.js +21 -12
  5. package/dist/assessments/assessmentStore.js +42 -34
  6. package/dist/config.d.ts +15 -0
  7. package/dist/config.js +66 -13
  8. package/dist/control/fileManager.d.ts +2 -0
  9. package/dist/control/fileManager.js +39 -0
  10. package/dist/control/middleware/auth.d.ts +6 -0
  11. package/dist/control/middleware/auth.js +14 -5
  12. package/dist/control/middleware/static.js +16 -3
  13. package/dist/control/routeTable.d.ts +24 -0
  14. package/dist/control/routeTable.js +263 -0
  15. package/dist/control/routes/audit.js +17 -7
  16. package/dist/control/routes/evidence.js +1 -1
  17. package/dist/control/routes/lineage.js +1 -1
  18. package/dist/control/routes/process.d.ts +7 -0
  19. package/dist/control/routes/process.js +329 -42
  20. package/dist/control/routes/sessions.d.ts +9 -1
  21. package/dist/control/routes/sessions.js +84 -21
  22. package/dist/control/routes/status.d.ts +46 -1
  23. package/dist/control/routes/status.js +72 -15
  24. package/dist/control/routes/taskActions.js +24 -60
  25. package/dist/control/routes/tasks.d.ts +4 -0
  26. package/dist/control/routes/tasks.js +61 -62
  27. package/dist/control/routes/workspace.js +50 -23
  28. package/dist/control/runtime.d.ts +3 -2
  29. package/dist/control/runtime.js +63 -30
  30. package/dist/control/server.js +36 -365
  31. package/dist/control/shared.d.ts +25 -1
  32. package/dist/control/shared.js +64 -11
  33. package/dist/direct/directAudit.js +234 -225
  34. package/dist/direct/directGuards.d.ts +2 -1
  35. package/dist/direct/directGuards.js +42 -29
  36. package/dist/direct/directPatch.d.ts +6 -1
  37. package/dist/direct/directPatch.js +55 -8
  38. package/dist/direct/directSessionStore.d.ts +16 -6
  39. package/dist/direct/directSessionStore.js +127 -35
  40. package/dist/direct/directVerification.js +8 -16
  41. package/dist/doctor.js +62 -52
  42. package/dist/goal/acceptanceEngine.d.ts +1 -1
  43. package/dist/goal/goalProgress.js +75 -69
  44. package/dist/goal/goalReport.js +5 -12
  45. package/dist/goal/goalStatus.d.ts +2 -0
  46. package/dist/goal/goalStatus.js +10 -3
  47. package/dist/goal/goalStore.d.ts +9 -2
  48. package/dist/goal/goalStore.js +152 -45
  49. package/dist/goal/handoffExport.js +6 -6
  50. package/dist/goal/specKitImport.js +97 -96
  51. package/dist/goal/subgoalSync.js +11 -9
  52. package/dist/goal/worktreeManager.d.ts +2 -0
  53. package/dist/goal/worktreeManager.js +209 -136
  54. package/dist/httpServer.js +111 -32
  55. package/dist/logging.js +5 -3
  56. package/dist/policy/projectPolicy.js +5 -2
  57. package/dist/release/releaseGate.d.ts +1 -1
  58. package/dist/release/releaseGate.js +78 -25
  59. package/dist/runner/agentInvocation.d.ts +14 -0
  60. package/dist/runner/agentInvocation.js +96 -4
  61. package/dist/runner/changeCapture.d.ts +13 -5
  62. package/dist/runner/changeCapture.js +243 -61
  63. package/dist/runner/postTaskCleanup.js +48 -19
  64. package/dist/runner/processSecurity.d.ts +56 -0
  65. package/dist/runner/processSecurity.js +373 -0
  66. package/dist/runner/runTask.d.ts +1 -1
  67. package/dist/runner/runTask.js +115 -87
  68. package/dist/runner/simpleProcess.d.ts +3 -0
  69. package/dist/runner/simpleProcess.js +50 -36
  70. package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
  71. package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
  72. package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +1 -1
  73. package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
  74. package/dist/runner/taskStatusStore.d.ts +11 -0
  75. package/dist/runner/taskStatusStore.js +24 -0
  76. package/dist/runner/watch.d.ts +14 -1
  77. package/dist/runner/watch.js +256 -48
  78. package/dist/security/contentRedaction.js +2 -2
  79. package/dist/security/discoveryTokenStore.d.ts +3 -2
  80. package/dist/security/discoveryTokenStore.js +17 -2
  81. package/dist/security/loopbackHost.d.ts +2 -0
  82. package/dist/security/loopbackHost.js +16 -0
  83. package/dist/security/pathGuard.js +32 -17
  84. package/dist/security/planGuard.js +2 -1
  85. package/dist/security/runtimeGuard.js +9 -6
  86. package/dist/security/secretComparison.d.ts +3 -0
  87. package/dist/security/secretComparison.js +11 -0
  88. package/dist/security/sensitiveGuard.d.ts +5 -0
  89. package/dist/security/sensitiveGuard.js +27 -8
  90. package/dist/security/toolInvocationGuard.d.ts +2 -2
  91. package/dist/security/toolInvocationGuard.js +1 -1
  92. package/dist/security/workspaceRootGuard.d.ts +8 -0
  93. package/dist/security/workspaceRootGuard.js +47 -0
  94. package/dist/smoke-test.js +24 -23
  95. package/dist/tools/catalog/index.d.ts +4 -0
  96. package/dist/tools/catalog/index.js +4 -0
  97. package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
  98. package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
  99. package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +6 -15
  100. package/dist/tools/definitions/toolDefs.d.ts +18 -0
  101. package/dist/tools/definitions/toolDefs.js +1177 -0
  102. package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
  103. package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
  104. package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +1 -1
  105. package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +99 -29
  106. package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +6 -6
  107. package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +7 -7
  108. package/dist/tools/diagnostics/index.d.ts +6 -0
  109. package/dist/tools/diagnostics/index.js +6 -0
  110. package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
  111. package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
  112. package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +12 -8
  113. package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +23 -13
  114. package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
  115. package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
  116. package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +6 -6
  117. package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +1 -1
  118. package/dist/tools/direct/finalizeDirectSession.js +86 -0
  119. package/dist/tools/direct/index.d.ts +3 -0
  120. package/dist/tools/direct/index.js +3 -0
  121. package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
  122. package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
  123. package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
  124. package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
  125. package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
  126. package/dist/tools/discovery/index.d.ts +3 -0
  127. package/dist/tools/discovery/index.js +3 -0
  128. package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
  129. package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
  130. package/dist/tools/dispatch/coreDispatch.js +32 -31
  131. package/dist/tools/dispatch/diagnosticDispatch.d.ts +3 -5
  132. package/dist/tools/dispatch/diagnosticDispatch.js +70 -68
  133. package/dist/tools/dispatch/directDispatch.js +11 -10
  134. package/dist/tools/dispatch/goalDispatch.js +5 -4
  135. package/dist/tools/dispatch/releaseDispatch.js +3 -2
  136. package/dist/tools/dispatch/validation.d.ts +7 -0
  137. package/dist/tools/dispatch/validation.js +71 -0
  138. package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
  139. package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +1 -1
  140. package/dist/tools/goals/goalSubgoalTask.js +118 -0
  141. package/dist/tools/goals/index.d.ts +3 -0
  142. package/dist/tools/goals/index.js +3 -0
  143. package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
  144. package/dist/tools/registry.d.ts +7 -11
  145. package/dist/tools/registry.js +17 -1178
  146. package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
  147. package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
  148. package/dist/tools/release/index.d.ts +2 -0
  149. package/dist/tools/release/index.js +2 -0
  150. package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
  151. package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
  152. package/dist/tools/tasks/cancelTask.d.ts +11 -0
  153. package/dist/tools/tasks/cancelTask.js +85 -0
  154. package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +10 -2
  155. package/dist/tools/{createTask.js → tasks/createTask.js} +42 -27
  156. package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
  157. package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +8 -8
  158. package/dist/tools/{evidencePack.js → tasks/evidencePack.js} +34 -22
  159. package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
  160. package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
  161. package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +5 -5
  162. package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
  163. package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +33 -26
  164. package/dist/tools/tasks/index.d.ts +18 -0
  165. package/dist/tools/tasks/index.js +18 -0
  166. package/dist/tools/tasks/killTask.d.ts +1 -0
  167. package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
  168. package/dist/tools/{listTasks.js → tasks/listTasks.js} +3 -3
  169. package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +1 -1
  170. package/dist/tools/{reconcileTasks.js → tasks/reconcileTasks.js} +64 -66
  171. package/dist/tools/tasks/retryTask.js +60 -0
  172. package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
  173. package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +58 -30
  174. package/dist/tools/tasks/runVerification.js +38 -0
  175. package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
  176. package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
  177. package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
  178. package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
  179. package/dist/tools/workspace/applyPatch.js +53 -0
  180. package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
  181. package/dist/tools/workspace/index.d.ts +10 -0
  182. package/dist/tools/workspace/index.js +10 -0
  183. package/dist/tools/{listAgents.d.ts → workspace/listAgents.d.ts} +5 -0
  184. package/dist/tools/{listAgents.js → workspace/listAgents.js} +8 -4
  185. package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
  186. package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
  187. package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
  188. package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
  189. package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
  190. package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
  191. package/dist/tools/workspace/syncFile.js +134 -0
  192. package/dist/utils/atomicFile.d.ts +7 -0
  193. package/dist/utils/atomicFile.js +48 -0
  194. package/dist/utils/boundedFile.d.ts +8 -0
  195. package/dist/utils/boundedFile.js +93 -0
  196. package/dist/utils/lockedJsonFile.d.ts +15 -0
  197. package/dist/utils/lockedJsonFile.js +224 -0
  198. package/dist/utils/platform.d.ts +11 -0
  199. package/dist/utils/platform.js +26 -0
  200. package/dist/utils/stableJson.d.ts +2 -0
  201. package/dist/utils/stableJson.js +12 -0
  202. package/dist/version.d.ts +3 -2
  203. package/dist/version.js +3 -2
  204. package/dist/watcherStatus.d.ts +2 -2
  205. package/dist/watcherStatus.js +18 -0
  206. package/docs/CODE_WIKI.md +808 -143
  207. package/docs/architecture.md +15 -55
  208. package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
  209. package/docs/control-center/README.md +4 -4
  210. package/docs/dashboard-overview.md +4 -4
  211. package/docs/desktop-app.md +175 -0
  212. package/docs/evidence-pack-schema.md +3 -3
  213. package/docs/open-source-application.md +17 -11
  214. package/docs/release-checklist.md +1 -1
  215. package/docs/release-evidence.md +39 -29
  216. package/docs/task-safe-review-workflow.md +5 -5
  217. package/docs/threat-model.md +19 -1
  218. package/examples/config.example.json +4 -2
  219. package/package.json +27 -10
  220. package/scripts/README.md +15 -6
  221. package/scripts/build.js +11 -0
  222. package/scripts/checks/brand-check.js +3 -0
  223. package/scripts/checks/build-output-check.js +37 -0
  224. package/scripts/checks/control-center-smoke.js +91 -6
  225. package/scripts/checks/control-smoke.js +19 -8
  226. package/scripts/checks/http-mcp-smoke.js +82 -4
  227. package/scripts/checks/lifecycle-smoke.js +10 -10
  228. package/scripts/checks/mcp-manifest-check.js +1 -1
  229. package/scripts/checks/mcp-smoke.js +27 -3
  230. package/scripts/checks/package-manifest-check.js +20 -7
  231. package/scripts/checks/unit-tests.js +3 -5
  232. package/scripts/checks/watcher-supervisor-smoke.js +9 -0
  233. package/scripts/control/get-patchwarden-health.ps1 +1 -1
  234. package/scripts/control/manage-patchwarden.ps1 +69 -4
  235. package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
  236. package/scripts/control/run-background-supervisor.ps1 +41 -0
  237. package/scripts/control/start-patchwarden-tunnel.ps1 +126 -32
  238. package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
  239. package/scripts/launchers/PatchWarden-Control.cmd +6 -0
  240. package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
  241. package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
  242. package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
  243. package/scripts/lib/clean-generated-output.js +11 -0
  244. package/scripts/lib/file-discovery.js +12 -0
  245. package/scripts/release/desktop-preflight.js +211 -0
  246. package/scripts/release/pack-clean.js +59 -14
  247. package/src/assessments/agentAssessor.ts +26 -12
  248. package/src/assessments/assessmentStore.ts +52 -40
  249. package/src/config.ts +70 -13
  250. package/src/control/fileManager.ts +40 -0
  251. package/src/control/middleware/auth.ts +22 -4
  252. package/src/control/middleware/static.ts +16 -3
  253. package/src/control/routeTable.ts +301 -0
  254. package/src/control/routes/audit.ts +14 -6
  255. package/src/control/routes/evidence.ts +1 -1
  256. package/src/control/routes/lineage.ts +1 -1
  257. package/src/control/routes/process.ts +341 -40
  258. package/src/control/routes/sessions.ts +88 -25
  259. package/src/control/routes/status.ts +97 -17
  260. package/src/control/routes/taskActions.ts +24 -58
  261. package/src/control/routes/tasks.ts +66 -58
  262. package/src/control/routes/workspace.ts +56 -25
  263. package/src/control/runtime.ts +69 -33
  264. package/src/control/server.ts +36 -342
  265. package/src/control/shared.ts +77 -11
  266. package/src/direct/directAudit.ts +17 -9
  267. package/src/direct/directGuards.ts +72 -44
  268. package/src/direct/directPatch.ts +95 -8
  269. package/src/direct/directSessionStore.ts +211 -55
  270. package/src/direct/directVerification.ts +9 -23
  271. package/src/doctor.ts +73 -59
  272. package/src/goal/acceptanceEngine.ts +1 -1
  273. package/src/goal/goalProgress.ts +17 -13
  274. package/src/goal/goalReport.ts +5 -13
  275. package/src/goal/goalStatus.ts +19 -3
  276. package/src/goal/goalStore.ts +241 -54
  277. package/src/goal/handoffExport.ts +6 -6
  278. package/src/goal/specKitImport.ts +12 -12
  279. package/src/goal/subgoalSync.ts +11 -8
  280. package/src/goal/worktreeManager.ts +139 -22
  281. package/src/httpServer.ts +113 -30
  282. package/src/logging.ts +10 -3
  283. package/src/policy/projectPolicy.ts +5 -2
  284. package/src/release/releaseGate.ts +74 -27
  285. package/src/runner/agentInvocation.ts +126 -4
  286. package/src/runner/changeCapture.ts +291 -57
  287. package/src/runner/postTaskCleanup.ts +41 -17
  288. package/src/runner/processSecurity.ts +433 -0
  289. package/src/runner/runTask.ts +138 -91
  290. package/src/runner/simpleProcess.ts +66 -31
  291. package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
  292. package/src/{taskRuntime.ts → runner/taskRuntime.ts} +4 -3
  293. package/src/runner/taskStatusStore.ts +54 -0
  294. package/src/runner/watch.ts +281 -51
  295. package/src/security/contentRedaction.ts +2 -2
  296. package/src/security/discoveryTokenStore.ts +18 -4
  297. package/src/security/loopbackHost.ts +19 -0
  298. package/src/security/pathGuard.ts +35 -16
  299. package/src/security/planGuard.ts +2 -1
  300. package/src/security/runtimeGuard.ts +9 -6
  301. package/src/security/secretComparison.ts +13 -0
  302. package/src/security/sensitiveGuard.ts +27 -8
  303. package/src/security/toolInvocationGuard.ts +2 -2
  304. package/src/security/workspaceRootGuard.ts +53 -0
  305. package/src/smoke-test.ts +25 -24
  306. package/src/tools/catalog/index.ts +4 -0
  307. package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
  308. package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +7 -16
  309. package/src/tools/definitions/toolDefs.ts +1264 -0
  310. package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
  311. package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +99 -32
  312. package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +8 -8
  313. package/src/tools/diagnostics/index.ts +6 -0
  314. package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
  315. package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +27 -17
  316. package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
  317. package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +6 -6
  318. package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +7 -5
  319. package/src/tools/direct/index.ts +3 -0
  320. package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
  321. package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
  322. package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
  323. package/src/tools/discovery/index.ts +3 -0
  324. package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
  325. package/src/tools/dispatch/coreDispatch.ts +36 -31
  326. package/src/tools/dispatch/diagnosticDispatch.ts +26 -21
  327. package/src/tools/dispatch/directDispatch.ts +11 -10
  328. package/src/tools/dispatch/goalDispatch.ts +5 -4
  329. package/src/tools/dispatch/releaseDispatch.ts +3 -2
  330. package/src/tools/dispatch/validation.ts +78 -0
  331. package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
  332. package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +41 -26
  333. package/src/tools/goals/index.ts +3 -0
  334. package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
  335. package/src/tools/registry.ts +17 -1261
  336. package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
  337. package/src/tools/release/index.ts +2 -0
  338. package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
  339. package/src/tools/tasks/cancelTask.ts +109 -0
  340. package/src/tools/{createTask.ts → tasks/createTask.ts} +49 -26
  341. package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +8 -8
  342. package/src/tools/{evidencePack.ts → tasks/evidencePack.ts} +36 -22
  343. package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
  344. package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +7 -5
  345. package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
  346. package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +44 -33
  347. package/src/tools/tasks/index.ts +18 -0
  348. package/src/tools/{listTasks.ts → tasks/listTasks.ts} +4 -4
  349. package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +68 -66
  350. package/src/tools/tasks/retryTask.ts +69 -0
  351. package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +69 -34
  352. package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
  353. package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
  354. package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
  355. package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
  356. package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
  357. package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
  358. package/src/tools/workspace/index.ts +10 -0
  359. package/src/tools/{listAgents.ts → workspace/listAgents.ts} +11 -4
  360. package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
  361. package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
  362. package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
  363. package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
  364. package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
  365. package/src/tools/workspace/syncFile.ts +292 -0
  366. package/src/utils/atomicFile.ts +58 -0
  367. package/src/utils/boundedFile.ts +116 -0
  368. package/src/utils/lockedJsonFile.ts +251 -0
  369. package/src/utils/platform.ts +31 -0
  370. package/src/utils/stableJson.ts +12 -0
  371. package/src/version.ts +3 -2
  372. package/src/watcherStatus.ts +19 -1
  373. package/ui/desktop-bootstrap.js +11 -0
  374. package/ui/desktop-bridge.js +36 -0
  375. package/ui/desktop.css +160 -0
  376. package/ui/getting-started.js +93 -0
  377. package/ui/i18n.js +484 -0
  378. package/ui/log-parser.js +30 -0
  379. package/ui/pages/audit.html +12 -0
  380. package/ui/pages/dashboard.html +90 -147
  381. package/ui/pages/direct-sessions.html +123 -26
  382. package/ui/pages/getting-started.html +43 -0
  383. package/ui/pages/logs.html +105 -22
  384. package/ui/pages/settings.html +101 -0
  385. package/ui/pages/task-detail.html +12 -0
  386. package/ui/pages/tasks.html +54 -8
  387. package/ui/pages/workspace.html +38 -1
  388. package/ui/settings.js +245 -0
  389. package/PatchWarden-Control.cmd +0 -6
  390. package/Restart-PatchWarden-Control.cmd +0 -6
  391. package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
  392. package/dist/test/unit/acceptance-engine.test.js +0 -228
  393. package/dist/test/unit/agent-router.test.d.ts +0 -1
  394. package/dist/test/unit/agent-router.test.js +0 -287
  395. package/dist/test/unit/android-doctor.test.d.ts +0 -1
  396. package/dist/test/unit/android-doctor.test.js +0 -118
  397. package/dist/test/unit/apply-patch.test.d.ts +0 -1
  398. package/dist/test/unit/apply-patch.test.js +0 -225
  399. package/dist/test/unit/audit-checks.test.d.ts +0 -1
  400. package/dist/test/unit/audit-checks.test.js +0 -350
  401. package/dist/test/unit/chinese-path.test.d.ts +0 -1
  402. package/dist/test/unit/chinese-path.test.js +0 -91
  403. package/dist/test/unit/command-guard.test.d.ts +0 -1
  404. package/dist/test/unit/command-guard.test.js +0 -160
  405. package/dist/test/unit/create-task.test.d.ts +0 -1
  406. package/dist/test/unit/create-task.test.js +0 -197
  407. package/dist/test/unit/diagnose-task.test.d.ts +0 -1
  408. package/dist/test/unit/diagnose-task.test.js +0 -457
  409. package/dist/test/unit/direct-guards.test.d.ts +0 -1
  410. package/dist/test/unit/direct-guards.test.js +0 -328
  411. package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
  412. package/dist/test/unit/discovery-token-store.test.js +0 -139
  413. package/dist/test/unit/evidence-pack.test.d.ts +0 -1
  414. package/dist/test/unit/evidence-pack.test.js +0 -224
  415. package/dist/test/unit/get-task-status.test.d.ts +0 -1
  416. package/dist/test/unit/get-task-status.test.js +0 -174
  417. package/dist/test/unit/get-task-summary.test.d.ts +0 -1
  418. package/dist/test/unit/get-task-summary.test.js +0 -146
  419. package/dist/test/unit/goal-graph.test.d.ts +0 -1
  420. package/dist/test/unit/goal-graph.test.js +0 -298
  421. package/dist/test/unit/goal-progress.test.d.ts +0 -1
  422. package/dist/test/unit/goal-progress.test.js +0 -381
  423. package/dist/test/unit/goal-report.test.d.ts +0 -1
  424. package/dist/test/unit/goal-report.test.js +0 -159
  425. package/dist/test/unit/goal-status.test.d.ts +0 -1
  426. package/dist/test/unit/goal-status.test.js +0 -215
  427. package/dist/test/unit/goal-store.test.d.ts +0 -1
  428. package/dist/test/unit/goal-store.test.js +0 -253
  429. package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
  430. package/dist/test/unit/goal-subgoal-task.test.js +0 -55
  431. package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
  432. package/dist/test/unit/goal-tools-registry.test.js +0 -192
  433. package/dist/test/unit/handoff-export.test.d.ts +0 -1
  434. package/dist/test/unit/handoff-export.test.js +0 -263
  435. package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
  436. package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
  437. package/dist/test/unit/logging.test.d.ts +0 -1
  438. package/dist/test/unit/logging.test.js +0 -397
  439. package/dist/test/unit/path-guard.test.d.ts +0 -1
  440. package/dist/test/unit/path-guard.test.js +0 -133
  441. package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
  442. package/dist/test/unit/post-task-cleanup.test.js +0 -48
  443. package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
  444. package/dist/test/unit/project-policy-release-mode.test.js +0 -125
  445. package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
  446. package/dist/test/unit/reconcile-tasks.test.js +0 -456
  447. package/dist/test/unit/release-gate.test.d.ts +0 -1
  448. package/dist/test/unit/release-gate.test.js +0 -242
  449. package/dist/test/unit/run-task-loop.test.d.ts +0 -1
  450. package/dist/test/unit/run-task-loop.test.js +0 -380
  451. package/dist/test/unit/safe-status.test.d.ts +0 -1
  452. package/dist/test/unit/safe-status.test.js +0 -165
  453. package/dist/test/unit/safe-views.test.d.ts +0 -1
  454. package/dist/test/unit/safe-views.test.js +0 -171
  455. package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
  456. package/dist/test/unit/schema-drift-check.test.js +0 -176
  457. package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
  458. package/dist/test/unit/sensitive-guard.test.js +0 -104
  459. package/dist/test/unit/spec-kit-import.test.d.ts +0 -1
  460. package/dist/test/unit/spec-kit-import.test.js +0 -341
  461. package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
  462. package/dist/test/unit/subgoal-sync.test.js +0 -183
  463. package/dist/test/unit/sync-file.test.d.ts +0 -1
  464. package/dist/test/unit/sync-file.test.js +0 -154
  465. package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
  466. package/dist/test/unit/tool-invocation-guard.test.js +0 -432
  467. package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
  468. package/dist/test/unit/tool-usage-stats.test.js +0 -300
  469. package/dist/test/unit/toolSearch.test.d.ts +0 -1
  470. package/dist/test/unit/toolSearch.test.js +0 -571
  471. package/dist/test/unit/wait-for-task.test.d.ts +0 -1
  472. package/dist/test/unit/wait-for-task.test.js +0 -144
  473. package/dist/test/unit/watcher-status.test.d.ts +0 -1
  474. package/dist/test/unit/watcher-status.test.js +0 -169
  475. package/dist/test/unit/worktree-manager.test.d.ts +0 -1
  476. package/dist/test/unit/worktree-manager.test.js +0 -176
  477. package/dist/tools/applyPatch.js +0 -41
  478. package/dist/tools/cancelTask.d.ts +0 -30
  479. package/dist/tools/cancelTask.js +0 -64
  480. package/dist/tools/finalizeDirectSession.js +0 -84
  481. package/dist/tools/goalSubgoalTask.js +0 -110
  482. package/dist/tools/killTask.d.ts +0 -15
  483. package/dist/tools/retryTask.js +0 -45
  484. package/dist/tools/runVerification.js +0 -36
  485. package/dist/tools/syncFile.js +0 -65
  486. package/docs/control-center/control-center-daily-driver.md +0 -211
  487. package/docs/control-center/control-center-mvp.md +0 -205
  488. package/docs/control-center/control-center-phase2.md +0 -159
  489. package/docs/execution-plan-2026-07-09.md +0 -315
  490. package/docs/release-v0.6.0.md +0 -71
  491. package/docs/release-v0.6.1.md +0 -75
  492. package/docs/release-v0.6.4.md +0 -45
  493. package/docs/roadmap-execution-and-acceptance.md +0 -365
  494. package/src/test/unit/acceptance-engine.test.ts +0 -261
  495. package/src/test/unit/agent-router.test.ts +0 -342
  496. package/src/test/unit/android-doctor.test.ts +0 -158
  497. package/src/test/unit/apply-patch.test.ts +0 -293
  498. package/src/test/unit/audit-checks.test.ts +0 -567
  499. package/src/test/unit/chinese-path.test.ts +0 -106
  500. package/src/test/unit/command-guard.test.ts +0 -221
  501. package/src/test/unit/create-task.test.ts +0 -255
  502. package/src/test/unit/diagnose-task.test.ts +0 -544
  503. package/src/test/unit/direct-guards.test.ts +0 -467
  504. package/src/test/unit/discovery-token-store.test.ts +0 -181
  505. package/src/test/unit/evidence-pack.test.ts +0 -251
  506. package/src/test/unit/get-task-status.test.ts +0 -203
  507. package/src/test/unit/get-task-summary.test.ts +0 -173
  508. package/src/test/unit/goal-graph.test.ts +0 -347
  509. package/src/test/unit/goal-progress.test.ts +0 -538
  510. package/src/test/unit/goal-report.test.ts +0 -189
  511. package/src/test/unit/goal-status.test.ts +0 -270
  512. package/src/test/unit/goal-store.test.ts +0 -318
  513. package/src/test/unit/goal-subgoal-task.test.ts +0 -72
  514. package/src/test/unit/goal-tools-registry.test.ts +0 -245
  515. package/src/test/unit/handoff-export.test.ts +0 -295
  516. package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
  517. package/src/test/unit/logging.test.ts +0 -497
  518. package/src/test/unit/path-guard.test.ts +0 -180
  519. package/src/test/unit/post-task-cleanup.test.ts +0 -53
  520. package/src/test/unit/project-policy-release-mode.test.ts +0 -156
  521. package/src/test/unit/reconcile-tasks.test.ts +0 -551
  522. package/src/test/unit/release-gate.test.ts +0 -314
  523. package/src/test/unit/run-task-loop.test.ts +0 -425
  524. package/src/test/unit/safe-status.test.ts +0 -187
  525. package/src/test/unit/safe-views.test.ts +0 -184
  526. package/src/test/unit/schema-drift-check.test.ts +0 -260
  527. package/src/test/unit/sensitive-guard.test.ts +0 -124
  528. package/src/test/unit/spec-kit-import.test.ts +0 -429
  529. package/src/test/unit/subgoal-sync.test.ts +0 -236
  530. package/src/test/unit/sync-file.test.ts +0 -231
  531. package/src/test/unit/tool-invocation-guard.test.ts +0 -542
  532. package/src/test/unit/tool-usage-stats.test.ts +0 -384
  533. package/src/test/unit/toolSearch.test.ts +0 -756
  534. package/src/test/unit/wait-for-task.test.ts +0 -176
  535. package/src/test/unit/watcher-status.test.ts +0 -190
  536. package/src/test/unit/worktree-manager.test.ts +0 -247
  537. package/src/tools/cancelTask.ts +0 -70
  538. package/src/tools/retryTask.ts +0 -53
  539. package/src/tools/syncFile.ts +0 -122
  540. /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
  541. /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
  542. /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
  543. /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
  544. /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
  545. /package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +0 -0
  546. /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
  547. /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
  548. /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
  549. /package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +0 -0
  550. /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
  551. /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
  552. /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
  553. /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
  554. /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
  555. /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
  556. /package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +0 -0
  557. /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
  558. /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
  559. /package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +0 -0
  560. /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
  561. /package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +0 -0
  562. /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
  563. /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
  564. /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
  565. /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
  566. /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
  567. /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
  568. /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
  569. /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
  570. /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
  571. /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
  572. /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
  573. /package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +0 -0
@@ -1,13 +1,13 @@
1
1
  import { setTimeout as sleep } from "node:timers/promises";
2
- import { getConfig } from "../config.js";
3
- import { createWorktree } from "../goal/worktreeManager.js";
4
- import { guardWorkspacePath } from "../security/pathGuard.js";
5
- import { createDirectSession } from "./createDirectSession.js";
2
+ import { getConfig } from "../../config.js";
3
+ import { createWorktree } from "../../goal/worktreeManager.js";
4
+ import { guardWorkspacePath } from "../../security/pathGuard.js";
5
+ import { createDirectSession } from "../direct/createDirectSession.js";
6
6
  import { createTask } from "./createTask.js";
7
- import { recommendAgentForTask } from "./recommendAgentForTask.js";
8
- import { runDirectVerificationBundle } from "./runDirectVerificationBundle.js";
7
+ import { recommendAgentForTask } from "../workspace/recommendAgentForTask.js";
8
+ import { runDirectVerificationBundle } from "../direct/runDirectVerificationBundle.js";
9
9
  import { waitForTask } from "./waitForTask.js";
10
- import { safeAudit, safeAuditDirectSession, safeFinalizeDirectSession, safeResult, safeTestSummary } from "./safeViews.js";
10
+ import { safeAudit, safeAuditDirectSession, safeFinalizeDirectSession, safeResult, safeTestSummary } from "../diagnostics/safeViews.js";
11
11
  import { createLineageId, writeTaskLineage, } from "./taskLineage.js";
12
12
  const DEFAULT_DEPS = {
13
13
  createTask,
@@ -130,17 +130,17 @@ export async function runTaskLoopWithDeps(input, deps) {
130
130
  timeout_seconds: normalized.task_timeout_seconds,
131
131
  execution_mode: "assess_only",
132
132
  };
133
- const assessment = await deps.createTask(assessmentInput);
133
+ const assessment = asRecord(await deps.createTask(assessmentInput));
134
134
  if (assessment.decision === "blocked") {
135
- return finalize("blocked", "high_risk_blocked", "Risk assessment blocked task execution.", assessment.reason_codes?.join(", "));
135
+ return finalize("blocked", "high_risk_blocked", "Risk assessment blocked task execution.", asArray(assessment.reason_codes).map(String).join(", "));
136
136
  }
137
137
  if (assessment.decision === "needs_confirm") {
138
138
  return finalize("blocked", "user_confirmation_required", "Ask the user to confirm the assessment before executing the loop.");
139
139
  }
140
- const created = await deps.createTask({
140
+ const created = asRecord(await deps.createTask({
141
141
  execution_mode: "execute",
142
142
  assessment_id: String(assessment.assessment_id || ""),
143
- });
143
+ }));
144
144
  const taskId = String(created.task_id || "");
145
145
  if (!taskId) {
146
146
  return finalize("failed", "policy_blocked", "create_task returned no task_id.", "create_task returned no task_id");
@@ -153,9 +153,9 @@ export async function runTaskLoopWithDeps(input, deps) {
153
153
  if (wait.stop_reason) {
154
154
  return finalize("blocked", wait.stop_reason, wait.next_action, wait.error);
155
155
  }
156
- const result = deps.safeResult(taskId, { max_items: 8 });
157
- const tests = deps.safeTestSummary(taskId);
158
- const audit = deps.safeAudit(taskId, { max_items: 8 });
156
+ const result = asRecord(deps.safeResult(taskId, { max_items: 8 }));
157
+ const tests = asRecord(deps.safeTestSummary(taskId));
158
+ const audit = asRecord(deps.safeAudit(taskId, { max_items: 8 }));
159
159
  const round = buildRound(iteration, taskId, role, result, tests, audit);
160
160
  lineage.rounds.push(round);
161
161
  lineage.updated_at = deps.now().toISOString();
@@ -204,20 +204,32 @@ async function waitUntilTerminal(taskId, timeoutSeconds, deps) {
204
204
  error: `Task loop timed out waiting for ${taskId}.`,
205
205
  };
206
206
  }
207
- function buildRound(iteration, taskId, role, result, tests, audit) {
208
- const failChecks = Array.isArray(audit.fail_checks) ? audit.fail_checks.map((entry) => String(entry.name || entry)) : [];
209
- const warnChecks = Array.isArray(audit.warn_checks) ? audit.warn_checks.map((entry) => String(entry.name || entry)) : [];
207
+ function buildRound(iteration, taskId, role, resultValue, testsValue, auditValue) {
208
+ const result = asRecord(resultValue);
209
+ const tests = asRecord(testsValue);
210
+ const audit = asRecord(auditValue);
211
+ const resultVerification = asRecord(result.verification);
212
+ const auditAcceptance = asRecord(audit.acceptance);
213
+ const failChecks = asArray(audit.fail_checks).map((entry) => {
214
+ const check = asRecord(entry);
215
+ return String(check.name || entry);
216
+ });
217
+ const warnChecks = asArray(audit.warn_checks).map((entry) => {
218
+ const check = asRecord(entry);
219
+ return String(check.name || entry);
220
+ });
221
+ const recommendedActions = asArray(audit.recommended_next_actions);
210
222
  return {
211
223
  iteration,
212
224
  task_id: taskId,
213
225
  role,
214
226
  status: String(result.status || "unknown"),
215
227
  terminal: Boolean(result.terminal),
216
- verification_status: String(tests.status || result.verification?.status || "not_available"),
217
- audit_verdict: String(audit.verdict || audit.acceptance?.verdict || "unknown"),
228
+ verification_status: String(tests.status || resultVerification.status || "not_available"),
229
+ audit_verdict: String(audit.verdict || auditAcceptance.verdict || "unknown"),
218
230
  fail_checks: failChecks,
219
231
  warn_checks: warnChecks,
220
- next_action: String(result.next_action || audit.recommended_next_actions?.[0] || "review_task"),
232
+ next_action: String(result.next_action || recommendedActions[0] || "review_task"),
221
233
  };
222
234
  }
223
235
  function isSuccessfulRound(round) {
@@ -228,23 +240,27 @@ function isSuccessfulRound(round) {
228
240
  round.warn_checks.length === 0 &&
229
241
  round.audit_verdict === "pass");
230
242
  }
231
- function isHardStop(round, result, audit, stopOnHighRisk) {
243
+ function isHardStop(round, resultValue, auditValue, stopOnHighRisk) {
232
244
  if (["failed_scope_violation", "failed_policy_violation", "canceled"].includes(round.status))
233
245
  return true;
234
246
  if (!stopOnHighRisk)
235
247
  return false;
236
248
  const checkNames = [...round.fail_checks, ...round.warn_checks].join(" ").toLowerCase();
237
- const reason = String(result.failure_reason || audit.acceptance?.reason || "").toLowerCase();
249
+ const result = asRecord(resultValue);
250
+ const audit = asRecord(auditValue);
251
+ const reason = String(result.failure_reason || asRecord(audit.acceptance).reason || "").toLowerCase();
238
252
  return /scope|secret|sensitive|publish|release|policy|push/.test(`${checkNames} ${reason}`);
239
253
  }
240
- function hardStopReason(round, result) {
254
+ function hardStopReason(round, resultValue) {
255
+ const result = asRecord(resultValue);
241
256
  if (round.status === "failed_scope_violation" || round.status === "failed_policy_violation")
242
257
  return "policy_blocked";
243
258
  if (String(result.failure_reason || "").toLowerCase().includes("timeout"))
244
259
  return "agent_timeout";
245
260
  return "high_risk_blocked";
246
261
  }
247
- function buildFixGoal(originalGoal, result, round) {
262
+ function buildFixGoal(originalGoal, resultValue, round) {
263
+ const result = asRecord(resultValue);
248
264
  const failedCommand = result.failed_command ? ` Failed command: ${result.failed_command}.` : "";
249
265
  return [
250
266
  `Fix the failing verification for this PatchWarden loop without changing unrelated behavior.`,
@@ -303,8 +319,12 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
303
319
  commands: normalized.direct_verify_commands,
304
320
  timeout_seconds: normalized.direct_verify_timeout_seconds,
305
321
  });
306
- const finalized = await deps.safeFinalizeDirectSession(sessionId, { max_items: 8 });
307
- const audit = deps.safeAuditDirectSession(sessionId, { max_items: 8 });
322
+ const finalized = asRecord(await deps.safeFinalizeDirectSession(sessionId, { max_items: 8 }));
323
+ const audit = asRecord(deps.safeAuditDirectSession(sessionId, { max_items: 8 }));
324
+ const auditEvidence = asRecord(audit.evidence);
325
+ const auditDecision = audit.decision === "pass" || audit.decision === "warn" || audit.decision === "fail"
326
+ ? audit.decision
327
+ : "not_run";
308
328
  const evidence = {
309
329
  session_id: sessionId,
310
330
  status: bundle.status,
@@ -312,8 +332,8 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
312
332
  passed_commands: bundle.passed_commands,
313
333
  failed_commands: bundle.failed_commands,
314
334
  timed_out_commands: bundle.timed_out_commands,
315
- audit_decision: audit.decision || "not_run",
316
- changed_files_total: Number(finalized.changed_files_total || audit.evidence?.changed_files_total || 0),
335
+ audit_decision: auditDecision,
336
+ changed_files_total: Number(finalized.changed_files_total || auditEvidence.changed_files_total || 0),
317
337
  next_action: String(audit.next_action || bundle.next_action || "review_direct_session"),
318
338
  };
319
339
  if (bundle.status !== "passed") {
@@ -325,7 +345,7 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
325
345
  error: "Direct verification failed.",
326
346
  };
327
347
  }
328
- if (audit.decision === "fail") {
348
+ if (auditDecision === "fail") {
329
349
  return {
330
350
  evidence,
331
351
  stop_reason: "direct_audit_failed",
@@ -338,7 +358,7 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
338
358
  evidence,
339
359
  final_status: "accepted",
340
360
  next_action: "accept",
341
- warning: audit.decision === "warn" ? "Direct audit completed with warnings." : undefined,
361
+ warning: auditDecision === "warn" ? "Direct audit completed with warnings." : undefined,
342
362
  };
343
363
  }
344
364
  catch (err) {
@@ -357,6 +377,14 @@ async function runDirectVerification(lineageId, normalized, repoPath, deps) {
357
377
  };
358
378
  }
359
379
  }
380
+ function asRecord(value) {
381
+ return value && typeof value === "object" && !Array.isArray(value)
382
+ ? value
383
+ : {};
384
+ }
385
+ function asArray(value) {
386
+ return Array.isArray(value) ? value : [];
387
+ }
360
388
  function normalizeInput(input) {
361
389
  const config = getConfig();
362
390
  const repoPath = String(input.repo_path || "").trim();
@@ -0,0 +1,38 @@
1
+ import { readDirectSession, appendDirectSessionVerificationRun, withDirectSessionMutationLockAsync, } from "../../direct/directSessionStore.js";
2
+ import { guardDirectSessionActive } from "../../direct/directGuards.js";
3
+ import { runDirectVerification } from "../../direct/directVerification.js";
4
+ export async function runVerification(input) {
5
+ return withDirectSessionMutationLockAsync(input.session_id, async () => {
6
+ // 1. Read session and guard active
7
+ const session = readDirectSession(input.session_id);
8
+ guardDirectSessionActive(session);
9
+ // 2. Call runDirectVerification with command, resolvedRepoPath,
10
+ // sessionId, and timeoutSeconds
11
+ const timeoutSeconds = input.timeout_seconds ?? 120;
12
+ const result = await runDirectVerification({
13
+ command: input.command,
14
+ resolvedRepoPath: session.resolved_repo_path,
15
+ sessionId: input.session_id,
16
+ timeoutSeconds,
17
+ });
18
+ // 3. Append verification run to session
19
+ appendDirectSessionVerificationRun(input.session_id, result.run);
20
+ // 4. Return result
21
+ return {
22
+ command: result.run.command,
23
+ exit_code: result.run.exit_code,
24
+ passed: result.run.passed,
25
+ timed_out: result.run.timed_out,
26
+ redacted: Boolean(result.run.redacted),
27
+ redaction_categories: result.run.redaction_categories || [],
28
+ started_at: result.run.started_at,
29
+ finished_at: result.run.finished_at,
30
+ stdout_tail: result.run.stdout_tail,
31
+ stderr_tail: result.run.stderr_tail,
32
+ log_path: result.run.log_path,
33
+ next_action: result.run.passed
34
+ ? "Call finalize_direct_session to complete the session."
35
+ : "Review the verification output and apply_patch to fix issues.",
36
+ };
37
+ });
38
+ }
@@ -1,10 +1,11 @@
1
1
  import { randomBytes } from "node:crypto";
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { existsSync, mkdirSync, readFileSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
- import { getConfig } from "../config.js";
5
- import { guardReadPath } from "../security/pathGuard.js";
6
- import { redactSensitiveValue } from "../security/contentRedaction.js";
7
- import { PatchWardenError } from "../errors.js";
4
+ import { getConfig } from "../../config.js";
5
+ import { guardReadPath } from "../../security/pathGuard.js";
6
+ import { redactSensitiveValue } from "../../security/contentRedaction.js";
7
+ import { PatchWardenError } from "../../errors.js";
8
+ import { atomicWriteFileSync, atomicWriteJsonFileSync } from "../../utils/atomicFile.js";
8
9
  export function createLineageId(now = new Date()) {
9
10
  const stamp = now.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
10
11
  return `lineage_${stamp}_${randomBytes(4).toString("hex")}`;
@@ -14,8 +15,8 @@ export function writeTaskLineage(record) {
14
15
  const lineageDir = resolve(config.workspaceRoot, ".patchwarden", "lineages", record.lineage_id);
15
16
  mkdirSync(lineageDir, { recursive: true });
16
17
  const safeRecord = redactSensitiveValue(record).value;
17
- writeFileSync(join(lineageDir, "lineage.json"), JSON.stringify(safeRecord, null, 2) + "\n", "utf-8");
18
- writeFileSync(join(lineageDir, "SUMMARY.md"), buildSummaryMarkdown(safeRecord), "utf-8");
18
+ atomicWriteJsonFileSync(join(lineageDir, "lineage.json"), safeRecord);
19
+ atomicWriteFileSync(join(lineageDir, "SUMMARY.md"), buildSummaryMarkdown(safeRecord));
19
20
  return toSafeTaskLineage(safeRecord);
20
21
  }
21
22
  export function getTaskLineage(lineageId, options = {}) {
@@ -1,9 +1,10 @@
1
1
  import { getTaskFile } from "./getTaskFile.js";
2
- import { existsSync, readFileSync, statSync } from "node:fs";
2
+ import { existsSync, statSync } from "node:fs";
3
3
  import { join, resolve } from "node:path";
4
- import { getConfig, getTasksDir } from "../config.js";
5
- import { guardPath } from "../security/pathGuard.js";
6
- import { redactSensitiveContent } from "../security/contentRedaction.js";
4
+ import { getConfig, getTasksDir } from "../../config.js";
5
+ import { guardPath } from "../../security/pathGuard.js";
6
+ import { redactSensitiveContent } from "../../security/contentRedaction.js";
7
+ import { readTextFilePrefixSync, readTextFileTailLinesSync, } from "../../utils/boundedFile.js";
7
8
  export function getResult(taskId) {
8
9
  return getTaskFile(taskId, "result.md");
9
10
  }
@@ -20,10 +21,9 @@ export function getDiff(taskId) {
20
21
  }
21
22
  const filePath = existsSync(preferred) ? preferred : fallback;
22
23
  guardPath(filePath, config.workspaceRoot, config.tasksDir);
23
- const size = statSync(filePath).size;
24
- const raw = readFileSync(filePath, "utf-8");
25
- const patchHead = raw.slice(0, config.maxReadFileBytes);
26
- const rawReturnedBytes = Buffer.byteLength(patchHead, "utf-8");
24
+ const bounded = readTextFilePrefixSync(filePath, config.maxReadFileBytes);
25
+ const size = bounded.totalBytes;
26
+ const patchHead = bounded.content;
27
27
  const redaction = redactSensitiveContent(patchHead);
28
28
  const content = redaction.content;
29
29
  const diff = {
@@ -32,7 +32,7 @@ export function getDiff(taskId) {
32
32
  content,
33
33
  path: filePath,
34
34
  available: true,
35
- truncated: size > rawReturnedBytes,
35
+ truncated: bounded.truncated,
36
36
  total_bytes: size,
37
37
  returned_bytes: Buffer.byteLength(content, "utf-8"),
38
38
  patch_head: content,
@@ -90,8 +90,7 @@ export function getTaskLogTail(taskId, file, options) {
90
90
  }
91
91
  const stat = statSync(filePath);
92
92
  const totalBytes = stat.size;
93
- const raw = readFileSync(filePath, "utf-8");
94
- const tail = raw.split("\n").slice(-maxLines).join("\n");
93
+ const tail = readTextFileTailLinesSync(filePath, maxLines);
95
94
  const content = applyRedact ? redactSensitiveContent(tail) : { content: tail, redacted: false, redaction_categories: [] };
96
95
  return {
97
96
  task_id: taskId,
@@ -115,13 +114,15 @@ function getTaskFileTail(taskId, filename, options) {
115
114
  return getTaskFile(taskId, filename);
116
115
  }
117
116
  const stat = statSync(filePath);
118
- const raw = readFileSync(filePath, "utf-8");
119
- let content = raw;
117
+ const maxBytes = options.maxBytes > 0
118
+ ? Math.min(options.maxBytes, config.maxReadFileBytes)
119
+ : config.maxReadFileBytes;
120
+ let content;
120
121
  if (options.tailLines > 0) {
121
- content = raw.split("\n").slice(-options.tailLines).join("\n");
122
+ content = readTextFileTailLinesSync(filePath, Math.min(Math.max(1, options.tailLines), 1000), maxBytes);
122
123
  }
123
- if (options.maxBytes > 0 && Buffer.byteLength(content, "utf-8") > options.maxBytes) {
124
- content = content.slice(0, options.maxBytes);
124
+ else {
125
+ content = readTextFilePrefixSync(filePath, maxBytes).content;
125
126
  }
126
127
  const redaction = redactSensitiveContent(content);
127
128
  return {
@@ -7,9 +7,9 @@
7
7
  * and never installs global dependencies. It only runs `java -version` (read-only)
8
8
  * and inspects files/directories/env vars that already exist.
9
9
  */
10
- import { execSync } from "node:child_process";
11
10
  import { existsSync, readFileSync, statSync } from "node:fs";
12
11
  import { join } from "node:path";
12
+ import { runSimpleProcessSync } from "../../runner/simpleProcess.js";
13
13
  // ── Constants ──────────────────────────────────────────────────────
14
14
  /**
15
15
  * Required explanatory sentence emitted whenever the Android SDK is missing.
@@ -18,17 +18,23 @@ import { join } from "node:path";
18
18
  const SDK_MISSING_REASON = "Android project exists, APK not built because Android SDK is missing.";
19
19
  // ── Helpers ────────────────────────────────────────────────────────
20
20
  /**
21
- * Run a shell command and return its trimmed combined stdout/stderr output.
21
+ * Run a shell-free command and return its trimmed combined stdout/stderr output.
22
22
  * Returns an empty string when the command is missing or fails so callers can
23
23
  * treat absence gracefully. A timeout guards against hanging processes.
24
24
  */
25
- function runCmd(cmdStr) {
25
+ function runCmd(command, args, cwd = process.cwd()) {
26
26
  try {
27
- return execSync(cmdStr, {
28
- encoding: "utf-8",
29
- timeout: 8000,
30
- stdio: ["ignore", "pipe", "ignore"],
31
- }).trim();
27
+ const result = runSimpleProcessSync({
28
+ command,
29
+ args: [...args],
30
+ cwd,
31
+ timeoutMs: 8000,
32
+ maxStdoutBytes: 64 * 1024,
33
+ maxStderrBytes: 64 * 1024,
34
+ });
35
+ if (result.exitCode !== 0)
36
+ return "";
37
+ return `${result.stdout}\n${result.stderr}`.trim();
32
38
  }
33
39
  catch {
34
40
  return "";
@@ -95,8 +101,8 @@ export function diagnoseAndroidBuild(repoPath) {
95
101
  const sdkRoot = androidHomeEnv || androidSdkRootEnv;
96
102
  const sdkExists = sdkRoot !== "" && isDirectory(sdkRoot);
97
103
  // 1. java -version ------------------------------------------------------
98
- // `java -version` writes to stderr; redirect with 2>&1 so execSync captures it.
99
- const javaOutput = runCmd("java -version 2>&1");
104
+ // `java -version` normally writes to stderr; runSimpleProcessSync captures both.
105
+ const javaOutput = runCmd("java", ["-version"], repoPath);
100
106
  const javaVersion = parseJavaVersion(javaOutput);
101
107
  if (javaVersion) {
102
108
  const major = parseJavaMajor(javaVersion);
@@ -1,4 +1,4 @@
1
- import { type PatchOperation } from "../direct/directPatch.js";
1
+ import { type PatchOperation } from "../../direct/directPatch.js";
2
2
  export interface ApplyPatchInput {
3
3
  session_id: string;
4
4
  path: string;
@@ -0,0 +1,53 @@
1
+ import { getConfig } from "../../config.js";
2
+ import { PatchWardenError } from "../../errors.js";
3
+ import { readDirectSession, appendDirectSessionOperation, withDirectSessionMutationLock, } from "../../direct/directSessionStore.js";
4
+ import { guardDirectSessionActive, guardDirectWritePath, guardDirectPatchSize, } from "../../direct/directGuards.js";
5
+ import { applyPatchOperations, computeFileSha256, } from "../../direct/directPatch.js";
6
+ export function applyPatch(input) {
7
+ const config = getConfig();
8
+ return withDirectSessionMutationLock(input.session_id, () => {
9
+ // 1. Read session and guard active (not expired, not finalized)
10
+ const session = readDirectSession(input.session_id);
11
+ guardDirectSessionActive(session);
12
+ // 2. Guard write path (inside repo, not sensitive, not binary,
13
+ // not node_modules/release/dist)
14
+ const resolvedPath = guardDirectWritePath(input.path, session.resolved_repo_path, config.workspaceRoot);
15
+ // 3. Calculate patch size and guard against directMaxPatchBytes
16
+ const patchBytes = Buffer.byteLength(JSON.stringify(input.operations), "utf-8");
17
+ guardDirectPatchSize(patchBytes);
18
+ // 4. Apply against the same bytes whose hash is validated. Re-resolve the
19
+ // target immediately before replacement to detect link/reparse-point swaps.
20
+ const patchResult = applyPatchOperations(resolvedPath, input.operations, {
21
+ expectedSha256: input.expected_sha256,
22
+ maxFileBytes: config.directMaxFileBytes,
23
+ revalidatePath: () => guardDirectWritePath(input.path, session.resolved_repo_path, config.workspaceRoot),
24
+ });
25
+ const beforeSha256 = patchResult.before_sha256;
26
+ // Re-read the file from disk to compute the authoritative after_sha256
27
+ const finalPath = guardDirectWritePath(input.path, session.resolved_repo_path, config.workspaceRoot);
28
+ const afterSha256 = computeFileSha256(finalPath);
29
+ if (afterSha256 !== patchResult.after_sha256) {
30
+ throw new PatchWardenError("direct_target_changed_after_write", `Patch target "${input.path}" changed before the operation could be recorded.`, "Inspect the file and retry only after concurrent filesystem changes stop.", true, { path: input.path, expected_sha256: patchResult.after_sha256, actual_sha256: afterSha256 });
31
+ }
32
+ // 6. Append operation record to session
33
+ appendDirectSessionOperation(input.session_id, {
34
+ index: 0,
35
+ timestamp: new Date().toISOString(),
36
+ path: input.path,
37
+ operation_type: "patch",
38
+ before_sha256: beforeSha256,
39
+ after_sha256: afterSha256,
40
+ operations_applied: patchResult.operations_applied,
41
+ bytes_changed: patchResult.bytes_changed,
42
+ });
43
+ // 7. Return result
44
+ return {
45
+ path: input.path,
46
+ before_sha256: beforeSha256,
47
+ after_sha256: afterSha256,
48
+ operations_applied: patchResult.operations_applied,
49
+ bytes_changed: patchResult.bytes_changed,
50
+ next_action: "Call run_verification to test the changes, or apply_patch for more edits.",
51
+ };
52
+ }, config);
53
+ }
@@ -4,9 +4,9 @@
4
4
  *
5
5
  * 参考 src/tools/auditTask.ts 的导出/返回风格。
6
6
  */
7
- import { getConfig } from "../config.js";
8
- import { guardWorkspacePath } from "../security/pathGuard.js";
9
- import { discardWorktree } from "../goal/worktreeManager.js";
7
+ import { getConfig } from "../../config.js";
8
+ import { guardWorkspacePath } from "../../security/pathGuard.js";
9
+ import { discardWorktree } from "../../goal/worktreeManager.js";
10
10
  /**
11
11
  * 丢弃指定 worktree:移除 worktree 目录、删除临时 branch、归档状态。
12
12
  *
@@ -0,0 +1,10 @@
1
+ export * from "./androidDoctor.js";
2
+ export * from "./applyPatch.js";
3
+ export * from "./discardWorktree.js";
4
+ export * from "./listAgents.js";
5
+ export * from "./listWorkspace.js";
6
+ export * from "./mergeWorktree.js";
7
+ export * from "./readWorkspaceFile.js";
8
+ export * from "./recommendAgentForTask.js";
9
+ export * from "./searchWorkspace.js";
10
+ export * from "./syncFile.js";
@@ -0,0 +1,10 @@
1
+ export * from "./androidDoctor.js";
2
+ export * from "./applyPatch.js";
3
+ export * from "./discardWorktree.js";
4
+ export * from "./listAgents.js";
5
+ export * from "./listWorkspace.js";
6
+ export * from "./mergeWorktree.js";
7
+ export * from "./readWorkspaceFile.js";
8
+ export * from "./recommendAgentForTask.js";
9
+ export * from "./searchWorkspace.js";
10
+ export * from "./syncFile.js";
@@ -5,6 +5,11 @@ export interface AgentAvailability {
5
5
  command: string;
6
6
  reason: string | null;
7
7
  checked_at: string;
8
+ adapter: string | null;
9
+ model: string | null;
10
+ capabilities: {
11
+ model_override: boolean;
12
+ };
8
13
  }
9
14
  export declare function listAgents(): {
10
15
  agents: AgentAvailability[];
@@ -1,13 +1,14 @@
1
1
  import { existsSync, statSync } from "node:fs";
2
2
  import { basename, delimiter, extname, isAbsolute, join } from "node:path";
3
- import { getConfig } from "../config.js";
3
+ import { getConfig } from "../../config.js";
4
+ import { sanitizeTrustedPath } from "../../runner/processSecurity.js";
4
5
  export function listAgents() {
5
6
  const config = getConfig();
6
7
  const checkedAt = new Date().toISOString();
7
8
  const agents = Object.entries(config.agents)
8
9
  .sort(([left], [right]) => left.localeCompare(right))
9
10
  .map(([name, agent]) => {
10
- const available = commandExists(agent.command);
11
+ const available = commandExists(agent.command, config.workspaceRoot);
11
12
  return {
12
13
  name,
13
14
  configured: true,
@@ -15,15 +16,18 @@ export function listAgents() {
15
16
  command: basename(agent.command),
16
17
  reason: available ? null : "Configured executable was not found on disk or PATH.",
17
18
  checked_at: checkedAt,
19
+ adapter: typeof agent.adapter === "string" ? agent.adapter : ["codex", "opencode"].includes(name) ? name : null,
20
+ model: typeof agent.model === "string" ? agent.model : null,
21
+ capabilities: { model_override: typeof agent.adapter === "string" || ["codex", "opencode"].includes(name) },
18
22
  };
19
23
  });
20
24
  return { agents, total: agents.length };
21
25
  }
22
- function commandExists(command) {
26
+ function commandExists(command, workspaceRoot) {
23
27
  if (isAbsolute(command) || command.includes("/") || command.includes("\\")) {
24
28
  return isFile(command);
25
29
  }
26
- const pathEntries = (process.env.PATH || "").split(delimiter).filter(Boolean);
30
+ const pathEntries = sanitizeTrustedPath(process.env.PATH || "", workspaceRoot).split(delimiter).filter(Boolean);
27
31
  const extensions = process.platform === "win32"
28
32
  ? (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM").split(";")
29
33
  : [""];
@@ -1,8 +1,8 @@
1
1
  import { readdirSync, statSync, existsSync } from "node:fs";
2
2
  import { resolve } from "node:path";
3
- import { getConfig } from "../config.js";
4
- import { guardPath } from "../security/pathGuard.js";
5
- import { guardSensitivePath } from "../security/sensitiveGuard.js";
3
+ import { getConfig } from "../../config.js";
4
+ import { guardPath } from "../../security/pathGuard.js";
5
+ import { guardSensitivePath } from "../../security/sensitiveGuard.js";
6
6
  const MAX_LIST_FILES = 200;
7
7
  export function listWorkspace(relativePath) {
8
8
  const config = getConfig();
@@ -4,9 +4,9 @@
4
4
  *
5
5
  * 参考 src/tools/auditTask.ts 的导出/返回风格。
6
6
  */
7
- import { getConfig } from "../config.js";
8
- import { guardWorkspacePath } from "../security/pathGuard.js";
9
- import { mergeWorktree } from "../goal/worktreeManager.js";
7
+ import { getConfig } from "../../config.js";
8
+ import { guardWorkspacePath } from "../../security/pathGuard.js";
9
+ import { mergeWorktree } from "../../goal/worktreeManager.js";
10
10
  /**
11
11
  * 合并指定 worktree 的 branch 回 repo_path(主工作区)。
12
12
  *
@@ -1,13 +1,13 @@
1
1
  import { readFileSync, statSync, existsSync } from "node:fs";
2
2
  import { createHash } from "node:crypto";
3
- import { getConfig } from "../config.js";
4
- import { guardReadPath } from "../security/pathGuard.js";
5
- import { guardSensitivePath } from "../security/sensitiveGuard.js";
6
- import { redactSensitiveContent } from "../security/contentRedaction.js";
7
- import { PatchWardenError } from "../errors.js";
8
- import { readDirectSession } from "../direct/directSessionStore.js";
9
- import { guardDirectSessionActive, guardDirectReadPath, isBinaryFile, guardDirectFileSize } from "../direct/directGuards.js";
10
- import { resolveToolProfile } from "./toolCatalog.js";
3
+ import { getConfig } from "../../config.js";
4
+ import { guardReadPath } from "../../security/pathGuard.js";
5
+ import { guardSensitivePath } from "../../security/sensitiveGuard.js";
6
+ import { redactSensitiveContent } from "../../security/contentRedaction.js";
7
+ import { PatchWardenError } from "../../errors.js";
8
+ import { readDirectSession } from "../../direct/directSessionStore.js";
9
+ import { guardDirectSessionActive, guardDirectReadPath, isBinaryFile, guardDirectFileSize } from "../../direct/directGuards.js";
10
+ import { resolveToolProfile } from "../catalog/toolCatalog.js";
11
11
  export function readWorkspaceFile(input) {
12
12
  const config = getConfig();
13
13
  // Support both old string API and new object API
@@ -1,6 +1,6 @@
1
- import { getConfig } from "../config.js";
2
- import { guardWorkspacePath } from "../security/pathGuard.js";
3
- import { routeAgent } from "../agents/agentRouter.js";
1
+ import { getConfig } from "../../config.js";
2
+ import { guardWorkspacePath } from "../../security/pathGuard.js";
3
+ import { routeAgent } from "../../agents/agentRouter.js";
4
4
  export function recommendAgentForTask(input) {
5
5
  const config = getConfig();
6
6
  const repoPath = String(input.repo_path || "").trim();
@@ -1,10 +1,10 @@
1
1
  import { readdirSync, readFileSync, statSync, existsSync } from "node:fs";
2
2
  import { relative, join, extname } from "node:path";
3
- import { getConfig } from "../config.js";
4
- import { PatchWardenError } from "../errors.js";
5
- import { isSensitivePath } from "../security/sensitiveGuard.js";
6
- import { validateDirectSessionFreshness, } from "../direct/directSessionStore.js";
7
- import { guardDirectSessionActive } from "../direct/directGuards.js";
3
+ import { getConfig } from "../../config.js";
4
+ import { PatchWardenError } from "../../errors.js";
5
+ import { isSensitivePath } from "../../security/sensitiveGuard.js";
6
+ import { validateDirectSessionFreshness, } from "../../direct/directSessionStore.js";
7
+ import { guardDirectSessionActive } from "../../direct/directGuards.js";
8
8
  // ── Constants ──────────────────────────────────────────────────────
9
9
  const SKIP_DIRECTORIES = new Set([
10
10
  ".git",
@@ -1,4 +1,4 @@
1
- import { type PatchWardenConfig } from "../config.js";
1
+ import { type PatchWardenConfig } from "../../config.js";
2
2
  export interface SyncFileResult {
3
3
  source_path: string;
4
4
  target_path: string;