patchwork-os 0.2.0-beta.1 → 0.2.0-beta.10.canary.95

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 (652) hide show
  1. package/README.bridge.md +14 -14
  2. package/README.md +201 -34
  3. package/deploy/README.md +1 -1
  4. package/deploy/bootstrap-vps.sh +14 -9
  5. package/deploy/deploy-dashboard.sh +25 -1
  6. package/deploy/macos/README.md +153 -0
  7. package/deploy/macos/com.patchwork.bridge.plist.template +54 -0
  8. package/deploy/macos/com.patchwork.tunnel.plist.template +76 -0
  9. package/deploy/macos/install-mac-bridge.sh +244 -0
  10. package/deploy/macos/uninstall-mac-bridge.sh +22 -0
  11. package/dist/activityLog.d.ts +6 -0
  12. package/dist/activityLog.js +63 -26
  13. package/dist/activityLog.js.map +1 -1
  14. package/dist/adapters/claude.js +22 -16
  15. package/dist/adapters/claude.js.map +1 -1
  16. package/dist/adapters/gemini.js +15 -11
  17. package/dist/adapters/gemini.js.map +1 -1
  18. package/dist/adapters/openai.js +9 -9
  19. package/dist/adapters/openai.js.map +1 -1
  20. package/dist/ajv2020.d.ts +25 -0
  21. package/dist/ajv2020.js +33 -0
  22. package/dist/ajv2020.js.map +1 -0
  23. package/dist/analyticsAggregator.js +1 -1
  24. package/dist/analyticsAggregator.js.map +1 -1
  25. package/dist/analyticsConfig.d.ts +29 -0
  26. package/dist/analyticsConfig.js +102 -0
  27. package/dist/analyticsConfig.js.map +1 -0
  28. package/dist/analyticsPrefs.d.ts +38 -2
  29. package/dist/analyticsPrefs.js +148 -23
  30. package/dist/analyticsPrefs.js.map +1 -1
  31. package/dist/analyticsSend.d.ts +17 -1
  32. package/dist/analyticsSend.js +67 -5
  33. package/dist/analyticsSend.js.map +1 -1
  34. package/dist/approvalHttp.d.ts +14 -0
  35. package/dist/approvalHttp.js +212 -9
  36. package/dist/approvalHttp.js.map +1 -1
  37. package/dist/approvalInsights.js +13 -5
  38. package/dist/approvalInsights.js.map +1 -1
  39. package/dist/approvalQueue.d.ts +97 -3
  40. package/dist/approvalQueue.js +193 -19
  41. package/dist/approvalQueue.js.map +1 -1
  42. package/dist/approvalSignals.js +19 -11
  43. package/dist/approvalSignals.js.map +1 -1
  44. package/dist/automation.d.ts +35 -10
  45. package/dist/automation.js +133 -37
  46. package/dist/automation.js.map +1 -1
  47. package/dist/automationSuggestions.js +10 -8
  48. package/dist/automationSuggestions.js.map +1 -1
  49. package/dist/bridge.d.ts +2 -0
  50. package/dist/bridge.js +202 -25
  51. package/dist/bridge.js.map +1 -1
  52. package/dist/bridgeLockDiscovery.d.ts +27 -1
  53. package/dist/bridgeLockDiscovery.js +38 -11
  54. package/dist/bridgeLockDiscovery.js.map +1 -1
  55. package/dist/bridgeToken.js +3 -2
  56. package/dist/bridgeToken.js.map +1 -1
  57. package/dist/claudeDriver.js +23 -8
  58. package/dist/claudeDriver.js.map +1 -1
  59. package/dist/claudeOrchestrator.d.ts +1 -1
  60. package/dist/claudeOrchestrator.js +87 -44
  61. package/dist/claudeOrchestrator.js.map +1 -1
  62. package/dist/commands/analytics.d.ts +8 -0
  63. package/dist/commands/analytics.js +134 -0
  64. package/dist/commands/analytics.js.map +1 -0
  65. package/dist/commands/auditEnv.d.ts +36 -0
  66. package/dist/commands/auditEnv.js +202 -0
  67. package/dist/commands/auditEnv.js.map +1 -0
  68. package/dist/commands/dashboard.js +8 -1
  69. package/dist/commands/dashboard.js.map +1 -1
  70. package/dist/commands/doctor.d.ts +35 -0
  71. package/dist/commands/doctor.js +51 -0
  72. package/dist/commands/doctor.js.map +1 -0
  73. package/dist/commands/install.js +3 -0
  74. package/dist/commands/install.js.map +1 -1
  75. package/dist/commands/launchd.js +15 -16
  76. package/dist/commands/launchd.js.map +1 -1
  77. package/dist/commands/patchworkInit.d.ts +5 -0
  78. package/dist/commands/patchworkInit.js +89 -7
  79. package/dist/commands/patchworkInit.js.map +1 -1
  80. package/dist/commands/recipe.d.ts +110 -0
  81. package/dist/commands/recipe.js +512 -9
  82. package/dist/commands/recipe.js.map +1 -1
  83. package/dist/commands/recipeInstall.js +11 -4
  84. package/dist/commands/recipeInstall.js.map +1 -1
  85. package/dist/commands/shadowScan.d.ts +34 -0
  86. package/dist/commands/shadowScan.js +142 -0
  87. package/dist/commands/shadowScan.js.map +1 -0
  88. package/dist/commands/task.js +2 -2
  89. package/dist/commands/task.js.map +1 -1
  90. package/dist/commands/tools.d.ts +20 -1
  91. package/dist/commands/tools.js +112 -3
  92. package/dist/commands/tools.js.map +1 -1
  93. package/dist/commands/tracesImport.js +21 -4
  94. package/dist/commands/tracesImport.js.map +1 -1
  95. package/dist/commitIssueLinkLog.d.ts +16 -0
  96. package/dist/commitIssueLinkLog.js +110 -24
  97. package/dist/commitIssueLinkLog.js.map +1 -1
  98. package/dist/companions/registry.js +15 -7
  99. package/dist/companions/registry.js.map +1 -1
  100. package/dist/config.d.ts +47 -3
  101. package/dist/config.js +111 -21
  102. package/dist/config.js.map +1 -1
  103. package/dist/connectorRoutes.js +866 -57
  104. package/dist/connectorRoutes.js.map +1 -1
  105. package/dist/connectors/airtable.d.ts +230 -0
  106. package/dist/connectors/airtable.js +700 -0
  107. package/dist/connectors/airtable.js.map +1 -0
  108. package/dist/connectors/asana.js +13 -9
  109. package/dist/connectors/asana.js.map +1 -1
  110. package/dist/connectors/baseConnector.js +25 -3
  111. package/dist/connectors/baseConnector.js.map +1 -1
  112. package/dist/connectors/caldiy.d.ts +137 -0
  113. package/dist/connectors/caldiy.js +424 -0
  114. package/dist/connectors/caldiy.js.map +1 -0
  115. package/dist/connectors/circleci.d.ts +162 -0
  116. package/dist/connectors/circleci.js +576 -0
  117. package/dist/connectors/circleci.js.map +1 -0
  118. package/dist/connectors/cloudflare.d.ts +132 -0
  119. package/dist/connectors/cloudflare.js +622 -0
  120. package/dist/connectors/cloudflare.js.map +1 -0
  121. package/dist/connectors/confluence.js +35 -0
  122. package/dist/connectors/confluence.js.map +1 -1
  123. package/dist/connectors/connectorRedirectUri.d.ts +30 -0
  124. package/dist/connectors/connectorRedirectUri.js +38 -0
  125. package/dist/connectors/connectorRedirectUri.js.map +1 -0
  126. package/dist/connectors/connectorRegistry.d.ts +63 -0
  127. package/dist/connectors/connectorRegistry.js +354 -0
  128. package/dist/connectors/connectorRegistry.js.map +1 -0
  129. package/dist/connectors/datadog.js +33 -4
  130. package/dist/connectors/datadog.js.map +1 -1
  131. package/dist/connectors/discord.js +14 -10
  132. package/dist/connectors/discord.js.map +1 -1
  133. package/dist/connectors/elasticsearch.d.ts +141 -0
  134. package/dist/connectors/elasticsearch.js +601 -0
  135. package/dist/connectors/elasticsearch.js.map +1 -0
  136. package/dist/connectors/figma.d.ts +130 -0
  137. package/dist/connectors/figma.js +387 -0
  138. package/dist/connectors/figma.js.map +1 -0
  139. package/dist/connectors/github.d.ts +17 -0
  140. package/dist/connectors/github.js +53 -2
  141. package/dist/connectors/github.js.map +1 -1
  142. package/dist/connectors/gitlab.js +12 -6
  143. package/dist/connectors/gitlab.js.map +1 -1
  144. package/dist/connectors/gmail.js +72 -21
  145. package/dist/connectors/gmail.js.map +1 -1
  146. package/dist/connectors/googleCalendar.js +8 -8
  147. package/dist/connectors/googleCalendar.js.map +1 -1
  148. package/dist/connectors/googleDocs.d.ts +103 -0
  149. package/dist/connectors/googleDocs.js +409 -0
  150. package/dist/connectors/googleDocs.js.map +1 -0
  151. package/dist/connectors/googleDrive.d.ts +12 -0
  152. package/dist/connectors/googleDrive.js +35 -8
  153. package/dist/connectors/googleDrive.js.map +1 -1
  154. package/dist/connectors/grafana.d.ts +133 -0
  155. package/dist/connectors/grafana.js +478 -0
  156. package/dist/connectors/grafana.js.map +1 -0
  157. package/dist/connectors/jira.d.ts +25 -0
  158. package/dist/connectors/jira.js +227 -1
  159. package/dist/connectors/jira.js.map +1 -1
  160. package/dist/connectors/linear.js +1 -1
  161. package/dist/connectors/linear.js.map +1 -1
  162. package/dist/connectors/mcpOAuth.js +78 -16
  163. package/dist/connectors/mcpOAuth.js.map +1 -1
  164. package/dist/connectors/monday.d.ts +217 -0
  165. package/dist/connectors/monday.js +655 -0
  166. package/dist/connectors/monday.js.map +1 -0
  167. package/dist/connectors/mongodb.d.ts +139 -0
  168. package/dist/connectors/mongodb.js +455 -0
  169. package/dist/connectors/mongodb.js.map +1 -0
  170. package/dist/connectors/oauthStateStore.d.ts +20 -0
  171. package/dist/connectors/oauthStateStore.js +94 -4
  172. package/dist/connectors/oauthStateStore.js.map +1 -1
  173. package/dist/connectors/obsidian.d.ts +83 -0
  174. package/dist/connectors/obsidian.js +441 -0
  175. package/dist/connectors/obsidian.js.map +1 -0
  176. package/dist/connectors/paystack.d.ts +159 -0
  177. package/dist/connectors/paystack.js +607 -0
  178. package/dist/connectors/paystack.js.map +1 -0
  179. package/dist/connectors/pipedrive.d.ts +189 -0
  180. package/dist/connectors/pipedrive.js +559 -0
  181. package/dist/connectors/pipedrive.js.map +1 -0
  182. package/dist/connectors/postgres.d.ts +127 -0
  183. package/dist/connectors/postgres.js +512 -0
  184. package/dist/connectors/postgres.js.map +1 -0
  185. package/dist/connectors/posthog.d.ts +119 -0
  186. package/dist/connectors/posthog.js +479 -0
  187. package/dist/connectors/posthog.js.map +1 -0
  188. package/dist/connectors/redis.d.ts +140 -0
  189. package/dist/connectors/redis.js +571 -0
  190. package/dist/connectors/redis.js.map +1 -0
  191. package/dist/connectors/resend.d.ts +131 -0
  192. package/dist/connectors/resend.js +529 -0
  193. package/dist/connectors/resend.js.map +1 -0
  194. package/dist/connectors/salesforce.d.ts +136 -0
  195. package/dist/connectors/salesforce.js +603 -0
  196. package/dist/connectors/salesforce.js.map +1 -0
  197. package/dist/connectors/secrets.d.ts +51 -0
  198. package/dist/connectors/secrets.js +102 -0
  199. package/dist/connectors/secrets.js.map +1 -0
  200. package/dist/connectors/sendgrid.d.ts +102 -0
  201. package/dist/connectors/sendgrid.js +423 -0
  202. package/dist/connectors/sendgrid.js.map +1 -0
  203. package/dist/connectors/shopify.d.ts +145 -0
  204. package/dist/connectors/shopify.js +502 -0
  205. package/dist/connectors/shopify.js.map +1 -0
  206. package/dist/connectors/slack.d.ts +1 -1
  207. package/dist/connectors/slack.js +61 -9
  208. package/dist/connectors/slack.js.map +1 -1
  209. package/dist/connectors/snowflake.d.ts +119 -0
  210. package/dist/connectors/snowflake.js +615 -0
  211. package/dist/connectors/snowflake.js.map +1 -0
  212. package/dist/connectors/supabase.d.ts +92 -0
  213. package/dist/connectors/supabase.js +630 -0
  214. package/dist/connectors/supabase.js.map +1 -0
  215. package/dist/connectors/todoist.d.ts +117 -0
  216. package/dist/connectors/todoist.js +485 -0
  217. package/dist/connectors/todoist.js.map +1 -0
  218. package/dist/connectors/tokenStorage.js +56 -14
  219. package/dist/connectors/tokenStorage.js.map +1 -1
  220. package/dist/connectors/twilio.d.ts +118 -0
  221. package/dist/connectors/twilio.js +475 -0
  222. package/dist/connectors/twilio.js.map +1 -0
  223. package/dist/connectors/vercel.d.ts +110 -0
  224. package/dist/connectors/vercel.js +479 -0
  225. package/dist/connectors/vercel.js.map +1 -0
  226. package/dist/connectors/webflow.d.ts +118 -0
  227. package/dist/connectors/webflow.js +393 -0
  228. package/dist/connectors/webflow.js.map +1 -0
  229. package/dist/connectors/woocommerce.d.ts +220 -0
  230. package/dist/connectors/woocommerce.js +464 -0
  231. package/dist/connectors/woocommerce.js.map +1 -0
  232. package/dist/crypto.js +7 -2
  233. package/dist/crypto.js.map +1 -1
  234. package/dist/decisionReplay.js +15 -6
  235. package/dist/decisionReplay.js.map +1 -1
  236. package/dist/decisionTraceLog.d.ts +28 -0
  237. package/dist/decisionTraceLog.js +156 -29
  238. package/dist/decisionTraceLog.js.map +1 -1
  239. package/dist/drivers/claude/api.js +5 -4
  240. package/dist/drivers/claude/api.js.map +1 -1
  241. package/dist/drivers/claude/envSanitizer.d.ts +0 -6
  242. package/dist/drivers/claude/envSanitizer.js +17 -2
  243. package/dist/drivers/claude/envSanitizer.js.map +1 -1
  244. package/dist/drivers/claude/streamParser.js +5 -4
  245. package/dist/drivers/claude/streamParser.js.map +1 -1
  246. package/dist/drivers/claude/subprocess.js +22 -3
  247. package/dist/drivers/claude/subprocess.js.map +1 -1
  248. package/dist/drivers/gemini/index.d.ts +22 -0
  249. package/dist/drivers/gemini/index.js +256 -129
  250. package/dist/drivers/gemini/index.js.map +1 -1
  251. package/dist/drivers/local/index.d.ts +17 -0
  252. package/dist/drivers/local/index.js +99 -0
  253. package/dist/drivers/local/index.js.map +1 -1
  254. package/dist/drivers/openai/index.js +30 -2
  255. package/dist/drivers/openai/index.js.map +1 -1
  256. package/dist/extensionClient.d.ts +37 -4
  257. package/dist/extensionClient.js +58 -16
  258. package/dist/extensionClient.js.map +1 -1
  259. package/dist/featureFlags.d.ts +91 -0
  260. package/dist/featureFlags.js +174 -3
  261. package/dist/featureFlags.js.map +1 -1
  262. package/dist/fileLock.js +21 -12
  263. package/dist/fileLock.js.map +1 -1
  264. package/dist/fileLockSync.d.ts +67 -0
  265. package/dist/fileLockSync.js +126 -0
  266. package/dist/fileLockSync.js.map +1 -0
  267. package/dist/fp/activityAnalytics.js +26 -12
  268. package/dist/fp/activityAnalytics.js.map +1 -1
  269. package/dist/fp/automationInterpreter.d.ts +15 -1
  270. package/dist/fp/automationInterpreter.js +217 -82
  271. package/dist/fp/automationInterpreter.js.map +1 -1
  272. package/dist/fp/automationProgram.d.ts +30 -0
  273. package/dist/fp/automationProgram.js.map +1 -1
  274. package/dist/fp/automationState.d.ts +24 -5
  275. package/dist/fp/automationState.js +56 -9
  276. package/dist/fp/automationState.js.map +1 -1
  277. package/dist/fp/automationUtils.js +1 -1
  278. package/dist/fp/automationUtils.js.map +1 -1
  279. package/dist/fp/commandDescription.js +7 -1
  280. package/dist/fp/commandDescription.js.map +1 -1
  281. package/dist/fp/extensionSnapshot.js +8 -2
  282. package/dist/fp/extensionSnapshot.js.map +1 -1
  283. package/dist/fp/interpreterContext.d.ts +66 -1
  284. package/dist/fp/interpreterContext.js +91 -1
  285. package/dist/fp/interpreterContext.js.map +1 -1
  286. package/dist/fp/policyParser.js +29 -1
  287. package/dist/fp/policyParser.js.map +1 -1
  288. package/dist/fsWatchWithFallback.d.ts +36 -0
  289. package/dist/fsWatchWithFallback.js +128 -0
  290. package/dist/fsWatchWithFallback.js.map +1 -0
  291. package/dist/haltPushDispatch.d.ts +33 -0
  292. package/dist/haltPushDispatch.js +103 -0
  293. package/dist/haltPushDispatch.js.map +1 -0
  294. package/dist/httpBodyValidation.d.ts +41 -0
  295. package/dist/httpBodyValidation.js +45 -0
  296. package/dist/httpBodyValidation.js.map +1 -0
  297. package/dist/inboxRoutes.d.ts +22 -0
  298. package/dist/inboxRoutes.js +61 -1
  299. package/dist/inboxRoutes.js.map +1 -1
  300. package/dist/index.js +1053 -76
  301. package/dist/index.js.map +1 -1
  302. package/dist/installGuard.js +6 -2
  303. package/dist/installGuard.js.map +1 -1
  304. package/dist/lockfile.js +31 -4
  305. package/dist/lockfile.js.map +1 -1
  306. package/dist/oauth.d.ts +9 -0
  307. package/dist/oauth.js +33 -0
  308. package/dist/oauth.js.map +1 -1
  309. package/dist/oauthRoutes.d.ts +1 -1
  310. package/dist/oauthRoutes.js +5 -3
  311. package/dist/oauthRoutes.js.map +1 -1
  312. package/dist/orchestrator/childBridgeRegistry.js +29 -11
  313. package/dist/orchestrator/childBridgeRegistry.js.map +1 -1
  314. package/dist/patchworkConfig.d.ts +44 -1
  315. package/dist/patchworkConfig.js +28 -3
  316. package/dist/patchworkConfig.js.map +1 -1
  317. package/dist/pluginLoader.js +10 -1
  318. package/dist/pluginLoader.js.map +1 -1
  319. package/dist/pluginWatcher.js +12 -14
  320. package/dist/pluginWatcher.js.map +1 -1
  321. package/dist/preToolUseHook.js +3 -2
  322. package/dist/preToolUseHook.js.map +1 -1
  323. package/dist/processTree.d.ts +34 -0
  324. package/dist/processTree.js +105 -0
  325. package/dist/processTree.js.map +1 -0
  326. package/dist/prompts.js +3 -3
  327. package/dist/prompts.js.map +1 -1
  328. package/dist/recipeOrchestration.d.ts +9 -0
  329. package/dist/recipeOrchestration.js +341 -24
  330. package/dist/recipeOrchestration.js.map +1 -1
  331. package/dist/recipeRoutes.d.ts +58 -2
  332. package/dist/recipeRoutes.js +744 -115
  333. package/dist/recipeRoutes.js.map +1 -1
  334. package/dist/recipes/RecipeOrchestrator.d.ts +2 -0
  335. package/dist/recipes/RecipeOrchestrator.js +6 -1
  336. package/dist/recipes/RecipeOrchestrator.js.map +1 -1
  337. package/dist/recipes/agentExecutor.d.ts +25 -5
  338. package/dist/recipes/agentExecutor.js.map +1 -1
  339. package/dist/recipes/chainedRunner.d.ts +2 -0
  340. package/dist/recipes/chainedRunner.js +142 -5
  341. package/dist/recipes/chainedRunner.js.map +1 -1
  342. package/dist/recipes/connectorPreflight.d.ts +66 -0
  343. package/dist/recipes/connectorPreflight.js +169 -0
  344. package/dist/recipes/connectorPreflight.js.map +1 -0
  345. package/dist/recipes/dependencyGraph.js +13 -5
  346. package/dist/recipes/dependencyGraph.js.map +1 -1
  347. package/dist/recipes/githubInstallSource.d.ts +128 -0
  348. package/dist/recipes/githubInstallSource.js +206 -0
  349. package/dist/recipes/githubInstallSource.js.map +1 -0
  350. package/dist/recipes/haltCategory.d.ts +119 -0
  351. package/dist/recipes/haltCategory.js +188 -0
  352. package/dist/recipes/haltCategory.js.map +1 -0
  353. package/dist/recipes/idempotencyKey.d.ts +134 -0
  354. package/dist/recipes/idempotencyKey.js +322 -0
  355. package/dist/recipes/idempotencyKey.js.map +1 -0
  356. package/dist/recipes/installer.js +48 -2
  357. package/dist/recipes/installer.js.map +1 -1
  358. package/dist/recipes/judgeSummary.d.ts +50 -0
  359. package/dist/recipes/judgeSummary.js +47 -0
  360. package/dist/recipes/judgeSummary.js.map +1 -0
  361. package/dist/recipes/judgeVerdict.d.ts +48 -0
  362. package/dist/recipes/judgeVerdict.js +174 -0
  363. package/dist/recipes/judgeVerdict.js.map +1 -0
  364. package/dist/recipes/migrations/index.d.ts +9 -0
  365. package/dist/recipes/migrations/index.js +133 -0
  366. package/dist/recipes/migrations/index.js.map +1 -1
  367. package/dist/recipes/names.d.ts +20 -0
  368. package/dist/recipes/names.js +25 -0
  369. package/dist/recipes/names.js.map +1 -1
  370. package/dist/recipes/parser.js +88 -5
  371. package/dist/recipes/parser.js.map +1 -1
  372. package/dist/recipes/replayRun.js +1 -1
  373. package/dist/recipes/replayRun.js.map +1 -1
  374. package/dist/recipes/runBudget.d.ts +70 -0
  375. package/dist/recipes/runBudget.js +109 -0
  376. package/dist/recipes/runBudget.js.map +1 -0
  377. package/dist/recipes/scheduler.d.ts +30 -0
  378. package/dist/recipes/scheduler.js +69 -19
  379. package/dist/recipes/scheduler.js.map +1 -1
  380. package/dist/recipes/schema.d.ts +36 -0
  381. package/dist/recipes/schemaGenerator.js +103 -5
  382. package/dist/recipes/schemaGenerator.js.map +1 -1
  383. package/dist/recipes/stepObservation.js +9 -0
  384. package/dist/recipes/stepObservation.js.map +1 -1
  385. package/dist/recipes/toolRegistry.js +20 -3
  386. package/dist/recipes/toolRegistry.js.map +1 -1
  387. package/dist/recipes/tools/fanOut.d.ts +20 -0
  388. package/dist/recipes/tools/fanOut.js +199 -0
  389. package/dist/recipes/tools/fanOut.js.map +1 -0
  390. package/dist/recipes/tools/file.js +5 -2
  391. package/dist/recipes/tools/file.js.map +1 -1
  392. package/dist/recipes/tools/github.d.ts +1 -1
  393. package/dist/recipes/tools/github.js +75 -1
  394. package/dist/recipes/tools/github.js.map +1 -1
  395. package/dist/recipes/tools/gmail.js +27 -5
  396. package/dist/recipes/tools/gmail.js.map +1 -1
  397. package/dist/recipes/tools/googleDrive.js +64 -0
  398. package/dist/recipes/tools/googleDrive.js.map +1 -1
  399. package/dist/recipes/tools/http.d.ts +10 -0
  400. package/dist/recipes/tools/http.js +176 -0
  401. package/dist/recipes/tools/http.js.map +1 -0
  402. package/dist/recipes/tools/index.d.ts +2 -0
  403. package/dist/recipes/tools/index.js +2 -0
  404. package/dist/recipes/tools/index.js.map +1 -1
  405. package/dist/recipes/tools/slack.js +1 -1
  406. package/dist/recipes/validation.d.ts +17 -0
  407. package/dist/recipes/validation.js +29 -11
  408. package/dist/recipes/validation.js.map +1 -1
  409. package/dist/recipes/workspaceRoot.d.ts +37 -0
  410. package/dist/recipes/workspaceRoot.js +73 -0
  411. package/dist/recipes/workspaceRoot.js.map +1 -0
  412. package/dist/recipes/yamlPositions.d.ts +56 -0
  413. package/dist/recipes/yamlPositions.js +183 -0
  414. package/dist/recipes/yamlPositions.js.map +1 -0
  415. package/dist/recipes/yamlRunner.d.ts +182 -8
  416. package/dist/recipes/yamlRunner.js +877 -217
  417. package/dist/recipes/yamlRunner.js.map +1 -1
  418. package/dist/recipesHttp.d.ts +19 -3
  419. package/dist/recipesHttp.js +67 -11
  420. package/dist/recipesHttp.js.map +1 -1
  421. package/dist/resources.js +21 -13
  422. package/dist/resources.js.map +1 -1
  423. package/dist/runLog.d.ts +58 -5
  424. package/dist/runLog.js +98 -21
  425. package/dist/runLog.js.map +1 -1
  426. package/dist/sanitizeParsedJson.d.ts +39 -0
  427. package/dist/sanitizeParsedJson.js +55 -0
  428. package/dist/sanitizeParsedJson.js.map +1 -0
  429. package/dist/schemas/recipe.v1.json +885 -196
  430. package/dist/server.d.ts +160 -3
  431. package/dist/server.js +1099 -122
  432. package/dist/server.js.map +1 -1
  433. package/dist/sessionCheckpoint.d.ts +8 -0
  434. package/dist/sessionCheckpoint.js +33 -3
  435. package/dist/sessionCheckpoint.js.map +1 -1
  436. package/dist/ssrfGuard.d.ts +16 -0
  437. package/dist/ssrfGuard.js +87 -4
  438. package/dist/ssrfGuard.js.map +1 -1
  439. package/dist/streamableHttp.d.ts +9 -4
  440. package/dist/streamableHttp.js +76 -20
  441. package/dist/streamableHttp.js.map +1 -1
  442. package/dist/telemetry.js +19 -12
  443. package/dist/telemetry.js.map +1 -1
  444. package/dist/testing/shadowRun.d.ts +52 -0
  445. package/dist/testing/shadowRun.js +71 -0
  446. package/dist/testing/shadowRun.js.map +1 -0
  447. package/dist/tools/batchLsp.d.ts +3 -0
  448. package/dist/tools/bridgeDoctor.d.ts +11 -0
  449. package/dist/tools/bridgeDoctor.js +48 -2
  450. package/dist/tools/bridgeDoctor.js.map +1 -1
  451. package/dist/tools/bridgeStatus.d.ts +0 -12
  452. package/dist/tools/bridgeStatus.js +2 -28
  453. package/dist/tools/bridgeStatus.js.map +1 -1
  454. package/dist/tools/cancelClaudeTask.d.ts +1 -0
  455. package/dist/tools/clipboard.d.ts +2 -0
  456. package/dist/tools/closeTabs.d.ts +1 -0
  457. package/dist/tools/codeLens.d.ts +1 -0
  458. package/dist/tools/createIssueFromAIComment.d.ts +1 -0
  459. package/dist/tools/ctxGetTaskContext.d.ts +9 -0
  460. package/dist/tools/ctxGetTaskContext.js +50 -2
  461. package/dist/tools/ctxGetTaskContext.js.map +1 -1
  462. package/dist/tools/ctxQueryTraces.js +32 -24
  463. package/dist/tools/ctxQueryTraces.js.map +1 -1
  464. package/dist/tools/ctxSaveTrace.d.ts +1 -0
  465. package/dist/tools/debug.d.ts +4 -0
  466. package/dist/tools/decorations.d.ts +2 -0
  467. package/dist/tools/detectUnusedCode.js +9 -7
  468. package/dist/tools/detectUnusedCode.js.map +1 -1
  469. package/dist/tools/documentLinks.d.ts +1 -0
  470. package/dist/tools/editText.d.ts +1 -0
  471. package/dist/tools/editText.js +2 -1
  472. package/dist/tools/editText.js.map +1 -1
  473. package/dist/tools/enrichCommit.d.ts +1 -0
  474. package/dist/tools/enrichStackTrace.js +11 -5
  475. package/dist/tools/enrichStackTrace.js.map +1 -1
  476. package/dist/tools/explainDiagnostic.d.ts +1 -0
  477. package/dist/tools/explainSymbol.d.ts +1 -0
  478. package/dist/tools/fileOperations.d.ts +3 -0
  479. package/dist/tools/fileOperations.js +2 -1
  480. package/dist/tools/fileOperations.js.map +1 -1
  481. package/dist/tools/fileWatcher.d.ts +2 -0
  482. package/dist/tools/fileWatcher.js +8 -2
  483. package/dist/tools/fileWatcher.js.map +1 -1
  484. package/dist/tools/findFiles.d.ts +1 -0
  485. package/dist/tools/fixAllLintErrors.d.ts +1 -0
  486. package/dist/tools/fixAllLintErrors.js +10 -5
  487. package/dist/tools/fixAllLintErrors.js.map +1 -1
  488. package/dist/tools/foldingRanges.d.ts +1 -0
  489. package/dist/tools/formatDocument.d.ts +1 -0
  490. package/dist/tools/formatDocument.js +10 -5
  491. package/dist/tools/formatDocument.js.map +1 -1
  492. package/dist/tools/generateTests.d.ts +1 -0
  493. package/dist/tools/getAIComments.d.ts +1 -0
  494. package/dist/tools/getAnalyticsReport.js +5 -1
  495. package/dist/tools/getAnalyticsReport.js.map +1 -1
  496. package/dist/tools/getBufferContent.d.ts +1 -0
  497. package/dist/tools/getChangeImpact.d.ts +1 -0
  498. package/dist/tools/getChangeImpact.js +23 -14
  499. package/dist/tools/getChangeImpact.js.map +1 -1
  500. package/dist/tools/getClaudeTaskStatus.d.ts +1 -0
  501. package/dist/tools/getCodeCoverage.d.ts +1 -0
  502. package/dist/tools/getCodeCoverage.js +32 -14
  503. package/dist/tools/getCodeCoverage.js.map +1 -1
  504. package/dist/tools/getCommitsForIssue.d.ts +1 -0
  505. package/dist/tools/getDebugState.d.ts +1 -0
  506. package/dist/tools/getDiagnostics.js +32 -29
  507. package/dist/tools/getDiagnostics.js.map +1 -1
  508. package/dist/tools/getDiffFromHandoff.js +8 -2
  509. package/dist/tools/getDiffFromHandoff.js.map +1 -1
  510. package/dist/tools/getDocumentSymbols.d.ts +1 -0
  511. package/dist/tools/getGitHotspots.d.ts +1 -0
  512. package/dist/tools/getImportedSignatures.d.ts +1 -0
  513. package/dist/tools/getImportedSignatures.js +18 -14
  514. package/dist/tools/getImportedSignatures.js.map +1 -1
  515. package/dist/tools/getPRTemplate.d.ts +1 -0
  516. package/dist/tools/getProjectContext.js +23 -10
  517. package/dist/tools/getProjectContext.js.map +1 -1
  518. package/dist/tools/getSymbolHistory.d.ts +1 -0
  519. package/dist/tools/getToolCapabilities.d.ts +10 -5
  520. package/dist/tools/getToolCapabilities.js +79 -202
  521. package/dist/tools/getToolCapabilities.js.map +1 -1
  522. package/dist/tools/getTypeSignature.d.ts +1 -0
  523. package/dist/tools/getWorkspaceSettings.d.ts +1 -0
  524. package/dist/tools/gitWrite.d.ts +11 -0
  525. package/dist/tools/github/actions.d.ts +2 -0
  526. package/dist/tools/github/composite.d.ts +3 -0
  527. package/dist/tools/github/issues.d.ts +4 -0
  528. package/dist/tools/github/pr.d.ts +7 -0
  529. package/dist/tools/handoffNote.d.ts +1 -0
  530. package/dist/tools/handoffNote.js +2 -1
  531. package/dist/tools/handoffNote.js.map +1 -1
  532. package/dist/tools/headless/lspClient.js +3 -0
  533. package/dist/tools/headless/lspClient.js.map +1 -1
  534. package/dist/tools/hoverAtCursor.d.ts +1 -0
  535. package/dist/tools/httpClient.d.ts +2 -0
  536. package/dist/tools/httpClient.js +38 -71
  537. package/dist/tools/httpClient.js.map +1 -1
  538. package/dist/tools/inlayHints.d.ts +1 -0
  539. package/dist/tools/launchQuickTask.d.ts +1 -0
  540. package/dist/tools/listClaudeTasks.d.ts +1 -0
  541. package/dist/tools/listClaudeTasks.js +10 -8
  542. package/dist/tools/listClaudeTasks.js.map +1 -1
  543. package/dist/tools/listTerminals.d.ts +1 -0
  544. package/dist/tools/lsp.d.ts +15 -0
  545. package/dist/tools/lsp.js +17 -0
  546. package/dist/tools/lsp.js.map +1 -1
  547. package/dist/tools/navigateToSymbolByName.d.ts +1 -0
  548. package/dist/tools/openDiff.d.ts +1 -0
  549. package/dist/tools/openDiff.js +4 -1
  550. package/dist/tools/openDiff.js.map +1 -1
  551. package/dist/tools/openFile.d.ts +1 -0
  552. package/dist/tools/openFile.js +4 -1
  553. package/dist/tools/openFile.js.map +1 -1
  554. package/dist/tools/openInBrowser.js +6 -1
  555. package/dist/tools/openInBrowser.js.map +1 -1
  556. package/dist/tools/organizeImports.d.ts +1 -0
  557. package/dist/tools/organizeImports.js +5 -3
  558. package/dist/tools/organizeImports.js.map +1 -1
  559. package/dist/tools/performanceReport.js +5 -3
  560. package/dist/tools/performanceReport.js.map +1 -1
  561. package/dist/tools/planPersistence.d.ts +3 -0
  562. package/dist/tools/planPersistence.js +4 -1
  563. package/dist/tools/planPersistence.js.map +1 -1
  564. package/dist/tools/previewEdit.d.ts +1 -0
  565. package/dist/tools/previewEdit.js +15 -4
  566. package/dist/tools/previewEdit.js.map +1 -1
  567. package/dist/tools/recentTracesDigest.js +54 -11
  568. package/dist/tools/recentTracesDigest.js.map +1 -1
  569. package/dist/tools/refactorAnalyze.d.ts +1 -0
  570. package/dist/tools/refactorExtractFunction.js +4 -1
  571. package/dist/tools/refactorExtractFunction.js.map +1 -1
  572. package/dist/tools/refactorPreview.d.ts +1 -0
  573. package/dist/tools/refactorPreview.js +10 -2
  574. package/dist/tools/refactorPreview.js.map +1 -1
  575. package/dist/tools/replaceBlock.d.ts +1 -0
  576. package/dist/tools/replaceBlock.js +2 -1
  577. package/dist/tools/replaceBlock.js.map +1 -1
  578. package/dist/tools/resumeClaudeTask.d.ts +1 -0
  579. package/dist/tools/runClaudeTask.d.ts +1 -0
  580. package/dist/tools/runTests.js +15 -4
  581. package/dist/tools/runTests.js.map +1 -1
  582. package/dist/tools/screenshot.d.ts +1 -0
  583. package/dist/tools/screenshotAndAnnotate.js +6 -2
  584. package/dist/tools/screenshotAndAnnotate.js.map +1 -1
  585. package/dist/tools/searchAndReplace.d.ts +1 -0
  586. package/dist/tools/searchAndReplace.js +17 -7
  587. package/dist/tools/searchAndReplace.js.map +1 -1
  588. package/dist/tools/searchTools.js +20 -19
  589. package/dist/tools/searchTools.js.map +1 -1
  590. package/dist/tools/searchWorkspace.d.ts +1 -0
  591. package/dist/tools/selectionRanges.d.ts +1 -0
  592. package/dist/tools/semanticTokens.d.ts +1 -0
  593. package/dist/tools/signatureHelp.d.ts +1 -0
  594. package/dist/tools/spawnWorkspace.js +15 -7
  595. package/dist/tools/spawnWorkspace.js.map +1 -1
  596. package/dist/tools/terminal.d.ts +6 -0
  597. package/dist/tools/testRunners/pytest.js +6 -2
  598. package/dist/tools/testRunners/pytest.js.map +1 -1
  599. package/dist/tools/testRunners/vitestJest.js +3 -1
  600. package/dist/tools/testRunners/vitestJest.js.map +1 -1
  601. package/dist/tools/testTraceToSource.d.ts +1 -0
  602. package/dist/tools/transaction.d.ts +4 -0
  603. package/dist/tools/transaction.js +4 -1
  604. package/dist/tools/transaction.js.map +1 -1
  605. package/dist/tools/typeHierarchy.d.ts +1 -0
  606. package/dist/tools/utils.d.ts +18 -0
  607. package/dist/tools/utils.js +103 -18
  608. package/dist/tools/utils.js.map +1 -1
  609. package/dist/tools/vscodeCommands.d.ts +2 -0
  610. package/dist/tools/vscodeTasks.d.ts +2 -0
  611. package/dist/tools/workspaceSettings.d.ts +1 -0
  612. package/dist/transport.d.ts +3 -1
  613. package/dist/transport.js +103 -52
  614. package/dist/transport.js.map +1 -1
  615. package/dist/winShim.d.ts +34 -0
  616. package/dist/winShim.js +94 -0
  617. package/dist/winShim.js.map +1 -0
  618. package/dist/wireHaltPushDispatch.d.ts +38 -0
  619. package/dist/wireHaltPushDispatch.js +71 -0
  620. package/dist/wireHaltPushDispatch.js.map +1 -0
  621. package/dist/writeFileAtomic.d.ts +23 -0
  622. package/dist/writeFileAtomic.js +121 -0
  623. package/dist/writeFileAtomic.js.map +1 -0
  624. package/package.json +23 -7
  625. package/scripts/postinstall.mjs +42 -2
  626. package/scripts/smoke/run-all.mjs +213 -0
  627. package/scripts/start-all.mjs +572 -0
  628. package/scripts/start-all.ps1 +209 -0
  629. package/scripts/start-all.sh +73 -17
  630. package/scripts/start-orchestrator.ps1 +158 -0
  631. package/scripts/start-remote.mjs +122 -0
  632. package/templates/automation-policies/recipe-authoring.json +1 -1
  633. package/templates/automation-policies/security-first.json +1 -1
  634. package/templates/automation-policies/strict-lint.json +1 -1
  635. package/templates/automation-policies/test-driven.json +1 -1
  636. package/templates/automation-policy.example.json +1 -1
  637. package/templates/co.patchwork-os.bridge.plist +2 -2
  638. package/templates/recipes/approval-queue-ui-test.yaml +1 -1
  639. package/templates/recipes/ctx-loop-test.yaml +1 -1
  640. package/templates/recipes/fix-errors-on-save.yaml +71 -0
  641. package/templates/recipes/morning-brief.yaml +5 -2
  642. package/templates/recipes/project-health-check.yaml +4 -1
  643. package/templates/recipes/sentry-to-linear.yaml +72 -38
  644. package/templates/recipes/webhook/apple-watch-health-log.yaml +145 -0
  645. package/templates/recipes/webhook/customer-escalation.yaml +8 -9
  646. package/templates/recipes/webhook/meeting-prep.yaml +11 -5
  647. package/dist/commands/marketplace.d.ts +0 -16
  648. package/dist/commands/marketplace.js +0 -32
  649. package/dist/commands/marketplace.js.map +0 -1
  650. package/dist/recipes/legacyRecipeCompat.d.ts +0 -10
  651. package/dist/recipes/legacyRecipeCompat.js +0 -131
  652. package/dist/recipes/legacyRecipeCompat.js.map +0 -1
