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
@@ -1,6 +1,7 @@
1
1
  import { resolve, join, dirname } from "node:path";
2
2
  import { fileURLToPath } from "node:url";
3
3
  import { PatchWardenError } from "../errors.js";
4
+ import { isPathChildOf, isSamePath } from "../utils/platform.js";
4
5
  const CRITICAL_RUNTIME_DIRS = ["dist", "src", "scripts", "release"];
5
6
  /**
6
7
  * Refuse operations against the active PatchWarden runtime directory or its
@@ -8,15 +9,17 @@ const CRITICAL_RUNTIME_DIRS = ["dist", "src", "scripts", "release"];
8
9
  * and direct-session flows share the same protection.
9
10
  */
10
11
  export function guardRuntimeSelfModification(resolvedRepoPath) {
11
- const runtimeRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
12
- if (resolvedRepoPath === runtimeRoot ||
13
- resolvedRepoPath.startsWith(runtimeRoot + resolve("/")[0])) {
12
+ // runtimeGuard lives at <package-root>/{src,dist}/security/runtimeGuard.*.
13
+ const runtimeRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..", "..");
14
+ const isRuntimeRoot = isSamePath(resolvedRepoPath, runtimeRoot);
15
+ if (isRuntimeRoot ||
16
+ isPathChildOf(resolvedRepoPath, runtimeRoot)) {
14
17
  const isCritical = CRITICAL_RUNTIME_DIRS.some((dir) => {
15
18
  const full = join(runtimeRoot, dir);
16
- return (resolvedRepoPath === full ||
17
- resolvedRepoPath.startsWith(full + resolve("/")[0]));
19
+ return (isSamePath(resolvedRepoPath, full) ||
20
+ isPathChildOf(resolvedRepoPath, full));
18
21
  });
19
- if (resolvedRepoPath === runtimeRoot || isCritical) {
22
+ if (isRuntimeRoot || isCritical) {
20
23
  throw new PatchWardenError("runtime_self_modification_blocked", `repo_path points to the active PatchWarden runtime or its critical subdirectories.`, "Use a dev copy or git worktree for PatchWarden development. The running MCP server must not be modified by a task.", true, {
21
24
  operation: "runtime_guard",
22
25
  path: resolvedRepoPath,
@@ -0,0 +1,3 @@
1
+ /** Compare secret text without content-dependent byte comparison. */
2
+ export declare function timingSafeStringEqual(actual: string, expected: string): boolean;
3
+ export declare function firstHeaderValue(value: string | string[] | undefined): string;
@@ -0,0 +1,11 @@
1
+ import { timingSafeEqual } from "node:crypto";
2
+ /** Compare secret text without content-dependent byte comparison. */
3
+ export function timingSafeStringEqual(actual, expected) {
4
+ const actualBytes = Buffer.from(actual, "utf-8");
5
+ const expectedBytes = Buffer.from(expected, "utf-8");
6
+ return actualBytes.length === expectedBytes.length
7
+ && timingSafeEqual(actualBytes, expectedBytes);
8
+ }
9
+ export function firstHeaderValue(value) {
10
+ return Array.isArray(value) ? (value[0] || "") : (value || "");
11
+ }
@@ -1,2 +1,7 @@
1
+ /**
2
+ * Detect a Windows NTFS alternate data stream suffix. The colon in an
3
+ * absolute drive prefix (for example, C:\\) is the only permitted colon.
4
+ */
5
+ export declare function hasWindowsAlternateDataStream(filePath: string): boolean;
1
6
  export declare function isSensitivePath(filePath: string): boolean;
2
7
  export declare function guardSensitivePath(filePath: string): void;
@@ -7,22 +7,28 @@ const SENSITIVE_PATTERNS = [
7
7
  // Exact filenames
8
8
  /(?:^|[\\/])\.env$/i,
9
9
  /(?:^|[\\/])\.env\..+$/i,
10
+ /(?:^|[\\/])\.envrc$/i,
10
11
  /(?:^|[\\/])id_rsa$/i,
12
+ /(?:^|[\\/])id_dsa$/i,
11
13
  /(?:^|[\\/])id_ed25519$/i,
12
14
  /(?:^|[\\/])id_ecdsa$/i,
13
15
  /(?:^|[\\/])\.ssh[\\/]/i,
14
16
  // Credentials / tokens
15
- /(?:^|[\\/])credentials/i,
17
+ /(?:^|[\\/])credentials(?:\.(?:txt|json|ya?ml|toml|ini|cfg|db))?$/i,
16
18
  /(?:^|[\\/])\.?aws[\\/]credentials/i,
17
19
  /(?:^|[\\/])\.netrc$/i,
18
20
  /(?:^|[\\/])\.npmrc$/i,
19
21
  /(?:^|[\\/])\.pypirc$/i,
20
- /(?:^|[\\/])token/i,
22
+ /(?:^|[\\/])token$/i,
23
+ /(?:^|[\\/])tokens?\.(?:txt|json|ya?ml|toml|ini|cfg|db)$/i,
24
+ /(?:^|[\\/])token[-_](?:store|cache|data|secret|auth|credentials|backup|local|prod|production|dev|development)(?:\.[^\\/]+)?$/i,
25
+ /(?:^|[\\/])(?:access[_-]?token|refresh[_-]?token|api[_-]?key|client[_-]?secret)(?:\.(?:txt|json|ya?ml|ini|cfg))?$/i,
21
26
  // Private keys
22
27
  /(?:^|[\\/])[^.]+\.pem$/i,
23
28
  /(?:^|[\\/])[^.]+\.key$/i,
24
29
  /(?:^|[\\/])[^.]+\.pfx$/i,
25
30
  /(?:^|[\\/])[^.]+\.p12$/i,
31
+ /(?:^|[\\/])[^.]+\.ppk$/i,
26
32
  // Browser data
27
33
  /(?:^|[\\/])cookies/i,
28
34
  /(?:^|[\\/])web data$/i,
@@ -30,17 +36,30 @@ const SENSITIVE_PATTERNS = [
30
36
  /(?:^|[\\/])local state$/i,
31
37
  // Other sensitive files
32
38
  /(?:^|[\\/])\.git-credentials$/i,
39
+ /(?:^|[\\/])\.git[\\/]config$/i,
33
40
  /(?:^|[\\/])\.docker[\\/]config\.json$/i,
34
41
  /(?:^|[\\/])\.kube[\\/]config$/i,
42
+ /(?:^|[\\/])kubeconfig$/i,
43
+ /(?:^|[\\/])application_default_credentials\.json$/i,
44
+ /(?:^|[\\/])service[-_]?account(?:[-_][^\\/]+)?\.json$/i,
35
45
  /(?:^|[\\/])config\.json$/i, // generic config files often contain local tokens or service credentials
36
46
  ];
37
- // Files specifically inside .patchwarden are always allowed
38
- const SAFE_PREFIX = ".patchwarden";
47
+ /**
48
+ * Detect a Windows NTFS alternate data stream suffix. The colon in an
49
+ * absolute drive prefix (for example, C:\\) is the only permitted colon.
50
+ */
51
+ export function hasWindowsAlternateDataStream(filePath) {
52
+ const withoutDrivePrefix = /^[A-Za-z]:[\\/]/.test(filePath)
53
+ ? filePath.slice(2)
54
+ : filePath;
55
+ return withoutDrivePrefix.includes(":");
56
+ }
39
57
  export function isSensitivePath(filePath) {
40
- // Files inside .patchwarden are always safe
41
- const normalized = filePath.replace(/\\/g, "/");
42
- if (normalized.includes(`${SAFE_PREFIX}/`) || normalized.endsWith(SAFE_PREFIX)) {
43
- return false;
58
+ if (filePath.includes("\0"))
59
+ return true;
60
+ // ADS can hide content behind an otherwise safe-looking filename.
61
+ if (hasWindowsAlternateDataStream(filePath)) {
62
+ return true;
44
63
  }
45
64
  for (const pattern of SENSITIVE_PATTERNS) {
46
65
  if (pattern.test(filePath)) {
@@ -14,8 +14,8 @@
14
14
  *
15
15
  * 加上 consumeToken 内的 token_not_found / token_expired,共 10 项调用前强制校验。
16
16
  */
17
- import { type PatchWardenToolMeta } from "../tools/toolRegistry.js";
18
- import type { ToolProfile } from "../tools/toolCatalog.js";
17
+ import { type PatchWardenToolMeta } from "../tools/catalog/toolRegistry.js";
18
+ import type { ToolProfile } from "../tools/catalog/toolCatalog.js";
19
19
  import type { DiscoveryTokenRecord } from "./discoveryTokenStore.js";
20
20
  export interface GuardInput {
21
21
  toolName: string;
@@ -16,7 +16,7 @@
16
16
  */
17
17
  import { PatchWardenError } from "../errors.js";
18
18
  import { guardSensitivePath } from "./sensitiveGuard.js";
19
- import { TOOL_RISK_RANK } from "../tools/toolRegistry.js";
19
+ import { TOOL_RISK_RANK } from "../tools/catalog/toolRegistry.js";
20
20
  // ── 内部常量 ──────────────────────────────────────────────────────
21
21
  /**
22
22
  * 常见路径参数字段名,用于 workspace_read_sensitive 校验时扫描 args。
@@ -0,0 +1,8 @@
1
+ export interface WorkspaceRootValidation {
2
+ ok: boolean;
3
+ path: string;
4
+ reason: string | null;
5
+ category: "valid" | "missing" | "not_directory" | "unsafe_root";
6
+ }
7
+ export declare function unsafeWorkspaceRootLabel(value: string, userHome?: string): string | null;
8
+ export declare function validateWorkspaceRoot(value: string, userHome?: string): WorkspaceRootValidation;
@@ -0,0 +1,47 @@
1
+ import { existsSync, realpathSync, statSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { basename, normalize, resolve, win32 } from "node:path";
4
+ function normalizeInput(value) {
5
+ return /^[a-z]:[\\/]/i.test(value) ? win32.normalize(value) : normalize(resolve(value));
6
+ }
7
+ function comparable(value) {
8
+ return normalizeInput(value).replace(/[\\/]+$/, "").toLowerCase();
9
+ }
10
+ export function unsafeWorkspaceRootLabel(value, userHome = homedir()) {
11
+ const resolved = normalizeInput(value);
12
+ const trimmed = resolved.replace(/[\\/]+$/, "");
13
+ const windowsStyle = /^[a-z]:[\\/]/i.test(value) || /^\\\\/.test(value);
14
+ const leaf = (windowsStyle ? win32.basename(trimmed) : basename(trimmed)).toLowerCase();
15
+ if (/^[a-z]:$/i.test(trimmed) || trimmed === "" || trimmed === "/")
16
+ return "drive root";
17
+ if (comparable(trimmed) === comparable(userHome))
18
+ return "user home directory";
19
+ if (leaf === "desktop")
20
+ return "Desktop";
21
+ if (leaf === "downloads")
22
+ return "Downloads";
23
+ if (leaf === "documents")
24
+ return "Documents";
25
+ return null;
26
+ }
27
+ export function validateWorkspaceRoot(value, userHome = homedir()) {
28
+ const lexicalPath = normalize(resolve(value || "."));
29
+ if (!existsSync(lexicalPath)) {
30
+ return { ok: false, path: lexicalPath, reason: "workspaceRoot does not exist", category: "missing" };
31
+ }
32
+ let resolved;
33
+ try {
34
+ resolved = normalize(realpathSync(lexicalPath));
35
+ if (!statSync(resolved).isDirectory()) {
36
+ return { ok: false, path: resolved, reason: "workspaceRoot is not a directory", category: "not_directory" };
37
+ }
38
+ }
39
+ catch {
40
+ return { ok: false, path: lexicalPath, reason: "workspaceRoot is not accessible", category: "not_directory" };
41
+ }
42
+ const unsafeLabel = unsafeWorkspaceRootLabel(resolved, userHome);
43
+ if (unsafeLabel) {
44
+ return { ok: false, path: resolved, reason: `workspaceRoot cannot be ${unsafeLabel}`, category: "unsafe_root" };
45
+ }
46
+ return { ok: true, path: resolved, reason: null, category: "valid" };
47
+ }
@@ -18,32 +18,32 @@ import { tmpdir } from "node:os";
18
18
  import { fileURLToPath } from "node:url";
19
19
  import { spawnSync } from "node:child_process";
20
20
  import { loadConfig, getConfig, getTasksDir, reloadConfig } from "./config.js";
21
- import { savePlan } from "./tools/savePlan.js";
22
- import { getPlan } from "./tools/getPlan.js";
23
- import { createTask } from "./tools/createTask.js";
21
+ import { savePlan } from "./tools/goals/savePlan.js";
22
+ import { getPlan } from "./tools/goals/getPlan.js";
23
+ import { createTask } from "./tools/tasks/createTask.js";
24
24
  import { confirmAssessment, readAssessment, createAssessment } from "./assessments/assessmentStore.js";
25
25
  import { captureRepoSnapshot } from "./runner/changeCapture.js";
26
- import { getTaskStatus } from "./tools/getTaskStatus.js";
27
- import { getResult, getDiff, getTestLog } from "./tools/taskOutputs.js";
28
- import { listWorkspace } from "./tools/listWorkspace.js";
29
- import { readWorkspaceFile } from "./tools/readWorkspaceFile.js";
30
- import { listTasks } from "./tools/listTasks.js";
31
- import { cancelTask } from "./tools/cancelTask.js";
32
- import { retryTask } from "./tools/retryTask.js";
33
- import { getTaskStdoutTail } from "./tools/getTaskStdoutTail.js";
34
- import { auditTask } from "./tools/auditTask.js";
35
- import { getTaskSummary } from "./tools/getTaskSummary.js";
26
+ import { getTaskStatus } from "./tools/tasks/getTaskStatus.js";
27
+ import { getResult, getDiff, getTestLog } from "./tools/tasks/taskOutputs.js";
28
+ import { listWorkspace } from "./tools/workspace/listWorkspace.js";
29
+ import { readWorkspaceFile } from "./tools/workspace/readWorkspaceFile.js";
30
+ import { listTasks } from "./tools/tasks/listTasks.js";
31
+ import { cancelTask } from "./tools/tasks/cancelTask.js";
32
+ import { retryTask } from "./tools/tasks/retryTask.js";
33
+ import { getTaskStdoutTail } from "./tools/tasks/getTaskStdoutTail.js";
34
+ import { auditTask } from "./tools/diagnostics/auditTask.js";
35
+ import { getTaskSummary } from "./tools/tasks/getTaskSummary.js";
36
36
  import { guardAgentCommand } from "./security/commandGuard.js";
37
37
  import { getToolDefs } from "./tools/registry.js";
38
- import { buildToolCatalogSnapshot, CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES, selectToolsForProfile, } from "./tools/toolCatalog.js";
38
+ import { buildToolCatalogSnapshot, CHATGPT_CORE_TOOL_NAMES, CHATGPT_DIRECT_TOOL_NAMES, selectToolsForProfile, } from "./tools/catalog/toolCatalog.js";
39
39
  import { errorPayload } from "./errors.js";
40
40
  import { readWatcherStatus } from "./watcherStatus.js";
41
- import { createDirectSession } from "./tools/createDirectSession.js";
42
- import { searchWorkspace } from "./tools/searchWorkspace.js";
43
- import { applyPatch } from "./tools/applyPatch.js";
44
- import { runVerification } from "./tools/runVerification.js";
45
- import { finalizeDirectSession } from "./tools/finalizeDirectSession.js";
46
- import { auditSession } from "./tools/auditSession.js";
41
+ import { createDirectSession } from "./tools/direct/createDirectSession.js";
42
+ import { searchWorkspace } from "./tools/workspace/searchWorkspace.js";
43
+ import { applyPatch } from "./tools/workspace/applyPatch.js";
44
+ import { runVerification } from "./tools/tasks/runVerification.js";
45
+ import { finalizeDirectSession } from "./tools/direct/finalizeDirectSession.js";
46
+ import { auditSession } from "./tools/diagnostics/auditSession.js";
47
47
  import { readDirectSession, updateDirectSession } from "./direct/directSessionStore.js";
48
48
  import { createHash } from "node:crypto";
49
49
  // Resolve the actual node binary path (spawnSync needs it on WSL/Windows)
@@ -418,15 +418,16 @@ const sensitiveFiles = [
418
418
  "cookies.sqlite",
419
419
  ".git-credentials",
420
420
  "config.json",
421
+ ".patchwarden/.env",
422
+ ".patchwarden/credentials.json",
421
423
  ];
422
424
  for (const sf of sensitiveFiles) {
423
425
  await testReject(`C. readWorkspaceFile blocks "${sf}"`, () => {
424
426
  readWorkspaceFile(sf);
425
427
  });
426
428
  }
427
- // Files inside .patchwarden should always be allowed
428
- await test("C. readWorkspaceFile allows .patchwarden/plans/...", () => {
429
- // This should work because .patchwarden files are whitelisted
429
+ // Ordinary PatchWarden artifacts remain readable through their dedicated tool.
430
+ await test("C. getPlan reads ordinary .patchwarden/plans artifacts", () => {
430
431
  const plan = savePlan({ title: "Allowlist Test", content: "test" });
431
432
  const result = getPlan({ plan_id: plan.plan_id });
432
433
  if (!result.content.includes("test"))
@@ -1268,7 +1269,7 @@ await test("K8. assessment not found rejected", async () => {
1268
1269
  agent: "codex",
1269
1270
  repo_path: ".",
1270
1271
  execution_mode: "execute",
1271
- assessment_id: "assessment_20260101_" + "0".repeat(32),
1272
+ assessment_id: "assessment_20260101_000000_" + "0".repeat(32),
1272
1273
  });
1273
1274
  throw new Error("Should have rejected unknown assessment");
1274
1275
  }
@@ -1508,8 +1509,8 @@ await test("K16. assessment_short_id cannot execute", async () => {
1508
1509
  throw new Error("Should have rejected short ID");
1509
1510
  }
1510
1511
  catch (e) {
1511
- if (!e.message?.includes("not found"))
1512
- throw new Error(`Expected not found for short ID, got: ${e.message}`);
1512
+ if (e.reason !== "assessment_id_invalid")
1513
+ throw new Error(`Expected assessment_id_invalid for short ID, got: ${e.reason || e.message}`);
1513
1514
  }
1514
1515
  });
1515
1516
  await test("K17. blocked assessment cannot execute", async () => {
@@ -0,0 +1,4 @@
1
+ export * from "./toolCatalog.js";
2
+ export * from "./toolRegistry.js";
3
+ export * from "./toolSearch.js";
4
+ export * from "./toolUsageStats.js";
@@ -0,0 +1,4 @@
1
+ export * from "./toolCatalog.js";
2
+ export * from "./toolRegistry.js";
3
+ export * from "./toolSearch.js";
4
+ export * from "./toolUsageStats.js";
@@ -1,5 +1,6 @@
1
1
  import { createHash } from "node:crypto";
2
- import { PATCHWARDEN_VERSION, TOOL_SCHEMA_EPOCH } from "../version.js";
2
+ import { PATCHWARDEN_VERSION, TOOL_SCHEMA_EPOCH } from "../../version.js";
3
+ import { stableJsonStringify } from "../../utils/stableJson.js";
3
4
  export const CHATGPT_CORE_TOOL_NAMES = [
4
5
  "health_check",
5
6
  "list_agents",
@@ -101,7 +102,7 @@ export function buildToolCatalogSnapshot(tools, profile) {
101
102
  inputSchema: tool.inputSchema,
102
103
  }));
103
104
  const tool_manifest_sha256 = createHash("sha256")
104
- .update(stableJson(manifestInput))
105
+ .update(stableJsonStringify(manifestInput))
105
106
  .digest("hex");
106
107
  lastSnapshot = {
107
108
  server_version: PATCHWARDEN_VERSION,
@@ -116,13 +117,3 @@ export function buildToolCatalogSnapshot(tools, profile) {
116
117
  export function getLastToolCatalogSnapshot() {
117
118
  return lastSnapshot ? { ...lastSnapshot, tool_names: [...lastSnapshot.tool_names] } : null;
118
119
  }
119
- function stableJson(value) {
120
- if (Array.isArray(value))
121
- return `[${value.map(stableJson).join(",")}]`;
122
- if (value && typeof value === "object") {
123
- const entries = Object.entries(value)
124
- .sort(([left], [right]) => left.localeCompare(right));
125
- return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableJson(entry)}`).join(",")}}`;
126
- }
127
- return JSON.stringify(value);
128
- }
@@ -5,8 +5,9 @@
5
5
  * schema digest 使用稳定字段顺序的 canonical JSON → sha256 计算,
6
6
  * 用于检测工具 schema 漂移、release check 校验、discover_tools 返回。
7
7
  */
8
+ import { stableJsonStringify } from "../../utils/stableJson.js";
8
9
  import type { ToolProfile } from "./toolCatalog.js";
9
- import type { ToolDef } from "./registry.js";
10
+ import type { ToolDef } from "../definitions/toolDefs.js";
10
11
  export type ToolRisk = "readonly" | "workspace_read_sensitive" | "workspace_write" | "command" | "release" | "credential_sensitive";
11
12
  export declare const TOOL_RISK_RANK: Record<ToolRisk, number>;
12
13
  export type ToolMode = "delegate" | "direct" | "audit" | "release" | "diagnostic";
@@ -42,7 +43,7 @@ interface StaticToolMeta {
42
43
  /**
43
44
  * 稳定 JSON 序列化:按字段名排序,避免 key 顺序导致 digest 漂移。
44
45
  */
45
- export declare function stableJsonStringify(value: unknown): string;
46
+ export { stableJsonStringify };
46
47
  /**
47
48
  * 计算 inputSchema 的 sha256 digest。
48
49
  * 返回格式:"sha256:<hex>"
@@ -58,4 +59,3 @@ export declare function buildToolRegistry(tools: ToolDef[]): PatchWardenToolMeta
58
59
  * 获取单个工具的元数据(不含 schema digest,digest 需从 registry 获取)。
59
60
  */
60
61
  export declare function getStaticToolMeta(name: string): StaticToolMeta | undefined;
61
- export {};
@@ -6,6 +6,7 @@
6
6
  * 用于检测工具 schema 漂移、release check 校验、discover_tools 返回。
7
7
  */
8
8
  import { createHash } from "node:crypto";
9
+ import { stableJsonStringify } from "../../utils/stableJson.js";
9
10
  export const TOOL_RISK_RANK = {
10
11
  readonly: 0,
11
12
  workspace_read_sensitive: 1,
@@ -56,7 +57,7 @@ const STATIC_TOOL_META = {
56
57
  summary: "列出已配置的本地 agent 及其可用性",
57
58
  profiles: ["full", "chatgpt_core"],
58
59
  modes: ["delegate", "diagnostic"],
59
- tags: ["agent", "list", "config", "codex", "opencode"],
60
+ tags: ["agent", "list", "config", "local-cli", "model"],
60
61
  aliases: ["agents", "list_agent"],
61
62
  risk: "readonly",
62
63
  requiresConfirmation: false,
@@ -201,7 +202,7 @@ const STATIC_TOOL_META = {
201
202
  modes: ["delegate", "audit"],
202
203
  tags: ["safe", "audit", "checks", "acceptance", "task"],
203
204
  aliases: ["safe_audit", "audit_summary"],
204
- risk: "readonly",
205
+ risk: "workspace_write",
205
206
  requiresConfirmation: false,
206
207
  relatedTools: ["audit_task", "safe_result"],
207
208
  },
@@ -545,7 +546,7 @@ const STATIC_TOOL_META = {
545
546
  modes: ["direct", "audit"],
546
547
  tags: ["safe", "direct", "finalize", "summary"],
547
548
  aliases: ["safe_finalize", "finalize_summary"],
548
- risk: "readonly",
549
+ risk: "workspace_write",
549
550
  requiresConfirmation: false,
550
551
  relatedTools: ["finalize_direct_session", "safe_direct_summary"],
551
552
  },
@@ -556,7 +557,7 @@ const STATIC_TOOL_META = {
556
557
  modes: ["direct", "audit"],
557
558
  tags: ["safe", "direct", "audit", "session"],
558
559
  aliases: ["safe_direct_audit", "audit_direct_summary"],
559
- risk: "readonly",
560
+ risk: "workspace_write",
560
561
  requiresConfirmation: false,
561
562
  relatedTools: ["audit_session", "safe_finalize_direct_session"],
562
563
  },
@@ -798,17 +799,7 @@ const STATIC_TOOL_META = {
798
799
  /**
799
800
  * 稳定 JSON 序列化:按字段名排序,避免 key 顺序导致 digest 漂移。
800
801
  */
801
- export function stableJsonStringify(value) {
802
- if (Array.isArray(value)) {
803
- return `[${value.map(stableJsonStringify).join(",")}]`;
804
- }
805
- if (value !== null && typeof value === "object") {
806
- const entries = Object.entries(value)
807
- .sort(([left], [right]) => left.localeCompare(right));
808
- return `{${entries.map(([key, entry]) => `${JSON.stringify(key)}:${stableJsonStringify(entry)}`).join(",")}}`;
809
- }
810
- return JSON.stringify(value);
811
- }
802
+ export { stableJsonStringify };
812
803
  /**
813
804
  * 计算 inputSchema 的 sha256 digest。
814
805
  * 返回格式:"sha256:<hex>"
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Tool definitions for PatchWarden MCP server.
3
+ *
4
+ * Extracted from registry.ts to keep the registry focused on dispatch
5
+ * wiring. getToolDefs() builds the active tool list based on config
6
+ * (test/direct allow-lists, agent names, profile selection) and refreshes
7
+ * the tool catalog snapshot as a side effect.
8
+ */
9
+ export interface ToolDef {
10
+ name: string;
11
+ description: string;
12
+ inputSchema: {
13
+ type: "object";
14
+ properties: Record<string, unknown>;
15
+ required?: string[];
16
+ };
17
+ }
18
+ export declare function getToolDefs(): ToolDef[];