patchwork-os 0.2.0-alpha.8 → 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.
- package/README.bridge.md +6 -0
- package/README.md +315 -35
- package/deploy/bootstrap-new-vps.sh +12 -12
- package/deploy/bootstrap-vps.sh +187 -0
- package/deploy/deploy-dashboard.sh +174 -0
- package/deploy/deploy-landing.sh +136 -0
- package/dist/activationMetrics.d.ts +67 -0
- package/dist/activationMetrics.js +255 -0
- package/dist/activationMetrics.js.map +1 -0
- package/dist/activityLog.d.ts +49 -0
- package/dist/activityLog.js +78 -0
- package/dist/activityLog.js.map +1 -1
- package/dist/approvalHttp.d.ts +49 -2
- package/dist/approvalHttp.js +217 -21
- package/dist/approvalHttp.js.map +1 -1
- package/dist/approvalInsights.d.ts +49 -0
- package/dist/approvalInsights.js +97 -0
- package/dist/approvalInsights.js.map +1 -0
- package/dist/approvalQueue.d.ts +27 -1
- package/dist/approvalQueue.js +123 -3
- package/dist/approvalQueue.js.map +1 -1
- package/dist/approvalSignals.d.ts +124 -0
- package/dist/approvalSignals.js +512 -0
- package/dist/approvalSignals.js.map +1 -0
- package/dist/automation.d.ts +57 -0
- package/dist/automation.js +156 -59
- package/dist/automation.js.map +1 -1
- package/dist/automationSuggestions.d.ts +79 -0
- package/dist/automationSuggestions.js +150 -0
- package/dist/automationSuggestions.js.map +1 -0
- package/dist/bridge.d.ts +3 -0
- package/dist/bridge.js +174 -143
- package/dist/bridge.js.map +1 -1
- package/dist/bridgeToken.js +57 -19
- package/dist/bridgeToken.js.map +1 -1
- package/dist/ccPermissions.d.ts +15 -0
- package/dist/ccPermissions.js +21 -4
- package/dist/ccPermissions.js.map +1 -1
- package/dist/claudeDriver.js +74 -16
- package/dist/claudeDriver.js.map +1 -1
- package/dist/claudeOrchestrator.d.ts +1 -1
- package/dist/claudeOrchestrator.js +14 -8
- package/dist/claudeOrchestrator.js.map +1 -1
- package/dist/commands/dashboard.js +1 -1
- package/dist/commands/dashboard.js.map +1 -1
- package/dist/commands/launchd.d.ts +2 -0
- package/dist/commands/launchd.js +94 -0
- package/dist/commands/launchd.js.map +1 -0
- package/dist/commands/patchworkInit.d.ts +8 -0
- package/dist/commands/patchworkInit.js +77 -11
- package/dist/commands/patchworkInit.js.map +1 -1
- package/dist/commands/recipe.d.ts +289 -0
- package/dist/commands/recipe.js +1359 -0
- package/dist/commands/recipe.js.map +1 -0
- package/dist/commands/recipeInstall.d.ts +150 -0
- package/dist/commands/recipeInstall.js +647 -0
- package/dist/commands/recipeInstall.js.map +1 -0
- package/dist/commands/tracesExport.d.ts +83 -0
- package/dist/commands/tracesExport.js +269 -0
- package/dist/commands/tracesExport.js.map +1 -0
- package/dist/commands/tracesImport.d.ts +56 -0
- package/dist/commands/tracesImport.js +161 -0
- package/dist/commands/tracesImport.js.map +1 -0
- package/dist/config.d.ts +22 -1
- package/dist/config.js +108 -9
- package/dist/config.js.map +1 -1
- package/dist/connectorRoutes.d.ts +43 -0
- package/dist/connectorRoutes.js +1609 -0
- package/dist/connectorRoutes.js.map +1 -0
- package/dist/connectors/asana.d.ts +198 -0
- package/dist/connectors/asana.js +679 -0
- package/dist/connectors/asana.js.map +1 -0
- package/dist/connectors/baseConnector.d.ts +153 -0
- package/dist/connectors/baseConnector.js +336 -0
- package/dist/connectors/baseConnector.js.map +1 -0
- package/dist/connectors/confluence.d.ts +111 -0
- package/dist/connectors/confluence.js +406 -0
- package/dist/connectors/confluence.js.map +1 -0
- package/dist/connectors/datadog.d.ts +116 -0
- package/dist/connectors/datadog.js +385 -0
- package/dist/connectors/datadog.js.map +1 -0
- package/dist/connectors/discord.d.ts +150 -0
- package/dist/connectors/discord.js +543 -0
- package/dist/connectors/discord.js.map +1 -0
- package/dist/connectors/fixtureLibrary.d.ts +21 -0
- package/dist/connectors/fixtureLibrary.js +70 -0
- package/dist/connectors/fixtureLibrary.js.map +1 -0
- package/dist/connectors/fixtureRecorder.d.ts +1 -0
- package/dist/connectors/fixtureRecorder.js +35 -0
- package/dist/connectors/fixtureRecorder.js.map +1 -0
- package/dist/connectors/github.js +17 -18
- package/dist/connectors/github.js.map +1 -1
- package/dist/connectors/gitlab.d.ts +180 -0
- package/dist/connectors/gitlab.js +582 -0
- package/dist/connectors/gitlab.js.map +1 -0
- package/dist/connectors/gmail.d.ts +4 -1
- package/dist/connectors/gmail.js +157 -27
- package/dist/connectors/gmail.js.map +1 -1
- package/dist/connectors/googleCalendar.d.ts +4 -1
- package/dist/connectors/googleCalendar.js +88 -25
- package/dist/connectors/googleCalendar.js.map +1 -1
- package/dist/connectors/googleDrive.d.ts +34 -0
- package/dist/connectors/googleDrive.js +321 -0
- package/dist/connectors/googleDrive.js.map +1 -0
- package/dist/connectors/htmlEscape.d.ts +5 -0
- package/dist/connectors/htmlEscape.js +13 -0
- package/dist/connectors/htmlEscape.js.map +1 -0
- package/dist/connectors/hubspot.d.ts +112 -0
- package/dist/connectors/hubspot.js +408 -0
- package/dist/connectors/hubspot.js.map +1 -0
- package/dist/connectors/intercom.d.ts +102 -0
- package/dist/connectors/intercom.js +402 -0
- package/dist/connectors/intercom.js.map +1 -0
- package/dist/connectors/jira.d.ts +98 -0
- package/dist/connectors/jira.js +379 -0
- package/dist/connectors/jira.js.map +1 -0
- package/dist/connectors/linear.js +30 -19
- package/dist/connectors/linear.js.map +1 -1
- package/dist/connectors/mcpOAuth.d.ts +3 -0
- package/dist/connectors/mcpOAuth.js +64 -10
- package/dist/connectors/mcpOAuth.js.map +1 -1
- package/dist/connectors/mockConnector.d.ts +28 -0
- package/dist/connectors/mockConnector.js +81 -0
- package/dist/connectors/mockConnector.js.map +1 -0
- package/dist/connectors/notion.d.ts +143 -0
- package/dist/connectors/notion.js +424 -0
- package/dist/connectors/notion.js.map +1 -0
- package/dist/connectors/oauthStateStore.d.ts +31 -0
- package/dist/connectors/oauthStateStore.js +52 -0
- package/dist/connectors/oauthStateStore.js.map +1 -0
- package/dist/connectors/pagerduty.d.ts +160 -0
- package/dist/connectors/pagerduty.js +464 -0
- package/dist/connectors/pagerduty.js.map +1 -0
- package/dist/connectors/sentry.js +5 -13
- package/dist/connectors/sentry.js.map +1 -1
- package/dist/connectors/slack.d.ts +16 -1
- package/dist/connectors/slack.js +155 -32
- package/dist/connectors/slack.js.map +1 -1
- package/dist/connectors/stripe.d.ts +116 -0
- package/dist/connectors/stripe.js +379 -0
- package/dist/connectors/stripe.js.map +1 -0
- package/dist/connectors/tokenStorage.d.ts +35 -0
- package/dist/connectors/tokenStorage.js +484 -0
- package/dist/connectors/tokenStorage.js.map +1 -0
- package/dist/connectors/zendesk.d.ts +104 -0
- package/dist/connectors/zendesk.js +442 -0
- package/dist/connectors/zendesk.js.map +1 -0
- package/dist/cors.d.ts +10 -0
- package/dist/cors.js +29 -0
- package/dist/cors.js.map +1 -0
- package/dist/decisionReplay.d.ts +72 -0
- package/dist/decisionReplay.js +92 -0
- package/dist/decisionReplay.js.map +1 -0
- package/dist/decisionTraceLog.d.ts +6 -0
- package/dist/decisionTraceLog.js +54 -2
- package/dist/decisionTraceLog.js.map +1 -1
- package/dist/drivers/gemini/index.d.ts +5 -1
- package/dist/drivers/gemini/index.js +39 -5
- package/dist/drivers/gemini/index.js.map +1 -1
- package/dist/drivers/index.d.ts +5 -0
- package/dist/drivers/index.js +1 -1
- package/dist/drivers/index.js.map +1 -1
- package/dist/featureFlags.d.ts +79 -0
- package/dist/featureFlags.js +208 -0
- package/dist/featureFlags.js.map +1 -0
- package/dist/fp/automationInterpreter.js +26 -21
- package/dist/fp/automationInterpreter.js.map +1 -1
- package/dist/fp/automationProgram.d.ts +1 -1
- package/dist/fp/automationProgram.js.map +1 -1
- package/dist/fp/automationState.js +4 -1
- package/dist/fp/automationState.js.map +1 -1
- package/dist/fp/policyParser.js +21 -1
- package/dist/fp/policyParser.js.map +1 -1
- package/dist/inboxRoutes.d.ts +22 -0
- package/dist/inboxRoutes.js +114 -0
- package/dist/inboxRoutes.js.map +1 -0
- package/dist/index.js +1400 -201
- package/dist/index.js.map +1 -1
- package/dist/installGuard.d.ts +25 -0
- package/dist/installGuard.js +48 -0
- package/dist/installGuard.js.map +1 -0
- package/dist/mcpRoutes.d.ts +37 -0
- package/dist/mcpRoutes.js +76 -0
- package/dist/mcpRoutes.js.map +1 -0
- package/dist/oauth.d.ts +7 -1
- package/dist/oauth.js +201 -39
- package/dist/oauth.js.map +1 -1
- package/dist/oauthRoutes.d.ts +32 -0
- package/dist/oauthRoutes.js +124 -0
- package/dist/oauthRoutes.js.map +1 -0
- package/dist/orchestrator/orchestratorBridge.js +2 -2
- package/dist/orchestrator/orchestratorBridge.js.map +1 -1
- package/dist/patchworkConfig.d.ts +16 -0
- package/dist/patchworkConfig.js +1 -1
- package/dist/patchworkConfig.js.map +1 -1
- package/dist/pluginLoader.d.ts +28 -0
- package/dist/pluginLoader.js +77 -11
- package/dist/pluginLoader.js.map +1 -1
- package/dist/pluginWatcher.js +8 -3
- package/dist/pluginWatcher.js.map +1 -1
- package/dist/preToolUseHook.d.ts +12 -0
- package/dist/preToolUseHook.js +23 -0
- package/dist/preToolUseHook.js.map +1 -1
- package/dist/recipeOrchestration.d.ts +121 -0
- package/dist/recipeOrchestration.js +955 -0
- package/dist/recipeOrchestration.js.map +1 -0
- package/dist/recipeRoutes.d.ts +180 -0
- package/dist/recipeRoutes.js +1345 -0
- package/dist/recipeRoutes.js.map +1 -0
- package/dist/recipes/RecipeOrchestrator.d.ts +40 -0
- package/dist/recipes/RecipeOrchestrator.js +51 -0
- package/dist/recipes/RecipeOrchestrator.js.map +1 -0
- package/dist/recipes/agentExecutor.d.ts +29 -0
- package/dist/recipes/agentExecutor.js +49 -0
- package/dist/recipes/agentExecutor.js.map +1 -0
- package/dist/recipes/chainedRunner.d.ts +191 -0
- package/dist/recipes/chainedRunner.js +759 -0
- package/dist/recipes/chainedRunner.js.map +1 -0
- package/dist/recipes/compiler.js +3 -3
- package/dist/recipes/compiler.js.map +1 -1
- package/dist/recipes/dependencyGraph.d.ts +39 -0
- package/dist/recipes/dependencyGraph.js +199 -0
- package/dist/recipes/dependencyGraph.js.map +1 -0
- package/dist/recipes/disabledMarkers.d.ts +48 -0
- package/dist/recipes/disabledMarkers.js +52 -0
- package/dist/recipes/disabledMarkers.js.map +1 -0
- package/dist/recipes/installer.js +3 -3
- package/dist/recipes/installer.js.map +1 -1
- package/dist/recipes/legacyRecipeCompat.d.ts +10 -0
- package/dist/recipes/legacyRecipeCompat.js +131 -0
- package/dist/recipes/legacyRecipeCompat.js.map +1 -0
- package/dist/recipes/manifest.d.ts +47 -0
- package/dist/recipes/manifest.js +156 -0
- package/dist/recipes/manifest.js.map +1 -0
- package/dist/recipes/migrationWarnings.d.ts +12 -0
- package/dist/recipes/migrationWarnings.js +44 -0
- package/dist/recipes/migrationWarnings.js.map +1 -0
- package/dist/recipes/migrations/index.d.ts +24 -0
- package/dist/recipes/migrations/index.js +55 -0
- package/dist/recipes/migrations/index.js.map +1 -0
- package/dist/recipes/migrations/types.d.ts +28 -0
- package/dist/recipes/migrations/types.js +2 -0
- package/dist/recipes/migrations/types.js.map +1 -0
- package/dist/recipes/migrations/v1.d.ts +11 -0
- package/dist/recipes/migrations/v1.js +18 -0
- package/dist/recipes/migrations/v1.js.map +1 -0
- package/dist/recipes/names.d.ts +40 -0
- package/dist/recipes/names.js +66 -0
- package/dist/recipes/names.js.map +1 -0
- package/dist/recipes/nestedRecipeStep.d.ts +58 -0
- package/dist/recipes/nestedRecipeStep.js +95 -0
- package/dist/recipes/nestedRecipeStep.js.map +1 -0
- package/dist/recipes/outputRegistry.d.ts +28 -0
- package/dist/recipes/outputRegistry.js +52 -0
- package/dist/recipes/outputRegistry.js.map +1 -0
- package/dist/recipes/parser.js +4 -1
- package/dist/recipes/parser.js.map +1 -1
- package/dist/recipes/replayRun.d.ts +62 -0
- package/dist/recipes/replayRun.js +97 -0
- package/dist/recipes/replayRun.js.map +1 -0
- package/dist/recipes/resolveRecipePath.d.ts +69 -0
- package/dist/recipes/resolveRecipePath.js +202 -0
- package/dist/recipes/resolveRecipePath.js.map +1 -0
- package/dist/recipes/scheduler.d.ts +23 -7
- package/dist/recipes/scheduler.js +225 -45
- package/dist/recipes/scheduler.js.map +1 -1
- package/dist/recipes/schema.d.ts +17 -2
- package/dist/recipes/schemaGenerator.d.ts +28 -0
- package/dist/recipes/schemaGenerator.js +565 -0
- package/dist/recipes/schemaGenerator.js.map +1 -0
- package/dist/recipes/stepObservation.d.ts +44 -0
- package/dist/recipes/stepObservation.js +232 -0
- package/dist/recipes/stepObservation.js.map +1 -0
- package/dist/recipes/templateEngine.d.ts +62 -0
- package/dist/recipes/templateEngine.js +201 -0
- package/dist/recipes/templateEngine.js.map +1 -0
- package/dist/recipes/toolRegistry.d.ts +186 -0
- package/dist/recipes/toolRegistry.js +309 -0
- package/dist/recipes/toolRegistry.js.map +1 -0
- package/dist/recipes/tools/asana.d.ts +16 -0
- package/dist/recipes/tools/asana.js +524 -0
- package/dist/recipes/tools/asana.js.map +1 -0
- package/dist/recipes/tools/calendar.d.ts +6 -0
- package/dist/recipes/tools/calendar.js +61 -0
- package/dist/recipes/tools/calendar.js.map +1 -0
- package/dist/recipes/tools/confluence.d.ts +6 -0
- package/dist/recipes/tools/confluence.js +254 -0
- package/dist/recipes/tools/confluence.js.map +1 -0
- package/dist/recipes/tools/datadog.d.ts +6 -0
- package/dist/recipes/tools/datadog.js +239 -0
- package/dist/recipes/tools/datadog.js.map +1 -0
- package/dist/recipes/tools/diagnostics.d.ts +6 -0
- package/dist/recipes/tools/diagnostics.js +36 -0
- package/dist/recipes/tools/diagnostics.js.map +1 -0
- package/dist/recipes/tools/discord.d.ts +18 -0
- package/dist/recipes/tools/discord.js +254 -0
- package/dist/recipes/tools/discord.js.map +1 -0
- package/dist/recipes/tools/file.d.ts +12 -0
- package/dist/recipes/tools/file.js +174 -0
- package/dist/recipes/tools/file.js.map +1 -0
- package/dist/recipes/tools/git.d.ts +6 -0
- package/dist/recipes/tools/git.js +63 -0
- package/dist/recipes/tools/git.js.map +1 -0
- package/dist/recipes/tools/github.d.ts +6 -0
- package/dist/recipes/tools/github.js +116 -0
- package/dist/recipes/tools/github.js.map +1 -0
- package/dist/recipes/tools/gitlab.d.ts +11 -0
- package/dist/recipes/tools/gitlab.js +285 -0
- package/dist/recipes/tools/gitlab.js.map +1 -0
- package/dist/recipes/tools/gmail.d.ts +6 -0
- package/dist/recipes/tools/gmail.js +434 -0
- package/dist/recipes/tools/gmail.js.map +1 -0
- package/dist/recipes/tools/googleDrive.d.ts +1 -0
- package/dist/recipes/tools/googleDrive.js +55 -0
- package/dist/recipes/tools/googleDrive.js.map +1 -0
- package/dist/recipes/tools/hubspot.d.ts +6 -0
- package/dist/recipes/tools/hubspot.js +232 -0
- package/dist/recipes/tools/hubspot.js.map +1 -0
- package/dist/recipes/tools/index.d.ts +30 -0
- package/dist/recipes/tools/index.js +33 -0
- package/dist/recipes/tools/index.js.map +1 -0
- package/dist/recipes/tools/intercom.d.ts +6 -0
- package/dist/recipes/tools/intercom.js +226 -0
- package/dist/recipes/tools/intercom.js.map +1 -0
- package/dist/recipes/tools/jira.d.ts +14 -0
- package/dist/recipes/tools/jira.js +369 -0
- package/dist/recipes/tools/jira.js.map +1 -0
- package/dist/recipes/tools/linear.d.ts +7 -0
- package/dist/recipes/tools/linear.js +307 -0
- package/dist/recipes/tools/linear.js.map +1 -0
- package/dist/recipes/tools/meetingNotes.d.ts +21 -0
- package/dist/recipes/tools/meetingNotes.js +701 -0
- package/dist/recipes/tools/meetingNotes.js.map +1 -0
- package/dist/recipes/tools/notion.d.ts +6 -0
- package/dist/recipes/tools/notion.js +278 -0
- package/dist/recipes/tools/notion.js.map +1 -0
- package/dist/recipes/tools/pagerduty.d.ts +15 -0
- package/dist/recipes/tools/pagerduty.js +451 -0
- package/dist/recipes/tools/pagerduty.js.map +1 -0
- package/dist/recipes/tools/sentry.d.ts +12 -0
- package/dist/recipes/tools/sentry.js +73 -0
- package/dist/recipes/tools/sentry.js.map +1 -0
- package/dist/recipes/tools/slack.d.ts +6 -0
- package/dist/recipes/tools/slack.js +82 -0
- package/dist/recipes/tools/slack.js.map +1 -0
- package/dist/recipes/tools/stripe.d.ts +6 -0
- package/dist/recipes/tools/stripe.js +265 -0
- package/dist/recipes/tools/stripe.js.map +1 -0
- package/dist/recipes/tools/zendesk.d.ts +6 -0
- package/dist/recipes/tools/zendesk.js +245 -0
- package/dist/recipes/tools/zendesk.js.map +1 -0
- package/dist/recipes/validation.d.ts +13 -0
- package/dist/recipes/validation.js +617 -0
- package/dist/recipes/validation.js.map +1 -0
- package/dist/recipes/yamlRunner.d.ts +116 -1
- package/dist/recipes/yamlRunner.js +1000 -401
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +137 -6
- package/dist/recipesHttp.js +941 -29
- package/dist/recipesHttp.js.map +1 -1
- package/dist/riskTier.js +7 -1
- package/dist/riskTier.js.map +1 -1
- package/dist/runLog.d.ts +100 -1
- package/dist/runLog.js +258 -5
- package/dist/runLog.js.map +1 -1
- package/dist/schemas/dry-run-plan.v1.json +139 -0
- package/dist/schemas/recipe.v1.json +684 -0
- package/dist/server.d.ts +121 -8
- package/dist/server.js +538 -735
- package/dist/server.js.map +1 -1
- package/dist/ssrfGuard.d.ts +54 -0
- package/dist/ssrfGuard.js +122 -0
- package/dist/ssrfGuard.js.map +1 -0
- package/dist/streamableHttp.d.ts +39 -1
- package/dist/streamableHttp.js +128 -17
- package/dist/streamableHttp.js.map +1 -1
- package/dist/tokenUsageTracker.d.ts +33 -0
- package/dist/tokenUsageTracker.js +146 -0
- package/dist/tokenUsageTracker.js.map +1 -0
- package/dist/tools/activityLog.d.ts +2 -0
- package/dist/tools/addLinearComment.d.ts +1 -0
- package/dist/tools/addLinearComment.js +4 -2
- package/dist/tools/addLinearComment.js.map +1 -1
- package/dist/tools/batchLsp.d.ts +3 -0
- package/dist/tools/bridgeDoctor.d.ts +1 -0
- package/dist/tools/bridgeDoctor.js +2 -2
- package/dist/tools/bridgeDoctor.js.map +1 -1
- package/dist/tools/bridgeStatus.d.ts +1 -0
- package/dist/tools/cancelClaudeTask.d.ts +2 -0
- package/dist/tools/cancelClaudeTask.js +1 -0
- package/dist/tools/cancelClaudeTask.js.map +1 -1
- package/dist/tools/checkDocumentDirty.d.ts +1 -0
- package/dist/tools/clipboard.d.ts +2 -0
- package/dist/tools/closeTabs.d.ts +2 -0
- package/dist/tools/codeLens.d.ts +1 -0
- package/dist/tools/contextBundle.d.ts +1 -0
- package/dist/tools/createIssueFromAIComment.d.ts +1 -0
- package/dist/tools/createLinearIssue.d.ts +1 -0
- package/dist/tools/ctxGetTaskContext.d.ts +1 -0
- package/dist/tools/ctxQueryTraces.d.ts +1 -0
- package/dist/tools/ctxSaveTrace.d.ts +1 -0
- package/dist/tools/debug.d.ts +4 -0
- package/dist/tools/decorations.d.ts +2 -0
- package/dist/tools/documentLinks.d.ts +1 -0
- package/dist/tools/editText.d.ts +1 -0
- package/dist/tools/enrichCommit.d.ts +1 -0
- package/dist/tools/enrichStackTrace.d.ts +1 -0
- package/dist/tools/explainDiagnostic.d.ts +1 -0
- package/dist/tools/explainSymbol.d.ts +1 -0
- package/dist/tools/fetchCalendarEvents.d.ts +1 -0
- package/dist/tools/fetchGithubIssue.d.ts +1 -0
- package/dist/tools/fetchGithubPR.d.ts +1 -0
- package/dist/tools/fetchLinearIssue.d.ts +1 -0
- package/dist/tools/fetchSentryIssue.d.ts +1 -0
- package/dist/tools/fetchSlackProfile.d.ts +1 -0
- package/dist/tools/fetchSlackProfile.js +4 -1
- package/dist/tools/fetchSlackProfile.js.map +1 -1
- package/dist/tools/fileOperations.d.ts +3 -0
- package/dist/tools/fileWatcher.d.ts +2 -0
- package/dist/tools/findFiles.d.ts +1 -0
- package/dist/tools/findRelatedTests.d.ts +1 -0
- package/dist/tools/fixAllLintErrors.d.ts +1 -0
- package/dist/tools/foldingRanges.d.ts +1 -0
- package/dist/tools/formatDocument.d.ts +1 -0
- package/dist/tools/generateTests.d.ts +1 -0
- package/dist/tools/getAIComments.d.ts +1 -0
- package/dist/tools/getAnalyticsReport.d.ts +1 -0
- package/dist/tools/getArchitectureContext.d.ts +1 -0
- package/dist/tools/getBufferContent.d.ts +1 -0
- package/dist/tools/getChangeImpact.d.ts +1 -0
- package/dist/tools/getClaudeTaskStatus.d.ts +2 -0
- package/dist/tools/getClaudeTaskStatus.js +1 -0
- package/dist/tools/getClaudeTaskStatus.js.map +1 -1
- package/dist/tools/getCodeCoverage.d.ts +1 -0
- package/dist/tools/getCommitsForIssue.d.ts +1 -0
- package/dist/tools/getConnectorStatus.d.ts +1 -0
- package/dist/tools/getCurrentSelection.d.ts +2 -0
- package/dist/tools/getDebugState.d.ts +1 -0
- package/dist/tools/getDependencyTree.d.ts +1 -0
- package/dist/tools/getDiagnostics.d.ts +1 -0
- package/dist/tools/getDiffFromHandoff.d.ts +1 -0
- package/dist/tools/getDocumentSymbols.d.ts +25 -0
- package/dist/tools/getDocumentSymbols.js +74 -8
- package/dist/tools/getDocumentSymbols.js.map +1 -1
- package/dist/tools/getFileTree.d.ts +1 -0
- package/dist/tools/getGitDiff.d.ts +1 -0
- package/dist/tools/getGitHotspots.d.ts +1 -0
- package/dist/tools/getGitLog.d.ts +1 -0
- package/dist/tools/getGitStatus.d.ts +1 -0
- package/dist/tools/getImportTree.d.ts +1 -0
- package/dist/tools/getImportedSignatures.d.ts +1 -0
- package/dist/tools/getOpenEditors.d.ts +1 -0
- package/dist/tools/getPRTemplate.d.ts +1 -0
- package/dist/tools/getProjectContext.d.ts +1 -0
- package/dist/tools/getProjectInfo.d.ts +1 -0
- package/dist/tools/getSecurityAdvisories.d.ts +1 -0
- package/dist/tools/getSecurityAdvisories.js +10 -1
- package/dist/tools/getSecurityAdvisories.js.map +1 -1
- package/dist/tools/getSessionUsage.d.ts +4 -0
- package/dist/tools/getSessionUsage.js +3 -0
- package/dist/tools/getSessionUsage.js.map +1 -1
- package/dist/tools/getSymbolHistory.d.ts +1 -0
- package/dist/tools/getToolCapabilities.d.ts +1 -0
- package/dist/tools/getTypeSignature.d.ts +1 -0
- package/dist/tools/getWorkspaceFolders.d.ts +1 -0
- package/dist/tools/getWorkspaceSettings.d.ts +1 -0
- package/dist/tools/gitHistory.d.ts +2 -0
- package/dist/tools/gitWrite.d.ts +11 -0
- package/dist/tools/github/actions.d.ts +2 -0
- package/dist/tools/github/actions.js +4 -2
- package/dist/tools/github/actions.js.map +1 -1
- package/dist/tools/github/composite.d.ts +342 -0
- package/dist/tools/github/composite.js +343 -0
- package/dist/tools/github/composite.js.map +1 -0
- package/dist/tools/github/index.d.ts +1 -0
- package/dist/tools/github/index.js +1 -0
- package/dist/tools/github/index.js.map +1 -1
- package/dist/tools/github/issues.d.ts +4 -0
- package/dist/tools/github/issues.js +8 -4
- package/dist/tools/github/issues.js.map +1 -1
- package/dist/tools/github/pr.d.ts +7 -0
- package/dist/tools/github/pr.js +50 -12
- package/dist/tools/github/pr.js.map +1 -1
- package/dist/tools/handoffNote.d.ts +4 -0
- package/dist/tools/handoffNote.js +2 -0
- package/dist/tools/handoffNote.js.map +1 -1
- package/dist/tools/hoverAtCursor.d.ts +1 -0
- package/dist/tools/httpClient.d.ts +2 -0
- package/dist/tools/index.d.ts +8 -0
- package/dist/tools/index.js +47 -8
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/inlayHints.d.ts +1 -0
- package/dist/tools/launchQuickTask.d.ts +2 -0
- package/dist/tools/launchQuickTask.js +1 -0
- package/dist/tools/launchQuickTask.js.map +1 -1
- package/dist/tools/listClaudeTasks.d.ts +2 -0
- package/dist/tools/listClaudeTasks.js +1 -0
- package/dist/tools/listClaudeTasks.js.map +1 -1
- package/dist/tools/listTerminals.d.ts +1 -0
- package/dist/tools/lsp.d.ts +14 -0
- package/dist/tools/navigateToSymbolByName.d.ts +1 -0
- package/dist/tools/openDiff.d.ts +1 -0
- package/dist/tools/openFile.d.ts +1 -0
- package/dist/tools/openInBrowser.d.ts +1 -0
- package/dist/tools/organizeImports.d.ts +1 -0
- package/dist/tools/performanceReport.d.ts +1 -0
- package/dist/tools/planPersistence.d.ts +5 -0
- package/dist/tools/previewEdit.d.ts +1 -0
- package/dist/tools/refactorAnalyze.d.ts +1 -0
- package/dist/tools/refactorPreview.d.ts +2 -0
- package/dist/tools/refactorPreview.js +1 -0
- package/dist/tools/refactorPreview.js.map +1 -1
- package/dist/tools/replaceBlock.d.ts +1 -0
- package/dist/tools/resumeClaudeTask.d.ts +2 -0
- package/dist/tools/resumeClaudeTask.js +1 -0
- package/dist/tools/resumeClaudeTask.js.map +1 -1
- package/dist/tools/runClaudeTask.d.ts +2 -0
- package/dist/tools/runClaudeTask.js +1 -0
- package/dist/tools/runClaudeTask.js.map +1 -1
- package/dist/tools/runCommand.d.ts +1 -0
- package/dist/tools/runTests.d.ts +1 -0
- package/dist/tools/saveDocument.d.ts +1 -0
- package/dist/tools/screenshotAndAnnotate.d.ts +1 -0
- package/dist/tools/searchAndReplace.d.ts +1 -0
- package/dist/tools/searchTools.d.ts +1 -0
- package/dist/tools/searchTools.js +1 -1
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/tools/searchWorkspace.d.ts +1 -0
- package/dist/tools/selectionRanges.d.ts +1 -0
- package/dist/tools/semanticTokens.d.ts +1 -0
- package/dist/tools/setActiveWorkspaceFolder.d.ts +1 -0
- package/dist/tools/signatureHelp.d.ts +1 -0
- package/dist/tools/slackListChannels.d.ts +1 -0
- package/dist/tools/slackListChannels.js.map +1 -1
- package/dist/tools/slackPostMessage.d.ts +1 -0
- package/dist/tools/slackPostMessage.js +11 -6
- package/dist/tools/slackPostMessage.js.map +1 -1
- package/dist/tools/terminal.d.ts +6 -0
- package/dist/tools/testTraceToSource.d.ts +1 -0
- package/dist/tools/testTraceToSource.js +2 -2
- package/dist/tools/testTraceToSource.js.map +1 -1
- package/dist/tools/transaction.d.ts +23 -0
- package/dist/tools/transaction.js +29 -0
- package/dist/tools/transaction.js.map +1 -1
- package/dist/tools/typeHierarchy.d.ts +1 -0
- package/dist/tools/updateLinearIssue.d.ts +1 -0
- package/dist/tools/updateLinearIssue.js +20 -6
- package/dist/tools/updateLinearIssue.js.map +1 -1
- package/dist/tools/utils.d.ts +2 -0
- package/dist/tools/utils.js.map +1 -1
- package/dist/tools/vscodeCommands.d.ts +2 -0
- package/dist/tools/vscodeTasks.d.ts +2 -0
- package/dist/tools/workspaceSettings.d.ts +1 -0
- package/dist/traceEncryption.d.ts +46 -0
- package/dist/traceEncryption.js +124 -0
- package/dist/traceEncryption.js.map +1 -0
- package/dist/transport.d.ts +46 -1
- package/dist/transport.js +173 -19
- package/dist/transport.js.map +1 -1
- package/package.json +30 -8
- package/scripts/mcp-stdio-shim.cjs +19 -3
- package/scripts/start-all.sh +30 -1
- package/templates/automation-policies/recipe-authoring.json +25 -0
- package/templates/automation-policy.example.json +6 -0
- package/templates/co.patchwork-os.bridge.plist +34 -0
- package/templates/policies/README.md +72 -0
- package/templates/policies/conservative.json +14 -0
- package/templates/policies/developer.json +14 -0
- package/templates/policies/headless-ci.json +24 -0
- package/templates/policies/personal-assistant.json +15 -0
- package/templates/policies/regulated-industry.json +18 -0
- package/templates/recipes/lint-on-save.yaml +1 -2
- package/templates/recipes/morning-brief-slack.yaml +57 -0
- package/templates/recipes/morning-brief.yaml +2 -2
- package/templates/recipes/project-health-check.yaml +50 -0
- package/templates/recipes/webhook/README.md +70 -0
- package/templates/recipes/webhook/capture-thought.yaml +26 -0
- package/templates/recipes/webhook/customer-escalation.yaml +49 -0
- package/templates/recipes/webhook/incident-intake.yaml +46 -0
- package/templates/recipes/webhook/meeting-prep.yaml +48 -0
- 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
|