@desplega.ai/agent-swarm 1.49.0 → 1.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/openapi.json +2070 -728
- package/package.json +10 -1
- package/src/agentmail/handlers.ts +65 -10
- package/src/agentmail/templates.ts +111 -0
- package/src/be/db.ts +1233 -7
- package/src/be/migrations/014_prompt_templates.sql +33 -0
- package/src/be/migrations/015_workflow_workspace.sql +3 -0
- package/src/be/migrations/016_active_session_runner_session.sql +4 -0
- package/src/be/migrations/017_channel_activity_cursors.sql +6 -0
- package/src/be/migrations/018_fix_seed_double_version.sql +30 -0
- package/src/be/migrations/019_skills.sql +65 -0
- package/src/be/migrations/020_approval_requests.sql +41 -0
- package/src/be/seed.ts +62 -0
- package/src/be/skill-parser.ts +70 -0
- package/src/be/skill-sync.ts +106 -0
- package/src/commands/runner.ts +320 -132
- package/src/commands/templates.ts +172 -0
- package/src/github/handlers.ts +292 -77
- package/src/github/mentions-aliases.test.ts +73 -0
- package/src/github/mentions.test.ts +3 -3
- package/src/github/mentions.ts +32 -6
- package/src/github/templates.ts +398 -0
- package/src/gitlab/handlers.ts +63 -22
- package/src/gitlab/templates.ts +140 -0
- package/src/heartbeat/heartbeat.ts +19 -10
- package/src/heartbeat/templates.ts +30 -0
- package/src/http/active-sessions.ts +27 -0
- package/src/http/approval-requests.ts +247 -0
- package/src/http/config.ts +3 -3
- package/src/http/index.ts +9 -2
- package/src/http/poll.ts +135 -14
- package/src/http/prompt-templates.ts +412 -0
- package/src/http/schedules.ts +35 -0
- package/src/http/skills.ts +479 -0
- package/src/http/workflows.ts +8 -0
- package/src/linear/sync.ts +28 -4
- package/src/linear/templates.ts +47 -0
- package/src/prompts/base-prompt.ts +41 -490
- package/src/prompts/registry.ts +57 -0
- package/src/prompts/resolver.ts +296 -0
- package/src/prompts/session-templates.ts +604 -0
- package/src/providers/claude-adapter.ts +15 -2
- package/src/providers/pi-mono-extension.ts +5 -1
- package/src/scheduler/scheduler.ts +125 -91
- package/src/server.ts +44 -0
- package/src/slack/assistant.ts +7 -4
- package/src/slack/channel-activity.ts +177 -0
- package/src/slack/handlers.ts +21 -6
- package/src/slack/templates.ts +55 -0
- package/src/tests/approval-requests.test.ts +735 -0
- package/src/tests/artifact-sdk.test.ts +12 -12
- package/src/tests/base-prompt.test.ts +49 -49
- package/src/tests/channel-activity.test.ts +363 -0
- package/src/tests/heartbeat.test.ts +1 -0
- package/src/tests/linear-webhook.test.ts +7 -3
- package/src/tests/pool-session-logs.test.ts +199 -0
- package/src/tests/prompt-template-github.test.ts +682 -0
- package/src/tests/prompt-template-remaining.test.ts +504 -0
- package/src/tests/prompt-template-resolver.test.ts +621 -0
- package/src/tests/prompt-template-session.test.ts +363 -0
- package/src/tests/prompt-templates-db.test.ts +616 -0
- package/src/tests/self-improvement.test.ts +8 -7
- package/src/tests/skill-parser.test.ts +178 -0
- package/src/tests/skill-sync.test.ts +171 -0
- package/src/tests/slack-metadata-inheritance.test.ts +1 -1
- package/src/tests/slack-thread-followups.test.ts +1 -1
- package/src/tests/structured-output.test.ts +0 -4
- package/src/tests/tool-annotations.test.ts +2 -1
- package/src/tests/update-profile-agentid.test.ts +248 -0
- package/src/tests/update-profile-auth.test.ts +195 -0
- package/src/tests/workflow-async-v2.test.ts +126 -4
- package/src/tests/workflow-definition-validation.test.ts +76 -0
- package/src/tests/workflow-executors.test.ts +4 -2
- package/src/tests/workflow-retry-v2.test.ts +1 -1
- package/src/tests/workflow-schedule-trigger.test.ts +104 -0
- package/src/tests/workflow-workspace.test.ts +272 -0
- package/src/tools/prompt-templates/delete.ts +86 -0
- package/src/tools/prompt-templates/get.ts +89 -0
- package/src/tools/prompt-templates/index.ts +5 -0
- package/src/tools/prompt-templates/list.ts +95 -0
- package/src/tools/prompt-templates/preview.ts +84 -0
- package/src/tools/prompt-templates/set.ts +117 -0
- package/src/tools/request-human-input.ts +106 -0
- package/src/tools/skills/index.ts +11 -0
- package/src/tools/skills/skill-create.ts +105 -0
- package/src/tools/skills/skill-delete.ts +67 -0
- package/src/tools/skills/skill-get.ts +75 -0
- package/src/tools/skills/skill-install-remote.ts +152 -0
- package/src/tools/skills/skill-install.ts +101 -0
- package/src/tools/skills/skill-list.ts +77 -0
- package/src/tools/skills/skill-publish.ts +123 -0
- package/src/tools/skills/skill-search.ts +43 -0
- package/src/tools/skills/skill-sync-remote.ts +128 -0
- package/src/tools/skills/skill-uninstall.ts +60 -0
- package/src/tools/skills/skill-update.ts +128 -0
- package/src/tools/store-progress.ts +22 -4
- package/src/tools/task-action.ts +20 -0
- package/src/tools/templates.ts +53 -0
- package/src/tools/tool-config.ts +23 -0
- package/src/tools/update-profile.ts +106 -34
- package/src/tools/workflows/create-workflow.ts +19 -1
- package/src/tools/workflows/update-workflow.ts +16 -1
- package/src/types.ts +109 -2
- package/src/workflows/definition.ts +30 -12
- package/src/workflows/engine.ts +40 -14
- package/src/workflows/executors/agent-task.ts +14 -3
- package/src/workflows/executors/human-in-the-loop.ts +160 -0
- package/src/workflows/executors/registry.ts +2 -0
- package/src/workflows/index.ts +1 -1
- package/src/workflows/recovery.ts +72 -0
- package/src/workflows/resume.ts +162 -12
- package/src/workflows/triggers.ts +31 -2
- package/src/workflows/version.ts +2 -0
- package/.claude/settings.json +0 -84
- package/.claude/settings.local.json +0 -117
- package/.dockerignore +0 -61
- package/.editorconfig +0 -15
- package/.entire/settings.json +0 -4
- package/.env.docker.example +0 -56
- package/.env.example +0 -78
- package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -78
- package/.github/ISSUE_TEMPLATE/community-template.yml +0 -77
- package/.github/ISSUE_TEMPLATE/config.yml +0 -8
- package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -60
- package/.github/PULL_REQUEST_TEMPLATE/community-template.md +0 -29
- package/.github/workflows/ci.yml +0 -52
- package/.github/workflows/docker-and-deploy.yml +0 -132
- package/.github/workflows/merge-gate.yml +0 -233
- package/.opencode/plugins/entire.ts +0 -133
- package/.superset/config.json +0 -6
- package/.wts-config.json +0 -4
- package/.wts-setup.ts +0 -171
- package/CHANGELOG.md +0 -447
- package/CLAUDE.md +0 -521
- package/CONTRIBUTING.md +0 -315
- package/DEPLOYMENT.md +0 -622
- package/Dockerfile +0 -65
- package/Dockerfile.worker +0 -189
- package/MCP.md +0 -841
- package/UI.md +0 -40
- package/api-entrypoint.sh +0 -56
- package/assets/agent-swarm-logo-orange.png +0 -0
- package/assets/agent-swarm-logo.png +0 -0
- package/assets/agent-swarm.mp4 +0 -0
- package/assets/agent-swarm.png +0 -0
- package/biome.json +0 -39
- package/deploy/DEPLOY.md +0 -60
- package/deploy/agent-swarm.service +0 -17
- package/deploy/docker-push.ts +0 -30
- package/deploy/install.ts +0 -85
- package/deploy/prod-db.ts +0 -42
- package/deploy/uninstall.ts +0 -12
- package/deploy/update.ts +0 -21
- package/depot.json +0 -1
- package/docker-compose.example.yml +0 -350
- package/docker-compose.local.yml +0 -119
- package/docker-entrypoint.sh +0 -632
- package/docs-site/app/api/search/route.ts +0 -4
- package/docs-site/app/docs/[[...slug]]/page.tsx +0 -87
- package/docs-site/app/docs/layout.tsx +0 -12
- package/docs-site/app/globals.css +0 -24
- package/docs-site/app/layout.config.tsx +0 -34
- package/docs-site/app/layout.tsx +0 -119
- package/docs-site/app/llms-full.txt/route.ts +0 -11
- package/docs-site/app/llms.mdx/docs/[[...slug]]/route.ts +0 -24
- package/docs-site/app/llms.txt/route.ts +0 -8
- package/docs-site/app/page.tsx +0 -5
- package/docs-site/app/robots.ts +0 -13
- package/docs-site/app/sitemap.ts +0 -37
- package/docs-site/components/api-page.client.tsx +0 -4
- package/docs-site/components/api-page.tsx +0 -7
- package/docs-site/components/mdx/mermaid.tsx +0 -55
- package/docs-site/content/docs/(documentation)/architecture/agents.mdx +0 -117
- package/docs-site/content/docs/(documentation)/architecture/hooks.mdx +0 -77
- package/docs-site/content/docs/(documentation)/architecture/memory.mdx +0 -96
- package/docs-site/content/docs/(documentation)/architecture/meta.json +0 -4
- package/docs-site/content/docs/(documentation)/architecture/overview.mdx +0 -172
- package/docs-site/content/docs/(documentation)/concepts/epics.mdx +0 -98
- package/docs-site/content/docs/(documentation)/concepts/meta.json +0 -4
- package/docs-site/content/docs/(documentation)/concepts/scheduling.mdx +0 -136
- package/docs-site/content/docs/(documentation)/concepts/services.mdx +0 -104
- package/docs-site/content/docs/(documentation)/concepts/task-lifecycle.mdx +0 -148
- package/docs-site/content/docs/(documentation)/concepts/workflows.mdx +0 -209
- package/docs-site/content/docs/(documentation)/contributing.mdx +0 -158
- package/docs-site/content/docs/(documentation)/getting-started.mdx +0 -157
- package/docs-site/content/docs/(documentation)/guides/agentmail-integration.mdx +0 -79
- package/docs-site/content/docs/(documentation)/guides/deployment.mdx +0 -171
- package/docs-site/content/docs/(documentation)/guides/github-integration.mdx +0 -81
- package/docs-site/content/docs/(documentation)/guides/gitlab-integration.mdx +0 -93
- package/docs-site/content/docs/(documentation)/guides/linear-integration.mdx +0 -98
- package/docs-site/content/docs/(documentation)/guides/meta.json +0 -13
- package/docs-site/content/docs/(documentation)/guides/sentry-integration.mdx +0 -52
- package/docs-site/content/docs/(documentation)/guides/slack-integration.mdx +0 -179
- package/docs-site/content/docs/(documentation)/guides/x402-payments.mdx +0 -154
- package/docs-site/content/docs/(documentation)/index.mdx +0 -65
- package/docs-site/content/docs/(documentation)/meta.json +0 -19
- package/docs-site/content/docs/(documentation)/reference/cli.mdx +0 -241
- package/docs-site/content/docs/(documentation)/reference/environment-variables.mdx +0 -205
- package/docs-site/content/docs/(documentation)/reference/mcp-tools.mdx +0 -449
- package/docs-site/content/docs/(documentation)/reference/meta.json +0 -4
- package/docs-site/content/docs/api-reference/active-sessions.mdx +0 -9
- package/docs-site/content/docs/api-reference/agents.mdx +0 -9
- package/docs-site/content/docs/api-reference/channels.mdx +0 -9
- package/docs-site/content/docs/api-reference/config.mdx +0 -9
- package/docs-site/content/docs/api-reference/debug.mdx +0 -9
- package/docs-site/content/docs/api-reference/ecosystem.mdx +0 -9
- package/docs-site/content/docs/api-reference/epics.mdx +0 -9
- package/docs-site/content/docs/api-reference/index.mdx +0 -32
- package/docs-site/content/docs/api-reference/memory.mdx +0 -9
- package/docs-site/content/docs/api-reference/meta.json +0 -25
- package/docs-site/content/docs/api-reference/poll.mdx +0 -9
- package/docs-site/content/docs/api-reference/repos.mdx +0 -9
- package/docs-site/content/docs/api-reference/schedules.mdx +0 -9
- package/docs-site/content/docs/api-reference/session-data.mdx +0 -9
- package/docs-site/content/docs/api-reference/stats.mdx +0 -9
- package/docs-site/content/docs/api-reference/tasks.mdx +0 -9
- package/docs-site/content/docs/api-reference/trackers.mdx +0 -9
- package/docs-site/content/docs/api-reference/webhooks.mdx +0 -9
- package/docs-site/content/docs/api-reference/workflows.mdx +0 -9
- package/docs-site/content/docs/meta.json +0 -3
- package/docs-site/lib/get-llm-text.ts +0 -10
- package/docs-site/lib/openapi.ts +0 -23
- package/docs-site/lib/source.ts +0 -8
- package/docs-site/mdx-components.tsx +0 -13
- package/docs-site/next.config.mjs +0 -29
- package/docs-site/package.json +0 -35
- package/docs-site/pnpm-lock.yaml +0 -5407
- package/docs-site/postcss.config.mjs +0 -8
- package/docs-site/public/logo.png +0 -0
- package/docs-site/scripts/generate-docs.ts +0 -171
- package/docs-site/source.config.ts +0 -17
- package/docs-site/tsconfig.json +0 -46
- package/ecosystem.config.cjs +0 -66
- package/landing/next.config.ts +0 -14
- package/landing/package.json +0 -31
- package/landing/pnpm-lock.yaml +0 -1091
- package/landing/postcss.config.mjs +0 -8
- package/landing/public/apple-touch-icon.png +0 -0
- package/landing/public/favicon.ico +0 -0
- package/landing/public/logo.png +0 -0
- package/landing/public/og-image.png +0 -0
- package/landing/public/omghost-desplega.svg +0 -30
- package/landing/public/omghost-openfort.svg +0 -9
- package/landing/src/app/actions/waitlist.ts +0 -25
- package/landing/src/app/blog/openfort-hackathon/page.tsx +0 -863
- package/landing/src/app/blog/page.tsx +0 -162
- package/landing/src/app/blog/swarm-metrics/page.tsx +0 -685
- package/landing/src/app/examples/page.tsx +0 -174
- package/landing/src/app/examples/x402/page.tsx +0 -456
- package/landing/src/app/globals.css +0 -122
- package/landing/src/app/layout.tsx +0 -134
- package/landing/src/app/page.tsx +0 -27
- package/landing/src/app/robots.ts +0 -13
- package/landing/src/app/sitemap.ts +0 -44
- package/landing/src/components/architecture.tsx +0 -163
- package/landing/src/components/cta.tsx +0 -52
- package/landing/src/components/features.tsx +0 -160
- package/landing/src/components/footer.tsx +0 -100
- package/landing/src/components/hero.tsx +0 -217
- package/landing/src/components/how-it-works.tsx +0 -165
- package/landing/src/components/navbar.tsx +0 -147
- package/landing/src/components/waitlist.tsx +0 -110
- package/landing/src/components/why-choose.tsx +0 -149
- package/landing/src/components/workshops.tsx +0 -328
- package/landing/src/lib/utils.ts +0 -6
- package/landing/tsconfig.json +0 -41
- package/misc/transcripts/2026-03-09-pi-mono-e2e-verification.md +0 -154
- package/new-ui/CLAUDE.md +0 -92
- package/new-ui/README.md +0 -73
- package/new-ui/biome.json +0 -42
- package/new-ui/components.json +0 -21
- package/new-ui/index.html +0 -25
- package/new-ui/package.json +0 -49
- package/new-ui/pnpm-lock.yaml +0 -4845
- package/new-ui/public/logo.png +0 -0
- package/new-ui/src/api/client.ts +0 -814
- package/new-ui/src/api/hooks/index.ts +0 -64
- package/new-ui/src/api/hooks/use-agents.ts +0 -58
- package/new-ui/src/api/hooks/use-channels.ts +0 -115
- package/new-ui/src/api/hooks/use-config-api.ts +0 -46
- package/new-ui/src/api/hooks/use-costs.ts +0 -122
- package/new-ui/src/api/hooks/use-db-query.ts +0 -29
- package/new-ui/src/api/hooks/use-epics.ts +0 -75
- package/new-ui/src/api/hooks/use-repos.ts +0 -61
- package/new-ui/src/api/hooks/use-schedules.ts +0 -81
- package/new-ui/src/api/hooks/use-services.ts +0 -16
- package/new-ui/src/api/hooks/use-stats.ts +0 -27
- package/new-ui/src/api/hooks/use-tasks.ts +0 -89
- package/new-ui/src/api/hooks/use-workflows.ts +0 -109
- package/new-ui/src/api/types.ts +0 -549
- package/new-ui/src/app/App.tsx +0 -13
- package/new-ui/src/app/providers.tsx +0 -32
- package/new-ui/src/app/router.tsx +0 -52
- package/new-ui/src/components/layout/app-header.tsx +0 -47
- package/new-ui/src/components/layout/app-sidebar.tsx +0 -128
- package/new-ui/src/components/layout/breadcrumbs.tsx +0 -57
- package/new-ui/src/components/layout/config-guard.tsx +0 -22
- package/new-ui/src/components/layout/root-layout.tsx +0 -40
- package/new-ui/src/components/layout/swarm-switcher.tsx +0 -85
- package/new-ui/src/components/shared/command-menu.tsx +0 -131
- package/new-ui/src/components/shared/data-grid.tsx +0 -141
- package/new-ui/src/components/shared/empty-state.tsx +0 -24
- package/new-ui/src/components/shared/error-boundary.tsx +0 -72
- package/new-ui/src/components/shared/json-viewer.tsx +0 -47
- package/new-ui/src/components/shared/name-connection-modal.tsx +0 -99
- package/new-ui/src/components/shared/page-skeleton.tsx +0 -16
- package/new-ui/src/components/shared/session-log-viewer.tsx +0 -364
- package/new-ui/src/components/shared/stats-bar.tsx +0 -132
- package/new-ui/src/components/shared/status-badge.tsx +0 -131
- package/new-ui/src/components/shared/usage-summary.tsx +0 -179
- package/new-ui/src/components/ui/alert-dialog.tsx +0 -176
- package/new-ui/src/components/ui/alert.tsx +0 -60
- package/new-ui/src/components/ui/avatar.tsx +0 -96
- package/new-ui/src/components/ui/badge.tsx +0 -46
- package/new-ui/src/components/ui/button.tsx +0 -62
- package/new-ui/src/components/ui/card.tsx +0 -75
- package/new-ui/src/components/ui/command.tsx +0 -160
- package/new-ui/src/components/ui/dialog.tsx +0 -143
- package/new-ui/src/components/ui/dropdown-menu.tsx +0 -226
- package/new-ui/src/components/ui/input.tsx +0 -21
- package/new-ui/src/components/ui/label.tsx +0 -19
- package/new-ui/src/components/ui/progress.tsx +0 -26
- package/new-ui/src/components/ui/scroll-area.tsx +0 -54
- package/new-ui/src/components/ui/select.tsx +0 -175
- package/new-ui/src/components/ui/separator.tsx +0 -28
- package/new-ui/src/components/ui/sheet.tsx +0 -132
- package/new-ui/src/components/ui/sidebar.tsx +0 -691
- package/new-ui/src/components/ui/skeleton.tsx +0 -13
- package/new-ui/src/components/ui/sonner.tsx +0 -35
- package/new-ui/src/components/ui/switch.tsx +0 -33
- package/new-ui/src/components/ui/table.tsx +0 -92
- package/new-ui/src/components/ui/tabs.tsx +0 -79
- package/new-ui/src/components/ui/textarea.tsx +0 -18
- package/new-ui/src/components/ui/tooltip.tsx +0 -51
- package/new-ui/src/components/workflows/action-node.tsx +0 -53
- package/new-ui/src/components/workflows/condition-node.tsx +0 -50
- package/new-ui/src/components/workflows/graph-utils.ts +0 -124
- package/new-ui/src/components/workflows/json-tree.tsx +0 -189
- package/new-ui/src/components/workflows/node-styles.ts +0 -10
- package/new-ui/src/components/workflows/step-detail-sheet.tsx +0 -87
- package/new-ui/src/components/workflows/trigger-node.tsx +0 -41
- package/new-ui/src/components/workflows/workflow-graph.tsx +0 -65
- package/new-ui/src/hooks/use-auto-scroll.ts +0 -82
- package/new-ui/src/hooks/use-config.ts +0 -203
- package/new-ui/src/hooks/use-keyboard-shortcuts.ts +0 -41
- package/new-ui/src/hooks/use-mobile.ts +0 -19
- package/new-ui/src/hooks/use-theme.ts +0 -60
- package/new-ui/src/lib/config.ts +0 -188
- package/new-ui/src/lib/slugs.ts +0 -71
- package/new-ui/src/lib/utils.ts +0 -120
- package/new-ui/src/main.tsx +0 -11
- package/new-ui/src/pages/agents/[id]/page.tsx +0 -492
- package/new-ui/src/pages/agents/page.tsx +0 -134
- package/new-ui/src/pages/chat/page.tsx +0 -674
- package/new-ui/src/pages/config/page.tsx +0 -1109
- package/new-ui/src/pages/dashboard/page.tsx +0 -454
- package/new-ui/src/pages/debug/page.tsx +0 -275
- package/new-ui/src/pages/epics/[id]/page.tsx +0 -809
- package/new-ui/src/pages/epics/page.tsx +0 -321
- package/new-ui/src/pages/not-found/page.tsx +0 -18
- package/new-ui/src/pages/repos/page.tsx +0 -369
- package/new-ui/src/pages/schedules/[id]/page.tsx +0 -664
- package/new-ui/src/pages/schedules/page.tsx +0 -477
- package/new-ui/src/pages/services/page.tsx +0 -128
- package/new-ui/src/pages/tasks/[id]/page.tsx +0 -670
- package/new-ui/src/pages/tasks/page.tsx +0 -592
- package/new-ui/src/pages/usage/page.tsx +0 -195
- package/new-ui/src/pages/workflow-runs/[id]/page.tsx +0 -363
- package/new-ui/src/pages/workflows/[id]/page.tsx +0 -417
- package/new-ui/src/pages/workflows/page.tsx +0 -266
- package/new-ui/src/styles/ag-grid.css +0 -36
- package/new-ui/src/styles/globals.css +0 -213
- package/new-ui/test-results/.last-run.json +0 -4
- package/new-ui/tsconfig.app.json +0 -34
- package/new-ui/tsconfig.json +0 -4
- package/new-ui/tsconfig.node.json +0 -26
- package/new-ui/vercel.json +0 -4
- package/new-ui/vite.config.ts +0 -28
- package/plugin/README.md +0 -1
- package/plugin/build-pi-skills.ts +0 -233
- package/plugin/hooks/hooks.json +0 -71
- package/prek.toml +0 -75
- package/pyproject.toml +0 -9
- package/scripts/check-db-boundary.sh +0 -60
- package/scripts/e2e-docker-provider.ts +0 -820
- package/scripts/e2e-io-schemas-test.ts +0 -807
- package/scripts/e2e-provider-test.ts +0 -220
- package/scripts/e2e-workflow-redesign.sh +0 -229
- package/scripts/e2e-workflow-test.sh +0 -285
- package/scripts/e2e-workflow-test.ts +0 -857
- package/scripts/generate-mcp-docs.ts +0 -415
- package/scripts/generate-openapi.ts +0 -26
- package/scripts/measure-tool-tokens.ts +0 -118
- package/scripts/x402-e2e-test.ts +0 -195
- package/scripts/x402-test-server.ts +0 -236
- package/scripts/x402-testnet-e2e.ts +0 -668
- package/slack-manifest.json +0 -88
- package/templates-ui/README.md +0 -46
- package/templates-ui/components.json +0 -17
- package/templates-ui/eslint.config.mjs +0 -18
- package/templates-ui/next.config.ts +0 -7
- package/templates-ui/package.json +0 -35
- package/templates-ui/pnpm-lock.yaml +0 -4571
- package/templates-ui/postcss.config.mjs +0 -7
- package/templates-ui/public/file.svg +0 -1
- package/templates-ui/public/globe.svg +0 -1
- package/templates-ui/public/logo.png +0 -0
- package/templates-ui/public/next.svg +0 -1
- package/templates-ui/public/vercel.svg +0 -1
- package/templates-ui/public/window.svg +0 -1
- package/templates-ui/src/app/[category]/[name]/page.tsx +0 -89
- package/templates-ui/src/app/api/templates/[...slug]/route.ts +0 -52
- package/templates-ui/src/app/api/templates/route.ts +0 -18
- package/templates-ui/src/app/builder/page.tsx +0 -37
- package/templates-ui/src/app/globals.css +0 -94
- package/templates-ui/src/app/layout.tsx +0 -79
- package/templates-ui/src/app/page.tsx +0 -38
- package/templates-ui/src/app/robots.ts +0 -11
- package/templates-ui/src/app/sitemap.ts +0 -31
- package/templates-ui/src/components/compose-builder.tsx +0 -442
- package/templates-ui/src/components/compose-preview.tsx +0 -117
- package/templates-ui/src/components/file-preview.tsx +0 -77
- package/templates-ui/src/components/footer.tsx +0 -40
- package/templates-ui/src/components/header.tsx +0 -41
- package/templates-ui/src/components/template-card.tsx +0 -87
- package/templates-ui/src/components/template-detail.tsx +0 -125
- package/templates-ui/src/components/template-gallery.tsx +0 -263
- package/templates-ui/src/components/ui/badge.tsx +0 -36
- package/templates-ui/src/components/ui/button.tsx +0 -57
- package/templates-ui/src/components/ui/card.tsx +0 -76
- package/templates-ui/src/components/ui/separator.tsx +0 -31
- package/templates-ui/src/components/ui/tooltip.tsx +0 -32
- package/templates-ui/src/lib/compose-generator.ts +0 -241
- package/templates-ui/src/lib/templates.ts +0 -137
- package/templates-ui/src/lib/utils.ts +0 -6
- package/templates-ui/tsconfig.json +0 -34
- package/thoughts/research/2026-02-28-openfort-viem-x402-research.md +0 -679
- package/thoughts/research/2026-02-28-x402-payments-research.md +0 -686
- package/thoughts/researcher/plans/2026-02-20-agent-self-improvement-plan.md +0 -282
- package/thoughts/researcher/research/2026-02-20-agent-self-improvement.md +0 -492
- package/thoughts/shared/plans/.gitkeep +0 -0
- package/thoughts/shared/plans/2025-12-18-slack-integration.md +0 -1195
- package/thoughts/shared/plans/2025-12-19-agent-log-streaming.md +0 -732
- package/thoughts/shared/plans/2025-12-19-role-based-swarm-plugin.md +0 -361
- package/thoughts/shared/plans/2025-12-20-mobile-responsive-ui.md +0 -501
- package/thoughts/shared/plans/2025-12-20-startup-team-swarm.md +0 -560
- package/thoughts/shared/plans/2025-12-23-runner-level-polling.md +0 -934
- package/thoughts/shared/plans/2025-12-23-runner-session-logs.md +0 -1000
- package/thoughts/shared/plans/2025-12-23-worker-lead-spawn-triggers.md +0 -568
- package/thoughts/shared/plans/2026-01-09-inverse-teleport.md +0 -1516
- package/thoughts/shared/plans/2026-01-12-agent-rename-pm2-control.md +0 -1133
- package/thoughts/shared/plans/2026-01-12-github-app-integration.md +0 -380
- package/thoughts/shared/plans/2026-01-12-lead-inbox-model.md +0 -876
- package/thoughts/shared/plans/2026-01-12-ralph-wiggum-integration.md +0 -463
- package/thoughts/shared/plans/2026-01-13-agent-concurrency.md +0 -691
- package/thoughts/shared/plans/2026-01-13-github-assignment-handling.md +0 -690
- package/thoughts/shared/plans/2026-01-13-prevent-duplicate-trigger-processing.md +0 -1071
- package/thoughts/shared/plans/2026-01-14-fix-slack-thread-context.md +0 -507
- package/thoughts/shared/plans/2026-01-15-scheduled-tasks-implementation.md +0 -565
- package/thoughts/shared/plans/2026-01-15-usage-cost-tracking-ui.md +0 -1479
- package/thoughts/shared/plans/2026-01-16-epics-feature-implementation.md +0 -1230
- package/thoughts/shared/plans/2026-02-26-mcp-tool-context-reduction.md +0 -282
- package/thoughts/shared/plans/2026-03-02-claude-context-mode-integration.md +0 -328
- package/thoughts/shared/plans/2026-03-02-code-level-heartbeat.md +0 -224
- package/thoughts/shared/research/.gitkeep +0 -0
- package/thoughts/shared/research/2025-01-09-inverse-teleport-plan-review.md +0 -420
- package/thoughts/shared/research/2025-12-18-slack-integration.md +0 -442
- package/thoughts/shared/research/2025-12-19-agent-log-streaming.md +0 -339
- package/thoughts/shared/research/2025-12-19-agent-secrets-cli-research.md +0 -390
- package/thoughts/shared/research/2025-12-21-gemini-cli-integration.md +0 -376
- package/thoughts/shared/research/2025-12-22-runner-loop-architecture.md +0 -582
- package/thoughts/shared/research/2025-12-22-setup-experience-improvements.md +0 -264
- package/thoughts/shared/research/2026-01-13-lead-duplicate-trigger-processing.md +0 -223
- package/thoughts/shared/research/2026-01-14-lead-slack-thread-context.md +0 -277
- package/thoughts/shared/research/2026-01-15-ai-tracker-agent-swarm-integration.md +0 -376
- package/thoughts/shared/research/2026-01-15-auto-starting-processes-in-worker-containers.md +0 -787
- package/thoughts/shared/research/2026-01-15-scheduled-tasks.md +0 -390
- package/thoughts/shared/research/2026-01-16-epics-feature-research.md +0 -437
- package/thoughts/shared/research/2026-02-26-cliffy-mcp-tools.md +0 -159
- package/thoughts/shared/research/2026-03-03-database-migration-system-refactor.md +0 -337
- package/thoughts/swarm-researcher/plans/2026-02-23-openclaw-improvements-plan.md +0 -778
- package/thoughts/swarm-researcher/plans/2026-02-26-artifacts-localtunnel-plan.md +0 -1269
- package/thoughts/swarm-researcher/research/2026-02-23-openclaw-vs-agent-swarm-comparison.md +0 -411
- package/thoughts/swarm-researcher/research/2026-02-26-artifacts-localtunnel.md +0 -724
- package/thoughts/taras/brainstorms/2026-03-20-prompt-template-registry.md +0 -443
- package/thoughts/taras/brainstorms/2026-03-20-setup-cli-onboarding.md +0 -307
- package/thoughts/taras/plans/2026-01-22-agent-swarm-schemas.md +0 -98
- package/thoughts/taras/plans/2026-01-28-per-worker-claude-md.md +0 -617
- package/thoughts/taras/plans/2026-01-28-sentry-cli-integration.md +0 -214
- package/thoughts/taras/plans/2026-02-20-auto-improvement.md +0 -803
- package/thoughts/taras/plans/2026-02-20-env-management.md +0 -538
- package/thoughts/taras/plans/2026-02-20-memory-system.md +0 -882
- package/thoughts/taras/plans/2026-02-20-repos-knowledge.md +0 -806
- package/thoughts/taras/plans/2026-02-20-session-attach.md +0 -647
- package/thoughts/taras/plans/2026-02-20-worker-identity.md +0 -820
- package/thoughts/taras/plans/2026-02-25-feat-new-ui-visual-redesign-plan.md +0 -768
- package/thoughts/taras/plans/2026-03-04-fix-buildSystemPrompt-missing-fields.md +0 -77
- package/thoughts/taras/plans/2026-03-04-new-ui-missing-actions.md +0 -543
- package/thoughts/taras/plans/2026-03-06-one-time-scheduled-tasks.md +0 -373
- package/thoughts/taras/plans/2026-03-08-memory-self-improvement-enhancements.md +0 -512
- package/thoughts/taras/plans/2026-03-08-pi-mono-provider-implementation.md +0 -919
- package/thoughts/taras/plans/2026-03-09-templates-registry.md +0 -723
- package/thoughts/taras/plans/2026-03-10-task-working-directory.md +0 -371
- package/thoughts/taras/plans/2026-03-11-archil-per-agent-write-strategy.md +0 -621
- package/thoughts/taras/plans/2026-03-12-eliminate-inbox-route-to-tasks.md +0 -61
- package/thoughts/taras/plans/2026-03-12-slack-thread-followup-additive.md +0 -488
- package/thoughts/taras/plans/2026-03-13-slack-ai-improvements.md +0 -644
- package/thoughts/taras/plans/2026-03-16-route-wrapper-openapi.md +0 -636
- package/thoughts/taras/plans/2026-03-17-multi-api-config.md +0 -444
- package/thoughts/taras/plans/2026-03-18-agent-fs-integration.md +0 -591
- package/thoughts/taras/plans/2026-03-18-debug-db-explorer.md +0 -446
- package/thoughts/taras/plans/2026-03-18-workflow-redesign.md +0 -987
- package/thoughts/taras/plans/2026-03-19-compound-learnings.md +0 -403
- package/thoughts/taras/plans/2026-03-19-ticket-tracker-linear-integration.md +0 -860
- package/thoughts/taras/plans/2026-03-19-workflow-io-schemas-and-bugs.md +0 -899
- package/thoughts/taras/plans/2026-03-20-setup-cli-onboarding.md +0 -874
- package/thoughts/taras/plans/2026-03-20-workflow-structured-output-validation-workspace.md +0 -723
- package/thoughts/taras/research/2026-01-22-vercel-cli-integration.md +0 -287
- package/thoughts/taras/research/2026-01-27-excessive-polling-issue.md +0 -311
- package/thoughts/taras/research/2026-01-28-per-worker-claude-md.md +0 -383
- package/thoughts/taras/research/2026-01-28-sentry-cli-integration.md +0 -240
- package/thoughts/taras/research/2026-02-19-agent-native-swarm-architecture.md +0 -390
- package/thoughts/taras/research/2026-02-19-swarm-gaps-implementation.md +0 -594
- package/thoughts/taras/research/2026-02-25-dashboard-ui-design-best-practices.md +0 -825
- package/thoughts/taras/research/2026-02-26-task-detail-page-redesign.md +0 -393
- package/thoughts/taras/research/2026-03-03-new-ui-missing-actions.md +0 -168
- package/thoughts/taras/research/2026-03-05-pi-mono-provider-research.md +0 -230
- package/thoughts/taras/research/2026-03-06-workflow-engine-design.md +0 -445
- package/thoughts/taras/research/2026-03-08-drive-loop-concept.md +0 -375
- package/thoughts/taras/research/2026-03-08-pi-mono-deep-dive.md +0 -869
- package/thoughts/taras/research/2026-03-09-templates-registry.md +0 -373
- package/thoughts/taras/research/2026-03-10-agent-working-directory.md +0 -223
- package/thoughts/taras/research/2026-03-10-configurable-event-prompts.md +0 -339
- package/thoughts/taras/research/2026-03-11-archil-production-setup.md +0 -181
- package/thoughts/taras/research/2026-03-11-archil-shared-disk-write-strategies.md +0 -437
- package/thoughts/taras/research/2026-03-13-slack-ai-features.md +0 -258
- package/thoughts/taras/research/2026-03-16-openapi-docs-generation.md +0 -335
- package/thoughts/taras/research/2026-03-16-route-wrapper-openapi.md +0 -670
- package/thoughts/taras/research/2026-03-16-slack-thread-followups-e2e.md +0 -54
- package/thoughts/taras/research/2026-03-18-agent-fs-integration.md +0 -558
- package/thoughts/taras/research/2026-03-18-linear-integration-finalization.md +0 -526
- package/thoughts/taras/research/2026-03-18-workflow-redesign.md +0 -797
- package/thoughts/taras/research/2026-03-19-workflow-node-io-schemas-and-bugs.md +0 -563
- package/thoughts/taras/research/2026-03-19-workflow-structured-output-validation-workspace.md +0 -486
- package/thoughts/taras/research/2026-03-20-prompt-template-registry.md +0 -469
- package/tsconfig.json +0 -37
|
@@ -1,807 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* E2E Workflow I/O Schemas Test
|
|
4
|
-
*
|
|
5
|
-
* Spins up the full API server with a clean DB, then exercises:
|
|
6
|
-
* 1. triggerSchema validation (missing, wrong type, valid)
|
|
7
|
-
* 2. Node inputs mapping + data flow between nodes
|
|
8
|
-
* 3. inputSchema validation
|
|
9
|
-
* 4. Unresolved token diagnostics
|
|
10
|
-
* 5. Static data flow validation (non-existent/downstream references)
|
|
11
|
-
* 6. Deep interpolation (nested objects, arrays)
|
|
12
|
-
* 7. Convergence with conditional branches
|
|
13
|
-
* 8. Backward compatibility (no schemas)
|
|
14
|
-
* 9. outputSchema validation
|
|
15
|
-
*
|
|
16
|
-
* Usage:
|
|
17
|
-
* bun scripts/e2e-io-schemas-test.ts
|
|
18
|
-
* E2E_PORT=13098 bun scripts/e2e-io-schemas-test.ts
|
|
19
|
-
*/
|
|
20
|
-
import { $, type Subprocess } from "bun";
|
|
21
|
-
|
|
22
|
-
// ─── Config ─────────────────────────────────────────────────────────────────
|
|
23
|
-
const PORT = process.env.E2E_PORT || "13098";
|
|
24
|
-
const API_KEY = process.env.API_KEY || "123123";
|
|
25
|
-
const BASE_URL = `http://localhost:${PORT}`;
|
|
26
|
-
const DB_PATH = `/tmp/e2e-io-schemas-${Date.now()}.sqlite`;
|
|
27
|
-
const AGENT_ID = crypto.randomUUID();
|
|
28
|
-
|
|
29
|
-
// ─── State ──────────────────────────────────────────────────────────────────
|
|
30
|
-
let apiProc: Subprocess | null = null;
|
|
31
|
-
let pass = 0;
|
|
32
|
-
let fail = 0;
|
|
33
|
-
let cleaningUp = false;
|
|
34
|
-
|
|
35
|
-
// ─── Helpers ────────────────────────────────────────────────────────────────
|
|
36
|
-
function log(msg: string) {
|
|
37
|
-
console.log(`\x1b[1;34m[E2E]\x1b[0m ${msg}`);
|
|
38
|
-
}
|
|
39
|
-
function logPass(name: string) {
|
|
40
|
-
console.log(`\x1b[1;32m PASS\x1b[0m ${name}`);
|
|
41
|
-
pass++;
|
|
42
|
-
}
|
|
43
|
-
function logFail(name: string, detail: string) {
|
|
44
|
-
console.log(`\x1b[1;31m FAIL\x1b[0m ${name}: ${detail}`);
|
|
45
|
-
fail++;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function assert(condition: boolean, name: string, detail = "") {
|
|
49
|
-
if (condition) logPass(name);
|
|
50
|
-
else logFail(name, detail || "assertion failed");
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function assertEq(actual: unknown, expected: unknown, name: string) {
|
|
54
|
-
if (actual === expected) logPass(name);
|
|
55
|
-
else logFail(name, `expected '${expected}', got '${actual}'`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async function api<T = unknown>(
|
|
59
|
-
method: string,
|
|
60
|
-
path: string,
|
|
61
|
-
body?: unknown,
|
|
62
|
-
): Promise<{ status: number; data: T }> {
|
|
63
|
-
const opts: RequestInit = {
|
|
64
|
-
method,
|
|
65
|
-
headers: {
|
|
66
|
-
"Content-Type": "application/json",
|
|
67
|
-
Authorization: `Bearer ${API_KEY}`,
|
|
68
|
-
"X-Agent-ID": AGENT_ID,
|
|
69
|
-
},
|
|
70
|
-
};
|
|
71
|
-
if (body !== undefined) opts.body = JSON.stringify(body);
|
|
72
|
-
const res = await fetch(`${BASE_URL}${path}`, opts);
|
|
73
|
-
let data: T;
|
|
74
|
-
try {
|
|
75
|
-
data = (await res.json()) as T;
|
|
76
|
-
} catch {
|
|
77
|
-
data = null as T;
|
|
78
|
-
}
|
|
79
|
-
return { status: res.status, data };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async function waitForServer(url: string, timeoutMs = 30_000): Promise<void> {
|
|
83
|
-
const start = Date.now();
|
|
84
|
-
while (Date.now() - start < timeoutMs) {
|
|
85
|
-
try {
|
|
86
|
-
const res = await fetch(`${url}/api/agents`, {
|
|
87
|
-
headers: { Authorization: `Bearer ${API_KEY}` },
|
|
88
|
-
});
|
|
89
|
-
if (res.ok) return;
|
|
90
|
-
} catch {
|
|
91
|
-
// not ready yet
|
|
92
|
-
}
|
|
93
|
-
await Bun.sleep(500);
|
|
94
|
-
}
|
|
95
|
-
throw new Error(`Server at ${url} did not start within ${timeoutMs}ms`);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ─── Cleanup ────────────────────────────────────────────────────────────────
|
|
99
|
-
async function cleanup() {
|
|
100
|
-
if (cleaningUp) return;
|
|
101
|
-
cleaningUp = true;
|
|
102
|
-
log("Cleaning up...");
|
|
103
|
-
|
|
104
|
-
if (apiProc) {
|
|
105
|
-
try {
|
|
106
|
-
apiProc.kill("SIGTERM");
|
|
107
|
-
await Bun.sleep(1000);
|
|
108
|
-
if (apiProc.exitCode === null) apiProc.kill("SIGKILL");
|
|
109
|
-
} catch {
|
|
110
|
-
// already dead
|
|
111
|
-
}
|
|
112
|
-
apiProc = null;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
for (const suffix of ["", "-wal", "-shm"]) {
|
|
116
|
-
try {
|
|
117
|
-
await $`rm -f ${DB_PATH}${suffix}`.quiet();
|
|
118
|
-
} catch {
|
|
119
|
-
// fine
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
log("Cleanup complete.");
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
process.on("SIGINT", async () => {
|
|
127
|
-
await cleanup();
|
|
128
|
-
process.exit(fail > 0 ? 1 : 0);
|
|
129
|
-
});
|
|
130
|
-
process.on("SIGTERM", async () => {
|
|
131
|
-
await cleanup();
|
|
132
|
-
process.exit(fail > 0 ? 1 : 0);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// ─── Start API ──────────────────────────────────────────────────────────────
|
|
136
|
-
async function startApi() {
|
|
137
|
-
log(`Starting API server on port ${PORT} with DB at ${DB_PATH}...`);
|
|
138
|
-
apiProc = Bun.spawn(["bun", "src/http.ts"], {
|
|
139
|
-
cwd: `${import.meta.dir}/..`,
|
|
140
|
-
env: {
|
|
141
|
-
...process.env,
|
|
142
|
-
PORT,
|
|
143
|
-
API_KEY,
|
|
144
|
-
DATABASE_PATH: DB_PATH,
|
|
145
|
-
SLACK_DISABLE: "true",
|
|
146
|
-
GITHUB_DISABLE: "true",
|
|
147
|
-
HEARTBEAT_DISABLE: "true",
|
|
148
|
-
AGENTMAIL_DISABLE: "true",
|
|
149
|
-
},
|
|
150
|
-
stdout: "pipe",
|
|
151
|
-
stderr: "pipe",
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
const decoder = new TextDecoder();
|
|
155
|
-
const pipeOutput = async (stream: ReadableStream<Uint8Array>, prefix: string) => {
|
|
156
|
-
const reader = stream.getReader();
|
|
157
|
-
let buffer = "";
|
|
158
|
-
try {
|
|
159
|
-
while (true) {
|
|
160
|
-
const { done, value } = await reader.read();
|
|
161
|
-
if (done) break;
|
|
162
|
-
buffer += decoder.decode(value, { stream: true });
|
|
163
|
-
const lines = buffer.split("\n");
|
|
164
|
-
buffer = lines.pop() || "";
|
|
165
|
-
for (const line of lines) {
|
|
166
|
-
if (line.trim()) console.log(` \x1b[90m${prefix}\x1b[0m ${line}`);
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
} catch {
|
|
170
|
-
// stream closed
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
pipeOutput(apiProc.stdout, "[API]");
|
|
174
|
-
pipeOutput(apiProc.stderr, "[API]");
|
|
175
|
-
|
|
176
|
-
await waitForServer(BASE_URL);
|
|
177
|
-
log("API server is up.");
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// ─── Response Types ─────────────────────────────────────────────────────────
|
|
181
|
-
interface WfJson {
|
|
182
|
-
id: string;
|
|
183
|
-
name: string;
|
|
184
|
-
enabled: boolean;
|
|
185
|
-
}
|
|
186
|
-
interface TriggerJson {
|
|
187
|
-
runId: string;
|
|
188
|
-
}
|
|
189
|
-
interface RunJson {
|
|
190
|
-
run: {
|
|
191
|
-
id: string;
|
|
192
|
-
status: string;
|
|
193
|
-
error?: string;
|
|
194
|
-
};
|
|
195
|
-
steps: Array<{
|
|
196
|
-
id: string;
|
|
197
|
-
nodeId: string;
|
|
198
|
-
status: string;
|
|
199
|
-
error?: string;
|
|
200
|
-
output?: unknown;
|
|
201
|
-
diagnostics?: string;
|
|
202
|
-
}>;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// ─── Helper: create, trigger, wait, fetch run ───────────────────────────────
|
|
206
|
-
async function createAndTrigger(
|
|
207
|
-
name: string,
|
|
208
|
-
definition: unknown,
|
|
209
|
-
triggerData: unknown,
|
|
210
|
-
extra: Record<string, unknown> = {},
|
|
211
|
-
): Promise<{ wfId: string; runId: string; run: RunJson }> {
|
|
212
|
-
const { data: wf } = await api<WfJson>("POST", "/api/workflows", {
|
|
213
|
-
name,
|
|
214
|
-
definition,
|
|
215
|
-
...extra,
|
|
216
|
-
});
|
|
217
|
-
const { status, data: triggerResult } = await api<TriggerJson>(
|
|
218
|
-
"POST",
|
|
219
|
-
`/api/workflows/${wf.id}/trigger`,
|
|
220
|
-
triggerData,
|
|
221
|
-
);
|
|
222
|
-
if (status !== 201) {
|
|
223
|
-
return {
|
|
224
|
-
wfId: wf.id,
|
|
225
|
-
runId: "",
|
|
226
|
-
run: { run: { id: "", status: "trigger_failed", error: `status ${status}` }, steps: [] },
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
// Wait for async execution
|
|
230
|
-
await Bun.sleep(2000);
|
|
231
|
-
const { data: run } = await api<RunJson>("GET", `/api/workflow-runs/${triggerResult.runId}`);
|
|
232
|
-
return { wfId: wf.id, runId: triggerResult.runId, run };
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// ─── Test 1: triggerSchema ──────────────────────────────────────────────────
|
|
236
|
-
|
|
237
|
-
async function testTriggerSchema() {
|
|
238
|
-
log("Test 1: triggerSchema validation");
|
|
239
|
-
|
|
240
|
-
const triggerSchema = {
|
|
241
|
-
type: "object",
|
|
242
|
-
properties: {
|
|
243
|
-
repo: { type: "string" },
|
|
244
|
-
priority: { type: "number" },
|
|
245
|
-
},
|
|
246
|
-
required: ["repo"],
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
const definition = {
|
|
250
|
-
nodes: [
|
|
251
|
-
{
|
|
252
|
-
id: "echo",
|
|
253
|
-
type: "script",
|
|
254
|
-
inputs: { repo: "trigger.repo" },
|
|
255
|
-
config: { runtime: "bash", script: "echo {{repo}}" },
|
|
256
|
-
},
|
|
257
|
-
],
|
|
258
|
-
};
|
|
259
|
-
|
|
260
|
-
// Create workflow with triggerSchema
|
|
261
|
-
const { data: wf } = await api<WfJson>("POST", "/api/workflows", {
|
|
262
|
-
name: "e2e-trigger-schema",
|
|
263
|
-
definition,
|
|
264
|
-
triggerSchema,
|
|
265
|
-
});
|
|
266
|
-
assert(!!wf.id, "1a. Created workflow with triggerSchema");
|
|
267
|
-
|
|
268
|
-
// Trigger with missing required field "repo" -> 400
|
|
269
|
-
const { status: s1 } = await api("POST", `/api/workflows/${wf.id}/trigger`, {
|
|
270
|
-
priority: 5,
|
|
271
|
-
});
|
|
272
|
-
assertEq(s1, 400, "1b. Trigger with missing repo returns 400");
|
|
273
|
-
|
|
274
|
-
// Trigger with wrong type repo: 123 (number instead of string) -> 400
|
|
275
|
-
const { status: s2 } = await api("POST", `/api/workflows/${wf.id}/trigger`, {
|
|
276
|
-
repo: 123,
|
|
277
|
-
});
|
|
278
|
-
assertEq(s2, 400, "1c. Trigger with repo=123 (wrong type) returns 400");
|
|
279
|
-
|
|
280
|
-
// Trigger with valid payload -> 201
|
|
281
|
-
const { status: s3, data: trigResult } = await api<TriggerJson>(
|
|
282
|
-
"POST",
|
|
283
|
-
`/api/workflows/${wf.id}/trigger`,
|
|
284
|
-
{ repo: "my-repo", priority: 3 },
|
|
285
|
-
);
|
|
286
|
-
assertEq(s3, 201, "1d. Trigger with valid payload returns 201");
|
|
287
|
-
assert(typeof trigResult.runId === "string" && trigResult.runId.length > 0, "1e. Got runId");
|
|
288
|
-
|
|
289
|
-
// Wait and verify run executed
|
|
290
|
-
await Bun.sleep(2000);
|
|
291
|
-
const { data: run } = await api<RunJson>("GET", `/api/workflow-runs/${trigResult.runId}`);
|
|
292
|
-
assertEq(run.run.status, "completed", "1f. Valid trigger run completed");
|
|
293
|
-
|
|
294
|
-
// Verify the script output contains the repo value
|
|
295
|
-
const echoStep = run.steps.find((s) => s.nodeId === "echo");
|
|
296
|
-
const echoOutput = echoStep?.output as { stdout?: string } | undefined;
|
|
297
|
-
assert(
|
|
298
|
-
echoOutput?.stdout?.includes("my-repo") ?? false,
|
|
299
|
-
"1g. Script output contains repo value",
|
|
300
|
-
`got stdout: ${echoOutput?.stdout}`,
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
// Cleanup
|
|
304
|
-
await api("DELETE", `/api/workflows/${wf.id}`);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// ─── Test 2: Node inputs mapping + data flow ────────────────────────────────
|
|
308
|
-
|
|
309
|
-
async function testInputsMappingDataFlow() {
|
|
310
|
-
log("Test 2: Node inputs mapping + data flow");
|
|
311
|
-
|
|
312
|
-
const definition = {
|
|
313
|
-
nodes: [
|
|
314
|
-
{
|
|
315
|
-
id: "fetch",
|
|
316
|
-
type: "script",
|
|
317
|
-
inputs: { repo: "trigger.repo" },
|
|
318
|
-
config: { runtime: "bash", script: "echo {{repo}}" },
|
|
319
|
-
next: "process",
|
|
320
|
-
},
|
|
321
|
-
{
|
|
322
|
-
id: "process",
|
|
323
|
-
type: "script",
|
|
324
|
-
inputs: { code: "fetch.stdout" },
|
|
325
|
-
config: { runtime: "bash", script: "echo processed: {{code}}" },
|
|
326
|
-
},
|
|
327
|
-
],
|
|
328
|
-
};
|
|
329
|
-
|
|
330
|
-
const { run, wfId } = await createAndTrigger("e2e-inputs-flow", definition, {
|
|
331
|
-
repo: "agent-swarm",
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
assertEq(run.run.status, "completed", "2a. Data flow run completed");
|
|
335
|
-
assert(run.steps.length >= 2, "2b. Both steps executed");
|
|
336
|
-
|
|
337
|
-
// Check fetch step
|
|
338
|
-
const fetchStep = run.steps.find((s) => s.nodeId === "fetch");
|
|
339
|
-
const fetchOutput = fetchStep?.output as { stdout?: string } | undefined;
|
|
340
|
-
assert(
|
|
341
|
-
fetchOutput?.stdout?.includes("agent-swarm") ?? false,
|
|
342
|
-
"2c. Fetch step output contains trigger value",
|
|
343
|
-
`got stdout: ${fetchOutput?.stdout}`,
|
|
344
|
-
);
|
|
345
|
-
|
|
346
|
-
// Check process step - should contain the fetch output passed through
|
|
347
|
-
const processStep = run.steps.find((s) => s.nodeId === "process");
|
|
348
|
-
const processOutput = processStep?.output as { stdout?: string } | undefined;
|
|
349
|
-
assert(
|
|
350
|
-
processOutput?.stdout?.includes("agent-swarm") ?? false,
|
|
351
|
-
"2d. Process step output contains trigger value passed through fetch",
|
|
352
|
-
`got stdout: ${processOutput?.stdout}`,
|
|
353
|
-
);
|
|
354
|
-
assert(
|
|
355
|
-
processOutput?.stdout?.includes("processed:") ?? false,
|
|
356
|
-
"2e. Process step output has 'processed:' prefix",
|
|
357
|
-
`got stdout: ${processOutput?.stdout}`,
|
|
358
|
-
);
|
|
359
|
-
|
|
360
|
-
await api("DELETE", `/api/workflows/${wfId}`);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// ─── Test 3: inputSchema validation ─────────────────────────────────────────
|
|
364
|
-
|
|
365
|
-
async function testInputSchemaValidation() {
|
|
366
|
-
log("Test 3: inputSchema validation");
|
|
367
|
-
|
|
368
|
-
const definition = {
|
|
369
|
-
nodes: [
|
|
370
|
-
{
|
|
371
|
-
id: "greet",
|
|
372
|
-
type: "script",
|
|
373
|
-
inputs: { msg: "trigger.msg" },
|
|
374
|
-
inputSchema: {
|
|
375
|
-
type: "object",
|
|
376
|
-
properties: { msg: { type: "string" } },
|
|
377
|
-
required: ["msg"],
|
|
378
|
-
},
|
|
379
|
-
config: { runtime: "bash", script: "echo {{msg}}" },
|
|
380
|
-
},
|
|
381
|
-
],
|
|
382
|
-
};
|
|
383
|
-
|
|
384
|
-
// 3a. Trigger with valid input { msg: "hello" } -> success
|
|
385
|
-
const { run: run1, wfId: wfId1 } = await createAndTrigger("e2e-input-schema-valid", definition, {
|
|
386
|
-
msg: "hello",
|
|
387
|
-
});
|
|
388
|
-
assertEq(run1.run.status, "completed", "3a. Valid inputSchema run completed");
|
|
389
|
-
const greetStep1 = run1.steps.find((s) => s.nodeId === "greet");
|
|
390
|
-
const greetOutput1 = greetStep1?.output as { stdout?: string } | undefined;
|
|
391
|
-
assert(
|
|
392
|
-
greetOutput1?.stdout?.includes("hello") ?? false,
|
|
393
|
-
"3b. Valid input produces correct output",
|
|
394
|
-
`got stdout: ${greetOutput1?.stdout}`,
|
|
395
|
-
);
|
|
396
|
-
await api("DELETE", `/api/workflows/${wfId1}`);
|
|
397
|
-
|
|
398
|
-
// 3c. Trigger with wrong type { msg: 123 } -> step should fail
|
|
399
|
-
// The inputSchema checks the interpolation context which includes trigger.msg
|
|
400
|
-
// Since the node has inputs: { msg: "trigger.msg" }, the resolved value will
|
|
401
|
-
// be number 123, and the inputSchema requires msg to be string
|
|
402
|
-
const definitionStrict = {
|
|
403
|
-
nodes: [
|
|
404
|
-
{
|
|
405
|
-
id: "greet",
|
|
406
|
-
type: "script",
|
|
407
|
-
inputs: { msg: "trigger.msg" },
|
|
408
|
-
inputSchema: {
|
|
409
|
-
type: "object",
|
|
410
|
-
properties: { msg: { type: "string" } },
|
|
411
|
-
required: ["msg"],
|
|
412
|
-
},
|
|
413
|
-
config: { runtime: "bash", script: "echo {{msg}}" },
|
|
414
|
-
},
|
|
415
|
-
],
|
|
416
|
-
};
|
|
417
|
-
|
|
418
|
-
const { run: run2, wfId: wfId2 } = await createAndTrigger(
|
|
419
|
-
"e2e-input-schema-invalid",
|
|
420
|
-
definitionStrict,
|
|
421
|
-
{ msg: 123 },
|
|
422
|
-
);
|
|
423
|
-
assertEq(run2.run.status, "failed", "3c. Invalid inputSchema run failed");
|
|
424
|
-
const greetStep2 = run2.steps.find((s) => s.nodeId === "greet");
|
|
425
|
-
assert(
|
|
426
|
-
greetStep2?.status === "failed",
|
|
427
|
-
"3d. Greet step failed on inputSchema violation",
|
|
428
|
-
`got status: ${greetStep2?.status}`,
|
|
429
|
-
);
|
|
430
|
-
assert(
|
|
431
|
-
greetStep2?.error?.includes("Input schema validation failed") ?? false,
|
|
432
|
-
"3e. Error message mentions input schema validation",
|
|
433
|
-
`got error: ${greetStep2?.error}`,
|
|
434
|
-
);
|
|
435
|
-
await api("DELETE", `/api/workflows/${wfId2}`);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
// ─── Test 4: Unresolved token diagnostics ───────────────────────────────────
|
|
439
|
-
|
|
440
|
-
async function testUnresolvedTokenDiagnostics() {
|
|
441
|
-
log("Test 4: Unresolved token diagnostics");
|
|
442
|
-
|
|
443
|
-
const definition = {
|
|
444
|
-
nodes: [
|
|
445
|
-
{
|
|
446
|
-
id: "echo",
|
|
447
|
-
type: "script",
|
|
448
|
-
inputs: { missing: "trigger.nonexistent" },
|
|
449
|
-
config: { runtime: "bash", script: "echo val={{missing}}" },
|
|
450
|
-
},
|
|
451
|
-
],
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
const { run, wfId } = await createAndTrigger("e2e-unresolved-tokens", definition, {
|
|
455
|
-
existing: "yes",
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
// The step should still complete (unresolved tokens are warnings, not errors)
|
|
459
|
-
assertEq(run.run.status, "completed", "4a. Run completes despite unresolved tokens");
|
|
460
|
-
|
|
461
|
-
const echoStep = run.steps.find((s) => s.nodeId === "echo");
|
|
462
|
-
assert(echoStep !== undefined, "4b. Echo step exists");
|
|
463
|
-
|
|
464
|
-
// Check diagnostics field contains unresolvedTokens
|
|
465
|
-
if (echoStep?.diagnostics) {
|
|
466
|
-
const diag = JSON.parse(echoStep.diagnostics);
|
|
467
|
-
assert(
|
|
468
|
-
Array.isArray(diag.unresolvedTokens) && diag.unresolvedTokens.length > 0,
|
|
469
|
-
"4c. Diagnostics contains unresolvedTokens",
|
|
470
|
-
`got diagnostics: ${echoStep.diagnostics}`,
|
|
471
|
-
);
|
|
472
|
-
} else {
|
|
473
|
-
// The token "missing" resolves to undefined (trigger.nonexistent doesn't exist),
|
|
474
|
-
// so {{missing}} in the script template would be unresolved
|
|
475
|
-
logFail("4c. Diagnostics contains unresolvedTokens", "diagnostics field is empty/null");
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
await api("DELETE", `/api/workflows/${wfId}`);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
// ─── Test 5: Static data flow validation ────────────────────────────────────
|
|
482
|
-
|
|
483
|
-
async function testStaticDataFlowValidation() {
|
|
484
|
-
log("Test 5: Static data flow validation");
|
|
485
|
-
|
|
486
|
-
// 5a. Reference a non-existent node -> 400
|
|
487
|
-
const { status: s1, data: d1 } = await api<{ error?: string }>("POST", "/api/workflows", {
|
|
488
|
-
name: "e2e-bad-ref-nonexistent",
|
|
489
|
-
definition: {
|
|
490
|
-
nodes: [
|
|
491
|
-
{
|
|
492
|
-
id: "step1",
|
|
493
|
-
type: "script",
|
|
494
|
-
inputs: { data: "nonexistent_node.output" },
|
|
495
|
-
config: { runtime: "bash", script: "echo {{data}}" },
|
|
496
|
-
},
|
|
497
|
-
],
|
|
498
|
-
},
|
|
499
|
-
});
|
|
500
|
-
assertEq(s1, 400, "5a. Non-existent node reference returns 400");
|
|
501
|
-
assert(
|
|
502
|
-
typeof d1?.error === "string" && d1.error.includes("non-existent node"),
|
|
503
|
-
"5b. Error message mentions non-existent node",
|
|
504
|
-
`got error: ${d1?.error}`,
|
|
505
|
-
);
|
|
506
|
-
|
|
507
|
-
// 5c. Reference a downstream node (not upstream) -> 400
|
|
508
|
-
// step1 -> step2, but step2 tries to reference step1's sibling "step3"
|
|
509
|
-
// which is a parallel node (not upstream)
|
|
510
|
-
const { status: s2, data: d2 } = await api<{ error?: string }>("POST", "/api/workflows", {
|
|
511
|
-
name: "e2e-bad-ref-downstream",
|
|
512
|
-
definition: {
|
|
513
|
-
nodes: [
|
|
514
|
-
{
|
|
515
|
-
id: "step1",
|
|
516
|
-
type: "script",
|
|
517
|
-
inputs: { data: "step2.stdout" },
|
|
518
|
-
config: { runtime: "bash", script: "echo {{data}}" },
|
|
519
|
-
next: "step2",
|
|
520
|
-
},
|
|
521
|
-
{
|
|
522
|
-
id: "step2",
|
|
523
|
-
type: "script",
|
|
524
|
-
config: { runtime: "bash", script: "echo done" },
|
|
525
|
-
},
|
|
526
|
-
],
|
|
527
|
-
},
|
|
528
|
-
});
|
|
529
|
-
assertEq(s2, 400, "5c. Downstream node reference returns 400");
|
|
530
|
-
assert(
|
|
531
|
-
typeof d2?.error === "string" && d2.error.includes("not upstream"),
|
|
532
|
-
"5d. Error message mentions not upstream",
|
|
533
|
-
`got error: ${d2?.error}`,
|
|
534
|
-
);
|
|
535
|
-
|
|
536
|
-
// 5e. Valid upstream reference -> 201
|
|
537
|
-
const { status: s3 } = await api<WfJson>("POST", "/api/workflows", {
|
|
538
|
-
name: "e2e-valid-upstream-ref",
|
|
539
|
-
definition: {
|
|
540
|
-
nodes: [
|
|
541
|
-
{
|
|
542
|
-
id: "step1",
|
|
543
|
-
type: "script",
|
|
544
|
-
config: { runtime: "bash", script: "echo hello" },
|
|
545
|
-
next: "step2",
|
|
546
|
-
},
|
|
547
|
-
{
|
|
548
|
-
id: "step2",
|
|
549
|
-
type: "script",
|
|
550
|
-
inputs: { data: "step1.stdout" },
|
|
551
|
-
config: { runtime: "bash", script: "echo {{data}}" },
|
|
552
|
-
},
|
|
553
|
-
],
|
|
554
|
-
},
|
|
555
|
-
});
|
|
556
|
-
assertEq(s3, 201, "5e. Valid upstream reference returns 201");
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
// ─── Test 6: Deep interpolation ─────────────────────────────────────────────
|
|
560
|
-
|
|
561
|
-
async function testDeepInterpolation() {
|
|
562
|
-
log("Test 6: Deep interpolation (nested objects + arrays in config)");
|
|
563
|
-
|
|
564
|
-
// The script executor only looks at config.script, config.runtime, etc.
|
|
565
|
-
// But the deep interpolation happens on the entire config object.
|
|
566
|
-
// We'll verify by using a script that echoes something based on the config,
|
|
567
|
-
// and also verify the step completes (meaning interpolation didn't break).
|
|
568
|
-
//
|
|
569
|
-
// We can test deep interpolation by passing nested values through inputs
|
|
570
|
-
// and interpolating them in the script.
|
|
571
|
-
const definition = {
|
|
572
|
-
nodes: [
|
|
573
|
-
{
|
|
574
|
-
id: "echo",
|
|
575
|
-
type: "script",
|
|
576
|
-
inputs: { name: "trigger.name", tag: "trigger.tag" },
|
|
577
|
-
config: {
|
|
578
|
-
runtime: "bash",
|
|
579
|
-
script: "echo name={{name}} tag={{tag}}",
|
|
580
|
-
// These nested fields are not used by the script executor but
|
|
581
|
-
// they will be deep-interpolated by the engine
|
|
582
|
-
nested: { val: "{{name}}" },
|
|
583
|
-
list: ["{{tag}}", "fixed"],
|
|
584
|
-
},
|
|
585
|
-
},
|
|
586
|
-
],
|
|
587
|
-
};
|
|
588
|
-
|
|
589
|
-
const { run, wfId } = await createAndTrigger("e2e-deep-interpolation", definition, {
|
|
590
|
-
name: "TestName",
|
|
591
|
-
tag: "v1.0",
|
|
592
|
-
});
|
|
593
|
-
|
|
594
|
-
assertEq(run.run.status, "completed", "6a. Deep interpolation run completed");
|
|
595
|
-
|
|
596
|
-
const echoStep = run.steps.find((s) => s.nodeId === "echo");
|
|
597
|
-
const echoOutput = echoStep?.output as { stdout?: string } | undefined;
|
|
598
|
-
assert(
|
|
599
|
-
echoOutput?.stdout?.includes("name=TestName") ?? false,
|
|
600
|
-
"6b. Script output contains interpolated name",
|
|
601
|
-
`got stdout: ${echoOutput?.stdout}`,
|
|
602
|
-
);
|
|
603
|
-
assert(
|
|
604
|
-
echoOutput?.stdout?.includes("tag=v1.0") ?? false,
|
|
605
|
-
"6c. Script output contains interpolated tag",
|
|
606
|
-
`got stdout: ${echoOutput?.stdout}`,
|
|
607
|
-
);
|
|
608
|
-
|
|
609
|
-
await api("DELETE", `/api/workflows/${wfId}`);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// ─── Test 7: Convergence with conditional branches ──────────────────────────
|
|
613
|
-
|
|
614
|
-
async function testConvergenceConditionalBranches() {
|
|
615
|
-
log("Test 7: Convergence with conditional branches");
|
|
616
|
-
|
|
617
|
-
// Workflow: A (code-match, branches true/false) ->
|
|
618
|
-
// true: B (script) -> C (script)
|
|
619
|
-
// false: C (script)
|
|
620
|
-
// C converges from both paths.
|
|
621
|
-
|
|
622
|
-
const definition = {
|
|
623
|
-
nodes: [
|
|
624
|
-
{
|
|
625
|
-
id: "A",
|
|
626
|
-
type: "code-match",
|
|
627
|
-
config: {
|
|
628
|
-
code: "(input) => input.trigger && input.trigger.match === true",
|
|
629
|
-
outputPorts: ["true", "false"],
|
|
630
|
-
},
|
|
631
|
-
next: { true: "B", false: "C" },
|
|
632
|
-
},
|
|
633
|
-
{
|
|
634
|
-
id: "B",
|
|
635
|
-
type: "script",
|
|
636
|
-
config: { runtime: "bash", script: "echo branch-B" },
|
|
637
|
-
next: "C",
|
|
638
|
-
},
|
|
639
|
-
{
|
|
640
|
-
id: "C",
|
|
641
|
-
type: "script",
|
|
642
|
-
config: { runtime: "bash", script: "echo final-C" },
|
|
643
|
-
},
|
|
644
|
-
],
|
|
645
|
-
};
|
|
646
|
-
|
|
647
|
-
// 7a. Trigger with match=true -> A, B, C all execute
|
|
648
|
-
const { run: run1, wfId: wfId1 } = await createAndTrigger("e2e-convergence-true", definition, {
|
|
649
|
-
match: true,
|
|
650
|
-
});
|
|
651
|
-
assertEq(run1.run.status, "completed", "7a. Convergence (true path) run completed");
|
|
652
|
-
const stepIds1 = run1.steps.map((s) => s.nodeId);
|
|
653
|
-
assert(stepIds1.includes("A"), "7b. Node A executed (true path)");
|
|
654
|
-
assert(stepIds1.includes("B"), "7c. Node B executed (true path)");
|
|
655
|
-
assert(stepIds1.includes("C"), "7d. Node C executed (true path)");
|
|
656
|
-
await api("DELETE", `/api/workflows/${wfId1}`);
|
|
657
|
-
|
|
658
|
-
// 7e. Trigger with match=false -> A, C execute (B skipped)
|
|
659
|
-
const { run: run2, wfId: wfId2 } = await createAndTrigger("e2e-convergence-false", definition, {
|
|
660
|
-
match: false,
|
|
661
|
-
});
|
|
662
|
-
assertEq(run2.run.status, "completed", "7e. Convergence (false path) run completed");
|
|
663
|
-
const stepIds2 = run2.steps.map((s) => s.nodeId);
|
|
664
|
-
assert(stepIds2.includes("A"), "7f. Node A executed (false path)");
|
|
665
|
-
assert(!stepIds2.includes("B"), "7g. Node B NOT executed (false path, skipped)");
|
|
666
|
-
assert(stepIds2.includes("C"), "7h. Node C executed (false path, converged)");
|
|
667
|
-
await api("DELETE", `/api/workflows/${wfId2}`);
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
// ─── Test 8: Backward compatibility ─────────────────────────────────────────
|
|
671
|
-
|
|
672
|
-
async function testBackwardCompatibility() {
|
|
673
|
-
log("Test 8: Backward compatibility (no triggerSchema, no inputs, no inputSchema)");
|
|
674
|
-
|
|
675
|
-
const definition = {
|
|
676
|
-
nodes: [
|
|
677
|
-
{
|
|
678
|
-
id: "echo",
|
|
679
|
-
type: "script",
|
|
680
|
-
// No inputs, no inputSchema, no outputSchema
|
|
681
|
-
config: { runtime: "bash", script: "echo hello-compat" },
|
|
682
|
-
},
|
|
683
|
-
],
|
|
684
|
-
};
|
|
685
|
-
|
|
686
|
-
// No triggerSchema -> any payload accepted
|
|
687
|
-
const { run, wfId } = await createAndTrigger("e2e-backward-compat", definition, {
|
|
688
|
-
anything: "goes",
|
|
689
|
-
nested: { value: 42 },
|
|
690
|
-
});
|
|
691
|
-
|
|
692
|
-
assertEq(run.run.status, "completed", "8a. Backward-compat run completed");
|
|
693
|
-
const echoStep = run.steps.find((s) => s.nodeId === "echo");
|
|
694
|
-
const echoOutput = echoStep?.output as { stdout?: string } | undefined;
|
|
695
|
-
assertEq(echoOutput?.stdout, "hello-compat", "8b. Script executed correctly");
|
|
696
|
-
|
|
697
|
-
await api("DELETE", `/api/workflows/${wfId}`);
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
// ─── Test 9: outputSchema validation ────────────────────────────────────────
|
|
701
|
-
|
|
702
|
-
async function testOutputSchemaValidation() {
|
|
703
|
-
log("Test 9: outputSchema validation");
|
|
704
|
-
|
|
705
|
-
// Script executor outputs { exitCode: number, stdout: string, stderr: string }
|
|
706
|
-
// We'll define an outputSchema that matches this shape -> should succeed
|
|
707
|
-
|
|
708
|
-
const definition = {
|
|
709
|
-
nodes: [
|
|
710
|
-
{
|
|
711
|
-
id: "echo",
|
|
712
|
-
type: "script",
|
|
713
|
-
outputSchema: {
|
|
714
|
-
type: "object",
|
|
715
|
-
properties: {
|
|
716
|
-
exitCode: { type: "number" },
|
|
717
|
-
},
|
|
718
|
-
required: ["exitCode"],
|
|
719
|
-
},
|
|
720
|
-
config: { runtime: "bash", script: "echo ok" },
|
|
721
|
-
},
|
|
722
|
-
],
|
|
723
|
-
};
|
|
724
|
-
|
|
725
|
-
const { run: run1, wfId: wfId1 } = await createAndTrigger(
|
|
726
|
-
"e2e-output-schema-valid",
|
|
727
|
-
definition,
|
|
728
|
-
{},
|
|
729
|
-
);
|
|
730
|
-
assertEq(run1.run.status, "completed", "9a. OutputSchema (valid) run completed");
|
|
731
|
-
const echoStep = run1.steps.find((s) => s.nodeId === "echo");
|
|
732
|
-
assertEq(echoStep?.status, "completed", "9b. Echo step completed with matching outputSchema");
|
|
733
|
-
await api("DELETE", `/api/workflows/${wfId1}`);
|
|
734
|
-
|
|
735
|
-
// 9c. Define an outputSchema that expects a string where there's a number
|
|
736
|
-
// Script executor returns exitCode as number, but we require it to be string -> should fail
|
|
737
|
-
const definitionBad = {
|
|
738
|
-
nodes: [
|
|
739
|
-
{
|
|
740
|
-
id: "echo",
|
|
741
|
-
type: "script",
|
|
742
|
-
outputSchema: {
|
|
743
|
-
type: "object",
|
|
744
|
-
properties: {
|
|
745
|
-
exitCode: { type: "string" },
|
|
746
|
-
},
|
|
747
|
-
required: ["exitCode"],
|
|
748
|
-
},
|
|
749
|
-
config: { runtime: "bash", script: "echo ok" },
|
|
750
|
-
},
|
|
751
|
-
],
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
const { run: run2, wfId: wfId2 } = await createAndTrigger(
|
|
755
|
-
"e2e-output-schema-invalid",
|
|
756
|
-
definitionBad,
|
|
757
|
-
{},
|
|
758
|
-
);
|
|
759
|
-
assertEq(run2.run.status, "failed", "9c. OutputSchema (invalid) run failed");
|
|
760
|
-
const echoStep2 = run2.steps.find((s) => s.nodeId === "echo");
|
|
761
|
-
assert(
|
|
762
|
-
echoStep2?.status === "failed",
|
|
763
|
-
"9d. Echo step failed on outputSchema violation",
|
|
764
|
-
`got status: ${echoStep2?.status}`,
|
|
765
|
-
);
|
|
766
|
-
assert(
|
|
767
|
-
echoStep2?.error?.includes("Output schema validation failed") ?? false,
|
|
768
|
-
"9e. Error message mentions output schema validation",
|
|
769
|
-
`got error: ${echoStep2?.error}`,
|
|
770
|
-
);
|
|
771
|
-
await api("DELETE", `/api/workflows/${wfId2}`);
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// ─── Main ───────────────────────────────────────────────────────────────────
|
|
775
|
-
async function main() {
|
|
776
|
-
log("=== E2E Workflow I/O Schemas Test ===");
|
|
777
|
-
log(`PORT=${PORT} DB=${DB_PATH}`);
|
|
778
|
-
|
|
779
|
-
try {
|
|
780
|
-
await startApi();
|
|
781
|
-
|
|
782
|
-
await testTriggerSchema();
|
|
783
|
-
await testInputsMappingDataFlow();
|
|
784
|
-
await testInputSchemaValidation();
|
|
785
|
-
await testUnresolvedTokenDiagnostics();
|
|
786
|
-
await testStaticDataFlowValidation();
|
|
787
|
-
await testDeepInterpolation();
|
|
788
|
-
await testConvergenceConditionalBranches();
|
|
789
|
-
await testBackwardCompatibility();
|
|
790
|
-
await testOutputSchemaValidation();
|
|
791
|
-
} catch (err) {
|
|
792
|
-
logFail("UNEXPECTED ERROR", String(err));
|
|
793
|
-
console.error(err);
|
|
794
|
-
} finally {
|
|
795
|
-
await cleanup();
|
|
796
|
-
}
|
|
797
|
-
|
|
798
|
-
// Summary
|
|
799
|
-
console.log("");
|
|
800
|
-
log("=========================================");
|
|
801
|
-
log(`Results: ${pass} passed, ${fail} failed`);
|
|
802
|
-
log("=========================================");
|
|
803
|
-
|
|
804
|
-
process.exit(fail > 0 ? 1 : 0);
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
main();
|