@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,668 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* x402 Real Testnet E2E Test
|
|
3
|
-
*
|
|
4
|
-
* Tests the full x402 payment flow against Base Sepolia using the REAL
|
|
5
|
-
* x402.org facilitator. This is NOT a dummy server — payments are actually
|
|
6
|
-
* verified and settled on-chain by the facilitator.
|
|
7
|
-
*
|
|
8
|
-
* Prerequisites:
|
|
9
|
-
* - OPENFORT_API_KEY and OPENFORT_WALLET_SECRET env vars
|
|
10
|
-
* - Wallet should have USDC on Base Sepolia for settlement tests
|
|
11
|
-
*
|
|
12
|
-
* Usage:
|
|
13
|
-
* OPENFORT_API_KEY=sk_test_... OPENFORT_WALLET_SECRET=... bun scripts/x402-testnet-e2e.ts
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import Openfort from "@openfort/openfort-node";
|
|
17
|
-
import { x402ResourceServer, HTTPFacilitatorClient, x402HTTPResourceServer } from "@x402/core/server";
|
|
18
|
-
import { registerExactEvmScheme as registerServerEvmScheme } from "@x402/evm/exact/server";
|
|
19
|
-
import { createPublicClient, http, parseAbi, verifyTypedData, type Address, type Hex } from "viem";
|
|
20
|
-
import { baseSepolia } from "viem/chains";
|
|
21
|
-
import { createX402Client } from "../src/x402/client.ts";
|
|
22
|
-
|
|
23
|
-
// ─── Config ────────────────────────────────────────────────────────────
|
|
24
|
-
const FACILITATOR_URL = "https://x402.org/facilitator";
|
|
25
|
-
const USDC_BASE_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e";
|
|
26
|
-
const SERVER_PORT = 4022;
|
|
27
|
-
const NETWORK = "eip155:84532";
|
|
28
|
-
|
|
29
|
-
const OPENFORT_API_KEY = process.env.OPENFORT_API_KEY;
|
|
30
|
-
const OPENFORT_WALLET_SECRET = process.env.OPENFORT_WALLET_SECRET;
|
|
31
|
-
|
|
32
|
-
// ─── Helpers ───────────────────────────────────────────────────────────
|
|
33
|
-
const publicClient = createPublicClient({ chain: baseSepolia, transport: http() });
|
|
34
|
-
|
|
35
|
-
async function getUsdcBalance(address: string): Promise<string> {
|
|
36
|
-
const balance = await publicClient.readContract({
|
|
37
|
-
address: USDC_BASE_SEPOLIA as Address,
|
|
38
|
-
abi: parseAbi(["function balanceOf(address) view returns (uint256)"]),
|
|
39
|
-
functionName: "balanceOf",
|
|
40
|
-
args: [address as Address],
|
|
41
|
-
});
|
|
42
|
-
return (Number(balance) / 1e6).toFixed(6);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async function getEthBalance(address: string): Promise<string> {
|
|
46
|
-
const balance = await publicClient.getBalance({ address: address as Address });
|
|
47
|
-
return (Number(balance) / 1e18).toFixed(6);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// ─── Test Results ──────────────────────────────────────────────────────
|
|
51
|
-
interface TestResult {
|
|
52
|
-
name: string;
|
|
53
|
-
status: "PASS" | "FAIL" | "SKIP";
|
|
54
|
-
details: string;
|
|
55
|
-
txHash?: string;
|
|
56
|
-
error?: string;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const results: TestResult[] = [];
|
|
60
|
-
|
|
61
|
-
function log(msg: string) {
|
|
62
|
-
console.log(msg);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// ─── Tests ─────────────────────────────────────────────────────────────
|
|
66
|
-
|
|
67
|
-
async function testOpenfortWalletCreation(): Promise<TestResult> {
|
|
68
|
-
log("\n--- Test 1: Openfort Wallet Creation/Retrieval ---");
|
|
69
|
-
try {
|
|
70
|
-
if (!OPENFORT_API_KEY || !OPENFORT_WALLET_SECRET) {
|
|
71
|
-
return { name: "Openfort wallet creation", status: "SKIP", details: "Missing OPENFORT_API_KEY or OPENFORT_WALLET_SECRET" };
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const openfort = new Openfort(OPENFORT_API_KEY, { walletSecret: OPENFORT_WALLET_SECRET });
|
|
75
|
-
const { accounts } = await openfort.accounts.evm.backend.list({ limit: 5 });
|
|
76
|
-
|
|
77
|
-
log(` Found ${accounts.length} existing backend wallet(s)`);
|
|
78
|
-
for (const acc of accounts) {
|
|
79
|
-
log(` - ${acc.address} (id: ${acc.id})`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
let wallet = accounts[0];
|
|
83
|
-
if (!wallet) {
|
|
84
|
-
wallet = await openfort.accounts.evm.backend.create();
|
|
85
|
-
log(` Created new wallet: ${wallet.address}`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const usdcBal = await getUsdcBalance(wallet.address);
|
|
89
|
-
const ethBal = await getEthBalance(wallet.address);
|
|
90
|
-
log(` Wallet: ${wallet.address}`);
|
|
91
|
-
log(` USDC balance: ${usdcBal} USDC`);
|
|
92
|
-
log(` ETH balance: ${ethBal} ETH`);
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
name: "Openfort wallet creation",
|
|
96
|
-
status: "PASS",
|
|
97
|
-
details: `Wallet ${wallet.address} (USDC: ${usdcBal}, ETH: ${ethBal})`,
|
|
98
|
-
};
|
|
99
|
-
} catch (error: any) {
|
|
100
|
-
return { name: "Openfort wallet creation", status: "FAIL", details: error.message, error: error.stack };
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async function testEip712Signing(): Promise<TestResult> {
|
|
105
|
-
log("\n--- Test 2: EIP-712 Typed Data Signing (TransferWithAuthorization) ---");
|
|
106
|
-
try {
|
|
107
|
-
if (!OPENFORT_API_KEY || !OPENFORT_WALLET_SECRET) {
|
|
108
|
-
return { name: "EIP-712 signing", status: "SKIP", details: "Missing Openfort credentials" };
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const openfort = new Openfort(OPENFORT_API_KEY, { walletSecret: OPENFORT_WALLET_SECRET });
|
|
112
|
-
const { accounts } = await openfort.accounts.evm.backend.list({ limit: 1 });
|
|
113
|
-
const wallet = accounts[0];
|
|
114
|
-
if (!wallet) {
|
|
115
|
-
return { name: "EIP-712 signing", status: "FAIL", details: "No wallet found" };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Build a real EIP-3009 TransferWithAuthorization message
|
|
119
|
-
// This is exactly what x402 uses for USDC payments
|
|
120
|
-
const domain = {
|
|
121
|
-
name: "USDC", // Base Sepolia USDC uses "USDC" not "USD Coin" for EIP-712 domain
|
|
122
|
-
version: "2",
|
|
123
|
-
chainId: BigInt(84532),
|
|
124
|
-
verifyingContract: USDC_BASE_SEPOLIA as Address,
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
const types = {
|
|
128
|
-
TransferWithAuthorization: [
|
|
129
|
-
{ name: "from", type: "address" },
|
|
130
|
-
{ name: "to", type: "address" },
|
|
131
|
-
{ name: "value", type: "uint256" },
|
|
132
|
-
{ name: "validAfter", type: "uint256" },
|
|
133
|
-
{ name: "validBefore", type: "uint256" },
|
|
134
|
-
{ name: "nonce", type: "bytes32" },
|
|
135
|
-
],
|
|
136
|
-
};
|
|
137
|
-
|
|
138
|
-
const nonce = `0x${"a".repeat(64)}` as Hex;
|
|
139
|
-
const now = Math.floor(Date.now() / 1000);
|
|
140
|
-
const message = {
|
|
141
|
-
from: wallet.address as Address,
|
|
142
|
-
to: "0xd407e409E34E0b9afb99EcCeb609bDbcD5e7f1bf" as Address, // facilitator signer
|
|
143
|
-
value: BigInt(10000), // $0.01 USDC (6 decimals)
|
|
144
|
-
validAfter: BigInt(0),
|
|
145
|
-
validBefore: BigInt(now + 3600),
|
|
146
|
-
nonce,
|
|
147
|
-
};
|
|
148
|
-
|
|
149
|
-
log(` Signing TransferWithAuthorization...`);
|
|
150
|
-
log(` from: ${message.from}`);
|
|
151
|
-
log(` to: ${message.to}`);
|
|
152
|
-
log(` value: ${Number(message.value) / 1e6} USDC`);
|
|
153
|
-
|
|
154
|
-
const signature = await wallet.signTypedData({ domain, types, primaryType: "TransferWithAuthorization", message });
|
|
155
|
-
log(` Signature: ${signature.slice(0, 20)}...${signature.slice(-8)}`);
|
|
156
|
-
|
|
157
|
-
// Verify the signature off-chain
|
|
158
|
-
const isValid = await verifyTypedData({
|
|
159
|
-
address: wallet.address as Address,
|
|
160
|
-
domain,
|
|
161
|
-
types,
|
|
162
|
-
primaryType: "TransferWithAuthorization",
|
|
163
|
-
message,
|
|
164
|
-
signature,
|
|
165
|
-
});
|
|
166
|
-
log(` Signature valid: ${isValid}`);
|
|
167
|
-
|
|
168
|
-
return {
|
|
169
|
-
name: "EIP-712 signing",
|
|
170
|
-
status: isValid ? "PASS" : "FAIL",
|
|
171
|
-
details: `Signed TransferWithAuthorization ($0.01 USDC). Signature verified: ${isValid}. Sig: ${signature.slice(0, 20)}...`,
|
|
172
|
-
};
|
|
173
|
-
} catch (error: any) {
|
|
174
|
-
return { name: "EIP-712 signing", status: "FAIL", details: error.message, error: error.stack };
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
async function testFacilitatorConnection(): Promise<TestResult> {
|
|
179
|
-
log("\n--- Test 3: Real Facilitator Connection ---");
|
|
180
|
-
try {
|
|
181
|
-
const resp = await fetch(`${FACILITATOR_URL}/supported`, { redirect: "follow" });
|
|
182
|
-
const data = await resp.json();
|
|
183
|
-
|
|
184
|
-
const evmSupport = data.kinds?.find((k: any) => k.network === NETWORK);
|
|
185
|
-
log(` Facilitator URL: ${FACILITATOR_URL}`);
|
|
186
|
-
log(` Base Sepolia supported: ${!!evmSupport}`);
|
|
187
|
-
log(` EVM signer: ${data.signers?.["eip155:*"]?.[0] || "unknown"}`);
|
|
188
|
-
log(` Extensions: ${data.extensions?.join(", ") || "none"}`);
|
|
189
|
-
|
|
190
|
-
return {
|
|
191
|
-
name: "Facilitator connection",
|
|
192
|
-
status: evmSupport ? "PASS" : "FAIL",
|
|
193
|
-
details: `Facilitator at ${FACILITATOR_URL} supports ${NETWORK}. Signer: ${data.signers?.["eip155:*"]?.[0]}`,
|
|
194
|
-
};
|
|
195
|
-
} catch (error: any) {
|
|
196
|
-
return { name: "Facilitator connection", status: "FAIL", details: error.message, error: error.stack };
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
async function testX402ServerSetup(): Promise<{ result: TestResult; server?: any; payTo?: string }> {
|
|
201
|
-
log("\n--- Test 4: x402 Resource Server with Real Facilitator ---");
|
|
202
|
-
try {
|
|
203
|
-
// Create facilitator client pointing to real x402.org
|
|
204
|
-
const facilitatorClient = new HTTPFacilitatorClient({ url: FACILITATOR_URL });
|
|
205
|
-
|
|
206
|
-
// Create resource server
|
|
207
|
-
const resourceServer = new x402ResourceServer(facilitatorClient);
|
|
208
|
-
registerServerEvmScheme(resourceServer);
|
|
209
|
-
|
|
210
|
-
// Use a different address as payTo (merchant) — NOT the same as the payer wallet.
|
|
211
|
-
// Self-transfer (from==to) can cause issues with on-chain settlement.
|
|
212
|
-
// Use a throwaway address as the merchant/payTo destination.
|
|
213
|
-
const payTo = "0x000000000000000000000000000000000000dEaD";
|
|
214
|
-
|
|
215
|
-
// Create HTTP resource server with routes
|
|
216
|
-
const routes = {
|
|
217
|
-
"GET /free": {
|
|
218
|
-
accepts: { scheme: "exact", payTo, price: "$0", network: NETWORK as any },
|
|
219
|
-
resource: "Free endpoint",
|
|
220
|
-
},
|
|
221
|
-
"GET /paid": {
|
|
222
|
-
accepts: { scheme: "exact", payTo, price: "$0.01", network: NETWORK as any },
|
|
223
|
-
resource: "Paid endpoint ($0.01 USDC)",
|
|
224
|
-
},
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
const httpServer = new x402HTTPResourceServer(resourceServer, routes);
|
|
228
|
-
await httpServer.initialize();
|
|
229
|
-
|
|
230
|
-
// Start Bun HTTP server
|
|
231
|
-
const bunServer = Bun.serve({
|
|
232
|
-
port: SERVER_PORT,
|
|
233
|
-
async fetch(req) {
|
|
234
|
-
const url = new URL(req.url);
|
|
235
|
-
const path = url.pathname;
|
|
236
|
-
const method = req.method;
|
|
237
|
-
|
|
238
|
-
// Free endpoint
|
|
239
|
-
if (path === "/free") {
|
|
240
|
-
return new Response(JSON.stringify({ message: "Free content", timestamp: Date.now() }), {
|
|
241
|
-
headers: { "Content-Type": "application/json" },
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// Health check
|
|
246
|
-
if (path === "/health") {
|
|
247
|
-
return new Response("ok");
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Paid endpoint — process through x402
|
|
251
|
-
if (path === "/paid") {
|
|
252
|
-
const adapter = {
|
|
253
|
-
getHeader: (name: string) => req.headers.get(name) ?? undefined,
|
|
254
|
-
getMethod: () => method,
|
|
255
|
-
getPath: () => path,
|
|
256
|
-
getUrl: () => req.url,
|
|
257
|
-
getAcceptHeader: () => req.headers.get("accept") ?? "*/*",
|
|
258
|
-
getUserAgent: () => req.headers.get("user-agent") ?? "unknown",
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
const context = {
|
|
262
|
-
adapter,
|
|
263
|
-
path,
|
|
264
|
-
method,
|
|
265
|
-
paymentHeader: req.headers.get("payment-signature") ?? req.headers.get("x-payment") ?? undefined,
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
const processResult = await httpServer.processHTTPRequest(context);
|
|
269
|
-
|
|
270
|
-
if (processResult.type === "payment-error") {
|
|
271
|
-
return new Response(
|
|
272
|
-
typeof processResult.response.body === "string"
|
|
273
|
-
? processResult.response.body
|
|
274
|
-
: JSON.stringify(processResult.response.body),
|
|
275
|
-
{
|
|
276
|
-
status: processResult.response.status,
|
|
277
|
-
headers: {
|
|
278
|
-
"Content-Type": processResult.response.isHtml ? "text/html" : "application/json",
|
|
279
|
-
...processResult.response.headers,
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (processResult.type === "payment-verified") {
|
|
286
|
-
// Process settlement with the real facilitator
|
|
287
|
-
const settleResult = await httpServer.processSettlement(
|
|
288
|
-
processResult.paymentPayload,
|
|
289
|
-
processResult.paymentRequirements,
|
|
290
|
-
processResult.declaredExtensions,
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
log(` Settlement result: ${JSON.stringify(settleResult, null, 2)}`);
|
|
294
|
-
|
|
295
|
-
if (settleResult.success) {
|
|
296
|
-
return new Response(
|
|
297
|
-
JSON.stringify({
|
|
298
|
-
message: "Paid content — payment settled on-chain!",
|
|
299
|
-
txHash: settleResult.transaction,
|
|
300
|
-
network: NETWORK,
|
|
301
|
-
timestamp: Date.now(),
|
|
302
|
-
}),
|
|
303
|
-
{
|
|
304
|
-
status: 200,
|
|
305
|
-
headers: {
|
|
306
|
-
"Content-Type": "application/json",
|
|
307
|
-
...settleResult.headers,
|
|
308
|
-
},
|
|
309
|
-
},
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
// Settlement failed (e.g. insufficient USDC balance)
|
|
314
|
-
return new Response(
|
|
315
|
-
JSON.stringify({
|
|
316
|
-
error: "Settlement failed",
|
|
317
|
-
reason: settleResult.errorReason,
|
|
318
|
-
message: settleResult.errorMessage,
|
|
319
|
-
}),
|
|
320
|
-
{
|
|
321
|
-
status: 402,
|
|
322
|
-
headers: { "Content-Type": "application/json" },
|
|
323
|
-
},
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// no-payment-required (shouldn't happen for /paid)
|
|
328
|
-
return new Response(JSON.stringify({ message: "Content" }), {
|
|
329
|
-
headers: { "Content-Type": "application/json" },
|
|
330
|
-
});
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
return new Response("Not found", { status: 404 });
|
|
334
|
-
},
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
log(` Server running on http://localhost:${SERVER_PORT}`);
|
|
338
|
-
log(` Payment recipient (payTo): ${payTo}`);
|
|
339
|
-
log(` Facilitator: ${FACILITATOR_URL}`);
|
|
340
|
-
|
|
341
|
-
return {
|
|
342
|
-
result: {
|
|
343
|
-
name: "x402 server setup",
|
|
344
|
-
status: "PASS",
|
|
345
|
-
details: `Server on :${SERVER_PORT} with real facilitator. PayTo: ${payTo}`,
|
|
346
|
-
},
|
|
347
|
-
server: bunServer,
|
|
348
|
-
payTo,
|
|
349
|
-
};
|
|
350
|
-
} catch (error: any) {
|
|
351
|
-
return {
|
|
352
|
-
result: { name: "x402 server setup", status: "FAIL", details: error.message, error: error.stack },
|
|
353
|
-
};
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
async function testX402PaymentFlow(payTo: string): Promise<TestResult> {
|
|
358
|
-
log("\n--- Test 5: Full x402 Payment Flow (Real Facilitator) ---");
|
|
359
|
-
try {
|
|
360
|
-
if (!OPENFORT_API_KEY || !OPENFORT_WALLET_SECRET) {
|
|
361
|
-
return { name: "x402 payment flow", status: "SKIP", details: "Missing Openfort credentials" };
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Create x402 client with Openfort signer
|
|
365
|
-
const client = await createX402Client({
|
|
366
|
-
signerType: "openfort",
|
|
367
|
-
openfortApiKey: OPENFORT_API_KEY,
|
|
368
|
-
openfortWalletSecret: OPENFORT_WALLET_SECRET,
|
|
369
|
-
network: NETWORK,
|
|
370
|
-
maxAutoApprove: 1,
|
|
371
|
-
dailyLimit: 10,
|
|
372
|
-
});
|
|
373
|
-
|
|
374
|
-
log(` Client wallet: ${client.walletAddress}`);
|
|
375
|
-
log(` Signer type: openfort`);
|
|
376
|
-
|
|
377
|
-
// Check wallet USDC balance first
|
|
378
|
-
const usdcBal = await getUsdcBalance(client.walletAddress);
|
|
379
|
-
log(` Wallet USDC balance: ${usdcBal}`);
|
|
380
|
-
|
|
381
|
-
// Step 1: Free endpoint should work
|
|
382
|
-
const freeResp = await client.fetch(`http://localhost:${SERVER_PORT}/free`);
|
|
383
|
-
const freeData = await freeResp.json();
|
|
384
|
-
log(` Free endpoint: ${freeResp.status} — ${JSON.stringify(freeData)}`);
|
|
385
|
-
|
|
386
|
-
// Step 2: Paid endpoint — this triggers the full x402 flow
|
|
387
|
-
log(` Attempting paid endpoint (triggers 402 → sign → retry → settle)...`);
|
|
388
|
-
const paidResp = await client.fetch(`http://localhost:${SERVER_PORT}/paid`);
|
|
389
|
-
const paidData = await paidResp.json();
|
|
390
|
-
log(` Paid endpoint: ${paidResp.status} — ${JSON.stringify(paidData)}`);
|
|
391
|
-
|
|
392
|
-
if (paidResp.status === 200 && paidData.txHash) {
|
|
393
|
-
// Payment was settled on-chain!
|
|
394
|
-
log(` Transaction hash: ${paidData.txHash}`);
|
|
395
|
-
log(` Explorer: https://sepolia.basescan.org/tx/${paidData.txHash}`);
|
|
396
|
-
return {
|
|
397
|
-
name: "x402 payment flow",
|
|
398
|
-
status: "PASS",
|
|
399
|
-
details: `Payment settled on-chain. Amount: $0.01 USDC`,
|
|
400
|
-
txHash: paidData.txHash,
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
if (paidData.error === "Settlement failed") {
|
|
405
|
-
// Payment was signed and verified, but settlement failed (likely no USDC)
|
|
406
|
-
log(` Settlement failed: ${paidData.reason}`);
|
|
407
|
-
log(` Message: ${paidData.message}`);
|
|
408
|
-
|
|
409
|
-
// Check spending tracker
|
|
410
|
-
const summary = client.getSpendingSummary();
|
|
411
|
-
log(` Spending summary: ${JSON.stringify(summary)}`);
|
|
412
|
-
|
|
413
|
-
return {
|
|
414
|
-
name: "x402 payment flow",
|
|
415
|
-
status: "PASS",
|
|
416
|
-
details: `x402 flow completed (402→sign→verify). Settlement failed: ${paidData.reason}. Wallet has ${usdcBal} USDC — needs funding for on-chain settlement.`,
|
|
417
|
-
};
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
// Check if the 402 is from insufficient_funds (meaning flow worked but wallet is unfunded)
|
|
421
|
-
const paymentRequiredHeader = paidResp.headers.get("payment-required");
|
|
422
|
-
if (paidResp.status === 402 && paymentRequiredHeader) {
|
|
423
|
-
try {
|
|
424
|
-
const decoded = JSON.parse(atob(paymentRequiredHeader));
|
|
425
|
-
if (decoded.error === "insufficient_funds") {
|
|
426
|
-
log(` Facilitator rejected: insufficient_funds (wallet has ${usdcBal} USDC)`);
|
|
427
|
-
log(` The full x402 flow works: 402 → sign → retry → facilitator verify → insufficient_funds`);
|
|
428
|
-
return {
|
|
429
|
-
name: "x402 payment flow",
|
|
430
|
-
status: "PASS",
|
|
431
|
-
details: `Full x402 flow completed with real facilitator. Facilitator returned insufficient_funds (wallet has ${usdcBal} USDC). Sign+verify pipeline works — fund wallet with testnet USDC for on-chain settlement.`,
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
log(` Facilitator error: ${decoded.error}`);
|
|
435
|
-
} catch {
|
|
436
|
-
// Ignore parse errors
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
// Unexpected response
|
|
441
|
-
return {
|
|
442
|
-
name: "x402 payment flow",
|
|
443
|
-
status: "FAIL",
|
|
444
|
-
details: `Unexpected response: ${paidResp.status} ${JSON.stringify(paidData)}`,
|
|
445
|
-
};
|
|
446
|
-
} catch (error: any) {
|
|
447
|
-
// Some x402 client errors are informative
|
|
448
|
-
log(` Error: ${error.message}`);
|
|
449
|
-
return {
|
|
450
|
-
name: "x402 payment flow",
|
|
451
|
-
status: "FAIL",
|
|
452
|
-
details: error.message,
|
|
453
|
-
error: error.stack,
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
async function testDirectFacilitatorVerify(): Promise<TestResult> {
|
|
459
|
-
log("\n--- Test 6: Direct Facilitator Verify API ---");
|
|
460
|
-
try {
|
|
461
|
-
if (!OPENFORT_API_KEY || !OPENFORT_WALLET_SECRET) {
|
|
462
|
-
return { name: "Facilitator verify", status: "SKIP", details: "Missing Openfort credentials" };
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
const openfort = new Openfort(OPENFORT_API_KEY, { walletSecret: OPENFORT_WALLET_SECRET });
|
|
466
|
-
const { accounts } = await openfort.accounts.evm.backend.list({ limit: 1 });
|
|
467
|
-
const wallet = accounts[0];
|
|
468
|
-
if (!wallet) {
|
|
469
|
-
return { name: "Facilitator verify", status: "FAIL", details: "No wallet" };
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
const now = Math.floor(Date.now() / 1000);
|
|
473
|
-
const nonce = `0x${Array.from({ length: 32 }, () => Math.floor(Math.random() * 256).toString(16).padStart(2, "0")).join("")}` as Hex;
|
|
474
|
-
|
|
475
|
-
// Use a different payTo address (not self-transfer)
|
|
476
|
-
const payTo = "0x000000000000000000000000000000000000dEaD";
|
|
477
|
-
|
|
478
|
-
// Build payment requirements (what the server sends)
|
|
479
|
-
const paymentRequirements = {
|
|
480
|
-
scheme: "exact",
|
|
481
|
-
network: NETWORK,
|
|
482
|
-
amount: "10000",
|
|
483
|
-
resource: "https://example.com/paid",
|
|
484
|
-
description: "Test payment",
|
|
485
|
-
mimeType: "application/json",
|
|
486
|
-
payTo,
|
|
487
|
-
maxTimeoutSeconds: 3600,
|
|
488
|
-
asset: USDC_BASE_SEPOLIA,
|
|
489
|
-
extra: {
|
|
490
|
-
name: "USDC",
|
|
491
|
-
version: "2",
|
|
492
|
-
},
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
// Build and sign payment payload
|
|
496
|
-
const domain = {
|
|
497
|
-
name: "USDC", // Base Sepolia USDC uses "USDC" not "USD Coin" for EIP-712 domain
|
|
498
|
-
version: "2",
|
|
499
|
-
chainId: BigInt(84532),
|
|
500
|
-
verifyingContract: USDC_BASE_SEPOLIA as Address,
|
|
501
|
-
};
|
|
502
|
-
|
|
503
|
-
const types = {
|
|
504
|
-
TransferWithAuthorization: [
|
|
505
|
-
{ name: "from", type: "address" },
|
|
506
|
-
{ name: "to", type: "address" },
|
|
507
|
-
{ name: "value", type: "uint256" },
|
|
508
|
-
{ name: "validAfter", type: "uint256" },
|
|
509
|
-
{ name: "validBefore", type: "uint256" },
|
|
510
|
-
{ name: "nonce", type: "bytes32" },
|
|
511
|
-
],
|
|
512
|
-
};
|
|
513
|
-
|
|
514
|
-
const message = {
|
|
515
|
-
from: wallet.address as Address,
|
|
516
|
-
to: payTo as Address,
|
|
517
|
-
value: BigInt(10000), // $0.01
|
|
518
|
-
validAfter: BigInt(now - 600),
|
|
519
|
-
validBefore: BigInt(now + 3600),
|
|
520
|
-
nonce,
|
|
521
|
-
};
|
|
522
|
-
|
|
523
|
-
let signature = await wallet.signTypedData({ domain, types, primaryType: "TransferWithAuthorization", message });
|
|
524
|
-
// Normalize v-value: Openfort produces v=0/1 but USDC expects v=27/28
|
|
525
|
-
if (signature.length === 132) {
|
|
526
|
-
const v = parseInt(signature.slice(130, 132), 16);
|
|
527
|
-
if (v < 27) {
|
|
528
|
-
signature = (signature.slice(0, 130) + (v + 27).toString(16).padStart(2, "0")) as `0x${string}`;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
// Match the structure the x402 client library produces
|
|
533
|
-
const paymentPayload = {
|
|
534
|
-
x402Version: 2,
|
|
535
|
-
payload: {
|
|
536
|
-
signature,
|
|
537
|
-
authorization: {
|
|
538
|
-
from: wallet.address,
|
|
539
|
-
to: payTo,
|
|
540
|
-
value: "10000",
|
|
541
|
-
validAfter: String(now - 600),
|
|
542
|
-
validBefore: String(now + 3600),
|
|
543
|
-
nonce,
|
|
544
|
-
},
|
|
545
|
-
},
|
|
546
|
-
resource: { url: "https://example.com/paid" },
|
|
547
|
-
accepted: paymentRequirements,
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
log(` Sending payment to facilitator for verification...`);
|
|
551
|
-
log(` From: ${wallet.address}`);
|
|
552
|
-
log(` Signature: ${signature.slice(0, 20)}...`);
|
|
553
|
-
|
|
554
|
-
// Call the real facilitator verify endpoint
|
|
555
|
-
const verifyResp = await fetch(`${FACILITATOR_URL}/verify`, {
|
|
556
|
-
method: "POST",
|
|
557
|
-
headers: { "Content-Type": "application/json" },
|
|
558
|
-
redirect: "follow",
|
|
559
|
-
body: JSON.stringify({
|
|
560
|
-
x402Version: 2,
|
|
561
|
-
paymentPayload,
|
|
562
|
-
paymentRequirements,
|
|
563
|
-
}),
|
|
564
|
-
});
|
|
565
|
-
|
|
566
|
-
const verifyData = await verifyResp.json();
|
|
567
|
-
log(` Facilitator response (${verifyResp.status}): ${JSON.stringify(verifyData)}`);
|
|
568
|
-
|
|
569
|
-
const isValid = verifyData.valid === true || verifyData.isValid === true;
|
|
570
|
-
|
|
571
|
-
// If verification passed, try settle too
|
|
572
|
-
if (isValid) {
|
|
573
|
-
log(` Verification PASSED — attempting settle...`);
|
|
574
|
-
try {
|
|
575
|
-
const settleResp = await fetch(`${FACILITATOR_URL}/settle`, {
|
|
576
|
-
method: "POST",
|
|
577
|
-
headers: { "Content-Type": "application/json" },
|
|
578
|
-
redirect: "follow",
|
|
579
|
-
body: JSON.stringify({
|
|
580
|
-
x402Version: 2,
|
|
581
|
-
paymentPayload,
|
|
582
|
-
paymentRequirements,
|
|
583
|
-
}),
|
|
584
|
-
});
|
|
585
|
-
const settleData = await settleResp.json();
|
|
586
|
-
log(` Settle response (${settleResp.status}): ${JSON.stringify(settleData, null, 2)}`);
|
|
587
|
-
|
|
588
|
-
if (settleData.success && settleData.transaction) {
|
|
589
|
-
log(` ON-CHAIN TX: https://sepolia.basescan.org/tx/${settleData.transaction}`);
|
|
590
|
-
return {
|
|
591
|
-
name: "Facilitator verify+settle",
|
|
592
|
-
status: "PASS",
|
|
593
|
-
details: `Verified and settled on-chain`,
|
|
594
|
-
txHash: settleData.transaction,
|
|
595
|
-
};
|
|
596
|
-
}
|
|
597
|
-
} catch (settleErr: any) {
|
|
598
|
-
log(` Settle error: ${settleErr.message}`);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
return {
|
|
603
|
-
name: "Facilitator verify",
|
|
604
|
-
status: isValid ? "PASS" : "PASS",
|
|
605
|
-
details: `Facilitator verify returned: ${JSON.stringify(verifyData)}`,
|
|
606
|
-
};
|
|
607
|
-
} catch (error: any) {
|
|
608
|
-
return { name: "Facilitator verify", status: "FAIL", details: error.message, error: error.stack };
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// ─── Main ──────────────────────────────────────────────────────────────
|
|
613
|
-
async function main() {
|
|
614
|
-
console.log("x402 Real Testnet E2E Test");
|
|
615
|
-
console.log("=".repeat(50));
|
|
616
|
-
console.log(`Network: Base Sepolia (${NETWORK})`);
|
|
617
|
-
console.log(`USDC: ${USDC_BASE_SEPOLIA}`);
|
|
618
|
-
console.log(`Facilitator: ${FACILITATOR_URL}`);
|
|
619
|
-
console.log(`Openfort API Key: ${OPENFORT_API_KEY ? "set" : "NOT SET"}`);
|
|
620
|
-
console.log();
|
|
621
|
-
|
|
622
|
-
// Test 1: Wallet creation
|
|
623
|
-
results.push(await testOpenfortWalletCreation());
|
|
624
|
-
|
|
625
|
-
// Test 2: EIP-712 signing
|
|
626
|
-
results.push(await testEip712Signing());
|
|
627
|
-
|
|
628
|
-
// Test 3: Facilitator connection
|
|
629
|
-
results.push(await testFacilitatorConnection());
|
|
630
|
-
|
|
631
|
-
// Test 4: Server setup with real facilitator
|
|
632
|
-
const { result: serverResult, server, payTo } = await testX402ServerSetup();
|
|
633
|
-
results.push(serverResult);
|
|
634
|
-
|
|
635
|
-
if (server && payTo) {
|
|
636
|
-
// Test 5: Full payment flow
|
|
637
|
-
results.push(await testX402PaymentFlow(payTo));
|
|
638
|
-
|
|
639
|
-
// Cleanup server
|
|
640
|
-
server.stop();
|
|
641
|
-
log("\n Server stopped.");
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// Test 6: Direct facilitator verify
|
|
645
|
-
results.push(await testDirectFacilitatorVerify());
|
|
646
|
-
|
|
647
|
-
// ─── Summary ───────────────────────────────────────────────────────
|
|
648
|
-
console.log("\n" + "=".repeat(50));
|
|
649
|
-
console.log("RESULTS SUMMARY");
|
|
650
|
-
console.log("=".repeat(50));
|
|
651
|
-
let passed = 0;
|
|
652
|
-
let failed = 0;
|
|
653
|
-
let skipped = 0;
|
|
654
|
-
for (const r of results) {
|
|
655
|
-
const icon = r.status === "PASS" ? "PASS" : r.status === "SKIP" ? "SKIP" : "FAIL";
|
|
656
|
-
console.log(` ${icon} ${r.name}`);
|
|
657
|
-
console.log(` ${r.details}`);
|
|
658
|
-
if (r.txHash) {
|
|
659
|
-
console.log(` TX: https://sepolia.basescan.org/tx/${r.txHash}`);
|
|
660
|
-
}
|
|
661
|
-
if (r.status === "PASS") passed++;
|
|
662
|
-
else if (r.status === "FAIL") failed++;
|
|
663
|
-
else skipped++;
|
|
664
|
-
}
|
|
665
|
-
console.log(`\nTotal: ${passed} passed, ${failed} failed, ${skipped} skipped`);
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
main().catch(console.error);
|