patchwarden 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (597) hide show
  1. package/PatchWarden.cmd +32 -2
  2. package/README.en.md +194 -26
  3. package/README.md +160 -22
  4. package/dist/assessments/agentAssessor.d.ts +1 -1
  5. package/dist/assessments/agentAssessor.js +24 -15
  6. package/dist/assessments/assessmentStore.d.ts +1 -1
  7. package/dist/assessments/assessmentStore.js +44 -36
  8. package/dist/assessments/confirmCli.js +5 -4
  9. package/dist/config.d.ts +22 -0
  10. package/dist/config.js +98 -11
  11. package/dist/control/fileManager.d.ts +2 -0
  12. package/dist/control/fileManager.js +39 -0
  13. package/dist/control/middleware/auth.d.ts +16 -0
  14. package/dist/control/middleware/auth.js +17 -0
  15. package/dist/control/middleware/static.d.ts +3 -0
  16. package/dist/control/middleware/static.js +78 -0
  17. package/dist/control/routeTable.d.ts +24 -0
  18. package/dist/control/routeTable.js +263 -0
  19. package/dist/control/routes/audit.d.ts +15 -0
  20. package/dist/control/routes/audit.js +287 -0
  21. package/dist/control/routes/evidence.d.ts +4 -0
  22. package/dist/control/routes/evidence.js +96 -0
  23. package/dist/control/routes/lineage.d.ts +3 -0
  24. package/dist/control/routes/lineage.js +71 -0
  25. package/dist/control/routes/policy.d.ts +3 -0
  26. package/dist/control/routes/policy.js +81 -0
  27. package/dist/control/routes/process.d.ts +12 -0
  28. package/dist/control/routes/process.js +487 -0
  29. package/dist/control/routes/sessions.d.ts +30 -0
  30. package/dist/control/routes/sessions.js +287 -0
  31. package/dist/control/routes/status.d.ts +51 -0
  32. package/dist/control/routes/status.js +307 -0
  33. package/dist/control/routes/taskActions.d.ts +21 -0
  34. package/dist/control/routes/taskActions.js +197 -0
  35. package/dist/control/routes/tasks.d.ts +24 -0
  36. package/dist/control/routes/tasks.js +309 -0
  37. package/dist/control/routes/workspace.d.ts +15 -0
  38. package/dist/control/routes/workspace.js +220 -0
  39. package/dist/control/runtime.d.ts +92 -0
  40. package/dist/control/runtime.js +425 -0
  41. package/dist/control/server.d.ts +13 -0
  42. package/dist/control/server.js +150 -0
  43. package/dist/control/shared.d.ts +59 -0
  44. package/dist/control/shared.js +341 -0
  45. package/dist/controlCenter.d.ts +6 -0
  46. package/dist/controlCenter.js +7 -2197
  47. package/dist/direct/directAudit.js +234 -225
  48. package/dist/direct/directGuards.d.ts +2 -1
  49. package/dist/direct/directGuards.js +72 -37
  50. package/dist/direct/directPatch.d.ts +6 -1
  51. package/dist/direct/directPatch.js +55 -8
  52. package/dist/direct/directSessionStore.d.ts +16 -6
  53. package/dist/direct/directSessionStore.js +127 -35
  54. package/dist/direct/directVerification.js +8 -16
  55. package/dist/doctor.d.ts +18 -1
  56. package/dist/doctor.js +614 -373
  57. package/dist/goal/acceptanceEngine.d.ts +1 -1
  58. package/dist/goal/goalProgress.js +75 -69
  59. package/dist/goal/goalReport.d.ts +54 -0
  60. package/dist/goal/goalReport.js +197 -0
  61. package/dist/goal/goalStatus.d.ts +8 -0
  62. package/dist/goal/goalStatus.js +10 -3
  63. package/dist/goal/goalStore.d.ts +9 -2
  64. package/dist/goal/goalStore.js +152 -45
  65. package/dist/goal/handoffExport.js +6 -6
  66. package/dist/goal/specKitImport.d.ts +63 -0
  67. package/dist/goal/specKitImport.js +221 -0
  68. package/dist/goal/subgoalSync.js +13 -10
  69. package/dist/goal/worktreeManager.d.ts +2 -0
  70. package/dist/goal/worktreeManager.js +209 -136
  71. package/dist/httpServer.js +126 -44
  72. package/dist/index.js +7 -4
  73. package/dist/logging.d.ts +7 -1
  74. package/dist/logging.js +13 -3
  75. package/dist/policy/projectPolicy.js +5 -2
  76. package/dist/release/releaseGate.d.ts +1 -1
  77. package/dist/release/releaseGate.js +78 -25
  78. package/dist/runner/agentInvocation.d.ts +14 -0
  79. package/dist/runner/agentInvocation.js +96 -4
  80. package/dist/runner/changeCapture.d.ts +14 -6
  81. package/dist/runner/changeCapture.js +287 -81
  82. package/dist/runner/cli.js +7 -6
  83. package/dist/runner/postTaskCleanup.js +60 -7
  84. package/dist/runner/processSecurity.d.ts +56 -0
  85. package/dist/runner/processSecurity.js +373 -0
  86. package/dist/runner/runTask.d.ts +1 -1
  87. package/dist/runner/runTask.js +339 -287
  88. package/dist/runner/simpleProcess.d.ts +3 -0
  89. package/dist/runner/simpleProcess.js +52 -38
  90. package/dist/{taskProgress.d.ts → runner/taskProgress.d.ts} +1 -1
  91. package/dist/{taskProgress.js → runner/taskProgress.js} +2 -2
  92. package/dist/{taskRuntime.d.ts → runner/taskRuntime.d.ts} +1 -1
  93. package/dist/{taskRuntime.js → runner/taskRuntime.js} +3 -2
  94. package/dist/runner/taskStatusStore.d.ts +11 -0
  95. package/dist/runner/taskStatusStore.js +24 -0
  96. package/dist/runner/watch.d.ts +14 -1
  97. package/dist/runner/watch.js +265 -54
  98. package/dist/security/contentRedaction.d.ts +6 -0
  99. package/dist/security/contentRedaction.js +24 -2
  100. package/dist/security/discoveryTokenStore.d.ts +3 -2
  101. package/dist/security/discoveryTokenStore.js +17 -2
  102. package/dist/security/loopbackHost.d.ts +2 -0
  103. package/dist/security/loopbackHost.js +16 -0
  104. package/dist/security/pathGuard.js +32 -17
  105. package/dist/security/planGuard.js +2 -1
  106. package/dist/security/runtimeGuard.js +9 -6
  107. package/dist/security/secretComparison.d.ts +3 -0
  108. package/dist/security/secretComparison.js +11 -0
  109. package/dist/security/sensitiveGuard.d.ts +5 -0
  110. package/dist/security/sensitiveGuard.js +27 -8
  111. package/dist/security/toolInvocationGuard.d.ts +2 -2
  112. package/dist/security/toolInvocationGuard.js +1 -1
  113. package/dist/security/workspaceRootGuard.d.ts +8 -0
  114. package/dist/security/workspaceRootGuard.js +47 -0
  115. package/dist/smoke-test.js +280 -273
  116. package/dist/tools/catalog/index.d.ts +4 -0
  117. package/dist/tools/catalog/index.js +4 -0
  118. package/dist/tools/{toolCatalog.js → catalog/toolCatalog.js} +3 -12
  119. package/dist/tools/{toolRegistry.d.ts → catalog/toolRegistry.d.ts} +3 -3
  120. package/dist/tools/{toolRegistry.js → catalog/toolRegistry.js} +28 -15
  121. package/dist/tools/definitions/toolDefs.d.ts +18 -0
  122. package/dist/tools/definitions/toolDefs.js +1177 -0
  123. package/dist/tools/{auditSession.d.ts → diagnostics/auditSession.d.ts} +1 -1
  124. package/dist/tools/{auditSession.js → diagnostics/auditSession.js} +2 -2
  125. package/dist/tools/{auditTask.d.ts → diagnostics/auditTask.d.ts} +8 -63
  126. package/dist/tools/{auditTask.js → diagnostics/auditTask.js} +111 -37
  127. package/dist/tools/{healthCheck.d.ts → diagnostics/healthCheck.d.ts} +6 -6
  128. package/dist/tools/{healthCheck.js → diagnostics/healthCheck.js} +10 -10
  129. package/dist/tools/diagnostics/index.d.ts +6 -0
  130. package/dist/tools/diagnostics/index.js +6 -0
  131. package/dist/tools/{safeStatus.d.ts → diagnostics/safeStatus.d.ts} +3 -3
  132. package/dist/tools/{safeStatus.js → diagnostics/safeStatus.js} +6 -6
  133. package/dist/tools/{safeViews.d.ts → diagnostics/safeViews.d.ts} +14 -10
  134. package/dist/tools/{safeViews.js → diagnostics/safeViews.js} +25 -15
  135. package/dist/tools/{schemaDriftCheck.d.ts → diagnostics/schemaDriftCheck.d.ts} +1 -1
  136. package/dist/tools/{schemaDriftCheck.js → diagnostics/schemaDriftCheck.js} +2 -2
  137. package/dist/tools/{createDirectSession.d.ts → direct/createDirectSession.d.ts} +1 -1
  138. package/dist/tools/{createDirectSession.js → direct/createDirectSession.js} +8 -8
  139. package/dist/tools/{finalizeDirectSession.d.ts → direct/finalizeDirectSession.d.ts} +2 -2
  140. package/dist/tools/direct/finalizeDirectSession.js +86 -0
  141. package/dist/tools/direct/index.d.ts +3 -0
  142. package/dist/tools/direct/index.js +3 -0
  143. package/dist/tools/{runDirectVerificationBundle.js → direct/runDirectVerificationBundle.js} +2 -2
  144. package/dist/tools/{discoverTools.d.ts → discovery/discoverTools.d.ts} +2 -2
  145. package/dist/tools/{discoverTools.js → discovery/discoverTools.js} +5 -5
  146. package/dist/tools/{explainTool.d.ts → discovery/explainTool.d.ts} +2 -2
  147. package/dist/tools/{explainTool.js → discovery/explainTool.js} +2 -2
  148. package/dist/tools/discovery/index.d.ts +3 -0
  149. package/dist/tools/discovery/index.js +3 -0
  150. package/dist/tools/{invokeDiscoveredTool.d.ts → discovery/invokeDiscoveredTool.d.ts} +2 -2
  151. package/dist/tools/{invokeDiscoveredTool.js → discovery/invokeDiscoveredTool.js} +5 -5
  152. package/dist/tools/dispatch/coreDispatch.d.ts +9 -0
  153. package/dist/tools/dispatch/coreDispatch.js +283 -0
  154. package/dist/tools/dispatch/diagnosticDispatch.d.ts +12 -0
  155. package/dist/tools/dispatch/diagnosticDispatch.js +80 -0
  156. package/dist/tools/dispatch/directDispatch.d.ts +8 -0
  157. package/dist/tools/dispatch/directDispatch.js +116 -0
  158. package/dist/tools/dispatch/goalDispatch.d.ts +8 -0
  159. package/dist/tools/dispatch/goalDispatch.js +92 -0
  160. package/dist/tools/dispatch/releaseDispatch.d.ts +8 -0
  161. package/dist/tools/dispatch/releaseDispatch.js +46 -0
  162. package/dist/tools/dispatch/types.d.ts +23 -0
  163. package/dist/tools/dispatch/types.js +15 -0
  164. package/dist/tools/dispatch/validation.d.ts +7 -0
  165. package/dist/tools/dispatch/validation.js +71 -0
  166. package/dist/tools/{getPlan.js → goals/getPlan.js} +4 -4
  167. package/dist/tools/{goalSubgoalTask.d.ts → goals/goalSubgoalTask.d.ts} +2 -2
  168. package/dist/tools/goals/goalSubgoalTask.js +118 -0
  169. package/dist/tools/goals/index.d.ts +3 -0
  170. package/dist/tools/goals/index.js +3 -0
  171. package/dist/tools/{savePlan.js → goals/savePlan.js} +28 -8
  172. package/dist/tools/registry.d.ts +10 -14
  173. package/dist/tools/registry.js +47 -1651
  174. package/dist/tools/{checkReleaseGate.d.ts → release/checkReleaseGate.d.ts} +1 -1
  175. package/dist/tools/{checkReleaseGate.js → release/checkReleaseGate.js} +3 -3
  176. package/dist/tools/release/index.d.ts +2 -0
  177. package/dist/tools/release/index.js +2 -0
  178. package/dist/tools/{releaseMode.d.ts → release/releaseMode.d.ts} +2 -2
  179. package/dist/tools/{releaseMode.js → release/releaseMode.js} +46 -26
  180. package/dist/tools/tasks/cancelTask.d.ts +11 -0
  181. package/dist/tools/tasks/cancelTask.js +85 -0
  182. package/dist/tools/{createTask.d.ts → tasks/createTask.d.ts} +12 -4
  183. package/dist/tools/{createTask.js → tasks/createTask.js} +46 -31
  184. package/dist/tools/{diagnoseTask.d.ts → tasks/diagnoseTask.d.ts} +1 -1
  185. package/dist/tools/{diagnoseTask.js → tasks/diagnoseTask.js} +8 -8
  186. package/dist/tools/{evidencePack.d.ts → tasks/evidencePack.d.ts} +6 -0
  187. package/dist/tools/tasks/evidencePack.js +387 -0
  188. package/dist/tools/{getTaskFile.js → tasks/getTaskFile.js} +4 -4
  189. package/dist/tools/{getTaskStatus.d.ts → tasks/getTaskStatus.d.ts} +6 -1
  190. package/dist/tools/{getTaskStatus.js → tasks/getTaskStatus.js} +5 -5
  191. package/dist/tools/{getTaskStdoutTail.js → tasks/getTaskStdoutTail.js} +13 -11
  192. package/dist/tools/{getTaskSummary.js → tasks/getTaskSummary.js} +33 -26
  193. package/dist/tools/tasks/index.d.ts +18 -0
  194. package/dist/tools/tasks/index.js +18 -0
  195. package/dist/tools/tasks/killTask.d.ts +1 -0
  196. package/dist/tools/{listTasks.d.ts → tasks/listTasks.d.ts} +1 -1
  197. package/dist/tools/{listTasks.js → tasks/listTasks.js} +3 -3
  198. package/dist/tools/{reconcileTasks.d.ts → tasks/reconcileTasks.d.ts} +1 -1
  199. package/dist/tools/{reconcileTasks.js → tasks/reconcileTasks.js} +64 -66
  200. package/dist/tools/{retryTask.d.ts → tasks/retryTask.d.ts} +2 -2
  201. package/dist/tools/tasks/retryTask.js +60 -0
  202. package/dist/tools/{runTaskLoop.d.ts → tasks/runTaskLoop.d.ts} +6 -6
  203. package/dist/tools/{runTaskLoop.js → tasks/runTaskLoop.js} +59 -31
  204. package/dist/tools/tasks/runVerification.js +38 -0
  205. package/dist/tools/{taskLineage.js → tasks/taskLineage.js} +8 -7
  206. package/dist/tools/{taskOutputs.js → tasks/taskOutputs.js} +17 -16
  207. package/dist/tools/{androidDoctor.js → workspace/androidDoctor.js} +16 -10
  208. package/dist/tools/{applyPatch.d.ts → workspace/applyPatch.d.ts} +1 -1
  209. package/dist/tools/workspace/applyPatch.js +53 -0
  210. package/dist/tools/{discardWorktree.js → workspace/discardWorktree.js} +3 -3
  211. package/dist/tools/workspace/index.d.ts +10 -0
  212. package/dist/tools/workspace/index.js +10 -0
  213. package/dist/tools/{listAgents.d.ts → workspace/listAgents.d.ts} +5 -0
  214. package/dist/tools/{listAgents.js → workspace/listAgents.js} +8 -4
  215. package/dist/tools/{listWorkspace.js → workspace/listWorkspace.js} +3 -3
  216. package/dist/tools/{mergeWorktree.js → workspace/mergeWorktree.js} +3 -3
  217. package/dist/tools/{readWorkspaceFile.js → workspace/readWorkspaceFile.js} +8 -8
  218. package/dist/tools/{recommendAgentForTask.js → workspace/recommendAgentForTask.js} +3 -3
  219. package/dist/tools/{searchWorkspace.js → workspace/searchWorkspace.js} +5 -5
  220. package/dist/tools/{syncFile.d.ts → workspace/syncFile.d.ts} +1 -1
  221. package/dist/tools/workspace/syncFile.js +134 -0
  222. package/dist/utils/atomicFile.d.ts +7 -0
  223. package/dist/utils/atomicFile.js +48 -0
  224. package/dist/utils/boundedFile.d.ts +8 -0
  225. package/dist/utils/boundedFile.js +93 -0
  226. package/dist/utils/lockedJsonFile.d.ts +15 -0
  227. package/dist/utils/lockedJsonFile.js +224 -0
  228. package/dist/utils/platform.d.ts +11 -0
  229. package/dist/utils/platform.js +26 -0
  230. package/dist/utils/stableJson.d.ts +2 -0
  231. package/dist/utils/stableJson.js +12 -0
  232. package/dist/version.d.ts +3 -2
  233. package/dist/version.js +3 -2
  234. package/dist/watcherStatus.d.ts +2 -2
  235. package/dist/watcherStatus.js +18 -0
  236. package/docs/CODE_WIKI.md +1648 -0
  237. package/docs/agentseal-integration.md +150 -0
  238. package/docs/architecture.md +23 -0
  239. package/docs/assets/patchwarden-desktop-onboarding.png +0 -0
  240. package/docs/assets/patchwarden-oss-demo.gif +0 -0
  241. package/docs/control-center/README.md +4 -4
  242. package/docs/dashboard-overview.md +86 -0
  243. package/docs/demo.md +8 -0
  244. package/docs/desktop-app.md +175 -0
  245. package/docs/direct-session-workflow.md +98 -0
  246. package/docs/evidence-pack-schema.md +215 -0
  247. package/docs/lineage-evidence-pack-workflow.md +127 -0
  248. package/docs/mcp-inspector-testing.md +200 -0
  249. package/docs/open-source-application.md +168 -0
  250. package/docs/opencode-worker.md +151 -0
  251. package/docs/openhands-worker.md +181 -0
  252. package/docs/release-checklist.md +1 -1
  253. package/docs/release-evidence.md +82 -0
  254. package/docs/spec-kit-integration.md +131 -0
  255. package/docs/task-safe-review-workflow.md +98 -0
  256. package/docs/threat-model.md +97 -0
  257. package/docs/user-feedback.md +40 -0
  258. package/docs/why-patchwarden.md +110 -0
  259. package/examples/config.example.json +4 -2
  260. package/package.json +28 -11
  261. package/scripts/README.md +15 -6
  262. package/scripts/build.js +11 -0
  263. package/scripts/checks/brand-check.js +3 -0
  264. package/scripts/checks/build-output-check.js +37 -0
  265. package/scripts/checks/control-center-smoke.js +447 -6
  266. package/scripts/checks/control-smoke.js +19 -8
  267. package/scripts/checks/http-mcp-smoke.js +82 -4
  268. package/scripts/checks/lifecycle-smoke.js +39 -33
  269. package/scripts/checks/mcp-manifest-check.js +1 -1
  270. package/scripts/checks/mcp-smoke.js +30 -4
  271. package/scripts/checks/package-manifest-check.js +20 -7
  272. package/scripts/checks/unit-tests.js +3 -5
  273. package/scripts/checks/watcher-supervisor-smoke.js +9 -0
  274. package/scripts/control/get-patchwarden-health.ps1 +1 -1
  275. package/scripts/control/manage-patchwarden.ps1 +69 -4
  276. package/scripts/control/provision-patchwarden-tunnel.ps1 +127 -0
  277. package/scripts/control/run-background-supervisor.ps1 +41 -0
  278. package/scripts/control/start-patchwarden-tunnel.ps1 +126 -32
  279. package/scripts/generate-demo-gif.py +320 -0
  280. package/{PatchWarden-Control-Tray.cmd → scripts/launchers/PatchWarden-Control-Tray.cmd} +3 -3
  281. package/scripts/launchers/PatchWarden-Control.cmd +6 -0
  282. package/{PatchWarden-Desktop.cmd → scripts/launchers/PatchWarden-Desktop.cmd} +2 -2
  283. package/scripts/launchers/Restart-PatchWarden-Control.cmd +6 -0
  284. package/{Stop-PatchWarden.cmd → scripts/launchers/Stop-PatchWarden.cmd} +2 -2
  285. package/scripts/lib/clean-generated-output.js +11 -0
  286. package/scripts/lib/file-discovery.js +12 -0
  287. package/scripts/release/desktop-preflight.js +211 -0
  288. package/scripts/release/pack-clean.js +59 -14
  289. package/src/assessments/agentAssessor.ts +29 -15
  290. package/src/assessments/assessmentStore.ts +55 -43
  291. package/src/assessments/confirmCli.ts +5 -4
  292. package/src/config.ts +105 -11
  293. package/src/control/fileManager.ts +40 -0
  294. package/src/control/middleware/auth.ts +35 -0
  295. package/src/control/middleware/static.ts +84 -0
  296. package/src/control/routeTable.ts +301 -0
  297. package/src/control/routes/audit.ts +329 -0
  298. package/src/control/routes/evidence.ts +107 -0
  299. package/src/control/routes/lineage.ts +92 -0
  300. package/src/control/routes/policy.ts +81 -0
  301. package/src/control/routes/process.ts +505 -0
  302. package/src/control/routes/sessions.ts +314 -0
  303. package/src/control/routes/status.ts +405 -0
  304. package/src/control/routes/taskActions.ts +214 -0
  305. package/src/control/routes/tasks.ts +331 -0
  306. package/src/control/routes/workspace.ts +234 -0
  307. package/src/control/runtime.ts +508 -0
  308. package/src/control/server.ts +165 -0
  309. package/src/control/shared.ts +360 -0
  310. package/src/controlCenter.ts +7 -2347
  311. package/src/direct/directAudit.ts +17 -9
  312. package/src/direct/directGuards.ts +100 -51
  313. package/src/direct/directPatch.ts +95 -8
  314. package/src/direct/directSessionStore.ts +211 -55
  315. package/src/direct/directVerification.ts +9 -23
  316. package/src/doctor.ts +766 -492
  317. package/src/goal/acceptanceEngine.ts +1 -1
  318. package/src/goal/goalProgress.ts +17 -13
  319. package/src/goal/goalReport.ts +263 -0
  320. package/src/goal/goalStatus.ts +25 -3
  321. package/src/goal/goalStore.ts +241 -54
  322. package/src/goal/handoffExport.ts +6 -6
  323. package/src/goal/specKitImport.ts +355 -0
  324. package/src/goal/subgoalSync.ts +15 -10
  325. package/src/goal/worktreeManager.ts +139 -22
  326. package/src/httpServer.ts +130 -44
  327. package/src/index.ts +7 -4
  328. package/src/logging.ts +20 -4
  329. package/src/policy/projectPolicy.ts +5 -2
  330. package/src/release/releaseGate.ts +74 -27
  331. package/src/runner/agentInvocation.ts +126 -4
  332. package/src/runner/changeCapture.ts +342 -80
  333. package/src/runner/cli.ts +7 -6
  334. package/src/runner/postTaskCleanup.ts +55 -7
  335. package/src/runner/processSecurity.ts +433 -0
  336. package/src/runner/runTask.ts +441 -292
  337. package/src/runner/simpleProcess.ts +68 -33
  338. package/src/{taskProgress.ts → runner/taskProgress.ts} +3 -3
  339. package/src/{taskRuntime.ts → runner/taskRuntime.ts} +4 -3
  340. package/src/runner/taskStatusStore.ts +54 -0
  341. package/src/runner/watch.ts +290 -57
  342. package/src/security/contentRedaction.ts +31 -2
  343. package/src/security/discoveryTokenStore.ts +18 -4
  344. package/src/security/loopbackHost.ts +19 -0
  345. package/src/security/pathGuard.ts +35 -16
  346. package/src/security/planGuard.ts +2 -1
  347. package/src/security/runtimeGuard.ts +9 -6
  348. package/src/security/secretComparison.ts +13 -0
  349. package/src/security/sensitiveGuard.ts +27 -8
  350. package/src/security/toolInvocationGuard.ts +2 -2
  351. package/src/security/workspaceRootGuard.ts +53 -0
  352. package/src/smoke-test.ts +276 -273
  353. package/src/tools/catalog/index.ts +4 -0
  354. package/src/tools/{toolCatalog.ts → catalog/toolCatalog.ts} +3 -12
  355. package/src/tools/{toolRegistry.ts → catalog/toolRegistry.ts} +29 -16
  356. package/src/tools/definitions/toolDefs.ts +1264 -0
  357. package/src/tools/{auditSession.ts → diagnostics/auditSession.ts} +2 -2
  358. package/src/tools/{auditTask.ts → diagnostics/auditTask.ts} +196 -89
  359. package/src/tools/{healthCheck.ts → diagnostics/healthCheck.ts} +11 -11
  360. package/src/tools/diagnostics/index.ts +6 -0
  361. package/src/tools/{safeStatus.ts → diagnostics/safeStatus.ts} +7 -7
  362. package/src/tools/{safeViews.ts → diagnostics/safeViews.ts} +29 -19
  363. package/src/tools/{schemaDriftCheck.ts → diagnostics/schemaDriftCheck.ts} +3 -3
  364. package/src/tools/{createDirectSession.ts → direct/createDirectSession.ts} +9 -9
  365. package/src/tools/{finalizeDirectSession.ts → direct/finalizeDirectSession.ts} +11 -9
  366. package/src/tools/direct/index.ts +3 -0
  367. package/src/tools/{runDirectVerificationBundle.ts → direct/runDirectVerificationBundle.ts} +2 -2
  368. package/src/tools/{discoverTools.ts → discovery/discoverTools.ts} +6 -6
  369. package/src/tools/{explainTool.ts → discovery/explainTool.ts} +3 -3
  370. package/src/tools/discovery/index.ts +3 -0
  371. package/src/tools/{invokeDiscoveredTool.ts → discovery/invokeDiscoveredTool.ts} +7 -7
  372. package/src/tools/dispatch/coreDispatch.ts +379 -0
  373. package/src/tools/dispatch/diagnosticDispatch.ts +106 -0
  374. package/src/tools/dispatch/directDispatch.ts +168 -0
  375. package/src/tools/dispatch/goalDispatch.ts +128 -0
  376. package/src/tools/dispatch/releaseDispatch.ts +66 -0
  377. package/src/tools/dispatch/types.ts +24 -0
  378. package/src/tools/dispatch/validation.ts +78 -0
  379. package/src/tools/{getPlan.ts → goals/getPlan.ts} +4 -4
  380. package/src/tools/{goalSubgoalTask.ts → goals/goalSubgoalTask.ts} +43 -28
  381. package/src/tools/goals/index.ts +3 -0
  382. package/src/tools/{savePlan.ts → goals/savePlan.ts} +38 -8
  383. package/src/tools/registry.ts +54 -1858
  384. package/src/tools/{checkReleaseGate.ts → release/checkReleaseGate.ts} +3 -3
  385. package/src/tools/release/index.ts +2 -0
  386. package/src/tools/{releaseMode.ts → release/releaseMode.ts} +42 -24
  387. package/src/tools/tasks/cancelTask.ts +109 -0
  388. package/src/tools/{createTask.ts → tasks/createTask.ts} +56 -33
  389. package/src/tools/{diagnoseTask.ts → tasks/diagnoseTask.ts} +8 -8
  390. package/src/tools/tasks/evidencePack.ts +504 -0
  391. package/src/tools/{getTaskFile.ts → tasks/getTaskFile.ts} +4 -4
  392. package/src/tools/{getTaskStatus.ts → tasks/getTaskStatus.ts} +7 -5
  393. package/src/tools/{getTaskStdoutTail.ts → tasks/getTaskStdoutTail.ts} +13 -11
  394. package/src/tools/{getTaskSummary.ts → tasks/getTaskSummary.ts} +44 -33
  395. package/src/tools/tasks/index.ts +18 -0
  396. package/src/tools/{listTasks.ts → tasks/listTasks.ts} +4 -4
  397. package/src/tools/{reconcileTasks.ts → tasks/reconcileTasks.ts} +68 -66
  398. package/src/tools/tasks/retryTask.ts +69 -0
  399. package/src/tools/{runTaskLoop.ts → tasks/runTaskLoop.ts} +70 -35
  400. package/src/tools/{runVerification.ts → tasks/runVerification.ts} +6 -3
  401. package/src/tools/{taskLineage.ts → tasks/taskLineage.ts} +8 -7
  402. package/src/tools/{taskOutputs.ts → tasks/taskOutputs.ts} +27 -20
  403. package/src/tools/{androidDoctor.ts → workspace/androidDoctor.ts} +15 -10
  404. package/src/tools/{applyPatch.ts → workspace/applyPatch.ts} +38 -16
  405. package/src/tools/{discardWorktree.ts → workspace/discardWorktree.ts} +3 -3
  406. package/src/tools/workspace/index.ts +10 -0
  407. package/src/tools/{listAgents.ts → workspace/listAgents.ts} +11 -4
  408. package/src/tools/{listWorkspace.ts → workspace/listWorkspace.ts} +3 -3
  409. package/src/tools/{mergeWorktree.ts → workspace/mergeWorktree.ts} +3 -3
  410. package/src/tools/{readWorkspaceFile.ts → workspace/readWorkspaceFile.ts} +8 -8
  411. package/src/tools/{recommendAgentForTask.ts → workspace/recommendAgentForTask.ts} +3 -3
  412. package/src/tools/{searchWorkspace.ts → workspace/searchWorkspace.ts} +5 -5
  413. package/src/tools/workspace/syncFile.ts +292 -0
  414. package/src/utils/atomicFile.ts +58 -0
  415. package/src/utils/boundedFile.ts +116 -0
  416. package/src/utils/lockedJsonFile.ts +251 -0
  417. package/src/utils/platform.ts +31 -0
  418. package/src/utils/stableJson.ts +12 -0
  419. package/src/version.ts +3 -2
  420. package/src/watcherStatus.ts +19 -1
  421. package/ui/desktop-bootstrap.js +11 -0
  422. package/ui/desktop-bridge.js +36 -0
  423. package/ui/desktop.css +160 -0
  424. package/ui/getting-started.js +93 -0
  425. package/ui/i18n.js +484 -0
  426. package/ui/log-parser.js +30 -0
  427. package/ui/pages/audit.html +204 -3
  428. package/ui/pages/dashboard.html +937 -79
  429. package/ui/pages/direct-sessions.html +609 -60
  430. package/ui/pages/getting-started.html +43 -0
  431. package/ui/pages/logs.html +105 -22
  432. package/ui/pages/settings.html +101 -0
  433. package/ui/pages/task-detail.html +468 -438
  434. package/ui/pages/tasks.html +648 -65
  435. package/ui/pages/workspace.html +38 -1
  436. package/ui/settings.js +245 -0
  437. package/PatchWarden-Control.cmd +0 -6
  438. package/Restart-PatchWarden-Control.cmd +0 -6
  439. package/dist/test/unit/acceptance-engine.test.d.ts +0 -1
  440. package/dist/test/unit/acceptance-engine.test.js +0 -228
  441. package/dist/test/unit/agent-router.test.d.ts +0 -1
  442. package/dist/test/unit/agent-router.test.js +0 -287
  443. package/dist/test/unit/android-doctor.test.d.ts +0 -1
  444. package/dist/test/unit/android-doctor.test.js +0 -118
  445. package/dist/test/unit/audit-checks.test.d.ts +0 -1
  446. package/dist/test/unit/audit-checks.test.js +0 -350
  447. package/dist/test/unit/chinese-path.test.d.ts +0 -1
  448. package/dist/test/unit/chinese-path.test.js +0 -91
  449. package/dist/test/unit/command-guard.test.d.ts +0 -1
  450. package/dist/test/unit/command-guard.test.js +0 -160
  451. package/dist/test/unit/diagnose-task.test.d.ts +0 -1
  452. package/dist/test/unit/diagnose-task.test.js +0 -457
  453. package/dist/test/unit/direct-guards.test.d.ts +0 -1
  454. package/dist/test/unit/direct-guards.test.js +0 -213
  455. package/dist/test/unit/discovery-token-store.test.d.ts +0 -1
  456. package/dist/test/unit/discovery-token-store.test.js +0 -139
  457. package/dist/test/unit/evidence-pack.test.d.ts +0 -1
  458. package/dist/test/unit/evidence-pack.test.js +0 -130
  459. package/dist/test/unit/goal-graph.test.d.ts +0 -1
  460. package/dist/test/unit/goal-graph.test.js +0 -298
  461. package/dist/test/unit/goal-progress.test.d.ts +0 -1
  462. package/dist/test/unit/goal-progress.test.js +0 -381
  463. package/dist/test/unit/goal-status.test.d.ts +0 -1
  464. package/dist/test/unit/goal-status.test.js +0 -215
  465. package/dist/test/unit/goal-store.test.d.ts +0 -1
  466. package/dist/test/unit/goal-store.test.js +0 -253
  467. package/dist/test/unit/goal-subgoal-task.test.d.ts +0 -1
  468. package/dist/test/unit/goal-subgoal-task.test.js +0 -55
  469. package/dist/test/unit/goal-tools-registry.test.d.ts +0 -1
  470. package/dist/test/unit/goal-tools-registry.test.js +0 -190
  471. package/dist/test/unit/handoff-export.test.d.ts +0 -1
  472. package/dist/test/unit/handoff-export.test.js +0 -263
  473. package/dist/test/unit/invoke-discovered-tool.test.d.ts +0 -1
  474. package/dist/test/unit/invoke-discovered-tool.test.js +0 -167
  475. package/dist/test/unit/logging.test.d.ts +0 -1
  476. package/dist/test/unit/logging.test.js +0 -397
  477. package/dist/test/unit/path-guard.test.d.ts +0 -1
  478. package/dist/test/unit/path-guard.test.js +0 -109
  479. package/dist/test/unit/post-task-cleanup.test.d.ts +0 -1
  480. package/dist/test/unit/post-task-cleanup.test.js +0 -48
  481. package/dist/test/unit/project-policy-release-mode.test.d.ts +0 -1
  482. package/dist/test/unit/project-policy-release-mode.test.js +0 -125
  483. package/dist/test/unit/reconcile-tasks.test.d.ts +0 -1
  484. package/dist/test/unit/reconcile-tasks.test.js +0 -456
  485. package/dist/test/unit/release-gate.test.d.ts +0 -1
  486. package/dist/test/unit/release-gate.test.js +0 -242
  487. package/dist/test/unit/run-task-loop.test.d.ts +0 -1
  488. package/dist/test/unit/run-task-loop.test.js +0 -380
  489. package/dist/test/unit/safe-status.test.d.ts +0 -1
  490. package/dist/test/unit/safe-status.test.js +0 -165
  491. package/dist/test/unit/safe-views.test.d.ts +0 -1
  492. package/dist/test/unit/safe-views.test.js +0 -171
  493. package/dist/test/unit/schema-drift-check.test.d.ts +0 -1
  494. package/dist/test/unit/schema-drift-check.test.js +0 -176
  495. package/dist/test/unit/sensitive-guard.test.d.ts +0 -1
  496. package/dist/test/unit/sensitive-guard.test.js +0 -104
  497. package/dist/test/unit/subgoal-sync.test.d.ts +0 -1
  498. package/dist/test/unit/subgoal-sync.test.js +0 -183
  499. package/dist/test/unit/sync-file.test.d.ts +0 -1
  500. package/dist/test/unit/sync-file.test.js +0 -154
  501. package/dist/test/unit/tool-invocation-guard.test.d.ts +0 -1
  502. package/dist/test/unit/tool-invocation-guard.test.js +0 -432
  503. package/dist/test/unit/tool-usage-stats.test.d.ts +0 -1
  504. package/dist/test/unit/tool-usage-stats.test.js +0 -300
  505. package/dist/test/unit/toolSearch.test.d.ts +0 -1
  506. package/dist/test/unit/toolSearch.test.js +0 -571
  507. package/dist/test/unit/watcher-status.test.d.ts +0 -1
  508. package/dist/test/unit/watcher-status.test.js +0 -169
  509. package/dist/test/unit/worktree-manager.test.d.ts +0 -1
  510. package/dist/test/unit/worktree-manager.test.js +0 -176
  511. package/dist/tools/applyPatch.js +0 -41
  512. package/dist/tools/cancelTask.d.ts +0 -30
  513. package/dist/tools/cancelTask.js +0 -64
  514. package/dist/tools/evidencePack.js +0 -168
  515. package/dist/tools/finalizeDirectSession.js +0 -84
  516. package/dist/tools/goalSubgoalTask.js +0 -110
  517. package/dist/tools/killTask.d.ts +0 -15
  518. package/dist/tools/retryTask.js +0 -45
  519. package/dist/tools/runVerification.js +0 -36
  520. package/dist/tools/syncFile.js +0 -65
  521. package/docs/control-center/control-center-daily-driver.md +0 -211
  522. package/docs/control-center/control-center-mvp.md +0 -205
  523. package/docs/control-center/control-center-phase2.md +0 -159
  524. package/docs/release-v0.6.0.md +0 -71
  525. package/docs/release-v0.6.1.md +0 -75
  526. package/docs/release-v0.6.4.md +0 -45
  527. package/src/test/unit/acceptance-engine.test.ts +0 -261
  528. package/src/test/unit/agent-router.test.ts +0 -342
  529. package/src/test/unit/android-doctor.test.ts +0 -158
  530. package/src/test/unit/audit-checks.test.ts +0 -567
  531. package/src/test/unit/chinese-path.test.ts +0 -106
  532. package/src/test/unit/command-guard.test.ts +0 -221
  533. package/src/test/unit/diagnose-task.test.ts +0 -544
  534. package/src/test/unit/direct-guards.test.ts +0 -297
  535. package/src/test/unit/discovery-token-store.test.ts +0 -181
  536. package/src/test/unit/evidence-pack.test.ts +0 -142
  537. package/src/test/unit/goal-graph.test.ts +0 -347
  538. package/src/test/unit/goal-progress.test.ts +0 -538
  539. package/src/test/unit/goal-status.test.ts +0 -270
  540. package/src/test/unit/goal-store.test.ts +0 -318
  541. package/src/test/unit/goal-subgoal-task.test.ts +0 -72
  542. package/src/test/unit/goal-tools-registry.test.ts +0 -243
  543. package/src/test/unit/handoff-export.test.ts +0 -295
  544. package/src/test/unit/invoke-discovered-tool.test.ts +0 -216
  545. package/src/test/unit/logging.test.ts +0 -497
  546. package/src/test/unit/path-guard.test.ts +0 -150
  547. package/src/test/unit/post-task-cleanup.test.ts +0 -53
  548. package/src/test/unit/project-policy-release-mode.test.ts +0 -156
  549. package/src/test/unit/reconcile-tasks.test.ts +0 -551
  550. package/src/test/unit/release-gate.test.ts +0 -314
  551. package/src/test/unit/run-task-loop.test.ts +0 -425
  552. package/src/test/unit/safe-status.test.ts +0 -187
  553. package/src/test/unit/safe-views.test.ts +0 -184
  554. package/src/test/unit/schema-drift-check.test.ts +0 -260
  555. package/src/test/unit/sensitive-guard.test.ts +0 -124
  556. package/src/test/unit/subgoal-sync.test.ts +0 -236
  557. package/src/test/unit/sync-file.test.ts +0 -231
  558. package/src/test/unit/tool-invocation-guard.test.ts +0 -542
  559. package/src/test/unit/tool-usage-stats.test.ts +0 -384
  560. package/src/test/unit/toolSearch.test.ts +0 -756
  561. package/src/test/unit/watcher-status.test.ts +0 -190
  562. package/src/test/unit/worktree-manager.test.ts +0 -247
  563. package/src/tools/cancelTask.ts +0 -70
  564. package/src/tools/evidencePack.ts +0 -205
  565. package/src/tools/retryTask.ts +0 -53
  566. package/src/tools/syncFile.ts +0 -122
  567. /package/dist/tools/{toolCatalog.d.ts → catalog/toolCatalog.d.ts} +0 -0
  568. /package/dist/tools/{toolSearch.d.ts → catalog/toolSearch.d.ts} +0 -0
  569. /package/dist/tools/{toolSearch.js → catalog/toolSearch.js} +0 -0
  570. /package/dist/tools/{toolUsageStats.d.ts → catalog/toolUsageStats.d.ts} +0 -0
  571. /package/dist/tools/{toolUsageStats.js → catalog/toolUsageStats.js} +0 -0
  572. /package/dist/tools/{runDirectVerificationBundle.d.ts → direct/runDirectVerificationBundle.d.ts} +0 -0
  573. /package/dist/tools/{getPlan.d.ts → goals/getPlan.d.ts} +0 -0
  574. /package/dist/tools/{savePlan.d.ts → goals/savePlan.d.ts} +0 -0
  575. /package/dist/tools/{getTaskFile.d.ts → tasks/getTaskFile.d.ts} +0 -0
  576. /package/dist/tools/{getTaskProgress.d.ts → tasks/getTaskProgress.d.ts} +0 -0
  577. /package/dist/tools/{getTaskProgress.js → tasks/getTaskProgress.js} +0 -0
  578. /package/dist/tools/{getTaskStdoutTail.d.ts → tasks/getTaskStdoutTail.d.ts} +0 -0
  579. /package/dist/tools/{getTaskSummary.d.ts → tasks/getTaskSummary.d.ts} +0 -0
  580. /package/dist/tools/{killTask.js → tasks/killTask.js} +0 -0
  581. /package/dist/tools/{runVerification.d.ts → tasks/runVerification.d.ts} +0 -0
  582. /package/dist/tools/{taskLineage.d.ts → tasks/taskLineage.d.ts} +0 -0
  583. /package/dist/tools/{taskOutputs.d.ts → tasks/taskOutputs.d.ts} +0 -0
  584. /package/dist/tools/{waitForTask.d.ts → tasks/waitForTask.d.ts} +0 -0
  585. /package/dist/tools/{waitForTask.js → tasks/waitForTask.js} +0 -0
  586. /package/dist/tools/{androidDoctor.d.ts → workspace/androidDoctor.d.ts} +0 -0
  587. /package/dist/tools/{discardWorktree.d.ts → workspace/discardWorktree.d.ts} +0 -0
  588. /package/dist/tools/{listWorkspace.d.ts → workspace/listWorkspace.d.ts} +0 -0
  589. /package/dist/tools/{mergeWorktree.d.ts → workspace/mergeWorktree.d.ts} +0 -0
  590. /package/dist/tools/{readWorkspaceFile.d.ts → workspace/readWorkspaceFile.d.ts} +0 -0
  591. /package/dist/tools/{recommendAgentForTask.d.ts → workspace/recommendAgentForTask.d.ts} +0 -0
  592. /package/dist/tools/{searchWorkspace.d.ts → workspace/searchWorkspace.d.ts} +0 -0
  593. /package/src/tools/{toolSearch.ts → catalog/toolSearch.ts} +0 -0
  594. /package/src/tools/{toolUsageStats.ts → catalog/toolUsageStats.ts} +0 -0
  595. /package/src/tools/{getTaskProgress.ts → tasks/getTaskProgress.ts} +0 -0
  596. /package/src/tools/{killTask.ts → tasks/killTask.ts} +0 -0
  597. /package/src/tools/{waitForTask.ts → tasks/waitForTask.ts} +0 -0
