patchwork-os 0.2.0-alpha.9 → 0.2.0-beta.0

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 (581) hide show
  1. package/README.bridge.md +6 -0
  2. package/README.md +315 -35
  3. package/deploy/bootstrap-new-vps.sh +12 -12
  4. package/deploy/bootstrap-vps.sh +187 -0
  5. package/deploy/deploy-dashboard.sh +174 -0
  6. package/deploy/deploy-landing.sh +136 -0
  7. package/dist/activationMetrics.d.ts +67 -0
  8. package/dist/activationMetrics.js +255 -0
  9. package/dist/activationMetrics.js.map +1 -0
  10. package/dist/activityLog.d.ts +49 -0
  11. package/dist/activityLog.js +78 -0
  12. package/dist/activityLog.js.map +1 -1
  13. package/dist/approvalHttp.d.ts +49 -2
  14. package/dist/approvalHttp.js +217 -21
  15. package/dist/approvalHttp.js.map +1 -1
  16. package/dist/approvalInsights.d.ts +49 -0
  17. package/dist/approvalInsights.js +97 -0
  18. package/dist/approvalInsights.js.map +1 -0
  19. package/dist/approvalQueue.d.ts +27 -1
  20. package/dist/approvalQueue.js +123 -3
  21. package/dist/approvalQueue.js.map +1 -1
  22. package/dist/approvalSignals.d.ts +124 -0
  23. package/dist/approvalSignals.js +512 -0
  24. package/dist/approvalSignals.js.map +1 -0
  25. package/dist/automation.d.ts +57 -0
  26. package/dist/automation.js +156 -59
  27. package/dist/automation.js.map +1 -1
  28. package/dist/automationSuggestions.d.ts +79 -0
  29. package/dist/automationSuggestions.js +150 -0
  30. package/dist/automationSuggestions.js.map +1 -0
  31. package/dist/bridge.d.ts +3 -0
  32. package/dist/bridge.js +174 -143
  33. package/dist/bridge.js.map +1 -1
  34. package/dist/bridgeToken.js +57 -19
  35. package/dist/bridgeToken.js.map +1 -1
  36. package/dist/ccPermissions.d.ts +15 -0
  37. package/dist/ccPermissions.js +21 -4
  38. package/dist/ccPermissions.js.map +1 -1
  39. package/dist/claudeDriver.js +74 -16
  40. package/dist/claudeDriver.js.map +1 -1
  41. package/dist/claudeOrchestrator.d.ts +1 -1
  42. package/dist/claudeOrchestrator.js +14 -8
  43. package/dist/claudeOrchestrator.js.map +1 -1
  44. package/dist/commands/dashboard.js +1 -1
  45. package/dist/commands/dashboard.js.map +1 -1
  46. package/dist/commands/launchd.d.ts +2 -0
  47. package/dist/commands/launchd.js +94 -0
  48. package/dist/commands/launchd.js.map +1 -0
  49. package/dist/commands/patchworkInit.d.ts +8 -0
  50. package/dist/commands/patchworkInit.js +77 -11
  51. package/dist/commands/patchworkInit.js.map +1 -1
  52. package/dist/commands/recipe.d.ts +289 -0
  53. package/dist/commands/recipe.js +1359 -0
  54. package/dist/commands/recipe.js.map +1 -0
  55. package/dist/commands/recipeInstall.d.ts +150 -0
  56. package/dist/commands/recipeInstall.js +647 -0
  57. package/dist/commands/recipeInstall.js.map +1 -0
  58. package/dist/commands/tracesExport.d.ts +83 -0
  59. package/dist/commands/tracesExport.js +269 -0
  60. package/dist/commands/tracesExport.js.map +1 -0
  61. package/dist/commands/tracesImport.d.ts +56 -0
  62. package/dist/commands/tracesImport.js +161 -0
  63. package/dist/commands/tracesImport.js.map +1 -0
  64. package/dist/config.d.ts +22 -1
  65. package/dist/config.js +108 -9
  66. package/dist/config.js.map +1 -1
  67. package/dist/connectorRoutes.d.ts +43 -0
  68. package/dist/connectorRoutes.js +1609 -0
  69. package/dist/connectorRoutes.js.map +1 -0
  70. package/dist/connectors/asana.d.ts +198 -0
  71. package/dist/connectors/asana.js +679 -0
  72. package/dist/connectors/asana.js.map +1 -0
  73. package/dist/connectors/baseConnector.d.ts +153 -0
  74. package/dist/connectors/baseConnector.js +336 -0
  75. package/dist/connectors/baseConnector.js.map +1 -0
  76. package/dist/connectors/confluence.d.ts +111 -0
  77. package/dist/connectors/confluence.js +406 -0
  78. package/dist/connectors/confluence.js.map +1 -0
  79. package/dist/connectors/datadog.d.ts +116 -0
  80. package/dist/connectors/datadog.js +385 -0
  81. package/dist/connectors/datadog.js.map +1 -0
  82. package/dist/connectors/discord.d.ts +150 -0
  83. package/dist/connectors/discord.js +543 -0
  84. package/dist/connectors/discord.js.map +1 -0
  85. package/dist/connectors/fixtureLibrary.d.ts +21 -0
  86. package/dist/connectors/fixtureLibrary.js +70 -0
  87. package/dist/connectors/fixtureLibrary.js.map +1 -0
  88. package/dist/connectors/fixtureRecorder.d.ts +1 -0
  89. package/dist/connectors/fixtureRecorder.js +35 -0
  90. package/dist/connectors/fixtureRecorder.js.map +1 -0
  91. package/dist/connectors/github.js +17 -18
  92. package/dist/connectors/github.js.map +1 -1
  93. package/dist/connectors/gitlab.d.ts +180 -0
  94. package/dist/connectors/gitlab.js +582 -0
  95. package/dist/connectors/gitlab.js.map +1 -0
  96. package/dist/connectors/gmail.d.ts +4 -1
  97. package/dist/connectors/gmail.js +149 -27
  98. package/dist/connectors/gmail.js.map +1 -1
  99. package/dist/connectors/googleCalendar.d.ts +4 -1
  100. package/dist/connectors/googleCalendar.js +88 -25
  101. package/dist/connectors/googleCalendar.js.map +1 -1
  102. package/dist/connectors/googleDrive.d.ts +34 -0
  103. package/dist/connectors/googleDrive.js +321 -0
  104. package/dist/connectors/googleDrive.js.map +1 -0
  105. package/dist/connectors/htmlEscape.d.ts +5 -0
  106. package/dist/connectors/htmlEscape.js +13 -0
  107. package/dist/connectors/htmlEscape.js.map +1 -0
  108. package/dist/connectors/hubspot.d.ts +112 -0
  109. package/dist/connectors/hubspot.js +408 -0
  110. package/dist/connectors/hubspot.js.map +1 -0
  111. package/dist/connectors/intercom.d.ts +102 -0
  112. package/dist/connectors/intercom.js +402 -0
  113. package/dist/connectors/intercom.js.map +1 -0
  114. package/dist/connectors/jira.d.ts +98 -0
  115. package/dist/connectors/jira.js +379 -0
  116. package/dist/connectors/jira.js.map +1 -0
  117. package/dist/connectors/linear.js +30 -19
  118. package/dist/connectors/linear.js.map +1 -1
  119. package/dist/connectors/mcpOAuth.d.ts +3 -0
  120. package/dist/connectors/mcpOAuth.js +64 -10
  121. package/dist/connectors/mcpOAuth.js.map +1 -1
  122. package/dist/connectors/mockConnector.d.ts +28 -0
  123. package/dist/connectors/mockConnector.js +81 -0
  124. package/dist/connectors/mockConnector.js.map +1 -0
  125. package/dist/connectors/notion.d.ts +143 -0
  126. package/dist/connectors/notion.js +424 -0
  127. package/dist/connectors/notion.js.map +1 -0
  128. package/dist/connectors/oauthStateStore.d.ts +31 -0
  129. package/dist/connectors/oauthStateStore.js +52 -0
  130. package/dist/connectors/oauthStateStore.js.map +1 -0
  131. package/dist/connectors/pagerduty.d.ts +160 -0
  132. package/dist/connectors/pagerduty.js +464 -0
  133. package/dist/connectors/pagerduty.js.map +1 -0
  134. package/dist/connectors/sentry.js +5 -13
  135. package/dist/connectors/sentry.js.map +1 -1
  136. package/dist/connectors/slack.d.ts +16 -1
  137. package/dist/connectors/slack.js +155 -32
  138. package/dist/connectors/slack.js.map +1 -1
  139. package/dist/connectors/stripe.d.ts +116 -0
  140. package/dist/connectors/stripe.js +379 -0
  141. package/dist/connectors/stripe.js.map +1 -0
  142. package/dist/connectors/tokenStorage.d.ts +35 -0
  143. package/dist/connectors/tokenStorage.js +484 -0
  144. package/dist/connectors/tokenStorage.js.map +1 -0
  145. package/dist/connectors/zendesk.d.ts +104 -0
  146. package/dist/connectors/zendesk.js +442 -0
  147. package/dist/connectors/zendesk.js.map +1 -0
  148. package/dist/cors.d.ts +10 -0
  149. package/dist/cors.js +29 -0
  150. package/dist/cors.js.map +1 -0
  151. package/dist/decisionReplay.d.ts +72 -0
  152. package/dist/decisionReplay.js +92 -0
  153. package/dist/decisionReplay.js.map +1 -0
  154. package/dist/decisionTraceLog.d.ts +6 -0
  155. package/dist/decisionTraceLog.js +54 -2
  156. package/dist/decisionTraceLog.js.map +1 -1
  157. package/dist/drivers/gemini/index.d.ts +5 -1
  158. package/dist/drivers/gemini/index.js +39 -5
  159. package/dist/drivers/gemini/index.js.map +1 -1
  160. package/dist/drivers/index.d.ts +5 -0
  161. package/dist/drivers/index.js +1 -1
  162. package/dist/drivers/index.js.map +1 -1
  163. package/dist/featureFlags.d.ts +79 -0
  164. package/dist/featureFlags.js +208 -0
  165. package/dist/featureFlags.js.map +1 -0
  166. package/dist/fp/automationInterpreter.js +26 -21
  167. package/dist/fp/automationInterpreter.js.map +1 -1
  168. package/dist/fp/automationProgram.d.ts +1 -1
  169. package/dist/fp/automationProgram.js.map +1 -1
  170. package/dist/fp/automationState.js +4 -1
  171. package/dist/fp/automationState.js.map +1 -1
  172. package/dist/fp/policyParser.js +21 -1
  173. package/dist/fp/policyParser.js.map +1 -1
  174. package/dist/inboxRoutes.d.ts +22 -0
  175. package/dist/inboxRoutes.js +114 -0
  176. package/dist/inboxRoutes.js.map +1 -0
  177. package/dist/index.js +1400 -201
  178. package/dist/index.js.map +1 -1
  179. package/dist/installGuard.d.ts +25 -0
  180. package/dist/installGuard.js +48 -0
  181. package/dist/installGuard.js.map +1 -0
  182. package/dist/mcpRoutes.d.ts +37 -0
  183. package/dist/mcpRoutes.js +76 -0
  184. package/dist/mcpRoutes.js.map +1 -0
  185. package/dist/oauth.d.ts +7 -1
  186. package/dist/oauth.js +201 -39
  187. package/dist/oauth.js.map +1 -1
  188. package/dist/oauthRoutes.d.ts +32 -0
  189. package/dist/oauthRoutes.js +124 -0
  190. package/dist/oauthRoutes.js.map +1 -0
  191. package/dist/orchestrator/orchestratorBridge.js +2 -2
  192. package/dist/orchestrator/orchestratorBridge.js.map +1 -1
  193. package/dist/patchworkConfig.d.ts +16 -0
  194. package/dist/patchworkConfig.js +1 -1
  195. package/dist/patchworkConfig.js.map +1 -1
  196. package/dist/pluginLoader.d.ts +28 -0
  197. package/dist/pluginLoader.js +77 -11
  198. package/dist/pluginLoader.js.map +1 -1
  199. package/dist/pluginWatcher.js +8 -3
  200. package/dist/pluginWatcher.js.map +1 -1
  201. package/dist/preToolUseHook.d.ts +12 -0
  202. package/dist/preToolUseHook.js +23 -0
  203. package/dist/preToolUseHook.js.map +1 -1
  204. package/dist/recipeOrchestration.d.ts +121 -0
  205. package/dist/recipeOrchestration.js +955 -0
  206. package/dist/recipeOrchestration.js.map +1 -0
  207. package/dist/recipeRoutes.d.ts +180 -0
  208. package/dist/recipeRoutes.js +1345 -0
  209. package/dist/recipeRoutes.js.map +1 -0
  210. package/dist/recipes/RecipeOrchestrator.d.ts +40 -0
  211. package/dist/recipes/RecipeOrchestrator.js +51 -0
  212. package/dist/recipes/RecipeOrchestrator.js.map +1 -0
  213. package/dist/recipes/agentExecutor.d.ts +29 -0
  214. package/dist/recipes/agentExecutor.js +49 -0
  215. package/dist/recipes/agentExecutor.js.map +1 -0
  216. package/dist/recipes/chainedRunner.d.ts +191 -0
  217. package/dist/recipes/chainedRunner.js +759 -0
  218. package/dist/recipes/chainedRunner.js.map +1 -0
  219. package/dist/recipes/compiler.js +3 -3
  220. package/dist/recipes/compiler.js.map +1 -1
  221. package/dist/recipes/dependencyGraph.d.ts +39 -0
  222. package/dist/recipes/dependencyGraph.js +199 -0
  223. package/dist/recipes/dependencyGraph.js.map +1 -0
  224. package/dist/recipes/disabledMarkers.d.ts +48 -0
  225. package/dist/recipes/disabledMarkers.js +52 -0
  226. package/dist/recipes/disabledMarkers.js.map +1 -0
  227. package/dist/recipes/installer.js +3 -3
  228. package/dist/recipes/installer.js.map +1 -1
  229. package/dist/recipes/legacyRecipeCompat.d.ts +10 -0
  230. package/dist/recipes/legacyRecipeCompat.js +131 -0
  231. package/dist/recipes/legacyRecipeCompat.js.map +1 -0
  232. package/dist/recipes/manifest.d.ts +47 -0
  233. package/dist/recipes/manifest.js +156 -0
  234. package/dist/recipes/manifest.js.map +1 -0
  235. package/dist/recipes/migrationWarnings.d.ts +12 -0
  236. package/dist/recipes/migrationWarnings.js +44 -0
  237. package/dist/recipes/migrationWarnings.js.map +1 -0
  238. package/dist/recipes/migrations/index.d.ts +24 -0
  239. package/dist/recipes/migrations/index.js +55 -0
  240. package/dist/recipes/migrations/index.js.map +1 -0
  241. package/dist/recipes/migrations/types.d.ts +28 -0
  242. package/dist/recipes/migrations/types.js +2 -0
  243. package/dist/recipes/migrations/types.js.map +1 -0
  244. package/dist/recipes/migrations/v1.d.ts +11 -0
  245. package/dist/recipes/migrations/v1.js +18 -0
  246. package/dist/recipes/migrations/v1.js.map +1 -0
  247. package/dist/recipes/names.d.ts +40 -0
  248. package/dist/recipes/names.js +66 -0
  249. package/dist/recipes/names.js.map +1 -0
  250. package/dist/recipes/nestedRecipeStep.d.ts +58 -0
  251. package/dist/recipes/nestedRecipeStep.js +95 -0
  252. package/dist/recipes/nestedRecipeStep.js.map +1 -0
  253. package/dist/recipes/outputRegistry.d.ts +28 -0
  254. package/dist/recipes/outputRegistry.js +52 -0
  255. package/dist/recipes/outputRegistry.js.map +1 -0
  256. package/dist/recipes/parser.js +4 -1
  257. package/dist/recipes/parser.js.map +1 -1
  258. package/dist/recipes/replayRun.d.ts +62 -0
  259. package/dist/recipes/replayRun.js +97 -0
  260. package/dist/recipes/replayRun.js.map +1 -0
  261. package/dist/recipes/resolveRecipePath.d.ts +69 -0
  262. package/dist/recipes/resolveRecipePath.js +202 -0
  263. package/dist/recipes/resolveRecipePath.js.map +1 -0
  264. package/dist/recipes/scheduler.d.ts +23 -7
  265. package/dist/recipes/scheduler.js +225 -45
  266. package/dist/recipes/scheduler.js.map +1 -1
  267. package/dist/recipes/schema.d.ts +17 -2
  268. package/dist/recipes/schemaGenerator.d.ts +28 -0
  269. package/dist/recipes/schemaGenerator.js +565 -0
  270. package/dist/recipes/schemaGenerator.js.map +1 -0
  271. package/dist/recipes/stepObservation.d.ts +44 -0
  272. package/dist/recipes/stepObservation.js +232 -0
  273. package/dist/recipes/stepObservation.js.map +1 -0
  274. package/dist/recipes/templateEngine.d.ts +62 -0
  275. package/dist/recipes/templateEngine.js +201 -0
  276. package/dist/recipes/templateEngine.js.map +1 -0
  277. package/dist/recipes/toolRegistry.d.ts +186 -0
  278. package/dist/recipes/toolRegistry.js +309 -0
  279. package/dist/recipes/toolRegistry.js.map +1 -0
  280. package/dist/recipes/tools/asana.d.ts +16 -0
  281. package/dist/recipes/tools/asana.js +524 -0
  282. package/dist/recipes/tools/asana.js.map +1 -0
  283. package/dist/recipes/tools/calendar.d.ts +6 -0
  284. package/dist/recipes/tools/calendar.js +61 -0
  285. package/dist/recipes/tools/calendar.js.map +1 -0
  286. package/dist/recipes/tools/confluence.d.ts +6 -0
  287. package/dist/recipes/tools/confluence.js +254 -0
  288. package/dist/recipes/tools/confluence.js.map +1 -0
  289. package/dist/recipes/tools/datadog.d.ts +6 -0
  290. package/dist/recipes/tools/datadog.js +239 -0
  291. package/dist/recipes/tools/datadog.js.map +1 -0
  292. package/dist/recipes/tools/diagnostics.d.ts +6 -0
  293. package/dist/recipes/tools/diagnostics.js +36 -0
  294. package/dist/recipes/tools/diagnostics.js.map +1 -0
  295. package/dist/recipes/tools/discord.d.ts +18 -0
  296. package/dist/recipes/tools/discord.js +254 -0
  297. package/dist/recipes/tools/discord.js.map +1 -0
  298. package/dist/recipes/tools/file.d.ts +12 -0
  299. package/dist/recipes/tools/file.js +174 -0
  300. package/dist/recipes/tools/file.js.map +1 -0
  301. package/dist/recipes/tools/git.d.ts +6 -0
  302. package/dist/recipes/tools/git.js +63 -0
  303. package/dist/recipes/tools/git.js.map +1 -0
  304. package/dist/recipes/tools/github.d.ts +6 -0
  305. package/dist/recipes/tools/github.js +116 -0
  306. package/dist/recipes/tools/github.js.map +1 -0
  307. package/dist/recipes/tools/gitlab.d.ts +11 -0
  308. package/dist/recipes/tools/gitlab.js +285 -0
  309. package/dist/recipes/tools/gitlab.js.map +1 -0
  310. package/dist/recipes/tools/gmail.d.ts +6 -0
  311. package/dist/recipes/tools/gmail.js +434 -0
  312. package/dist/recipes/tools/gmail.js.map +1 -0
  313. package/dist/recipes/tools/googleDrive.d.ts +1 -0
  314. package/dist/recipes/tools/googleDrive.js +55 -0
  315. package/dist/recipes/tools/googleDrive.js.map +1 -0
  316. package/dist/recipes/tools/hubspot.d.ts +6 -0
  317. package/dist/recipes/tools/hubspot.js +232 -0
  318. package/dist/recipes/tools/hubspot.js.map +1 -0
  319. package/dist/recipes/tools/index.d.ts +30 -0
  320. package/dist/recipes/tools/index.js +33 -0
  321. package/dist/recipes/tools/index.js.map +1 -0
  322. package/dist/recipes/tools/intercom.d.ts +6 -0
  323. package/dist/recipes/tools/intercom.js +226 -0
  324. package/dist/recipes/tools/intercom.js.map +1 -0
  325. package/dist/recipes/tools/jira.d.ts +14 -0
  326. package/dist/recipes/tools/jira.js +369 -0
  327. package/dist/recipes/tools/jira.js.map +1 -0
  328. package/dist/recipes/tools/linear.d.ts +7 -0
  329. package/dist/recipes/tools/linear.js +307 -0
  330. package/dist/recipes/tools/linear.js.map +1 -0
  331. package/dist/recipes/tools/meetingNotes.d.ts +21 -0
  332. package/dist/recipes/tools/meetingNotes.js +701 -0
  333. package/dist/recipes/tools/meetingNotes.js.map +1 -0
  334. package/dist/recipes/tools/notion.d.ts +6 -0
  335. package/dist/recipes/tools/notion.js +278 -0
  336. package/dist/recipes/tools/notion.js.map +1 -0
  337. package/dist/recipes/tools/pagerduty.d.ts +15 -0
  338. package/dist/recipes/tools/pagerduty.js +451 -0
  339. package/dist/recipes/tools/pagerduty.js.map +1 -0
  340. package/dist/recipes/tools/sentry.d.ts +12 -0
  341. package/dist/recipes/tools/sentry.js +73 -0
  342. package/dist/recipes/tools/sentry.js.map +1 -0
  343. package/dist/recipes/tools/slack.d.ts +6 -0
  344. package/dist/recipes/tools/slack.js +82 -0
  345. package/dist/recipes/tools/slack.js.map +1 -0
  346. package/dist/recipes/tools/stripe.d.ts +6 -0
  347. package/dist/recipes/tools/stripe.js +265 -0
  348. package/dist/recipes/tools/stripe.js.map +1 -0
  349. package/dist/recipes/tools/zendesk.d.ts +6 -0
  350. package/dist/recipes/tools/zendesk.js +245 -0
  351. package/dist/recipes/tools/zendesk.js.map +1 -0
  352. package/dist/recipes/validation.d.ts +13 -0
  353. package/dist/recipes/validation.js +617 -0
  354. package/dist/recipes/validation.js.map +1 -0
  355. package/dist/recipes/yamlRunner.d.ts +116 -1
  356. package/dist/recipes/yamlRunner.js +1000 -401
  357. package/dist/recipes/yamlRunner.js.map +1 -1
  358. package/dist/recipesHttp.d.ts +137 -6
  359. package/dist/recipesHttp.js +941 -29
  360. package/dist/recipesHttp.js.map +1 -1
  361. package/dist/riskTier.js +7 -1
  362. package/dist/riskTier.js.map +1 -1
  363. package/dist/runLog.d.ts +100 -1
  364. package/dist/runLog.js +258 -5
  365. package/dist/runLog.js.map +1 -1
  366. package/dist/schemas/dry-run-plan.v1.json +139 -0
  367. package/dist/schemas/recipe.v1.json +684 -0
  368. package/dist/server.d.ts +121 -8
  369. package/dist/server.js +538 -735
  370. package/dist/server.js.map +1 -1
  371. package/dist/ssrfGuard.d.ts +54 -0
  372. package/dist/ssrfGuard.js +122 -0
  373. package/dist/ssrfGuard.js.map +1 -0
  374. package/dist/streamableHttp.d.ts +39 -1
  375. package/dist/streamableHttp.js +128 -17
  376. package/dist/streamableHttp.js.map +1 -1
  377. package/dist/tokenUsageTracker.d.ts +33 -0
  378. package/dist/tokenUsageTracker.js +146 -0
  379. package/dist/tokenUsageTracker.js.map +1 -0
  380. package/dist/tools/activityLog.d.ts +2 -0
  381. package/dist/tools/addLinearComment.d.ts +1 -0
  382. package/dist/tools/addLinearComment.js +4 -2
  383. package/dist/tools/addLinearComment.js.map +1 -1
  384. package/dist/tools/batchLsp.d.ts +3 -0
  385. package/dist/tools/bridgeDoctor.d.ts +1 -0
  386. package/dist/tools/bridgeDoctor.js +2 -2
  387. package/dist/tools/bridgeDoctor.js.map +1 -1
  388. package/dist/tools/bridgeStatus.d.ts +1 -0
  389. package/dist/tools/cancelClaudeTask.d.ts +2 -0
  390. package/dist/tools/cancelClaudeTask.js +1 -0
  391. package/dist/tools/cancelClaudeTask.js.map +1 -1
  392. package/dist/tools/checkDocumentDirty.d.ts +1 -0
  393. package/dist/tools/clipboard.d.ts +2 -0
  394. package/dist/tools/closeTabs.d.ts +2 -0
  395. package/dist/tools/codeLens.d.ts +1 -0
  396. package/dist/tools/contextBundle.d.ts +1 -0
  397. package/dist/tools/createIssueFromAIComment.d.ts +1 -0
  398. package/dist/tools/createLinearIssue.d.ts +1 -0
  399. package/dist/tools/ctxGetTaskContext.d.ts +1 -0
  400. package/dist/tools/ctxQueryTraces.d.ts +1 -0
  401. package/dist/tools/ctxSaveTrace.d.ts +1 -0
  402. package/dist/tools/debug.d.ts +4 -0
  403. package/dist/tools/decorations.d.ts +2 -0
  404. package/dist/tools/documentLinks.d.ts +1 -0
  405. package/dist/tools/editText.d.ts +1 -0
  406. package/dist/tools/enrichCommit.d.ts +1 -0
  407. package/dist/tools/enrichStackTrace.d.ts +1 -0
  408. package/dist/tools/explainDiagnostic.d.ts +1 -0
  409. package/dist/tools/explainSymbol.d.ts +1 -0
  410. package/dist/tools/fetchCalendarEvents.d.ts +1 -0
  411. package/dist/tools/fetchGithubIssue.d.ts +1 -0
  412. package/dist/tools/fetchGithubPR.d.ts +1 -0
  413. package/dist/tools/fetchLinearIssue.d.ts +1 -0
  414. package/dist/tools/fetchSentryIssue.d.ts +1 -0
  415. package/dist/tools/fetchSlackProfile.d.ts +1 -0
  416. package/dist/tools/fetchSlackProfile.js +4 -1
  417. package/dist/tools/fetchSlackProfile.js.map +1 -1
  418. package/dist/tools/fileOperations.d.ts +3 -0
  419. package/dist/tools/fileWatcher.d.ts +2 -0
  420. package/dist/tools/findFiles.d.ts +1 -0
  421. package/dist/tools/findRelatedTests.d.ts +1 -0
  422. package/dist/tools/fixAllLintErrors.d.ts +1 -0
  423. package/dist/tools/foldingRanges.d.ts +1 -0
  424. package/dist/tools/formatDocument.d.ts +1 -0
  425. package/dist/tools/generateTests.d.ts +1 -0
  426. package/dist/tools/getAIComments.d.ts +1 -0
  427. package/dist/tools/getAnalyticsReport.d.ts +1 -0
  428. package/dist/tools/getArchitectureContext.d.ts +1 -0
  429. package/dist/tools/getBufferContent.d.ts +1 -0
  430. package/dist/tools/getChangeImpact.d.ts +1 -0
  431. package/dist/tools/getClaudeTaskStatus.d.ts +2 -0
  432. package/dist/tools/getClaudeTaskStatus.js +1 -0
  433. package/dist/tools/getClaudeTaskStatus.js.map +1 -1
  434. package/dist/tools/getCodeCoverage.d.ts +1 -0
  435. package/dist/tools/getCommitsForIssue.d.ts +1 -0
  436. package/dist/tools/getConnectorStatus.d.ts +1 -0
  437. package/dist/tools/getCurrentSelection.d.ts +2 -0
  438. package/dist/tools/getDebugState.d.ts +1 -0
  439. package/dist/tools/getDependencyTree.d.ts +1 -0
  440. package/dist/tools/getDiagnostics.d.ts +1 -0
  441. package/dist/tools/getDiffFromHandoff.d.ts +1 -0
  442. package/dist/tools/getDocumentSymbols.d.ts +25 -0
  443. package/dist/tools/getDocumentSymbols.js +74 -8
  444. package/dist/tools/getDocumentSymbols.js.map +1 -1
  445. package/dist/tools/getFileTree.d.ts +1 -0
  446. package/dist/tools/getGitDiff.d.ts +1 -0
  447. package/dist/tools/getGitHotspots.d.ts +1 -0
  448. package/dist/tools/getGitLog.d.ts +1 -0
  449. package/dist/tools/getGitStatus.d.ts +1 -0
  450. package/dist/tools/getImportTree.d.ts +1 -0
  451. package/dist/tools/getImportedSignatures.d.ts +1 -0
  452. package/dist/tools/getOpenEditors.d.ts +1 -0
  453. package/dist/tools/getPRTemplate.d.ts +1 -0
  454. package/dist/tools/getProjectContext.d.ts +1 -0
  455. package/dist/tools/getProjectInfo.d.ts +1 -0
  456. package/dist/tools/getSecurityAdvisories.d.ts +1 -0
  457. package/dist/tools/getSecurityAdvisories.js +10 -1
  458. package/dist/tools/getSecurityAdvisories.js.map +1 -1
  459. package/dist/tools/getSessionUsage.d.ts +4 -0
  460. package/dist/tools/getSessionUsage.js +3 -0
  461. package/dist/tools/getSessionUsage.js.map +1 -1
  462. package/dist/tools/getSymbolHistory.d.ts +1 -0
  463. package/dist/tools/getToolCapabilities.d.ts +1 -0
  464. package/dist/tools/getTypeSignature.d.ts +1 -0
  465. package/dist/tools/getWorkspaceFolders.d.ts +1 -0
  466. package/dist/tools/getWorkspaceSettings.d.ts +1 -0
  467. package/dist/tools/gitHistory.d.ts +2 -0
  468. package/dist/tools/gitWrite.d.ts +11 -0
  469. package/dist/tools/github/actions.d.ts +2 -0
  470. package/dist/tools/github/actions.js +4 -2
  471. package/dist/tools/github/actions.js.map +1 -1
  472. package/dist/tools/github/composite.d.ts +342 -0
  473. package/dist/tools/github/composite.js +343 -0
  474. package/dist/tools/github/composite.js.map +1 -0
  475. package/dist/tools/github/index.d.ts +1 -0
  476. package/dist/tools/github/index.js +1 -0
  477. package/dist/tools/github/index.js.map +1 -1
  478. package/dist/tools/github/issues.d.ts +4 -0
  479. package/dist/tools/github/issues.js +8 -4
  480. package/dist/tools/github/issues.js.map +1 -1
  481. package/dist/tools/github/pr.d.ts +7 -0
  482. package/dist/tools/github/pr.js +50 -12
  483. package/dist/tools/github/pr.js.map +1 -1
  484. package/dist/tools/handoffNote.d.ts +4 -0
  485. package/dist/tools/handoffNote.js +2 -0
  486. package/dist/tools/handoffNote.js.map +1 -1
  487. package/dist/tools/hoverAtCursor.d.ts +1 -0
  488. package/dist/tools/httpClient.d.ts +2 -0
  489. package/dist/tools/index.d.ts +8 -0
  490. package/dist/tools/index.js +47 -8
  491. package/dist/tools/index.js.map +1 -1
  492. package/dist/tools/inlayHints.d.ts +1 -0
  493. package/dist/tools/launchQuickTask.d.ts +2 -0
  494. package/dist/tools/launchQuickTask.js +1 -0
  495. package/dist/tools/launchQuickTask.js.map +1 -1
  496. package/dist/tools/listClaudeTasks.d.ts +2 -0
  497. package/dist/tools/listClaudeTasks.js +1 -0
  498. package/dist/tools/listClaudeTasks.js.map +1 -1
  499. package/dist/tools/listTerminals.d.ts +1 -0
  500. package/dist/tools/lsp.d.ts +14 -0
  501. package/dist/tools/navigateToSymbolByName.d.ts +1 -0
  502. package/dist/tools/openDiff.d.ts +1 -0
  503. package/dist/tools/openFile.d.ts +1 -0
  504. package/dist/tools/openInBrowser.d.ts +1 -0
  505. package/dist/tools/organizeImports.d.ts +1 -0
  506. package/dist/tools/performanceReport.d.ts +1 -0
  507. package/dist/tools/planPersistence.d.ts +5 -0
  508. package/dist/tools/previewEdit.d.ts +1 -0
  509. package/dist/tools/refactorAnalyze.d.ts +1 -0
  510. package/dist/tools/refactorPreview.d.ts +2 -0
  511. package/dist/tools/refactorPreview.js +1 -0
  512. package/dist/tools/refactorPreview.js.map +1 -1
  513. package/dist/tools/replaceBlock.d.ts +1 -0
  514. package/dist/tools/resumeClaudeTask.d.ts +2 -0
  515. package/dist/tools/resumeClaudeTask.js +1 -0
  516. package/dist/tools/resumeClaudeTask.js.map +1 -1
  517. package/dist/tools/runClaudeTask.d.ts +2 -0
  518. package/dist/tools/runClaudeTask.js +1 -0
  519. package/dist/tools/runClaudeTask.js.map +1 -1
  520. package/dist/tools/runCommand.d.ts +1 -0
  521. package/dist/tools/runTests.d.ts +1 -0
  522. package/dist/tools/saveDocument.d.ts +1 -0
  523. package/dist/tools/screenshotAndAnnotate.d.ts +1 -0
  524. package/dist/tools/searchAndReplace.d.ts +1 -0
  525. package/dist/tools/searchTools.d.ts +1 -0
  526. package/dist/tools/searchTools.js +1 -1
  527. package/dist/tools/searchTools.js.map +1 -1
  528. package/dist/tools/searchWorkspace.d.ts +1 -0
  529. package/dist/tools/selectionRanges.d.ts +1 -0
  530. package/dist/tools/semanticTokens.d.ts +1 -0
  531. package/dist/tools/setActiveWorkspaceFolder.d.ts +1 -0
  532. package/dist/tools/signatureHelp.d.ts +1 -0
  533. package/dist/tools/slackListChannels.d.ts +1 -0
  534. package/dist/tools/slackListChannels.js.map +1 -1
  535. package/dist/tools/slackPostMessage.d.ts +1 -0
  536. package/dist/tools/slackPostMessage.js +11 -6
  537. package/dist/tools/slackPostMessage.js.map +1 -1
  538. package/dist/tools/terminal.d.ts +6 -0
  539. package/dist/tools/testTraceToSource.d.ts +1 -0
  540. package/dist/tools/testTraceToSource.js +2 -2
  541. package/dist/tools/testTraceToSource.js.map +1 -1
  542. package/dist/tools/transaction.d.ts +23 -0
  543. package/dist/tools/transaction.js +29 -0
  544. package/dist/tools/transaction.js.map +1 -1
  545. package/dist/tools/typeHierarchy.d.ts +1 -0
  546. package/dist/tools/updateLinearIssue.d.ts +1 -0
  547. package/dist/tools/updateLinearIssue.js +20 -6
  548. package/dist/tools/updateLinearIssue.js.map +1 -1
  549. package/dist/tools/utils.d.ts +2 -0
  550. package/dist/tools/utils.js.map +1 -1
  551. package/dist/tools/vscodeCommands.d.ts +2 -0
  552. package/dist/tools/vscodeTasks.d.ts +2 -0
  553. package/dist/tools/workspaceSettings.d.ts +1 -0
  554. package/dist/traceEncryption.d.ts +46 -0
  555. package/dist/traceEncryption.js +124 -0
  556. package/dist/traceEncryption.js.map +1 -0
  557. package/dist/transport.d.ts +46 -1
  558. package/dist/transport.js +173 -19
  559. package/dist/transport.js.map +1 -1
  560. package/package.json +30 -8
  561. package/scripts/mcp-stdio-shim.cjs +19 -3
  562. package/scripts/start-all.sh +30 -1
  563. package/templates/automation-policies/recipe-authoring.json +25 -0
  564. package/templates/automation-policy.example.json +6 -0
  565. package/templates/co.patchwork-os.bridge.plist +34 -0
  566. package/templates/policies/README.md +72 -0
  567. package/templates/policies/conservative.json +14 -0
  568. package/templates/policies/developer.json +14 -0
  569. package/templates/policies/headless-ci.json +24 -0
  570. package/templates/policies/personal-assistant.json +15 -0
  571. package/templates/policies/regulated-industry.json +18 -0
  572. package/templates/recipes/lint-on-save.yaml +1 -2
  573. package/templates/recipes/morning-brief-slack.yaml +57 -0
  574. package/templates/recipes/morning-brief.yaml +2 -2
  575. package/templates/recipes/project-health-check.yaml +50 -0
  576. package/templates/recipes/webhook/README.md +70 -0
  577. package/templates/recipes/webhook/capture-thought.yaml +26 -0
  578. package/templates/recipes/webhook/customer-escalation.yaml +49 -0
  579. package/templates/recipes/webhook/incident-intake.yaml +46 -0
  580. package/templates/recipes/webhook/meeting-prep.yaml +48 -0
  581. package/templates/recipes/webhook/morning-brief.yaml +57 -0
