patchwork-os 0.2.0-beta.9.canary.93 → 1.1.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.bridge.md +15 -16
- package/README.md +46 -458
- package/dist/activationMetrics.js +2 -3
- package/dist/activationMetrics.js.map +1 -1
- package/dist/activityLog.d.ts +1 -0
- package/dist/activityLog.js +8 -3
- package/dist/activityLog.js.map +1 -1
- package/dist/adapters/gemini.js +2 -2
- package/dist/adapters/gemini.js.map +1 -1
- package/dist/adapters/grok.js +6 -1
- package/dist/adapters/grok.js.map +1 -1
- package/dist/adapters/openai.js +4 -0
- package/dist/adapters/openai.js.map +1 -1
- package/dist/approvalHttp.d.ts +9 -0
- package/dist/approvalHttp.js +210 -171
- package/dist/approvalHttp.js.map +1 -1
- package/dist/approvalKpi.d.ts +102 -0
- package/dist/approvalKpi.js +282 -0
- package/dist/approvalKpi.js.map +1 -0
- package/dist/approvalQueue.d.ts +1 -1
- package/dist/approvalQueue.js.map +1 -1
- package/dist/automation.d.ts +45 -4
- package/dist/automation.js +123 -15
- package/dist/automation.js.map +1 -1
- package/dist/bridge.d.ts +10 -0
- package/dist/bridge.js +225 -46
- package/dist/bridge.js.map +1 -1
- package/dist/bridgeLockDiscovery.d.ts +16 -1
- package/dist/bridgeLockDiscovery.js +38 -4
- package/dist/bridgeLockDiscovery.js.map +1 -1
- package/dist/bridgeToolsRules.js +3 -18
- package/dist/bridgeToolsRules.js.map +1 -1
- package/dist/claudeAuthHttp.d.ts +25 -0
- package/dist/claudeAuthHttp.js +219 -0
- package/dist/claudeAuthHttp.js.map +1 -0
- package/dist/claudeDriver.js +4 -1
- package/dist/claudeDriver.js.map +1 -1
- package/dist/claudeOrchestrator.d.ts +15 -0
- package/dist/claudeOrchestrator.js +44 -0
- package/dist/claudeOrchestrator.js.map +1 -1
- package/dist/commands/connect.d.ts +47 -0
- package/dist/commands/connect.js +419 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/install.js +3 -10
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/launchd.d.ts +7 -0
- package/dist/commands/launchd.js +20 -2
- package/dist/commands/launchd.js.map +1 -1
- package/dist/commands/patchworkInit.d.ts +7 -0
- package/dist/commands/patchworkInit.js +26 -0
- package/dist/commands/patchworkInit.js.map +1 -1
- package/dist/commands/recipe.d.ts +59 -4
- package/dist/commands/recipe.js +206 -5
- package/dist/commands/recipe.js.map +1 -1
- package/dist/commands/recipeInstall.d.ts +9 -0
- package/dist/commands/recipeInstall.js +56 -3
- package/dist/commands/recipeInstall.js.map +1 -1
- package/dist/commands/task.d.ts +25 -0
- package/dist/commands/task.js +61 -41
- package/dist/commands/task.js.map +1 -1
- package/dist/commands/tokenEfficiency.d.ts +4 -0
- package/dist/commands/tokenEfficiency.js +23 -26
- package/dist/commands/tokenEfficiency.js.map +1 -1
- package/dist/commands/tracesExport.d.ts +15 -1
- package/dist/commands/tracesExport.js +39 -5
- package/dist/commands/tracesExport.js.map +1 -1
- package/dist/config.js +16 -0
- package/dist/config.js.map +1 -1
- package/dist/connectorRoutes.js +613 -62
- package/dist/connectorRoutes.js.map +1 -1
- package/dist/connectors/asana.js +9 -3
- package/dist/connectors/asana.js.map +1 -1
- package/dist/connectors/baseConnector.d.ts +16 -0
- package/dist/connectors/baseConnector.js +2 -0
- package/dist/connectors/baseConnector.js.map +1 -1
- package/dist/connectors/caldiy.js +34 -0
- package/dist/connectors/caldiy.js.map +1 -1
- package/dist/connectors/confluence.js +9 -2
- package/dist/connectors/confluence.js.map +1 -1
- package/dist/connectors/connectorActivity.d.ts +24 -0
- package/dist/connectors/connectorActivity.js +32 -0
- package/dist/connectors/connectorActivity.js.map +1 -0
- package/dist/connectors/connectorRedirectUri.js +22 -2
- package/dist/connectors/connectorRedirectUri.js.map +1 -1
- package/dist/connectors/connectorRegistry.d.ts +0 -3
- package/dist/connectors/connectorRegistry.js +8 -8
- package/dist/connectors/connectorRegistry.js.map +1 -1
- package/dist/connectors/datadog.js +8 -1
- package/dist/connectors/datadog.js.map +1 -1
- package/dist/connectors/discord.js +4 -3
- package/dist/connectors/discord.js.map +1 -1
- package/dist/connectors/elasticsearch.js +22 -0
- package/dist/connectors/elasticsearch.js.map +1 -1
- package/dist/connectors/github.d.ts +38 -0
- package/dist/connectors/github.js +91 -5
- package/dist/connectors/github.js.map +1 -1
- package/dist/connectors/gitlab.js +19 -16
- package/dist/connectors/gitlab.js.map +1 -1
- package/dist/connectors/gmail.d.ts +5 -0
- package/dist/connectors/gmail.js +53 -11
- package/dist/connectors/gmail.js.map +1 -1
- package/dist/connectors/googleCalendar.js +5 -4
- package/dist/connectors/googleCalendar.js.map +1 -1
- package/dist/connectors/googleDocs.js +7 -6
- package/dist/connectors/googleDocs.js.map +1 -1
- package/dist/connectors/googleDrive.js +15 -8
- package/dist/connectors/googleDrive.js.map +1 -1
- package/dist/connectors/grafana.js +39 -3
- package/dist/connectors/grafana.js.map +1 -1
- package/dist/connectors/jira.d.ts +1 -1
- package/dist/connectors/jira.js +19 -4
- package/dist/connectors/jira.js.map +1 -1
- package/dist/connectors/linear.js +2 -2
- package/dist/connectors/linear.js.map +1 -1
- package/dist/connectors/mcpClient.d.ts +29 -1
- package/dist/connectors/mcpClient.js +114 -44
- package/dist/connectors/mcpClient.js.map +1 -1
- package/dist/connectors/mcpOAuth.d.ts +1 -0
- package/dist/connectors/mcpOAuth.js +49 -4
- package/dist/connectors/mcpOAuth.js.map +1 -1
- package/dist/connectors/monday.js +5 -4
- package/dist/connectors/monday.js.map +1 -1
- package/dist/connectors/mongodb.js +32 -5
- package/dist/connectors/mongodb.js.map +1 -1
- package/dist/connectors/notion.d.ts +1 -1
- package/dist/connectors/notion.js +22 -6
- package/dist/connectors/notion.js.map +1 -1
- package/dist/connectors/oauthError.d.ts +17 -0
- package/dist/connectors/oauthError.js +50 -0
- package/dist/connectors/oauthError.js.map +1 -0
- package/dist/connectors/postgres.d.ts +7 -0
- package/dist/connectors/postgres.js +32 -2
- package/dist/connectors/postgres.js.map +1 -1
- package/dist/connectors/posthog.js +26 -0
- package/dist/connectors/posthog.js.map +1 -1
- package/dist/connectors/redis.d.ts +1 -0
- package/dist/connectors/redis.js +47 -20
- package/dist/connectors/redis.js.map +1 -1
- package/dist/connectors/salesforce.js +66 -5
- package/dist/connectors/salesforce.js.map +1 -1
- package/dist/connectors/sentry.js +2 -2
- package/dist/connectors/sentry.js.map +1 -1
- package/dist/connectors/slack.js +37 -14
- package/dist/connectors/slack.js.map +1 -1
- package/dist/connectors/snowflake.js +24 -0
- package/dist/connectors/snowflake.js.map +1 -1
- package/dist/connectors/stripe.js +9 -2
- package/dist/connectors/stripe.js.map +1 -1
- package/dist/connectors/supabase.js +34 -0
- package/dist/connectors/supabase.js.map +1 -1
- package/dist/connectors/tokenStorage.d.ts +20 -0
- package/dist/connectors/tokenStorage.js +196 -64
- package/dist/connectors/tokenStorage.js.map +1 -1
- package/dist/connectors/woocommerce.js +34 -0
- package/dist/connectors/woocommerce.js.map +1 -1
- package/dist/copilot/parseIntent.d.ts +58 -0
- package/dist/copilot/parseIntent.js +149 -0
- package/dist/copilot/parseIntent.js.map +1 -0
- package/dist/decisionReplay.d.ts +8 -6
- package/dist/decisionReplay.js +35 -11
- package/dist/decisionReplay.js.map +1 -1
- package/dist/decisionTraceLog.d.ts +9 -0
- package/dist/decisionTraceLog.js +6 -0
- package/dist/decisionTraceLog.js.map +1 -1
- package/dist/drivers/claude/api.js +49 -7
- package/dist/drivers/claude/api.js.map +1 -1
- package/dist/drivers/claude/envSanitizer.d.ts +9 -1
- package/dist/drivers/claude/envSanitizer.js +41 -3
- package/dist/drivers/claude/envSanitizer.js.map +1 -1
- package/dist/drivers/claude/streamParser.d.ts +13 -0
- package/dist/drivers/claude/streamParser.js.map +1 -1
- package/dist/drivers/claude/subprocess.js +131 -16
- package/dist/drivers/claude/subprocess.js.map +1 -1
- package/dist/drivers/claude/subprocessSettings.d.ts +1 -1
- package/dist/drivers/claude/subprocessSettings.js +18 -4
- package/dist/drivers/claude/subprocessSettings.js.map +1 -1
- package/dist/drivers/gemini/index.d.ts +13 -0
- package/dist/drivers/gemini/index.js +211 -67
- package/dist/drivers/gemini/index.js.map +1 -1
- package/dist/drivers/local/index.d.ts +2 -17
- package/dist/drivers/local/index.js +5 -92
- package/dist/drivers/local/index.js.map +1 -1
- package/dist/drivers/openai/index.js +69 -9
- package/dist/drivers/openai/index.js.map +1 -1
- package/dist/drivers/outputCap.d.ts +27 -0
- package/dist/drivers/outputCap.js +50 -0
- package/dist/drivers/outputCap.js.map +1 -0
- package/dist/embeddings/cosine.d.ts +23 -0
- package/dist/embeddings/cosine.js +59 -0
- package/dist/embeddings/cosine.js.map +1 -0
- package/dist/embeddings/index.d.ts +19 -0
- package/dist/embeddings/index.js +35 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/embeddings/localEmbeddings.d.ts +29 -0
- package/dist/embeddings/localEmbeddings.js +103 -0
- package/dist/embeddings/localEmbeddings.js.map +1 -0
- package/dist/embeddings/localEndpoints.d.ts +24 -0
- package/dist/embeddings/localEndpoints.js +37 -0
- package/dist/embeddings/localEndpoints.js.map +1 -0
- package/dist/embeddings/types.d.ts +32 -0
- package/dist/embeddings/types.js +12 -0
- package/dist/embeddings/types.js.map +1 -0
- package/dist/featureFlags.d.ts +18 -0
- package/dist/featureFlags.js +32 -0
- package/dist/featureFlags.js.map +1 -1
- package/dist/fp/automationInterpreter.js +118 -39
- package/dist/fp/automationInterpreter.js.map +1 -1
- package/dist/fp/automationProgram.d.ts +10 -0
- package/dist/fp/automationProgram.js.map +1 -1
- package/dist/fp/automationState.d.ts +6 -0
- package/dist/fp/automationState.js +38 -0
- package/dist/fp/automationState.js.map +1 -1
- package/dist/fp/commandDescription.d.ts +6 -0
- package/dist/fp/commandDescription.js +18 -5
- package/dist/fp/commandDescription.js.map +1 -1
- package/dist/fp/interpreterContext.d.ts +16 -5
- package/dist/fp/interpreterContext.js +59 -3
- package/dist/fp/interpreterContext.js.map +1 -1
- package/dist/fp/policyParser.js +18 -8
- package/dist/fp/policyParser.js.map +1 -1
- package/dist/haltPushDispatch.d.ts +4 -0
- package/dist/haltPushDispatch.js +7 -22
- package/dist/haltPushDispatch.js.map +1 -1
- package/dist/inboxRoutes.js +2 -2
- package/dist/inboxRoutes.js.map +1 -1
- package/dist/index.js +672 -135
- package/dist/index.js.map +1 -1
- package/dist/installGuard.js +6 -0
- package/dist/installGuard.js.map +1 -1
- package/dist/localEndpointGuard.d.ts +25 -0
- package/dist/localEndpointGuard.js +101 -0
- package/dist/localEndpointGuard.js.map +1 -0
- package/dist/mcpRoutes.js +1 -1
- package/dist/mcpRoutes.js.map +1 -1
- package/dist/oauth.d.ts +13 -0
- package/dist/oauth.js +53 -9
- package/dist/oauth.js.map +1 -1
- package/dist/orchestrator/childBridgeClient.d.ts +7 -0
- package/dist/orchestrator/childBridgeClient.js +42 -1
- package/dist/orchestrator/childBridgeClient.js.map +1 -1
- package/dist/orchestrator/orchestratorBridge.d.ts +33 -0
- package/dist/orchestrator/orchestratorBridge.js +75 -9
- package/dist/orchestrator/orchestratorBridge.js.map +1 -1
- package/dist/patchworkConfig.d.ts +4 -0
- package/dist/patchworkConfig.js +33 -4
- package/dist/patchworkConfig.js.map +1 -1
- package/dist/probe.js +39 -5
- package/dist/probe.js.map +1 -1
- package/dist/recipeOrchestration.d.ts +59 -0
- package/dist/recipeOrchestration.js +314 -60
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipeRoutes.d.ts +93 -0
- package/dist/recipeRoutes.js +664 -27
- package/dist/recipeRoutes.js.map +1 -1
- package/dist/recipes/RecipeOrchestrator.d.ts +14 -0
- package/dist/recipes/RecipeOrchestrator.js +42 -2
- package/dist/recipes/RecipeOrchestrator.js.map +1 -1
- package/dist/recipes/agentExecutor.d.ts +51 -2
- package/dist/recipes/agentExecutor.js +86 -13
- package/dist/recipes/agentExecutor.js.map +1 -1
- package/dist/recipes/chainedRunner.d.ts +111 -3
- package/dist/recipes/chainedRunner.js +440 -45
- package/dist/recipes/chainedRunner.js.map +1 -1
- package/dist/recipes/compiler.js +42 -29
- package/dist/recipes/compiler.js.map +1 -1
- package/dist/recipes/connectorPreflight.js +31 -0
- package/dist/recipes/connectorPreflight.js.map +1 -1
- package/dist/recipes/dependencyGraph.d.ts +16 -0
- package/dist/recipes/dependencyGraph.js +37 -2
- package/dist/recipes/dependencyGraph.js.map +1 -1
- package/dist/recipes/eventTriggerPrograms.d.ts +36 -0
- package/dist/recipes/eventTriggerPrograms.js +158 -0
- package/dist/recipes/eventTriggerPrograms.js.map +1 -0
- package/dist/recipes/githubInstallSource.d.ts +9 -2
- package/dist/recipes/githubInstallSource.js +36 -6
- package/dist/recipes/githubInstallSource.js.map +1 -1
- package/dist/recipes/haltCategory.d.ts +10 -0
- package/dist/recipes/haltCategory.js +11 -1
- package/dist/recipes/haltCategory.js.map +1 -1
- package/dist/recipes/idempotencyKey.d.ts +30 -3
- package/dist/recipes/idempotencyKey.js +89 -5
- package/dist/recipes/idempotencyKey.js.map +1 -1
- package/dist/recipes/installer.js +12 -35
- package/dist/recipes/installer.js.map +1 -1
- package/dist/recipes/judgeVerdict.d.ts +11 -1
- package/dist/recipes/judgeVerdict.js +47 -7
- package/dist/recipes/judgeVerdict.js.map +1 -1
- package/dist/recipes/names.d.ts +5 -0
- package/dist/recipes/names.js +10 -5
- package/dist/recipes/names.js.map +1 -1
- package/dist/recipes/parser.js +74 -10
- package/dist/recipes/parser.js.map +1 -1
- package/dist/recipes/pricing/costRouter.d.ts +43 -0
- package/dist/recipes/pricing/costRouter.js +44 -0
- package/dist/recipes/pricing/costRouter.js.map +1 -0
- package/dist/recipes/pricing/priceTable.d.ts +76 -0
- package/dist/recipes/pricing/priceTable.js +144 -0
- package/dist/recipes/pricing/priceTable.js.map +1 -0
- package/dist/recipes/replayRun.js +5 -2
- package/dist/recipes/replayRun.js.map +1 -1
- package/dist/recipes/resolveRecipePath.js +15 -1
- package/dist/recipes/resolveRecipePath.js.map +1 -1
- package/dist/recipes/runBudget.d.ts +93 -32
- package/dist/recipes/runBudget.js +213 -49
- package/dist/recipes/runBudget.js.map +1 -1
- package/dist/recipes/runRegistry.d.ts +32 -0
- package/dist/recipes/runRegistry.js +54 -0
- package/dist/recipes/runRegistry.js.map +1 -0
- package/dist/recipes/scheduler.js +6 -2
- package/dist/recipes/scheduler.js.map +1 -1
- package/dist/recipes/schema.d.ts +59 -6
- package/dist/recipes/schemaGenerator.d.ts +9 -0
- package/dist/recipes/schemaGenerator.js +446 -77
- package/dist/recipes/schemaGenerator.js.map +1 -1
- package/dist/recipes/simulation/aggregateRunRisk.d.ts +46 -0
- package/dist/recipes/simulation/aggregateRunRisk.js +120 -0
- package/dist/recipes/simulation/aggregateRunRisk.js.map +1 -0
- package/dist/recipes/simulation/costProjector.d.ts +32 -0
- package/dist/recipes/simulation/costProjector.js +194 -0
- package/dist/recipes/simulation/costProjector.js.map +1 -0
- package/dist/recipes/simulation/sideEffects.d.ts +32 -0
- package/dist/recipes/simulation/sideEffects.js +62 -0
- package/dist/recipes/simulation/sideEffects.js.map +1 -0
- package/dist/recipes/simulation/simulate.d.ts +36 -0
- package/dist/recipes/simulation/simulate.js +264 -0
- package/dist/recipes/simulation/simulate.js.map +1 -0
- package/dist/recipes/simulation/simulateMockedRun.d.ts +52 -0
- package/dist/recipes/simulation/simulateMockedRun.js +84 -0
- package/dist/recipes/simulation/simulateMockedRun.js.map +1 -0
- package/dist/recipes/simulation/synthesizeMockedOutputs.d.ts +31 -0
- package/dist/recipes/simulation/synthesizeMockedOutputs.js +50 -0
- package/dist/recipes/simulation/synthesizeMockedOutputs.js.map +1 -0
- package/dist/recipes/simulation/types.d.ts +198 -0
- package/dist/recipes/simulation/types.js +30 -0
- package/dist/recipes/simulation/types.js.map +1 -0
- package/dist/recipes/stepObservation.d.ts +12 -0
- package/dist/recipes/stepObservation.js +21 -1
- package/dist/recipes/stepObservation.js.map +1 -1
- package/dist/recipes/toolRegistry.js +61 -24
- package/dist/recipes/toolRegistry.js.map +1 -1
- package/dist/recipes/tools/airtable.d.ts +15 -0
- package/dist/recipes/tools/airtable.js +240 -0
- package/dist/recipes/tools/airtable.js.map +1 -0
- package/dist/recipes/tools/caldiy.d.ts +13 -0
- package/dist/recipes/tools/caldiy.js +215 -0
- package/dist/recipes/tools/caldiy.js.map +1 -0
- package/dist/recipes/tools/circleci.d.ts +10 -0
- package/dist/recipes/tools/circleci.js +204 -0
- package/dist/recipes/tools/circleci.js.map +1 -0
- package/dist/recipes/tools/cloudflare.d.ts +13 -0
- package/dist/recipes/tools/cloudflare.js +211 -0
- package/dist/recipes/tools/cloudflare.js.map +1 -0
- package/dist/recipes/tools/confluence.js +11 -10
- package/dist/recipes/tools/confluence.js.map +1 -1
- package/dist/recipes/tools/datadog.js +13 -12
- package/dist/recipes/tools/datadog.js.map +1 -1
- package/dist/recipes/tools/docs.d.ts +18 -0
- package/dist/recipes/tools/docs.js +95 -0
- package/dist/recipes/tools/docs.js.map +1 -0
- package/dist/recipes/tools/elasticsearch.d.ts +11 -0
- package/dist/recipes/tools/elasticsearch.js +157 -0
- package/dist/recipes/tools/elasticsearch.js.map +1 -0
- package/dist/recipes/tools/fanOut.js +4 -4
- package/dist/recipes/tools/fanOut.js.map +1 -1
- package/dist/recipes/tools/figma.d.ts +12 -0
- package/dist/recipes/tools/figma.js +195 -0
- package/dist/recipes/tools/figma.js.map +1 -0
- package/dist/recipes/tools/file.js +43 -22
- package/dist/recipes/tools/file.js.map +1 -1
- package/dist/recipes/tools/github.js +162 -5
- package/dist/recipes/tools/github.js.map +1 -1
- package/dist/recipes/tools/gmail.js +45 -33
- package/dist/recipes/tools/gmail.js.map +1 -1
- package/dist/recipes/tools/grafana.d.ts +11 -0
- package/dist/recipes/tools/grafana.js +216 -0
- package/dist/recipes/tools/grafana.js.map +1 -0
- package/dist/recipes/tools/http.d.ts +1 -1
- package/dist/recipes/tools/http.js +10 -28
- package/dist/recipes/tools/http.js.map +1 -1
- package/dist/recipes/tools/hubspot.js +13 -12
- package/dist/recipes/tools/hubspot.js.map +1 -1
- package/dist/recipes/tools/index.d.ts +28 -0
- package/dist/recipes/tools/index.js +28 -0
- package/dist/recipes/tools/index.js.map +1 -1
- package/dist/recipes/tools/intercom.js +11 -10
- package/dist/recipes/tools/intercom.js.map +1 -1
- package/dist/recipes/tools/jira.js +13 -0
- package/dist/recipes/tools/jira.js.map +1 -1
- package/dist/recipes/tools/meetingNotes.js +2 -2
- package/dist/recipes/tools/monday.d.ts +22 -0
- package/dist/recipes/tools/monday.js +242 -0
- package/dist/recipes/tools/monday.js.map +1 -0
- package/dist/recipes/tools/mongodb.d.ts +19 -0
- package/dist/recipes/tools/mongodb.js +194 -0
- package/dist/recipes/tools/mongodb.js.map +1 -0
- package/dist/recipes/tools/notion.js +11 -10
- package/dist/recipes/tools/notion.js.map +1 -1
- package/dist/recipes/tools/obsidian.d.ts +15 -0
- package/dist/recipes/tools/obsidian.js +173 -0
- package/dist/recipes/tools/obsidian.js.map +1 -0
- package/dist/recipes/tools/outcomes.d.ts +15 -0
- package/dist/recipes/tools/outcomes.js +111 -0
- package/dist/recipes/tools/outcomes.js.map +1 -0
- package/dist/recipes/tools/paystack.d.ts +11 -0
- package/dist/recipes/tools/paystack.js +212 -0
- package/dist/recipes/tools/paystack.js.map +1 -0
- package/dist/recipes/tools/pipedrive.d.ts +16 -0
- package/dist/recipes/tools/pipedrive.js +234 -0
- package/dist/recipes/tools/pipedrive.js.map +1 -0
- package/dist/recipes/tools/postgres.d.ts +15 -0
- package/dist/recipes/tools/postgres.js +186 -0
- package/dist/recipes/tools/postgres.js.map +1 -0
- package/dist/recipes/tools/posthog.d.ts +16 -0
- package/dist/recipes/tools/posthog.js +219 -0
- package/dist/recipes/tools/posthog.js.map +1 -0
- package/dist/recipes/tools/redis.d.ts +9 -0
- package/dist/recipes/tools/redis.js +141 -0
- package/dist/recipes/tools/redis.js.map +1 -0
- package/dist/recipes/tools/resend.d.ts +8 -0
- package/dist/recipes/tools/resend.js +153 -0
- package/dist/recipes/tools/resend.js.map +1 -0
- package/dist/recipes/tools/salesforce.d.ts +16 -0
- package/dist/recipes/tools/salesforce.js +184 -0
- package/dist/recipes/tools/salesforce.js.map +1 -0
- package/dist/recipes/tools/sendgrid.d.ts +9 -0
- package/dist/recipes/tools/sendgrid.js +175 -0
- package/dist/recipes/tools/sendgrid.js.map +1 -0
- package/dist/recipes/tools/shopify.d.ts +16 -0
- package/dist/recipes/tools/shopify.js +266 -0
- package/dist/recipes/tools/shopify.js.map +1 -0
- package/dist/recipes/tools/snowflake.d.ts +16 -0
- package/dist/recipes/tools/snowflake.js +173 -0
- package/dist/recipes/tools/snowflake.js.map +1 -0
- package/dist/recipes/tools/stripe.js +13 -12
- package/dist/recipes/tools/stripe.js.map +1 -1
- package/dist/recipes/tools/supabase.d.ts +9 -0
- package/dist/recipes/tools/supabase.js +133 -0
- package/dist/recipes/tools/supabase.js.map +1 -0
- package/dist/recipes/tools/todoist.d.ts +15 -0
- package/dist/recipes/tools/todoist.js +228 -0
- package/dist/recipes/tools/todoist.js.map +1 -0
- package/dist/recipes/tools/twilio.d.ts +11 -0
- package/dist/recipes/tools/twilio.js +180 -0
- package/dist/recipes/tools/twilio.js.map +1 -0
- package/dist/recipes/tools/vercel.d.ts +9 -0
- package/dist/recipes/tools/vercel.js +146 -0
- package/dist/recipes/tools/vercel.js.map +1 -0
- package/dist/recipes/tools/webflow.d.ts +11 -0
- package/dist/recipes/tools/webflow.js +244 -0
- package/dist/recipes/tools/webflow.js.map +1 -0
- package/dist/recipes/tools/woocommerce.d.ts +18 -0
- package/dist/recipes/tools/woocommerce.js +260 -0
- package/dist/recipes/tools/woocommerce.js.map +1 -0
- package/dist/recipes/tools/wrapConnectorExecute.d.ts +25 -0
- package/dist/recipes/tools/wrapConnectorExecute.js +37 -0
- package/dist/recipes/tools/wrapConnectorExecute.js.map +1 -0
- package/dist/recipes/tools/zendesk.js +11 -10
- package/dist/recipes/tools/zendesk.js.map +1 -1
- package/dist/recipes/triggerVars.d.ts +15 -0
- package/dist/recipes/triggerVars.js +57 -0
- package/dist/recipes/triggerVars.js.map +1 -0
- package/dist/recipes/validation.d.ts +1 -1
- package/dist/recipes/validation.js +536 -12
- package/dist/recipes/validation.js.map +1 -1
- package/dist/recipes/yamlPositions.d.ts +1 -1
- package/dist/recipes/yamlPositions.js +7 -2
- package/dist/recipes/yamlPositions.js.map +1 -1
- package/dist/recipes/yamlRunner.d.ts +216 -4
- package/dist/recipes/yamlRunner.js +1030 -96
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/recipesHttp.d.ts +5 -0
- package/dist/recipesHttp.js +68 -6
- package/dist/recipesHttp.js.map +1 -1
- package/dist/resources.js +14 -1
- package/dist/resources.js.map +1 -1
- package/dist/riskSignals.d.ts +42 -0
- package/dist/riskSignals.js +197 -0
- package/dist/riskSignals.js.map +1 -0
- package/dist/riskTier.d.ts +9 -0
- package/dist/riskTier.js +48 -0
- package/dist/riskTier.js.map +1 -1
- package/dist/runLog.d.ts +53 -0
- package/dist/runLog.js +75 -16
- package/dist/runLog.js.map +1 -1
- package/dist/schemas/recipe.v1.json +360 -16
- package/dist/server.d.ts +60 -0
- package/dist/server.js +192 -31
- package/dist/server.js.map +1 -1
- package/dist/sessionCheckpoint.js +4 -1
- package/dist/sessionCheckpoint.js.map +1 -1
- package/dist/sessionDetail.d.ts +43 -0
- package/dist/sessionDetail.js +59 -0
- package/dist/sessionDetail.js.map +1 -0
- package/dist/settingsEnv.d.ts +47 -0
- package/dist/settingsEnv.js +88 -0
- package/dist/settingsEnv.js.map +1 -0
- package/dist/streamableHttp.js +44 -10
- package/dist/streamableHttp.js.map +1 -1
- package/dist/ta/backtest/abnday.d.ts +53 -0
- package/dist/ta/backtest/abnday.js +123 -0
- package/dist/ta/backtest/abnday.js.map +1 -0
- package/dist/ta/backtest/directional.d.ts +48 -0
- package/dist/ta/backtest/directional.js +103 -0
- package/dist/ta/backtest/directional.js.map +1 -0
- package/dist/ta/backtest/fundx.d.ts +67 -0
- package/dist/ta/backtest/fundx.js +264 -0
- package/dist/ta/backtest/fundx.js.map +1 -0
- package/dist/ta/backtest/fvg.d.ts +62 -0
- package/dist/ta/backtest/fvg.js +236 -0
- package/dist/ta/backtest/fvg.js.map +1 -0
- package/dist/ta/backtest/ichimoku.d.ts +41 -0
- package/dist/ta/backtest/ichimoku.js +146 -0
- package/dist/ta/backtest/ichimoku.js.map +1 -0
- package/dist/ta/backtest/ingest.d.ts +20 -0
- package/dist/ta/backtest/ingest.js +104 -0
- package/dist/ta/backtest/ingest.js.map +1 -0
- package/dist/ta/backtest/msb.d.ts +49 -0
- package/dist/ta/backtest/msb.js +162 -0
- package/dist/ta/backtest/msb.js.map +1 -0
- package/dist/ta/backtest/scoring.d.ts +33 -0
- package/dist/ta/backtest/scoring.js +82 -0
- package/dist/ta/backtest/scoring.js.map +1 -0
- package/dist/ta/backtest/summary.d.ts +20 -0
- package/dist/ta/backtest/summary.js +42 -0
- package/dist/ta/backtest/summary.js.map +1 -0
- package/dist/ta/backtest/tsmom.d.ts +72 -0
- package/dist/ta/backtest/tsmom.js +202 -0
- package/dist/ta/backtest/tsmom.js.map +1 -0
- package/dist/ta/backtest/volsq.d.ts +34 -0
- package/dist/ta/backtest/volsq.js +154 -0
- package/dist/ta/backtest/volsq.js.map +1 -0
- package/dist/ta/backtest/walkForward.d.ts +45 -0
- package/dist/ta/backtest/walkForward.js +136 -0
- package/dist/ta/backtest/walkForward.js.map +1 -0
- package/dist/ta/cycles.d.ts +15 -0
- package/dist/ta/cycles.js +31 -0
- package/dist/ta/cycles.js.map +1 -0
- package/dist/ta/desk/accrualEmitter.d.ts +59 -0
- package/dist/ta/desk/accrualEmitter.js +136 -0
- package/dist/ta/desk/accrualEmitter.js.map +1 -0
- package/dist/ta/desk/cellBacktest.d.ts +179 -0
- package/dist/ta/desk/cellBacktest.js +514 -0
- package/dist/ta/desk/cellBacktest.js.map +1 -0
- package/dist/ta/desk/cells/wpMaRejection.d.ts +49 -0
- package/dist/ta/desk/cells/wpMaRejection.js +141 -0
- package/dist/ta/desk/cells/wpMaRejection.js.map +1 -0
- package/dist/ta/desk/cells/wpVolumeClimax.d.ts +57 -0
- package/dist/ta/desk/cells/wpVolumeClimax.js +193 -0
- package/dist/ta/desk/cells/wpVolumeClimax.js.map +1 -0
- package/dist/ta/desk/collectors.d.ts +18 -0
- package/dist/ta/desk/collectors.js +450 -0
- package/dist/ta/desk/collectors.js.map +1 -0
- package/dist/ta/desk/contract.d.ts +51 -0
- package/dist/ta/desk/contract.js +261 -0
- package/dist/ta/desk/contract.js.map +1 -0
- package/dist/ta/desk/deskLedger.d.ts +36 -0
- package/dist/ta/desk/deskLedger.js +239 -0
- package/dist/ta/desk/deskLedger.js.map +1 -0
- package/dist/ta/desk/liqTape.d.ts +37 -0
- package/dist/ta/desk/liqTape.js +99 -0
- package/dist/ta/desk/liqTape.js.map +1 -0
- package/dist/ta/desk/post.d.ts +20 -0
- package/dist/ta/desk/post.js +65 -0
- package/dist/ta/desk/post.js.map +1 -0
- package/dist/ta/desk/render.d.ts +25 -0
- package/dist/ta/desk/render.js +398 -0
- package/dist/ta/desk/render.js.map +1 -0
- package/dist/ta/desk/surfaces.d.ts +216 -0
- package/dist/ta/desk/surfaces.js +472 -0
- package/dist/ta/desk/surfaces.js.map +1 -0
- package/dist/ta/desk/types.d.ts +174 -0
- package/dist/ta/desk/types.js +104 -0
- package/dist/ta/desk/types.js.map +1 -0
- package/dist/ta/index.d.ts +23 -0
- package/dist/ta/index.js +54 -0
- package/dist/ta/index.js.map +1 -0
- package/dist/ta/ledger.d.ts +44 -0
- package/dist/ta/ledger.js +95 -0
- package/dist/ta/ledger.js.map +1 -0
- package/dist/ta/levels.d.ts +21 -0
- package/dist/ta/levels.js +41 -0
- package/dist/ta/levels.js.map +1 -0
- package/dist/ta/swings.d.ts +30 -0
- package/dist/ta/swings.js +83 -0
- package/dist/ta/swings.js.map +1 -0
- package/dist/ta/types.d.ts +81 -0
- package/dist/ta/types.js +20 -0
- package/dist/ta/types.js.map +1 -0
- package/dist/telemetry.js +20 -9
- package/dist/telemetry.js.map +1 -1
- package/dist/tokenUsageTracker.d.ts +2 -1
- package/dist/tokenUsageTracker.js +38 -20
- package/dist/tokenUsageTracker.js.map +1 -1
- package/dist/tools/contextBundle.js +13 -9
- package/dist/tools/contextBundle.js.map +1 -1
- package/dist/tools/ctxGetTaskContext.js +8 -3
- package/dist/tools/ctxGetTaskContext.js.map +1 -1
- package/dist/tools/ctxQueryTraces.d.ts +18 -1
- package/dist/tools/ctxQueryTraces.js +176 -27
- package/dist/tools/ctxQueryTraces.js.map +1 -1
- package/dist/tools/enrichCommit.js +5 -2
- package/dist/tools/enrichCommit.js.map +1 -1
- package/dist/tools/getDependencyTree.js +2 -2
- package/dist/tools/getDependencyTree.js.map +1 -1
- package/dist/tools/getDiagnostics.js +3 -0
- package/dist/tools/getDiagnostics.js.map +1 -1
- package/dist/tools/getDocumentSymbols.js +5 -1
- package/dist/tools/getDocumentSymbols.js.map +1 -1
- package/dist/tools/getGitHotspots.js +12 -1
- package/dist/tools/getGitHotspots.js.map +1 -1
- package/dist/tools/getGitLog.js +5 -2
- package/dist/tools/getGitLog.js.map +1 -1
- package/dist/tools/getGitStatus.js +6 -1
- package/dist/tools/getGitStatus.js.map +1 -1
- package/dist/tools/getProjectContext.js +3 -1
- package/dist/tools/getProjectContext.js.map +1 -1
- package/dist/tools/getToolCapabilities.js +39 -4
- package/dist/tools/getToolCapabilities.js.map +1 -1
- package/dist/tools/gitWrite.js +12 -3
- package/dist/tools/gitWrite.js.map +1 -1
- package/dist/tools/github/composite.d.ts +1 -1
- package/dist/tools/github/composite.js +7 -7
- package/dist/tools/github/composite.js.map +1 -1
- package/dist/tools/github/pr.d.ts +6 -6
- package/dist/tools/github/pr.js +18 -11
- package/dist/tools/github/pr.js.map +1 -1
- package/dist/tools/httpClient.js +55 -3
- package/dist/tools/httpClient.js.map +1 -1
- package/dist/tools/index.d.ts +2 -1
- package/dist/tools/index.js +19 -12
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/lsp.d.ts +6 -0
- package/dist/tools/lsp.js +81 -12
- package/dist/tools/lsp.js.map +1 -1
- package/dist/tools/previewEdit.js +16 -1
- package/dist/tools/previewEdit.js.map +1 -1
- package/dist/tools/resumeClaudeTask.js +17 -0
- package/dist/tools/resumeClaudeTask.js.map +1 -1
- package/dist/tools/searchAndReplace.js +9 -5
- package/dist/tools/searchAndReplace.js.map +1 -1
- package/dist/tools/searchTools.d.ts +26 -0
- package/dist/tools/searchTools.js +42 -2
- package/dist/tools/searchTools.js.map +1 -1
- package/dist/tools/terminal.js +23 -51
- package/dist/tools/terminal.js.map +1 -1
- package/dist/tools/transaction.d.ts +9 -1
- package/dist/tools/transaction.js +59 -4
- package/dist/tools/transaction.js.map +1 -1
- package/dist/tools/utils.d.ts +16 -0
- package/dist/tools/utils.js +77 -7
- package/dist/tools/utils.js.map +1 -1
- package/dist/transport.d.ts +31 -0
- package/dist/transport.js +117 -14
- package/dist/transport.js.map +1 -1
- package/dist/wireHaltPushDispatch.js +12 -0
- package/dist/wireHaltPushDispatch.js.map +1 -1
- package/dist/workerGateDecisionLog.d.ts +141 -0
- package/dist/workerGateDecisionLog.js +361 -0
- package/dist/workerGateDecisionLog.js.map +1 -0
- package/dist/workers/actionClass.d.ts +38 -0
- package/dist/workers/actionClass.js +155 -0
- package/dist/workers/actionClass.js.map +1 -0
- package/dist/workers/backtest.d.ts +68 -0
- package/dist/workers/backtest.js +113 -0
- package/dist/workers/backtest.js.map +1 -0
- package/dist/workers/contextRisk.d.ts +35 -0
- package/dist/workers/contextRisk.js +20 -0
- package/dist/workers/contextRisk.js.map +1 -0
- package/dist/workers/contextRiskScorer.d.ts +48 -0
- package/dist/workers/contextRiskScorer.js +94 -0
- package/dist/workers/contextRiskScorer.js.map +1 -0
- package/dist/workers/graduation.d.ts +61 -0
- package/dist/workers/graduation.js +112 -0
- package/dist/workers/graduation.js.map +1 -0
- package/dist/workers/outcomeStore.d.ts +98 -0
- package/dist/workers/outcomeStore.js +146 -0
- package/dist/workers/outcomeStore.js.map +1 -0
- package/dist/workers/outcomesCli.d.ts +34 -0
- package/dist/workers/outcomesCli.js +91 -0
- package/dist/workers/outcomesCli.js.map +1 -0
- package/dist/workers/runWorkerShadow.d.ts +90 -0
- package/dist/workers/runWorkerShadow.js +323 -0
- package/dist/workers/runWorkerShadow.js.map +1 -0
- package/dist/workers/shadowGate.d.ts +30 -0
- package/dist/workers/shadowGate.js +58 -0
- package/dist/workers/shadowGate.js.map +1 -0
- package/dist/workers/shadowObserver.d.ts +165 -0
- package/dist/workers/shadowObserver.js +203 -0
- package/dist/workers/shadowObserver.js.map +1 -0
- package/dist/workers/shadowReport.d.ts +16 -0
- package/dist/workers/shadowReport.js +61 -0
- package/dist/workers/shadowReport.js.map +1 -0
- package/dist/workers/shadowRun.d.ts +38 -0
- package/dist/workers/shadowRun.js +44 -0
- package/dist/workers/shadowRun.js.map +1 -0
- package/dist/workers/trustLevel.d.ts +82 -0
- package/dist/workers/trustLevel.js +100 -0
- package/dist/workers/trustLevel.js.map +1 -0
- package/dist/workers/worker.d.ts +49 -0
- package/dist/workers/worker.js +88 -0
- package/dist/workers/worker.js.map +1 -0
- package/dist/workers/workerGate.d.ts +101 -0
- package/dist/workers/workerGate.js +210 -0
- package/dist/workers/workerGate.js.map +1 -0
- package/dist/workers/workerLevelStore.d.ts +33 -0
- package/dist/workers/workerLevelStore.js +87 -0
- package/dist/workers/workerLevelStore.js.map +1 -0
- package/dist/workers/workerLoader.d.ts +7 -0
- package/dist/workers/workerLoader.js +31 -0
- package/dist/workers/workerLoader.js.map +1 -0
- package/dist/writeFileAtomic.js +40 -13
- package/dist/writeFileAtomic.js.map +1 -1
- package/package.json +14 -6
- package/scripts/mcp-stdio-shim.cjs +247 -87
- package/templates/CLAUDE.bridge.md +1 -1
- package/templates/recipes/dependency-bump.yaml +33 -0
- package/templates/recipes/incident-to-pr.yaml +187 -0
- package/templates/recipes/outcome-ingester.yaml +53 -0
- package/templates/recipes/release-notes.yaml +30 -0
- package/templates/recipes/triage-failing-tests-autofile.yaml +152 -0
- package/templates/recipes/triage-failing-tests.yaml +38 -0
- package/templates/workers/dependency-upkeep.worker.yaml +26 -0
- package/templates/workers/release-notes.worker.yaml +17 -0
- package/templates/workers/test-guardian.worker.yaml +24 -0
- package/deploy/README.md +0 -172
- package/deploy/bootstrap-new-vps.sh +0 -364
- package/deploy/bootstrap-vps.sh +0 -192
- package/deploy/claude-ide-bridge.service.template +0 -67
- package/deploy/claude-ide-bridge@.service +0 -31
- package/deploy/deploy-dashboard.sh +0 -198
- package/deploy/deploy-landing.sh +0 -136
- package/deploy/ecosystem.config.js.example +0 -36
- package/deploy/install-vps-service.sh +0 -240
- package/deploy/macos/README.md +0 -153
- package/deploy/macos/com.patchwork.bridge.plist.template +0 -54
- package/deploy/macos/com.patchwork.tunnel.plist.template +0 -76
- package/deploy/macos/install-mac-bridge.sh +0 -244
- package/deploy/macos/uninstall-mac-bridge.sh +0 -22
- package/deploy/nginx-claude-bridge.conf.template +0 -129
|
@@ -5,6 +5,68 @@ import { defaultDeprecationWarn, normalizeRecipeForRuntime, } from "./migrations
|
|
|
5
5
|
import { RECIPE_NAME_RE, RECIPE_VAR_NAME_RE, RESERVED_VAR_NAMES, } from "./names.js";
|
|
6
6
|
import { generateSchemaSet } from "./schemaGenerator.js";
|
|
7
7
|
import { listToolOutputContextKeys } from "./toolRegistry.js";
|
|
8
|
+
/** Driver ids a `downshift` candidate may name (mirrors the JSON-schema enum). */
|
|
9
|
+
const DOWNSHIFT_KNOWN_DRIVERS = new Set([
|
|
10
|
+
"claude",
|
|
11
|
+
"claude-code",
|
|
12
|
+
"api",
|
|
13
|
+
"openai",
|
|
14
|
+
"grok",
|
|
15
|
+
"gemini",
|
|
16
|
+
"anthropic",
|
|
17
|
+
"local",
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Validate an ordered route-candidate list (`downshift` / `escalate`): an array
|
|
21
|
+
* of `{driver?, model?}` where each entry sets at least one field and any
|
|
22
|
+
* `driver` is dispatch-known. Shared by both routing fields so they stay in
|
|
23
|
+
* lockstep. Codes are field-prefixed (`downshift-type`, `escalate-type`, …).
|
|
24
|
+
* (quality-aware-escalation)
|
|
25
|
+
*/
|
|
26
|
+
function validateRouteCandidateList(field, value, stepIndex, issues) {
|
|
27
|
+
if (value === undefined)
|
|
28
|
+
return;
|
|
29
|
+
const base = `steps.${stepIndex}.agent.${field}`;
|
|
30
|
+
if (!Array.isArray(value)) {
|
|
31
|
+
issues.push({
|
|
32
|
+
level: "error",
|
|
33
|
+
message: `Step ${stepIndex + 1}: '${field}' must be an array of {driver?, model?} candidates`,
|
|
34
|
+
code: `${field}-type`,
|
|
35
|
+
path: base,
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
value.forEach((entry, di) => {
|
|
40
|
+
if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
|
|
41
|
+
issues.push({
|
|
42
|
+
level: "error",
|
|
43
|
+
message: `Step ${stepIndex + 1}: ${field}[${di}] must be an object with 'driver' and/or 'model'`,
|
|
44
|
+
code: `${field}-entry-type`,
|
|
45
|
+
path: `${base}.${di}`,
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const e = entry;
|
|
50
|
+
const hasDriver = typeof e.driver === "string";
|
|
51
|
+
const hasModel = typeof e.model === "string";
|
|
52
|
+
if (!hasDriver && !hasModel) {
|
|
53
|
+
issues.push({
|
|
54
|
+
level: "error",
|
|
55
|
+
message: `Step ${stepIndex + 1}: ${field}[${di}] must set at least one of 'driver' or 'model'`,
|
|
56
|
+
code: `${field}-entry-empty`,
|
|
57
|
+
path: `${base}.${di}`,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (hasDriver && !DOWNSHIFT_KNOWN_DRIVERS.has(e.driver)) {
|
|
61
|
+
issues.push({
|
|
62
|
+
level: "error",
|
|
63
|
+
message: `Step ${stepIndex + 1}: ${field}[${di}].driver '${String(e.driver)}' is not a known driver`,
|
|
64
|
+
code: `${field}-driver-enum`,
|
|
65
|
+
path: `${base}.${di}.driver`,
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
8
70
|
export function validateRecipeDefinition(recipe) {
|
|
9
71
|
const issues = [];
|
|
10
72
|
const normalizedRecipe = normalizeRecipeForValidation(recipe);
|
|
@@ -13,6 +75,17 @@ export function validateRecipeDefinition(recipe) {
|
|
|
13
75
|
}
|
|
14
76
|
else {
|
|
15
77
|
const r = normalizedRecipe;
|
|
78
|
+
// Root-level `vars:` is silently dropped at runtime — the runner reads
|
|
79
|
+
// only `trigger.vars` / `trigger.inputs` (PR#259 trap). Warn so the
|
|
80
|
+
// author moves it under `trigger:` instead of debugging empty {{vars}}.
|
|
81
|
+
if (r.vars !== undefined) {
|
|
82
|
+
issues.push({
|
|
83
|
+
level: "warning",
|
|
84
|
+
message: "Top-level 'vars' is ignored at runtime — only 'trigger.vars' / 'trigger.inputs' are read. Move declared variables under 'trigger:'.",
|
|
85
|
+
code: "root-vars-ignored",
|
|
86
|
+
path: "vars",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
16
89
|
if (!r.name || typeof r.name !== "string") {
|
|
17
90
|
issues.push({
|
|
18
91
|
level: "error",
|
|
@@ -69,14 +142,16 @@ export function validateRecipeDefinition(recipe) {
|
|
|
69
142
|
// src/recipes/scheduler.ts:parseSchedule.
|
|
70
143
|
const at = trigger.at.trim();
|
|
71
144
|
const isInterval = /^@every\s+[1-9]\d*\s*(ms|s|m|h)$/i.test(at);
|
|
72
|
-
|
|
73
|
-
if
|
|
145
|
+
// Accept 5-field and 6-field cron (M24: node-cron supports 6 fields
|
|
146
|
+
// with a seconds column; reject only if fewer than 5 fields).
|
|
147
|
+
const isCronExpr = /^\S+(?:\s+\S+){4,5}$/.test(at);
|
|
148
|
+
if (!isInterval && !isCronExpr) {
|
|
74
149
|
issues.push({
|
|
75
150
|
level: "error",
|
|
76
|
-
message: `trigger.at "${at}" is not a valid schedule — expected 5-field cron (e.g. "0 9 * * 1-5") or "@every Ns|Nm|Nh"`,
|
|
151
|
+
message: `trigger.at "${at}" is not a valid schedule — expected 5- or 6-field cron (e.g. "0 9 * * 1-5") or "@every Ns|Nm|Nh"`,
|
|
77
152
|
});
|
|
78
153
|
}
|
|
79
|
-
else if (
|
|
154
|
+
else if (isCronExpr && !cron.validate(at)) {
|
|
80
155
|
// node-cron catches range/step typos a field-count check
|
|
81
156
|
// misses — e.g. "0 25 * * *", "* / 5 * * *".
|
|
82
157
|
issues.push({
|
|
@@ -88,6 +163,35 @@ export function validateRecipeDefinition(recipe) {
|
|
|
88
163
|
validateTriggerVarsList(trigger.vars, "vars", issues);
|
|
89
164
|
validateTriggerVarsList(trigger.inputs, "inputs", issues);
|
|
90
165
|
}
|
|
166
|
+
// M26: parallel:{each} map-reduce is not implemented in chained recipes.
|
|
167
|
+
// Check raw recipe.steps (before flattening) so the parallel wrapper is visible.
|
|
168
|
+
const rawRecipe = recipe && typeof recipe === "object" && !Array.isArray(recipe)
|
|
169
|
+
? recipe
|
|
170
|
+
: null;
|
|
171
|
+
const isChainedRecipe = rawRecipe?.trigger &&
|
|
172
|
+
typeof rawRecipe.trigger === "object" &&
|
|
173
|
+
!Array.isArray(rawRecipe.trigger) &&
|
|
174
|
+
rawRecipe.trigger.type === "chained";
|
|
175
|
+
if (isChainedRecipe && Array.isArray(rawRecipe?.steps)) {
|
|
176
|
+
const rawSteps = rawRecipe.steps;
|
|
177
|
+
for (let i = 0; i < rawSteps.length; i++) {
|
|
178
|
+
const rawStep = rawSteps[i];
|
|
179
|
+
if (rawStep && typeof rawStep === "object" && !Array.isArray(rawStep)) {
|
|
180
|
+
const rs = rawStep;
|
|
181
|
+
if (rs.parallel &&
|
|
182
|
+
typeof rs.parallel === "object" &&
|
|
183
|
+
!Array.isArray(rs.parallel) &&
|
|
184
|
+
"each" in rs.parallel) {
|
|
185
|
+
issues.push({
|
|
186
|
+
level: "error",
|
|
187
|
+
message: `Step ${i + 1}: parallel:{each} map-reduce is not supported in chained recipes. Use the \`fan_out\` tool step for tool-only loops.`,
|
|
188
|
+
path: `steps.${i}.parallel`,
|
|
189
|
+
code: "chained-parallel-each-unsupported",
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
91
195
|
if (!Array.isArray(r.steps) || r.steps.length === 0) {
|
|
92
196
|
issues.push({
|
|
93
197
|
level: "error",
|
|
@@ -95,8 +199,25 @@ export function validateRecipeDefinition(recipe) {
|
|
|
95
199
|
});
|
|
96
200
|
}
|
|
97
201
|
else {
|
|
202
|
+
const seenStepIds = new Set();
|
|
98
203
|
for (let i = 0; i < r.steps.length; i++) {
|
|
99
204
|
const step = r.steps[i];
|
|
205
|
+
// Duplicate step ids break dependency wiring (`awaits:`, `into:`
|
|
206
|
+
// overwrite, output keying) — the runner keys outputs by id and a
|
|
207
|
+
// second step with the same id silently clobbers the first. Reject.
|
|
208
|
+
if (typeof step.id === "string") {
|
|
209
|
+
if (seenStepIds.has(step.id)) {
|
|
210
|
+
issues.push({
|
|
211
|
+
level: "error",
|
|
212
|
+
message: `Step ${i + 1}: duplicate step id '${step.id}' — step ids must be unique`,
|
|
213
|
+
code: "duplicate-step-id",
|
|
214
|
+
path: `steps.${i}.id`,
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
seenStepIds.add(step.id);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
100
221
|
const hasTool = typeof step.tool === "string";
|
|
101
222
|
const hasAgent = !!step.agent;
|
|
102
223
|
const hasNestedRecipe = typeof step.recipe === "string" || typeof step.chain === "string";
|
|
@@ -106,6 +227,20 @@ export function validateRecipeDefinition(recipe) {
|
|
|
106
227
|
message: `Step ${i + 1}: Must have 'tool', 'agent', 'recipe', or 'chain' field`,
|
|
107
228
|
});
|
|
108
229
|
}
|
|
230
|
+
// M31: step-level retry: -1 silently skips tool steps (loop body
|
|
231
|
+
// iterates 0 times when retryCount < 0). Reject at lint time.
|
|
232
|
+
if (step.retry !== undefined) {
|
|
233
|
+
const retryVal = step.retry;
|
|
234
|
+
if (typeof retryVal !== "number" ||
|
|
235
|
+
!Number.isInteger(retryVal) ||
|
|
236
|
+
retryVal < 0) {
|
|
237
|
+
issues.push({
|
|
238
|
+
level: "error",
|
|
239
|
+
message: `Step ${i + 1}: retry must be a non-negative integer (got ${JSON.stringify(retryVal)})`,
|
|
240
|
+
path: `steps.${i}.retry`,
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
109
244
|
if (step.agent && typeof step.agent === "object") {
|
|
110
245
|
const agent = step.agent;
|
|
111
246
|
if (!agent.prompt || typeof agent.prompt !== "string") {
|
|
@@ -114,10 +249,121 @@ export function validateRecipeDefinition(recipe) {
|
|
|
114
249
|
message: `Step ${i + 1}: Agent step missing 'prompt'`,
|
|
115
250
|
});
|
|
116
251
|
}
|
|
252
|
+
// Tier-1 #8 (audit 2026-06-22): the judge→refine loop is implemented
|
|
253
|
+
// ONLY in the flat runner. A chained recipe (trigger.type:"chained")
|
|
254
|
+
// treats a `kind: judge` step as a plain agent step and silently
|
|
255
|
+
// ignores `max_revisions` — the refinement never runs. Reject at lint
|
|
256
|
+
// time so users aren't misled into thinking it works here.
|
|
257
|
+
if (isChainedRecipe) {
|
|
258
|
+
const mrChained = agent.max_revisions;
|
|
259
|
+
const judgeRequested = agent.kind === "judge" ||
|
|
260
|
+
(typeof mrChained === "number" && mrChained > 0);
|
|
261
|
+
if (judgeRequested) {
|
|
262
|
+
issues.push({
|
|
263
|
+
level: "error",
|
|
264
|
+
message: `Step ${i + 1}: judge→refine (kind: judge / max_revisions) is not supported in chained recipes (trigger.type: chained) — it only runs in the flat runner and would silently no-op here.`,
|
|
265
|
+
code: "chained-judge-unsupported",
|
|
266
|
+
path: `steps.${i}.agent`,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// `driver: claude|anthropic` routes to the Anthropic API (needs
|
|
271
|
+
// ANTHROPIC_API_KEY), NOT the Claude Code subscription — a common
|
|
272
|
+
// trap. Warn at lint time when the key is absent so the step
|
|
273
|
+
// doesn't silently no-op ("[agent step skipped: ANTHROPIC_API_KEY
|
|
274
|
+
// not set]") at run time. Use `driver: subprocess`/`claude-code`
|
|
275
|
+
// for the subscription path.
|
|
276
|
+
if ((agent.driver === "claude" || agent.driver === "anthropic") &&
|
|
277
|
+
!process.env.ANTHROPIC_API_KEY) {
|
|
278
|
+
issues.push({
|
|
279
|
+
level: "warning",
|
|
280
|
+
message: `Step ${i + 1}: driver '${String(agent.driver)}' uses the Anthropic API but ANTHROPIC_API_KEY is not set — the step will be skipped at run time. Set ANTHROPIC_API_KEY, or use 'driver: subprocess' for the Claude Code subscription.`,
|
|
281
|
+
code: "driver-api-key-required",
|
|
282
|
+
path: `steps.${i}.agent.driver`,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
// OPT-IN judge→refine loop fields. Both `max_revisions` and
|
|
286
|
+
// `on_exhausted` are meaningless without a `kind: "judge"` step
|
|
287
|
+
// that points at an upstream step via `reviews:` — a refine loop
|
|
288
|
+
// needs an agent output to re-run. Flag misuse as an error so
|
|
289
|
+
// `recipe lint` / `doctor` catch it before any run.
|
|
290
|
+
const hasRefineField = agent.max_revisions !== undefined ||
|
|
291
|
+
agent.on_exhausted !== undefined;
|
|
292
|
+
if (hasRefineField) {
|
|
293
|
+
if (agent.kind !== "judge") {
|
|
294
|
+
issues.push({
|
|
295
|
+
level: "error",
|
|
296
|
+
message: `Step ${i + 1}: 'max_revisions'/'on_exhausted' require 'kind: judge' (the judge→refine loop only applies to judge steps)`,
|
|
297
|
+
code: "refine-requires-judge",
|
|
298
|
+
path: `steps.${i}.agent`,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
else if (typeof agent.reviews !== "string" ||
|
|
302
|
+
agent.reviews.length === 0) {
|
|
303
|
+
issues.push({
|
|
304
|
+
level: "error",
|
|
305
|
+
message: `Step ${i + 1}: 'max_revisions'/'on_exhausted' require 'reviews' to be set (the loop re-runs the reviewed step)`,
|
|
306
|
+
code: "refine-requires-reviews",
|
|
307
|
+
path: `steps.${i}.agent`,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
if (agent.max_revisions !== undefined) {
|
|
312
|
+
const mr = agent.max_revisions;
|
|
313
|
+
if (typeof mr !== "number" || !Number.isInteger(mr) || mr < 0) {
|
|
314
|
+
issues.push({
|
|
315
|
+
level: "error",
|
|
316
|
+
message: `Step ${i + 1}: 'max_revisions' must be a non-negative integer (got ${JSON.stringify(mr)})`,
|
|
317
|
+
code: "refine-max-revisions-invalid",
|
|
318
|
+
path: `steps.${i}.agent.max_revisions`,
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (agent.on_exhausted !== undefined &&
|
|
323
|
+
agent.on_exhausted !== "halt" &&
|
|
324
|
+
agent.on_exhausted !== "proceed") {
|
|
325
|
+
issues.push({
|
|
326
|
+
level: "error",
|
|
327
|
+
message: `Step ${i + 1}: invalid 'on_exhausted' '${String(agent.on_exhausted)}' — must be 'halt' or 'proceed'`,
|
|
328
|
+
code: "refine-on-exhausted-enum",
|
|
329
|
+
path: `steps.${i}.agent.on_exhausted`,
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
// OPT-IN routing fallbacks, both ordered {driver?, model?} lists:
|
|
333
|
+
// `downshift` (cost-aware, Phase 4 — go cheaper as budget depletes)
|
|
334
|
+
// and `escalate` (quality-aware — go more capable on judge rejection).
|
|
335
|
+
validateRouteCandidateList("downshift", agent.downshift, i, issues);
|
|
336
|
+
validateRouteCandidateList("escalate", agent.escalate, i, issues);
|
|
337
|
+
}
|
|
338
|
+
// Unconditional risk-enum check. `risk` was previously never
|
|
339
|
+
// validated here (the parser casts it; the JSON-schema enum is
|
|
340
|
+
// gated behind FLAG_SCHEMA_LINT, which defaults off). A typo like
|
|
341
|
+
// `risk: "hgh"` silently fell through the compiler's risk bucketer
|
|
342
|
+
// to `allow` — fail-open. Flag any out-of-enum value as an error so
|
|
343
|
+
// `recipe lint` / `doctor` catch it before a run. Reads risk from
|
|
344
|
+
// the top-level step AND the nested agent object (both forms occur).
|
|
345
|
+
const stepAgent = step.agent && typeof step.agent === "object"
|
|
346
|
+
? step.agent
|
|
347
|
+
: undefined;
|
|
348
|
+
const riskValue = step.risk ?? stepAgent?.risk;
|
|
349
|
+
if (riskValue !== undefined &&
|
|
350
|
+
riskValue !== "low" &&
|
|
351
|
+
riskValue !== "medium" &&
|
|
352
|
+
riskValue !== "high") {
|
|
353
|
+
issues.push({
|
|
354
|
+
level: "error",
|
|
355
|
+
message: `Step ${i + 1}: invalid risk '${String(riskValue)}' — must be one of: low, medium, high`,
|
|
356
|
+
code: "risk-enum",
|
|
357
|
+
path: `steps.${i}.risk`,
|
|
358
|
+
});
|
|
117
359
|
}
|
|
118
360
|
}
|
|
361
|
+
validateAwaitsTargets(r, recipe, issues);
|
|
362
|
+
validateJudgeReviewsTargets(r, issues);
|
|
119
363
|
validateTemplateReferences(r, issues, collectParallelEachKeys(recipe));
|
|
120
364
|
}
|
|
365
|
+
validateRecipeBudget(r, issues);
|
|
366
|
+
validateRecipeErrorPolicy(r, issues);
|
|
121
367
|
}
|
|
122
368
|
if (isEnabled(FLAG_SCHEMA_LINT)) {
|
|
123
369
|
issues.push(...validateRecipeSchema(normalizedRecipe));
|
|
@@ -136,6 +382,251 @@ export function validateRecipeDefinition(recipe) {
|
|
|
136
382
|
errors,
|
|
137
383
|
};
|
|
138
384
|
}
|
|
385
|
+
/**
|
|
386
|
+
* Validate the optional recipe `budget` block. Closes a real gap: before
|
|
387
|
+
* cost-routing Phase 3 there was NO budget validation, so `tokensMax: -5` or
|
|
388
|
+
* `tokensMax: "lots"` passed lint silently. A present cap must be a positive
|
|
389
|
+
* number; `onBreach` must be the halt|warn enum.
|
|
390
|
+
*/
|
|
391
|
+
function validateRecipeBudget(r, issues) {
|
|
392
|
+
const budget = r.budget;
|
|
393
|
+
if (budget === undefined)
|
|
394
|
+
return;
|
|
395
|
+
if (typeof budget !== "object" || budget === null || Array.isArray(budget)) {
|
|
396
|
+
issues.push({
|
|
397
|
+
level: "error",
|
|
398
|
+
message: "'budget' must be an object",
|
|
399
|
+
path: "budget",
|
|
400
|
+
code: "budget-type",
|
|
401
|
+
});
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
const b = budget;
|
|
405
|
+
for (const key of ["tokensMax", "usdMax"]) {
|
|
406
|
+
const value = b[key];
|
|
407
|
+
if (value === undefined)
|
|
408
|
+
continue;
|
|
409
|
+
if (typeof value !== "number" || !(value > 0)) {
|
|
410
|
+
issues.push({
|
|
411
|
+
level: "error",
|
|
412
|
+
message: `budget.${key} must be a positive number`,
|
|
413
|
+
path: `budget.${key}`,
|
|
414
|
+
code: "budget-positive",
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (b.onBreach !== undefined &&
|
|
419
|
+
b.onBreach !== "halt" &&
|
|
420
|
+
b.onBreach !== "warn") {
|
|
421
|
+
issues.push({
|
|
422
|
+
level: "error",
|
|
423
|
+
message: "budget.onBreach must be 'halt' or 'warn'",
|
|
424
|
+
path: "budget.onBreach",
|
|
425
|
+
code: "budget-onbreach-enum",
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
if (b.estimateUnmeasured !== undefined &&
|
|
429
|
+
typeof b.estimateUnmeasured !== "boolean") {
|
|
430
|
+
issues.push({
|
|
431
|
+
level: "error",
|
|
432
|
+
message: "budget.estimateUnmeasured must be a boolean",
|
|
433
|
+
path: "budget.estimateUnmeasured",
|
|
434
|
+
code: "budget-estimate-type",
|
|
435
|
+
});
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Validate the optional recipe `on_error` policy block. Audit 2026-06-03
|
|
440
|
+
* (MEDIUM): the hand-rolled lint never checked it, so a typo'd `fallback`
|
|
441
|
+
* enum, a non-numeric `retry`, or a negative `retry` (which the runtime
|
|
442
|
+
* now clamps — see chainedRunner.withRetry, audit HIGH #8) passed lint
|
|
443
|
+
* silently. Mirrors validateRecipeBudget. `retry` is a non-negative integer;
|
|
444
|
+
* `retryDelay` a non-negative number (ms); `fallback` the documented enum.
|
|
445
|
+
*/
|
|
446
|
+
function validateRecipeErrorPolicy(r, issues) {
|
|
447
|
+
const onError = r.on_error;
|
|
448
|
+
if (onError === undefined)
|
|
449
|
+
return;
|
|
450
|
+
if (typeof onError !== "object" ||
|
|
451
|
+
onError === null ||
|
|
452
|
+
Array.isArray(onError)) {
|
|
453
|
+
issues.push({
|
|
454
|
+
level: "error",
|
|
455
|
+
message: "'on_error' must be an object",
|
|
456
|
+
path: "on_error",
|
|
457
|
+
code: "on-error-type",
|
|
458
|
+
});
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const e = onError;
|
|
462
|
+
if (e.retry !== undefined) {
|
|
463
|
+
if (typeof e.retry !== "number" ||
|
|
464
|
+
!Number.isInteger(e.retry) ||
|
|
465
|
+
e.retry < 0) {
|
|
466
|
+
issues.push({
|
|
467
|
+
level: "error",
|
|
468
|
+
message: "on_error.retry must be a non-negative integer",
|
|
469
|
+
path: "on_error.retry",
|
|
470
|
+
code: "on-error-retry",
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (e.retryDelay !== undefined) {
|
|
475
|
+
if (typeof e.retryDelay !== "number" ||
|
|
476
|
+
!Number.isFinite(e.retryDelay) ||
|
|
477
|
+
e.retryDelay < 0) {
|
|
478
|
+
issues.push({
|
|
479
|
+
level: "error",
|
|
480
|
+
message: "on_error.retryDelay must be a non-negative number (ms)",
|
|
481
|
+
path: "on_error.retryDelay",
|
|
482
|
+
code: "on-error-retrydelay",
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (e.fallback !== undefined &&
|
|
487
|
+
e.fallback !== "log_only" &&
|
|
488
|
+
e.fallback !== "abort" &&
|
|
489
|
+
e.fallback !== "deliver_original") {
|
|
490
|
+
issues.push({
|
|
491
|
+
level: "error",
|
|
492
|
+
message: "on_error.fallback must be 'log_only', 'abort', or 'deliver_original'",
|
|
493
|
+
path: "on_error.fallback",
|
|
494
|
+
code: "on-error-fallback-enum",
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Validate step `awaits:` targets against the set of declared step ids.
|
|
500
|
+
*
|
|
501
|
+
* An `awaits:` target that matches no real step is a recipe-authoring bug
|
|
502
|
+
* that the runtime can't recover from: the cycle-detection DFS skips the
|
|
503
|
+
* phantom edge (so `hasCycles` stays false), but Kahn's algorithm counts it
|
|
504
|
+
* in the awaiting step's in-degree and never decrements it — so the
|
|
505
|
+
* awaiting step AND all its transitive dependents silently drop out of the
|
|
506
|
+
* topological order, never run, and the run STILL reports success. Flag it
|
|
507
|
+
* statically so `recipe lint` / `doctor` catch it before any run.
|
|
508
|
+
*
|
|
509
|
+
* Known-id collection runs over BOTH:
|
|
510
|
+
* - the NORMALIZED recipe (`normalizedRecipe.steps`) — `awaits:` clauses
|
|
511
|
+
* live here, and `flattenValidationSteps` has already hoisted parallel
|
|
512
|
+
* children to top level (so child ids are present), AND
|
|
513
|
+
* - the RAW recipe (`rawRecipe.steps`) — still carries the `parallel:`
|
|
514
|
+
* CONTAINER ids that flattening drops.
|
|
515
|
+
*
|
|
516
|
+
* The union matters because `awaits: [<parallel-group-id>]` is VALID at
|
|
517
|
+
* runtime: `chainedRunner.expandParallelSteps` rewrites a group-id await to
|
|
518
|
+
* the expanded child ids. Collecting from the raw steps keeps those
|
|
519
|
+
* container ids in `knownIds` so a legitimate group-await isn't flagged,
|
|
520
|
+
* while a genuine typo (`gather2`) — present in neither list — still errors.
|
|
521
|
+
*/
|
|
522
|
+
/**
|
|
523
|
+
* Cross-check each judge step's `reviews:` target against the set of resolvable
|
|
524
|
+
* step keys. The runtime resolves `reviews` against ctx (keyed by `into`) first,
|
|
525
|
+
* then falls back to step `id` — a reference matching neither silently reviews
|
|
526
|
+
* nothing. Flag as error when a refine loop is configured (max_revisions set),
|
|
527
|
+
* warning otherwise (the judge still runs; it just has no prior output to review).
|
|
528
|
+
*/
|
|
529
|
+
function validateJudgeReviewsTargets(r, issues) {
|
|
530
|
+
const steps = Array.isArray(r.steps)
|
|
531
|
+
? r.steps
|
|
532
|
+
: [];
|
|
533
|
+
// Collect all resolvable keys: every step's `into` value + every step `id`.
|
|
534
|
+
const resolvable = new Set();
|
|
535
|
+
for (const step of steps) {
|
|
536
|
+
const agent = step.agent && typeof step.agent === "object"
|
|
537
|
+
? step.agent
|
|
538
|
+
: undefined;
|
|
539
|
+
if (typeof agent?.into === "string")
|
|
540
|
+
resolvable.add(agent.into);
|
|
541
|
+
if (typeof step.id === "string")
|
|
542
|
+
resolvable.add(step.id);
|
|
543
|
+
}
|
|
544
|
+
for (let i = 0; i < steps.length; i++) {
|
|
545
|
+
const step = steps[i];
|
|
546
|
+
const agent = step.agent && typeof step.agent === "object"
|
|
547
|
+
? step.agent
|
|
548
|
+
: undefined;
|
|
549
|
+
if (!agent || agent.kind !== "judge")
|
|
550
|
+
continue;
|
|
551
|
+
const reviews = agent.reviews;
|
|
552
|
+
if (typeof reviews !== "string" || reviews.length === 0)
|
|
553
|
+
continue;
|
|
554
|
+
if (resolvable.has(reviews))
|
|
555
|
+
continue;
|
|
556
|
+
const hasRefineLoop = agent.max_revisions !== undefined || agent.on_exhausted !== undefined;
|
|
557
|
+
issues.push({
|
|
558
|
+
level: hasRefineLoop ? "error" : "warning",
|
|
559
|
+
message: `Step ${i + 1}: 'reviews: ${reviews}' does not match any step into key or step id — the judge would review nothing at run time`,
|
|
560
|
+
code: "judge-reviews-unresolved",
|
|
561
|
+
path: `steps.${i}.agent.reviews`,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function validateAwaitsTargets(normalizedRecipe, rawRecipe, issues) {
|
|
566
|
+
const steps = Array.isArray(normalizedRecipe.steps)
|
|
567
|
+
? normalizedRecipe.steps
|
|
568
|
+
: [];
|
|
569
|
+
if (steps.length === 0)
|
|
570
|
+
return;
|
|
571
|
+
const knownIds = new Set();
|
|
572
|
+
const collectIds = (list) => {
|
|
573
|
+
for (const step of list) {
|
|
574
|
+
if (!step || typeof step !== "object")
|
|
575
|
+
continue;
|
|
576
|
+
if (typeof step.id === "string")
|
|
577
|
+
knownIds.add(step.id);
|
|
578
|
+
if (Array.isArray(step.parallel)) {
|
|
579
|
+
collectIds(step.parallel);
|
|
580
|
+
}
|
|
581
|
+
else if (step.parallel &&
|
|
582
|
+
typeof step.parallel === "object" &&
|
|
583
|
+
Array.isArray(step.parallel.steps)) {
|
|
584
|
+
collectIds(step.parallel.steps);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
// Collect from the flattened (normalized) list first — child ids + any
|
|
589
|
+
// top-level ids.
|
|
590
|
+
collectIds(steps);
|
|
591
|
+
// Then collect from the RAW recipe steps so parallel-group CONTAINER ids
|
|
592
|
+
// (which `flattenValidationSteps` strips) are recognised as valid await
|
|
593
|
+
// targets. `collectIds` recurses into `parallel:` arrays / map-reduce
|
|
594
|
+
// `{steps}` blocks, picking up both the container id and its children.
|
|
595
|
+
if (rawRecipe &&
|
|
596
|
+
typeof rawRecipe === "object" &&
|
|
597
|
+
!Array.isArray(rawRecipe) &&
|
|
598
|
+
Array.isArray(rawRecipe.steps)) {
|
|
599
|
+
collectIds(rawRecipe.steps);
|
|
600
|
+
}
|
|
601
|
+
const checkAwaits = (list, label) => {
|
|
602
|
+
for (let i = 0; i < list.length; i++) {
|
|
603
|
+
const step = list[i];
|
|
604
|
+
if (!step || typeof step !== "object")
|
|
605
|
+
continue;
|
|
606
|
+
if (Array.isArray(step.awaits)) {
|
|
607
|
+
for (const target of step.awaits) {
|
|
608
|
+
if (typeof target === "string" && !knownIds.has(target)) {
|
|
609
|
+
issues.push({
|
|
610
|
+
level: "error",
|
|
611
|
+
message: `${label(i)}: awaits unknown step '${target}' — no step with that id exists. The step (and everything depending on it) would silently never run.`,
|
|
612
|
+
code: "unknown-awaits-target",
|
|
613
|
+
path: `steps.${i}.awaits`,
|
|
614
|
+
});
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (Array.isArray(step.parallel)) {
|
|
619
|
+
checkAwaits(step.parallel, (j) => `${label(i)}.parallel[${j}]`);
|
|
620
|
+
}
|
|
621
|
+
else if (step.parallel &&
|
|
622
|
+
typeof step.parallel === "object" &&
|
|
623
|
+
Array.isArray(step.parallel.steps)) {
|
|
624
|
+
checkAwaits(step.parallel.steps, (j) => `${label(i)}.parallel.steps[${j}]`);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
checkAwaits(steps, (i) => `Step ${i + 1}`);
|
|
629
|
+
}
|
|
139
630
|
/**
|
|
140
631
|
* Validate `trigger.vars` / `trigger.inputs` array entries. Catches names
|
|
141
632
|
* the runtime template engine can't resolve as `{{var}}` (e.g. spaces,
|
|
@@ -271,7 +762,17 @@ function flattenValidationStep(step) {
|
|
|
271
762
|
if (otherwiseStep &&
|
|
272
763
|
typeof otherwiseStep === "object" &&
|
|
273
764
|
!Array.isArray(otherwiseStep)) {
|
|
765
|
+
// Validate the `otherwise` block.
|
|
274
766
|
branchSteps.push(...flattenValidationStep(otherwiseStep));
|
|
767
|
+
// Also validate the co-located conditional step fields (if any) — strip
|
|
768
|
+
// `otherwise` so the validator sees only the branch-step shape.
|
|
769
|
+
// Only do this when the entry has keys beyond `otherwise`; a standalone
|
|
770
|
+
// `{ otherwise: {...} }` entry has nothing else to validate and passing
|
|
771
|
+
// an empty object `{}` to the schema validator produces bogus errors.
|
|
772
|
+
const { otherwise: _omit, ...branchWithoutOtherwise } = branchRecord;
|
|
773
|
+
if (Object.keys(branchWithoutOtherwise).length > 0) {
|
|
774
|
+
branchSteps.push(...flattenValidationStep(branchWithoutOtherwise));
|
|
775
|
+
}
|
|
275
776
|
continue;
|
|
276
777
|
}
|
|
277
778
|
branchSteps.push(...flattenValidationStep(branchRecord));
|
|
@@ -395,15 +896,29 @@ function collectParallelEachKeys(recipe) {
|
|
|
395
896
|
if (!recipe || typeof recipe !== "object" || Array.isArray(recipe))
|
|
396
897
|
return keys;
|
|
397
898
|
const steps = recipe.steps;
|
|
899
|
+
collectParallelEachKeysFromSteps(steps, keys);
|
|
900
|
+
return keys;
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* Walk a steps array, collecting parallel-each loop variable keys. Recurses
|
|
904
|
+
* into `parallel: [...]` group arrays so a nested map-reduce step inside a
|
|
905
|
+
* parallel group still contributes its loop variable (`as`) — otherwise
|
|
906
|
+
* `{{item}}` references in those child steps were flagged as unknown template
|
|
907
|
+
* references, blocking valid recipes (audit 2026-06-10 recipe-validation-4).
|
|
908
|
+
*/
|
|
909
|
+
function collectParallelEachKeysFromSteps(steps, keys) {
|
|
398
910
|
if (!Array.isArray(steps))
|
|
399
|
-
return
|
|
911
|
+
return;
|
|
400
912
|
for (const step of steps) {
|
|
401
913
|
if (!step || typeof step !== "object" || Array.isArray(step))
|
|
402
914
|
continue;
|
|
403
915
|
const s = step;
|
|
404
|
-
if (s.parallel
|
|
405
|
-
|
|
406
|
-
|
|
916
|
+
if (Array.isArray(s.parallel)) {
|
|
917
|
+
// Parallel GROUP array — recurse into its child steps.
|
|
918
|
+
collectParallelEachKeysFromSteps(s.parallel, keys);
|
|
919
|
+
}
|
|
920
|
+
else if (s.parallel && typeof s.parallel === "object") {
|
|
921
|
+
// Parallel map-reduce (each/as) object.
|
|
407
922
|
const par = s.parallel;
|
|
408
923
|
if (typeof par.as === "string")
|
|
409
924
|
keys.add(par.as);
|
|
@@ -411,24 +926,33 @@ function collectParallelEachKeys(recipe) {
|
|
|
411
926
|
keys.add(s.id);
|
|
412
927
|
keys.add(`${s.id}.results`);
|
|
413
928
|
}
|
|
929
|
+
// Recurse into the map-reduce body so deeper nesting is also covered.
|
|
930
|
+
collectParallelEachKeysFromSteps(par.steps, keys);
|
|
414
931
|
}
|
|
415
932
|
// Step-level each: "{{items}}" as: item — loop variable
|
|
416
933
|
if (typeof s.as === "string")
|
|
417
934
|
keys.add(s.as);
|
|
418
935
|
}
|
|
419
|
-
return keys;
|
|
420
936
|
}
|
|
421
937
|
function validateTemplateReferences(recipe, issues, extraParallelKeys) {
|
|
422
938
|
const builtinKeys = new Set([
|
|
939
|
+
// Date/time tokens injected at runtime: `date`/`time` on the flat path and
|
|
940
|
+
// `DATE`/`TIME` on the chained dispatch path, plus the YYYY / YYYY-MM /
|
|
941
|
+
// YYYY-MM-DD / ISO_NOW / HH / MM / SS family — now injected on BOTH paths
|
|
942
|
+
// (yamlRunner.ts ctx + dispatchRecipe env), so {{YYYY-MM-DD}} etc. render
|
|
943
|
+
// real values AND pass lint. Keep in sync with the yamlRunner.ts injection
|
|
944
|
+
// sites. (audit 2026-06-10 recipe-validation-1)
|
|
423
945
|
"date",
|
|
424
946
|
"time",
|
|
947
|
+
"DATE",
|
|
948
|
+
"TIME",
|
|
425
949
|
"YYYY",
|
|
426
950
|
"YYYY-MM",
|
|
427
951
|
"YYYY-MM-DD",
|
|
428
952
|
"ISO_NOW",
|
|
429
|
-
"HH",
|
|
430
|
-
"MM",
|
|
431
|
-
"SS",
|
|
953
|
+
"HH",
|
|
954
|
+
"MM",
|
|
955
|
+
"SS",
|
|
432
956
|
"this", // Handlebars loop current-item reference
|
|
433
957
|
]);
|
|
434
958
|
const availableKeys = new Set(builtinKeys);
|