flujo-ai 3.34.0 → 3.35.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/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +324 -317
- package/.next/app-path-routes-manifest.json +19 -18
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +24 -24
- package/.next/routes-manifest.json +9 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +1 -1
- package/.next/server/app/api/approvals/[id]/route.js +1 -1
- package/.next/server/app/api/approvals/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/approvals/route.js +2 -2
- package/.next/server/app/api/approvals/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/backup/route.js +1 -1
- package/.next/server/app/api/backup/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/bugs/enhance/route.js +1 -1
- package/.next/server/app/api/bugs/enhance/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/cwd/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/encryption/secure/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/env/route.js +2 -2
- package/.next/server/app/api/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/[id]/versions/[versionId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/[id]/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/compile/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/generate/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/generator/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/improve/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/prompt-renderer/route.js +1 -1
- package/.next/server/app/api/flow/prompt-renderer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/quick-chat/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/repair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/flow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/local-models/capability/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/local-models/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/local-models/suggest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/app-sandbox/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/cancel/route.js +1 -1
- package/.next/server/app/api/mcp/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/oauth-capability/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/[name]/prompts/get/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/[name]/prompts/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/[name]/resources/read/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/[name]/resources/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/[name]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/[name]/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/[name]/tools/[toolName]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/[name]/tools/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/servers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/test-connection/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp/test-connection/stream/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp-registry/route.js +1 -1
- package/.next/server/app/api/mcp-registry/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/mcp-registry/spotlight/route.js +1 -1
- package/.next/server/app/api/mcp-registry/spotlight/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/model/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/model/provider/route.js +1 -1
- package/.next/server/app/api/model/provider/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/model/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/model/test/route.js +1 -1
- package/.next/server/app/api/model/test/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/oauth/callback/route.js +1 -1
- package/.next/server/app/api/oauth/callback/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/oauth/initiate/route.js +1 -1
- package/.next/server/app/api/oauth/initiate/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/oauth/reset/route.js +1 -1
- package/.next/server/app/api/oauth/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/build/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/derive-secrets/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/install/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/installed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/resolve/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/scan-targets/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/search/route.js +1 -1
- package/.next/server/app/api/packages/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/packages/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/planned-executions/[id]/route.js +1 -1
- package/.next/server/app/api/planned-executions/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/planned-executions/[id]/run/route.js +1 -1
- package/.next/server/app/api/planned-executions/[id]/run/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/planned-executions/[id]/runs/route.js +1 -1
- package/.next/server/app/api/planned-executions/[id]/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/planned-executions/preview-schedule/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/planned-executions/reconcile/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/planned-executions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/auth/resend/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/auth/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/auth/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/feedback/route.js +1 -1
- package/.next/server/app/api/registry/feedback/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/oauth/callback/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/oauth/initiate/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/packages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/publish/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/registry/settings/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/restore/route.js +1 -1
- package/.next/server/app/api/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/runs/active/route.js +1 -1
- package/.next/server/app/api/runs/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/storage/route.js +1 -1
- package/.next/server/app/api/storage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/telemetry/daily-active/route.js +1 -1
- package/.next/server/app/api/telemetry/daily-active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/update/route.js +1 -1
- package/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/waves/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/webhooks/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/chat/page.js +2 -2
- package/.next/server/app/chat/page.js.nft.json +1 -1
- package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
- package/.next/server/app/chat.html +1 -1
- package/.next/server/app/chat.rsc +2 -2
- package/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/docs.html +1 -1
- package/.next/server/app/docs.rsc +1 -1
- package/.next/server/app/executions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/executions.html +1 -1
- package/.next/server/app/executions.rsc +1 -1
- package/.next/server/app/flows/page.js +2 -2
- package/.next/server/app/flows/page.js.nft.json +1 -1
- package/.next/server/app/flows/page_client-reference-manifest.js +1 -1
- package/.next/server/app/flows.html +1 -1
- package/.next/server/app/flows.rsc +2 -2
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +1 -1
- package/.next/server/app/mcp/page_client-reference-manifest.js +1 -1
- package/.next/server/app/mcp-flows/route.js +1 -1
- package/.next/server/app/mcp-flows/route_client-reference-manifest.js +1 -1
- package/.next/server/app/mcp-proxy/[server]/route.js +1 -1
- package/.next/server/app/mcp-proxy/[server]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/mcp.html +1 -1
- package/.next/server/app/mcp.rsc +2 -2
- package/.next/server/app/models/page.js +1 -1
- package/.next/server/app/models/page_client-reference-manifest.js +1 -1
- package/.next/server/app/packages/page.js +1 -1
- package/.next/server/app/packages/page_client-reference-manifest.js +1 -1
- package/.next/server/app/packages.html +1 -1
- package/.next/server/app/packages.rsc +2 -2
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/page.js +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings.html +1 -1
- package/.next/server/app/settings.rsc +2 -2
- package/.next/server/app/v1/chat/completions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/breakpoints/route.js +2 -2
- package/.next/server/app/v1/chat/conversations/[conversationId]/breakpoints/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/cancel/route.js +2 -2
- package/.next/server/app/v1/chat/conversations/[conversationId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/debug/continue/route.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/debug/continue/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/debug/step/route.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/debug/step/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/edit-state/route.js +2 -2
- package/.next/server/app/v1/chat/conversations/[conversationId]/edit-state/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/events/route.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/events/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/inject/route.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/inject/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/resources/[resourceId]/content/route.js +1 -0
- package/.next/server/app/v1/chat/conversations/[conversationId]/resources/[resourceId]/content/route.js.nft.json +1 -0
- package/.next/server/app/v1/chat/conversations/[conversationId]/resources/[resourceId]/content/route_client-reference-manifest.js +1 -0
- package/.next/server/app/v1/chat/conversations/[conversationId]/resources/route.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/resources/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/respond/route.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/route.js +1 -1
- package/.next/server/app/v1/chat/conversations/[conversationId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/conversations/route.js +1 -1
- package/.next/server/app/v1/chat/conversations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/chat/events/route.js +1 -1
- package/.next/server/app/v1/chat/events/route_client-reference-manifest.js +1 -1
- package/.next/server/app/v1/models/route.js +1 -1
- package/.next/server/app/v1/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/waves/page_client-reference-manifest.js +1 -1
- package/.next/server/app/waves.html +1 -1
- package/.next/server/app/waves.rsc +1 -1
- package/.next/server/app-paths-manifest.json +19 -18
- package/.next/server/chunks/1227.js +1 -1
- package/.next/server/chunks/1805.js +1 -1
- package/.next/server/chunks/2273.js +2 -2
- package/.next/server/chunks/2372.js +1 -1
- package/.next/server/chunks/2859.js +1 -1
- package/.next/server/chunks/3935.js +4 -0
- package/.next/server/chunks/4265.js +1 -1
- package/.next/server/chunks/4771.js +2 -2
- package/.next/server/chunks/4822.js +1 -1
- package/.next/server/chunks/5096.js +1 -1
- package/.next/server/chunks/5309.js +1 -1
- package/.next/server/chunks/544.js +16 -16
- package/.next/server/chunks/5544.js +1 -1
- package/.next/server/chunks/5703.js +2 -2
- package/.next/server/chunks/6041.js +1 -1
- package/.next/server/chunks/6226.js +1 -1
- package/.next/server/chunks/6747.js +42 -42
- package/.next/server/chunks/701.js +1 -1
- package/.next/server/chunks/7069.js +4 -4
- package/.next/server/chunks/7506.js +1 -1
- package/.next/server/chunks/7628.js +1 -1
- package/.next/server/chunks/7891.js +1 -1
- package/.next/server/chunks/7993.js +1 -1
- package/.next/server/chunks/8284.js +1 -1
- package/.next/server/chunks/8387.js +1 -1
- package/.next/server/chunks/8645.js +1 -1
- package/.next/server/chunks/8739.js +1 -1
- package/.next/server/chunks/9085.js +1 -1
- package/.next/server/chunks/9235.js +1 -1
- package/.next/server/chunks/9285.js +1 -1
- package/.next/server/functions-config-manifest.json +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{8650-5294c6ed1173b014.js → 8650-aa22dbf7b37348f0.js} +1 -1
- package/.next/static/chunks/9611-9867e6e8e65172ec.js +1 -0
- package/.next/static/chunks/app/api/approvals/[id]/{route-9ea2990be4b67136.js → route-b9c783850b4c2acf.js} +1 -1
- package/.next/static/chunks/app/api/approvals/{route-9ea2990be4b67136.js → route-b9c783850b4c2acf.js} +1 -1
- package/.next/static/chunks/app/api/backup/{route-9ea2990be4b67136.js → route-b9c783850b4c2acf.js} +1 -1
- package/.next/static/chunks/app/api/browse/{route-9ea2990be4b67136.js → route-b9c783850b4c2acf.js} +1 -1
- package/.next/static/chunks/app/api/bugs/enhance/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/cwd/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/encryption/secure/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/env/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/[id]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/[id]/versions/[versionId]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/[id]/versions/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/compile/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/generate/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/generator/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/improve/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/prompt-renderer/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/quick-chat/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/repair/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/flow/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/git/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/init/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/local-models/capability/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/local-models/pull/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/local-models/suggest/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/app-sandbox/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/cancel/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/oauth-capability/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/[name]/prompts/get/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/[name]/prompts/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/[name]/resources/read/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/[name]/resources/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/[name]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/[name]/status/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/[name]/tools/[toolName]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/[name]/tools/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/servers/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/test-connection/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp/test-connection/stream/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp-registry/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/mcp-registry/spotlight/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/model/[id]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/model/provider/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/model/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/model/test/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/oauth/callback/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/oauth/initiate/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/oauth/reset/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/build/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/derive-secrets/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/install/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/install/status/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/installed/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/resolve/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/scan-targets/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/search/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/packages/uninstall/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/planned-executions/[id]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/planned-executions/[id]/run/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/planned-executions/[id]/runs/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/planned-executions/preview-schedule/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/planned-executions/reconcile/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/planned-executions/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/auth/resend/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/auth/reset/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/auth/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/feedback/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/oauth/callback/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/oauth/initiate/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/packages/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/publish/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/registry/settings/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/restore/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/runs/active/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/storage/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/telemetry/daily-active/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/update/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/waves/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/api/webhooks/[id]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/chat/{page-bc7807593b8b7394.js → page-e37bbc561f40ce60.js} +1 -1
- package/.next/static/chunks/app/flows/{page-87fb466e491fc068.js → page-e52c8943555e38dd.js} +1 -1
- package/.next/static/chunks/app/mcp-flows/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/mcp-proxy/[server]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/models/page-595597042e227970.js +1 -0
- package/.next/static/chunks/app/packages/page-f1a22789a6c0e0b6.js +1 -0
- package/.next/static/chunks/app/settings/{page-2fc3a70bfd25c48b.js → page-f35e939032b0277d.js} +1 -1
- package/.next/static/chunks/app/v1/chat/completions/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/breakpoints/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/cancel/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/debug/continue/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/debug/step/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/edit-state/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/events/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/inject/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/resources/[resourceId]/content/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/resources/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/respond/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/conversations/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/chat/events/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/app/v1/models/route-b9c783850b4c2acf.js +1 -0
- package/.next/static/chunks/{webpack-d5d737ff6a86674f.js → webpack-9d09d53b271f49e2.js} +1 -1
- package/.next/trace +10 -10
- package/.next/types/app/v1/chat/conversations/[conversationId]/resources/[resourceId]/content/route.ts +347 -0
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/README.md +60 -61
- package/package.json +1 -1
- package/.next/server/chunks/4308.js +0 -4
- package/.next/static/chunks/6733-c9029143901e62e9.js +0 -1
- package/.next/static/chunks/app/api/bugs/enhance/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/cwd/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/encryption/secure/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/env/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/[id]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/[id]/versions/[versionId]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/[id]/versions/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/compile/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/generate/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/generator/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/improve/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/prompt-renderer/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/quick-chat/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/repair/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/flow/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/git/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/init/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/local-models/capability/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/local-models/pull/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/local-models/suggest/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/app-sandbox/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/cancel/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/oauth-capability/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/[name]/prompts/get/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/[name]/prompts/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/[name]/resources/read/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/[name]/resources/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/[name]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/[name]/status/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/[name]/tools/[toolName]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/[name]/tools/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/servers/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/test-connection/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp/test-connection/stream/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp-registry/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/mcp-registry/spotlight/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/model/[id]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/model/provider/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/model/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/model/test/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/oauth/callback/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/oauth/initiate/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/oauth/reset/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/build/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/derive-secrets/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/install/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/install/status/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/installed/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/resolve/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/scan-targets/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/search/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/packages/uninstall/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/planned-executions/[id]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/planned-executions/[id]/run/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/planned-executions/[id]/runs/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/planned-executions/preview-schedule/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/planned-executions/reconcile/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/planned-executions/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/auth/resend/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/auth/reset/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/auth/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/feedback/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/oauth/callback/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/oauth/initiate/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/packages/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/publish/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/registry/settings/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/restore/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/runs/active/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/storage/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/telemetry/daily-active/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/update/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/waves/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/api/webhooks/[id]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/mcp-flows/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/mcp-proxy/[server]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/models/page-a5e2437356b06db8.js +0 -1
- package/.next/static/chunks/app/packages/page-fba5696f33d9cdfb.js +0 -1
- package/.next/static/chunks/app/v1/chat/completions/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/breakpoints/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/cancel/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/debug/continue/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/debug/step/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/edit-state/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/events/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/inject/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/resources/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/respond/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/[conversationId]/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/conversations/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/chat/events/route-9ea2990be4b67136.js +0 -1
- package/.next/static/chunks/app/v1/models/route-9ea2990be4b67136.js +0 -1
- /package/.next/static/{Zz_Vh59XdtLIPcf-PxCpo → hbjnLG9RCje2AApS9TzP8}/_buildManifest.js +0 -0
- /package/.next/static/{Zz_Vh59XdtLIPcf-PxCpo → hbjnLG9RCje2AApS9TzP8}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
"use strict";exports.id=4771,exports.ids=[4771],exports.modules={4771:(a,b,c)=>{c.d(b,{getSchedulerService:()=>F});var d=c(32524),e=c(92372),f=c(38844),g=c(50846),h=c(58739),i=c(52189),j=c(33873),k=c.n(j),l=c(29021),m=c(9794);let n=(0,g.h)("backend/services/scheduler/triggers/fileWatch");var o=c(73736),p=c(10960),q=c(51875);let r=(0,g.h)("backend/services/scheduler/triggers/mcpPoll"),s=(0,g.h)("backend/services/scheduler/triggers/urlWatch");var t=c(56793);let u=(0,g.h)("backend/services/scheduler/triggers/flowEvent");function v(a){return a&&a.length>8192?`${a.slice(0,8192)}… (truncated)`:a}var w=c(59911);let x=(0,g.h)("backend/services/scheduler/state"),y=a=>`planned-execution-state/${a}`;async function z(a){try{return await (0,e.YM)(y(a),{})}catch(b){return x.error(`Failed to load trigger state for ${a}:`,b),{}}}async function A(a,b){await (0,e.VH)(y(a),b)}async function B(a){await (0,e.N2)(y(a))}let C=(0,g.h)("backend/services/scheduler/index"),D={version:1,paused:!1,executions:[]};class E{static{this.MAX_QUEUE_DEPTH=50}async start(){this.started||(this.started=!0,C.info("Starting scheduler"),await this.reconcile())}reconcile(){let a=this.reconcileChain.catch(()=>{}).then(()=>this.doReconcile());return this.reconcileChain=a,a}async doReconcile(){for(let[a,b]of this.armed)try{b.dispose()}catch(b){C.warn(`Failed to dispose trigger for ${a}:`,b)}this.armed.clear();let a=await this.loadFile();if(this.pausedCache=a.paused,a.paused)return void C.info("Scheduler is paused — nothing armed");for(let b of a.executions)if(b.enabled)try{await this.armExecution(b)}catch(c){let a=c instanceof Error?c.message:String(c);this.lastTriggerErrors.set(b.id,a),C.error(`Failed to arm "${b.name}" (${b.id}):`,c)}C.info(`Scheduler armed ${this.armed.size} execution(s)`)}async armExecution(a){let b=a.trigger;switch(b.type){case"schedule":{let c=await z(a.id);c.lastScheduledFireAt?b.catchUp&&(0,i.hk)(b,c.lastScheduledFireAt)&&(await A(a.id,{...c,lastScheduledFireAt:new Date().toISOString()}),C.info(`Catch-up run for "${a.name}" (missed while closed)`),this.fire(a,{kind:"schedule-catchup",summary:"Schedule (missed while FLUJO was closed — ran once at startup)"})):await A(a.id,{...c,lastScheduledFireAt:new Date().toISOString()}),this.armed.set(a.id,(0,i.wv)(b,()=>{(async()=>{let b=await z(a.id);await A(a.id,{...b,lastScheduledFireAt:new Date().toISOString()}),await this.fire(a,{kind:"schedule",summary:"Schedule"})})().catch(b=>C.error(`Scheduled fire failed for ${a.id}:`,b))}));break}case"webhook":break;case"file-watch":this.armed.set(a.id,function(a,b,c){let d,e=a.debounceMs??2e3,f=new Set(a.events),g=a.glob?.trim()?function(a){let b=a.replace(/\\/g,"/"),c="";for(let a=0;a<b.length;a++){let d=b[a];"*"===d?"*"===b[a+1]?"/"===b[++a+1]?(a++,c+="(?:.*/)?"):c+=".*":c+="[^/]*":"?"===d?c+="[^/]":c+=d.replace(/[.+^${}()|[\]\\]/g,"\\$&")}return RegExp(`^${c}$`)}(a.glob.trim()):null;try{d=l.realpathSync.native(a.path)}catch(d){let b=d instanceof Error?d.message:String(d);return n.warn(`Cannot watch "${a.path}": ${b}`),c(`Cannot watch "${a.path}": ${b}`),{dispose:()=>void 0}}let h=[],i=!1,j=null,o=!1,p=()=>{if(j=null,o||0===h.length)return;let a=h;i&&n.info("File-watch batch overflowed; reporting first 50 events"),h=[],i=!1,b({events:a})},q=(0,m.wB)(d,{ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:500,pollInterval:100}});return q.on("all",(a,b)=>{if(!o&&("add"===a||"change"===a||"unlink"===a)&&f.has(a)){if(g){let a=k().relative(d,b).replace(/\\/g,"/")||k().basename(b);if(!g.test(a))return}h.length>=50?i=!0:h.push({event:a,path:b}),j&&clearTimeout(j),j=setTimeout(p,e),j.unref?.()}}),q.on("error",a=>{let b=a instanceof Error?a.message:String(a);n.warn(`Watcher error for ${d}: ${b}`),c(b)}),{dispose:()=>{o=!0,j&&(clearTimeout(j),j=null),h=[],q.close().catch(a=>n.warn(`Failed to close watcher for ${d}:`,a))}}}(b,({events:c})=>{this.lastTriggerErrors.delete(a.id),this.fire(a,{kind:"file",summary:1===c.length?`File ${"unlink"===c[0].event?"deleted":"add"===c[0].event?"added":"changed"}`:`${c.length} file changes`,context:{watchedPath:b.path,events:c}})},b=>this.lastTriggerErrors.set(a.id,b)));break;case"mcp-poll":Promise.all([c.e(3128),c.e(4322),c.e(5067),c.e(6034),c.e(7821),c.e(5096),c.e(544),c.e(1925)]).then(c.bind(c,60453)).then(async({mcpService:c})=>{await c.isServerDisabled(b.serverName)&&this.lastTriggerErrors.set(a.id,`MCP server '${b.serverName}' is disabled — enable it on the MCP page or change the trigger`)}).catch(b=>C.warn(`Arm-time disabled-server check failed for ${a.id}:`,b)),this.armed.set(a.id,function(a,b){let c=a.cron||(0,p.X)(a.intervalMs),d=!1,e=!1,f=0,g=0,h=async()=>{if(!e&&!d){if(g>0)return void g--;d=!0;try{let c,d=await b.callTool(a.serverName,a.toolName,a.args);if(!d.success)throw Error(d.error||"Tool call failed");f=0;let g=await b.loadState(),h=a.evaluate;if(c="on-change"===h.mode?(0,q.Jl)(d.data,g):"new-items"===h.mode?(0,q.A1)(d.data,h.itemsPath,h.idField,g):b.evaluateAiGate?await b.evaluateAiGate(d.data,h,g):{fire:!1,newState:{},error:'The "AI decides" condition is not available yet'},e)return;if(Object.keys(c.newState).length>0&&await b.saveState(c.newState),c.error)b.onError(c.error);else if(c.fire){let{status:d}=await b.onFire({summary:`Watched tool: ${c.summary??"condition met"}`,context:{server:a.serverName,tool:a.toolName,..."object"==typeof c.context&&null!==c.context?c.context:{result:c.context}}});if(e)return;if(c.pendingState){let{giveUpError:a}=await (0,q.vV)({status:d,pendingState:c.pendingState,priorFailures:g.pendingFailures??0,saveState:b.saveState});a&&b.onError(a)}}else b.onSuccess?.()}catch(d){f++,g=Math.min(2**(f-1),8);let c=d instanceof Error?d.message:String(d);r.warn(`Poll failed for ${a.serverName}/${a.toolName} (backing off ${g} check(s)): ${c}`),b.onError(c)}finally{d=!1}}},i=new o.l4(c,{timezone:a.timezone,unref:!0},()=>void h());return h(),{dispose:()=>{e=!0,i.stop()},nextRun:()=>i.nextRun()?.toISOString()??null}}(b,{callTool:async(a,b,d)=>{let{mcpService:e}=await Promise.all([c.e(3128),c.e(4322),c.e(5067),c.e(6034),c.e(7821),c.e(5096),c.e(544),c.e(1925)]).then(c.bind(c,60453)),f=await e.callTool(a,b,d);return{success:!0===f.success,data:f.data,error:"string"==typeof f.error?f.error:void 0}},loadState:()=>z(a.id),saveState:async b=>{let c=await z(a.id);await A(a.id,{...c,...b})},onFire:async({summary:b,context:c})=>(this.lastTriggerErrors.delete(a.id),{status:(await this.fire(a,{kind:"mcp-poll",summary:b,context:c})).status}),onError:b=>this.lastTriggerErrors.set(a.id,b),onSuccess:()=>this.lastTriggerErrors.delete(a.id),evaluateAiGate:async(a,b,d)=>{let{evaluateAiGate:e}=await c.e(7506).then(c.bind(c,47506));return e(a,b,d)}}));break;case"url-watch":this.armed.set(a.id,function(a,b){let c=b.fetchImpl??fetch,d=!1,e=!1,f=async()=>{if(!e&&!d){d=!0;try{let d=await c(a.url,{redirect:"follow",headers:{"User-Agent":"FLUJO-url-watch"},signal:AbortSignal.timeout(3e4)});if(!d.ok)return void b.onError(`The URL answered with HTTP ${d.status}`);let f=await d.text(),g=(0,q.qq)(f),h=await b.loadState();if(e)return;if(!h.lastHash){await b.saveState({lastHash:g}),b.onSuccess?.();return}if(h.lastHash===g)return void b.onSuccess?.();let{status:i}=await b.onFire({summary:"Online content changed",context:{url:a.url,status:d.status,contentType:d.headers.get("content-type")??void 0,content:f.length>8192?`${f.slice(0,8192)}… (truncated, ${f.length} chars total)`:f}});if(e)return;let{giveUpError:j}=await (0,q.vV)({status:i,pendingState:{lastHash:g},priorFailures:h.pendingFailures??0,saveState:b.saveState});j&&b.onError(j)}catch(d){let c=d instanceof Error&&"TimeoutError"===d.name?"The URL did not answer within 30s":d instanceof Error?d.message:String(d);s.warn(`URL check failed for ${a.url}: ${c}`),b.onError(c)}finally{d=!1}}},g=new o.l4(a.cron,{timezone:a.timezone,unref:!0},()=>void f());return f(),{dispose:()=>{e=!0,g.stop()},nextRun:()=>g.nextRun()?.toISOString()??null}}(b,{loadState:()=>z(a.id),saveState:async b=>{let c=await z(a.id);await A(a.id,{...c,...b})},onFire:async({summary:b,context:c})=>(this.lastTriggerErrors.delete(a.id),{status:(await this.fire(a,{kind:"url-watch",summary:b,context:c})).status}),onError:b=>this.lastTriggerErrors.set(a.id,b),onSuccess:()=>this.lastTriggerErrors.delete(a.id)}));break;case"flow-event":this.armed.set(a.id,function(a,b){let c=a.maxChainDepth??5,d="string"==typeof a.source.topic?a.source.topic.trim():"",e=d.length>0,f=0,g=null,h=!1;if(a.outputMatch?.regex)try{g=new RegExp(a.outputMatch.regex)}catch(c){h=!0;let a=`Invalid output-match regex: ${c instanceof Error?c.message:String(c)}`;u.warn(a),b.onError(a)}let i=b=>{if(!a.outputMatch)return!0;if(h)return!1;let c=(b??"").slice(0,16384);return(!a.outputMatch.contains||!!c.includes(a.outputMatch.contains))&&(!g||!!g.test(c))},j=(d,e,g,h)=>{if(d>=c){let a=`Flow-event chain reached the depth limit (${c}); not firing again`;u.info(a),b.onSkip(a);return}let i=Date.now();if(a.minIntervalMs&&i-f<a.minIntervalMs)return void u.debug(`Flow-event cooldown active (${a.minIntervalMs}ms); ignoring event`);f=i,b.onFire({summary:e,context:g,chainDepth:d+1,sourceConversationId:h})},k=(0,t.eh)().subscribe(c=>{try{if(e){if(!(0,t.ru)(c)||c.topic!==d||!i(c.payload))return;j(c.chainDepth,`Signal "${c.topic}"`,{topic:c.topic,payload:v(c.payload),emitterFlowId:c.emitterFlowId,flowName:c.flowName,runId:c.runId,conversationId:c.conversationId,firedBy:c.firedBy},c.conversationId);return}if((0,t.ru)(c)||!(b=>{let c=a.source;return c.executionId?b.executionId===c.executionId:c.flowId?b.flowId===c.flowId:!!c.flowName&&b.flowName===c.flowName})(c)||!c.status||!(a.on??[]).includes(c.status)||!i(c.outputText))return;let b=c.flowName??c.flowId;j(c.chainDepth,`Flow "${b}" ${c.status}`,{flowId:c.flowId,flowName:c.flowName,executionId:c.executionId,runId:c.runId,conversationId:c.conversationId,status:c.status,firedBy:c.firedBy,outputText:v(c.outputText),error:c.error},c.conversationId)}catch(c){let a=c instanceof Error?c.message:String(c);u.warn(`Flow-event handling failed: ${a}`),b.onError(a)}});return{dispose:()=>k(),nextRun:()=>null}}(b,{onFire:({summary:b,context:c,chainDepth:d,sourceConversationId:e})=>{this.lastTriggerErrors.delete(a.id),this.fire(a,{kind:"flow-event",summary:b,context:c,chainDepth:d,parentConversationId:e}).catch(b=>C.error(`Flow-event fire failed for ${a.id}:`,b))},onSkip:b=>{let c=new Date().toISOString();(0,w.Hy)(a.id,{runId:(0,d.A)(),conversationId:"",firedAt:c,finishedAt:c,status:"skipped",triggerSummary:"Flow event",error:b}).catch(b=>C.warn(`Failed to record flow-event skip for ${a.id}:`,b))},onError:b=>this.lastTriggerErrors.set(a.id,b)}));break;default:C.warn(`Trigger type "${b.type}" is not implemented — "${a.name}" not armed`)}}async loadFile(){let a=await (0,e.YM)(f.Z.PLANNED_EXECUTIONS,D);return{version:1,paused:!0===a.paused,executions:Array.isArray(a.executions)?a.executions:[]}}async saveFile(a){await (0,e.VH)(f.Z.PLANNED_EXECUTIONS,a)}async isPaused(){return(await this.loadFile()).paused}async setPaused(a){let b=await this.loadFile();if(await this.saveFile({...b,paused:a}),await this.reconcile(),a){for(let a of[...this.queued.keys()])await this.cancelQueued(a,"scheduler paused",!0);await this.cancelAllExclusiveWaiting("scheduler paused",!0)}}async list(){return Promise.all((await this.loadFile()).executions.map(async a=>({execution:a,status:this.getStatus(a),lastRun:await (0,w.tl)(a.id)})))}async get(a){return(await this.loadFile()).executions.find(b=>b.id===a)??null}async create(a){let b=this.validateInput(a);if(b)return{error:b};if(void 0!==a.id&&!/^[A-Za-z0-9._:-]{1,128}$/.test(a.id))return{error:"The id must be 1-128 characters of letters, digits, dot, underscore, colon or hyphen"};if("."===a.id||".."===a.id)return{error:'The id must be a safe identifier, not "." or ".."'};let c=new Date().toISOString(),e={...a,folder:a.folder?.trim()||void 0,trigger:this.normalizeTrigger(a.trigger),id:a.id??(0,d.A)(),createdAt:c,updatedAt:c},f=await this.loadFile();return f.executions.some(a=>a.id===e.id)?{error:`A planned execution with id "${e.id}" already exists`,conflict:!0}:(await this.saveFile({...f,executions:[...f.executions,e]}),await this.reconcile(),{execution:e})}async update(a,b){let c=await this.loadFile(),d=c.executions.findIndex(b=>b.id===a);if(d<0)return{error:`No planned execution with id "${a}"`};let e=b.folder;if(Object.prototype.hasOwnProperty.call(b,"folder")&&void 0!==e&&"string"!=typeof e)return{error:"Folder must be text"};let f={...c.executions[d],...b,...Object.prototype.hasOwnProperty.call(b,"folder")?{folder:"string"==typeof e&&e.trim()||void 0}:{},...b.trigger?{trigger:this.normalizeTrigger(b.trigger)}:{},id:a,createdAt:c.executions[d].createdAt,updatedAt:new Date().toISOString()},g=this.validateInput(f);if(g)return{error:g};let h=[...c.executions];return h[d]=f,await this.saveFile({...c,executions:h}),Object.keys(b).some(a=>"folder"!==a)&&(await this.reconcile(),await this.cancelQueued(a,"execution updated",!0),await this.cancelExclusiveWaiting(a,"execution updated",!0)),{execution:f}}async delete(a){let b=await this.loadFile();return b.executions.some(b=>b.id===a)?(await this.saveFile({...b,executions:b.executions.filter(b=>b.id!==a)}),await this.reconcile(),this.lastTriggerErrors.delete(a),await this.cancelQueued(a,"execution deleted",!1),await this.cancelExclusiveWaiting(a,"execution deleted",!1),await (0,w.xC)(a),await B(a),{success:!0}):{success:!1,error:`No planned execution with id "${a}"`}}normalizeTrigger(a){return a?.type!=="webhook"||a.token?a?.type!=="mcp-poll"||a.cron?a:{...a,cron:(0,p.X)(a.intervalMs)}:{...a,token:(0,d.A)()}}validateInput(a){if(!a.name?.trim())return"A name is required";if(void 0!==a.folder&&"string"!=typeof a.folder)return"Folder must be text";if(a.folder&&a.folder.trim().length>120)return"Folder must be 120 characters or fewer";if(!a.flowId)return"A flow is required";if("string"!=typeof a.prompt)return"A prompt is required (may be empty)";if(void 0!==a.overlapStrategy&&!["skip","queue","parallel","error"].includes(a.overlapStrategy))return"Overlap strategy must be one of: skip, queue, parallel, error";if(void 0!==a.exclusive&&"boolean"!=typeof a.exclusive)return"Exclusive must be true or false";if(void 0!==a.nonExclusiveBehavior&&!["queue","skip","error"].includes(a.nonExclusiveBehavior))return"When exclusive is on, other triggers must be one of: queue, skip, error";let b=a.trigger;if(!b||"object"!=typeof b)return"A trigger is required";switch(b.type){case"schedule":{let a=(0,i.O9)(b.cron,b.timezone);return a.valid?null:`Invalid schedule: ${a.error}`}case"webhook":return null;case"file-watch":if(!b.path?.trim())return"A folder or file path to watch is required";if(!Array.isArray(b.events)||0===b.events.length)return"At least one file event is required";return null;case"mcp-poll":if(!b.serverName||!b.toolName)return"A server and tool are required";if(b.cron){let a=(0,i.O9)(b.cron,b.timezone);if(!a.valid)return`Invalid schedule: ${a.error}`}if(b.evaluate?.mode==="new-items"&&!b.evaluate.idField?.trim())return"An id field is required to detect new items";if((b.evaluate?.mode==="llm-gate"||b.evaluate?.mode==="flow-gate")&&!b.evaluate.condition?.trim())return"A condition is required for the AI to check";if(b.evaluate?.mode==="llm-gate"&&!b.evaluate.modelId)return"A model is required to check the condition";if(b.evaluate?.mode==="flow-gate"&&!b.evaluate.flowId)return"A flow is required to check the condition";return null;case"url-watch":{try{let a=new URL(b.url??"");if("http:"!==a.protocol&&"https:"!==a.protocol)return"The URL must start with http:// or https://"}catch{return"A valid URL is required"}let a=(0,i.O9)(b.cron,b.timezone);return a.valid?null:`Invalid schedule: ${a.error}`}case"flow-event":{let a=b.source;if(1!==[a?.executionId,a?.flowId,a?.flowName,a?.topic].filter(a=>"string"==typeof a&&a.trim().length>0).length)return"Choose exactly one source: a flow, a planned execution, or a signal topic";if(!("string"==typeof a?.topic&&a.topic.trim().length>0)){if(!Array.isArray(b.on)||0===b.on.length)return"Select at least one outcome to react to (completed or error)";if(b.on.some(a=>"completed"!==a&&"error"!==a))return'Outcomes must be "completed" or "error"'}if(b.outputMatch?.regex)try{new RegExp(b.outputMatch.regex)}catch(a){return`Invalid output-match regex: ${a instanceof Error?a.message:String(a)}`}if(void 0!==b.maxChainDepth&&(!Number.isInteger(b.maxChainDepth)||b.maxChainDepth<1))return"Max chain depth must be a positive whole number";if(void 0!==b.minIntervalMs&&(!Number.isFinite(b.minIntervalMs)||b.minIntervalMs<0))return"Minimum interval must be zero or more milliseconds";return null}default:return"Unknown trigger type"}}isRunning(a){let b=this.running.get(a);return void 0!==b&&b.size>0}addRunning(a,b,c){let d=this.running.get(a);d||(d=new Map,this.running.set(a,d)),d.set(b,c)}removeRunning(a,b){let c=this.running.get(a);c&&(c.delete(b),0===c.size&&this.running.delete(a))}earliestRunningSince(a){let b,c=this.running.get(a);if(c&&0!==c.size){for(let a of c.values())(void 0===b||a<b)&&(b=a);return b}}skippedRecord(a,b){let c=new Date().toISOString();return{runId:a.runId,conversationId:"",firedAt:c,finishedAt:c,status:"skipped",triggerSummary:a.payload.summary,error:b}}async cancelQueued(a,b,c){let d=this.queued.get(a);if(d&&0!==d.length){for(let e of(this.queued.delete(a),d)){let d=this.skippedRecord(e,b);if(c)try{await (0,w.Hy)(a,d)}catch(b){C.warn(`Failed to record cancelled queued fire for ${a}:`,b)}e.resolve(d)}C.info(`Cancelled ${d.length} queued fire(s) for ${a}: ${b}`)}}drainQueue(a){let b=this.queued.get(a);if(!b||0===b.length||this.isRunning(a))return;let c=b.shift();0===b.length&&this.queued.delete(a),c&&(async()=>{let b=await this.get(a);if(!b||!b.enabled||this.pausedCache){let a=b?b.enabled?"scheduler paused":"execution disabled":"execution deleted";c.resolve(this.skippedRecord(c,a));return}let d=await this.fire(b,c.payload,c.runId);c.resolve(d)})().catch(b=>C.error(`Queued fire failed for ${a}:`,b))}isSchedulerIdle(){for(let a of this.running.values())if(a.size>0)return!1;return!0}isExclusiveActive(){return null!==this.exclusiveHolder||this.exclusiveWaiting.length>0}currentExclusiveBehavior(){return null!==this.exclusiveHolder?this.exclusiveHolderBehavior:this.exclusiveWaiting[0]?.execution.nonExclusiveBehavior??"queue"}exclusiveGateFor(a){return!0!==a.exclusive&&this.isExclusiveActive()?this.currentExclusiveBehavior():null}drainExclusive(){if(null===this.exclusiveHolder&&this.exclusiveWaiting.length>0&&this.isSchedulerIdle())return void this.acquireNextExclusive();this.isExclusiveActive()||this.drainBlockedByExclusive()}acquireNextExclusive(){if(null!==this.exclusiveHolder||!this.isSchedulerIdle())return;let a=this.exclusiveWaiting.shift();if(!a)return;let b=a.execution.id;this.exclusiveHolder=b,this.exclusiveHolderBehavior=a.execution.nonExclusiveBehavior??"queue",(async()=>{let c=await this.get(b);if(!c||!c.enabled||this.pausedCache||!0!==c.exclusive){let d=c?c.enabled?this.pausedCache?"scheduler paused":"no longer exclusive":"execution disabled":"execution deleted";this.exclusiveHolder===b&&(this.exclusiveHolder=null),a.resolve(this.skippedRecord(a,d)),this.drainExclusive();return}this.exclusiveHolderBehavior=c.nonExclusiveBehavior??"queue";let d=await this.fire(c,a.payload,a.runId);a.resolve(d)})().catch(c=>{this.exclusiveHolder===b&&(this.exclusiveHolder=null),C.error(`Exclusive acquire failed for ${b}:`,c),a.resolve(this.skippedRecord(a,"exclusive acquire failed")),this.drainExclusive()})}drainBlockedByExclusive(){if(0===this.blockedByExclusive.length)return;let a=this.blockedByExclusive;for(let b of(this.blockedByExclusive=[],a))(async()=>{let a=await this.get(b.execution.id);if(!a||!a.enabled||this.pausedCache){let c=a?a.enabled?"scheduler paused":"execution disabled":"execution deleted";b.resolve(this.skippedRecord(b,c));return}let c=await this.fire(a,b.payload,b.runId);b.resolve(c)})().catch(a=>C.error(`Deferred non-exclusive fire failed for ${b.execution.id}:`,a))}async cancelExclusiveWaiting(a,b,c){let d=[];if(this.exclusiveWaiting=this.exclusiveWaiting.filter(b=>b.execution.id!==a||(d.push(b),!1)),this.blockedByExclusive=this.blockedByExclusive.filter(b=>b.execution.id!==a||(d.push(b),!1)),0!==d.length){for(let e of d){let d=this.skippedRecord(e,b);if(c)try{await (0,w.Hy)(a,d)}catch(b){C.warn(`Failed to record cancelled exclusive fire for ${a}:`,b)}e.resolve(d)}C.info(`Cancelled ${d.length} exclusive-related fire(s) for ${a}: ${b}`)}}async cancelAllExclusiveWaiting(a,b){let c=[...this.exclusiveWaiting,...this.blockedByExclusive];if(this.exclusiveWaiting=[],this.blockedByExclusive=[],0!==c.length){for(let d of c){let c=this.skippedRecord(d,a);if(b)try{await (0,w.Hy)(d.execution.id,c)}catch(a){C.warn(`Failed to record cancelled exclusive fire for ${d.execution.id}:`,a)}d.resolve(c)}C.info(`Cancelled ${c.length} exclusive-related fire(s): ${a}`)}}getStatus(a){let b=this.armed.get(a.id),c=void 0!==b||a.enabled&&"webhook"===a.trigger.type&&this.started&&!this.pausedCache,d=this.earliestRunningSince(a.id),e=c?void 0:a.enabled?this.pausedCache?"paused":void 0:"disabled",f=this.exclusiveHolder??void 0,g=!0!==a.exclusive&&this.isExclusiveActive();return{armed:c,notArmedReason:e,nextRun:b?.nextRun?b.nextRun():void 0,lastTriggerError:this.lastTriggerErrors.get(a.id),running:void 0!==d,runningSince:d,exclusiveHolderId:f,blockedByExclusive:g}}async runNow(a){let b=await this.get(a);return b?{record:await this.fire(b,{kind:"manual",summary:"Manual run"},(0,d.A)(),!0)}:{error:`No planned execution with id "${a}"`}}async fire(a,b,e=(0,d.A)(),f=!1){let g,i=new Date().toISOString();if(await (0,h.isEncryptionLocked)()){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:"encryption locked"};return await (0,w.Hy)(a.id,c),C.info(`Skipped fire for "${a.name}" — encryption locked`),c}let j="flow-event"===b.kind;if(!f&&!j){if(!0===a.exclusive){if(this.exclusiveHolder!==a.id){if(null!==this.exclusiveHolder||!this.isSchedulerIdle()){let c=this.exclusiveWaiting.length;if(c>=E.MAX_QUEUE_DEPTH){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:`Exclusive wait queue full (cap ${E.MAX_QUEUE_DEPTH}) — fire dropped`};return await (0,w.Hy)(a.id,c),C.warn(`Exclusive wait queue full for "${a.name}" — dropped fire`),c}return C.info(`Exclusive "${a.name}" waiting for scheduler to idle (depth ${c+1})`),new Promise(c=>{this.exclusiveWaiting.push({execution:a,payload:b,runId:e,resolve:c})})}this.exclusiveHolder=a.id,this.exclusiveHolderBehavior=a.nonExclusiveBehavior??"queue",C.info(`Exclusive "${a.name}" acquired the scheduler lock`)}}else if(this.isExclusiveActive()){let c=this.currentExclusiveBehavior();if("skip"===c){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:"Skipped — an exclusive execution holds the scheduler lock"};return await (0,w.Hy)(a.id,c),C.info(`Skipped non-exclusive fire for "${a.name}" — exclusive lock held`),c}if("error"===c){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"error",triggerSummary:b.summary,error:"Rejected — an exclusive execution holds the scheduler lock"};return await (0,w.Hy)(a.id,c),C.info(`Rejected non-exclusive fire for "${a.name}" — exclusive lock held`),c}let d=this.blockedByExclusive.length;if(d>=E.MAX_QUEUE_DEPTH){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:`Exclusive-block queue full (cap ${E.MAX_QUEUE_DEPTH}) — fire dropped`};return await (0,w.Hy)(a.id,c),C.warn(`Exclusive-block queue full for "${a.name}" — dropped fire`),c}return C.info(`Deferred non-exclusive fire for "${a.name}" — exclusive lock held (depth ${d+1})`),new Promise(c=>{this.blockedByExclusive.push({execution:a,payload:b,runId:e,resolve:c})})}}let k=a.overlapStrategy??"skip";if(!f&&this.isRunning(a.id)){if("skip"===k){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:"Previous run still in progress"};return await (0,w.Hy)(a.id,c),C.info(`Skipped overlapping fire for "${a.name}"`),c}if("error"===k){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"error",triggerSummary:b.summary,error:"Overlapping run rejected (overlapStrategy=error)"};return await (0,w.Hy)(a.id,c),C.info(`Rejected overlapping fire for "${a.name}" (overlapStrategy=error)`),c}if("queue"===k){let c=this.queued.get(a.id)?.length??0;if(c>=E.MAX_QUEUE_DEPTH){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:`Overlap queue full (cap ${E.MAX_QUEUE_DEPTH}) — fire dropped`};return await (0,w.Hy)(a.id,c),C.warn(`Overlap queue full for "${a.name}" — dropped fire`),c}return C.info(`Queued overlapping fire for "${a.name}" (depth ${c+1})`),new Promise(c=>{let d=this.queued.get(a.id)??[];d.push({execution:a,payload:b,runId:e,resolve:c}),this.queued.set(a.id,d)})}}this.addRunning(a.id,e,i);let l=(0,d.A)();try{C.info(`Firing "${a.name}" (${b.kind})`);let d=await (0,w.Sw)(a.id),f=d.length>0?d[d.length-1]:null,h={executionName:a.name,trigger:b.kind,now:i,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,lastRun:f?{at:f.firedAt,status:f.status}:null,nextPlannedRun:this.getStatus(a).nextRun??null},j=a.approvalPolicy??"auto",k=a.saveConversations||"pause"===j?"conversation":"ephemeral",{runFlow:m}=await Promise.all([c.e(3128),c.e(4322),c.e(5067),c.e(6034),c.e(7821),c.e(5096),c.e(544),c.e(4671),c.e(6226),c.e(4306)]).then(c.bind(c,16226)),n=await m({flowId:a.flowId,prompt:this.composePrompt(a.prompt,b,h),mode:k,conversationId:l,source:"schedule",plannedExecutionId:a.id,parentRunId:b.parentConversationId,chainDepth:b.chainDepth??0,requireApproval:"auto"!==j,onApprovalRequired:j,debug:!1,userTurn:!0});g=await this.recordFromResult(a,n,{runId:e,conversationId:l,firedAt:i,payload:b})}catch(c){g={runId:e,conversationId:l,firedAt:i,finishedAt:new Date().toISOString(),status:"error",triggerSummary:b.summary,error:c instanceof Error?c.message:String(c)},C.error(`Run crashed for "${a.name}":`,c)}finally{this.removeRunning(a.id,e),this.exclusiveHolder!==a.id||this.isRunning(a.id)||(this.exclusiveHolder=null,C.info(`Exclusive "${a.name}" released the scheduler lock`)),this.drainExclusive(),this.drainQueue(a.id)}return await this.get(a.id)===null?C.info(`Dropping run record for deleted execution ${a.id}`):(await (0,w.Hy)(a.id,g),("completed"===g.status||"error"===g.status)&&await this.publishFlowRunEvent(a,g,b)),g}async recordFromResult(a,b,c){let{runId:d,conversationId:e,firedAt:f,payload:g}=c,h=new Date().toISOString(),i="awaiting_tool_approval"===b.status,j="error"===b.status&&b.error?.details?.type==="approval_required";if(i||j){let c=(b.pendingToolCalls??[]).map(a=>({id:a.id,name:"function"===a.type?a.function.name:String(a.type)})),k={runId:d,conversationId:e,firedAt:f,finishedAt:h,status:"needs_approval",triggerSummary:g.summary,outputText:this.truncateOutput(b.outputText),usage:b.usage,error:j?b.error?.message??"Tool approval required":"Awaiting tool approval",pendingApproval:{tool:c[0]?.name??b.error?.details?.name,toolCallId:c[0]?.id,pendingToolCalls:c.length>0?c:void 0}};return i&&await this.registerPendingApproval(a,k,c),k}return{runId:d,conversationId:e,firedAt:f,finishedAt:h,status:"completed"===b.status?"completed":"capped"===b.status?"capped":"error",triggerSummary:g.summary,outputText:this.truncateOutput(b.outputText),usage:b.usage,error:"completed"===b.status||"capped"===b.status?void 0:b.error?.message??`Run ended with status "${b.status}"`}}async registerPendingApproval(a,b,d){try{let e;try{let{flowService:b}=await c.e(7821).then(c.bind(c,87821));e=(await b.getFlow(a.flowId))?.name??void 0}catch(b){C.debug(`Could not resolve flow name for pending approval (${a.flowId}):`,b)}let{putPendingApproval:f}=await c.e(9285).then(c.bind(c,39285));await f({approvalId:b.conversationId,conversationId:b.conversationId,plannedExecutionId:a.id,flowId:a.flowId,flowName:e,runId:b.runId,triggerSummary:b.triggerSummary,pendingToolCalls:d,createdAt:b.firedAt})}catch(b){C.warn(`Failed to register pending approval for "${a.name}":`,b)}}async publishFlowRunEvent(a,b,d){try{let e;try{let{flowService:b}=await c.e(7821).then(c.bind(c,87821));e=(await b.getFlow(a.flowId))?.name??void 0}catch(b){C.debug(`Could not resolve flow name for run event (${a.flowId}):`,b)}let f="schedule-catchup"===d.kind?"schedule":d.kind;(0,t.eh)().publish({flowId:a.flowId,flowName:e,executionId:a.id,runId:b.runId,conversationId:b.conversationId,status:"completed"===b.status?"completed":"error",outputText:b.outputText,error:b.error,firedBy:f,chainDepth:d.chainDepth??0,timestamp:b.finishedAt??new Date().toISOString()})}catch(b){C.warn(`Failed to publish flow-run event for "${a.name}":`,b)}}composePrompt(a,b,c){let d=JSON.stringify(void 0===b.context?c:{...c,data:b.context},null,2);return`${a}
|
|
1
|
+
"use strict";exports.id=4771,exports.ids=[4771],exports.modules={4771:(a,b,c)=>{c.d(b,{getSchedulerService:()=>F});var d=c(32524),e=c(92372),f=c(38844),g=c(50846),h=c(58739),i=c(52189),j=c(33873),k=c.n(j),l=c(29021),m=c(9794);let n=(0,g.h)("backend/services/scheduler/triggers/fileWatch");var o=c(73736),p=c(10960),q=c(51875);let r=(0,g.h)("backend/services/scheduler/triggers/mcpPoll"),s=(0,g.h)("backend/services/scheduler/triggers/urlWatch");var t=c(56793);let u=(0,g.h)("backend/services/scheduler/triggers/flowEvent");function v(a){return a&&a.length>8192?`${a.slice(0,8192)}… (truncated)`:a}var w=c(59911);let x=(0,g.h)("backend/services/scheduler/state"),y=a=>`planned-execution-state/${a}`;async function z(a){try{return await (0,e.loadItem)(y(a),{})}catch(b){return x.error(`Failed to load trigger state for ${a}:`,b),{}}}async function A(a,b){await (0,e.VH)(y(a),b)}async function B(a){await (0,e.N2)(y(a))}let C=(0,g.h)("backend/services/scheduler/index"),D={version:1,paused:!1,executions:[]};class E{static{this.MAX_QUEUE_DEPTH=50}async start(){this.started||(this.started=!0,C.info("Starting scheduler"),await this.reconcile())}reconcile(){let a=this.reconcileChain.catch(()=>{}).then(()=>this.doReconcile());return this.reconcileChain=a,a}async doReconcile(){for(let[a,b]of this.armed)try{b.dispose()}catch(b){C.warn(`Failed to dispose trigger for ${a}:`,b)}this.armed.clear();let a=await this.loadFile();if(this.pausedCache=a.paused,a.paused)return void C.info("Scheduler is paused — nothing armed");for(let b of a.executions)if(b.enabled)try{await this.armExecution(b)}catch(c){let a=c instanceof Error?c.message:String(c);this.lastTriggerErrors.set(b.id,a),C.error(`Failed to arm "${b.name}" (${b.id}):`,c)}C.info(`Scheduler armed ${this.armed.size} execution(s)`)}async armExecution(a){let b=a.trigger;switch(b.type){case"schedule":{let c=await z(a.id);c.lastScheduledFireAt?b.catchUp&&(0,i.hk)(b,c.lastScheduledFireAt)&&(await A(a.id,{...c,lastScheduledFireAt:new Date().toISOString()}),C.info(`Catch-up run for "${a.name}" (missed while closed)`),this.fire(a,{kind:"schedule-catchup",summary:"Schedule (missed while FLUJO was closed — ran once at startup)"})):await A(a.id,{...c,lastScheduledFireAt:new Date().toISOString()}),this.armed.set(a.id,(0,i.wv)(b,()=>{(async()=>{let b=await z(a.id);await A(a.id,{...b,lastScheduledFireAt:new Date().toISOString()}),await this.fire(a,{kind:"schedule",summary:"Schedule"})})().catch(b=>C.error(`Scheduled fire failed for ${a.id}:`,b))}));break}case"webhook":break;case"file-watch":this.armed.set(a.id,function(a,b,c){let d,e=a.debounceMs??2e3,f=new Set(a.events),g=a.glob?.trim()?function(a){let b=a.replace(/\\/g,"/"),c="";for(let a=0;a<b.length;a++){let d=b[a];"*"===d?"*"===b[a+1]?"/"===b[++a+1]?(a++,c+="(?:.*/)?"):c+=".*":c+="[^/]*":"?"===d?c+="[^/]":c+=d.replace(/[.+^${}()|[\]\\]/g,"\\$&")}return RegExp(`^${c}$`)}(a.glob.trim()):null;try{d=l.realpathSync.native(a.path)}catch(d){let b=d instanceof Error?d.message:String(d);return n.warn(`Cannot watch "${a.path}": ${b}`),c(`Cannot watch "${a.path}": ${b}`),{dispose:()=>void 0}}let h=[],i=!1,j=null,o=!1,p=()=>{if(j=null,o||0===h.length)return;let a=h;i&&n.info("File-watch batch overflowed; reporting first 50 events"),h=[],i=!1,b({events:a})},q=(0,m.wB)(d,{ignoreInitial:!0,awaitWriteFinish:{stabilityThreshold:500,pollInterval:100}});return q.on("all",(a,b)=>{if(!o&&("add"===a||"change"===a||"unlink"===a)&&f.has(a)){if(g){let a=k().relative(d,b).replace(/\\/g,"/")||k().basename(b);if(!g.test(a))return}h.length>=50?i=!0:h.push({event:a,path:b}),j&&clearTimeout(j),j=setTimeout(p,e),j.unref?.()}}),q.on("error",a=>{let b=a instanceof Error?a.message:String(a);n.warn(`Watcher error for ${d}: ${b}`),c(b)}),{dispose:()=>{o=!0,j&&(clearTimeout(j),j=null),h=[],q.close().catch(a=>n.warn(`Failed to close watcher for ${d}:`,a))}}}(b,({events:c})=>{this.lastTriggerErrors.delete(a.id),this.fire(a,{kind:"file",summary:1===c.length?`File ${"unlink"===c[0].event?"deleted":"add"===c[0].event?"added":"changed"}`:`${c.length} file changes`,context:{watchedPath:b.path,events:c}})},b=>this.lastTriggerErrors.set(a.id,b)));break;case"mcp-poll":Promise.all([c.e(3128),c.e(4322),c.e(5067),c.e(6034),c.e(7821),c.e(5096),c.e(544),c.e(1925)]).then(c.bind(c,60453)).then(async({mcpService:c})=>{await c.isServerDisabled(b.serverName)&&this.lastTriggerErrors.set(a.id,`MCP server '${b.serverName}' is disabled — enable it on the MCP page or change the trigger`)}).catch(b=>C.warn(`Arm-time disabled-server check failed for ${a.id}:`,b)),this.armed.set(a.id,function(a,b){let c=a.cron||(0,p.X)(a.intervalMs),d=!1,e=!1,f=0,g=0,h=async()=>{if(!e&&!d){if(g>0)return void g--;d=!0;try{let c,d=await b.callTool(a.serverName,a.toolName,a.args);if(!d.success)throw Error(d.error||"Tool call failed");f=0;let g=await b.loadState(),h=a.evaluate;if(c="on-change"===h.mode?(0,q.Jl)(d.data,g):"new-items"===h.mode?(0,q.A1)(d.data,h.itemsPath,h.idField,g):b.evaluateAiGate?await b.evaluateAiGate(d.data,h,g):{fire:!1,newState:{},error:'The "AI decides" condition is not available yet'},e)return;if(Object.keys(c.newState).length>0&&await b.saveState(c.newState),c.error)b.onError(c.error);else if(c.fire){let{status:d}=await b.onFire({summary:`Watched tool: ${c.summary??"condition met"}`,context:{server:a.serverName,tool:a.toolName,..."object"==typeof c.context&&null!==c.context?c.context:{result:c.context}}});if(e)return;if(c.pendingState){let{giveUpError:a}=await (0,q.vV)({status:d,pendingState:c.pendingState,priorFailures:g.pendingFailures??0,saveState:b.saveState});a&&b.onError(a)}}else b.onSuccess?.()}catch(d){f++,g=Math.min(2**(f-1),8);let c=d instanceof Error?d.message:String(d);r.warn(`Poll failed for ${a.serverName}/${a.toolName} (backing off ${g} check(s)): ${c}`),b.onError(c)}finally{d=!1}}},i=new o.l4(c,{timezone:a.timezone,unref:!0},()=>void h());return h(),{dispose:()=>{e=!0,i.stop()},nextRun:()=>i.nextRun()?.toISOString()??null}}(b,{callTool:async(a,b,d)=>{let{mcpService:e}=await Promise.all([c.e(3128),c.e(4322),c.e(5067),c.e(6034),c.e(7821),c.e(5096),c.e(544),c.e(1925)]).then(c.bind(c,60453)),f=await e.callTool(a,b,d);return{success:!0===f.success,data:f.data,error:"string"==typeof f.error?f.error:void 0}},loadState:()=>z(a.id),saveState:async b=>{let c=await z(a.id);await A(a.id,{...c,...b})},onFire:async({summary:b,context:c})=>(this.lastTriggerErrors.delete(a.id),{status:(await this.fire(a,{kind:"mcp-poll",summary:b,context:c})).status}),onError:b=>this.lastTriggerErrors.set(a.id,b),onSuccess:()=>this.lastTriggerErrors.delete(a.id),evaluateAiGate:async(a,b,d)=>{let{evaluateAiGate:e}=await c.e(7506).then(c.bind(c,47506));return e(a,b,d)}}));break;case"url-watch":this.armed.set(a.id,function(a,b){let c=b.fetchImpl??fetch,d=!1,e=!1,f=async()=>{if(!e&&!d){d=!0;try{let d=await c(a.url,{redirect:"follow",headers:{"User-Agent":"FLUJO-url-watch"},signal:AbortSignal.timeout(3e4)});if(!d.ok)return void b.onError(`The URL answered with HTTP ${d.status}`);let f=await d.text(),g=(0,q.qq)(f),h=await b.loadState();if(e)return;if(!h.lastHash){await b.saveState({lastHash:g}),b.onSuccess?.();return}if(h.lastHash===g)return void b.onSuccess?.();let{status:i}=await b.onFire({summary:"Online content changed",context:{url:a.url,status:d.status,contentType:d.headers.get("content-type")??void 0,content:f.length>8192?`${f.slice(0,8192)}… (truncated, ${f.length} chars total)`:f}});if(e)return;let{giveUpError:j}=await (0,q.vV)({status:i,pendingState:{lastHash:g},priorFailures:h.pendingFailures??0,saveState:b.saveState});j&&b.onError(j)}catch(d){let c=d instanceof Error&&"TimeoutError"===d.name?"The URL did not answer within 30s":d instanceof Error?d.message:String(d);s.warn(`URL check failed for ${a.url}: ${c}`),b.onError(c)}finally{d=!1}}},g=new o.l4(a.cron,{timezone:a.timezone,unref:!0},()=>void f());return f(),{dispose:()=>{e=!0,g.stop()},nextRun:()=>g.nextRun()?.toISOString()??null}}(b,{loadState:()=>z(a.id),saveState:async b=>{let c=await z(a.id);await A(a.id,{...c,...b})},onFire:async({summary:b,context:c})=>(this.lastTriggerErrors.delete(a.id),{status:(await this.fire(a,{kind:"url-watch",summary:b,context:c})).status}),onError:b=>this.lastTriggerErrors.set(a.id,b),onSuccess:()=>this.lastTriggerErrors.delete(a.id)}));break;case"flow-event":this.armed.set(a.id,function(a,b){let c=a.maxChainDepth??5,d="string"==typeof a.source.topic?a.source.topic.trim():"",e=d.length>0,f=0,g=null,h=!1;if(a.outputMatch?.regex)try{g=new RegExp(a.outputMatch.regex)}catch(c){h=!0;let a=`Invalid output-match regex: ${c instanceof Error?c.message:String(c)}`;u.warn(a),b.onError(a)}let i=b=>{if(!a.outputMatch)return!0;if(h)return!1;let c=(b??"").slice(0,16384);return(!a.outputMatch.contains||!!c.includes(a.outputMatch.contains))&&(!g||!!g.test(c))},j=(d,e,g,h)=>{if(d>=c){let a=`Flow-event chain reached the depth limit (${c}); not firing again`;u.info(a),b.onSkip(a);return}let i=Date.now();if(a.minIntervalMs&&i-f<a.minIntervalMs)return void u.debug(`Flow-event cooldown active (${a.minIntervalMs}ms); ignoring event`);f=i,b.onFire({summary:e,context:g,chainDepth:d+1,sourceConversationId:h})},k=(0,t.eh)().subscribe(c=>{try{if(e){if(!(0,t.ru)(c)||c.topic!==d||!i(c.payload))return;j(c.chainDepth,`Signal "${c.topic}"`,{topic:c.topic,payload:v(c.payload),emitterFlowId:c.emitterFlowId,flowName:c.flowName,runId:c.runId,conversationId:c.conversationId,firedBy:c.firedBy},c.conversationId);return}if((0,t.ru)(c)||!(b=>{let c=a.source;return c.executionId?b.executionId===c.executionId:c.flowId?b.flowId===c.flowId:!!c.flowName&&b.flowName===c.flowName})(c)||!c.status||!(a.on??[]).includes(c.status)||!i(c.outputText))return;let b=c.flowName??c.flowId;j(c.chainDepth,`Flow "${b}" ${c.status}`,{flowId:c.flowId,flowName:c.flowName,executionId:c.executionId,runId:c.runId,conversationId:c.conversationId,status:c.status,firedBy:c.firedBy,outputText:v(c.outputText),error:c.error},c.conversationId)}catch(c){let a=c instanceof Error?c.message:String(c);u.warn(`Flow-event handling failed: ${a}`),b.onError(a)}});return{dispose:()=>k(),nextRun:()=>null}}(b,{onFire:({summary:b,context:c,chainDepth:d,sourceConversationId:e})=>{this.lastTriggerErrors.delete(a.id),this.fire(a,{kind:"flow-event",summary:b,context:c,chainDepth:d,parentConversationId:e}).catch(b=>C.error(`Flow-event fire failed for ${a.id}:`,b))},onSkip:b=>{let c=new Date().toISOString();(0,w.Hy)(a.id,{runId:(0,d.A)(),conversationId:"",firedAt:c,finishedAt:c,status:"skipped",triggerSummary:"Flow event",error:b}).catch(b=>C.warn(`Failed to record flow-event skip for ${a.id}:`,b))},onError:b=>this.lastTriggerErrors.set(a.id,b)}));break;default:C.warn(`Trigger type "${b.type}" is not implemented — "${a.name}" not armed`)}}async loadFile(){let a=await (0,e.loadItem)(f.Z.PLANNED_EXECUTIONS,D);return{version:1,paused:!0===a.paused,executions:Array.isArray(a.executions)?a.executions:[]}}async saveFile(a){await (0,e.VH)(f.Z.PLANNED_EXECUTIONS,a)}async isPaused(){return(await this.loadFile()).paused}async setPaused(a){let b=await this.loadFile();if(await this.saveFile({...b,paused:a}),await this.reconcile(),a){for(let a of[...this.queued.keys()])await this.cancelQueued(a,"scheduler paused",!0);await this.cancelAllExclusiveWaiting("scheduler paused",!0)}}async list(){return Promise.all((await this.loadFile()).executions.map(async a=>({execution:a,status:this.getStatus(a),lastRun:await (0,w.tl)(a.id)})))}async get(a){return(await this.loadFile()).executions.find(b=>b.id===a)??null}async create(a){let b=this.validateInput(a);if(b)return{error:b};if(void 0!==a.id&&!/^[A-Za-z0-9._:-]{1,128}$/.test(a.id))return{error:"The id must be 1-128 characters of letters, digits, dot, underscore, colon or hyphen"};if("."===a.id||".."===a.id)return{error:'The id must be a safe identifier, not "." or ".."'};let c=new Date().toISOString(),e={...a,folder:a.folder?.trim()||void 0,trigger:this.normalizeTrigger(a.trigger),id:a.id??(0,d.A)(),createdAt:c,updatedAt:c},f=await this.loadFile();return f.executions.some(a=>a.id===e.id)?{error:`A planned execution with id "${e.id}" already exists`,conflict:!0}:(await this.saveFile({...f,executions:[...f.executions,e]}),await this.reconcile(),{execution:e})}async update(a,b){let c=await this.loadFile(),d=c.executions.findIndex(b=>b.id===a);if(d<0)return{error:`No planned execution with id "${a}"`};let e=b.folder;if(Object.prototype.hasOwnProperty.call(b,"folder")&&void 0!==e&&"string"!=typeof e)return{error:"Folder must be text"};let f={...c.executions[d],...b,...Object.prototype.hasOwnProperty.call(b,"folder")?{folder:"string"==typeof e&&e.trim()||void 0}:{},...b.trigger?{trigger:this.normalizeTrigger(b.trigger)}:{},id:a,createdAt:c.executions[d].createdAt,updatedAt:new Date().toISOString()},g=this.validateInput(f);if(g)return{error:g};let h=[...c.executions];return h[d]=f,await this.saveFile({...c,executions:h}),Object.keys(b).some(a=>"folder"!==a)&&(await this.reconcile(),await this.cancelQueued(a,"execution updated",!0),await this.cancelExclusiveWaiting(a,"execution updated",!0)),{execution:f}}async delete(a){let b=await this.loadFile();return b.executions.some(b=>b.id===a)?(await this.saveFile({...b,executions:b.executions.filter(b=>b.id!==a)}),await this.reconcile(),this.lastTriggerErrors.delete(a),await this.cancelQueued(a,"execution deleted",!1),await this.cancelExclusiveWaiting(a,"execution deleted",!1),await (0,w.xC)(a),await B(a),{success:!0}):{success:!1,error:`No planned execution with id "${a}"`}}normalizeTrigger(a){return a?.type!=="webhook"||a.token?a?.type!=="mcp-poll"||a.cron?a:{...a,cron:(0,p.X)(a.intervalMs)}:{...a,token:(0,d.A)()}}validateInput(a){if(!a.name?.trim())return"A name is required";if(void 0!==a.folder&&"string"!=typeof a.folder)return"Folder must be text";if(a.folder&&a.folder.trim().length>120)return"Folder must be 120 characters or fewer";if(!a.flowId)return"A flow is required";if("string"!=typeof a.prompt)return"A prompt is required (may be empty)";if(void 0!==a.overlapStrategy&&!["skip","queue","parallel","error"].includes(a.overlapStrategy))return"Overlap strategy must be one of: skip, queue, parallel, error";if(void 0!==a.exclusive&&"boolean"!=typeof a.exclusive)return"Exclusive must be true or false";if(void 0!==a.nonExclusiveBehavior&&!["queue","skip","error"].includes(a.nonExclusiveBehavior))return"When exclusive is on, other triggers must be one of: queue, skip, error";let b=a.trigger;if(!b||"object"!=typeof b)return"A trigger is required";switch(b.type){case"schedule":{let a=(0,i.O9)(b.cron,b.timezone);return a.valid?null:`Invalid schedule: ${a.error}`}case"webhook":return null;case"file-watch":if(!b.path?.trim())return"A folder or file path to watch is required";if(!Array.isArray(b.events)||0===b.events.length)return"At least one file event is required";return null;case"mcp-poll":if(!b.serverName||!b.toolName)return"A server and tool are required";if(b.cron){let a=(0,i.O9)(b.cron,b.timezone);if(!a.valid)return`Invalid schedule: ${a.error}`}if(b.evaluate?.mode==="new-items"&&!b.evaluate.idField?.trim())return"An id field is required to detect new items";if((b.evaluate?.mode==="llm-gate"||b.evaluate?.mode==="flow-gate")&&!b.evaluate.condition?.trim())return"A condition is required for the AI to check";if(b.evaluate?.mode==="llm-gate"&&!b.evaluate.modelId)return"A model is required to check the condition";if(b.evaluate?.mode==="flow-gate"&&!b.evaluate.flowId)return"A flow is required to check the condition";return null;case"url-watch":{try{let a=new URL(b.url??"");if("http:"!==a.protocol&&"https:"!==a.protocol)return"The URL must start with http:// or https://"}catch{return"A valid URL is required"}let a=(0,i.O9)(b.cron,b.timezone);return a.valid?null:`Invalid schedule: ${a.error}`}case"flow-event":{let a=b.source;if(1!==[a?.executionId,a?.flowId,a?.flowName,a?.topic].filter(a=>"string"==typeof a&&a.trim().length>0).length)return"Choose exactly one source: a flow, a planned execution, or a signal topic";if(!("string"==typeof a?.topic&&a.topic.trim().length>0)){if(!Array.isArray(b.on)||0===b.on.length)return"Select at least one outcome to react to (completed or error)";if(b.on.some(a=>"completed"!==a&&"error"!==a))return'Outcomes must be "completed" or "error"'}if(b.outputMatch?.regex)try{new RegExp(b.outputMatch.regex)}catch(a){return`Invalid output-match regex: ${a instanceof Error?a.message:String(a)}`}if(void 0!==b.maxChainDepth&&(!Number.isInteger(b.maxChainDepth)||b.maxChainDepth<1))return"Max chain depth must be a positive whole number";if(void 0!==b.minIntervalMs&&(!Number.isFinite(b.minIntervalMs)||b.minIntervalMs<0))return"Minimum interval must be zero or more milliseconds";return null}default:return"Unknown trigger type"}}isRunning(a){let b=this.running.get(a);return void 0!==b&&b.size>0}addRunning(a,b,c){let d=this.running.get(a);d||(d=new Map,this.running.set(a,d)),d.set(b,c)}removeRunning(a,b){let c=this.running.get(a);c&&(c.delete(b),0===c.size&&this.running.delete(a))}earliestRunningSince(a){let b,c=this.running.get(a);if(c&&0!==c.size){for(let a of c.values())(void 0===b||a<b)&&(b=a);return b}}skippedRecord(a,b){let c=new Date().toISOString();return{runId:a.runId,conversationId:"",firedAt:c,finishedAt:c,status:"skipped",triggerSummary:a.payload.summary,error:b}}async cancelQueued(a,b,c){let d=this.queued.get(a);if(d&&0!==d.length){for(let e of(this.queued.delete(a),d)){let d=this.skippedRecord(e,b);if(c)try{await (0,w.Hy)(a,d)}catch(b){C.warn(`Failed to record cancelled queued fire for ${a}:`,b)}e.resolve(d)}C.info(`Cancelled ${d.length} queued fire(s) for ${a}: ${b}`)}}drainQueue(a){let b=this.queued.get(a);if(!b||0===b.length||this.isRunning(a))return;let c=b.shift();0===b.length&&this.queued.delete(a),c&&(async()=>{let b=await this.get(a);if(!b||!b.enabled||this.pausedCache){let a=b?b.enabled?"scheduler paused":"execution disabled":"execution deleted";c.resolve(this.skippedRecord(c,a));return}let d=await this.fire(b,c.payload,c.runId);c.resolve(d)})().catch(b=>C.error(`Queued fire failed for ${a}:`,b))}isSchedulerIdle(){for(let a of this.running.values())if(a.size>0)return!1;return!0}isExclusiveActive(){return null!==this.exclusiveHolder||this.exclusiveWaiting.length>0}currentExclusiveBehavior(){return null!==this.exclusiveHolder?this.exclusiveHolderBehavior:this.exclusiveWaiting[0]?.execution.nonExclusiveBehavior??"queue"}exclusiveGateFor(a){return!0!==a.exclusive&&this.isExclusiveActive()?this.currentExclusiveBehavior():null}drainExclusive(){if(null===this.exclusiveHolder&&this.exclusiveWaiting.length>0&&this.isSchedulerIdle())return void this.acquireNextExclusive();this.isExclusiveActive()||this.drainBlockedByExclusive()}acquireNextExclusive(){if(null!==this.exclusiveHolder||!this.isSchedulerIdle())return;let a=this.exclusiveWaiting.shift();if(!a)return;let b=a.execution.id;this.exclusiveHolder=b,this.exclusiveHolderBehavior=a.execution.nonExclusiveBehavior??"queue",(async()=>{let c=await this.get(b);if(!c||!c.enabled||this.pausedCache||!0!==c.exclusive){let d=c?c.enabled?this.pausedCache?"scheduler paused":"no longer exclusive":"execution disabled":"execution deleted";this.exclusiveHolder===b&&(this.exclusiveHolder=null),a.resolve(this.skippedRecord(a,d)),this.drainExclusive();return}this.exclusiveHolderBehavior=c.nonExclusiveBehavior??"queue";let d=await this.fire(c,a.payload,a.runId);a.resolve(d)})().catch(c=>{this.exclusiveHolder===b&&(this.exclusiveHolder=null),C.error(`Exclusive acquire failed for ${b}:`,c),a.resolve(this.skippedRecord(a,"exclusive acquire failed")),this.drainExclusive()})}drainBlockedByExclusive(){if(0===this.blockedByExclusive.length)return;let a=this.blockedByExclusive;for(let b of(this.blockedByExclusive=[],a))(async()=>{let a=await this.get(b.execution.id);if(!a||!a.enabled||this.pausedCache){let c=a?a.enabled?"scheduler paused":"execution disabled":"execution deleted";b.resolve(this.skippedRecord(b,c));return}let c=await this.fire(a,b.payload,b.runId);b.resolve(c)})().catch(a=>C.error(`Deferred non-exclusive fire failed for ${b.execution.id}:`,a))}async cancelExclusiveWaiting(a,b,c){let d=[];if(this.exclusiveWaiting=this.exclusiveWaiting.filter(b=>b.execution.id!==a||(d.push(b),!1)),this.blockedByExclusive=this.blockedByExclusive.filter(b=>b.execution.id!==a||(d.push(b),!1)),0!==d.length){for(let e of d){let d=this.skippedRecord(e,b);if(c)try{await (0,w.Hy)(a,d)}catch(b){C.warn(`Failed to record cancelled exclusive fire for ${a}:`,b)}e.resolve(d)}C.info(`Cancelled ${d.length} exclusive-related fire(s) for ${a}: ${b}`)}}async cancelAllExclusiveWaiting(a,b){let c=[...this.exclusiveWaiting,...this.blockedByExclusive];if(this.exclusiveWaiting=[],this.blockedByExclusive=[],0!==c.length){for(let d of c){let c=this.skippedRecord(d,a);if(b)try{await (0,w.Hy)(d.execution.id,c)}catch(a){C.warn(`Failed to record cancelled exclusive fire for ${d.execution.id}:`,a)}d.resolve(c)}C.info(`Cancelled ${c.length} exclusive-related fire(s): ${a}`)}}getStatus(a){let b=this.armed.get(a.id),c=void 0!==b||a.enabled&&"webhook"===a.trigger.type&&this.started&&!this.pausedCache,d=this.earliestRunningSince(a.id),e=c?void 0:a.enabled?this.pausedCache?"paused":void 0:"disabled",f=this.exclusiveHolder??void 0,g=!0!==a.exclusive&&this.isExclusiveActive();return{armed:c,notArmedReason:e,nextRun:b?.nextRun?b.nextRun():void 0,lastTriggerError:this.lastTriggerErrors.get(a.id),running:void 0!==d,runningSince:d,exclusiveHolderId:f,blockedByExclusive:g}}async runNow(a){let b=await this.get(a);return b?{record:await this.fire(b,{kind:"manual",summary:"Manual run"},(0,d.A)(),!0)}:{error:`No planned execution with id "${a}"`}}async fire(a,b,e=(0,d.A)(),f=!1){let g,i=new Date().toISOString();if(await (0,h.isEncryptionLocked)()){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:"encryption locked"};return await (0,w.Hy)(a.id,c),C.info(`Skipped fire for "${a.name}" — encryption locked`),c}let j="flow-event"===b.kind;if(!f&&!j){if(!0===a.exclusive){if(this.exclusiveHolder!==a.id){if(null!==this.exclusiveHolder||!this.isSchedulerIdle()){let c=this.exclusiveWaiting.length;if(c>=E.MAX_QUEUE_DEPTH){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:`Exclusive wait queue full (cap ${E.MAX_QUEUE_DEPTH}) — fire dropped`};return await (0,w.Hy)(a.id,c),C.warn(`Exclusive wait queue full for "${a.name}" — dropped fire`),c}return C.info(`Exclusive "${a.name}" waiting for scheduler to idle (depth ${c+1})`),new Promise(c=>{this.exclusiveWaiting.push({execution:a,payload:b,runId:e,resolve:c})})}this.exclusiveHolder=a.id,this.exclusiveHolderBehavior=a.nonExclusiveBehavior??"queue",C.info(`Exclusive "${a.name}" acquired the scheduler lock`)}}else if(this.isExclusiveActive()){let c=this.currentExclusiveBehavior();if("skip"===c){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:"Skipped — an exclusive execution holds the scheduler lock"};return await (0,w.Hy)(a.id,c),C.info(`Skipped non-exclusive fire for "${a.name}" — exclusive lock held`),c}if("error"===c){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"error",triggerSummary:b.summary,error:"Rejected — an exclusive execution holds the scheduler lock"};return await (0,w.Hy)(a.id,c),C.info(`Rejected non-exclusive fire for "${a.name}" — exclusive lock held`),c}let d=this.blockedByExclusive.length;if(d>=E.MAX_QUEUE_DEPTH){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:`Exclusive-block queue full (cap ${E.MAX_QUEUE_DEPTH}) — fire dropped`};return await (0,w.Hy)(a.id,c),C.warn(`Exclusive-block queue full for "${a.name}" — dropped fire`),c}return C.info(`Deferred non-exclusive fire for "${a.name}" — exclusive lock held (depth ${d+1})`),new Promise(c=>{this.blockedByExclusive.push({execution:a,payload:b,runId:e,resolve:c})})}}let k=a.overlapStrategy??"skip";if(!f&&this.isRunning(a.id)){if("skip"===k){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:"Previous run still in progress"};return await (0,w.Hy)(a.id,c),C.info(`Skipped overlapping fire for "${a.name}"`),c}if("error"===k){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"error",triggerSummary:b.summary,error:"Overlapping run rejected (overlapStrategy=error)"};return await (0,w.Hy)(a.id,c),C.info(`Rejected overlapping fire for "${a.name}" (overlapStrategy=error)`),c}if("queue"===k){let c=this.queued.get(a.id)?.length??0;if(c>=E.MAX_QUEUE_DEPTH){let c={runId:e,conversationId:"",firedAt:i,finishedAt:i,status:"skipped",triggerSummary:b.summary,error:`Overlap queue full (cap ${E.MAX_QUEUE_DEPTH}) — fire dropped`};return await (0,w.Hy)(a.id,c),C.warn(`Overlap queue full for "${a.name}" — dropped fire`),c}return C.info(`Queued overlapping fire for "${a.name}" (depth ${c+1})`),new Promise(c=>{let d=this.queued.get(a.id)??[];d.push({execution:a,payload:b,runId:e,resolve:c}),this.queued.set(a.id,d)})}}this.addRunning(a.id,e,i);let l=(0,d.A)();try{C.info(`Firing "${a.name}" (${b.kind})`);let d=await (0,w.Sw)(a.id),f=d.length>0?d[d.length-1]:null,h={executionName:a.name,trigger:b.kind,now:i,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,lastRun:f?{at:f.firedAt,status:f.status}:null,nextPlannedRun:this.getStatus(a).nextRun??null},j=a.approvalPolicy??"auto",k=a.saveConversations||"pause"===j?"conversation":"ephemeral",{runFlow:m}=await Promise.all([c.e(3128),c.e(4322),c.e(5067),c.e(6034),c.e(7821),c.e(5096),c.e(544),c.e(4671),c.e(6226),c.e(4306)]).then(c.bind(c,16226)),n=await m({flowId:a.flowId,prompt:this.composePrompt(a.prompt,b,h),mode:k,conversationId:l,source:"schedule",plannedExecutionId:a.id,parentRunId:b.parentConversationId,chainDepth:b.chainDepth??0,requireApproval:"auto"!==j,onApprovalRequired:j,debug:!1,userTurn:!0});g=await this.recordFromResult(a,n,{runId:e,conversationId:l,firedAt:i,payload:b})}catch(c){g={runId:e,conversationId:l,firedAt:i,finishedAt:new Date().toISOString(),status:"error",triggerSummary:b.summary,error:c instanceof Error?c.message:String(c)},C.error(`Run crashed for "${a.name}":`,c)}finally{this.removeRunning(a.id,e),this.exclusiveHolder!==a.id||this.isRunning(a.id)||(this.exclusiveHolder=null,C.info(`Exclusive "${a.name}" released the scheduler lock`)),this.drainExclusive(),this.drainQueue(a.id)}return await this.get(a.id)===null?C.info(`Dropping run record for deleted execution ${a.id}`):(await (0,w.Hy)(a.id,g),("completed"===g.status||"error"===g.status)&&await this.publishFlowRunEvent(a,g,b)),g}async recordFromResult(a,b,c){let{runId:d,conversationId:e,firedAt:f,payload:g}=c,h=new Date().toISOString(),i="awaiting_tool_approval"===b.status,j="error"===b.status&&b.error?.details?.type==="approval_required";if(i||j){let c=(b.pendingToolCalls??[]).map(a=>({id:a.id,name:"function"===a.type?a.function.name:String(a.type)})),k={runId:d,conversationId:e,firedAt:f,finishedAt:h,status:"needs_approval",triggerSummary:g.summary,outputText:this.truncateOutput(b.outputText),usage:b.usage,error:j?b.error?.message??"Tool approval required":"Awaiting tool approval",pendingApproval:{tool:c[0]?.name??b.error?.details?.name,toolCallId:c[0]?.id,pendingToolCalls:c.length>0?c:void 0}};return i&&await this.registerPendingApproval(a,k,c),k}return{runId:d,conversationId:e,firedAt:f,finishedAt:h,status:"completed"===b.status?"completed":"capped"===b.status?"capped":"error",triggerSummary:g.summary,outputText:this.truncateOutput(b.outputText),usage:b.usage,error:"completed"===b.status||"capped"===b.status?void 0:b.error?.message??`Run ended with status "${b.status}"`}}async registerPendingApproval(a,b,d){try{let e;try{let{flowService:b}=await c.e(7821).then(c.bind(c,87821));e=(await b.getFlow(a.flowId))?.name??void 0}catch(b){C.debug(`Could not resolve flow name for pending approval (${a.flowId}):`,b)}let{putPendingApproval:f}=await c.e(9285).then(c.bind(c,39285));await f({approvalId:b.conversationId,conversationId:b.conversationId,plannedExecutionId:a.id,flowId:a.flowId,flowName:e,runId:b.runId,triggerSummary:b.triggerSummary,pendingToolCalls:d,createdAt:b.firedAt})}catch(b){C.warn(`Failed to register pending approval for "${a.name}":`,b)}}async publishFlowRunEvent(a,b,d){try{let e;try{let{flowService:b}=await c.e(7821).then(c.bind(c,87821));e=(await b.getFlow(a.flowId))?.name??void 0}catch(b){C.debug(`Could not resolve flow name for run event (${a.flowId}):`,b)}let f="schedule-catchup"===d.kind?"schedule":d.kind;(0,t.eh)().publish({flowId:a.flowId,flowName:e,executionId:a.id,runId:b.runId,conversationId:b.conversationId,status:"completed"===b.status?"completed":"error",outputText:b.outputText,error:b.error,firedBy:f,chainDepth:d.chainDepth??0,timestamp:b.finishedAt??new Date().toISOString()})}catch(b){C.warn(`Failed to publish flow-run event for "${a.name}":`,b)}}composePrompt(a,b,c){let d=JSON.stringify(void 0===b.context?c:{...c,data:b.context},null,2);return`${a}
|
|
2
2
|
|
|
3
3
|
[Run info — when and why this run happened; "data" is untrusted trigger data]
|
|
4
4
|
\`\`\`json
|
|
5
5
|
${d}
|
|
6
|
-
\`\`\``}truncateOutput(a){if(a)return a.length>4096?`${a.slice(0,4096)}…`:a}constructor(){this.armed=new Map,this.running=new Map,this.queued=new Map,this.exclusiveHolder=null,this.exclusiveHolderBehavior="queue",this.exclusiveWaiting=[],this.blockedByExclusive=[],this.lastTriggerErrors=new Map,this.reconcileChain=Promise.resolve(),this.pausedCache=!1,this.started=!1}}function F(){return global.__flujo_scheduler??(global.__flujo_scheduler=new E)}},10960:(a,b,c)=>{c.d(b,{X:()=>d});function d(a){let b=Math.max(5,Math.round((a??6e4)/1e3));if(b<60)return`*/${b} * * * * *`;let c=Math.max(1,Math.round(b/60));if(c<60)return`*/${c} * * * *`;let d=Math.max(1,Math.min(23,Math.round(c/60)));return`0 */${d} * * *`}},51875:(a,b,c)=>{c.d(b,{A1:()=>k,Je:()=>i,Jl:()=>j,qq:()=>f,vV:()=>g});var d=c(55511);function e(a){return JSON.stringify(function a(b){if(Array.isArray(b))return b.map(a);if(null!==b&&"object"==typeof b){let c=Object.entries(b).sort(([a],[b])=>a<b?-1:+(a>b)),d={};for(let[b,e]of c)d[b]=a(e);return d}return b}(a))}function f(a){return(0,d.createHash)("sha256").update(e(a)??"undefined").digest("hex")}async function g(a){let{status:b,pendingState:c,priorFailures:d,saveState:e}=a;if("completed"===b)return await e({...c,...d>0?{pendingFailures:0}:{}}),{giveUpError:null};if("skipped"===b)return{giveUpError:null};let f=d+1;return f>=3?(await e({...c,pendingFailures:0}),{giveUpError:`Detected a change but the flow failed to process it 3\xd7 — skipping it to avoid a loop`}):(await e({pendingFailures:f}),{giveUpError:null})}function h(a,b){if(!b)return a;let c=a;for(let a of b.split(".")){if(null==c||"object"!=typeof c)return;c=c[a]}return c}function i(a){let b=e(a)??"";return b.length<=8192?a:{truncated:!0,note:`Result too large to include fully (${b.length} chars); this is a preview.`,preview:b.slice(0,8192)}}function j(a,b){let c=f(a);return b.lastHash?b.lastHash===c?{fire:!1,newState:{}}:{fire:!0,summary:"Tool result changed",context:{result:i(a)},newState:{},pendingState:{lastHash:c}}:{fire:!1,newState:{lastHash:c}}}function k(a,b,c,d){let e=h(a,b);if(!Array.isArray(e))return{fire:!1,newState:{},error:`"${b||"(root)"}" did not resolve to a list in the tool result`};let g=e.map(a=>{let b=h(a,c);return{id:null==b||"object"==typeof b?`hash:${f(a)}`:String(b),item:a}}),j=d.seenIds,k=g.map(({id:a})=>a),l=(a,b)=>{let c=[...a??[]],d=new Set(c);for(let a of b)d.has(a)||(d.add(a),c.push(a));return c.slice(-1e3)};if(!j)return{fire:!1,newState:{seenIds:l(void 0,k)}};let m=new Set(j),n=g.filter(({id:a})=>!m.has(a));if(0===n.length)return{fire:!1,newState:{}};let o=n.slice(0,50);return{fire:!0,summary:1===n.length?"1 new item":`${n.length} new items`,context:{newItems:i(o.map(({item:a})=>a)),...n.length>50?{omitted:n.length-50}:{}},newState:{},pendingState:{seenIds:l(j,o.map(({id:a})=>a))}}}},52189:(a,b,c)=>{c.d(b,{O9:()=>e,Z9:()=>f,hk:()=>g,wv:()=>h});var d=c(73736);function e(a,b){try{let c=new d.l4(a,{timezone:b,paused:!0});return c.nextRun(),c.stop(),{valid:!0}}catch(a){return{valid:!1,error:a instanceof Error?a.message:"Invalid cron pattern"}}}function f(a,b,c){let e=new d.l4(a,{timezone:b,paused:!0});try{return e.nextRuns(c).map(a=>a.toISOString())}finally{e.stop()}}function g(a,b){let c=new d.l4(a.cron,{timezone:a.timezone,paused:!0});try{let a=c.nextRun(new Date(b));return null!==a&&a.getTime()<=Date.now()}finally{c.stop()}}function h(a,b){let c=new d.l4(a.cron,{timezone:a.timezone,unref:!0},b);return{dispose:()=>c.stop(),nextRun:()=>c.nextRun()?.toISOString()??null}}},59911:(a,b,c)=>{c.d(b,{Hy:()=>i,Sw:()=>h,s1:()=>j,tl:()=>k,xC:()=>l});var d=c(92372);let e=(0,c(50846).h)("backend/services/scheduler/runHistory"),f=a=>`planned-execution-runs/${a}`,g=new Map;async function h(a){try{return await (0,d.
|
|
6
|
+
\`\`\``}truncateOutput(a){if(a)return a.length>4096?`${a.slice(0,4096)}…`:a}constructor(){this.armed=new Map,this.running=new Map,this.queued=new Map,this.exclusiveHolder=null,this.exclusiveHolderBehavior="queue",this.exclusiveWaiting=[],this.blockedByExclusive=[],this.lastTriggerErrors=new Map,this.reconcileChain=Promise.resolve(),this.pausedCache=!1,this.started=!1}}function F(){return global.__flujo_scheduler??(global.__flujo_scheduler=new E)}},10960:(a,b,c)=>{c.d(b,{X:()=>d});function d(a){let b=Math.max(5,Math.round((a??6e4)/1e3));if(b<60)return`*/${b} * * * * *`;let c=Math.max(1,Math.round(b/60));if(c<60)return`*/${c} * * * *`;let d=Math.max(1,Math.min(23,Math.round(c/60)));return`0 */${d} * * *`}},51875:(a,b,c)=>{c.d(b,{A1:()=>k,Je:()=>i,Jl:()=>j,qq:()=>f,vV:()=>g});var d=c(55511);function e(a){return JSON.stringify(function a(b){if(Array.isArray(b))return b.map(a);if(null!==b&&"object"==typeof b){let c=Object.entries(b).sort(([a],[b])=>a<b?-1:+(a>b)),d={};for(let[b,e]of c)d[b]=a(e);return d}return b}(a))}function f(a){return(0,d.createHash)("sha256").update(e(a)??"undefined").digest("hex")}async function g(a){let{status:b,pendingState:c,priorFailures:d,saveState:e}=a;if("completed"===b)return await e({...c,...d>0?{pendingFailures:0}:{}}),{giveUpError:null};if("skipped"===b)return{giveUpError:null};let f=d+1;return f>=3?(await e({...c,pendingFailures:0}),{giveUpError:`Detected a change but the flow failed to process it 3\xd7 — skipping it to avoid a loop`}):(await e({pendingFailures:f}),{giveUpError:null})}function h(a,b){if(!b)return a;let c=a;for(let a of b.split(".")){if(null==c||"object"!=typeof c)return;c=c[a]}return c}function i(a){let b=e(a)??"";return b.length<=8192?a:{truncated:!0,note:`Result too large to include fully (${b.length} chars); this is a preview.`,preview:b.slice(0,8192)}}function j(a,b){let c=f(a);return b.lastHash?b.lastHash===c?{fire:!1,newState:{}}:{fire:!0,summary:"Tool result changed",context:{result:i(a)},newState:{},pendingState:{lastHash:c}}:{fire:!1,newState:{lastHash:c}}}function k(a,b,c,d){let e=h(a,b);if(!Array.isArray(e))return{fire:!1,newState:{},error:`"${b||"(root)"}" did not resolve to a list in the tool result`};let g=e.map(a=>{let b=h(a,c);return{id:null==b||"object"==typeof b?`hash:${f(a)}`:String(b),item:a}}),j=d.seenIds,k=g.map(({id:a})=>a),l=(a,b)=>{let c=[...a??[]],d=new Set(c);for(let a of b)d.has(a)||(d.add(a),c.push(a));return c.slice(-1e3)};if(!j)return{fire:!1,newState:{seenIds:l(void 0,k)}};let m=new Set(j),n=g.filter(({id:a})=>!m.has(a));if(0===n.length)return{fire:!1,newState:{}};let o=n.slice(0,50);return{fire:!0,summary:1===n.length?"1 new item":`${n.length} new items`,context:{newItems:i(o.map(({item:a})=>a)),...n.length>50?{omitted:n.length-50}:{}},newState:{},pendingState:{seenIds:l(j,o.map(({id:a})=>a))}}}},52189:(a,b,c)=>{c.d(b,{O9:()=>e,Z9:()=>f,hk:()=>g,wv:()=>h});var d=c(73736);function e(a,b){try{let c=new d.l4(a,{timezone:b,paused:!0});return c.nextRun(),c.stop(),{valid:!0}}catch(a){return{valid:!1,error:a instanceof Error?a.message:"Invalid cron pattern"}}}function f(a,b,c){let e=new d.l4(a,{timezone:b,paused:!0});try{return e.nextRuns(c).map(a=>a.toISOString())}finally{e.stop()}}function g(a,b){let c=new d.l4(a.cron,{timezone:a.timezone,paused:!0});try{let a=c.nextRun(new Date(b));return null!==a&&a.getTime()<=Date.now()}finally{c.stop()}}function h(a,b){let c=new d.l4(a.cron,{timezone:a.timezone,unref:!0},b);return{dispose:()=>c.stop(),nextRun:()=>c.nextRun()?.toISOString()??null}}},59911:(a,b,c)=>{c.d(b,{Hy:()=>i,Sw:()=>h,s1:()=>j,tl:()=>k,xC:()=>l});var d=c(92372);let e=(0,c(50846).h)("backend/services/scheduler/runHistory"),f=a=>`planned-execution-runs/${a}`,g=new Map;async function h(a){try{return await (0,d.loadItem)(f(a),[])}catch(b){return e.error(`Failed to load run history for ${a}:`,b),[]}}async function i(a,b){let c=(g.get(a)??Promise.resolve()).catch(()=>{}).then(async()=>{let c=await h(a);c.push(b);let e=c.slice(-100);await (0,d.VH)(f(a),e)});g.set(a,c);try{await c}finally{g.get(a)===c&&g.delete(a)}}async function j(a,b,c){let e=g.get(a)??Promise.resolve(),i=null,j=e.catch(()=>{}).then(async()=>{let e=await h(a),g=e.findIndex(a=>a.runId===b);if(g<0){i=null;return}e[g]={...e[g],...c,runId:b},i=e[g],await (0,d.VH)(f(a),e)});g.set(a,j);try{await j}finally{g.get(a)===j&&g.delete(a)}return i}async function k(a){let b=await h(a);return b.length>0?b[b.length-1]:null}async function l(a){await (0,d.N2)(f(a))}}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
exports.id=4822,exports.ids=[1925,3629,4306,4822,6793,9174],exports.modules={1925:(a,b,c)=>{"use strict";c.d(b,{Hm:()=>f,xc:()=>e});let d=["key","secret","token","password"],e=a=>d.some(b=>a.toLowerCase().includes(b)),f=a=>e(a)||"authorization"===a.trim().toLowerCase()},3676:(a,b,c)=>{"use strict";c.d(b,{Wj:()=>h,ln:()=>g});var d=c(10641),e=c(58739);let f="encryption_locked";async function g(){return(0,e.isEncryptionLocked)()}async function h(a){return await g()?a?.openai?d.NextResponse.json({error:{message:"Encryption is locked. Unlock FLUJO to continue.",type:f,code:f,param:null}},{status:423}):d.NextResponse.json({error:f},{status:423}):null}},41115:(a,b,c)=>{"use strict";c.d(b,{$:()=>h,v5:()=>g});var d=c(10641);let e=new Set(["localhost","127.0.0.1","::1"]);function f(a){let b=a.toLowerCase();return!!e.has(b)||(function(){let a=process.env.FLUJO_EXTRA_LOCAL_HOSTS;return a?a.split(",").map(a=>a.trim().toLowerCase()).filter(a=>a.length>0&&"."!==a):[]})().some(a=>a.startsWith(".")?b.endsWith(a):b===a)}function g(a,b){let c=function(a){if(!a)return null;let b=a.trim();if(b.startsWith("[")){let a=b.indexOf("]");return a>0?b.slice(1,a):null}return b.split(":")[0]||null}(a);if(!c||!f(c))return!1;if(b)try{if(!f(new URL(b).hostname))return!1}catch{return!1}return!0}function h(a){return g(a.headers.get("host"),a.headers.get("origin"))?null:d.NextResponse.json({error:"Forbidden: this endpoint only accepts local requests."},{status:403})}},42398:(a,b,c)=>{"use strict";c.d(b,{QE:()=>l,_u:()=>n,aZ:()=>k,qf:()=>o,v5:()=>h.v5,xK:()=>m,xV:()=>p});var d=c(50846),e=c(60453),f=c(3676),g=c(68780),h=c(41115);let i=(0,d.h)("backend/services/mcp/proxyForward"),j="FLUJO encryption is locked (encryption_locked). Unlock FLUJO to continue.";async function k(a){let b=await e.mcpService.loadServerConfigs();if(!Array.isArray(b))return i.warn("isServerExposed: failed to load server configs",{error:b.error}),!1;let c=b.find(b=>b.name===a);return!!c&&!c.disabled&&!0===c.exposeAsMcpServer}async function l(a){if(await (0,f.ln)())throw Error(j);let b=await e.mcpService.connectServer(a);if(!b.success)throw Error(`Failed to connect to MCP server '${a}': ${b.error}`);let c=await e.mcpService.listServerTools(a);if(c.error)throw Error(`Failed to list tools for '${a}': ${c.error}`);return{tools:c.tools??[]}}async function m(a,b,c){if(await (0,f.ln)())return{content:[{type:"text",text:j}],isError:!0};let d=await e.mcpService.connectServer(a);if(!d.success)return{content:[{type:"text",text:`Error connecting to '${a}': ${d.error}`}],isError:!0};let g=await e.mcpService.callTool(a,b,c,void 0,void 0,void 0,void 0,"model");return g.success?g.data:{content:[{type:"text",text:`Error: ${g.error??"Unknown error"}`}],isError:!0}}async function n(a){if(await (0,f.ln)())throw Error(j);let b=await e.mcpService.connectServer(a);if(!b.success)throw Error(`Failed to connect to MCP server '${a}': ${b.error}`);let c=await e.mcpService.listServerResources(a);if(c.error)throw Error(`Failed to list resources for '${a}': ${c.error}`);return{resources:c.resources??[]}}async function o(a){if(await (0,f.ln)())throw Error(j);let b=await e.mcpService.connectServer(a);if(!b.success)throw Error(`Failed to connect to MCP server '${a}': ${b.error}`);let c=await e.mcpService.listServerResourceTemplates(a);if(c.error)throw Error(`Failed to list resource templates for '${a}': ${c.error}`);return{resourceTemplates:c.resourceTemplates??[]}}async function p(a,b){if(await (0,f.ln)())throw Error(j);let c=await e.mcpService.connectServer(a);if(!c.success)throw Error(`Failed to connect to MCP server '${a}': ${c.error}`);let d=await e.mcpService.readResource(a,b);if(!d.success||!d.data)throw new g.Nh(g.O4.InvalidParams,`Resource not found: '${b}' on server '${a}': ${d.error??"unknown error"}`);return d.data}},56793:(a,b,c)=>{"use strict";c.d(b,{eh:()=>g,ru:()=>e});let d=(0,c(50846).h)("backend/services/scheduler/flowRunEventBus");function e(a){return"signal"===a.kind}class f{publish(a){if(0===this.listeners.size)return;let b=e(a)?`signal topic=${a.topic} emitter=${a.emitterFlowId}`:`flow=${a.flowId} status=${a.status}`;for(let c of(d.debug(`Publishing flow event: ${b} firedBy=${a.firedBy} depth=${a.chainDepth} listeners=${this.listeners.size}`),[...this.listeners]))try{c(a)}catch(a){d.warn("A flow-run event listener threw:",a)}}subscribe(a){return this.listeners.add(a),()=>{this.listeners.delete(a)}}get listenerCount(){return this.listeners.size}constructor(){this.listeners=new Set}}function g(){return global.__flujo_flow_run_event_bus||(global.__flujo_flow_run_event_bus=new f),global.__flujo_flow_run_event_bus}},73456:(a,b,c)=>{"use strict";c.d(b,{G:()=>m,V:()=>l,resolveGlobalVars:()=>k});var d=c(75879);c(68633);var e=c(50846),f=c(92372),g=c(38844),h=c(58739),i=c(51669);let j=(0,e.h)("backend/utils/resolveGlobalVars");async function k(a,b={}){j.debug("Entering resolveGlobalVars method");let c=!1!==b.resolveSecrets,d=await (0,f.
|
|
1
|
+
exports.id=4822,exports.ids=[1925,3629,4306,4822,6793,9174],exports.modules={1925:(a,b,c)=>{"use strict";c.d(b,{Hm:()=>f,xc:()=>e});let d=["key","secret","token","password"],e=a=>d.some(b=>a.toLowerCase().includes(b)),f=a=>e(a)||"authorization"===a.trim().toLowerCase()},3676:(a,b,c)=>{"use strict";c.d(b,{Wj:()=>h,ln:()=>g});var d=c(10641),e=c(58739);let f="encryption_locked";async function g(){return(0,e.isEncryptionLocked)()}async function h(a){return await g()?a?.openai?d.NextResponse.json({error:{message:"Encryption is locked. Unlock FLUJO to continue.",type:f,code:f,param:null}},{status:423}):d.NextResponse.json({error:f},{status:423}):null}},41115:(a,b,c)=>{"use strict";c.d(b,{$:()=>h,v5:()=>g});var d=c(10641);let e=new Set(["localhost","127.0.0.1","::1"]);function f(a){let b=a.toLowerCase();return!!e.has(b)||(function(){let a=process.env.FLUJO_EXTRA_LOCAL_HOSTS;return a?a.split(",").map(a=>a.trim().toLowerCase()).filter(a=>a.length>0&&"."!==a):[]})().some(a=>a.startsWith(".")?b.endsWith(a):b===a)}function g(a,b){let c=function(a){if(!a)return null;let b=a.trim();if(b.startsWith("[")){let a=b.indexOf("]");return a>0?b.slice(1,a):null}return b.split(":")[0]||null}(a);if(!c||!f(c))return!1;if(b)try{if(!f(new URL(b).hostname))return!1}catch{return!1}return!0}function h(a){return g(a.headers.get("host"),a.headers.get("origin"))?null:d.NextResponse.json({error:"Forbidden: this endpoint only accepts local requests."},{status:403})}},42398:(a,b,c)=>{"use strict";c.d(b,{QE:()=>l,_u:()=>n,aZ:()=>k,qf:()=>o,v5:()=>h.v5,xK:()=>m,xV:()=>p});var d=c(50846),e=c(60453),f=c(3676),g=c(68780),h=c(41115);let i=(0,d.h)("backend/services/mcp/proxyForward"),j="FLUJO encryption is locked (encryption_locked). Unlock FLUJO to continue.";async function k(a){let b=await e.mcpService.loadServerConfigs();if(!Array.isArray(b))return i.warn("isServerExposed: failed to load server configs",{error:b.error}),!1;let c=b.find(b=>b.name===a);return!!c&&!c.disabled&&!0===c.exposeAsMcpServer}async function l(a){if(await (0,f.ln)())throw Error(j);let b=await e.mcpService.connectServer(a);if(!b.success)throw Error(`Failed to connect to MCP server '${a}': ${b.error}`);let c=await e.mcpService.listServerTools(a);if(c.error)throw Error(`Failed to list tools for '${a}': ${c.error}`);return{tools:c.tools??[]}}async function m(a,b,c){if(await (0,f.ln)())return{content:[{type:"text",text:j}],isError:!0};let d=await e.mcpService.connectServer(a);if(!d.success)return{content:[{type:"text",text:`Error connecting to '${a}': ${d.error}`}],isError:!0};let g=await e.mcpService.callTool(a,b,c,void 0,void 0,void 0,void 0,"model");return g.success?g.data:{content:[{type:"text",text:`Error: ${g.error??"Unknown error"}`}],isError:!0}}async function n(a){if(await (0,f.ln)())throw Error(j);let b=await e.mcpService.connectServer(a);if(!b.success)throw Error(`Failed to connect to MCP server '${a}': ${b.error}`);let c=await e.mcpService.listServerResources(a);if(c.error)throw Error(`Failed to list resources for '${a}': ${c.error}`);return{resources:c.resources??[]}}async function o(a){if(await (0,f.ln)())throw Error(j);let b=await e.mcpService.connectServer(a);if(!b.success)throw Error(`Failed to connect to MCP server '${a}': ${b.error}`);let c=await e.mcpService.listServerResourceTemplates(a);if(c.error)throw Error(`Failed to list resource templates for '${a}': ${c.error}`);return{resourceTemplates:c.resourceTemplates??[]}}async function p(a,b){if(await (0,f.ln)())throw Error(j);let c=await e.mcpService.connectServer(a);if(!c.success)throw Error(`Failed to connect to MCP server '${a}': ${c.error}`);let d=await e.mcpService.readResource(a,b);if(!d.success||!d.data)throw new g.Nh(g.O4.InvalidParams,`Resource not found: '${b}' on server '${a}': ${d.error??"unknown error"}`);return d.data}},56793:(a,b,c)=>{"use strict";c.d(b,{eh:()=>g,ru:()=>e});let d=(0,c(50846).h)("backend/services/scheduler/flowRunEventBus");function e(a){return"signal"===a.kind}class f{publish(a){if(0===this.listeners.size)return;let b=e(a)?`signal topic=${a.topic} emitter=${a.emitterFlowId}`:`flow=${a.flowId} status=${a.status}`;for(let c of(d.debug(`Publishing flow event: ${b} firedBy=${a.firedBy} depth=${a.chainDepth} listeners=${this.listeners.size}`),[...this.listeners]))try{c(a)}catch(a){d.warn("A flow-run event listener threw:",a)}}subscribe(a){return this.listeners.add(a),()=>{this.listeners.delete(a)}}get listenerCount(){return this.listeners.size}constructor(){this.listeners=new Set}}function g(){return global.__flujo_flow_run_event_bus||(global.__flujo_flow_run_event_bus=new f),global.__flujo_flow_run_event_bus}},73456:(a,b,c)=>{"use strict";c.d(b,{G:()=>m,V:()=>l,resolveGlobalVars:()=>k});var d=c(75879);c(68633);var e=c(50846),f=c(92372),g=c(38844),h=c(58739),i=c(51669);let j=(0,e.h)("backend/utils/resolveGlobalVars");async function k(a,b={}){j.debug("Entering resolveGlobalVars method");let c=!1!==b.resolveSecrets,d=await (0,f.loadItem)(g.Z.GLOBAL_ENV_VARS,{}),e=function(a){if(!a||"object"!=typeof a)return!1;let b=Object.keys(a);if(0===b.length)return!0;let c=a[b[0]];return c&&"object"==typeof c&&"value"in c&&"metadata"in c&&"object"==typeof c.metadata&&"isSecret"in c.metadata}(d);j.debug(`Loaded ${Object.keys(d).length} global environment variables (${e?"new":"old"} format)`);let i={},l=new Set;if(e)for(let[a,b]of Object.entries(d))i[a]=b.value,b.metadata.isSecret&&l.add(a);else i={...d};let m=async a=>{let b=a.match(/\$\{global:([^}]+)\}/g);if(!b)return a;let d=a;for(let a of b){let b=a.substring(9,a.length-1);if(void 0!==i[b]){let e=i[b];if(!c&&(l.has(b)||e.startsWith("encrypted:")||e.startsWith("encrypted_failed:"))){j.debug(`Keeping secret global variable unresolved: ${b}`);continue}if(e.startsWith("encrypted:")){j.debug(`Decrypting encrypted global variable: ${b}`);try{let a=e.substring(10),c=await (0,h.decryptWithPassword)(a);if(c)e=c,j.debug(`Successfully decrypted global variable: ${b}`);else{j.warn(`Failed to decrypt global variable: ${b}`);continue}}catch(a){j.error(`Error decrypting global variable: ${b}`,a);continue}}else if(e.startsWith("encrypted_failed:")){j.warn(`Skipping failed encrypted global variable: ${b}`);continue}j.debug(`Resolved global variable: ${b}`),d=d.replace(a,e)}else j.warn(`Global variable not found: ${b}`)}return d},n=async a=>{if("string"==typeof a)return await m(a);if(Array.isArray(a))return await Promise.all(a.map(a=>n(a)));if(null!==a&&"object"==typeof a){let b={};for(let[c,d]of Object.entries(a))b[c]=await n(d);return b}return a},o=await n(a);return"object"==typeof a&&null!==a&&j.debug("Resolved global variables result:",JSON.stringify(o,null,2)),j.debug("Completed global variable resolution"),o}async function l(a){return k(a,{resolveSecrets:!1})}async function m(a,b=0){if(j.debug(`Entering resolveAndDecryptApiKey method (depth: ${b})`),!a)return j.warn("Empty value provided"),null;if(b>=10)return j.warn(`Maximum resolution depth reached (10) for value: ${a}`),a;let c=a;if(c.startsWith("encrypted:")){j.debug(`Decrypting encrypted value at depth ${b}`);try{let a=c.substring(10),d=await (0,h.decryptWithPassword)(a);if(!d)return j.warn(`Failed to decrypt value at depth ${b}`),null;j.debug(`Successfully decrypted value at depth ${b}`),j.verbose(d),c=d}catch(a){return j.error(`Error decrypting value at depth ${b}:`,a),null}}else c.startsWith("encrypted_failed:")&&(j.warn(`Skipping failed encrypted value at depth ${b}`),c=c.substring(17));if(c.includes("${global:")){j.debug(`Resolving global variables at depth ${b}`);try{let a=await k(c);if(j.verbose(a),a!==c)return j.debug(`Value changed after resolving globals at depth ${b}, processing recursively`),m(a,b+1);c=a}catch(a){return j.error(`Error resolving global variables at depth ${b}:`,a),null}}return j.debug(`Completed resolveAndDecryptApiKey at depth ${b}`),c}(0,i.D)([k,l,m]),(0,d.A)(k,"605caa1e030009a4bc7e820854ff481d3e0295325d",null),(0,d.A)(l,"4003ce37366709f5add0c98a6e32e47a1006fd7c7d",null),(0,d.A)(m,"6061ed6d99a98b5d9f5d2d15065caab0a27d6a8987",null)},78335:()=>{},91959:(a,b,c)=>{"use strict";c.r(b),c.d(b,{"4003ce37366709f5add0c98a6e32e47a1006fd7c7d":()=>d.V,"605caa1e030009a4bc7e820854ff481d3e0295325d":()=>d.resolveGlobalVars,"6061ed6d99a98b5d9f5d2d15065caab0a27d6a8987":()=>d.G});var d=c(73456)},96487:()=>{}};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";exports.id=5096,exports.ids=[1805,5096],exports.modules={25096:(a,b,c)=>{c.d(b,{C:()=>i});var d=c(50846),e=c(74186),f=c(73456);let g=(0,d.h)("backend/services/mcp/oauth");class h{constructor(a,b){this.config=a,this._redirectUrl=b,this._clientMetadata={redirect_uris:[b],client_name:`FLUJO MCP Client - ${a.name}`,client_uri:"https://github.com/mario-andreschak/FLUJO",grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"client_secret_post",scope:a.oauthScopes?.join(" ")||"read"},g.info(`Created OAuth client provider for ${a.name}`),g.verbose("OAuth client metadata",JSON.stringify(this._clientMetadata))}get redirectUrl(){return this._redirectUrl}get clientMetadata(){return this._clientMetadata}state(){return encodeURIComponent(JSON.stringify({serverName:this.config.name}))}async clientInformation(){if(this.config.oauthClientInformation)return g.debug(`Returning stored client information for ${this.config.name}`),this.config.oauthClientInformation;if(this.config.oauthClientId){let a=this.config.oauthClientSecret?await (0,f.G)(this.config.oauthClientSecret)??void 0:void 0;return g.debug(`Created client information from config for ${this.config.name}`),{client_id:this.config.oauthClientId,client_secret:a}}g.debug(`No client information available for ${this.config.name}`)}async persist(){let a=await (0,e.loadServerConfigs)();if(!Array.isArray(a))return void g.warn(`persist: failed to load server configs for ${this.config.name}, cannot persist OAuth state`);let b=new Map(a.map(a=>[a.name,a]));b.set(this.config.name,this.config);let c=await (0,e.q)(b);c.success||g.warn(`persist: failed to save OAuth state for ${this.config.name}: ${c.error}`)}async invalidateCredentials(a){g.info(`Invalidating OAuth credentials for ${this.config.name} (scope: ${a})`),("all"===a||"tokens"===a)&&(this.config.oauthTokens=void 0),("all"===a||"client"===a)&&(this.config.oauthClientInformation=void 0,this.config.oauthClientMetadata=void 0),("all"===a||"verifier"===a)&&(this.config.oauthCodeVerifier=void 0),await this.persist()}async saveClientInformation(a){g.info(`Saving client information for ${this.config.name}`),g.verbose("Client information to save",JSON.stringify(a)),this.config.oauthClientInformation={client_id:a.client_id,client_secret:a.client_secret,client_id_issued_at:a.client_id_issued_at,client_secret_expires_at:a.client_secret_expires_at},this.config.oauthClientMetadata={redirect_uris:a.redirect_uris,client_name:a.client_name,client_uri:a.client_uri,grant_types:a.grant_types,response_types:a.response_types,token_endpoint_auth_method:a.token_endpoint_auth_method,scope:a.scope,contacts:a.contacts,tos_uri:a.tos_uri,policy_uri:a.policy_uri,jwks_uri:a.jwks_uri,jwks:a.jwks,software_id:a.software_id,software_version:a.software_version},await this.persist(),g.info(`Client information saved for ${this.config.name}`)}async tokens(){if(this.config.oauthTokens){if(g.debug(`Returning stored tokens for ${this.config.name}`),this.config.oauthTokens.expires_in&&this.config.oauthTokens.issued_at){let a=this.config.oauthTokens.issued_at,b=this.config.oauthTokens.expires_in,c=Math.floor(Date.now()/1e3),d=a+b;c>=d?g.info(`Access token for ${this.config.name} has expired (issued: ${a}, expires: ${d}, current: ${c}); SDK will refresh via refresh_token`):g.debug(`Tokens for ${this.config.name} are valid (expires in ${d-c} seconds)`)}return this.config.oauthTokens}g.debug(`No tokens available for ${this.config.name}`)}async saveTokens(a){g.info(`Saving OAuth tokens for ${this.config.name}`),g.verbose("Tokens to save",JSON.stringify({...a,access_token:a.access_token?"[REDACTED]":void 0,refresh_token:a.refresh_token?"[REDACTED]":void 0}));let b={...a,issued_at:Math.floor(Date.now()/1e3)};this.config.oauthTokens=b,await this.persist(),g.info(`OAuth tokens saved for ${this.config.name}`)}async redirectToAuthorization(a){g.info(`Authorization required for ${this.config.name}`),g.info(`Authorization URL: ${a.toString()}`),this.config.authorizationUrl=a.toString();let b=Error(`OAuth authentication required for ${this.config.name}. Please complete the OAuth flow.`);throw b.name="OAuthAuthenticationRequired",b}async saveCodeVerifier(a){g.debug(`Saving code verifier for ${this.config.name}`),this.config.oauthCodeVerifier=a,await this.persist(),g.debug(`Code verifier saved for ${this.config.name}`)}async codeVerifier(){if(!this.config.oauthCodeVerifier){let a=`No code verifier found for ${this.config.name}`;throw g.error(a),Error(a)}return g.debug(`Returning code verifier for ${this.config.name}`),this.config.oauthCodeVerifier}}function i(a,b="http://localhost:4200/api/oauth/callback"){return new h(a,b)}},74186:(a,b,c)=>{c.d(b,{loadServerConfigs:()=>q,q:()=>r});var d=c(33873),e=c.n(d),f=c(34322),g=c(92372),h=c(38844),i=c(50846),j=c(43326);let k=(0,i.h)("backend/services/mcp/config"),l=new Set(["streamable","sse","websocket"]),m=e().join((0,j.getDataDir)(),"mcp-servers"),n=new Map;async function o(a){if(n.has(a))return n.get(a);let b=null;try{let c=(0,f.Ay)({baseDir:a,timeout:{block:5e3}});b=(await c.remote(["get-url","origin"])||"").trim()||null}catch{b=null}return n.set(a,b),b}async function p(a){var b;if(l.has(a.transport))return{type:"remote"};let c="string"!=typeof(b=a.rootPath)||""===b.trim()?null:e().isAbsolute(b)?b:e().resolve((0,j.getDataDir)(),b);if(c&&function(a){let b=e().relative(m,a);return""!==b&&!b.startsWith("..")&&!e().isAbsolute(b)}(c)){let a=await o(c);if(a)return{type:"github",repositoryUrl:a}}return{type:"local"}}async function q(){k.debug("Entering loadServerConfigs method");try{let a=await (0,g.
|
|
1
|
+
"use strict";exports.id=5096,exports.ids=[1805,5096],exports.modules={25096:(a,b,c)=>{c.d(b,{C:()=>i});var d=c(50846),e=c(74186),f=c(73456);let g=(0,d.h)("backend/services/mcp/oauth");class h{constructor(a,b){this.config=a,this._redirectUrl=b,this._clientMetadata={redirect_uris:[b],client_name:`FLUJO MCP Client - ${a.name}`,client_uri:"https://github.com/mario-andreschak/FLUJO",grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"client_secret_post",scope:a.oauthScopes?.join(" ")||"read"},g.info(`Created OAuth client provider for ${a.name}`),g.verbose("OAuth client metadata",JSON.stringify(this._clientMetadata))}get redirectUrl(){return this._redirectUrl}get clientMetadata(){return this._clientMetadata}state(){return encodeURIComponent(JSON.stringify({serverName:this.config.name}))}async clientInformation(){if(this.config.oauthClientInformation)return g.debug(`Returning stored client information for ${this.config.name}`),this.config.oauthClientInformation;if(this.config.oauthClientId){let a=this.config.oauthClientSecret?await (0,f.G)(this.config.oauthClientSecret)??void 0:void 0;return g.debug(`Created client information from config for ${this.config.name}`),{client_id:this.config.oauthClientId,client_secret:a}}g.debug(`No client information available for ${this.config.name}`)}async persist(){let a=await (0,e.loadServerConfigs)();if(!Array.isArray(a))return void g.warn(`persist: failed to load server configs for ${this.config.name}, cannot persist OAuth state`);let b=new Map(a.map(a=>[a.name,a]));b.set(this.config.name,this.config);let c=await (0,e.q)(b);c.success||g.warn(`persist: failed to save OAuth state for ${this.config.name}: ${c.error}`)}async invalidateCredentials(a){g.info(`Invalidating OAuth credentials for ${this.config.name} (scope: ${a})`),("all"===a||"tokens"===a)&&(this.config.oauthTokens=void 0),("all"===a||"client"===a)&&(this.config.oauthClientInformation=void 0,this.config.oauthClientMetadata=void 0),("all"===a||"verifier"===a)&&(this.config.oauthCodeVerifier=void 0),await this.persist()}async saveClientInformation(a){g.info(`Saving client information for ${this.config.name}`),g.verbose("Client information to save",JSON.stringify(a)),this.config.oauthClientInformation={client_id:a.client_id,client_secret:a.client_secret,client_id_issued_at:a.client_id_issued_at,client_secret_expires_at:a.client_secret_expires_at},this.config.oauthClientMetadata={redirect_uris:a.redirect_uris,client_name:a.client_name,client_uri:a.client_uri,grant_types:a.grant_types,response_types:a.response_types,token_endpoint_auth_method:a.token_endpoint_auth_method,scope:a.scope,contacts:a.contacts,tos_uri:a.tos_uri,policy_uri:a.policy_uri,jwks_uri:a.jwks_uri,jwks:a.jwks,software_id:a.software_id,software_version:a.software_version},await this.persist(),g.info(`Client information saved for ${this.config.name}`)}async tokens(){if(this.config.oauthTokens){if(g.debug(`Returning stored tokens for ${this.config.name}`),this.config.oauthTokens.expires_in&&this.config.oauthTokens.issued_at){let a=this.config.oauthTokens.issued_at,b=this.config.oauthTokens.expires_in,c=Math.floor(Date.now()/1e3),d=a+b;c>=d?g.info(`Access token for ${this.config.name} has expired (issued: ${a}, expires: ${d}, current: ${c}); SDK will refresh via refresh_token`):g.debug(`Tokens for ${this.config.name} are valid (expires in ${d-c} seconds)`)}return this.config.oauthTokens}g.debug(`No tokens available for ${this.config.name}`)}async saveTokens(a){g.info(`Saving OAuth tokens for ${this.config.name}`),g.verbose("Tokens to save",JSON.stringify({...a,access_token:a.access_token?"[REDACTED]":void 0,refresh_token:a.refresh_token?"[REDACTED]":void 0}));let b={...a,issued_at:Math.floor(Date.now()/1e3)};this.config.oauthTokens=b,await this.persist(),g.info(`OAuth tokens saved for ${this.config.name}`)}async redirectToAuthorization(a){g.info(`Authorization required for ${this.config.name}`),g.info(`Authorization URL: ${a.toString()}`),this.config.authorizationUrl=a.toString();let b=Error(`OAuth authentication required for ${this.config.name}. Please complete the OAuth flow.`);throw b.name="OAuthAuthenticationRequired",b}async saveCodeVerifier(a){g.debug(`Saving code verifier for ${this.config.name}`),this.config.oauthCodeVerifier=a,await this.persist(),g.debug(`Code verifier saved for ${this.config.name}`)}async codeVerifier(){if(!this.config.oauthCodeVerifier){let a=`No code verifier found for ${this.config.name}`;throw g.error(a),Error(a)}return g.debug(`Returning code verifier for ${this.config.name}`),this.config.oauthCodeVerifier}}function i(a,b="http://localhost:4200/api/oauth/callback"){return new h(a,b)}},74186:(a,b,c)=>{c.d(b,{loadServerConfigs:()=>q,q:()=>r});var d=c(33873),e=c.n(d),f=c(34322),g=c(92372),h=c(38844),i=c(50846),j=c(43326);let k=(0,i.h)("backend/services/mcp/config"),l=new Set(["streamable","sse","websocket"]),m=e().join((0,j.getDataDir)(),"mcp-servers"),n=new Map;async function o(a){if(n.has(a))return n.get(a);let b=null;try{let c=(0,f.Ay)({baseDir:a,timeout:{block:5e3}});b=(await c.remote(["get-url","origin"])||"").trim()||null}catch{b=null}return n.set(a,b),b}async function p(a){var b;if(l.has(a.transport))return{type:"remote"};let c="string"!=typeof(b=a.rootPath)||""===b.trim()?null:e().isAbsolute(b)?b:e().resolve((0,j.getDataDir)(),b);if(c&&function(a){let b=e().relative(m,a);return""!==b&&!b.startsWith("..")&&!e().isAbsolute(b)}(c)){let a=await o(c);if(a)return{type:"github",repositoryUrl:a}}return{type:"local"}}async function q(){k.debug("Entering loadServerConfigs method");try{let a=await (0,g.loadItem)(h.Z.MCP_SERVERS,{}),b=Object.entries(a).map(([a,b])=>{let c=b.transport||"stdio";l.has(c)&&function(a){if("string"!=typeof a)return!1;let b=a.trim();return"/"===b||"\\"===b||/^[A-Za-z]:[\\/]?$/.test(b)}(b.rootPath)&&(k.info(`Normalizing filesystem-root rootPath "${b.rootPath}" of remote server ${a} to mcp-servers/${a}`),b={...b,rootPath:`mcp-servers/${a}`});let d={name:a,disabled:!1,autoApprove:[],rootPath:"",env:{},_buildCommand:"",_installCommand:""};return"streamable"===c?{...d,...b,name:a,requestInit:b.requestInit&&"object"==typeof b.requestInit?b.requestInit:void 0,reconnectionOptions:b.reconnectionOptions&&"object"==typeof b.reconnectionOptions?b.reconnectionOptions:void 0,sessionId:b.sessionId||void 0,oauthClientId:b.oauthClientId||"",oauthClientSecret:b.oauthClientSecret||"",oauthScopes:b.oauthScopes||(b.oauthClientId||b.oauthClientInformation?["read"]:void 0),oauthClientMetadata:b.oauthClientMetadata,oauthClientInformation:b.oauthClientInformation,oauthTokens:b.oauthTokens,oauthCodeVerifier:b.oauthCodeVerifier}:"sse"===c?{...d,...b,name:a,eventSourceInit:b.eventSourceInit&&"object"==typeof b.eventSourceInit?b.eventSourceInit:void 0,requestInit:b.requestInit&&"object"==typeof b.requestInit?b.requestInit:void 0}:"websocket"===c?{...d,...b,name:a,websocketUrl:b.websocketUrl||""}:{...d,...b,name:a,command:b.command||"",args:b.args||[],stderr:b.stderr||"pipe"}});return await Promise.all(b.map(async a=>{a.source||(a.source=await p(a))})),b}catch(a){return k.warn("Failed to load server configs",a),{success:!1,error:`Failed to load server configs: ${a instanceof Error?a.message:"Unknown error"}`}}}async function r(a){k.debug("Entering saveConfig method");try{let b=Object.fromEntries(Array.from(a.entries()).filter(([,a])=>!0!==a.builtIn).map(([a,b])=>{let{name:c,...d}=b;return[a,d]}));return await (0,g.VH)(h.Z.MCP_SERVERS,b),{success:!0}}catch(a){return k.warn("Failed to save config",a),{success:!1,error:`Failed to save config: ${a instanceof Error?a.message:"Unknown error"}`}}}}};
|
|
@@ -75,4 +75,4 @@ RULES:
|
|
|
75
75
|
9d. Persistent state (cross-run): "captureKv": "NAME" (process or subflow) saves the step's output to a PERSISTENT key-value store that SURVIVES ACROSS RUNS, injected by any step with \${kv:NAME}. Unlike \${var:} / \${res:} (discarded when the run ends), \${kv:} is what a long-lived SCHEDULED flow uses to carry a loop counter, a pagination cursor, a last-seen id, or a flag to its NEXT run. By default a key lives on the flow's FOLDER board (flows in the same folder share it); prefix the name to change scope: "flow/NAME" (this flow only) or "global/NAME" (whole instance). Plaintext, never secrets (distinct from \${global:VAR}). A model can also read/update a key mid-run via the built-in "flujo" server's kv_get / kv_set tools.
|
|
76
76
|
10. Keep flows minimal — only the steps the task needs. Write clear, specific prompts and labels; fill "description" on process nodes.
|
|
77
77
|
11. Signals (fire-and-forget events): a "signal" node is a deterministic pass-through that, when the path reaches it, emits an event {topic, payload} onto the flow-run event bus and then continues to its successor unchanged (it never calls a model or touches the conversation). Use it when the flow should notify or kick off ANOTHER flow mid-run — a flow-event trigger configured elsewhere listens for the same "topic" (e.g. "when the review finds blockers, emit a review-blocked signal"). Always give it a "topic" (a signal with no topic emits nothing); "payloadTemplate" is the optional event body and may inject \${var:NAME}. Make emission conditional by putting a conditioned edge (rule 5b) INTO the signal node.
|
|
78
|
-
12. Input vs output modes are two DISTINCT axes whose value names differ per node type (issue #152 clarification). inputMode ("full-history" | "latest-message" | "isolated") controls what a step RECEIVES and exists on BOTH process and subflow nodes, but they behave differently: a process node keeps the current turn's tool calls/results, while a subflow node ALWAYS strips system/tool-result/tool-call turns from the parent transcript in every history mode (see the inputMode notes above). "latest-message" means "from the most recent user message onward", NOT "last user + last assistant". outputMode controls what LATER steps see of a step's work and is a SEPARATE enum per node type: a process node uses "full-conversation" | "latest-message" (latest-message hides this step's tool exchange from later steps), a subflow node uses "steps" | "final-only" (live-view folding only). Common word traps: "last-message" = inputMode latest-message; "full-conversation" is a process outputMode value, NOT an input mode. A subflow's final answer is always injected back into the parent transcript regardless of outputMode.`;var D=c(23826),E=c(12700),F=c(79861),G=c(88400);let H=(0,h.h)("backend/services/mcp/quality/cache"),I="mcp-quality-cache";class J{constructor(a=Date.now()){this.entries={},this.dirty=!1,this.now=a}async load(){try{let a=await (0,u.YM)(I,{entries:{}});this.entries=a?.entries&&"object"==typeof a.entries?a.entries:{}}catch(a){H.warn("Failed to load quality cache; starting empty",a),this.entries={}}}get(a,b){let c=this.entries[`${a}::${b}`];if(c&&!(this.now-c.at>864e5))return c.signal}set(a,b,c){this.entries[`${a}::${b}`]={at:this.now,signal:c},this.dirty=!0}async flush(){let a=!1;for(let[b,c]of Object.entries(this.entries))this.now-c.at>864e5&&(delete this.entries[b],a=!0);if(this.dirty||a)try{await (0,u.VH)(I,{entries:this.entries})}catch(a){H.warn("Failed to persist quality cache",a)}}}function K(a){return!Number.isFinite(a)||a<0?0:a>1?1:a}function L(a,b){return!Number.isFinite(a)||a<=0?0:!Number.isFinite(b)||b<=1?+(a>0):K(Math.log10(a+1)/Math.log10(b+1))}let M=(0,h.h)("backend/services/mcp/quality/providers/githubStars"),N="github",O=new Map;function P(){return d??(process.env.GITHUB_TOKEN||void 0)}function Q(a){let b,c=a.server.repository;if(c?.source&&"github"!==c.source.toLowerCase())return null;var d=c?.url;if(!d)return null;try{b=new URL(d.replace(/^git\+/,""))}catch{return null}if(!/(^|\.)github\.com$/i.test(b.hostname))return null;let e=b.pathname.replace(/\.git$/i,"").split("/").filter(Boolean);return e.length<2?null:`${e[0]}/${e[1]}`.toLowerCase()}async function R(a,b){let c=new AbortController,d=()=>c.abort();b.addEventListener("abort",d,{once:!0});let e=setTimeout(()=>c.abort(),6e3);try{return await fetch(`https://api.github.com${a}`,{headers:function(){let a={Accept:"application/vnd.github+json","User-Agent":"FLUJO-mcp-quality","X-GitHub-Api-Version":"2022-11-28"},b=P();return b&&(a.Authorization=`Bearer ${b}`),a}(),signal:c.signal,cache:"no-store"})}catch(b){return M.warn(`GitHub request failed (${a})`,b instanceof Error?b.message:b),null}finally{clearTimeout(e),b.removeEventListener("abort",d)}}function S(a){return(403===a.status||429===a.status)&&"0"===a.headers.get("x-ratelimit-remaining")}let T=(0,h.h)("backend/services/mcp/quality/providers/npmDownloads"),U="npm-downloads",V=new Map;function W(a){for(let b of a.server.packages??[])if("npm"===b.registryType&&b.identifier)return b.identifier;return null}function X(a){return a.startsWith("@")}async function Y(a,b){let c=new AbortController,d=()=>c.abort();b.addEventListener("abort",d,{once:!0});let e=setTimeout(()=>c.abort(),6e3);try{return await fetch(`https://api.npmjs.org${a}`,{signal:c.signal,cache:"no-store"})}catch(b){return T.warn(`npm request failed (${a})`,b instanceof Error?b.message:b),null}finally{clearTimeout(e),b.removeEventListener("abort",d)}}let Z="registry-status",$=[{id:N,label:"GitHub Stars & Activity",defaultWeight:.5,isApplicable:a=>null!==Q(a),cacheKey:a=>Q(a),async prefetch(a,b,c){let d=`${a??""} mcp`.trim(),e=`/search/repositories?q=${encodeURIComponent(d)}&sort=stars&order=desc&per_page=50`,f=await R(e,c);if(f&&f.ok)try{for(let a of(await f.json()).items??[])a.full_name&&O.set(a.full_name.toLowerCase(),{stars:"number"==typeof a.stargazers_count?a.stargazers_count:0,pushedAtMs:a.pushed_at?Date.parse(a.pushed_at):null})}catch(a){M.warn("Failed to parse GitHub search response",a)}else if(f&&S(f))return void M.warn("GitHub search rate-limited; ranking will degrade to other providers");if(!P())return;let g=3;for(let a of b){if(g<=0)break;let b=Q(a);if(!b||O.has(b))continue;g-=1;let d=await R(`/repos/${b}`,c);if(d){if(S(d))break;if(d.ok)try{let a=await d.json();O.set(b,{stars:"number"==typeof a.stargazers_count?a.stargazers_count:0,pushedAtMs:a.pushed_at?Date.parse(a.pushed_at):null})}catch{}}}},async fetch(a){let b=Q(a);if(!b)return null;let c=O.get(b);if(!c)return null;let d=L(c.stars,5e4),e=function(a,b,c=30,d=730){if(!a||!Number.isFinite(a))return 0;let e=(b-a)/864e5;return e<=c?1:e>=d?0:K(1-(e-c)/(d-c))}(c.pushedAtMs,Date.now());return{providerId:N,score:K(.7*d+.3*e),evidence:{repo:b,stars:c.stars,...c.pushedAtMs?{pushedAt:new Date(c.pushedAtMs).toISOString()}:{},starsScore:d,recencyScore:e}}}},{id:U,label:"npm Weekly Downloads",defaultWeight:.35,isApplicable:a=>null!==W(a),cacheKey:a=>W(a),async prefetch(a,b,c){let d=b.map(W).filter(a=>!!a&&!V.has(a)),e=d.filter(a=>!X(a)),f=d.filter(X);for(let a=0;a<e.length;a+=100){let b=e.slice(a,a+100),d=await Y(`/downloads/point/last-week/${b.join(",")}`,c);if(d&&d.ok)try{let a=await d.json();if(1===b.length)"number"==typeof a.downloads&&V.set(b[0],a.downloads);else for(let c of b){let b=a[c];V.set(c,b&&"number"==typeof b.downloads?b.downloads:0)}}catch(a){T.warn("Failed to parse npm bulk downloads response",a)}}for(let a of f){let b=await Y(`/downloads/point/last-week/${a}`,c);if(b&&b.ok)try{let c=await b.json();"number"==typeof c.downloads&&V.set(a,c.downloads)}catch{}}},async fetch(a){let b=W(a);if(!b)return null;let c=V.get(b);return void 0===c?null:{providerId:U,score:L(c,1e6),evidence:{package:b,weeklyDownloads:c}}}},{id:Z,label:"Registry Status",defaultWeight:.15,isApplicable:a=>!0,cacheKey:()=>null,fetch:async a=>({providerId:Z,score:+("active"===a.verificationStatus),evidence:{status:a.verificationStatus}})}];var _=c(14247);let aa=(0,h.h)("backend/services/mcp/quality/settings");function ab(){return{providers:$.map(a=>({id:a.id,enabled:!0,weight:a.defaultWeight})),minScore:0,worksGate:!0}}async function ac(){try{let a=await (0,u.YM)(_.Z.MCP_QUALITY_SETTINGS,ab());return function(a){var b,c;let d=ab(),e=a??{},f=new Map;if(Array.isArray(e.providers))for(let a of e.providers)a&&"string"==typeof a.id&&f.set(a.id,a);return{providers:d.providers.map(a=>{let b=f.get(a.id);return{id:a.id,enabled:"boolean"==typeof b?.enabled?b.enabled:a.enabled,weight:"number"==typeof b?.weight&&Number.isFinite(b.weight)&&b.weight>=0?b.weight:a.weight}}),minScore:(b=e.minScore,c=d.minScore,"number"==typeof b&&Number.isFinite(b)?Math.min(1,Math.max(0,b)):c),worksGate:"boolean"==typeof e.worksGate?e.worksGate:d.worksGate,..."string"==typeof e.githubToken&&e.githubToken.length>0?{githubToken:e.githubToken}:{}}}(a)}catch(a){return aa.warn("Failed to load mcpQuality settings; using defaults",a),ab()}}let ad=(0,h.h)("backend/services/mcp/quality/orchestrator");async function ae(a,b){let c=new AbortController,d=setTimeout(()=>c.abort(),b);try{return await a(c.signal)}finally{clearTimeout(d)}}async function af(a,b,c={}){let e=c.topN??10;try{var f;let g=c.settings??await ac(),h=$.filter(a=>(function(a,b){let c=a.providers.find(a=>a.id===b);return!!c?.enabled})(g,a.id));if(0===h.length)return b.map(a=>({candidate:a,score:0,signals:[]}));d=(f=g.githubToken)&&f.length>0?f:void 0;let i=b.slice(0,e),j=b.slice(e),k=new J(c.now??Date.now());await k.load();let l=i.map(()=>[]);for(let b of h){let c=i.map((a,b)=>({c:a,i:b})).filter(({c:a})=>b.isApplicable(a)),d=[],e=[];for(let a of c){let c=b.cacheKey(a.c);if(c){let d=k.get(b.id,c);if(d){e.push({i:a.i,signal:d});continue}}d.push(a)}if(b.prefetch&&d.length>0)try{await ae(c=>b.prefetch(a,d.map(a=>a.c),c),12e3)}catch(a){ad.warn(`Provider "${b.id}" prefetch failed; degrading`,a)}for(let{c:a,i:c}of d)try{let d=await ae(c=>b.fetch(a,c),2e3);if(d){l[c].push(d);let e=b.cacheKey(a);e&&k.set(b.id,e,d)}}catch(c){ad.warn(`Provider "${b.id}" fetch failed for "${a.registryName}"`,c)}for(let{i:a,signal:b}of e)l[a].push(b)}await k.flush();let m=i.map((a,b)=>{let c=l[b],d=new Map(c.map(a=>[a.providerId,a])),e=h.filter(b=>b.isApplicable(a)).map(a=>({providerId:a.id,weight:function(a,b){let c=a.providers.find(a=>a.id===b);return c&&c.enabled?c.weight:0}(g,a.id),score:d.get(a.id)?.score??0})),{score:f}=function(a){let b=0,c=0;for(let d of a){let a=Number.isFinite(d.weight)&&d.weight>0?d.weight:0,e=K(d.score);b+=a,c+=a*e}return{score:b>0?c/b:0,breakdown:a}}(e);return{candidate:a,score:f,signals:c}}).map((a,b)=>({s:a,idx:b})).sort((a,b)=>b.s.score-a.s.score||a.idx-b.idx).map(a=>a.s),n=j.map(a=>({candidate:a,score:0,signals:[]}));return[...m,...n]}catch(a){return ad.warn("enrichAndRank failed; returning unranked candidates",a),b.map(a=>({candidate:a,score:0,signals:[]}))}}let ag=(0,h.h)("backend/services/mcp/registryInstall"),ah="/v0.1/servers";function ai(a){return{registryName:a.server.name,server:a.server,verificationStatus:(0,F.vf)(a)}}async function aj(a,b=8){let c=await ak(a,b);return(await af(a,c.map(ai))).map(a=>(function(a,b){let c=(0,F.AH)(a),d=c[0];return{name:a.name,...a.title?{title:a.title}:{},...a.description?{description:a.description}:{},installable:c.length>0,requiredEnv:d?(0,F.jg)(d):[],...b?{quality:function(a){let b=b=>a.signals.find(a=>a.providerId===b)?.evidence,c=b(N),d=b(U),e=b(Z);return{score:a.score,..."number"==typeof c?.stars?{stars:c.stars}:{},..."number"==typeof d?.weeklyDownloads?{weeklyDownloads:d.weeklyDownloads}:{},..."string"==typeof e?.status?{status:e.status}:{}}}(b)}:{}}})(a.candidate.server,a))}async function ak(a,b){let c=new URL(E.jD+ah);c.searchParams.set("version","latest"),c.searchParams.set("limit",String(Math.min(Math.max(b,1),30))),a&&c.searchParams.set("search",a);let d=await (0,E.Ws)(c,15e3);return Array.isArray(d?.servers)?d.servers:[]}async function al(a){let b=new URL(E.jD+ah);b.searchParams.set("version","latest"),b.searchParams.set("limit","10"),b.searchParams.set("search",a);let c=await (0,E.Ws)(b,15e3),d=Array.isArray(c?.servers)?c.servers:[];return d.find(b=>b.server?.name===a)??d[0]??null}async function am(a,b,c){let d;if(!a||"string"!=typeof a)return{installed:!1,error:"A registry server name is required"};try{d=await al(a)}catch(a){return{installed:!1,error:`Registry lookup failed: ${a instanceof Error?a.message:String(a)}`}}let e=d?.server??null;if(!e)return{installed:!1,error:`No registry entry found for "${a}"`};let f=(0,F.AH)(e)[0];if(!f)return{installed:!1,error:`"${e.name}" has no install method FLUJO supports (stdio package or HTTP remote)`};let g=(0,F.vf)(d),h=(0,F.O$)(a,e,f,g);if(c?.resolveOnly)return{installed:!1,serverName:h.serverName,plan:h};let i=(0,F.jg)(f,b);if(i.length>0)return{installed:!1,needsEnv:i,plan:h,error:`"${e.name}" requires values for: ${i.join(", ")}`};let j=(0,F.cy)((0,F.Yr)(e,f),b),k=j.name,l=await G.mcpService.loadServerConfigs();if(Array.isArray(l)&&l.some(a=>a.name===k)){ag.info(`installRegistryServer: "${k}" already configured; reusing`);let{tools:a,error:b}=await G.mcpService.listServerTools(k);return{installed:!0,alreadyExisted:!0,serverName:k,plan:h,tools:(a??[]).map(a=>({name:a.name,...a.description?{description:a.description}:{}})),...b?{error:b}:{}}}ag.info(`installRegistryServer: installing "${e.name}" as "${k}" (${f.kind})`);let m=await G.mcpService.updateServerConfig(k,j);if(!Array.isArray(m)&&m&&"success"in m&&!1===m.success)return{installed:!1,error:`Saving the server failed: ${m.error??"unknown error"}`};let{tools:n,error:o}=await G.mcpService.listServerTools(k),p=(n??[]).map(a=>({name:a.name,...a.description?{description:a.description}:{}}));if((c?.worksGate??(await ac()).worksGate)&&0===p.length){ag.warn(`installRegistryServer: "${k}" exposed no tools${o?` (${o})`:""}; rolling back (works-gate)`);try{await G.mcpService.deleteServerConfig(k)}catch(a){ag.error(`installRegistryServer: rollback of "${k}" failed`,a)}return{installed:!1,worksGateRejected:!0,serverName:k,plan:h,error:o?`"${e.name}" failed to start: ${o}`:`"${e.name}" connected but exposed no tools — rejected by the works-gate. Try a different server.`}}return{installed:!0,serverName:k,plan:h,tools:p,...o?{error:o}:{}}}async function an(a,b,c){let d;if(!a||"string"!=typeof a)return{installed:!1,error:"A capability search query is required"};try{d=await ak(a,10)}catch(a){return{installed:!1,error:`Registry lookup failed: ${a instanceof Error?a.message:String(a)}`}}let e=await af(a,d.map(ai)),f=await ac(),g=c?.minScore??f.minScore,h=c?.maxAttempts??3,i=[],j=0;for(let a of e){let d=a.candidate.registryName;if(a.score<g){i.push({name:d,score:a.score,reason:`below minScore ${g}`});break}if(0===(0,F.AH)(a.candidate.server).length){i.push({name:d,score:a.score,reason:"no supported install method"});continue}if(j>=h)break;j+=1;let e=await am(d,b,{worksGate:!0});if(c?.onAttempt)try{await c.onAttempt(e.plan,e)}catch(a){ag.error("installBestForCapability: onAttempt hook failed",a)}if(e.installed)return{...e,attempts:i};let f=e.needsEnv?.length?`needs env: ${e.needsEnv.join(", ")}`:e.worksGateRejected?"works-gate rejected (no tools / failed to start)":e.error??"install failed";i.push({name:d,score:a.score,reason:f})}return{installed:!1,attempts:i,error:`No working server found for "${a}" among the top ${j} installable candidate(s).`}}let ao={requireConsent:!0,namespaceAllowlist:[],trustBrainStem:!0};function ap(a){let{caller:b,settings:c,registryName:d,allowInstall:e}=a;if("generator"===b)return!0===e?{allowed:!0,reason:"generator-allowinstall",message:"Approved by the per-generation allowInstall opt-in."}:{allowed:!1,reason:"generator-not-allowed",message:"Installing is not allowed in this generation (allowInstall is off)."};if("authoring-tool"===b&&c.trustBrainStem)return{allowed:!0,reason:"brainstem-trusted",message:"Approved: the /mcp-flows authoring tool is trusted (mcpAutoInstall.trustBrainStem)."};if(!c.requireConsent)return{allowed:!0,reason:"consent-disabled",message:"Approved: consent is not required (mcpAutoInstall.requireConsent is off)."};let f=function(a){if("string"!=typeof a)return"";let b=a.indexOf("/");return b>0?a.slice(0,b):""}(d);return""!==f&&c.namespaceAllowlist.includes(f)?{allowed:!0,reason:"namespace-allowlisted",message:`Approved: namespace "${f}" is allowlisted.`}:{allowed:!1,reason:"consent-required",message:"Consent required: review the exact command and arguments, then approve this install (SEP-1024)."}}function aq(a,b,c,d,e){return{at:new Date().toISOString(),caller:b,registryName:a.registryName,resolvedName:a.resolvedName,serverName:a.serverName,transport:a.transport,...a.command?{command:a.command}:{},...a.args?{args:a.args}:{},...a.serverUrl?{serverUrl:a.serverUrl}:{},requiredEnvNames:a.requiredEnvNames,verificationStatus:a.verificationStatus,consent:{allowed:c.allowed,reason:c.reason},installed:d,...e?{error:e}:{}}}let ar=(0,h.h)("backend/services/mcp/autoInstall");async function as(){try{let a=await (0,u.YM)(_.Z.MCP_AUTO_INSTALL_SETTINGS,ao)??{};return{requireConsent:"boolean"==typeof a.requireConsent?a.requireConsent:ao.requireConsent,namespaceAllowlist:Array.isArray(a.namespaceAllowlist)?a.namespaceAllowlist.filter(a=>"string"==typeof a&&a.length>0):[],trustBrainStem:"boolean"==typeof a.trustBrainStem?a.trustBrainStem:ao.trustBrainStem}}catch(a){return ar.warn("Failed to load mcpAutoInstall settings; using safe defaults",a),{...ao}}}let at="mcp-install-audit",au=Promise.resolve();async function av(){try{return await (0,u.YM)(at,[])}catch(a){return ar.error("Failed to load MCP install audit log",a),[]}}async function aw(a){let b=au.catch(()=>{}).then(async()=>{let b=await av();b.push(a);let c=b.slice(-300);await (0,u.VH)(at,c)}).catch(a=>{ar.error("Failed to append MCP install audit entry",a)});au=b,await b}let ax=(0,h.h)("backend/services/mcp/flowAuthoringTools"),ay=["list_flow_building_blocks","get_flow_authoring_guide","validate_flow_spec","draft_flow","draft_generated_flow","create_flow","search_mcp_marketplace","install_mcp_server","install_best_mcp_server"];function az(){return{type:"object",additionalProperties:!1,properties:{spec:{oneOf:[o,{type:"object",description:'Legacy advanced FlowSpec with nodes and edges. Pass profile="advanced"; fetch its contract with get_flow_authoring_guide.'}],description:"A guided SimpleFlowSpec by default, or a legacy advanced FlowSpec."},profile:{type:"string",enum:["simple","advanced"],description:"Authoring profile. Defaults to simple; legacy specs containing nodes+edges are auto-detected as advanced."},keepPills:{type:"boolean",description:"When true, binding pills (${tool:server__name}) that resolve against the node's wired servers are preserved in the compiled output instead of being stripped. Pills that cannot be resolved are still stripped with a warning. Default: false (strip all pills — generator-safe behaviour)."}},required:["spec"]}}function aA(a){let b=a?.spec;if("string"==typeof b)try{return JSON.parse(b)}catch{return null}return b??null}function aB(a,b=!1){return{content:[{type:"text",text:JSON.stringify(a,null,2)}],...b?{isError:!0}:{}}}async function aC(a,b){try{if("list_flow_building_blocks"===a){let a=await (0,q.jY)();return aB(a.blocks)}if("get_flow_authoring_guide"===a){let a=b?.profile==="advanced"?"advanced":"simple";if("advanced"===a)return aB({profile:a,guide:C});return aB({profile:a,schema:o,guide:["Set name, goal, and one or more ordered steps.","Each step needs id and task. model overrides the top-level default.","Tools use server/tool references from list_flow_building_blocks.","Set flow on a step to run an existing flow instead of a model.","Omit routes for a linear flow. Routes are only for branches; omit when for the fallback.","Start, Finish, layout, data handoff, and ordinary defaults are inferred."]})}if("search_mcp_marketplace"===a){let a="string"==typeof b?.query?b.query:"",c=await aj(a);return aB(c)}if("install_mcp_server"===a){let a="string"==typeof b?.name?b.name:"",c=b?.env&&"object"==typeof b.env&&!Array.isArray(b.env)?b.env:void 0,d=await am(a,c,{resolveOnly:!0});if(!d.plan)return aB(d,!0);let e=await as(),f=ap({caller:"authoring-tool",settings:e,registryName:a}),g=(0,F.nO)(d.plan.verificationStatus)?void 0:`Unverified / self-asserted registry entry (status: ${d.plan.verificationStatus}). Registry entries are publisher-asserted — review the command before approving.`;if(await aw(aq(d.plan,"authoring-tool",f,!1)),!f.allowed)return aB({installed:!1,consentRequired:!0,message:f.message,plan:d.plan,...g?{verificationWarning:g}:{}});let h=await am(a,c);return await aw(aq(h.plan??d.plan,"authoring-tool",f,h.installed,h.error)),aB({...h,...g?{verificationWarning:g}:{}},!h.installed)}if("install_best_mcp_server"===a){let a="string"==typeof b?.capability?b.capability:"",c=b?.env&&"object"==typeof b.env&&!Array.isArray(b.env)?b.env:void 0;if(!a)return aB({error:'Provide a "capability" search term.'},!0);let d=await as(),e=ap({caller:"authoring-tool",settings:d,registryName:a});if(!e.allowed){let b=(await aj(a)).find(a=>a.installable),d=b?await am(b.name,c,{resolveOnly:!0}):null;return d?.plan&&await aw(aq(d.plan,"authoring-tool",e,!1)),aB({installed:!1,consentRequired:!0,message:e.message,...d?.plan?{plan:d.plan}:{}})}let f=await an(a,c,{onAttempt:async(a,b)=>{a&&await aw(aq(a,"authoring-tool",e,b.installed,b.error))}}),g=f.installed&&!(0,F.nO)(f.plan?.verificationStatus)?`Installed an unverified / self-asserted registry entry (status: ${f.plan?.verificationStatus}).`:void 0;return aB({...f,...g?{verificationWarning:g}:{}},!f.installed)}if("draft_generated_flow"===a){let a=aA(b);if(!a||"object"!=typeof a||Array.isArray(a))return aB({error:'Provide a complete advanced FlowSpec object in "spec".'},!0);let c=await (0,q.jY)(),d=(0,D.oW)(a,c);if(!d.success)return aB({error:"The generated specification could not be compiled.",spec:d.spec,issues:d.issues,hardening:{guardChanges:d.guardChanges,repairChanges:d.repairChanges}},!0);return aB({profile:"advanced",pipeline:"production-generator",saved:!1,rootFlowId:d.flow.id,flow:d.flow,flows:d.flows.map(a=>a.flow),spec:d.spec,validation:d.validation,hardening:{guardChanges:d.guardChanges,repairChanges:d.repairChanges}})}if("validate_flow_spec"===a||"draft_flow"===a||"create_flow"===a){let c=aA(b);if(!c)return aB({error:'Provide a "spec" argument: a SimpleFlowSpec object (or JSON string).'},!0);let d=c&&"object"==typeof c&&!Array.isArray(c)?c:{},e="advanced"===b.profile?"advanced":"simple"===b.profile?"simple":Array.isArray(d.nodes)&&Array.isArray(d.edges)?"advanced":"simple",f=!0===b.keepPills,g=await s(c,{save:"create_flow"===a,keepPills:f,profile:e});if(!g.success)return aB({error:g.error,issues:g.issues??[]},!0);let h=g.flows.length,i=h>1?` (plus ${h-1} nested subflow flow(s))`:"",j={profile:e,flowId:g.flow.id,flowName:g.flow.name,nodeCount:g.flow.nodes.length,edgeCount:g.flow.edges.length,...h>1?{flows:g.flows.map(a=>({id:a.id,name:a.name}))}:{},validation:g.validation,..."draft_flow"===a?{saved:!1,rootFlowId:g.flow.id,flow:g.flow,flows:g.flows}:{},..."create_flow"===a?{saved:g.saved,...g.saved?{note:`Flow "${g.flow.name}"${i} was created. It is callable as a tool on this MCP server (after a fresh tools/list) and as model "flow-${g.flow.name}" on the OpenAI-compatible endpoint.`}:{note:"NOT saved: validation found errors. Fix the issues and call create_flow again."}}:{}};return aB(j,"create_flow"===a&&!g.saved)}return aB({error:`Unknown authoring tool: ${a}`},!0)}catch(b){return ax.error("authoringCallTool failed",{toolName:a,err:b}),aB({error:`Authoring tool failed: ${b instanceof Error?b.message:String(b)}`},!0)}}var aD=c(92018);let aE=(0,h.h)("backend/services/mcp/internalTools");function aF(a,b=!1){return{content:[{type:"text",text:"string"==typeof a?a:JSON.stringify(a,null,2)}],...b?{isError:!0}:{}}}function aG(){return[{name:"list_flow_building_blocks",description:"List models, MCP server/tool references, and existing flows available to a new flow.",inputSchema:{type:"object",properties:{}}},{name:"get_flow_authoring_guide",description:"Fetch the flow-authoring contract only when needed. The simple guide is compact; the advanced guide contains the complete FlowSpec reference.",inputSchema:{type:"object",properties:{profile:{type:"string",enum:["simple","advanced"],description:"Guide to return. Defaults to simple."}}}},{name:"validate_flow_spec",description:"Compile and validate a guided flow without saving. Returns a compact summary and issues. Use draft_flow when the caller needs the complete unsaved draft.",inputSchema:az()},{name:"draft_flow",description:"Compile and validate a flow WITHOUT saving and return the complete draft bundle for review or opening in the Flow Builder.",inputSchema:az()},{name:"draft_generated_flow",description:"Run the production Flow Generator post-processing pipeline on a complete advanced FlowSpec: scratchpad safety guard, structural auto-repair, bounded nested compilation, generated-flow defaults, and whole-bundle validation. Returns the complete UNSAVED draft and hardened spec.",inputSchema:{type:"object",additionalProperties:!1,properties:{spec:{type:"object",description:'A complete advanced FlowSpec authored using get_flow_authoring_guide(profile="advanced").'}},required:["spec"]}},{name:"create_flow",description:"Compile, validate, and save a guided flow. Saving occurs only when validation has no errors. Use list_flow_building_blocks for valid references.",inputSchema:az()},{name:"search_mcp_marketplace",description:"Search the public MCP server registry for new capabilities (voice, browsing, files, email, vision, …). The registry matches the query against server NAMES only (substring) — use short single terms and try several. Returns name, description, whether FLUJO can install it, and which env vars/keys it would require.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Short search term matched against server names."}},required:["query"]}},{name:"install_mcp_server",description:'Install an MCP server from the public registry (by the exact name returned by search_mcp_marketplace) and connect it — this DOWNLOADS AND RUNS a third-party package on the FLUJO host. Installs are gated by consent (SEP-1024): unless this trusted authoring tool is allowed via the mcpAutoInstall settings (trustBrainStem / requireConsent / namespaceAllowlist), the tool returns the exact resolved command + arguments with consentRequired=true INSTEAD of installing, and the caller must obtain explicit approval. Every attempt is written to an audit log (command, args, env NAMES, verification status — never secret values) before any spawn. Returns the FLUJO server name (reference it in FlowSpec "servers") and the tools it provides, or needsEnv when required keys are missing (supply values via the optional "env" argument), or the resolved plan when consent is required. First install can take minutes (package download).',inputSchema:{type:"object",properties:{name:{type:"string",description:'Exact registry name from search results, e.g. "ai.keenable/web-search".'},env:{type:"object",description:"Optional env var values for the server (e.g. required API keys).",additionalProperties:{type:"string"}}},required:["name"]}},{name:"install_best_mcp_server",description:"Install the BEST WORKING MCP server for a capability, unattended — the recommended way to acquire a capability when you don't already have a specific server name. Searches the registry, RANKS candidates by blended quality (GitHub stars + recent activity, npm weekly downloads, registry status), then installs best→worst until one actually boots and exposes tools (the \"works-gate\"): candidates that need unavailable keys, can't be installed, or start with zero tools are skipped automatically. Same consent/audit rules and third-party-code warning as install_mcp_server. Returns the installed server name + its tools and the list of candidates tried, or needsEnv/consentRequired. Prefer this over search+install for headless self-improvement; use install_mcp_server only when you must pin an exact server.",inputSchema:{type:"object",properties:{capability:{type:"string",description:'Short capability term matched against server names, e.g. "youtube", "email", "browser".'},env:{type:"object",description:"Optional env var values shared across attempted servers (e.g. an API key).",additionalProperties:{type:"string"}}},required:["capability"]}},{name:"list_flows",description:"List all flows in this FLUJO instance with lightweight metadata only (id, name, description, node count) and no flow content. Use this to enumerate flows cheaply. Use list_flow_building_blocks only when you need the full authoring catalog (models + servers + flows).",inputSchema:{type:"object",properties:{}}},{name:"execute_flow",description:"Run another FLUJO flow (by name or id) with the given input and return its final output. The run is ephemeral (no chat conversation is created). Use list_flow_building_blocks to see the available flows. Nested runs are limited in depth — a flow cannot recurse through itself indefinitely.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."},input:{type:"string",description:"The message to send to the flow as the user turn."}},required:["flow","input"]}},{name:"read_flow",description:"Read a FLUJO flow's full definition (by name or id): its nodes with their prompts, bound models, attached MCP servers/tools and input/output modes, plus the control and MCP edges. Note this is the COMPILED flow (node ids, not FlowSpec keys) — to change it, author a fresh FlowSpec and call update_flow.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."}},required:["flow"]}},{name:"update_flow",description:"REPLACE an existing FLUJO flow's definition (by name or id) with a newly compiled FlowSpec, keeping the flow's id — so planned executions, subflow nodes and conversations that reference it keep working. The spec format is the same as create_flow/validate_flow_spec (see those tool descriptions); saving is gated on zero validation errors. The replaced definition is archived automatically — list_flow_versions / revert_flow can restore it. Note that manual canvas edits made in the builder are part of what gets replaced. Use read_flow first to see what you are replacing.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id of the flow to replace."},spec:{type:"object",description:"The FlowSpec object (see the create_flow tool description for the format)."}},required:["flow","spec"]}},{name:"list_flow_versions",description:"List a flow's archived versions (by name or id), newest first. A version is created automatically whenever the flow's definition is overwritten (builder save, update_flow, revert_flow) and holds the definition that was replaced. Use read_flow_version to inspect one and revert_flow to restore one.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."}},required:["flow"]}},{name:"read_flow_version",description:"Read one archived version of a flow (see list_flow_versions): the full definition it held before it was replaced, in the same format as read_flow.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."},version:{type:"string",description:"The version id (see list_flow_versions)."}},required:["flow","version"]}},{name:"revert_flow",description:"Restore an archived version (see list_flow_versions) as the flow's CURRENT definition. The definition being reverted away from is archived first, so a revert can itself be undone. References by flow id keep working.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."},version:{type:"string",description:"The version id to restore (see list_flow_versions)."}},required:["flow","version"]}},{name:"delete_flow",description:"PERMANENTLY delete a FLUJO flow (by name or id). This cannot be undone — the flow's version history is deleted with it. Verify the target with list_flow_building_blocks first.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."}},required:["flow"]}},{name:"list_mcp_servers",description:"List the MCP servers configured in this FLUJO instance with their transport, enabled/disabled state and live connection status. Config details (env vars, headers, credentials) are never included.",inputSchema:{type:"object",properties:{}}},{name:"list_mcp_server_tools",description:"List the tools of one configured MCP server (name, description, input schema). Use together with call_mcp_tool for servers that are not bound to this flow.",inputSchema:{type:"object",properties:{server:{type:"string",description:"The FLUJO server name (see list_mcp_servers)."}},required:["server"]}},{name:"call_mcp_tool",description:"Call a tool on any configured MCP server by server name + tool name. This lets you use servers that are not bound to the current flow. Check the tool's input schema with list_mcp_server_tools first.",inputSchema:{type:"object",properties:{server:{type:"string",description:"The FLUJO server name."},tool:{type:"string",description:"The tool name on that server."},args:{type:"object",description:"Arguments for the tool (per its input schema)."},timeout:{type:"number",description:"Optional timeout in seconds."}},required:["server","tool"]}},{name:"restart_mcp_server",description:"Force-reconnect a configured MCP server (tears the connection down and rebuilds it). Useful when a server is in an error state after a config or environment change.",inputSchema:{type:"object",properties:{server:{type:"string",description:"The FLUJO server name."}},required:["server"]}},{name:"set_mcp_server_enabled",description:"Enable or disable a configured MCP server. Disabling disconnects it and prevents any further use; enabling connects it.",inputSchema:{type:"object",properties:{server:{type:"string",description:"The FLUJO server name."},enabled:{type:"boolean",description:"true to enable + connect, false to disable + disconnect."}},required:["server","enabled"]}},{name:"list_models",description:"List the models configured in this FLUJO instance (id, name, display name, description, provider, base URL, context window). API keys are never included. Reference models by id or name in FlowSpecs.",inputSchema:{type:"object",properties:{}}},{name:"list_planned_executions",description:"List the planned (scheduled/triggered) executions in this FLUJO instance with their trigger type, enabled state, armed status and last run outcome.",inputSchema:{type:"object",properties:{}}},{name:"run_planned_execution",description:"Fire a planned execution immediately (by id, see list_planned_executions) and return the run record with its output.",inputSchema:{type:"object",properties:{id:{type:"string",description:"The planned execution id."}},required:["id"]}},{name:"update_planned_execution",description:'Modify an existing planned execution (by id or name, see list_planned_executions). Patch any of: "enabled" (turn the schedule on/off), "prompt" (the run prompt), "flowId" (the flow to run — accepts a flow name or id), "cron" (a convenience for the trigger\'s cron pattern — works for schedule / mcp-poll / url-watch triggers) or a full "trigger" object for complete control. Flow-driven cadence changes are clamped to a minimum interval (a runaway every-second schedule is rejected). The webhook secret token is never returned.',inputSchema:{type:"object",properties:{execution:{type:"string",description:"The planned execution id or name."},enabled:{type:"boolean",description:"Enable or disable the execution."},prompt:{type:"string",description:"The run prompt."},flowId:{type:"string",description:"The flow to run — a flow name or id (resolved to the flow id)."},cron:{type:"string",description:"Cron pattern (croner syntax; 6-field form for seconds) for the trigger's schedule. Applies to schedule / mcp-poll / url-watch triggers."},trigger:{type:"object",description:"Full trigger config object (escape hatch for complete control). Prefer the named fields above."}},required:["execution"]}},{name:"create_planned_execution",description:'Create a new planned execution: bind a flow to a trigger so it runs headlessly. Provide "name", "flow" (a flow name or id), an optional "prompt", optional "enabled" (default true), and EITHER a full "trigger" object OR a convenience "cron" (which creates a schedule trigger). Flow-driven cadence is clamped to a minimum interval. A webhook trigger\'s secret token is minted server-side and never returned.',inputSchema:{type:"object",properties:{name:{type:"string",description:"A name for the planned execution."},flow:{type:"string",description:"The flow to run — a flow name or id."},prompt:{type:"string",description:"The run prompt (may be empty)."},enabled:{type:"boolean",description:"Whether to arm the trigger immediately (default true)."},cron:{type:"string",description:'Cron pattern for a schedule trigger (convenience — use "trigger" for other trigger types).'},trigger:{type:"object",description:"Full trigger config object (schedule / webhook / file-watch / mcp-poll / url-watch)."}},required:["name","flow"]}},{name:"delete_planned_execution",description:"Permanently delete a planned execution (by id or name, see list_planned_executions), along with its run history. This cannot be undone.",inputSchema:{type:"object",properties:{execution:{type:"string",description:"The planned execution id or name."}},required:["execution"]}},{name:"list_conversations",description:"List the chat conversations stored in this FLUJO instance (id, title, bound flow, status, created/updated timestamps), newest first. Use read_conversation to get a transcript.",inputSchema:{type:"object",properties:{limit:{type:"number",description:"Optional maximum number of conversations to return (newest first). Default: all."}}}},{name:"read_conversation",description:'Read one chat conversation\'s transcript by conversation id (see list_conversations). Returns the displayed messages: system prompts are excluded, nested subflow steps carry a "depth" marker, assistant tool calls are summarized. Long conversations return only the most recent messages — raise "limit" to get more.',inputSchema:{type:"object",properties:{conversation:{type:"string",description:"The conversation id."},limit:{type:"number",description:"Maximum number of most-recent messages to return (default 50). The total transcript size is capped regardless."}},required:["conversation"]}},{name:"kv_get",description:'Read a value from FLUJO\'s PERSISTENT key-value store (the ${kv:NAME} store) — state that survives ACROSS flow runs (loop counters, cursors, flags). Returns { found, value }. Defaults to the instance-global board; pass "scope" to target another board (e.g. a flow-folder board id). Values are plain strings, never secrets.',inputSchema:{type:"object",properties:{name:{type:"string",description:"The key to read (an identifier: letters, digits, _ and -, not starting with a digit)."},scope:{type:"string",description:'Optional board id to read from. Defaults to "global".'}},required:["name"]}},{name:"kv_set",description:'Write a value to FLUJO\'s PERSISTENT key-value store (the ${kv:NAME} store) — state that survives ACROSS flow runs. Last-write-wins. Defaults to the instance-global board; pass "scope" to target another board. Values are plain strings (never secrets — use ${global:} for those) and are size-capped; an oversized write is refused with { saved:false, skipped }.',inputSchema:{type:"object",properties:{name:{type:"string",description:"The key to write (an identifier: letters, digits, _ and -, not starting with a digit)."},value:{type:"string",description:"The string value to store."},scope:{type:"string",description:'Optional board id to write to. Defaults to "global".'}},required:["name","value"]}}]}async function aH(a){let b=await i.flowService.loadFlows();return b.find(b=>b.id===a)??b.find(b=>b.name===a)}async function aI(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": a flow name or id.'},!0);let c=await aH(b);if(!c)return aF({error:`No flow named or with id "${b}". Use list_flow_building_blocks to see the available flows.`},!0);let d=global.__flujo_internal_flow_depth??0;if(d>=4)return aF({error:`execute_flow nesting limit (4) reached — refusing to start "${c.name}" to prevent runaway recursion.`},!0);global.__flujo_internal_flow_depth=d+1;try{let b=await (0,m.runFlow)({flowId:c.id,prompt:String(a?.input??""),mode:"ephemeral",flujo:!0,requireApproval:!1});if(b.flowNotFound)return aF({error:`Flow not found: ${b.flowNotFound.name}`},!0);if("error"===b.status)return aF({error:b.error?.message??"Unknown error during flow execution."},!0);return aF(b.outputText??"")}finally{global.__flujo_internal_flow_depth=d}}async function aJ(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": a flow name or id.'},!0);let c=await aH(b);if(!c)return aF({error:`No flow named or with id "${b}".`},!0);let d=await i.flowService.deleteFlow(c.id);return d.success?aF({deleted:!0,flowId:c.id,flowName:c.name}):aF({error:d.error??`Failed to delete flow "${c.name}".`},!0)}function aK(a){let b=a.nodes.map(a=>{let{mcpNodes:b,...c}=a.data?.properties??{};return{id:a.id,type:a.type,label:a.data?.label,...a.data?.description?{description:a.data.description}:{},properties:c}}),c=a.edges.map(a=>{let b=a.data;return{from:a.source,to:a.target,type:b?.edgeType==="mcp"?"mcp":b?.edgeType==="resource"?"resource":"control",...b?.bidirectional?{bidirectional:!0}:{}}});return{id:a.id,name:a.name,...a.description?{description:a.description}:{},nodes:b,edges:c}}async function aL(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": a flow name or id.'},!0);let c=await aH(b);return c?aF({...aK(c),note:"This is the compiled flow (node ids, not FlowSpec keys). To change it, author a fresh FlowSpec and call update_flow — it replaces the whole definition while keeping this flow id."}):aF({error:`No flow named or with id "${b}". Use list_flow_building_blocks to see the available flows.`},!0)}async function aM(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": a flow name or id.'},!0);let c=await aH(b);if(!c)return aF({error:`No flow named or with id "${b}".`},!0);let d=await i.flowService.listFlowVersions(c.id);return aF({flowId:c.id,flowName:c.name,versions:d,...0===d.length?{note:"No archived versions yet — versions appear once the flow's definition is overwritten for the first time."}:{}})}async function aN(a){let b=String(a?.flow??"").trim(),c=String(a?.version??"").trim();if(!b||!c)return aF({error:'Provide "flow" (name or id) and "version" (see list_flow_versions).'},!0);let d=await aH(b);if(!d)return aF({error:`No flow named or with id "${b}".`},!0);let e=await i.flowService.getFlowVersion(d.id,c);return e?aF({versionId:e.versionId,savedAt:e.savedAt,...aK(e.flow)}):aF({error:`No version "${c}" of flow "${d.name}". Use list_flow_versions to see the archived versions.`},!0)}async function aO(a){let b=String(a?.flow??"").trim(),c=String(a?.version??"").trim();if(!b||!c)return aF({error:'Provide "flow" (name or id) and "version" (see list_flow_versions).'},!0);let d=await aH(b);if(!d)return aF({error:`No flow named or with id "${b}".`},!0);let e=await i.flowService.revertFlow(d.id,c);return e.success?aF({reverted:!0,flowId:d.id,versionId:c,note:"The definition that was just replaced has been archived too, so this revert can itself be undone via list_flow_versions / revert_flow."}):aF({error:e.error??`Failed to revert flow "${d.name}".`},!0)}async function aP(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": the name or id of the flow to replace.'},!0);let c=function(a){let b=a?.spec;if("string"==typeof b)try{return JSON.parse(b)}catch{return null}return b??null}(a);if(!c)return aF({error:'Provide a "spec" argument: a FlowSpec object (or a JSON string of one).'},!0);let d=await aH(b);if(!d)return aF({error:`No flow named or with id "${b}". Use list_flow_building_blocks to see the available flows.`},!0);let e=await s(c,{save:!0,updateFlowId:d.id});return e.success?aF({flowId:e.flow.id,flowName:e.flow.name,nodeCount:e.flow.nodes.length,edgeCount:e.flow.edges.length,validation:e.validation,saved:e.saved,...e.saved?{note:`Flow "${e.flow.name}" was replaced (id ${e.flow.id} kept — existing references keep working).`}:{note:"NOT saved: validation found errors. The existing flow is unchanged. Fix the issues and call update_flow again."}},!e.saved):aF({error:e.error,issues:e.issues??[]},!0)}async function aQ(a){let b=await a.loadServerConfigs();return Array.isArray(b)?aF(await Promise.all(b.map(async b=>{let c="unknown";try{c=(await a.getServerStatus(b.name)).status}catch(a){aE.debug(`list_mcp_servers: getServerStatus failed for ${b.name}`,a)}return{name:b.name,transport:b.transport,enabled:!b.disabled,status:c,...b.builtIn?{builtIn:!0}:{}}}))):aF({error:b.error??"Failed to load server configs."},!0)}async function aR(a,b,c){let d=String(b?.server??"").trim();if(!d)return aF({error:'Provide "server": a FLUJO server name.'},!0);if(d===aD._)return aF(aG().map(a=>({name:a.name,description:a.description,inputSchema:a.inputSchema})));let{tools:e,error:f}=await a.listServerTools(d,"host"===c?"all":c);return f?aF({error:f},!0):aF(e.map(a=>({name:a.name,description:a.description,inputSchema:a.inputSchema})))}async function aS(a,b,c){let d=String(b?.server??"").trim(),e=String(b?.tool??"").trim();if(!d||!e)return aF({error:'Provide "server" and "tool".'},!0);if(d===aD._)return aF({error:`"${aD._}" is this server — call its tools directly instead of through call_mcp_tool.`},!0);let f=b?.args&&"object"==typeof b.args&&!Array.isArray(b.args)?b.args:{},g="number"==typeof b?.timeout?b.timeout:void 0,h=await a.callTool(d,e,f,g,void 0,void 0,void 0,c);if(!h.success)return aF({error:h.error??`Tool call failed on ${d}.`},!0);let i=h.data;return i&&Array.isArray(i.content)?i:aF(i??{ok:!0})}async function aT(a,b){let c=String(b?.server??"").trim();if(!c)return aF({error:'Provide "server": a FLUJO server name.'},!0);if(c===aD._)return aF({ok:!0,note:`"${aD._}" is the built-in server — it is always running.`});let d=await a.forceReconnect(c);if(!d.success)return aF({error:d.error??`Failed to restart ${c}.`},!0);let e=await a.getServerStatus(c);return aF({restarted:!0,server:c,status:e.status})}async function aU(a,b){let c=String(b?.server??"").trim(),d=b?.enabled;if(!c||"boolean"!=typeof d)return aF({error:'Provide "server" (string) and "enabled" (boolean).'},!0);if(c===aD._)return aF({error:`The built-in "${aD._}" server cannot be disabled.`},!0);let e=await a.updateServerConfig(c,{disabled:!d});return"error"in e?aF({error:e.error},!0):aF({server:c,enabled:d})}async function aV(){try{let a=(await i.flowService.loadFlows()).map(a=>({id:a.id,name:a.name,...a.description?{description:(0,q.xv)(a.description,q.bD)}:{},nodeCount:a.nodes?.length??0}));return aF(a)}catch(a){return aE.error("list_flows failed",a),aF({error:"Failed to load flows."},!0)}}async function aW(){return aF((await j.modelService.loadModels()).map(a=>({id:a.id,name:a.name,...a.displayName?{displayName:a.displayName}:{},...a.description?{description:a.description}:{},...a.provider?{provider:a.provider}:{},...a.baseUrl?{baseUrl:a.baseUrl}:{},...a.contextWindow?{contextWindow:a.contextWindow}:{}})))}async function aX(){return aF((await (0,k.z)().list()).map(({execution:a,status:b,lastRun:c})=>({id:a.id,name:a.name,enabled:a.enabled,flowId:a.flowId,triggerType:a.trigger?.type,armed:b?.armed??!1,...c?{lastRun:{status:c.status,firedAt:c.firedAt,...c.error?{error:c.error}:{}}}:{}})))}async function aY(a){let b=String(a?.id??"").trim();if(!b)return aF({error:'Provide "id": a planned execution id (see list_planned_executions).'},!0);let{record:c,error:d}=await (0,k.z)().runNow(b);return d||!c?aF({error:d??"Run failed."},!0):aF({runId:c.runId,status:c.status,firedAt:c.firedAt,...c.finishedAt?{finishedAt:c.finishedAt}:{},...c.outputText?{outputText:c.outputText}:{},...c.error?{error:c.error}:{}})}async function aZ(a){let b=await (0,k.z)().list(),c=b.find(b=>b.execution.id===a),d=b.find(b=>b.execution.name===a);return(c??d)?.execution??null}function a$(a){return{id:a.id,name:a.name,enabled:a.enabled,flowId:a.flowId,triggerType:a.trigger?.type}}function a_(a,b){try{let c=(0,l.Z9)(a,b,5).map(a=>new Date(a).getTime()),d=1/0;for(let a=1;a<c.length;a++){let b=c[a]-c[a-1];b>0&&b<d&&(d=b)}return Number.isFinite(d)?d:null}catch{return null}}function a0(a){let b=null;return("schedule"===a.type||"url-watch"===a.type?a.cron&&(b=a_(a.cron,a.timezone)):"mcp-poll"===a.type&&(a.cron?b=a_(a.cron,a.timezone):"number"==typeof a.intervalMs&&(b=a.intervalMs)),null!==b&&b<6e4)?`Cadence too fast: the trigger would fire about every ${Math.round(b/1e3)}s, but flow-driven schedule changes are clamped to a minimum interval of 60s. Choose a slower cadence (change it from the Planned Executions page for a faster one).`:null}async function a1(a){let b,c=String(a?.execution??"").trim();if(!c)return aF({error:'Provide "execution": a planned execution id or name (see list_planned_executions).'},!0);let d=await aZ(c);if(!d)return aF({error:`No planned execution with id or name "${c}". Use list_planned_executions to see them.`},!0);let e={};"boolean"==typeof a?.enabled&&(e.enabled=a.enabled),"string"==typeof a?.prompt&&(e.prompt=a.prompt);let f=String(a?.flowId??a?.flow??"").trim();if(f){let a=await aH(f);if(!a)return aF({error:`No flow named or with id "${f}". Use list_flow_building_blocks to see the flows.`},!0);e.flowId=a.id}a?.trigger&&"object"==typeof a.trigger&&!Array.isArray(a.trigger)&&(b=a.trigger);let g="string"==typeof a?.cron?a.cron.trim():"";if(g){let a=b??d.trigger;if("schedule"!==a.type&&"mcp-poll"!==a.type&&"url-watch"!==a.type)return aF({error:`The "${a.type}" trigger has no schedule to change with "cron". Pass a full "trigger" object instead.`},!0);b={...a,cron:g}}if(b){let a=a0(b);if(a)return aF({error:a},!0);e.trigger=b}if(0===Object.keys(e).length)return aF({error:"Nothing to update. Provide at least one of: enabled, prompt, flowId, cron, trigger."},!0);let h=await (0,k.z)().update(d.id,e);return h.error||!h.execution?aF({error:h.error??"Update failed."},!0):aF({updated:!0,...a$(h.execution)})}async function a2(a){let b,c=String(a?.name??"").trim();if(!c)return aF({error:'Provide "name": a name for the planned execution.'},!0);let d=String(a?.flow??a?.flowId??"").trim();if(!d)return aF({error:'Provide "flow": a flow name or id to run.'},!0);let e=await aH(d);if(!e)return aF({error:`No flow named or with id "${d}". Use list_flow_building_blocks to see the flows.`},!0);if(a?.trigger&&"object"==typeof a.trigger&&!Array.isArray(a.trigger))b=a.trigger;else{let c="string"==typeof a?.cron?a.cron.trim():"";if(!c)return aF({error:'Provide a "trigger" object or a "cron" pattern (which creates a schedule trigger).'},!0);b={type:"schedule",cron:c}}let f=a0(b);if(f)return aF({error:f},!0);let g={name:c,enabled:"boolean"!=typeof a?.enabled||a.enabled,flowId:e.id,prompt:"string"==typeof a?.prompt?a.prompt:"",trigger:b},h=await (0,k.z)().create(g);return h.error||!h.execution?aF({error:h.error??"Create failed."},!0):aF({created:!0,...a$(h.execution)})}async function a3(a){let b=String(a?.execution??"").trim();if(!b)return aF({error:'Provide "execution": a planned execution id or name (see list_planned_executions).'},!0);let c=await aZ(b);if(!c)return aF({error:`No planned execution with id or name "${b}". Use list_planned_executions to see them.`},!0);let d=await (0,k.z)().delete(c.id);return d.success?aF({deleted:!0,id:c.id,name:c.name}):aF({error:d.error??`Failed to delete "${c.name}".`},!0)}async function a4(a){let b,c=f().join((0,A.getDataDir)(),"db","conversations");try{b=await g.promises.readdir(c)}catch(a){if("ENOENT"===a.code)return aF([]);return aF({error:`Failed to list conversations: ${a instanceof Error?a.message:String(a)}`},!0)}let d=(await Promise.all(b.filter(a=>a.endsWith(".json")).map(async a=>{try{let b=await g.promises.readFile(f().join(c,a),"utf-8"),d=JSON.parse(b),e=d.conversationId||a.replace(/\.json$/,""),h=d.status;return"running"===h&&0===z.$.currentSeq(e)&&(h="error"),{id:e,title:d.title||"Untitled Conversation",flowId:d.flowId||null,...h?{status:h}:{},createdAt:d.createdAt||0,updatedAt:d.updatedAt||0}}catch(b){return aE.warn(`list_conversations: skipping unreadable conversation file ${a}`,b),null}}))).filter(a=>null!==a).sort((a,b)=>b.updatedAt-a.updatedAt),e="number"==typeof a?.limit&&a.limit>0?Math.floor(a.limit):void 0;return aF(e?d.slice(0,e):d)}async function a5(a){let b=String(a?.conversation??"").trim();if(!b)return aF({error:'Provide "conversation": a conversation id (see list_conversations).'},!0);await (0,v.flushConversationLog)(b);let c=await y(b);if(!c)return aF({error:`No conversation with id "${b}". Use list_conversations to see the stored conversations.`},!0);let d=await (0,v.readConversationLog)(b),e=d?(0,v.projectMessages)(d):[],f=e.length>0?e:(c.messages||[]).filter(a=>"system"!==a.role),g="number"==typeof a?.limit&&a.limit>0?Math.floor(a.limit):50,h=[],i=0;for(let a=f.length-1;a>=0&&h.length<g;a--){let b=function(a){let b="";"string"==typeof a.content?b=a.content:Array.isArray(a.content)&&(b=a.content.map(a=>"text"in a&&"string"==typeof a.text?a.text:"").filter(Boolean).join("\n"));let c={role:a.role,...b?{content:b}:{},...a.timestamp?{timestamp:a.timestamp}:{},...a.depth?{depth:a.depth}:{}};return"assistant"===a.role&&Array.isArray(a.tool_calls)&&a.tool_calls.length>0&&(c.toolCalls=a.tool_calls.map(a=>{let b="function"in a?a.function:void 0,c=b&&"string"==typeof b.arguments?b.arguments:void 0;return{id:a.id,...b?.name?{name:b.name}:{},...void 0!==c?{arguments:c.length>2e3?c.slice(0,2e3)+"…[truncated]":c}:{}}})),"tool"===a.role&&a.tool_call_id&&(c.toolCallId=a.tool_call_id),c}(f[a]),c=JSON.stringify(b).length;if(h.length>0&&i+c>1e5)break;h.push(b),i+=c}return h.reverse(),aF({id:c.conversationId||b,title:c.title||"Untitled Conversation",flowId:c.flowId||null,...c.status?{status:c.status}:{},createdAt:c.createdAt||0,updatedAt:c.updatedAt||0,totalMessages:f.length,...h.length<f.length?{note:`Returning the ${h.length} most recent of ${f.length} messages — raise "limit" to get more.`}:{},messages:h})}let a6=/^[A-Za-z0-9_-]{1,64}$/,a7=/^[A-Za-z_][\w-]*$/;async function a8(a){let b="string"==typeof a.name?a.name.trim():"",c="string"==typeof a.scope&&a.scope.trim()?a.scope.trim():"global";if(!a7.test(b))return aF({error:'kv_get requires a valid "name" (letters, digits, _ and -, not starting with a digit).'},!0);if(!a6.test(c))return aF({error:`Invalid kv scope id: ${c}`},!0);let d=await (0,B.M3)(c,b);return aF({scope:c,name:b,found:void 0!==d,value:d??null})}async function a9(a){let b="string"==typeof a.name?a.name.trim():"",c="string"==typeof a.scope&&a.scope.trim()?a.scope.trim():"global",d="string"==typeof a.value?a.value:null==a.value?"":String(a.value);if(!a7.test(b))return aF({error:'kv_set requires a valid "name" (letters, digits, _ and -, not starting with a digit).'},!0);if(!a6.test(c))return aF({error:`Invalid kv scope id: ${c}`},!0);let e=await (0,B.or)(c,b,d);return"skipped"in e?aF({scope:c,name:b,saved:!1,skipped:e.skipped},!0):aF({scope:c,name:b,saved:!0,size:e.size})}async function ba(a,b,c,d="host"){try{if(ay.includes(b))return await aC(b,c);switch(b){case"list_flows":return await aV();case"execute_flow":return await aI(c);case"read_flow":return await aL(c);case"update_flow":return await aP(c);case"list_flow_versions":return await aM(c);case"read_flow_version":return await aN(c);case"revert_flow":return await aO(c);case"delete_flow":return await aJ(c);case"list_mcp_servers":return await aQ(a);case"list_mcp_server_tools":return await aR(a,c,d);case"call_mcp_tool":return await aS(a,c,d);case"restart_mcp_server":return await aT(a,c);case"set_mcp_server_enabled":return await aU(a,c);case"list_models":return await aW();case"list_planned_executions":return await aX();case"run_planned_execution":return await aY(c);case"update_planned_execution":return await a1(c);case"create_planned_execution":return await a2(c);case"delete_planned_execution":return await a3(c);case"list_conversations":return await a4(c);case"read_conversation":return await a5(c);case"kv_get":return await a8(c);case"kv_set":return await a9(c);default:return aF({error:`Unknown tool on the built-in FLUJO server: ${b}`},!0)}}catch(a){return aE.error("internalCallTool failed",{toolName:b,err:a}),aF({error:`Tool failed: ${a instanceof Error?a.message:String(a)}`},!0)}}}};
|
|
78
|
+
12. Input vs output modes are two DISTINCT axes whose value names differ per node type (issue #152 clarification). inputMode ("full-history" | "latest-message" | "isolated") controls what a step RECEIVES and exists on BOTH process and subflow nodes, but they behave differently: a process node keeps the current turn's tool calls/results, while a subflow node ALWAYS strips system/tool-result/tool-call turns from the parent transcript in every history mode (see the inputMode notes above). "latest-message" means "from the most recent user message onward", NOT "last user + last assistant". outputMode controls what LATER steps see of a step's work and is a SEPARATE enum per node type: a process node uses "full-conversation" | "latest-message" (latest-message hides this step's tool exchange from later steps), a subflow node uses "steps" | "final-only" (live-view folding only). Common word traps: "last-message" = inputMode latest-message; "full-conversation" is a process outputMode value, NOT an input mode. A subflow's final answer is always injected back into the parent transcript regardless of outputMode.`;var D=c(23826),E=c(12700),F=c(79861),G=c(88400);let H=(0,h.h)("backend/services/mcp/quality/cache"),I="mcp-quality-cache";class J{constructor(a=Date.now()){this.entries={},this.dirty=!1,this.now=a}async load(){try{let a=await (0,u.YM)(I,{entries:{}});this.entries=a?.entries&&"object"==typeof a.entries?a.entries:{}}catch(a){H.warn("Failed to load quality cache; starting empty",a),this.entries={}}}get(a,b){let c=this.entries[`${a}::${b}`];if(c&&!(this.now-c.at>864e5))return c.signal}set(a,b,c){this.entries[`${a}::${b}`]={at:this.now,signal:c},this.dirty=!0}async flush(){let a=!1;for(let[b,c]of Object.entries(this.entries))this.now-c.at>864e5&&(delete this.entries[b],a=!0);if(this.dirty||a)try{await (0,u.VH)(I,{entries:this.entries})}catch(a){H.warn("Failed to persist quality cache",a)}}}function K(a){return!Number.isFinite(a)||a<0?0:a>1?1:a}function L(a,b){return!Number.isFinite(a)||a<=0?0:!Number.isFinite(b)||b<=1?+(a>0):K(Math.log10(a+1)/Math.log10(b+1))}let M=(0,h.h)("backend/services/mcp/quality/providers/githubStars"),N="github",O=new Map;function P(){return d??(process.env.GITHUB_TOKEN||void 0)}function Q(a){let b,c=a.server.repository;if(c?.source&&"github"!==c.source.toLowerCase())return null;var d=c?.url;if(!d)return null;try{b=new URL(d.replace(/^git\+/,""))}catch{return null}if(!/(^|\.)github\.com$/i.test(b.hostname))return null;let e=b.pathname.replace(/\.git$/i,"").split("/").filter(Boolean);return e.length<2?null:`${e[0]}/${e[1]}`.toLowerCase()}async function R(a,b){let c=new AbortController,d=()=>c.abort();b.addEventListener("abort",d,{once:!0});let e=setTimeout(()=>c.abort(),6e3);try{return await fetch(`https://api.github.com${a}`,{headers:function(){let a={Accept:"application/vnd.github+json","User-Agent":"FLUJO-mcp-quality","X-GitHub-Api-Version":"2022-11-28"},b=P();return b&&(a.Authorization=`Bearer ${b}`),a}(),signal:c.signal,cache:"no-store"})}catch(b){return M.warn(`GitHub request failed (${a})`,b instanceof Error?b.message:b),null}finally{clearTimeout(e),b.removeEventListener("abort",d)}}function S(a){return(403===a.status||429===a.status)&&"0"===a.headers.get("x-ratelimit-remaining")}let T=(0,h.h)("backend/services/mcp/quality/providers/npmDownloads"),U="npm-downloads",V=new Map;function W(a){for(let b of a.server.packages??[])if("npm"===b.registryType&&b.identifier)return b.identifier;return null}function X(a){return a.startsWith("@")}async function Y(a,b){let c=new AbortController,d=()=>c.abort();b.addEventListener("abort",d,{once:!0});let e=setTimeout(()=>c.abort(),6e3);try{return await fetch(`https://api.npmjs.org${a}`,{signal:c.signal,cache:"no-store"})}catch(b){return T.warn(`npm request failed (${a})`,b instanceof Error?b.message:b),null}finally{clearTimeout(e),b.removeEventListener("abort",d)}}let Z="registry-status",$=[{id:N,label:"GitHub Stars & Activity",defaultWeight:.5,isApplicable:a=>null!==Q(a),cacheKey:a=>Q(a),async prefetch(a,b,c){let d=`${a??""} mcp`.trim(),e=`/search/repositories?q=${encodeURIComponent(d)}&sort=stars&order=desc&per_page=50`,f=await R(e,c);if(f&&f.ok)try{for(let a of(await f.json()).items??[])a.full_name&&O.set(a.full_name.toLowerCase(),{stars:"number"==typeof a.stargazers_count?a.stargazers_count:0,pushedAtMs:a.pushed_at?Date.parse(a.pushed_at):null})}catch(a){M.warn("Failed to parse GitHub search response",a)}else if(f&&S(f))return void M.warn("GitHub search rate-limited; ranking will degrade to other providers");if(!P())return;let g=3;for(let a of b){if(g<=0)break;let b=Q(a);if(!b||O.has(b))continue;g-=1;let d=await R(`/repos/${b}`,c);if(d){if(S(d))break;if(d.ok)try{let a=await d.json();O.set(b,{stars:"number"==typeof a.stargazers_count?a.stargazers_count:0,pushedAtMs:a.pushed_at?Date.parse(a.pushed_at):null})}catch{}}}},async fetch(a){let b=Q(a);if(!b)return null;let c=O.get(b);if(!c)return null;let d=L(c.stars,5e4),e=function(a,b,c=30,d=730){if(!a||!Number.isFinite(a))return 0;let e=(b-a)/864e5;return e<=c?1:e>=d?0:K(1-(e-c)/(d-c))}(c.pushedAtMs,Date.now());return{providerId:N,score:K(.7*d+.3*e),evidence:{repo:b,stars:c.stars,...c.pushedAtMs?{pushedAt:new Date(c.pushedAtMs).toISOString()}:{},starsScore:d,recencyScore:e}}}},{id:U,label:"npm Weekly Downloads",defaultWeight:.35,isApplicable:a=>null!==W(a),cacheKey:a=>W(a),async prefetch(a,b,c){let d=b.map(W).filter(a=>!!a&&!V.has(a)),e=d.filter(a=>!X(a)),f=d.filter(X);for(let a=0;a<e.length;a+=100){let b=e.slice(a,a+100),d=await Y(`/downloads/point/last-week/${b.join(",")}`,c);if(d&&d.ok)try{let a=await d.json();if(1===b.length)"number"==typeof a.downloads&&V.set(b[0],a.downloads);else for(let c of b){let b=a[c];V.set(c,b&&"number"==typeof b.downloads?b.downloads:0)}}catch(a){T.warn("Failed to parse npm bulk downloads response",a)}}for(let a of f){let b=await Y(`/downloads/point/last-week/${a}`,c);if(b&&b.ok)try{let c=await b.json();"number"==typeof c.downloads&&V.set(a,c.downloads)}catch{}}},async fetch(a){let b=W(a);if(!b)return null;let c=V.get(b);return void 0===c?null:{providerId:U,score:L(c,1e6),evidence:{package:b,weeklyDownloads:c}}}},{id:Z,label:"Registry Status",defaultWeight:.15,isApplicable:a=>!0,cacheKey:()=>null,fetch:async a=>({providerId:Z,score:+("active"===a.verificationStatus),evidence:{status:a.verificationStatus}})}];var _=c(14247);let aa=(0,h.h)("backend/services/mcp/quality/settings");function ab(){return{providers:$.map(a=>({id:a.id,enabled:!0,weight:a.defaultWeight})),minScore:0,worksGate:!0}}async function ac(){try{let a=await (0,u.YM)(_.Z.MCP_QUALITY_SETTINGS,ab());return function(a){var b,c;let d=ab(),e=a??{},f=new Map;if(Array.isArray(e.providers))for(let a of e.providers)a&&"string"==typeof a.id&&f.set(a.id,a);return{providers:d.providers.map(a=>{let b=f.get(a.id);return{id:a.id,enabled:"boolean"==typeof b?.enabled?b.enabled:a.enabled,weight:"number"==typeof b?.weight&&Number.isFinite(b.weight)&&b.weight>=0?b.weight:a.weight}}),minScore:(b=e.minScore,c=d.minScore,"number"==typeof b&&Number.isFinite(b)?Math.min(1,Math.max(0,b)):c),worksGate:"boolean"==typeof e.worksGate?e.worksGate:d.worksGate,..."string"==typeof e.githubToken&&e.githubToken.length>0?{githubToken:e.githubToken}:{}}}(a)}catch(a){return aa.warn("Failed to load mcpQuality settings; using defaults",a),ab()}}let ad=(0,h.h)("backend/services/mcp/quality/orchestrator");async function ae(a,b){let c=new AbortController,d=setTimeout(()=>c.abort(),b);try{return await a(c.signal)}finally{clearTimeout(d)}}async function af(a,b,c={}){let e=c.topN??10;try{var f;let g=c.settings??await ac(),h=$.filter(a=>(function(a,b){let c=a.providers.find(a=>a.id===b);return!!c?.enabled})(g,a.id));if(0===h.length)return b.map(a=>({candidate:a,score:0,signals:[]}));d=(f=g.githubToken)&&f.length>0?f:void 0;let i=b.slice(0,e),j=b.slice(e),k=new J(c.now??Date.now());await k.load();let l=i.map(()=>[]);for(let b of h){let c=i.map((a,b)=>({c:a,i:b})).filter(({c:a})=>b.isApplicable(a)),d=[],e=[];for(let a of c){let c=b.cacheKey(a.c);if(c){let d=k.get(b.id,c);if(d){e.push({i:a.i,signal:d});continue}}d.push(a)}if(b.prefetch&&d.length>0)try{await ae(c=>b.prefetch(a,d.map(a=>a.c),c),12e3)}catch(a){ad.warn(`Provider "${b.id}" prefetch failed; degrading`,a)}for(let{c:a,i:c}of d)try{let d=await ae(c=>b.fetch(a,c),2e3);if(d){l[c].push(d);let e=b.cacheKey(a);e&&k.set(b.id,e,d)}}catch(c){ad.warn(`Provider "${b.id}" fetch failed for "${a.registryName}"`,c)}for(let{i:a,signal:b}of e)l[a].push(b)}await k.flush();let m=i.map((a,b)=>{let c=l[b],d=new Map(c.map(a=>[a.providerId,a])),e=h.filter(b=>b.isApplicable(a)).map(a=>({providerId:a.id,weight:function(a,b){let c=a.providers.find(a=>a.id===b);return c&&c.enabled?c.weight:0}(g,a.id),score:d.get(a.id)?.score??0})),{score:f}=function(a){let b=0,c=0;for(let d of a){let a=Number.isFinite(d.weight)&&d.weight>0?d.weight:0,e=K(d.score);b+=a,c+=a*e}return{score:b>0?c/b:0,breakdown:a}}(e);return{candidate:a,score:f,signals:c}}).map((a,b)=>({s:a,idx:b})).sort((a,b)=>b.s.score-a.s.score||a.idx-b.idx).map(a=>a.s),n=j.map(a=>({candidate:a,score:0,signals:[]}));return[...m,...n]}catch(a){return ad.warn("enrichAndRank failed; returning unranked candidates",a),b.map(a=>({candidate:a,score:0,signals:[]}))}}let ag=(0,h.h)("backend/services/mcp/registryInstall"),ah="/v0.1/servers";function ai(a){return{registryName:a.server.name,server:a.server,verificationStatus:(0,F.vf)(a)}}async function aj(a,b=8){let c=await ak(a,b);return(await af(a,c.map(ai))).map(a=>(function(a,b){let c=(0,F.AH)(a),d=c[0];return{name:a.name,...a.title?{title:a.title}:{},...a.description?{description:a.description}:{},installable:c.length>0,requiredEnv:d?(0,F.jg)(d):[],...b?{quality:function(a){let b=b=>a.signals.find(a=>a.providerId===b)?.evidence,c=b(N),d=b(U),e=b(Z);return{score:a.score,..."number"==typeof c?.stars?{stars:c.stars}:{},..."number"==typeof d?.weeklyDownloads?{weeklyDownloads:d.weeklyDownloads}:{},..."string"==typeof e?.status?{status:e.status}:{}}}(b)}:{}}})(a.candidate.server,a))}async function ak(a,b){let c=new URL(E.jD+ah);c.searchParams.set("version","latest"),c.searchParams.set("limit",String(Math.min(Math.max(b,1),30))),a&&c.searchParams.set("search",a);let d=await (0,E.Ws)(c,15e3);return Array.isArray(d?.servers)?d.servers:[]}async function al(a){let b=new URL(E.jD+ah);b.searchParams.set("version","latest"),b.searchParams.set("limit","10"),b.searchParams.set("search",a);let c=await (0,E.Ws)(b,15e3),d=Array.isArray(c?.servers)?c.servers:[];return d.find(b=>b.server?.name===a)??d[0]??null}async function am(a,b,c){let d;if(!a||"string"!=typeof a)return{installed:!1,error:"A registry server name is required"};try{d=await al(a)}catch(a){return{installed:!1,error:`Registry lookup failed: ${a instanceof Error?a.message:String(a)}`}}let e=d?.server??null;if(!e)return{installed:!1,error:`No registry entry found for "${a}"`};let f=(0,F.AH)(e)[0];if(!f)return{installed:!1,error:`"${e.name}" has no install method FLUJO supports (stdio package or HTTP remote)`};let g=(0,F.vf)(d),h=(0,F.O$)(a,e,f,g);if(c?.resolveOnly)return{installed:!1,serverName:h.serverName,plan:h};let i=(0,F.jg)(f,b);if(i.length>0)return{installed:!1,needsEnv:i,plan:h,error:`"${e.name}" requires values for: ${i.join(", ")}`};let j=function(a,b){if(!b?.length)return a;if("stdio"!==a.transport||!Array.isArray(a.args))return{error:"Package argument templates require a stdio registry server"};let c=[...a.args];for(let a of b){if(!Number.isInteger(a.index)||a.index<0||a.index>c.length||a.index<c.length&&!/\$\{global:[A-Za-z0-9_.-]+\}/.test(c[a.index])||!/\$\{global:[A-Za-z0-9_.-]+\}/.test(a.value))return{error:`Invalid package argument template at index ${String(a.index)}; templates may append arguments or replace an existing global-backed argument`};c[a.index]=a.value}return{...a,args:c}}((0,F.cy)((0,F.Yr)(e,f),b),c?.argTemplates);if("error"in j)return{installed:!1,plan:h,error:j.error};let k=j.name,l=await G.mcpService.loadServerConfigs();if(Array.isArray(l)&&l.some(a=>a.name===k)){ag.info(`installRegistryServer: "${k}" already configured; reusing`);let{tools:a,error:b}=await G.mcpService.listServerTools(k);return{installed:!0,alreadyExisted:!0,serverName:k,plan:h,tools:(a??[]).map(a=>({name:a.name,...a.description?{description:a.description}:{}})),...b?{error:b}:{}}}ag.info(`installRegistryServer: installing "${e.name}" as "${k}" (${f.kind})`);let m=await G.mcpService.updateServerConfig(k,j);if(!Array.isArray(m)&&m&&"success"in m&&!1===m.success)return{installed:!1,error:`Saving the server failed: ${m.error??"unknown error"}`};let{tools:n,error:o}=await G.mcpService.listServerTools(k),p=(n??[]).map(a=>({name:a.name,...a.description?{description:a.description}:{}}));if((c?.worksGate??(await ac()).worksGate)&&0===p.length){ag.warn(`installRegistryServer: "${k}" exposed no tools${o?` (${o})`:""}; rolling back (works-gate)`);try{await G.mcpService.deleteServerConfig(k)}catch(a){ag.error(`installRegistryServer: rollback of "${k}" failed`,a)}return{installed:!1,worksGateRejected:!0,serverName:k,plan:h,error:o?`"${e.name}" failed to start: ${o}`:`"${e.name}" connected but exposed no tools — rejected by the works-gate. Try a different server.`}}return{installed:!0,serverName:k,plan:h,tools:p,...o?{error:o}:{}}}async function an(a,b,c){let d;if(!a||"string"!=typeof a)return{installed:!1,error:"A capability search query is required"};try{d=await ak(a,10)}catch(a){return{installed:!1,error:`Registry lookup failed: ${a instanceof Error?a.message:String(a)}`}}let e=await af(a,d.map(ai)),f=await ac(),g=c?.minScore??f.minScore,h=c?.maxAttempts??3,i=[],j=0;for(let a of e){let d=a.candidate.registryName;if(a.score<g){i.push({name:d,score:a.score,reason:`below minScore ${g}`});break}if(0===(0,F.AH)(a.candidate.server).length){i.push({name:d,score:a.score,reason:"no supported install method"});continue}if(j>=h)break;j+=1;let e=await am(d,b,{worksGate:!0});if(c?.onAttempt)try{await c.onAttempt(e.plan,e)}catch(a){ag.error("installBestForCapability: onAttempt hook failed",a)}if(e.installed)return{...e,attempts:i};let f=e.needsEnv?.length?`needs env: ${e.needsEnv.join(", ")}`:e.worksGateRejected?"works-gate rejected (no tools / failed to start)":e.error??"install failed";i.push({name:d,score:a.score,reason:f})}return{installed:!1,attempts:i,error:`No working server found for "${a}" among the top ${j} installable candidate(s).`}}let ao={requireConsent:!0,namespaceAllowlist:[],trustBrainStem:!0};function ap(a){let{caller:b,settings:c,registryName:d,allowInstall:e}=a;if("generator"===b)return!0===e?{allowed:!0,reason:"generator-allowinstall",message:"Approved by the per-generation allowInstall opt-in."}:{allowed:!1,reason:"generator-not-allowed",message:"Installing is not allowed in this generation (allowInstall is off)."};if("authoring-tool"===b&&c.trustBrainStem)return{allowed:!0,reason:"brainstem-trusted",message:"Approved: the /mcp-flows authoring tool is trusted (mcpAutoInstall.trustBrainStem)."};if(!c.requireConsent)return{allowed:!0,reason:"consent-disabled",message:"Approved: consent is not required (mcpAutoInstall.requireConsent is off)."};let f=function(a){if("string"!=typeof a)return"";let b=a.indexOf("/");return b>0?a.slice(0,b):""}(d);return""!==f&&c.namespaceAllowlist.includes(f)?{allowed:!0,reason:"namespace-allowlisted",message:`Approved: namespace "${f}" is allowlisted.`}:{allowed:!1,reason:"consent-required",message:"Consent required: review the exact command and arguments, then approve this install (SEP-1024)."}}function aq(a,b,c,d,e){return{at:new Date().toISOString(),caller:b,registryName:a.registryName,resolvedName:a.resolvedName,serverName:a.serverName,transport:a.transport,...a.command?{command:a.command}:{},...a.args?{args:a.args}:{},...a.serverUrl?{serverUrl:a.serverUrl}:{},requiredEnvNames:a.requiredEnvNames,verificationStatus:a.verificationStatus,consent:{allowed:c.allowed,reason:c.reason},installed:d,...e?{error:e}:{}}}let ar=(0,h.h)("backend/services/mcp/autoInstall");async function as(){try{let a=await (0,u.YM)(_.Z.MCP_AUTO_INSTALL_SETTINGS,ao)??{};return{requireConsent:"boolean"==typeof a.requireConsent?a.requireConsent:ao.requireConsent,namespaceAllowlist:Array.isArray(a.namespaceAllowlist)?a.namespaceAllowlist.filter(a=>"string"==typeof a&&a.length>0):[],trustBrainStem:"boolean"==typeof a.trustBrainStem?a.trustBrainStem:ao.trustBrainStem}}catch(a){return ar.warn("Failed to load mcpAutoInstall settings; using safe defaults",a),{...ao}}}let at="mcp-install-audit",au=Promise.resolve();async function av(){try{return await (0,u.YM)(at,[])}catch(a){return ar.error("Failed to load MCP install audit log",a),[]}}async function aw(a){let b=au.catch(()=>{}).then(async()=>{let b=await av();b.push(a);let c=b.slice(-300);await (0,u.VH)(at,c)}).catch(a=>{ar.error("Failed to append MCP install audit entry",a)});au=b,await b}let ax=(0,h.h)("backend/services/mcp/flowAuthoringTools"),ay=["list_flow_building_blocks","get_flow_authoring_guide","validate_flow_spec","draft_flow","draft_generated_flow","create_flow","search_mcp_marketplace","install_mcp_server","install_best_mcp_server"];function az(){return{type:"object",additionalProperties:!1,properties:{spec:{oneOf:[o,{type:"object",description:'Legacy advanced FlowSpec with nodes and edges. Pass profile="advanced"; fetch its contract with get_flow_authoring_guide.'}],description:"A guided SimpleFlowSpec by default, or a legacy advanced FlowSpec."},profile:{type:"string",enum:["simple","advanced"],description:"Authoring profile. Defaults to simple; legacy specs containing nodes+edges are auto-detected as advanced."},keepPills:{type:"boolean",description:"When true, binding pills (${tool:server__name}) that resolve against the node's wired servers are preserved in the compiled output instead of being stripped. Pills that cannot be resolved are still stripped with a warning. Default: false (strip all pills — generator-safe behaviour)."}},required:["spec"]}}function aA(a){let b=a?.spec;if("string"==typeof b)try{return JSON.parse(b)}catch{return null}return b??null}function aB(a,b=!1){return{content:[{type:"text",text:JSON.stringify(a,null,2)}],...b?{isError:!0}:{}}}async function aC(a,b){try{if("list_flow_building_blocks"===a){let a=await (0,q.jY)();return aB(a.blocks)}if("get_flow_authoring_guide"===a){let a=b?.profile==="advanced"?"advanced":"simple";if("advanced"===a)return aB({profile:a,guide:C});return aB({profile:a,schema:o,guide:["Set name, goal, and one or more ordered steps.","Each step needs id and task. model overrides the top-level default.","Tools use server/tool references from list_flow_building_blocks.","Set flow on a step to run an existing flow instead of a model.","Omit routes for a linear flow. Routes are only for branches; omit when for the fallback.","Start, Finish, layout, data handoff, and ordinary defaults are inferred."]})}if("search_mcp_marketplace"===a){let a="string"==typeof b?.query?b.query:"",c=await aj(a);return aB(c)}if("install_mcp_server"===a){let a="string"==typeof b?.name?b.name:"",c=b?.env&&"object"==typeof b.env&&!Array.isArray(b.env)?b.env:void 0,d=await am(a,c,{resolveOnly:!0});if(!d.plan)return aB(d,!0);let e=await as(),f=ap({caller:"authoring-tool",settings:e,registryName:a}),g=(0,F.nO)(d.plan.verificationStatus)?void 0:`Unverified / self-asserted registry entry (status: ${d.plan.verificationStatus}). Registry entries are publisher-asserted — review the command before approving.`;if(await aw(aq(d.plan,"authoring-tool",f,!1)),!f.allowed)return aB({installed:!1,consentRequired:!0,message:f.message,plan:d.plan,...g?{verificationWarning:g}:{}});let h=await am(a,c);return await aw(aq(h.plan??d.plan,"authoring-tool",f,h.installed,h.error)),aB({...h,...g?{verificationWarning:g}:{}},!h.installed)}if("install_best_mcp_server"===a){let a="string"==typeof b?.capability?b.capability:"",c=b?.env&&"object"==typeof b.env&&!Array.isArray(b.env)?b.env:void 0;if(!a)return aB({error:'Provide a "capability" search term.'},!0);let d=await as(),e=ap({caller:"authoring-tool",settings:d,registryName:a});if(!e.allowed){let b=(await aj(a)).find(a=>a.installable),d=b?await am(b.name,c,{resolveOnly:!0}):null;return d?.plan&&await aw(aq(d.plan,"authoring-tool",e,!1)),aB({installed:!1,consentRequired:!0,message:e.message,...d?.plan?{plan:d.plan}:{}})}let f=await an(a,c,{onAttempt:async(a,b)=>{a&&await aw(aq(a,"authoring-tool",e,b.installed,b.error))}}),g=f.installed&&!(0,F.nO)(f.plan?.verificationStatus)?`Installed an unverified / self-asserted registry entry (status: ${f.plan?.verificationStatus}).`:void 0;return aB({...f,...g?{verificationWarning:g}:{}},!f.installed)}if("draft_generated_flow"===a){let a=aA(b);if(!a||"object"!=typeof a||Array.isArray(a))return aB({error:'Provide a complete advanced FlowSpec object in "spec".'},!0);let c=await (0,q.jY)(),d=(0,D.oW)(a,c);if(!d.success)return aB({error:"The generated specification could not be compiled.",spec:d.spec,issues:d.issues,hardening:{guardChanges:d.guardChanges,repairChanges:d.repairChanges}},!0);return aB({profile:"advanced",pipeline:"production-generator",saved:!1,rootFlowId:d.flow.id,flow:d.flow,flows:d.flows.map(a=>a.flow),spec:d.spec,validation:d.validation,hardening:{guardChanges:d.guardChanges,repairChanges:d.repairChanges}})}if("validate_flow_spec"===a||"draft_flow"===a||"create_flow"===a){let c=aA(b);if(!c)return aB({error:'Provide a "spec" argument: a SimpleFlowSpec object (or JSON string).'},!0);let d=c&&"object"==typeof c&&!Array.isArray(c)?c:{},e="advanced"===b.profile?"advanced":"simple"===b.profile?"simple":Array.isArray(d.nodes)&&Array.isArray(d.edges)?"advanced":"simple",f=!0===b.keepPills,g=await s(c,{save:"create_flow"===a,keepPills:f,profile:e});if(!g.success)return aB({error:g.error,issues:g.issues??[]},!0);let h=g.flows.length,i=h>1?` (plus ${h-1} nested subflow flow(s))`:"",j={profile:e,flowId:g.flow.id,flowName:g.flow.name,nodeCount:g.flow.nodes.length,edgeCount:g.flow.edges.length,...h>1?{flows:g.flows.map(a=>({id:a.id,name:a.name}))}:{},validation:g.validation,..."draft_flow"===a?{saved:!1,rootFlowId:g.flow.id,flow:g.flow,flows:g.flows}:{},..."create_flow"===a?{saved:g.saved,...g.saved?{note:`Flow "${g.flow.name}"${i} was created. It is callable as a tool on this MCP server (after a fresh tools/list) and as model "flow-${g.flow.name}" on the OpenAI-compatible endpoint.`}:{note:"NOT saved: validation found errors. Fix the issues and call create_flow again."}}:{}};return aB(j,"create_flow"===a&&!g.saved)}return aB({error:`Unknown authoring tool: ${a}`},!0)}catch(b){return ax.error("authoringCallTool failed",{toolName:a,err:b}),aB({error:`Authoring tool failed: ${b instanceof Error?b.message:String(b)}`},!0)}}var aD=c(92018);let aE=(0,h.h)("backend/services/mcp/internalTools");function aF(a,b=!1){return{content:[{type:"text",text:"string"==typeof a?a:JSON.stringify(a,null,2)}],...b?{isError:!0}:{}}}function aG(){return[{name:"list_flow_building_blocks",description:"List models, MCP server/tool references, and existing flows available to a new flow.",inputSchema:{type:"object",properties:{}}},{name:"get_flow_authoring_guide",description:"Fetch the flow-authoring contract only when needed. The simple guide is compact; the advanced guide contains the complete FlowSpec reference.",inputSchema:{type:"object",properties:{profile:{type:"string",enum:["simple","advanced"],description:"Guide to return. Defaults to simple."}}}},{name:"validate_flow_spec",description:"Compile and validate a guided flow without saving. Returns a compact summary and issues. Use draft_flow when the caller needs the complete unsaved draft.",inputSchema:az()},{name:"draft_flow",description:"Compile and validate a flow WITHOUT saving and return the complete draft bundle for review or opening in the Flow Builder.",inputSchema:az()},{name:"draft_generated_flow",description:"Run the production Flow Generator post-processing pipeline on a complete advanced FlowSpec: scratchpad safety guard, structural auto-repair, bounded nested compilation, generated-flow defaults, and whole-bundle validation. Returns the complete UNSAVED draft and hardened spec.",inputSchema:{type:"object",additionalProperties:!1,properties:{spec:{type:"object",description:'A complete advanced FlowSpec authored using get_flow_authoring_guide(profile="advanced").'}},required:["spec"]}},{name:"create_flow",description:"Compile, validate, and save a guided flow. Saving occurs only when validation has no errors. Use list_flow_building_blocks for valid references.",inputSchema:az()},{name:"search_mcp_marketplace",description:"Search the public MCP server registry for new capabilities (voice, browsing, files, email, vision, …). The registry matches the query against server NAMES only (substring) — use short single terms and try several. Returns name, description, whether FLUJO can install it, and which env vars/keys it would require.",inputSchema:{type:"object",properties:{query:{type:"string",description:"Short search term matched against server names."}},required:["query"]}},{name:"install_mcp_server",description:'Install an MCP server from the public registry (by the exact name returned by search_mcp_marketplace) and connect it — this DOWNLOADS AND RUNS a third-party package on the FLUJO host. Installs are gated by consent (SEP-1024): unless this trusted authoring tool is allowed via the mcpAutoInstall settings (trustBrainStem / requireConsent / namespaceAllowlist), the tool returns the exact resolved command + arguments with consentRequired=true INSTEAD of installing, and the caller must obtain explicit approval. Every attempt is written to an audit log (command, args, env NAMES, verification status — never secret values) before any spawn. Returns the FLUJO server name (reference it in FlowSpec "servers") and the tools it provides, or needsEnv when required keys are missing (supply values via the optional "env" argument), or the resolved plan when consent is required. First install can take minutes (package download).',inputSchema:{type:"object",properties:{name:{type:"string",description:'Exact registry name from search results, e.g. "ai.keenable/web-search".'},env:{type:"object",description:"Optional env var values for the server (e.g. required API keys).",additionalProperties:{type:"string"}}},required:["name"]}},{name:"install_best_mcp_server",description:"Install the BEST WORKING MCP server for a capability, unattended — the recommended way to acquire a capability when you don't already have a specific server name. Searches the registry, RANKS candidates by blended quality (GitHub stars + recent activity, npm weekly downloads, registry status), then installs best→worst until one actually boots and exposes tools (the \"works-gate\"): candidates that need unavailable keys, can't be installed, or start with zero tools are skipped automatically. Same consent/audit rules and third-party-code warning as install_mcp_server. Returns the installed server name + its tools and the list of candidates tried, or needsEnv/consentRequired. Prefer this over search+install for headless self-improvement; use install_mcp_server only when you must pin an exact server.",inputSchema:{type:"object",properties:{capability:{type:"string",description:'Short capability term matched against server names, e.g. "youtube", "email", "browser".'},env:{type:"object",description:"Optional env var values shared across attempted servers (e.g. an API key).",additionalProperties:{type:"string"}}},required:["capability"]}},{name:"list_flows",description:"List all flows in this FLUJO instance with lightweight metadata only (id, name, description, node count) and no flow content. Use this to enumerate flows cheaply. Use list_flow_building_blocks only when you need the full authoring catalog (models + servers + flows).",inputSchema:{type:"object",properties:{}}},{name:"execute_flow",description:"Run another FLUJO flow (by name or id) with the given input and return its final output. The run is ephemeral (no chat conversation is created). Use list_flow_building_blocks to see the available flows. Nested runs are limited in depth — a flow cannot recurse through itself indefinitely.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."},input:{type:"string",description:"The message to send to the flow as the user turn."}},required:["flow","input"]}},{name:"read_flow",description:"Read a FLUJO flow's full definition (by name or id): its nodes with their prompts, bound models, attached MCP servers/tools and input/output modes, plus the control and MCP edges. Note this is the COMPILED flow (node ids, not FlowSpec keys) — to change it, author a fresh FlowSpec and call update_flow.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."}},required:["flow"]}},{name:"update_flow",description:"REPLACE an existing FLUJO flow's definition (by name or id) with a newly compiled FlowSpec, keeping the flow's id — so planned executions, subflow nodes and conversations that reference it keep working. The spec format is the same as create_flow/validate_flow_spec (see those tool descriptions); saving is gated on zero validation errors. The replaced definition is archived automatically — list_flow_versions / revert_flow can restore it. Note that manual canvas edits made in the builder are part of what gets replaced. Use read_flow first to see what you are replacing.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id of the flow to replace."},spec:{type:"object",description:"The FlowSpec object (see the create_flow tool description for the format)."}},required:["flow","spec"]}},{name:"list_flow_versions",description:"List a flow's archived versions (by name or id), newest first. A version is created automatically whenever the flow's definition is overwritten (builder save, update_flow, revert_flow) and holds the definition that was replaced. Use read_flow_version to inspect one and revert_flow to restore one.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."}},required:["flow"]}},{name:"read_flow_version",description:"Read one archived version of a flow (see list_flow_versions): the full definition it held before it was replaced, in the same format as read_flow.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."},version:{type:"string",description:"The version id (see list_flow_versions)."}},required:["flow","version"]}},{name:"revert_flow",description:"Restore an archived version (see list_flow_versions) as the flow's CURRENT definition. The definition being reverted away from is archived first, so a revert can itself be undone. References by flow id keep working.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."},version:{type:"string",description:"The version id to restore (see list_flow_versions)."}},required:["flow","version"]}},{name:"delete_flow",description:"PERMANENTLY delete a FLUJO flow (by name or id). This cannot be undone — the flow's version history is deleted with it. Verify the target with list_flow_building_blocks first.",inputSchema:{type:"object",properties:{flow:{type:"string",description:"Flow name or flow id."}},required:["flow"]}},{name:"list_mcp_servers",description:"List the MCP servers configured in this FLUJO instance with their transport, enabled/disabled state and live connection status. Config details (env vars, headers, credentials) are never included.",inputSchema:{type:"object",properties:{}}},{name:"list_mcp_server_tools",description:"List the tools of one configured MCP server (name, description, input schema). Use together with call_mcp_tool for servers that are not bound to this flow.",inputSchema:{type:"object",properties:{server:{type:"string",description:"The FLUJO server name (see list_mcp_servers)."}},required:["server"]}},{name:"call_mcp_tool",description:"Call a tool on any configured MCP server by server name + tool name. This lets you use servers that are not bound to the current flow. Check the tool's input schema with list_mcp_server_tools first.",inputSchema:{type:"object",properties:{server:{type:"string",description:"The FLUJO server name."},tool:{type:"string",description:"The tool name on that server."},args:{type:"object",description:"Arguments for the tool (per its input schema)."},timeout:{type:"number",description:"Optional timeout in seconds."}},required:["server","tool"]}},{name:"restart_mcp_server",description:"Force-reconnect a configured MCP server (tears the connection down and rebuilds it). Useful when a server is in an error state after a config or environment change.",inputSchema:{type:"object",properties:{server:{type:"string",description:"The FLUJO server name."}},required:["server"]}},{name:"set_mcp_server_enabled",description:"Enable or disable a configured MCP server. Disabling disconnects it and prevents any further use; enabling connects it.",inputSchema:{type:"object",properties:{server:{type:"string",description:"The FLUJO server name."},enabled:{type:"boolean",description:"true to enable + connect, false to disable + disconnect."}},required:["server","enabled"]}},{name:"list_models",description:"List the models configured in this FLUJO instance (id, name, display name, description, provider, base URL, context window). API keys are never included. Reference models by id or name in FlowSpecs.",inputSchema:{type:"object",properties:{}}},{name:"list_planned_executions",description:"List the planned (scheduled/triggered) executions in this FLUJO instance with their trigger type, enabled state, armed status and last run outcome.",inputSchema:{type:"object",properties:{}}},{name:"run_planned_execution",description:"Fire a planned execution immediately (by id, see list_planned_executions) and return the run record with its output.",inputSchema:{type:"object",properties:{id:{type:"string",description:"The planned execution id."}},required:["id"]}},{name:"update_planned_execution",description:'Modify an existing planned execution (by id or name, see list_planned_executions). Patch any of: "enabled" (turn the schedule on/off), "prompt" (the run prompt), "flowId" (the flow to run — accepts a flow name or id), "cron" (a convenience for the trigger\'s cron pattern — works for schedule / mcp-poll / url-watch triggers) or a full "trigger" object for complete control. Flow-driven cadence changes are clamped to a minimum interval (a runaway every-second schedule is rejected). The webhook secret token is never returned.',inputSchema:{type:"object",properties:{execution:{type:"string",description:"The planned execution id or name."},enabled:{type:"boolean",description:"Enable or disable the execution."},prompt:{type:"string",description:"The run prompt."},flowId:{type:"string",description:"The flow to run — a flow name or id (resolved to the flow id)."},cron:{type:"string",description:"Cron pattern (croner syntax; 6-field form for seconds) for the trigger's schedule. Applies to schedule / mcp-poll / url-watch triggers."},trigger:{type:"object",description:"Full trigger config object (escape hatch for complete control). Prefer the named fields above."}},required:["execution"]}},{name:"create_planned_execution",description:'Create a new planned execution: bind a flow to a trigger so it runs headlessly. Provide "name", "flow" (a flow name or id), an optional "prompt", optional "enabled" (default true), and EITHER a full "trigger" object OR a convenience "cron" (which creates a schedule trigger). Flow-driven cadence is clamped to a minimum interval. A webhook trigger\'s secret token is minted server-side and never returned.',inputSchema:{type:"object",properties:{name:{type:"string",description:"A name for the planned execution."},flow:{type:"string",description:"The flow to run — a flow name or id."},prompt:{type:"string",description:"The run prompt (may be empty)."},enabled:{type:"boolean",description:"Whether to arm the trigger immediately (default true)."},cron:{type:"string",description:'Cron pattern for a schedule trigger (convenience — use "trigger" for other trigger types).'},trigger:{type:"object",description:"Full trigger config object (schedule / webhook / file-watch / mcp-poll / url-watch)."}},required:["name","flow"]}},{name:"delete_planned_execution",description:"Permanently delete a planned execution (by id or name, see list_planned_executions), along with its run history. This cannot be undone.",inputSchema:{type:"object",properties:{execution:{type:"string",description:"The planned execution id or name."}},required:["execution"]}},{name:"list_conversations",description:"List the chat conversations stored in this FLUJO instance (id, title, bound flow, status, created/updated timestamps), newest first. Use read_conversation to get a transcript.",inputSchema:{type:"object",properties:{limit:{type:"number",description:"Optional maximum number of conversations to return (newest first). Default: all."}}}},{name:"read_conversation",description:'Read one chat conversation\'s transcript by conversation id (see list_conversations). Returns the displayed messages: system prompts are excluded, nested subflow steps carry a "depth" marker, assistant tool calls are summarized. Long conversations return only the most recent messages — raise "limit" to get more.',inputSchema:{type:"object",properties:{conversation:{type:"string",description:"The conversation id."},limit:{type:"number",description:"Maximum number of most-recent messages to return (default 50). The total transcript size is capped regardless."}},required:["conversation"]}},{name:"kv_get",description:'Read a value from FLUJO\'s PERSISTENT key-value store (the ${kv:NAME} store) — state that survives ACROSS flow runs (loop counters, cursors, flags). Returns { found, value }. Defaults to the instance-global board; pass "scope" to target another board (e.g. a flow-folder board id). Values are plain strings, never secrets.',inputSchema:{type:"object",properties:{name:{type:"string",description:"The key to read (an identifier: letters, digits, _ and -, not starting with a digit)."},scope:{type:"string",description:'Optional board id to read from. Defaults to "global".'}},required:["name"]}},{name:"kv_set",description:'Write a value to FLUJO\'s PERSISTENT key-value store (the ${kv:NAME} store) — state that survives ACROSS flow runs. Last-write-wins. Defaults to the instance-global board; pass "scope" to target another board. Values are plain strings (never secrets — use ${global:} for those) and are size-capped; an oversized write is refused with { saved:false, skipped }.',inputSchema:{type:"object",properties:{name:{type:"string",description:"The key to write (an identifier: letters, digits, _ and -, not starting with a digit)."},value:{type:"string",description:"The string value to store."},scope:{type:"string",description:'Optional board id to write to. Defaults to "global".'}},required:["name","value"]}}]}async function aH(a){let b=await i.flowService.loadFlows();return b.find(b=>b.id===a)??b.find(b=>b.name===a)}async function aI(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": a flow name or id.'},!0);let c=await aH(b);if(!c)return aF({error:`No flow named or with id "${b}". Use list_flow_building_blocks to see the available flows.`},!0);let d=global.__flujo_internal_flow_depth??0;if(d>=4)return aF({error:`execute_flow nesting limit (4) reached — refusing to start "${c.name}" to prevent runaway recursion.`},!0);global.__flujo_internal_flow_depth=d+1;try{let b=await (0,m.runFlow)({flowId:c.id,prompt:String(a?.input??""),mode:"ephemeral",flujo:!0,requireApproval:!1});if(b.flowNotFound)return aF({error:`Flow not found: ${b.flowNotFound.name}`},!0);if("error"===b.status)return aF({error:b.error?.message??"Unknown error during flow execution."},!0);return aF(b.outputText??"")}finally{global.__flujo_internal_flow_depth=d}}async function aJ(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": a flow name or id.'},!0);let c=await aH(b);if(!c)return aF({error:`No flow named or with id "${b}".`},!0);let d=await i.flowService.deleteFlow(c.id);return d.success?aF({deleted:!0,flowId:c.id,flowName:c.name}):aF({error:d.error??`Failed to delete flow "${c.name}".`},!0)}function aK(a){let b=a.nodes.map(a=>{let{mcpNodes:b,...c}=a.data?.properties??{};return{id:a.id,type:a.type,label:a.data?.label,...a.data?.description?{description:a.data.description}:{},properties:c}}),c=a.edges.map(a=>{let b=a.data;return{from:a.source,to:a.target,type:b?.edgeType==="mcp"?"mcp":b?.edgeType==="resource"?"resource":"control",...b?.bidirectional?{bidirectional:!0}:{}}});return{id:a.id,name:a.name,...a.description?{description:a.description}:{},nodes:b,edges:c}}async function aL(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": a flow name or id.'},!0);let c=await aH(b);return c?aF({...aK(c),note:"This is the compiled flow (node ids, not FlowSpec keys). To change it, author a fresh FlowSpec and call update_flow — it replaces the whole definition while keeping this flow id."}):aF({error:`No flow named or with id "${b}". Use list_flow_building_blocks to see the available flows.`},!0)}async function aM(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": a flow name or id.'},!0);let c=await aH(b);if(!c)return aF({error:`No flow named or with id "${b}".`},!0);let d=await i.flowService.listFlowVersions(c.id);return aF({flowId:c.id,flowName:c.name,versions:d,...0===d.length?{note:"No archived versions yet — versions appear once the flow's definition is overwritten for the first time."}:{}})}async function aN(a){let b=String(a?.flow??"").trim(),c=String(a?.version??"").trim();if(!b||!c)return aF({error:'Provide "flow" (name or id) and "version" (see list_flow_versions).'},!0);let d=await aH(b);if(!d)return aF({error:`No flow named or with id "${b}".`},!0);let e=await i.flowService.getFlowVersion(d.id,c);return e?aF({versionId:e.versionId,savedAt:e.savedAt,...aK(e.flow)}):aF({error:`No version "${c}" of flow "${d.name}". Use list_flow_versions to see the archived versions.`},!0)}async function aO(a){let b=String(a?.flow??"").trim(),c=String(a?.version??"").trim();if(!b||!c)return aF({error:'Provide "flow" (name or id) and "version" (see list_flow_versions).'},!0);let d=await aH(b);if(!d)return aF({error:`No flow named or with id "${b}".`},!0);let e=await i.flowService.revertFlow(d.id,c);return e.success?aF({reverted:!0,flowId:d.id,versionId:c,note:"The definition that was just replaced has been archived too, so this revert can itself be undone via list_flow_versions / revert_flow."}):aF({error:e.error??`Failed to revert flow "${d.name}".`},!0)}async function aP(a){let b=String(a?.flow??"").trim();if(!b)return aF({error:'Provide "flow": the name or id of the flow to replace.'},!0);let c=function(a){let b=a?.spec;if("string"==typeof b)try{return JSON.parse(b)}catch{return null}return b??null}(a);if(!c)return aF({error:'Provide a "spec" argument: a FlowSpec object (or a JSON string of one).'},!0);let d=await aH(b);if(!d)return aF({error:`No flow named or with id "${b}". Use list_flow_building_blocks to see the available flows.`},!0);let e=await s(c,{save:!0,updateFlowId:d.id});return e.success?aF({flowId:e.flow.id,flowName:e.flow.name,nodeCount:e.flow.nodes.length,edgeCount:e.flow.edges.length,validation:e.validation,saved:e.saved,...e.saved?{note:`Flow "${e.flow.name}" was replaced (id ${e.flow.id} kept — existing references keep working).`}:{note:"NOT saved: validation found errors. The existing flow is unchanged. Fix the issues and call update_flow again."}},!e.saved):aF({error:e.error,issues:e.issues??[]},!0)}async function aQ(a){let b=await a.loadServerConfigs();return Array.isArray(b)?aF(await Promise.all(b.map(async b=>{let c="unknown";try{c=(await a.getServerStatus(b.name)).status}catch(a){aE.debug(`list_mcp_servers: getServerStatus failed for ${b.name}`,a)}return{name:b.name,transport:b.transport,enabled:!b.disabled,status:c,...b.builtIn?{builtIn:!0}:{}}}))):aF({error:b.error??"Failed to load server configs."},!0)}async function aR(a,b,c){let d=String(b?.server??"").trim();if(!d)return aF({error:'Provide "server": a FLUJO server name.'},!0);if(d===aD._)return aF(aG().map(a=>({name:a.name,description:a.description,inputSchema:a.inputSchema})));let{tools:e,error:f}=await a.listServerTools(d,"host"===c?"all":c);return f?aF({error:f},!0):aF(e.map(a=>({name:a.name,description:a.description,inputSchema:a.inputSchema})))}async function aS(a,b,c){let d=String(b?.server??"").trim(),e=String(b?.tool??"").trim();if(!d||!e)return aF({error:'Provide "server" and "tool".'},!0);if(d===aD._)return aF({error:`"${aD._}" is this server — call its tools directly instead of through call_mcp_tool.`},!0);let f=b?.args&&"object"==typeof b.args&&!Array.isArray(b.args)?b.args:{},g="number"==typeof b?.timeout?b.timeout:void 0,h=await a.callTool(d,e,f,g,void 0,void 0,void 0,c);if(!h.success)return aF({error:h.error??`Tool call failed on ${d}.`},!0);let i=h.data;return i&&Array.isArray(i.content)?i:aF(i??{ok:!0})}async function aT(a,b){let c=String(b?.server??"").trim();if(!c)return aF({error:'Provide "server": a FLUJO server name.'},!0);if(c===aD._)return aF({ok:!0,note:`"${aD._}" is the built-in server — it is always running.`});let d=await a.forceReconnect(c);if(!d.success)return aF({error:d.error??`Failed to restart ${c}.`},!0);let e=await a.getServerStatus(c);return aF({restarted:!0,server:c,status:e.status})}async function aU(a,b){let c=String(b?.server??"").trim(),d=b?.enabled;if(!c||"boolean"!=typeof d)return aF({error:'Provide "server" (string) and "enabled" (boolean).'},!0);if(c===aD._)return aF({error:`The built-in "${aD._}" server cannot be disabled.`},!0);let e=await a.updateServerConfig(c,{disabled:!d});return"error"in e?aF({error:e.error},!0):aF({server:c,enabled:d})}async function aV(){try{let a=(await i.flowService.loadFlows()).map(a=>({id:a.id,name:a.name,...a.description?{description:(0,q.xv)(a.description,q.bD)}:{},nodeCount:a.nodes?.length??0}));return aF(a)}catch(a){return aE.error("list_flows failed",a),aF({error:"Failed to load flows."},!0)}}async function aW(){return aF((await j.modelService.loadModels()).map(a=>({id:a.id,name:a.name,...a.displayName?{displayName:a.displayName}:{},...a.description?{description:a.description}:{},...a.provider?{provider:a.provider}:{},...a.baseUrl?{baseUrl:a.baseUrl}:{},...a.contextWindow?{contextWindow:a.contextWindow}:{}})))}async function aX(){return aF((await (0,k.z)().list()).map(({execution:a,status:b,lastRun:c})=>({id:a.id,name:a.name,enabled:a.enabled,flowId:a.flowId,triggerType:a.trigger?.type,armed:b?.armed??!1,...c?{lastRun:{status:c.status,firedAt:c.firedAt,...c.error?{error:c.error}:{}}}:{}})))}async function aY(a){let b=String(a?.id??"").trim();if(!b)return aF({error:'Provide "id": a planned execution id (see list_planned_executions).'},!0);let{record:c,error:d}=await (0,k.z)().runNow(b);return d||!c?aF({error:d??"Run failed."},!0):aF({runId:c.runId,status:c.status,firedAt:c.firedAt,...c.finishedAt?{finishedAt:c.finishedAt}:{},...c.outputText?{outputText:c.outputText}:{},...c.error?{error:c.error}:{}})}async function aZ(a){let b=await (0,k.z)().list(),c=b.find(b=>b.execution.id===a),d=b.find(b=>b.execution.name===a);return(c??d)?.execution??null}function a$(a){return{id:a.id,name:a.name,enabled:a.enabled,flowId:a.flowId,triggerType:a.trigger?.type}}function a_(a,b){try{let c=(0,l.Z9)(a,b,5).map(a=>new Date(a).getTime()),d=1/0;for(let a=1;a<c.length;a++){let b=c[a]-c[a-1];b>0&&b<d&&(d=b)}return Number.isFinite(d)?d:null}catch{return null}}function a0(a){let b=null;return("schedule"===a.type||"url-watch"===a.type?a.cron&&(b=a_(a.cron,a.timezone)):"mcp-poll"===a.type&&(a.cron?b=a_(a.cron,a.timezone):"number"==typeof a.intervalMs&&(b=a.intervalMs)),null!==b&&b<6e4)?`Cadence too fast: the trigger would fire about every ${Math.round(b/1e3)}s, but flow-driven schedule changes are clamped to a minimum interval of 60s. Choose a slower cadence (change it from the Planned Executions page for a faster one).`:null}async function a1(a){let b,c=String(a?.execution??"").trim();if(!c)return aF({error:'Provide "execution": a planned execution id or name (see list_planned_executions).'},!0);let d=await aZ(c);if(!d)return aF({error:`No planned execution with id or name "${c}". Use list_planned_executions to see them.`},!0);let e={};"boolean"==typeof a?.enabled&&(e.enabled=a.enabled),"string"==typeof a?.prompt&&(e.prompt=a.prompt);let f=String(a?.flowId??a?.flow??"").trim();if(f){let a=await aH(f);if(!a)return aF({error:`No flow named or with id "${f}". Use list_flow_building_blocks to see the flows.`},!0);e.flowId=a.id}a?.trigger&&"object"==typeof a.trigger&&!Array.isArray(a.trigger)&&(b=a.trigger);let g="string"==typeof a?.cron?a.cron.trim():"";if(g){let a=b??d.trigger;if("schedule"!==a.type&&"mcp-poll"!==a.type&&"url-watch"!==a.type)return aF({error:`The "${a.type}" trigger has no schedule to change with "cron". Pass a full "trigger" object instead.`},!0);b={...a,cron:g}}if(b){let a=a0(b);if(a)return aF({error:a},!0);e.trigger=b}if(0===Object.keys(e).length)return aF({error:"Nothing to update. Provide at least one of: enabled, prompt, flowId, cron, trigger."},!0);let h=await (0,k.z)().update(d.id,e);return h.error||!h.execution?aF({error:h.error??"Update failed."},!0):aF({updated:!0,...a$(h.execution)})}async function a2(a){let b,c=String(a?.name??"").trim();if(!c)return aF({error:'Provide "name": a name for the planned execution.'},!0);let d=String(a?.flow??a?.flowId??"").trim();if(!d)return aF({error:'Provide "flow": a flow name or id to run.'},!0);let e=await aH(d);if(!e)return aF({error:`No flow named or with id "${d}". Use list_flow_building_blocks to see the flows.`},!0);if(a?.trigger&&"object"==typeof a.trigger&&!Array.isArray(a.trigger))b=a.trigger;else{let c="string"==typeof a?.cron?a.cron.trim():"";if(!c)return aF({error:'Provide a "trigger" object or a "cron" pattern (which creates a schedule trigger).'},!0);b={type:"schedule",cron:c}}let f=a0(b);if(f)return aF({error:f},!0);let g={name:c,enabled:"boolean"!=typeof a?.enabled||a.enabled,flowId:e.id,prompt:"string"==typeof a?.prompt?a.prompt:"",trigger:b},h=await (0,k.z)().create(g);return h.error||!h.execution?aF({error:h.error??"Create failed."},!0):aF({created:!0,...a$(h.execution)})}async function a3(a){let b=String(a?.execution??"").trim();if(!b)return aF({error:'Provide "execution": a planned execution id or name (see list_planned_executions).'},!0);let c=await aZ(b);if(!c)return aF({error:`No planned execution with id or name "${b}". Use list_planned_executions to see them.`},!0);let d=await (0,k.z)().delete(c.id);return d.success?aF({deleted:!0,id:c.id,name:c.name}):aF({error:d.error??`Failed to delete "${c.name}".`},!0)}async function a4(a){let b,c=f().join((0,A.getDataDir)(),"db","conversations");try{b=await g.promises.readdir(c)}catch(a){if("ENOENT"===a.code)return aF([]);return aF({error:`Failed to list conversations: ${a instanceof Error?a.message:String(a)}`},!0)}let d=(await Promise.all(b.filter(a=>a.endsWith(".json")).map(async a=>{try{let b=await g.promises.readFile(f().join(c,a),"utf-8"),d=JSON.parse(b),e=d.conversationId||a.replace(/\.json$/,""),h=d.status;return"running"===h&&0===z.$.currentSeq(e)&&(h="error"),{id:e,title:d.title||"Untitled Conversation",flowId:d.flowId||null,...h?{status:h}:{},createdAt:d.createdAt||0,updatedAt:d.updatedAt||0}}catch(b){return aE.warn(`list_conversations: skipping unreadable conversation file ${a}`,b),null}}))).filter(a=>null!==a).sort((a,b)=>b.updatedAt-a.updatedAt),e="number"==typeof a?.limit&&a.limit>0?Math.floor(a.limit):void 0;return aF(e?d.slice(0,e):d)}async function a5(a){let b=String(a?.conversation??"").trim();if(!b)return aF({error:'Provide "conversation": a conversation id (see list_conversations).'},!0);await (0,v.flushConversationLog)(b);let c=await y(b);if(!c)return aF({error:`No conversation with id "${b}". Use list_conversations to see the stored conversations.`},!0);let d=await (0,v.readConversationLog)(b),e=d?(0,v.projectMessages)(d):[],f=e.length>0?e:(c.messages||[]).filter(a=>"system"!==a.role),g="number"==typeof a?.limit&&a.limit>0?Math.floor(a.limit):50,h=[],i=0;for(let a=f.length-1;a>=0&&h.length<g;a--){let b=function(a){let b="";"string"==typeof a.content?b=a.content:Array.isArray(a.content)&&(b=a.content.map(a=>"text"in a&&"string"==typeof a.text?a.text:"").filter(Boolean).join("\n"));let c={role:a.role,...b?{content:b}:{},...a.timestamp?{timestamp:a.timestamp}:{},...a.depth?{depth:a.depth}:{}};return"assistant"===a.role&&Array.isArray(a.tool_calls)&&a.tool_calls.length>0&&(c.toolCalls=a.tool_calls.map(a=>{let b="function"in a?a.function:void 0,c=b&&"string"==typeof b.arguments?b.arguments:void 0;return{id:a.id,...b?.name?{name:b.name}:{},...void 0!==c?{arguments:c.length>2e3?c.slice(0,2e3)+"…[truncated]":c}:{}}})),"tool"===a.role&&a.tool_call_id&&(c.toolCallId=a.tool_call_id),c}(f[a]),c=JSON.stringify(b).length;if(h.length>0&&i+c>1e5)break;h.push(b),i+=c}return h.reverse(),aF({id:c.conversationId||b,title:c.title||"Untitled Conversation",flowId:c.flowId||null,...c.status?{status:c.status}:{},createdAt:c.createdAt||0,updatedAt:c.updatedAt||0,totalMessages:f.length,...h.length<f.length?{note:`Returning the ${h.length} most recent of ${f.length} messages — raise "limit" to get more.`}:{},messages:h})}let a6=/^[A-Za-z0-9_-]{1,64}$/,a7=/^[A-Za-z_][\w-]*$/;async function a8(a){let b="string"==typeof a.name?a.name.trim():"",c="string"==typeof a.scope&&a.scope.trim()?a.scope.trim():"global";if(!a7.test(b))return aF({error:'kv_get requires a valid "name" (letters, digits, _ and -, not starting with a digit).'},!0);if(!a6.test(c))return aF({error:`Invalid kv scope id: ${c}`},!0);let d=await (0,B.M3)(c,b);return aF({scope:c,name:b,found:void 0!==d,value:d??null})}async function a9(a){let b="string"==typeof a.name?a.name.trim():"",c="string"==typeof a.scope&&a.scope.trim()?a.scope.trim():"global",d="string"==typeof a.value?a.value:null==a.value?"":String(a.value);if(!a7.test(b))return aF({error:'kv_set requires a valid "name" (letters, digits, _ and -, not starting with a digit).'},!0);if(!a6.test(c))return aF({error:`Invalid kv scope id: ${c}`},!0);let e=await (0,B.or)(c,b,d);return"skipped"in e?aF({scope:c,name:b,saved:!1,skipped:e.skipped},!0):aF({scope:c,name:b,saved:!0,size:e.size})}async function ba(a,b,c,d="host"){try{if(ay.includes(b))return await aC(b,c);switch(b){case"list_flows":return await aV();case"execute_flow":return await aI(c);case"read_flow":return await aL(c);case"update_flow":return await aP(c);case"list_flow_versions":return await aM(c);case"read_flow_version":return await aN(c);case"revert_flow":return await aO(c);case"delete_flow":return await aJ(c);case"list_mcp_servers":return await aQ(a);case"list_mcp_server_tools":return await aR(a,c,d);case"call_mcp_tool":return await aS(a,c,d);case"restart_mcp_server":return await aT(a,c);case"set_mcp_server_enabled":return await aU(a,c);case"list_models":return await aW();case"list_planned_executions":return await aX();case"run_planned_execution":return await aY(c);case"update_planned_execution":return await a1(c);case"create_planned_execution":return await a2(c);case"delete_planned_execution":return await a3(c);case"list_conversations":return await a4(c);case"read_conversation":return await a5(c);case"kv_get":return await a8(c);case"kv_set":return await a9(c);default:return aF({error:`Unknown tool on the built-in FLUJO server: ${b}`},!0)}}catch(a){return aE.error("internalCallTool failed",{toolName:b,err:a}),aF({error:`Tool failed: ${a instanceof Error?a.message:String(a)}`},!0)}}}};
|