@@ -0,0 +1,759 @@
1
+ /**
2
+ * ChainedRecipeRunner — executes recipes with:
3
+ * - Parallel step execution (respecting dependencies)
4
+ * - Template-based variable resolution
5
+ * - Nested recipe calls
6
+ * - Conditional step execution (when)
7
+ * - Dry-run mode
8
+ */
9
+ import { buildDependencyGraph, executeWithDependencies, } from "./dependencyGraph.js";
10
+ import { mockNestedRecipe, resolveNestedVars, validateNestedRecipe, } from "./nestedRecipeStep.js";
11
+ import { createOutputRegistry } from "./outputRegistry.js";
12
+ import { resolveRecipePath } from "./resolveRecipePath.js";
13
+ import { captureForRunlog } from "./stepObservation.js";
14
+ import { compileTemplate } from "./templateEngine.js";
15
+ function nestedRecipeRef(step) {
16
+ return typeof step.recipe === "string"
17
+ ? step.recipe
18
+ : typeof step.chain === "string"
19
+ ? step.chain
20
+ : undefined;
21
+ }
22
+ /** Build template context from registry and env */
23
+ export function buildTemplateContext(registry, env) {
24
+ return registry.toTemplateContext(env);
25
+ }
26
+ /** Resolve all template strings in a step */
27
+ export function resolveStepTemplates(step, context) {
28
+ const resolved = {};
29
+ const errors = [];
30
+ // W3: keys that are recipe metadata, not tool params
31
+ const STEP_META_KEYS = new Set([
32
+ "id",
33
+ "tool",
34
+ "agent",
35
+ "recipe",
36
+ "chain",
37
+ "awaits",
38
+ "when",
39
+ "output",
40
+ "risk",
41
+ "optional",
42
+ "vars",
43
+ "transform",
44
+ "retry",
45
+ "retryDelay",
46
+ "parallel",
47
+ ]);
48
+ // Resolve tool params
49
+ for (const [key, value] of Object.entries(step)) {
50
+ if (STEP_META_KEYS.has(key)) {
51
+ continue;
52
+ }
53
+ if (typeof value === "string" && value.includes("{{")) {
54
+ const compiled = compileTemplate(value);
55
+ const result = compiled.evaluate(context);
56
+ if ("error" in result) {
57
+ errors.push(result.error);
58
+ resolved[key] = value;
59
+ }
60
+ else {
61
+ // Try to parse JSON for structured data
62
+ try {
63
+ resolved[key] = JSON.parse(result.value);
64
+ }
65
+ catch {
66
+ resolved[key] = result.value;
67
+ }
68
+ }
69
+ }
70
+ else {
71
+ resolved[key] = value;
72
+ }
73
+ }
74
+ // R2 C-1 / F-02 defense-in-depth: every chained-runner template substitution
75
+ // site must re-validate `path` fields on file.* tools after rendering. The
76
+ // per-tool jail in `tools/file.ts` is the primary check; this layer
77
+ // catches paths that survived the chained substitution (e.g. via JSON
78
+ // round-trip) and ensures `err.code === "recipe_path_jail_escape"` is
79
+ // raised before the resolved step reaches executeTool dispatch.
80
+ const toolId = typeof step.tool === "string" ? step.tool : undefined;
81
+ if ((toolId === "file.read" ||
82
+ toolId === "file.write" ||
83
+ toolId === "file.append") &&
84
+ typeof resolved.path === "string") {
85
+ // Throws RecipePathJailError — propagates as a step error so the
86
+ // chained runner's error-policy machinery can handle it (and tests can
87
+ // assert on err.code without needing to inspect step results).
88
+ resolveRecipePath(resolved.path, { write: toolId !== "file.read" });
89
+ }
90
+ // Resolve agent prompt if present
91
+ if (step.agent && typeof step.agent.prompt === "string") {
92
+ const compiled = compileTemplate(step.agent.prompt);
93
+ const result = compiled.evaluate(context);
94
+ if ("error" in result) {
95
+ errors.push(result.error);
96
+ }
97
+ else {
98
+ resolved.agentPrompt = result.value;
99
+ }
100
+ }
101
+ // Evaluate when condition
102
+ let conditionResult = true;
103
+ if (step.when) {
104
+ const compiled = compileTemplate(step.when);
105
+ const result = compiled.evaluate(context);
106
+ if ("error" in result) {
107
+ errors.push(result.error);
108
+ conditionResult = false;
109
+ }
110
+ else {
111
+ // Simple truthiness check (empty string, "0", "false" are falsy)
112
+ const val = result.value.trim().toLowerCase();
113
+ conditionResult =
114
+ !!val &&
115
+ val !== "0" &&
116
+ val !== "false" &&
117
+ val !== "null" &&
118
+ val !== "undefined";
119
+ }
120
+ }
121
+ return { resolved, conditionResult, errors };
122
+ }
123
+ /** Execute a single step */
124
+ export async function executeChainedStep(ctx, deps) {
125
+ const { registry, step, options, depth } = ctx;
126
+ const { dryRun } = options;
127
+ // Build template context
128
+ const templateContext = buildTemplateContext(registry, options.env);
129
+ // Resolve templates
130
+ const { resolved, conditionResult, errors } = resolveStepTemplates(step, templateContext);
131
+ if (errors.length > 0) {
132
+ return {
133
+ success: false,
134
+ error: `Template errors: ${errors.map((e) => e.message).join(", ")}`,
135
+ };
136
+ }
137
+ // Check when condition
138
+ if (!conditionResult) {
139
+ return {
140
+ success: true,
141
+ skipped: true,
142
+ data: { skipped: true, reason: "when condition falsy" },
143
+ };
144
+ }
145
+ // Dry run: just report what would happen
146
+ if (dryRun) {
147
+ const recipeRef = nestedRecipeRef(step);
148
+ return {
149
+ success: true,
150
+ data: {
151
+ dryRun: true,
152
+ stepType: recipeRef ? "recipe" : step.agent ? "agent" : "tool",
153
+ wouldExecute: (step.tool ?? step.agent) ? "prompt" : recipeRef,
154
+ resolvedParams: Object.keys(resolved).length > 0 ? resolved : undefined,
155
+ },
156
+ };
157
+ }
158
+ /** Flat `{{ key }}` renderer for transform strings — mirrors yamlRunner.render */
159
+ function applyTransform(template, rawResult, ctx) {
160
+ const resultStr = typeof rawResult === "string" ? rawResult : JSON.stringify(rawResult);
161
+ const flatCtx = { $result: resultStr };
162
+ // Expose env keys as flat vars too
163
+ for (const [k, v] of Object.entries(ctx.env)) {
164
+ if (v !== undefined)
165
+ flatCtx[k] = v;
166
+ }
167
+ try {
168
+ return template.replace(/\{\{\s*([^}]+?)\s*\}\}/g, (_, expr) => {
169
+ const key = expr.trim();
170
+ return Object.hasOwn(flatCtx, key) ? (flatCtx[key] ?? "") : "";
171
+ });
172
+ }
173
+ catch {
174
+ return rawResult;
175
+ }
176
+ }
177
+ // VD-4 mocked replay: short-circuit BEFORE executing tool/agent. The
178
+ // step still runs through template + condition resolution + transform
179
+ // (so the user sees how upstream outputs flow downstream) but tool /
180
+ // agent / nested-recipe execution is replaced with the captured
181
+ // output from the original run. Templates may still re-resolve to
182
+ // different values if the recipe was edited — that's expected; it's
183
+ // what makes mocked replay useful for debugging template wiring.
184
+ if (options.mockedOutputs?.has(step.id)) {
185
+ let mockedData = options.mockedOutputs.get(step.id);
186
+ if (step.transform) {
187
+ try {
188
+ mockedData = applyTransform(step.transform, mockedData, templateContext);
189
+ }
190
+ catch (err) {
191
+ console.warn(`transform failed for step ${step.id}: ${err}`);
192
+ }
193
+ }
194
+ return {
195
+ success: true,
196
+ data: mockedData,
197
+ resolvedParams: resolved,
198
+ };
199
+ }
200
+ // Execute based on step type
201
+ try {
202
+ const recipeRef = nestedRecipeRef(step);
203
+ if (recipeRef) {
204
+ // Nested recipe call
205
+ const nestedConfig = {
206
+ recipe: recipeRef,
207
+ vars: step.vars ?? {},
208
+ output: step.output ?? step.id,
209
+ risk: step.risk,
210
+ id: step.id,
211
+ };
212
+ const nestedContext = {
213
+ parentRegistry: registry,
214
+ parentEnv: options.env,
215
+ recipeMaxDepth: options.maxDepth,
216
+ currentDepth: depth,
217
+ dryRun,
218
+ };
219
+ if (dryRun) {
220
+ const result = await mockNestedRecipe(nestedConfig, nestedContext);
221
+ return {
222
+ success: result.success,
223
+ data: result.data,
224
+ error: result.error,
225
+ };
226
+ }
227
+ // Load and execute nested recipe
228
+ const nestedRecipe = await deps.loadNestedRecipe(recipeRef, options.sourcePath);
229
+ if (!nestedRecipe) {
230
+ return {
231
+ success: false,
232
+ error: `Nested recipe "${recipeRef}" not found`,
233
+ };
234
+ }
235
+ const validation = validateNestedRecipe(nestedConfig, nestedContext);
236
+ if (!validation.valid) {
237
+ return { success: false, error: validation.error };
238
+ }
239
+ // Resolve vars for child
240
+ const { resolved: resolvedVars, errors: varErrors } = resolveNestedVars(step.vars ?? {}, templateContext);
241
+ if (varErrors.length > 0) {
242
+ return {
243
+ success: false,
244
+ error: `Variable template errors: ${varErrors.map((e) => e.message).join(", ")}`,
245
+ };
246
+ }
247
+ // Execute child recipe with isolated registry
248
+ const childRegistry = createOutputRegistry();
249
+ const childOptions = {
250
+ ...options,
251
+ maxDepth: options.maxDepth,
252
+ sourcePath: nestedRecipe.sourcePath,
253
+ env: { ...options.env, ...resolvedVars }, // Merge resolved vars into env
254
+ };
255
+ const childResult = await runChainedRecipe(nestedRecipe.recipe, childOptions, deps, childRegistry, depth + 1);
256
+ return {
257
+ success: !childResult.errorMessage,
258
+ data: {
259
+ recipe: recipeRef,
260
+ childSummary: childRegistry.summary(),
261
+ childOutputs: Object.fromEntries(childRegistry.keys().map((k) => [k, childRegistry.get(k)?.data])),
262
+ },
263
+ };
264
+ }
265
+ else if (step.agent) {
266
+ // Agent step
267
+ const prompt = resolved.agentPrompt ?? step.agent.prompt;
268
+ let result = await deps.executeAgent(prompt, step.agent.model, step.agent.driver);
269
+ if (step.transform) {
270
+ try {
271
+ result = applyTransform(step.transform, result, templateContext);
272
+ }
273
+ catch (err) {
274
+ console.warn(`transform failed for step ${step.id}: ${err}`);
275
+ }
276
+ }
277
+ return { success: true, data: result, resolvedParams: resolved };
278
+ }
279
+ else if (step.tool) {
280
+ // Tool step
281
+ let result = await deps.executeTool(step.tool, resolved);
282
+ if (step.transform) {
283
+ try {
284
+ result = applyTransform(step.transform, result, templateContext);
285
+ }
286
+ catch (err) {
287
+ console.warn(`transform failed for step ${step.id}: ${err}`);
288
+ }
289
+ }
290
+ return { success: true, data: result, resolvedParams: resolved };
291
+ }
292
+ else {
293
+ return { success: false, error: "Step has no tool, agent, or recipe" };
294
+ }
295
+ }
296
+ catch (error) {
297
+ const msg = error instanceof Error ? error.message : String(error);
298
+ return { success: false, error: msg };
299
+ }
300
+ }
301
+ async function withRetry(fn, maxRetries, delayMs) {
302
+ let last = { success: false };
303
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
304
+ if (attempt > 0) {
305
+ await new Promise((r) => setTimeout(r, delayMs));
306
+ }
307
+ last = await fn();
308
+ if (last.success)
309
+ return last;
310
+ }
311
+ return last;
312
+ }
313
+ /**
314
+ * Expand `parallel:` sugar into flat steps with auto-generated ids and
315
+ * correct `awaits` wiring so the existing dependency graph handles execution.
316
+ *
317
+ * A `parallel:` step is a group container — it has no id/tool/agent of its
318
+ * own. Each child in the group inherits the group's `awaits` and is assigned
319
+ * an id of `<groupId>_<index>`. Steps that previously awaited the group
320
+ * (determined by a post-pass) are rewritten to await all children instead.
321
+ *
322
+ * Expansion is recursive so nested `parallel:` blocks work too.
323
+ */
324
+ export function expandParallelSteps(steps) {
325
+ const flat = [];
326
+ // Maps a group placeholder id → the ids of its expanded children.
327
+ const groupChildren = new Map();
328
+ for (let i = 0; i < steps.length; i++) {
329
+ const step = steps[i];
330
+ if (!step)
331
+ continue;
332
+ if (Array.isArray(step.parallel) && step.parallel.length > 0) {
333
+ // Generate a stable group id from position if the group has no id.
334
+ const groupId = step.id ?? `parallel_${i}`;
335
+ const groupAwaits = step.awaits ?? [];
336
+ const childIds = [];
337
+ for (let j = 0; j < step.parallel.length; j++) {
338
+ const child = step.parallel[j];
339
+ if (!child)
340
+ continue;
341
+ const childId = child.id ?? `${groupId}_${j}`;
342
+ childIds.push(childId);
343
+ // Expand child recursively in case it also has parallel:.
344
+ const expanded = expandParallelSteps([
345
+ {
346
+ ...child,
347
+ id: childId,
348
+ awaits: [...groupAwaits, ...(child.awaits ?? [])],
349
+ },
350
+ ]);
351
+ flat.push(...expanded);
352
+ }
353
+ groupChildren.set(groupId, childIds);
354
+ }
355
+ else {
356
+ flat.push(step);
357
+ }
358
+ }
359
+ // Rewrite awaits: any step that awaited a group id now awaits all its children.
360
+ if (groupChildren.size === 0)
361
+ return flat;
362
+ return flat.map((step) => {
363
+ if (!step.awaits?.length)
364
+ return step;
365
+ const rewritten = step.awaits.flatMap((dep) => groupChildren.get(dep) ?? [dep]);
366
+ // Deduplicate while preserving order.
367
+ const seen = new Set();
368
+ const deduped = rewritten.filter((id) => {
369
+ if (seen.has(id))
370
+ return false;
371
+ seen.add(id);
372
+ return true;
373
+ });
374
+ return { ...step, awaits: deduped };
375
+ });
376
+ }
377
+ /** Main entry point: run a chained recipe */
378
+ export async function runChainedRecipe(recipe, options, deps, existingRegistry, depth = 0) {
379
+ // Load plugin servers declared in the recipe before executing any steps.
380
+ // Only done at the top-level call (depth 0) to avoid redundant loads in nested recipes.
381
+ if (depth === 0 && recipe.servers?.length) {
382
+ try {
383
+ const { loadRecipeServers } = await import("./yamlRunner.js");
384
+ await loadRecipeServers(recipe.servers);
385
+ }
386
+ catch {
387
+ // Non-fatal — if yamlRunner import fails, proceed without plugins
388
+ }
389
+ }
390
+ const registry = existingRegistry ?? createOutputRegistry();
391
+ // Expand parallel: sugar into flat steps before building the dependency graph.
392
+ const steps = expandParallelSteps(recipe.steps);
393
+ // Build dependency graph
394
+ const depGraph = buildDependencyGraph(steps.map((s, i) => ({ id: s.id ?? `step_${i}`, awaits: s.awaits })));
395
+ const runStartedAt = Date.now();
396
+ // Open a `running`-state run-log entry so the dashboard sees the recipe
397
+ // as in flight (depth 0 only — nested recipes are part of their parent
398
+ // run). The seq is used by VD-1 live-tail to correlate step events.
399
+ const recipeTriggerKind = recipe.trigger?.type ??
400
+ "recipe";
401
+ const triggerKind = (["cron", "webhook", "recipe"].includes(recipeTriggerKind)
402
+ ? recipeTriggerKind
403
+ : "recipe");
404
+ const taskIdPrefix = options.taskIdPrefix ?? "chained";
405
+ const runTaskId = `${taskIdPrefix}:${recipe.name}:${runStartedAt}`;
406
+ let runSeq;
407
+ if (depth === 0 && options.runLog) {
408
+ try {
409
+ runSeq = options.runLog.startRun({
410
+ taskId: runTaskId,
411
+ recipeName: recipe.name,
412
+ trigger: triggerKind,
413
+ createdAt: runStartedAt,
414
+ startedAt: runStartedAt,
415
+ ...(options.parentSeq !== undefined && {
416
+ parentSeq: options.parentSeq,
417
+ }),
418
+ });
419
+ }
420
+ catch {
421
+ // Non-fatal — run-log failures must never break recipe execution.
422
+ }
423
+ }
424
+ if (depGraph.hasCycles) {
425
+ if (depth === 0) {
426
+ const doneAt = Date.now();
427
+ const durationMs = doneAt - runStartedAt;
428
+ try {
429
+ if (options.runLog && runSeq !== undefined) {
430
+ options.runLog.completeRun(runSeq, {
431
+ status: "error",
432
+ doneAt,
433
+ durationMs,
434
+ stepResults: [],
435
+ errorMessage: "Recipe has circular dependencies",
436
+ });
437
+ }
438
+ else if (options.runLogDir) {
439
+ const { RecipeRunLog } = await import("../runLog.js");
440
+ const log = new RecipeRunLog({ dir: options.runLogDir });
441
+ log.appendDirect({
442
+ taskId: runTaskId,
443
+ recipeName: recipe.name,
444
+ trigger: triggerKind,
445
+ status: "error",
446
+ createdAt: runStartedAt,
447
+ startedAt: runStartedAt,
448
+ doneAt,
449
+ durationMs,
450
+ errorMessage: "Recipe has circular dependencies",
451
+ stepResults: [],
452
+ });
453
+ }
454
+ }
455
+ catch {
456
+ // Non-fatal — run-log failures must never break recipe execution.
457
+ }
458
+ }
459
+ return {
460
+ success: false,
461
+ stepResults: new Map(),
462
+ summary: { total: 0, succeeded: 0, failed: 0, skipped: 0 },
463
+ errorMessage: "Recipe has circular dependencies",
464
+ context: {},
465
+ };
466
+ }
467
+ // Create step lookup from expanded steps.
468
+ const stepMap = new Map();
469
+ for (let i = 0; i < steps.length; i++) {
470
+ const step = steps[i];
471
+ if (!step)
472
+ continue;
473
+ const stepId = step.id ?? `step_${i}`;
474
+ stepMap.set(stepId, { ...step, id: stepId });
475
+ }
476
+ const stepTimings = new Map();
477
+ // VD-2: per-step capture (resolved params + output + registry snapshot).
478
+ // Populated at the `registry.set(...)` site during step execution and
479
+ // attached to the final `RunStepResult` written via `completeRun`.
480
+ const capturedStepData = new Map();
481
+ // VD-1 live-tail: when an `activityLog` is provided AND we have a `runSeq`
482
+ // (depth 0, runLog supplied), broadcast `recipe_step_start` /
483
+ // `recipe_step_done` events so the dashboard `/runs/[seq]` page can
484
+ // subscribe to step changes via SSE instead of 3s polling.
485
+ const broadcastActivity = options.activityLog;
486
+ const broadcastSeq = runSeq;
487
+ const broadcastName = recipe.name;
488
+ const stepStartTimes = new Map();
489
+ const wrappedOnStepStart = broadcastActivity && broadcastSeq !== undefined
490
+ ? (stepId) => {
491
+ const ts = Date.now();
492
+ stepStartTimes.set(stepId, ts);
493
+ try {
494
+ broadcastActivity.recordEvent("recipe_step_start", {
495
+ runSeq: broadcastSeq,
496
+ recipeName: broadcastName,
497
+ stepId,
498
+ tool: stepMap.get(stepId)?.tool,
499
+ ts,
500
+ });
501
+ }
502
+ catch {
503
+ // never let live-tail failure break the run
504
+ }
505
+ options.onStepStart?.(stepId);
506
+ }
507
+ : options.onStepStart;
508
+ const wrappedOnStepComplete = broadcastActivity && broadcastSeq !== undefined
509
+ ? (stepId, error) => {
510
+ const ts = Date.now();
511
+ const startedAt = stepStartTimes.get(stepId);
512
+ try {
513
+ broadcastActivity.recordEvent("recipe_step_done", {
514
+ runSeq: broadcastSeq,
515
+ recipeName: broadcastName,
516
+ stepId,
517
+ tool: stepMap.get(stepId)?.tool,
518
+ status: error ? "error" : "ok",
519
+ ...(error?.message !== undefined && { error: error.message }),
520
+ ...(startedAt !== undefined && {
521
+ durationMs: ts - startedAt,
522
+ }),
523
+ ts,
524
+ });
525
+ }
526
+ catch {
527
+ // never let live-tail failure break the run
528
+ }
529
+ options.onStepComplete?.(stepId, error);
530
+ }
531
+ : options.onStepComplete;
532
+ // Execute with dependency tracking
533
+ const execOptions = {
534
+ maxConcurrency: options.maxConcurrency,
535
+ onStepStart: wrappedOnStepStart,
536
+ onStepComplete: wrappedOnStepComplete,
537
+ };
538
+ const stepExecutor = async (stepId) => {
539
+ const step = stepMap.get(stepId);
540
+ if (!step)
541
+ throw new Error(`Step ${stepId} not found`);
542
+ const ctx = {
543
+ registry,
544
+ step,
545
+ options,
546
+ recipe,
547
+ depth,
548
+ };
549
+ const retryCount = step.retry ?? recipe.on_error?.retry ?? 0;
550
+ const retryDelay = step.retryDelay ?? recipe.on_error?.retryDelay ?? 1000;
551
+ const stepStart = Date.now();
552
+ const result = await withRetry(() => executeChainedStep(ctx, deps), retryCount, retryDelay);
553
+ stepTimings.set(stepId, {
554
+ durationMs: Date.now() - stepStart,
555
+ skipped: result.skipped,
556
+ });
557
+ // Recipe-level on_error.fallback: "log_only" and "deliver_original" both
558
+ // treat step failures as non-fatal (fail-open) — same semantics as
559
+ // step-level optional: true. "abort" is the default (propagate failure).
560
+ const recipeFallback = recipe.on_error?.fallback;
561
+ const recipeFallbackFailOpen = recipeFallback === "log_only" || recipeFallback === "deliver_original";
562
+ const isOptional = step.optional === true || recipeFallbackFailOpen;
563
+ const effectiveSuccess = result.success || isOptional;
564
+ if (!result.success && recipeFallbackFailOpen && !step.optional) {
565
+ console.warn(`step ${stepId} failed but on_error.fallback=${recipeFallback} — treating as non-fatal: ${result.error ?? "unknown error"}`);
566
+ }
567
+ // Store output in registry with accurate status
568
+ registry.set(stepId, {
569
+ status: result.skipped
570
+ ? "skipped"
571
+ : result.success
572
+ ? "success"
573
+ : isOptional
574
+ ? "success"
575
+ : "error",
576
+ data: result.data,
577
+ });
578
+ // VD-2: capture per-step inputs/outputs/registry snapshot for the
579
+ // dashboard's diff hover + replay. Only at depth 0 (nested steps are
580
+ // part of their parent's audit) and only when we have a runSeq +
581
+ // runLog to push into. Sensitive keys are redacted; large values
582
+ // truncated to 8 KB.
583
+ if (depth === 0 && options.runLog && runSeq !== undefined) {
584
+ try {
585
+ const snapshot = {};
586
+ for (const k of registry.keys()) {
587
+ const v = registry.get(k);
588
+ if (v !== undefined)
589
+ snapshot[k] = v;
590
+ }
591
+ capturedStepData.set(stepId, {
592
+ resolvedParams: captureForRunlog(result.resolvedParams),
593
+ output: captureForRunlog(result.data),
594
+ registrySnapshot: captureForRunlog(snapshot),
595
+ startedAt: stepStart,
596
+ });
597
+ }
598
+ catch {
599
+ // Capture is best-effort — never let a serialization failure
600
+ // break the run.
601
+ }
602
+ }
603
+ // Optional steps must not propagate failure to the executor
604
+ if (!effectiveSuccess) {
605
+ throw new Error(result.error ?? `Step ${stepId} failed`);
606
+ }
607
+ };
608
+ const stepResults = await executeWithDependencies(depGraph, stepExecutor, execOptions);
609
+ // Merge timings into step results
610
+ const enrichedResults = new Map();
611
+ let failed = 0;
612
+ for (const [id, result] of stepResults) {
613
+ const timing = stepTimings.get(id);
614
+ enrichedResults.set(id, {
615
+ ...result,
616
+ skipped: timing?.skipped,
617
+ durationMs: timing?.durationMs,
618
+ });
619
+ if (!result.success)
620
+ failed++;
621
+ }
622
+ // Build string context map from registry for expect: assertions
623
+ const context = {};
624
+ for (const id of registry.keys()) {
625
+ const entry = registry.get(id);
626
+ if (entry?.data !== undefined) {
627
+ context[id] =
628
+ typeof entry.data === "string"
629
+ ? entry.data
630
+ : JSON.stringify(entry.data);
631
+ }
632
+ }
633
+ const result = {
634
+ success: failed === 0,
635
+ stepResults: enrichedResults,
636
+ summary: registry.summary(),
637
+ errorMessage: failed > 0 ? `${failed} step(s) failed` : undefined,
638
+ context,
639
+ };
640
+ // Write to RecipeRunLog so the dashboard Runs page shows chained executions.
641
+ // Only top-level (depth 0) runs are logged — nested recipe calls are part of
642
+ // their parent's run. Failures here must never break recipe execution.
643
+ //
644
+ // Two paths:
645
+ // - `options.runLog` (bridge-driven): we already called `startRun` above.
646
+ // Finalize via `completeRun` so the dashboard sees the live status flip.
647
+ // - `options.runLogDir` (CLI): construct a local log + `appendDirect`.
648
+ // No live-tail, but back-compat with the pre-VD-1 CLI flow.
649
+ if (depth === 0 && (options.runLog || options.runLogDir)) {
650
+ try {
651
+ const doneAt = Date.now();
652
+ const stepResultsList = [];
653
+ for (const [id, r] of enrichedResults) {
654
+ const step = stepMap.get(id);
655
+ const captured = capturedStepData.get(id);
656
+ stepResultsList.push({
657
+ id,
658
+ tool: step?.tool,
659
+ status: r.skipped ? "skipped" : r.success ? "ok" : "error",
660
+ error: r.error?.message,
661
+ durationMs: r.durationMs ?? 0,
662
+ ...(captured?.resolvedParams !== undefined && {
663
+ resolvedParams: captured.resolvedParams,
664
+ }),
665
+ ...(captured?.output !== undefined && { output: captured.output }),
666
+ ...(captured?.registrySnapshot !== undefined && {
667
+ registrySnapshot: captured.registrySnapshot,
668
+ }),
669
+ ...(captured?.startedAt !== undefined && {
670
+ startedAt: captured.startedAt,
671
+ }),
672
+ });
673
+ }
674
+ const outputTail = stepResultsList
675
+ .map((s) => `[${s.status}] ${s.tool ?? s.id}${s.error ? `: ${s.error}` : ""}`)
676
+ .join("\n")
677
+ .slice(0, 2000);
678
+ if (options.runLog && runSeq !== undefined) {
679
+ options.runLog.completeRun(runSeq, {
680
+ status: result.success ? "done" : "error",
681
+ doneAt,
682
+ durationMs: doneAt - runStartedAt,
683
+ stepResults: stepResultsList,
684
+ outputTail,
685
+ ...(result.errorMessage !== undefined && {
686
+ errorMessage: result.errorMessage,
687
+ }),
688
+ });
689
+ }
690
+ else if (options.runLogDir) {
691
+ const { RecipeRunLog } = await import("../runLog.js");
692
+ const log = new RecipeRunLog({ dir: options.runLogDir });
693
+ log.appendDirect({
694
+ taskId: runTaskId,
695
+ recipeName: recipe.name,
696
+ trigger: triggerKind,
697
+ status: result.success ? "done" : "error",
698
+ createdAt: runStartedAt,
699
+ startedAt: runStartedAt,
700
+ doneAt,
701
+ durationMs: doneAt - runStartedAt,
702
+ outputTail,
703
+ errorMessage: result.errorMessage,
704
+ stepResults: stepResultsList,
705
+ });
706
+ }
707
+ }
708
+ catch {
709
+ // Non-fatal — run log write failure must never break recipe execution
710
+ }
711
+ }
712
+ return result;
713
+ }
714
+ /** Generate execution plan for dry-run mode */
715
+ export function generateExecutionPlan(recipe) {
716
+ const expandedSteps = expandParallelSteps(recipe.steps);
717
+ const depGraph = buildDependencyGraph(expandedSteps.map((s, i) => ({
718
+ id: s.id ?? `step_${i}`,
719
+ awaits: s.awaits,
720
+ })));
721
+ // Group by topological levels (parallelizable)
722
+ const levels = [];
723
+ const completed = new Set();
724
+ while (completed.size < depGraph.topologicalOrder.length) {
725
+ const ready = depGraph.topologicalOrder.filter((id) => !completed.has(id) &&
726
+ depGraph.steps
727
+ .find((s) => s.stepId === id)
728
+ ?.awaits.every((dep) => completed.has(dep)));
729
+ if (ready.length === 0)
730
+ break;
731
+ levels.push(ready);
732
+ for (const id of ready)
733
+ completed.add(id);
734
+ }
735
+ return {
736
+ steps: expandedSteps.map((s) => {
737
+ const nestedRef = nestedRecipeRef(s);
738
+ const stepType = nestedRef
739
+ ? "recipe"
740
+ : s.agent
741
+ ? "agent"
742
+ : "tool";
743
+ return {
744
+ id: s.id ?? "",
745
+ type: stepType,
746
+ dependencies: s.awaits ?? [],
747
+ condition: s.when,
748
+ risk: s.risk ?? "low",
749
+ optional: s.optional,
750
+ ...(typeof s.tool === "string" && { tool: s.tool }),
751
+ ...(typeof s.into === "string" && { into: s.into }),
752
+ ...(nestedRef !== undefined && { recipe: nestedRef }),
753
+ };
754
+ }),
755
+ parallelGroups: levels,
756
+ maxDepth: recipe.maxDepth ?? 3,
757
+ };
758
+ }
759
+ //# sourceMappingURL=chainedRunner.js.map