package/dist/bridge.js CHANGED
@@ -16,7 +16,7 @@ import { CommitIssueLinkLog } from "./commitIssueLinkLog.js";
16
16
  import { DecisionTraceLog } from "./decisionTraceLog.js";
17
17
  import { createDriver } from "./drivers/index.js";
18
18
  import { ExtensionClient } from "./extensionClient.js";
19
- import { lockKillSwitchEnv } from "./featureFlags.js";
19
+ import { lockKillSwitchEnv, watchFlags } from "./featureFlags.js";
20
20
  import { FileLock } from "./fileLock.js";
21
21
  import { buildEnforcementReminder } from "./instructionsUtils.js";
22
22
  import { LockFileManager } from "./lockfile.js";
@@ -28,6 +28,8 @@ import { PluginWatcher } from "./pluginWatcher.js";
28
28
  import { isPreToolUseHookRegistered } from "./preToolUseHook.js";
29
29
  import { probeAll } from "./probe.js";
30
30
  import { RecipeOrchestration } from "./recipeOrchestration.js";
31
+ import { haltSummaryToPrometheus, summariseHalts, } from "./recipes/haltCategory.js";
32
+ import { judgeSummaryToPrometheus, summariseJudgments, } from "./recipes/judgeSummary.js";
31
33
  import { warnAboutLegacyPermissionsSidecars } from "./recipes/migrationWarnings.js";
