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,184 +0,0 @@
1
- import { describe, it, beforeEach, afterEach } from "node:test";
2
- import { strict as assert } from "node:assert";
3
- import { mkdtempSync, rmSync, mkdirSync, writeFileSync } from "node:fs";
4
- import { join } from "node:path";
5
- import { tmpdir } from "node:os";
6
- import { reloadConfig } from "../../config.js";
7
- import { safeDirectSummary, safeAuditDirectSession, safeDiffSummary, safeResult, safeTestSummary } from "../../tools/safeViews.js";
8
-
9
- let tempDir: string;
10
- let prevConfigEnv: string | undefined;
11
-
12
- function writeConfig() {
13
- const configPath = join(tempDir, "patchwarden.config.json");
14
- writeFileSync(
15
- configPath,
16
- JSON.stringify({
17
- workspaceRoot: tempDir,
18
- tasksDir: ".patchwarden/tasks",
19
- plansDir: ".patchwarden/plans",
20
- assessmentsDir: ".patchwarden/assessments",
21
- directSessionsDir: ".patchwarden/direct-sessions",
22
- agents: {},
23
- allowedTestCommands: ["npm test"],
24
- directAllowedCommands: ["npm test"],
25
- enableDirectProfile: true,
26
- }),
27
- "utf-8"
28
- );
29
- prevConfigEnv = process.env.PATCHWARDEN_CONFIG;
30
- process.env.PATCHWARDEN_CONFIG = configPath;
31
- reloadConfig();
32
- }
33
-
34
- describe("safeViews", () => {
35
- beforeEach(() => {
36
- tempDir = mkdtempSync(join(tmpdir(), "pw-safeviews-"));
37
- writeConfig();
38
- });
39
-
40
- afterEach(() => {
41
- if (prevConfigEnv === undefined) delete process.env.PATCHWARDEN_CONFIG;
42
- else process.env.PATCHWARDEN_CONFIG = prevConfigEnv;
43
- reloadConfig();
44
- rmSync(tempDir, { recursive: true, force: true });
45
- });
46
-
47
- it("returns bounded task summaries without log or diff content", () => {
48
- const taskId = "task-safe-001";
49
- const taskDir = join(tempDir, ".patchwarden", "tasks", taskId);
50
- mkdirSync(taskDir, { recursive: true });
51
- writeFileSync(join(taskDir, "status.json"), JSON.stringify({
52
- task_id: taskId,
53
- status: "done_by_agent",
54
- phase: "done_by_agent",
55
- repo_path: "repo",
56
- resolved_repo_path: join(tempDir, "repo"),
57
- verify_status: "passed",
58
- }), "utf-8");
59
- writeFileSync(join(taskDir, "result.json"), JSON.stringify({
60
- task_id: taskId,
61
- status: "done_by_agent",
62
- summary: "Finished safely",
63
- changed_files: [{ path: "src/index.ts", change: "modified" }],
64
- verify_status: "passed",
65
- warnings: [],
66
- }), "utf-8");
67
- writeFileSync(join(taskDir, "verify.json"), JSON.stringify({
68
- status: "passed",
69
- commands: [{ command: "npm test", status: "passed", exit_code: 0, stdout_tail: "SECRET_STDOUT", stderr_tail: "SECRET_STDERR" }],
70
- }), "utf-8");
71
- writeFileSync(join(taskDir, "changed-files.json"), JSON.stringify({
72
- changed_files: [{ path: "src/index.ts", change: "modified", tracked: true, ignored: false, kind: "source" }],
73
- additions: 1,
74
- deletions: 0,
75
- diff_available: true,
76
- diff_truncated: false,
77
- patch_mode: "textual",
78
- artifact_hygiene: { counts: { source_changes: 1 }, source_changes: [], tracked_build_artifacts: [], ignored_untracked_artifacts: [], runtime_generated_files: [], suspicious_changes: [] },
79
- }), "utf-8");
80
- writeFileSync(join(taskDir, "git.diff"), "SECRET_DIFF", "utf-8");
81
- writeFileSync(join(taskDir, "test.log"), "SECRET_TEST_LOG", "utf-8");
82
-
83
- const payload = JSON.stringify({
84
- result: safeResult(taskId),
85
- tests: safeTestSummary(taskId),
86
- diff: safeDiffSummary(taskId),
87
- });
88
- assert.ok(!payload.includes("SECRET_STDOUT"));
89
- assert.ok(!payload.includes("SECRET_STDERR"));
90
- assert.ok(!payload.includes("SECRET_DIFF"));
91
- assert.ok(!payload.includes("SECRET_TEST_LOG"));
92
- assert.ok(payload.includes("src/index.ts"));
93
- });
94
-
95
- it("treats corrupted safe-view JSON artifacts as empty summaries", () => {
96
- const taskId = "task-safe-corrupt";
97
- const taskDir = join(tempDir, ".patchwarden", "tasks", taskId);
98
- mkdirSync(taskDir, { recursive: true });
99
- writeFileSync(join(taskDir, "status.json"), JSON.stringify({
100
- task_id: taskId,
101
- status: "done_by_agent",
102
- phase: "done_by_agent",
103
- repo_path: "repo",
104
- resolved_repo_path: join(tempDir, "repo"),
105
- verify_status: "passed",
106
- }), "utf-8");
107
- writeFileSync(join(taskDir, "result.json"), JSON.stringify({
108
- task_id: taskId,
109
- status: "done_by_agent",
110
- summary: "Finished safely",
111
- changed_files: [],
112
- verify_status: "passed",
113
- warnings: [],
114
- }), "utf-8");
115
- writeFileSync(join(taskDir, "verify.json"), "\uFEFF{not json", "utf-8");
116
- writeFileSync(join(taskDir, "changed-files.json"), "{not json", "utf-8");
117
-
118
- const tests = safeTestSummary(taskId);
119
- const diff = safeDiffSummary(taskId);
120
-
121
- assert.equal(tests.command_count, 0);
122
- assert.equal(diff.changed_files_total, 0);
123
- });
124
-
125
- it("returns Direct safe summaries without verification tails", () => {
126
- const sessionId = "direct-safe-001";
127
- const sessionDir = join(tempDir, ".patchwarden", "direct-sessions", sessionId);
128
- mkdirSync(sessionDir, { recursive: true });
129
- const session = {
130
- session_id: sessionId,
131
- title: "safe direct",
132
- repo_path: "repo",
133
- resolved_repo_path: join(tempDir, "repo"),
134
- created_at: new Date().toISOString(),
135
- expires_at: new Date(Date.now() + 60_000).toISOString(),
136
- server_version: "1.0.0",
137
- schema_epoch: "test",
138
- tool_manifest_sha256: "x".repeat(64),
139
- workspace_snapshot_before: { head: null, status: "", files: {}, workspace_dirty: false, warnings: [], is_git: false },
140
- workspace_fingerprint_before: "fingerprint",
141
- allowed_commands: ["npm test"],
142
- operations: [],
143
- verification_runs: [{
144
- command: "npm test",
145
- exit_code: 0,
146
- passed: true,
147
- timed_out: false,
148
- stdout_tail: "SECRET_DIRECT_STDOUT",
149
- stderr_tail: "SECRET_DIRECT_STDERR",
150
- started_at: new Date().toISOString(),
151
- finished_at: new Date().toISOString(),
152
- log_path: join(sessionDir, "verification.log"),
153
- }],
154
- finalized: true,
155
- finalized_at: new Date().toISOString(),
156
- audited: false,
157
- change_artifacts: {
158
- changed_files: [],
159
- diff: "SECRET_DIRECT_DIFF",
160
- diff_available: true,
161
- diff_truncated: false,
162
- diff_size_bytes: 18,
163
- additions: 0,
164
- deletions: 0,
165
- file_stats: [],
166
- workspace_dirty_before: false,
167
- workspace_dirty_after: false,
168
- patch_mode: "no_changes",
169
- unavailable_reason: null,
170
- artifact_hygiene: { counts: { source_changes: 0, tracked_build_artifacts: 0, ignored_untracked_artifacts: 0, runtime_generated_files: 0, suspicious_changes: 0 }, source_changes: [], tracked_build_artifacts: [], ignored_untracked_artifacts: [], runtime_generated_files: [], suspicious_changes: [] },
171
- },
172
- };
173
- writeFileSync(join(sessionDir, "session.json"), JSON.stringify(session, null, 2), "utf-8");
174
-
175
- const payload = JSON.stringify({
176
- summary: safeDirectSummary(sessionId),
177
- audit: safeAuditDirectSession(sessionId),
178
- });
179
- assert.ok(!payload.includes("SECRET_DIRECT_STDOUT"));
180
- assert.ok(!payload.includes("SECRET_DIRECT_STDERR"));
181
- assert.ok(!payload.includes("SECRET_DIRECT_DIFF"));
182
- assert.ok(payload.includes("npm test"));
183
- });
184
- });
@@ -1,260 +0,0 @@
1
- import { describe, it } from "node:test";
2
- import { strict as assert } from "node:assert";
3
- import { computeSchemaDigest } from "../../tools/toolRegistry.js";
4
- import type {
5
- PatchWardenToolMeta,
6
- ToolMode,
7
- ToolRisk,
8
- } from "../../tools/toolRegistry.js";
9
- import type { ToolProfile } from "../../tools/toolCatalog.js";
10
- import { CHATGPT_CORE_TOOL_NAMES } from "../../tools/toolCatalog.js";
11
- import {
12
- checkRegistrySchemaDigest,
13
- checkChatgptCoreManifestStable,
14
- checkNewToolsProfileAppend,
15
- runAllSchemaDriftChecks,
16
- type ToolDefLike,
17
- } from "../../tools/schemaDriftCheck.js";
18
-
19
- // ── 测试夹具构造工具 ─────────────────────────────────────────────
20
-
21
- const SAMPLE_SCHEMA = {
22
- type: "object" as const,
23
- properties: {
24
- task_id: { type: "string", description: "Task ID" },
25
- },
26
- required: ["task_id"],
27
- };
28
-
29
- const OTHER_SCHEMA = {
30
- type: "object" as const,
31
- properties: {
32
- plan_id: { type: "string", description: "Plan ID" },
33
- },
34
- required: ["plan_id"],
35
- };
36
-
37
- const CORE_COUNT = CHATGPT_CORE_TOOL_NAMES.length;
38
-
39
- interface MakeMetaOpts {
40
- name: string;
41
- inputSchema?: unknown;
42
- inputSchemaDigest?: string;
43
- profiles?: ToolProfile[];
44
- }
45
-
46
- /** 构造一个满足 PatchWardenToolMeta 接口的元数据对象。 */
47
- function makeMeta(opts: MakeMetaOpts): PatchWardenToolMeta {
48
- const schema = opts.inputSchema ?? SAMPLE_SCHEMA;
49
- return {
50
- name: opts.name,
51
- title: `Tool ${opts.name}`,
52
- summary: `summary for ${opts.name}`,
53
- description: `description for ${opts.name}`,
54
- profiles: opts.profiles ?? ["full"],
55
- modes: ["diagnostic"] as ToolMode[],
56
- tags: [],
57
- aliases: [],
58
- risk: "readonly" as ToolRisk,
59
- requiresConfirmation: false,
60
- inputSchemaDigest: opts.inputSchemaDigest ?? computeSchemaDigest(schema),
61
- };
62
- }
63
-
64
- /** 构造 toolDefs Map。 */
65
- function makeToolDefs(
66
- entries: Array<{ name: string; inputSchema?: unknown }>,
67
- ): Map<string, ToolDefLike> {
68
- const map = new Map<string, ToolDefLike>();
69
- for (const e of entries) {
70
- map.set(e.name, {
71
- inputSchema: e.inputSchema ?? SAMPLE_SCHEMA,
72
- });
73
- }
74
- return map;
75
- }
76
-
77
- /** 构造包含全部 21 个 chatgpt_core 工具(顺序一致)的 toolDefs Map。 */
78
- function makeCoreToolDefs(): Map<string, ToolDefLike> {
79
- return makeToolDefs(
80
- [...CHATGPT_CORE_TOOL_NAMES].map((name) => ({ name })),
81
- );
82
- }
83
-
84
- /** 构造一个 registry:所有工具都属于 chatgpt_core profile。 */
85
- function makeCoreRegistry(count: number): PatchWardenToolMeta[] {
86
- const names = [...CHATGPT_CORE_TOOL_NAMES].slice(0, count);
87
- return names.map((name) => makeMeta({ name, profiles: ["chatgpt_core"] }));
88
- }
89
-
90
- // ── 1. checkRegistrySchemaDigest ─────────────────────────────────
91
-
92
- describe("checkRegistrySchemaDigest", () => {
93
- it("digest 一致时 ok=true,warnings 为空", () => {
94
- const schema = { type: "object", properties: { a: { type: "string" } } };
95
- const registry = [makeMeta({ name: "tool_a", inputSchema: schema })];
96
- const toolDefs = makeToolDefs([{ name: "tool_a", inputSchema: schema }]);
97
-
98
- const result = checkRegistrySchemaDigest(registry, toolDefs);
99
-
100
- assert.equal(result.ok, true);
101
- assert.deepEqual(result.warnings, []);
102
- });
103
-
104
- it("digest 不一致时 ok=false,warnings 包含工具名和两个 digest", () => {
105
- const registrySchema = SAMPLE_SCHEMA;
106
- const actualSchema = OTHER_SCHEMA;
107
- // registry 记录的是 registrySchema 的 digest,但实际 toolDef 用的是 actualSchema
108
- const registry = [
109
- makeMeta({ name: "tool_drift", inputSchema: registrySchema }),
110
- ];
111
- const toolDefs = makeToolDefs([{ name: "tool_drift", inputSchema: actualSchema }]);
112
-
113
- const result = checkRegistrySchemaDigest(registry, toolDefs);
114
-
115
- assert.equal(result.ok, false);
116
- assert.equal(result.warnings.length, 1);
117
- const warning = result.warnings[0];
118
- const expectedRegistryDigest = computeSchemaDigest(registrySchema);
119
- const expectedActualDigest = computeSchemaDigest(actualSchema);
120
- assert.ok(warning.includes("tool_drift"), "warning 应包含工具名");
121
- assert.ok(
122
- warning.includes(expectedRegistryDigest),
123
- "warning 应包含 registry digest",
124
- );
125
- assert.ok(
126
- warning.includes(expectedActualDigest),
127
- "warning 应包含 actual digest",
128
- );
129
- });
130
-
131
- it("toolDefs 中找不到工具时跳过(不报 drift)", () => {
132
- const registry = [makeMeta({ name: "missing_tool" })];
133
- const toolDefs = makeToolDefs([]); // 空映射
134
-
135
- const result = checkRegistrySchemaDigest(registry, toolDefs);
136
-
137
- assert.equal(result.ok, true);
138
- assert.deepEqual(result.warnings, []);
139
- });
140
- });
141
-
142
- // ── 2. checkChatgptCoreManifestStable ────────────────────────────
143
-
144
- describe("checkChatgptCoreManifestStable", () => {
145
- it("21 工具全部存在时 ok=true", () => {
146
- const toolDefs = makeCoreToolDefs();
147
-
148
- const result = checkChatgptCoreManifestStable(toolDefs);
149
-
150
- assert.equal(result.ok, true);
151
- assert.deepEqual(result.warnings, []);
152
- });
153
-
154
- it("缺少工具时 ok=false", () => {
155
- // 移除最后一个工具,使 chatgpt_core 工具数为 20
156
- const names = [...CHATGPT_CORE_TOOL_NAMES].slice(0, CORE_COUNT - 1);
157
- const toolDefs = makeToolDefs(names.map((name) => ({ name })));
158
-
159
- const result = checkChatgptCoreManifestStable(toolDefs);
160
-
161
- assert.equal(result.ok, false);
162
- assert.equal(result.warnings.length, 1);
163
- assert.ok(
164
- result.warnings[0].includes("missing tools"),
165
- "warning 应包含 missing tools",
166
- );
167
- assert.ok(
168
- result.warnings[0].includes(CHATGPT_CORE_TOOL_NAMES[CORE_COUNT - 1]),
169
- "warning 应包含缺失的工具名",
170
- );
171
- });
172
- });
173
-
174
- // ── 3. checkNewToolsProfileAppend ────────────────────────────────
175
-
176
- describe("checkNewToolsProfileAppend", () => {
177
- it("chatgpt_core 21 工具时 ok=true", () => {
178
- const registry = makeCoreRegistry(CORE_COUNT);
179
-
180
- const result = checkNewToolsProfileAppend(registry);
181
-
182
- assert.equal(result.ok, true);
183
- assert.deepEqual(result.warnings, []);
184
- });
185
-
186
- it("chatgpt_core 工具数不为 21 时 ok=false", () => {
187
- // 22 个 chatgpt_core 工具:21 个标准工具 + 1 个重复名(模拟新工具追加)
188
- const registry = makeCoreRegistry(CORE_COUNT);
189
- registry.push(makeMeta({ name: "extra_tool", profiles: ["chatgpt_core"] }));
190
-
191
- const result = checkNewToolsProfileAppend(registry);
192
-
193
- assert.equal(result.ok, false);
194
- assert.equal(result.warnings.length, 1);
195
- assert.ok(
196
- result.warnings[0].includes(`expected ${CORE_COUNT}`),
197
- "warning 应包含预期数量 21",
198
- );
199
- assert.ok(
200
- result.warnings[0].includes(`got ${CORE_COUNT + 1}`),
201
- "warning 应包含实际数量 22",
202
- );
203
- });
204
- });
205
-
206
- // ── 4. runAllSchemaDriftChecks ───────────────────────────────────
207
-
208
- describe("runAllSchemaDriftChecks", () => {
209
- it("无 drift 时 ok=true", () => {
210
- // registry 与 toolDefs 完全一致,且 chatgpt_core 工具数为 21
211
- const registry = makeCoreRegistry(CORE_COUNT);
212
- const toolDefs = makeCoreToolDefs();
213
-
214
- const result = runAllSchemaDriftChecks(registry, toolDefs);
215
-
216
- assert.equal(result.ok, true);
217
- assert.deepEqual(result.warnings, []);
218
- });
219
-
220
- it("有 drift 时 ok=false,warnings 合并正确", () => {
221
- // 构造同时触发三个检查的 drift:
222
- // - check 1: 一个工具 digest 不一致
223
- // - check 2: toolDefs 缺少一个 chatgpt_core 工具(数量 16)
224
- // - check 3: registry 有 22 个 chatgpt_core 工具
225
- const driftedSchema = OTHER_SCHEMA;
226
- const registry = makeCoreRegistry(CORE_COUNT);
227
- // 第一个工具的 digest 指向 SAMPLE_SCHEMA,但 toolDefs 中该工具用 driftedSchema
228
- registry[0] = makeMeta({
229
- name: CHATGPT_CORE_TOOL_NAMES[0],
230
- inputSchema: SAMPLE_SCHEMA,
231
- profiles: ["chatgpt_core"],
232
- });
233
- // 追加一个额外的 chatgpt_core 工具,使 profile 工具数变为 22
234
- registry.push(makeMeta({ name: "extra_tool", profiles: ["chatgpt_core"] }));
235
-
236
- // toolDefs:第一个工具用 driftedSchema(触发 check 1),且移除最后一个核心工具(触发 check 2)
237
- const coreNames = [...CHATGPT_CORE_TOOL_NAMES];
238
- const toolDefEntries = coreNames.slice(0, CORE_COUNT - 1).map((name) => ({
239
- name,
240
- inputSchema: name === CHATGPT_CORE_TOOL_NAMES[0] ? driftedSchema : SAMPLE_SCHEMA,
241
- }));
242
- const toolDefs = makeToolDefs(toolDefEntries);
243
-
244
- const result = runAllSchemaDriftChecks(registry, toolDefs);
245
-
246
- assert.equal(result.ok, false);
247
- // 至少包含来自三个检查的警告
248
- assert.ok(
249
- result.warnings.length >= 3,
250
- `应有至少 3 条警告,实际 ${result.warnings.length}`,
251
- );
252
- // 验证三类警告都存在
253
- const hasDigestDrift = result.warnings.some((w) => w.startsWith("Schema drift for tool"));
254
- const hasManifestMissing = result.warnings.some((w) => w.includes("missing tools"));
255
- const hasProfileCount = result.warnings.some((w) => w.includes("profile tool count changed"));
256
- assert.ok(hasDigestDrift, "应包含 registry digest drift 警告");
257
- assert.ok(hasManifestMissing, "应包含 manifest 缺失工具警告");
258
- assert.ok(hasProfileCount, "应包含 profile 数量变化警告");
259
- });
260
- });
@@ -1,124 +0,0 @@
1
- import { describe, it } from "node:test";
2
- import { strict as assert } from "node:assert";
3
- import { isSensitivePath, guardSensitivePath } from "../../security/sensitiveGuard.js";
4
- import { PatchWardenError } from "../../errors.js";
5
-
6
- describe("isSensitivePath", () => {
7
- it("blocks .env files", () => {
8
- assert.equal(isSensitivePath(".env"), true);
9
- assert.equal(isSensitivePath("path/to/.env"), true);
10
- assert.equal(isSensitivePath(".env.production"), true);
11
- assert.equal(isSensitivePath(".env.local"), true);
12
- });
13
-
14
- it("blocks .ENV case insensitive", () => {
15
- assert.equal(isSensitivePath(".ENV"), true);
16
- assert.equal(isSensitivePath("path/to/.ENV"), true);
17
- assert.equal(isSensitivePath(".Env.Production"), true);
18
- });
19
-
20
- it("blocks config.json case insensitive", () => {
21
- assert.equal(isSensitivePath("config.json"), true);
22
- assert.equal(isSensitivePath("Config.json"), true);
23
- assert.equal(isSensitivePath("CONFIG.JSON"), true);
24
- assert.equal(isSensitivePath("path/to/Config.json"), true);
25
- });
26
-
27
- it("blocks SSH keys", () => {
28
- assert.equal(isSensitivePath("id_rsa"), true);
29
- assert.equal(isSensitivePath("id_ed25519"), true);
30
- assert.equal(isSensitivePath("id_ecdsa"), true);
31
- assert.equal(isSensitivePath("path/to/id_rsa"), true);
32
- assert.equal(isSensitivePath(".ssh/id_rsa"), true);
33
- });
34
-
35
- it("blocks credentials and tokens", () => {
36
- assert.equal(isSensitivePath("credentials"), true);
37
- assert.equal(isSensitivePath("path/to/credentials.json"), true);
38
- assert.equal(isSensitivePath("token.txt"), true);
39
- // access_token does NOT match because the pattern requires token at start or after /
40
- assert.equal(isSensitivePath("access_token"), false);
41
- assert.equal(isSensitivePath("path/to/token"), true);
42
- assert.equal(isSensitivePath(".netrc"), true);
43
- assert.equal(isSensitivePath(".npmrc"), true);
44
- assert.equal(isSensitivePath(".pypirc"), true);
45
- });
46
-
47
- it("blocks private key files", () => {
48
- assert.equal(isSensitivePath("server.pem"), true);
49
- assert.equal(isSensitivePath("private.key"), true);
50
- assert.equal(isSensitivePath("cert.pfx"), true);
51
- assert.equal(isSensitivePath("cert.p12"), true);
52
- });
53
-
54
- it("blocks browser data files", () => {
55
- assert.equal(isSensitivePath("cookies"), true);
56
- assert.equal(isSensitivePath("cookies.db"), true);
57
- assert.equal(isSensitivePath("Web Data"), true);
58
- assert.equal(isSensitivePath("Login Data"), true);
59
- assert.equal(isSensitivePath("Local State"), true);
60
- });
61
-
62
- it("blocks .git-credentials", () => {
63
- assert.equal(isSensitivePath(".git-credentials"), true);
64
- assert.equal(isSensitivePath("path/to/.git-credentials"), true);
65
- });
66
-
67
- it("blocks docker and kube config", () => {
68
- assert.equal(isSensitivePath(".docker/config.json"), true);
69
- assert.equal(isSensitivePath(".kube/config"), true);
70
- });
71
-
72
- it("allows .patchwarden safe prefix", () => {
73
- assert.equal(isSensitivePath(".patchwarden/tasks/task-001/status.json"), false);
74
- assert.equal(isSensitivePath(".patchwarden/config.json"), false);
75
- assert.equal(isSensitivePath(".patchwarden"), false);
76
- });
77
-
78
- it("allows non-sensitive files", () => {
79
- assert.equal(isSensitivePath("src/main.ts"), false);
80
- assert.equal(isSensitivePath("README.md"), false);
81
- assert.equal(isSensitivePath("package.json"), false);
82
- assert.equal(isSensitivePath("docs/guide.md"), false);
83
- });
84
-
85
- it("handles Windows backslash paths", () => {
86
- assert.equal(isSensitivePath("path\\to\\.env"), true);
87
- assert.equal(isSensitivePath("path\\to\\config.json"), true);
88
- assert.equal(isSensitivePath(".patchwarden\\tasks\\status.json"), false);
89
- });
90
-
91
- it("handles null byte in path", () => {
92
- // config.json with null byte appended — the $ anchor means this won't match
93
- // because the string doesn't end with "config.json"
94
- const nullPath = "config.json\x00.txt";
95
- assert.equal(isSensitivePath(nullPath), false);
96
- // But plain config.json still matches
97
- assert.equal(isSensitivePath("config.json"), true);
98
- });
99
-
100
- it("handles Unicode lookalike characters", () => {
101
- // Full-width dot (U+FF0E) should not match .env pattern
102
- // This is expected behavior — Unicode lookalikes are NOT matched
103
- const fullWidthPath = "\uFF0Eenv";
104
- assert.equal(isSensitivePath(fullWidthPath), false);
105
- });
106
- });
107
-
108
- describe("guardSensitivePath", () => {
109
- it("throws PatchWardenError for sensitive paths", () => {
110
- assert.throws(
111
- () => guardSensitivePath(".env"),
112
- (err: unknown) => err instanceof PatchWardenError && err.reason === "sensitive_path_blocked"
113
- );
114
- });
115
-
116
- it("does not throw for non-sensitive paths", () => {
117
- assert.doesNotThrow(() => guardSensitivePath("src/main.ts"));
118
- assert.doesNotThrow(() => guardSensitivePath("README.md"));
119
- });
120
-
121
- it("does not throw for .patchwarden paths", () => {
122
- assert.doesNotThrow(() => guardSensitivePath(".patchwarden/tasks/status.json"));
123
- });
124
- });