@@ -89,6 +89,58 @@ function Read-FileLineSafe {
89
89
  }
90
90
  }
91
91
 
92
+ function Write-JsonFileAtomic {
93
+ param([string]$Path, [object]$Payload)
94
+ $directory = Split-Path -Parent $Path
95
+ New-Item -ItemType Directory -Force -Path $directory | Out-Null
96
+ $temporary = "$Path.tmp"
97
+ $Payload | ConvertTo-Json -Depth 5 | Set-Content -LiteralPath $temporary -Encoding UTF8
98
+ Move-Item -LiteralPath $temporary -Destination $Path -Force
99
+ }
100
+
101
+ function Write-BackgroundStartingState {
102
+ param($Definition)
103
+ $statusPath = Join-Path $Definition.RuntimeDirectory "tunnel-status.json"
104
+ $previous = Read-JsonFileSafe -Path $statusPath
105
+ $payload = [ordered]@{
106
+ status = "starting"
107
+ reason_code = $null
108
+ ready = $false
109
+ attempt = 0
110
+ pid = $null
111
+ checked_at = (Get-Date).ToUniversalTime().ToString("o")
112
+ next_retry_at = $null
113
+ last_error = $null
114
+ last_exit_code = $null
115
+ stdout_tail = @()
116
+ stderr_tail = @()
117
+ stdout_log = Join-Path $Definition.RuntimeDirectory "tunnel-client.stdout.log"
118
+ stderr_log = Join-Path $Definition.RuntimeDirectory "tunnel-client.stderr.log"
119
+ server_version = if ($previous) { $previous.server_version } else { $null }
120
+ schema_epoch = if ($previous) { $previous.schema_epoch } else { $null }
121
+ tool_profile = $Definition.ToolProfile
122
+ tool_count = if ($previous) { $previous.tool_count } else { $null }
123
+ tool_names = if ($previous -and $previous.tool_names) { @($previous.tool_names) } else { @() }
124
+ tool_manifest_sha256 = if ($previous) { $previous.tool_manifest_sha256 } else { $null }
125
+ tools_ready = [bool]($previous -and $previous.tools_ready)
126
+ core_tools_ready = [bool]($Definition.Key -eq "core" -and $previous -and $previous.core_tools_ready)
127
+ }
128
+ Write-JsonFileAtomic -Path $statusPath -Payload $payload
129
+ }
130
+
131
+ function Write-BackgroundSupervisorState {
132
+ param($Definition, [string]$Status, [Nullable[int]]$ProcessId, [string]$ReasonCode = $null)
133
+ $payload = [ordered]@{
134
+ status = $Status
135
+ reason_code = $ReasonCode
136
+ pid = $ProcessId
137
+ checked_at = (Get-Date).ToUniversalTime().ToString("o")
138
+ stdout_log = Join-Path $Definition.RuntimeDirectory "supervisor.stdout.log"
139
+ stderr_log = Join-Path $Definition.RuntimeDirectory "supervisor.stderr.log"
140
+ }
141
+ Write-JsonFileAtomic -Path (Join-Path $Definition.RuntimeDirectory "supervisor-status.json") -Payload $payload
142
+ }
143
+
92
144
  function Test-TunnelHealthEndpoint {
93
145
  param([string]$HealthUrl)
94
146
  if (-not $HealthUrl) { return $null }
@@ -522,20 +574,33 @@ function Start-Mode {
522
574
  if ($Background) {
523
575
  $launcherScript = Join-Path $PSScriptRoot "start-patchwarden-tunnel.ps1"
524
576
  if (-not (Test-Path -LiteralPath $launcherScript)) { throw "Launcher script not found: $launcherScript" }
577
+ $backgroundWrapper = Join-Path $PSScriptRoot "run-background-supervisor.ps1"
578
+ if (-not (Test-Path -LiteralPath $backgroundWrapper)) { throw "Background wrapper not found: $backgroundWrapper" }
525
579
  $healthListenAddr = ([Uri]$Definition.HealthBaseUrl).Authority
526
580
  $arguments = @(
527
- "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $launcherScript,
581
+ "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $backgroundWrapper,
528
582
  "-ToolProfile", $Definition.ToolProfile,
529
583
  "-Profile", $Definition.Profile,
530
- "-HealthListenAddr", $healthListenAddr,
531
- "-NoTunnelWebUi"
584
+ "-HealthListenAddr", $healthListenAddr
532
585
  )
533
586
  if (-not $Definition.HasWatcher) { $arguments += "-SkipWatcher" }
534
587
  if ($WhatIf) {
535
588
  Write-Host "[start:$($Definition.Key)] WHAT-IF: start hidden supervisor for $($Definition.Profile)" -ForegroundColor Magenta
536
589
  return
537
590
  }
538
- $process = Start-Process -FilePath "powershell.exe" -ArgumentList $arguments -WorkingDirectory $ProjectRoot -PassThru -WindowStyle Hidden
591
+ New-Item -ItemType Directory -Force -Path $Definition.RuntimeDirectory | Out-Null
592
+ $supervisorStdout = Join-Path $Definition.RuntimeDirectory "supervisor.stdout.log"
593
+ $supervisorStderr = Join-Path $Definition.RuntimeDirectory "supervisor.stderr.log"
594
+ Write-BackgroundStartingState -Definition $Definition
595
+ Set-Content -LiteralPath $supervisorStdout -Value "" -Encoding UTF8 -NoNewline
596
+ Set-Content -LiteralPath $supervisorStderr -Value "" -Encoding UTF8 -NoNewline
597
+ try {
598
+ $process = Start-Process -FilePath "powershell.exe" -ArgumentList $arguments -WorkingDirectory $ProjectRoot -PassThru -WindowStyle Hidden
599
+ Write-BackgroundSupervisorState -Definition $Definition -Status "running" -ProcessId $process.Id
600
+ } catch {
601
+ Write-BackgroundSupervisorState -Definition $Definition -Status "failed" -ProcessId $null -ReasonCode "supervisor_launch_failed"
602
+ throw
603
+ }
539
604
  Write-Host "[start:$($Definition.Key)] Started hidden supervisor PID $($process.Id). Logs: $($Definition.RuntimeDirectory)" -ForegroundColor Green
540
605
  return
541
606
  }
@@ -0,0 +1,127 @@
1
+ [CmdletBinding()]
2
+ param(
3
+ [Parameter(Mandatory = $true)]
4
+ [ValidateSet("core", "direct")]
5
+ [string]$Mode,
6
+ [AllowEmptyString()]
7
+ [string]$TunnelId = "",
8
+ [Parameter(Mandatory = $true)]
9
+ [string]$TunnelClientExe,
10
+ [Parameter(Mandatory = $true)]
11
+ [string]$ConfigPath,
12
+ [Parameter(Mandatory = $true)]
13
+ [string]$CredentialPath,
14
+ [ValidateSet("environment", "none", "manual")]
15
+ [string]$ProxyMode = "environment",
16
+ [AllowEmptyString()]
17
+ [string]$ProxyUrl = "",
18
+ [switch]$UseSavedCredential
19
+ )
20
+
21
+ $ErrorActionPreference = "Stop"
22
+ $ProjectRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
23
+ $Profile = if ($Mode -eq "direct") { "patchwarden-direct" } else { "patchwarden" }
24
+ $ToolProfile = if ($Mode -eq "direct") { "chatgpt_direct" } else { "chatgpt_core" }
25
+ $LauncherName = if ($Mode -eq "direct") { "patchwarden-mcp-direct.cmd" } else { "patchwarden-mcp-stdio.cmd" }
26
+ $HealthListenAddr = if ($Mode -eq "direct") { "127.0.0.1:8081" } else { "127.0.0.1:8080" }
27
+ $ProfilePath = Join-Path $env:APPDATA "tunnel-client\$Profile.yaml"
28
+ $McpLauncher = (Join-Path $ProjectRoot "scripts\mcp\$LauncherName") -replace "\\", "/"
29
+ $profileBackup = "$ProfilePath.patchwarden-provision-backup-$PID"
30
+ $hadProfile = Test-Path -LiteralPath $ProfilePath
31
+ $runtimeKey = $null
32
+
33
+ function Write-Result {
34
+ param([bool]$Ok, [string]$ReasonCode, [string]$NextStep)
35
+ [ordered]@{ ok = $Ok; reason_code = $ReasonCode; next_step = $NextStep } | ConvertTo-Json -Compress
36
+ }
37
+
38
+ function Get-DoctorReason {
39
+ param([string]$Text)
40
+ $value = [string]$Text
41
+ if ($value -match '(?i)unauthor|forbidden|invalid.*(?:key|token)|authentication|401|403') { return "authentication_failed" }
42
+ if ($value -match '(?i)proxy|ECONNREFUSED|connection refused|connect.*failed|timeout|timed out') { return "proxy_unreachable" }
43
+ if ($value -match '(?i)region|country|unsupported location|not available in') { return "region_unsupported" }
44
+ return "doctor_failed"
45
+ }
46
+
47
+ try {
48
+ if (-not (Test-Path -LiteralPath $TunnelClientExe -PathType Leaf)) { throw "tunnel_client_missing" }
49
+ if (-not (Test-Path -LiteralPath $ConfigPath -PathType Leaf)) { throw "config_missing" }
50
+ if (-not (Test-Path -LiteralPath ($McpLauncher -replace "/", "\") -PathType Leaf)) { throw "mcp_launcher_missing" }
51
+ if ($UseSavedCredential) {
52
+ if (-not (Test-Path -LiteralPath $ProfilePath -PathType Leaf)) { throw "tunnel_profile_missing" }
53
+ if (-not (Test-Path -LiteralPath $CredentialPath -PathType Leaf)) { throw "tunnel_credential_missing" }
54
+ $secure = ConvertTo-SecureString (Get-Content -LiteralPath $CredentialPath -Raw -Encoding UTF8)
55
+ $bstr = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
56
+ try { $runtimeKey = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) }
57
+ finally { if ($bstr -ne [IntPtr]::Zero) { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } }
58
+ } else {
59
+ if ([string]::IsNullOrWhiteSpace($TunnelId)) { throw "tunnel_id_missing" }
60
+ $runtimeKey = [Console]::In.ReadLine()
61
+ }
62
+ if ([string]::IsNullOrWhiteSpace($runtimeKey)) { throw "runtime_key_missing" }
63
+ $env:CONTROL_PLANE_API_KEY = $runtimeKey
64
+ $env:PATCHWARDEN_CONFIG = $ConfigPath
65
+ $env:NO_PROXY = "localhost,127.0.0.1,::1"
66
+
67
+ $useProxy = $false
68
+ switch ($ProxyMode) {
69
+ "manual" {
70
+ $proxyUri = $null
71
+ if (-not [Uri]::TryCreate($ProxyUrl, [UriKind]::Absolute, [ref]$proxyUri) -or $proxyUri.Scheme -notin @("http", "https", "socks5")) { throw "proxy_invalid" }
72
+ if (-not [string]::IsNullOrEmpty($proxyUri.UserInfo)) { throw "proxy_credentials_forbidden" }
73
+ $env:HTTP_PROXY = $ProxyUrl; $env:HTTPS_PROXY = $ProxyUrl; $env:ALL_PROXY = $ProxyUrl
74
+ $useProxy = $true
75
+ }
76
+ "none" { Remove-Item Env:HTTP_PROXY, Env:HTTPS_PROXY, Env:ALL_PROXY -ErrorAction SilentlyContinue }
77
+ "environment" { $useProxy = -not [string]::IsNullOrWhiteSpace($env:HTTPS_PROXY) }
78
+ }
79
+
80
+ if (-not $UseSavedCredential) {
81
+ New-Item -ItemType Directory -Force -Path (Split-Path -Parent $ProfilePath) | Out-Null
82
+ if ($hadProfile) { Copy-Item -LiteralPath $ProfilePath -Destination $profileBackup -Force }
83
+ & $TunnelClientExe init --sample sample_mcp_stdio_local --profile $Profile --tunnel-id $TunnelId --mcp-command $McpLauncher --force | Out-Null
84
+ if ($LASTEXITCODE -ne 0) { throw "profile_init_failed" }
85
+
86
+ $profileText = Get-Content -LiteralPath $ProfilePath -Raw -Encoding UTF8
87
+ if ($profileText -match 'listen_addr:\s*"[^"]*"') {
88
+ $profileText = $profileText -replace '(listen_addr:\s*)"[^"]*"', "`$1`"$HealthListenAddr`""
89
+ } elseif ($profileText -match '(?m)^health:') {
90
+ $profileText = $profileText -replace '(?m)^(health:.*)$', "`$1`n listen_addr: `"$HealthListenAddr`""
91
+ } else {
92
+ $profileText = "$($profileText.TrimEnd())`n`nhealth:`n listen_addr: `"$HealthListenAddr`"`n"
93
+ }
94
+ Set-Content -LiteralPath $ProfilePath -Value $profileText -Encoding UTF8 -NoNewline
95
+ }
96
+
97
+ $doctorArgs = @("doctor", "--profile", $Profile, "--explain", "--json")
98
+ if ($useProxy) { $doctorArgs += @("--http-proxy", "env:HTTPS_PROXY") }
99
+ $doctorOutput = (& $TunnelClientExe @doctorArgs 2>&1 | Out-String)
100
+ if ($LASTEXITCODE -ne 0) { throw (Get-DoctorReason -Text $doctorOutput) }
101
+
102
+ if (-not $UseSavedCredential) {
103
+ $secure = ConvertTo-SecureString $runtimeKey -AsPlainText -Force
104
+ $encrypted = ConvertFrom-SecureString $secure
105
+ $credentialDirectory = Split-Path -Parent $CredentialPath
106
+ New-Item -ItemType Directory -Force -Path $credentialDirectory | Out-Null
107
+ $credentialTemp = "$CredentialPath.tmp-$PID"
108
+ Set-Content -LiteralPath $credentialTemp -Value $encrypted -Encoding UTF8 -NoNewline
109
+ Move-Item -LiteralPath $credentialTemp -Destination $CredentialPath -Force
110
+ }
111
+ Remove-Item -LiteralPath $profileBackup -Force -ErrorAction SilentlyContinue
112
+ Write-Result -Ok $true -ReasonCode "configured" -NextStep "start_core"
113
+ exit 0
114
+ } catch {
115
+ if ($hadProfile -and (Test-Path -LiteralPath $profileBackup)) {
116
+ Move-Item -LiteralPath $profileBackup -Destination $ProfilePath -Force
117
+ } elseif (-not $hadProfile) {
118
+ Remove-Item -LiteralPath $ProfilePath -Force -ErrorAction SilentlyContinue
119
+ }
120
+ $reason = [string]$_.Exception.Message
121
+ if ($reason -notmatch '^[a-z0-9_]+$') { $reason = "provisioning_failed" }
122
+ Write-Result -Ok $false -ReasonCode $reason -NextStep $(if ($reason -eq "authentication_failed") { "replace_runtime_key" } elseif ($reason -eq "proxy_unreachable") { "check_proxy" } else { "review_tunnel_setup" })
123
+ exit 1
124
+ } finally {
125
+ $env:CONTROL_PLANE_API_KEY = $null
126
+ $runtimeKey = $null
127
+ }
@@ -0,0 +1,41 @@
1
+ [CmdletBinding()]
2
+ param(
3
+ [Parameter(Mandatory = $true)]
4
+ [ValidateSet("chatgpt_core", "chatgpt_direct")]
5
+ [string]$ToolProfile,
6
+
7
+ [Parameter(Mandatory = $true)]
8
+ [ValidateSet("patchwarden", "patchwarden-direct")]
9
+ [string]$Profile,
10
+
11
+ [Parameter(Mandatory = $true)]
12
+ [ValidatePattern('^127\.0\.0\.1:\d+$')]
13
+ [string]$HealthListenAddr,
14
+
15
+ [switch]$SkipWatcher
16
+ )
17
+
18
+ $ErrorActionPreference = "Stop"
19
+ $launcherScript = Join-Path $PSScriptRoot "start-patchwarden-tunnel.ps1"
20
+ $runtimeName = if ($ToolProfile -eq "chatgpt_direct") { "runtime-direct" } else { "runtime" }
21
+ $runtimeDirectory = Join-Path $env:LOCALAPPDATA "patchwarden\$runtimeName"
22
+ $stdout = Join-Path $runtimeDirectory "supervisor.stdout.log"
23
+ $stderr = Join-Path $runtimeDirectory "supervisor.stderr.log"
24
+
25
+ New-Item -ItemType Directory -Force -Path $runtimeDirectory | Out-Null
26
+ $arguments = @(
27
+ "-NoProfile", "-ExecutionPolicy", "Bypass", "-File", $launcherScript,
28
+ "-ToolProfile", $ToolProfile,
29
+ "-Profile", $Profile,
30
+ "-HealthListenAddr", $HealthListenAddr,
31
+ "-NoTunnelWebUi"
32
+ )
33
+ if ($SkipWatcher) { $arguments += "-SkipWatcher" }
34
+
35
+ try {
36
+ & powershell.exe @arguments 1> $stdout 2> $stderr
37
+ exit $LASTEXITCODE
38
+ } catch {
39
+ $_ | Out-String | Set-Content -LiteralPath $stderr -Encoding UTF8
40
+ exit 1
41
+ }
@@ -3,7 +3,10 @@
3
3
  [string]$Profile = "patchwarden",
4
4
  [ValidateSet("chatgpt_core", "chatgpt_direct")]
5
5
  [string]$ToolProfile = "chatgpt_core",
6
- [string]$ProxyUrl = $(if ($env:HTTPS_PROXY) { $env:HTTPS_PROXY } else { "http://127.0.0.1:7892" }),
6
+ [ValidateSet("", "environment", "none", "manual")]
7
+ [string]$ProxyMode = "",
8
+ [AllowEmptyString()]
9
+ [string]$ProxyUrl = "",
7
10
  [string]$TunnelClientExe = $(if ($env:TUNNEL_CLIENT_EXE) { $env:TUNNEL_CLIENT_EXE } else { $env:PATCHWARDEN_TUNNEL_CLIENT_EXE }),
8
11
  [string]$OpencodeBin = $env:OPENCODE_BIN_DIR,
9
12
  [string]$ConfigPath = $env:PATCHWARDEN_CONFIG,
@@ -22,6 +25,47 @@
22
25
 
23
26
  $ErrorActionPreference = "Stop"
24
27
 
28
+ if ([string]::IsNullOrWhiteSpace($ProxyMode)) {
29
+ $ProxyMode = if ($ToolProfile -eq "chatgpt_direct" -and $env:PATCHWARDEN_DIRECT_PROXY_MODE) {
30
+ $env:PATCHWARDEN_DIRECT_PROXY_MODE
31
+ } elseif ($env:PATCHWARDEN_TUNNEL_PROXY_MODE) {
32
+ $env:PATCHWARDEN_TUNNEL_PROXY_MODE
33
+ } else {
34
+ "environment"
35
+ }
36
+ }
37
+ if ([string]::IsNullOrWhiteSpace($ProxyUrl)) {
38
+ $ProxyUrl = if ($ToolProfile -eq "chatgpt_direct" -and $env:PATCHWARDEN_DIRECT_PROXY_URL) {
39
+ $env:PATCHWARDEN_DIRECT_PROXY_URL
40
+ } else {
41
+ $env:PATCHWARDEN_TUNNEL_PROXY_URL
42
+ }
43
+ }
44
+
45
+ $script:UseProxyArgument = $false
46
+ switch ($ProxyMode) {
47
+ "manual" {
48
+ if ([string]::IsNullOrWhiteSpace($ProxyUrl)) { throw "Manual proxy mode requires ProxyUrl." }
49
+ $proxyUri = $null
50
+ if (-not [Uri]::TryCreate($ProxyUrl, [UriKind]::Absolute, [ref]$proxyUri) -or $proxyUri.Scheme -notin @("http", "https", "socks5")) {
51
+ throw "ProxyUrl must use http, https, or socks5."
52
+ }
53
+ if (-not [string]::IsNullOrEmpty($proxyUri.UserInfo)) { throw "ProxyUrl must not contain credentials." }
54
+ $env:HTTP_PROXY = $ProxyUrl
55
+ $env:HTTPS_PROXY = $ProxyUrl
56
+ $env:ALL_PROXY = $ProxyUrl
57
+ $script:UseProxyArgument = $true
58
+ }
59
+ "none" {
60
+ Remove-Item Env:HTTP_PROXY, Env:HTTPS_PROXY, Env:ALL_PROXY -ErrorAction SilentlyContinue
61
+ }
62
+ "environment" {
63
+ $script:UseProxyArgument = -not [string]::IsNullOrWhiteSpace($env:HTTPS_PROXY)
64
+ }
65
+ default { throw "Unsupported proxy mode: $ProxyMode" }
66
+ }
67
+ $env:NO_PROXY = "localhost,127.0.0.1,::1"
68
+
25
69
  if ([string]::IsNullOrWhiteSpace($HealthListenAddr)) {
26
70
  if ($Profile -eq "patchwarden-direct" -or $ToolProfile -eq "chatgpt_direct") {
27
71
  $HealthListenAddr = "127.0.0.1:8081"
@@ -58,12 +102,35 @@ $script:WatcherManaged = $false
58
102
  $script:WatcherRestartAttempts = 0
59
103
  $script:WatcherHealthySince = $null
60
104
  $script:WatcherRestartExhausted = $false
61
- $DefaultTunnelClientPath = "D:\ai_agent\tunnel-client-v0.0.9--context-conduit-topaz-windows-amd64\tunnel-client.exe"
62
-
63
105
  if ($ToolProfile -eq "chatgpt_direct") {
64
106
  $SkipWatcher = $true
65
107
  }
66
108
 
109
+ $script:AgentEnvironmentNames = @(
110
+ ([string]$env:PATCHWARDEN_AGENT_ENV_ALLOWLIST -split ';') |
111
+ Where-Object { $_ -match '^[A-Za-z_][A-Za-z0-9_]*$' } |
112
+ Select-Object -Unique
113
+ )
114
+
115
+ function Suspend-AgentProviderEnvironment {
116
+ $saved = @{}
117
+ foreach ($name in $script:AgentEnvironmentNames) {
118
+ $item = Get-Item -LiteralPath "Env:$name" -ErrorAction SilentlyContinue
119
+ if ($null -ne $item) {
120
+ $saved[$name] = [string]$item.Value
121
+ Remove-Item -LiteralPath "Env:$name" -ErrorAction SilentlyContinue
122
+ }
123
+ }
124
+ return $saved
125
+ }
126
+
127
+ function Restore-AgentProviderEnvironment {
128
+ param([hashtable]$Saved)
129
+ foreach ($name in $Saved.Keys) {
130
+ Set-Item -LiteralPath "Env:$name" -Value $Saved[$name]
131
+ }
132
+ }
133
+
67
134
  function Assert-File {
68
135
  param([string]$Path, [string]$Name)
69
136
  if (-not (Test-Path -LiteralPath $Path)) {
@@ -230,9 +297,17 @@ function Get-DiagnosticCode {
230
297
  }
231
298
 
232
299
  function Invoke-TunnelDoctor {
233
- $output = (& $TunnelClientExe doctor --profile $Profile --explain --json --http-proxy env:HTTPS_PROXY 2>&1 | Out-String)
300
+ $doctorArguments = @("doctor", "--profile", $Profile, "--explain", "--json")
301
+ if ($script:UseProxyArgument) { $doctorArguments += @("--http-proxy", "env:HTTPS_PROXY") }
302
+ $savedAgentEnvironment = Suspend-AgentProviderEnvironment
303
+ try {
304
+ $output = (& $TunnelClientExe @doctorArguments 2>&1 | Out-String)
305
+ $exitCode = $LASTEXITCODE
306
+ } finally {
307
+ Restore-AgentProviderEnvironment -Saved $savedAgentEnvironment
308
+ }
234
309
  return [pscustomobject]@{
235
- ExitCode = $LASTEXITCODE
310
+ ExitCode = $exitCode
236
311
  Output = $output
237
312
  ReasonCode = Get-DiagnosticCode $output
238
313
  }
@@ -306,11 +381,15 @@ function Start-OwnedWatcherProcess {
306
381
  $previousWatcherLauncherPid = $env:PATCHWARDEN_WATCHER_LAUNCHER_PID
307
382
  $previousXdgConfigHome = $env:XDG_CONFIG_HOME
308
383
  $previousPath = $env:PATH
384
+ $previousControlPlaneApiKey = $env:CONTROL_PLANE_API_KEY
385
+ $previousOwnerToken = $env:PATCHWARDEN_OWNER_TOKEN
309
386
  try {
310
387
  $env:PATCHWARDEN_WATCHER_INSTANCE_ID = $script:WatcherInstanceId
311
388
  $env:PATCHWARDEN_WATCHER_LAUNCHER_PID = [string]$PID
312
389
  $env:XDG_CONFIG_HOME = $OpencodeConfigHome
313
390
  if ($OpencodeBin) { $env:PATH = "$OpencodeBin;$env:PATH" }
391
+ Remove-Item Env:CONTROL_PLANE_API_KEY -ErrorAction SilentlyContinue
392
+ Remove-Item Env:PATCHWARDEN_OWNER_TOKEN -ErrorAction SilentlyContinue
314
393
  $script:WatcherProcess = Start-Process -FilePath $node `
315
394
  -ArgumentList @((Join-Path $ProjectRoot "dist\runner\watch.js")) `
316
395
  -WorkingDirectory $ProjectRoot -PassThru -WindowStyle Hidden `
@@ -319,6 +398,8 @@ function Start-OwnedWatcherProcess {
319
398
  if ($null -eq $previousWatcherInstanceId) { Remove-Item Env:PATCHWARDEN_WATCHER_INSTANCE_ID -ErrorAction SilentlyContinue } else { $env:PATCHWARDEN_WATCHER_INSTANCE_ID = $previousWatcherInstanceId }
320
399
  if ($null -eq $previousWatcherLauncherPid) { Remove-Item Env:PATCHWARDEN_WATCHER_LAUNCHER_PID -ErrorAction SilentlyContinue } else { $env:PATCHWARDEN_WATCHER_LAUNCHER_PID = $previousWatcherLauncherPid }
321
400
  if ($null -eq $previousXdgConfigHome) { Remove-Item Env:XDG_CONFIG_HOME -ErrorAction SilentlyContinue } else { $env:XDG_CONFIG_HOME = $previousXdgConfigHome }
401
+ if ($null -eq $previousControlPlaneApiKey) { Remove-Item Env:CONTROL_PLANE_API_KEY -ErrorAction SilentlyContinue } else { $env:CONTROL_PLANE_API_KEY = $previousControlPlaneApiKey }
402
+ if ($null -eq $previousOwnerToken) { Remove-Item Env:PATCHWARDEN_OWNER_TOKEN -ErrorAction SilentlyContinue } else { $env:PATCHWARDEN_OWNER_TOKEN = $previousOwnerToken }
322
403
  $env:PATH = $previousPath
323
404
  }
324
405
  Write-WatcherStatus -Status "starting"
@@ -368,7 +449,12 @@ function Invoke-WatcherSupervisorTick {
368
449
 
369
450
  function Get-TunnelHealth {
370
451
  if (-not (Test-Path -LiteralPath $HealthUrlFile) -or -not (Test-Path -LiteralPath $PidFile)) { return $null }
371
- $output = (& $TunnelClientExe health --json --url-file $HealthUrlFile --pid-file $PidFile 2>&1 | Out-String)
452
+ $savedAgentEnvironment = Suspend-AgentProviderEnvironment
453
+ try {
454
+ $output = (& $TunnelClientExe health --json --url-file $HealthUrlFile --pid-file $PidFile 2>&1 | Out-String)
455
+ } finally {
456
+ Restore-AgentProviderEnvironment -Saved $savedAgentEnvironment
457
+ }
372
458
  try { return $output | ConvertFrom-Json } catch { return $null }
373
459
  }
374
460
 
@@ -505,8 +591,7 @@ if (-not $TunnelClientExe) {
505
591
 
506
592
  # Search common installation locations
507
593
  $commonPaths = @(
508
- $DefaultTunnelClientPath
509
- Join-Path $env:LOCALAPPDATA "patchwarden\tunnel-client.exe"
594
+ Join-Path $env:LOCALAPPDATA "PatchWarden\tunnel-client.exe"
510
595
  Join-Path $env:APPDATA "tunnel-client\tunnel-client.exe"
511
596
  Join-Path $env:USERPROFILE "tunnel-client\tunnel-client.exe"
512
597
  )
@@ -525,11 +610,8 @@ if (-not $TunnelClientExe) {
525
610
  Write-Host "[input] tunnel-client.exe not found on PATH or common locations." -ForegroundColor Yellow
526
611
  Write-Host " Please provide the full path."
527
612
  Write-Host ""
528
- Write-Host " To search for it manually, try one of these commands:" -ForegroundColor Cyan
529
- Write-Host " Get-ChildItem -Path `$env:LOCALAPPDATA -Recurse -Filter tunnel-client.exe -ErrorAction SilentlyContinue" -ForegroundColor Gray
530
- Write-Host " Get-ChildItem -Path `$env:APPDATA -Recurse -Filter tunnel-client.exe -ErrorAction SilentlyContinue" -ForegroundColor Gray
531
- Write-Host " Get-ChildItem -Path C:\ -Recurse -Filter tunnel-client.exe -ErrorAction SilentlyContinue" -ForegroundColor Gray
532
- Write-Host " Or download it from: https://platform.openai.com/docs/guides/mcp-connector" -ForegroundColor Cyan
613
+ Write-Host " Desktop users can open Settings -> MCP and tunnel -> Auto detect / Choose file." -ForegroundColor Cyan
614
+ Write-Host " The desktop guide explains trusted downloads and SHA256 verification." -ForegroundColor Cyan
533
615
  Write-Host ""
534
616
  $TunnelClientExe = Read-Host "Path to tunnel-client.exe"
535
617
  }
@@ -556,7 +638,7 @@ if (-not $TunnelId -and (Test-Path -LiteralPath $ProfilePath)) {
556
638
  $profileContent = Get-Content -LiteralPath $ProfilePath -Raw -Encoding UTF8
557
639
  if ($profileContent -match 'tunnel_id:\s*"([^"]+)"') {
558
640
  $TunnelId = $matches[1]
559
- Write-Host "[detect] Tunnel ID read from profile $Profile`: $TunnelId" -ForegroundColor Green
641
+ Write-Host "[detect] Tunnel ID read from profile $Profile." -ForegroundColor Green
560
642
  }
561
643
  } catch {
562
644
  Write-Host "[warn] Could not read Tunnel ID from $ProfilePath`: $($_.Exception.Message)" -ForegroundColor Yellow
@@ -580,8 +662,15 @@ if (-not (Test-Path -LiteralPath (Join-Path $ProjectRoot "dist\index.js"))) {
580
662
  New-Item -ItemType Directory -Force -Path $RuntimeDirectory | Out-Null
581
663
  $env:PATCHWARDEN_CONFIG = $ConfigPath
582
664
  Write-Host "[manifest] Verifying the exact $ToolProfile stdio MCP tool catalog..."
583
- $manifestOutput = (& node (Join-Path $ProjectRoot "scripts\checks\mcp-manifest-check.js") --profile $ToolProfile --json 2>&1 | Out-String).Trim()
584
- if ($LASTEXITCODE -ne 0) {
665
+ $previousErrorActionPreference = $ErrorActionPreference
666
+ try {
667
+ $ErrorActionPreference = "Continue"
668
+ $manifestOutput = (& node (Join-Path $ProjectRoot "scripts\checks\mcp-manifest-check.js") --profile $ToolProfile --json 2>&1 | Out-String).Trim()
669
+ $manifestExitCode = $LASTEXITCODE
670
+ } finally {
671
+ $ErrorActionPreference = $previousErrorActionPreference
672
+ }
673
+ if ($manifestExitCode -ne 0) {
585
674
  Write-TunnelStatus -Status "stopped" -ReasonCode "tool_manifest_check_failed" -LastError "The tunnel MCP tool manifest preflight failed."
586
675
  throw "Tool manifest preflight failed: $manifestOutput"
587
676
  }
@@ -601,10 +690,6 @@ Write-Host "[config] health listen addr: $HealthListenAddr"
601
690
  Set-SecretEnvIfMissing
602
691
 
603
692
  $env:PATCHWARDEN_CONFIG = $ConfigPath
604
- $env:HTTP_PROXY = $ProxyUrl
605
- $env:HTTPS_PROXY = $ProxyUrl
606
- $env:ALL_PROXY = $ProxyUrl
607
- $env:NO_PROXY = "localhost,127.0.0.1,::1"
608
693
 
609
694
  $profileNeedsInit = $true
610
695
  if (Test-Path -LiteralPath $ProfilePath) {
@@ -614,12 +699,17 @@ if (Test-Path -LiteralPath $ProfilePath) {
614
699
 
615
700
  if ($profileNeedsInit) {
616
701
  Write-Host "[init] Creating tunnel-client profile: $Profile"
617
- & $TunnelClientExe init `
618
- --sample sample_mcp_stdio_local `
619
- --profile $Profile `
620
- --tunnel-id $TunnelId `
621
- --mcp-command $McpStdioLauncherForTunnel `
622
- --force
702
+ $savedAgentEnvironment = Suspend-AgentProviderEnvironment
703
+ try {
704
+ & $TunnelClientExe init `
705
+ --sample sample_mcp_stdio_local `
706
+ --profile $Profile `
707
+ --tunnel-id $TunnelId `
708
+ --mcp-command $McpStdioLauncherForTunnel `
709
+ --force
710
+ } finally {
711
+ Restore-AgentProviderEnvironment -Saved $savedAgentEnvironment
712
+ }
623
713
  Set-ProfileHealthListenAddr -ProfilePath $ProfilePath -HealthListenAddr $HealthListenAddr
624
714
  } else {
625
715
  Set-ProfileHealthListenAddr -ProfilePath $ProfilePath -HealthListenAddr $HealthListenAddr
@@ -628,7 +718,7 @@ if ($profileNeedsInit) {
628
718
  $env:PATCHWARDEN_TUNNEL_STATUS_FILE = $StatusFile
629
719
  if (-not $SkipWatcher) { Start-PatchWardenWatcher }
630
720
 
631
- Write-Host "[doctor] Checking tunnel-client profile through the configured proxy..."
721
+ Write-Host "[doctor] Checking tunnel-client profile (proxy mode: $ProxyMode)..."
632
722
  $preflightAttempt = 0
633
723
  $preflightMaxRetries = 3
634
724
  $doctor = Invoke-TunnelDoctor
@@ -665,8 +755,7 @@ Write-Host "[run-config] health url file: $HealthUrlFile"
665
755
  Write-Host "[run-config] pid file: $PidFile"
666
756
  Write-Host "[run-config] stdout log: $StdoutLogFile"
667
757
  Write-Host "[run-config] stderr log: $StderrLogFile"
668
- Write-Host "[run-config] HTTPS_PROXY: $env:HTTPS_PROXY"
669
- Write-Host "[run-config] HTTP_PROXY: $env:HTTP_PROXY"
758
+ Write-Host "[run-config] proxy mode: $ProxyMode"
670
759
  Write-Host "[run-config] CONTROL_PLANE_API_KEY: $(if ($env:CONTROL_PLANE_API_KEY) { 'set' } else { 'missing' })"
671
760
  Write-Host "[run-config] cwd: $ProjectRoot"
672
761
  Write-Host ""
@@ -681,18 +770,23 @@ try {
681
770
  Write-TunnelStatus -Status "starting" -ReasonCode $null -Ready $false -Attempt $attempt
682
771
  $runArguments = @(
683
772
  "run", "--profile", $Profile,
684
- "--http-proxy", "env:HTTPS_PROXY",
685
773
  "--health.url-file", $HealthUrlFile,
686
774
  "--pid.file", $PidFile,
687
775
  "--log.format", "json"
688
776
  )
777
+ if ($script:UseProxyArgument) { $runArguments += @("--http-proxy", "env:HTTPS_PROXY") }
689
778
  if ($openUi) { $runArguments += "--open-web-ui"; $openUi = $false }
690
779
  $argumentLine = ($runArguments | ForEach-Object { Quote-ProcessArgument $_ }) -join " "
691
780
  Write-Host "[run-config] command: tunnel-client $($runArguments -join ' ')"
692
781
  $redirectedCommand = '""' + $TunnelClientExe + '" ' + $argumentLine + ' 1>"' + $StdoutLogFile + '" 2>"' + $StderrLogFile + '""'
693
782
  $processArgumentLine = '/d /s /c ' + $redirectedCommand
694
- $script:TunnelProcess = Start-Process -FilePath $env:ComSpec -ArgumentList $processArgumentLine `
695
- -WorkingDirectory $ProjectRoot -PassThru -WindowStyle Hidden
783
+ $savedAgentEnvironment = Suspend-AgentProviderEnvironment
784
+ try {
785
+ $script:TunnelProcess = Start-Process -FilePath $env:ComSpec -ArgumentList $processArgumentLine `
786
+ -WorkingDirectory $ProjectRoot -PassThru -WindowStyle Hidden
787
+ } finally {
788
+ Restore-AgentProviderEnvironment -Saved $savedAgentEnvironment
789
+ }
696
790
  Write-TunnelStatus -Status "connecting" -ReasonCode $null -Ready $false -Attempt $attempt -ProcessId $script:TunnelProcess.Id
697
791
  Write-Host "[run] supervised command PID $($script:TunnelProcess.Id), attempt $attempt"
698
792