32
34
  import { RecipeOrchestrator } from "./recipes/RecipeOrchestrator.js";
33
35
  import { classifyTool } from "./riskTier.js";
@@ -45,6 +47,7 @@ import { buildRecentTracesDigest } from "./tools/recentTracesDigest.js";
45
47
  import { resolveFilePath } from "./tools/utils.js";
46
48
  import { McpTransport } from "./transport.js";
47
49
  import { PACKAGE_VERSION } from "./version.js";
50
+ import { wireHaltPushDispatch } from "./wireHaltPushDispatch.js";
48
51
  const SHUTDOWN_TIMEOUT_MS = 5000;
49
52
  let globalHandlersRegistered = false;
50
53
  /** Collect the union of openedFiles across all sessions in a checkpoint. */
@@ -143,8 +146,9 @@ export class Bridge {
143
146
  this.lockFile = new LockFileManager(this.logger);
144
147
  const configDir = process.env.CLAUDE_CONFIG_DIR ?? path.join(os.homedir(), ".claude");
145
148
  this.authToken = config.fixedToken ?? loadOrCreateBridgeToken(configDir);
146
- this.server = new Server(this.authToken, this.logger, config.corsOrigins);
149
+ this.server = new Server(this.authToken, this.logger, config.corsOrigins, undefined, config.trustedProxies);
147
150
  this.server.bridgeConfigPath = config.configFilePath ?? undefined;
151
+ this.server.webhookSecret = config.webhookSecret ?? null;
148
152
  if (config.issuerUrl) {
149
153
  this.oauthServer = new OAuthServerImpl(this.authToken, config.issuerUrl, {
150
154
  configDir,
@@ -245,7 +249,11 @@ export class Bridge {
245
249
  }
246
250
  // ─────────────────────────────────────────────────────────────────────
247
251
  // Reject connections beyond capacity (grace-period sessions don't count)
248
- const activeSessionCount = [...this.sessions.values()].filter((s) => !s.graceTimer).length;
252
+ let activeSessionCount = 0;
253
+ for (const s of this.sessions.values()) {
254
+ if (!s.graceTimer)
255
+ activeSessionCount++;
256
+ }
249
257
  if (activeSessionCount >= this.config.maxSessions) {
250
258
  this.logger.warn(`Session capacity reached (${this.config.maxSessions} active). Rejecting connection.`);
251
259
  ws.close(1013, "Bridge at capacity");
@@ -493,10 +501,15 @@ export class Bridge {
493
501
  // Detect false→true transition (session started)
494
502
  if (!this._lastDebugSessionActive && state.hasActiveSession) {
495
503
  const breakpoints = state.breakpoints ?? [];
504
+ let enabledBreakpoints = 0;
505
+ for (const b of breakpoints) {
506
+ if (b.enabled)
507
+ enabledBreakpoints++;
508
+ }
496
509
  this.automationHooks?.handleDebugSessionStart({
497
510
  sessionName: state.sessionName ?? "unknown",
498
511
  sessionType: state.sessionType ?? "unknown",
499
- breakpointCount: breakpoints.filter((b) => b.enabled).length,
512
+ breakpointCount: enabledBreakpoints,
500
513
  activeFile: breakpoints[0]?.file ?? "",
501
514
  });
502
515
  }
@@ -534,8 +547,14 @@ export class Bridge {
534
547
  let warnings = 0;
535
548
  const errorFiles = [];
536
549
  for (const [file, diags] of this.extensionClient.latestDiagnostics) {
537
- const e = diags.filter((d) => d.severity === "error").length;
538
- const w = diags.filter((d) => d.severity === "warning").length;
550
+ let e = 0;
551
+ let w = 0;
552
+ for (const d of diags) {
553
+ if (d.severity === "error")
554
+ e++;
555
+ else if (d.severity === "warning")
556
+ w++;
557
+ }
539
558
  errors += e;
540
559
  warnings += w;
541
560
  if (e > 0)
@@ -580,6 +599,8 @@ export class Bridge {
580
599
  }
581
600
  /** Write a periodic auto-snapshot while sessions are active (every 5 minutes). */
582
601
  _periodicSnapshotTimer = null;
602
+ /** Cleanup handle for `watchFlags()` — set in start(), invoked in stop(). */
603
+ _stopFlagsWatch = null;
583
604
  _startPeriodicSnapshots() {
584
605
  if (this._periodicSnapshotTimer)
585
606
  return;
@@ -721,6 +742,10 @@ export class Bridge {
721
742
  // recipe steps mutating `process.env.PATCHWORK_FLAG_*` cannot disable an
722
743
  // active emergency stop. Closes MED-2 from the 2026-04-28 audit.
723
744
  lockKillSwitchEnv();
745
+ // 0a-bis. Watch flags.json for cross-process changes — picks up CLI
746
+ // fallback writes and sibling-bridge updates in a multi-bridge fleet.
747
+ // v2-S1 + v2-B2 from issue #422.
748
+ this._stopFlagsWatch = watchFlags();
724
749
  // 0b. Auto-repair .claude/rules/bridge-tools.md if stale (present but missing the
725
750
  // current version sentinel). Older package versions write stale files that may
726
751
  // lack new tool substitution rules. Repair is silent on success; falls back to
@@ -849,17 +874,35 @@ export class Bridge {
849
874
  });
850
875
  // scheduler.start() deferred to after this.port is set (see below)
851
876
  // so bridgeMcp callback has a valid port when first cron fires.
877
+ //
878
+ // Hot-reload: re-prime the scheduler whenever the recipe set
879
+ // changes on disk (install / save / delete). RecipeScheduler.start()
880
+ // is idempotent (calls this.stop() first) and reads the recipes
881
+ // directory fresh, so calling it again cleanly picks up the new
882
+ // file. Stored as a callback on the Server so route handlers can
883
+ // fire it post-success without owning a reference to the scheduler.
884
+ this.server.onRecipesChangedFn = () => {
885
+ if (!this.recipeScheduler)
886
+ return;
887
+ try {
888
+ const scheduled = this.recipeScheduler.start();
889
+ this.logger.info(`[patchwork] scheduler re-primed after recipe change · ${scheduled.length} cron recipe${scheduled.length === 1 ? "" : "s"} active`);
890
+ }
891
+ catch (err) {
892
+ this.logger.warn?.(`[patchwork] scheduler restart failed: ${err instanceof Error ? err.message : String(err)}`);
893
+ }
894
+ };
852
895
  }
853
896
  }
854
897
  if (this.config.automationEnabled) {
855
898
  if (!this.orchestrator) {
856
- throw new Error("--automation requires --claude-driver != none");
899
+ throw new Error("--automation requires --driver != none");
857
900
  }
858
901
  if (!this.config.automationPolicyPath) {
859
902
  throw new Error("--automation requires --automation-policy <path>");
860
903
  }
861
904
  const policy = loadPolicy(this.config.automationPolicyPath);
862
- this.automationHooks = new AutomationHooks(policy, this.orchestrator, (msg) => this.logger.info(msg), this.extensionClient, this.config.workspace);
905
+ this.automationHooks = new AutomationHooks(policy, this.orchestrator, (msg) => this.logger.info(msg), this.extensionClient, this.config.workspace, this.config.automationAllowPrivateWebhooks);
863
906
  this.logger.info(`[bridge] Automation enabled (policy: ${this.config.automationPolicyPath})`);
864
907
  }
865
908
  // 3. Wire up /health endpoint data and /metrics
@@ -885,10 +928,37 @@ export class Bridge {
885
928
  tokens: this.tokenUsageTracker.getTotals(),
886
929
  };
887
930
  };
888
- this.server.metricsFn = () => this.activityLog.toPrometheus({
889
- rateLimitRejected: this.activityLog.getRateLimitRejections(),
890
- extensionDisconnects: this.extensionDisconnectCount,
891
- });
931
+ this.server.metricsFn = () => {
932
+ const base = this.activityLog.toPrometheus({
933
+ rateLimitRejected: this.activityLog.getRateLimitRejections(),
934
+ extensionDisconnects: this.extensionDisconnectCount,
935
+ });
936
+ // Append per-category halt gauges from the runLog so users with
937
+ // their own Prometheus stack can dashboard halts without using
938
+ // Patchwork's UI. Reads everything currently in the in-memory ring
939
+ // (bounded by runLog memoryCap); rotation may cause the values to
940
+ // decrease, so we expose this as a `gauge` rather than a `counter`.
941
+ // Composes #441/#444/#447 — same data shape as /runs/halt-summary
942
+ // and `patchwork halts`, surfaced through the existing /metrics
943
+ // route.
944
+ let haltLines = [];
945
+ let judgeLines = [];
946
+ try {
947
+ if (this.recipeRunLog) {
948
+ const runs = this.recipeRunLog.query({ limit: 500 });
949
+ haltLines = haltSummaryToPrometheus(summariseHalts(runs));
950
+ // PR3b — judge verdicts are a separate channel from halts
951
+ // (augment-only invariant; see judgeVerdict.ts). Same window,
952
+ // same fail-open posture.
953
+ judgeLines = judgeSummaryToPrometheus(summariseJudgments(runs));
954
+ }
955
+ }
956
+ catch {
957
+ /* fail-open: prometheus must never break on log read */
958
+ }
959
+ const extras = [...haltLines, ...judgeLines];
960
+ return extras.length > 0 ? `${base}\n${extras.join("\n")}\n` : base;
961
+ };
892
962
  this.server.perfDataFn = () => {
893
963
  const windowMs = 60 * 60_000; // 1h window for dashboard
894
964
  const windowedS = this.activityLog.windowedStats(windowMs);
@@ -899,10 +969,11 @@ export class Bridge {
899
969
  totalCalls += s.count;
900
970
  totalErrors += s.errors;
901
971
  }
902
- const p95Values = Object.values(allPercentiles).map((p) => p.p95);
903
- const overallP95Ms = p95Values.length > 0 ? Math.max(...p95Values) : 0;
972
+ let overallP95Ms = 0;
904
973
  const perTool = {};
905
974
  for (const [tool, pct] of Object.entries(allPercentiles)) {
975
+ if (pct.p95 > overallP95Ms)
976
+ overallP95Ms = pct.p95;
906
977
  const ws = windowedS[tool];
907
978
  perTool[tool] = {
908
979
  p50: pct.p50,
@@ -1011,14 +1082,16 @@ export class Bridge {
1011
1082
  // Count automation tasks (isAutomationTask) created within the window.
1012
1083
  // These originate from automation hooks (onFileSave, onGitCommit, etc.)
1013
1084
  // and accurately represent "hooks fired" rather than session lifecycle events.
1014
- const hooksLast24h = this.orchestrator
1015
- ? this.orchestrator
1016
- .list()
1017
- .filter((t) => t.isAutomationTask && t.createdAt > cutoff).length
1018
- : 0;
1019
- const recentAutomationTasks = this.orchestrator
1020
- ? this.orchestrator
1021
- .list()
1085
+ const allTasks = this.orchestrator ? this.orchestrator.list() : null;
1086
+ let hooksLast24h = 0;
1087
+ if (allTasks) {
1088
+ for (const t of allTasks) {
1089
+ if (t.isAutomationTask && t.createdAt > cutoff)
1090
+ hooksLast24h++;
1091
+ }
1092
+ }
1093
+ const recentAutomationTasks = allTasks
1094
+ ? allTasks
1022
1095
  .sort((a, b) => b.createdAt - a.createdAt)
1023
1096
  .slice(0, 20)
1024
1097
  .map((t) => ({
@@ -1049,6 +1122,23 @@ export class Bridge {
1049
1122
  };
1050
1123
  };
1051
1124
  this.server.streamFn = (listener) => this.activityLog.subscribe(listener);
1125
+ // v2-I8 (#422): broadcast kind:"kill-switch" SSE when state changes.
1126
+ // The activityLog subscriber list fans out to all open /stream clients.
1127
+ this.server.broadcastKillSwitchEventFn = (engaged, reason) => {
1128
+ for (const listener of this.activityLog.getListeners()) {
1129
+ try {
1130
+ listener("kill-switch", {
1131
+ id: 0,
1132
+ timestamp: new Date().toISOString(),
1133
+ event: engaged ? "engage" : "release",
1134
+ metadata: { engaged, ...(reason ? { reason } : {}) },
1135
+ });
1136
+ }
1137
+ catch {
1138
+ /* listener must not crash broadcast */
1139
+ }
1140
+ }
1141
+ };
1052
1142
  this.server.cancelTaskFn = (id) => this.orchestrator?.cancel(id, "user") ?? false;
1053
1143
  // Wire `/sessions` for the dashboard's Sessions page. The same Map is
1054
1144
  // already iterated by `statusFn` for the bridge-status payload — exposing
@@ -1080,6 +1170,24 @@ export class Bridge {
1080
1170
  }
1081
1171
  return out;
1082
1172
  };
1173
+ this.server.restartCheckFn = () => {
1174
+ let totalSessions = 0;
1175
+ let totalInFlight = 0;
1176
+ const busySessions = [];
1177
+ for (const [sid, session] of this.sessions) {
1178
+ totalSessions++;
1179
+ const stats = session.transport.getStats();
1180
+ if (stats.activeToolCalls > 0) {
1181
+ totalInFlight += stats.activeToolCalls;
1182
+ busySessions.push(`${sid.slice(0, 8)} (${stats.activeToolCalls} tool${stats.activeToolCalls === 1 ? "" : "s"}: ${stats.inFlightTools.join(", ")})`);
1183
+ }
1184
+ }
1185
+ return {
1186
+ totalSessions,
1187
+ inFlightCalls: totalInFlight,
1188
+ busySessions,
1189
+ };
1190
+ };
1083
1191
  this.server.tasksFn = () => ({
1084
1192
  tasks: (this.orchestrator?.list() ?? []).map((t) => ({
1085
1193
  taskId: t.id,
@@ -1121,9 +1229,33 @@ export class Bridge {
1121
1229
  // ~/.patchwork/config.json's enableTimeOfDayAnomaly field.
1122
1230
  this.server.enableTimeOfDayAnomaly =
1123
1231
  this.config.enableTimeOfDayAnomaly ?? false;
1232
+ // Push / ntfy config — previously only set by /settings and lost on
1233
+ // restart. Now restored from ~/.patchwork/config.json on boot so the
1234
+ // mobile-oversight phone path survives a bridge bounce.
1235
+ this.server.pushServiceUrl = this.config.pushServiceUrl ?? undefined;
1236
+ this.server.pushServiceToken = this.config.pushServiceToken ?? undefined;
1237
+ this.server.pushServiceBaseUrl =
1238
+ this.config.pushServiceBaseUrl ?? undefined;
1239
+ this.server.ntfyTopic = this.config.ntfyTopic ?? undefined;
1240
+ this.server.ntfyServer = this.config.ntfyServer ?? undefined;
1241
+ // Wire recipe-halt → Web Push dispatch. The listener reads
1242
+ // pushServiceUrl/Token via getter each fire, so config edits
1243
+ // through /settings take effect without a restart. Push request
1244
+ // is fire-and-forget; runner is never blocked on a relay outage.
1245
+ wireHaltPushDispatch({
1246
+ activityLog: this.activityLog,
1247
+ getPushConfig: () => {
1248
+ const url = this.server.pushServiceUrl;
1249
+ const token = this.server.pushServiceToken;
1250
+ if (!url || !token)
1251
+ return null;
1252
+ return { url, token };
1253
+ },
1254
+ logger: this.logger,
1255
+ });
1124
1256
  this.server.readyFn = () => {
1125
1257
  // Count tools from the first active session (all sessions share the same tool set)
1126
- const anySession = [...this.sessions.values()][0];
1258
+ const anySession = this.sessions.values().next().value;
1127
1259
  const toolCount = anySession?.transport.toolCount ?? 0;
1128
1260
  return {
1129
1261
  ready: this.ready,
@@ -1131,6 +1263,30 @@ export class Bridge {
1131
1263
  extensionConnected: this.extensionClient.isConnected(),
1132
1264
  };
1133
1265
  };
1266
+ // Wire kill-switch audit-trace emit to decisionTraceLog. State
1267
+ // transitions become DecisionTrace entries with tags=["kill-switch",
1268
+ // "engage"|"release", "actor:http"]; query via ctxQueryTraces. See
1269
+ // step 5 of #422.
1270
+ if (this.decisionTraceLog) {
1271
+ const traceLog = this.decisionTraceLog;
1272
+ const workspace = this.config.workspace;
1273
+ this.server.recordKillSwitchTraceFn = (event) => {
1274
+ const direction = event.engaged ? "engage" : "release";
1275
+ const isoTs = new Date(event.ts).toISOString();
1276
+ try {
1277
+ traceLog.record({
1278
+ ref: "kill-switch.writes",
1279
+ problem: event.reason ?? direction,
1280
+ solution: `${event.engaged ? "ENGAGED" : "RELEASED"} at ${isoTs}`,
1281
+ workspace,
1282
+ tags: ["kill-switch", direction, "actor:http"],
1283
+ });
1284
+ }
1285
+ catch (err) {
1286
+ this.logger.warn(`[kill-switch] failed to record audit trace: ${err instanceof Error ? err.message : String(err)}`);
1287
+ }
1288
+ };
1289
+ }
1134
1290
  this.server.statusFn = () => {
1135
1291
  let sessionsInGrace = 0;
1136
1292
  const sessionList = [];
@@ -1179,6 +1335,8 @@ export class Bridge {
1179
1335
  pushServiceUrl: this.server.pushServiceUrl ?? null,
1180
1336
  pushServiceToken: this.server.pushServiceToken ? "***" : null,
1181
1337
  pushServiceBaseUrl: this.server.pushServiceBaseUrl ?? null,
1338
+ ntfyTopic: this.server.ntfyTopic ?? null,
1339
+ ntfyServer: this.server.ntfyServer ?? null,
1182
1340
  };
1183
1341
  })(),
1184
1342
  };
@@ -1240,7 +1398,7 @@ export class Bridge {
1240
1398
  if (result === null) {
1241
1399
  return {
1242
1400
  ok: false,
1243
- error: "launchQuickTask not registered — requires --claude-driver subprocess",
1401
+ error: "launchQuickTask not registered — requires --driver subprocess",
1244
1402
  };
1245
1403
  }
1246
1404
  const r = result;
@@ -1380,6 +1538,16 @@ export class Bridge {
1380
1538
  // All process-level signal handlers are guarded by globalHandlersRegistered so
1381
1539
  // that repeated start() calls (e.g. in tests or --watch restarts) don't
1382
1540
  // accumulate process.once listeners and trigger MaxListenersExceededWarning.
1541
+ // Wire server callbacks so /restart and /shutdown invoke the bridge's
1542
+ // shutdown sequence directly. This is the only path that works on
1543
+ // Windows, where `process.kill(pid, 'SIGTERM')` is TerminateProcess
1544
+ // and registered handlers never fire.
1545
+ this.server.restartKillFn = () => {
1546
+ void shutdown("SIGTERM", 143);
1547
+ };
1548
+ this.server.shutdownFn = () => {
1549
+ void shutdown("SIGTERM", 0);
1550
+ };
1383
1551
  if (!globalHandlersRegistered) {
1384
1552
  globalHandlersRegistered = true;
1385
1553
  process.once("SIGINT", () => shutdown("SIGINT", 130));
@@ -1477,6 +1645,15 @@ export class Bridge {
1477
1645
  this.stopped = true;
1478
1646
  this.logger.info("Shutting down...");
1479
1647
  this._stopPeriodicSnapshots();
1648
+ if (this._stopFlagsWatch) {
1649
+ try {
1650
+ this._stopFlagsWatch();
1651
+ }
1652
+ catch {
1653
+ /* ignore */
1654
+ }
1655
+ this._stopFlagsWatch = null;
1656
+ }
1480
1657
  this.tokenUsageTracker.stop();
1481
1658
  this.automationHooks?.destroy();
1482
1659
  this.recipeScheduler?.stop();
@@ -1521,7 +1698,7 @@ export class Bridge {
1521
1698
  }
1522
1699
  // Clean up all active sessions (cleanupSession skips the extension notification
1523
1700
  // during shutdown because this.stopped is already true)
1524
- for (const id of [...this.sessions.keys()]) {
1701
+ for (const id of this.sessions.keys()) {
1525
1702
  this.cleanupSession(id);
1526
1703
  }
1527
1704
  const shutdownErrorPart = totalErrors > 0