@agent-native/core 0.92.11 → 0.93.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/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +45 -0
- package/corpus/core/docs/content/automation-connectors.mdx +80 -0
- package/corpus/core/docs/content/extensions.mdx +8 -0
- package/corpus/core/docs/content/locales/ar-SA/extensions.mdx +8 -0
- package/corpus/core/docs/content/locales/ar-SA/messaging.mdx +84 -15
- package/corpus/core/docs/content/locales/ar-SA/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/ar-SA/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/de-DE/extensions.mdx +10 -0
- package/corpus/core/docs/content/locales/de-DE/messaging.mdx +92 -15
- package/corpus/core/docs/content/locales/de-DE/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/de-DE/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/es-ES/extensions.mdx +10 -0
- package/corpus/core/docs/content/locales/es-ES/messaging.mdx +91 -15
- package/corpus/core/docs/content/locales/es-ES/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/es-ES/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/fr-FR/extensions.mdx +10 -0
- package/corpus/core/docs/content/locales/fr-FR/messaging.mdx +91 -15
- package/corpus/core/docs/content/locales/fr-FR/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/fr-FR/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/hi-IN/extensions.mdx +8 -0
- package/corpus/core/docs/content/locales/hi-IN/messaging.mdx +81 -15
- package/corpus/core/docs/content/locales/hi-IN/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/hi-IN/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/ja-JP/extensions.mdx +9 -0
- package/corpus/core/docs/content/locales/ja-JP/messaging.mdx +81 -15
- package/corpus/core/docs/content/locales/ja-JP/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/ja-JP/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/ko-KR/extensions.mdx +8 -0
- package/corpus/core/docs/content/locales/ko-KR/messaging.mdx +80 -15
- package/corpus/core/docs/content/locales/ko-KR/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/ko-KR/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/pt-BR/extensions.mdx +9 -0
- package/corpus/core/docs/content/locales/pt-BR/messaging.mdx +88 -15
- package/corpus/core/docs/content/locales/pt-BR/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/pt-BR/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/zh-CN/extensions.mdx +6 -0
- package/corpus/core/docs/content/locales/zh-CN/messaging.mdx +78 -15
- package/corpus/core/docs/content/locales/zh-CN/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/zh-CN/template-design.mdx +1 -0
- package/corpus/core/docs/content/locales/zh-TW/extensions.mdx +6 -0
- package/corpus/core/docs/content/locales/zh-TW/messaging.mdx +78 -15
- package/corpus/core/docs/content/locales/zh-TW/template-clips.mdx +1 -0
- package/corpus/core/docs/content/locales/zh-TW/template-design.mdx +1 -0
- package/corpus/core/docs/content/messaging.mdx +227 -45
- package/corpus/core/docs/content/template-clips.mdx +3 -0
- package/corpus/core/docs/content/template-design.mdx +4 -0
- package/corpus/core/package.json +5 -1
- package/corpus/core/src/a2a/artifact-response.ts +131 -2
- package/corpus/core/src/a2a/client.ts +10 -0
- package/corpus/core/src/a2a/handlers.ts +40 -76
- package/corpus/core/src/a2a/types.ts +2 -0
- package/corpus/core/src/agent/durable-background.ts +24 -0
- package/corpus/core/src/agent/production-agent.ts +48 -5
- package/corpus/core/src/agent/run-manager.ts +171 -20
- package/corpus/core/src/agent/run-store.ts +297 -42
- package/corpus/core/src/agent/types.ts +23 -0
- package/corpus/core/src/audit/record.ts +31 -0
- package/corpus/core/src/audit/store.ts +69 -3
- package/corpus/core/src/audit/types.ts +13 -0
- package/corpus/core/src/automation/index.ts +802 -0
- package/corpus/core/src/cli/create.ts +12 -5
- package/corpus/core/src/cli/design-connect.ts +596 -36
- package/corpus/core/src/client/AgentPanel.tsx +51 -6
- package/corpus/core/src/client/AssistantChat.tsx +274 -147
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +3 -0
- package/corpus/core/src/client/RunStuckBanner.tsx +69 -20
- package/corpus/core/src/client/agent-chat-adapter.ts +110 -17
- package/corpus/core/src/client/automation.ts +22 -0
- package/corpus/core/src/client/chat/run-recovery.tsx +67 -50
- package/corpus/core/src/client/composer/TiptapComposer.tsx +8 -0
- package/corpus/core/src/client/index.ts +30 -0
- package/corpus/core/src/client/integrations/api.ts +295 -0
- package/corpus/core/src/client/integrations/index.ts +26 -0
- package/corpus/core/src/client/transcription/use-live-transcription.ts +68 -5
- package/corpus/core/src/client/use-run-stuck-detection.ts +41 -3
- package/corpus/core/src/deploy/build.ts +59 -3
- package/corpus/core/src/deploy/workspace-deploy.ts +37 -2
- package/corpus/core/src/file-upload/types.ts +2 -0
- package/corpus/core/src/index.ts +37 -0
- package/corpus/core/src/integrations/a2a-continuations-store.ts +6 -4
- package/corpus/core/src/integrations/adapters/discord.ts +362 -0
- package/corpus/core/src/integrations/adapters/index.ts +29 -0
- package/corpus/core/src/integrations/adapters/microsoft-teams.ts +411 -0
- package/corpus/core/src/integrations/adapters/slack.ts +861 -27
- package/corpus/core/src/integrations/adapters/telegram.ts +54 -15
- package/corpus/core/src/integrations/adapters/whatsapp.ts +41 -17
- package/corpus/core/src/integrations/catalog.ts +571 -0
- package/corpus/core/src/integrations/controls-store.ts +187 -0
- package/corpus/core/src/integrations/index.ts +100 -0
- package/corpus/core/src/integrations/installations-store.ts +677 -0
- package/corpus/core/src/integrations/integration-memory.ts +187 -0
- package/corpus/core/src/integrations/pending-tasks-retry-job.ts +6 -6
- package/corpus/core/src/integrations/pending-tasks-store.ts +83 -5
- package/corpus/core/src/integrations/plugin.ts +685 -47
- package/corpus/core/src/integrations/scope-store.ts +498 -0
- package/corpus/core/src/integrations/slack-manifest.ts +78 -0
- package/corpus/core/src/integrations/slack-oauth.ts +343 -0
- package/corpus/core/src/integrations/types.ts +179 -0
- package/corpus/core/src/integrations/usage-budget-store.ts +906 -0
- package/corpus/core/src/integrations/webhook-handler.ts +562 -51
- package/corpus/core/src/jobs/scheduler.ts +100 -2
- package/corpus/core/src/jobs/tools.ts +45 -9
- package/corpus/core/src/provider-api/index.ts +72 -1
- package/corpus/core/src/resources/handlers.ts +88 -14
- package/corpus/core/src/resources/script-helpers.ts +36 -7
- package/corpus/core/src/resources/store.ts +59 -52
- package/corpus/core/src/scripts/call-agent.ts +107 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +294 -119
- package/corpus/core/src/server/auth.ts +10 -14
- package/corpus/core/src/server/builder-design-systems.ts +16 -1
- package/corpus/core/src/server/edge.ts +18 -0
- package/corpus/core/src/server/index.ts +26 -0
- package/corpus/core/src/server/request-context.ts +18 -0
- package/corpus/core/src/server/social-og-image.ts +3 -2
- package/corpus/core/src/styles/agent-native.css +62 -44
- package/corpus/core/src/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/core/src/templates/default/AGENTS.md +7 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/core/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
- package/corpus/core/src/templates/workspace-core/AGENTS.md +3 -2
- package/corpus/core/src/usage/store.ts +37 -2
- package/corpus/templates/analytics/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/analytics/.agents/skills/provider-api/SKILL.md +23 -0
- package/corpus/templates/analytics/.builder/skills/provider-api/SKILL.md +15 -0
- package/corpus/templates/analytics/actions/save-monitor.ts +25 -2
- package/corpus/templates/analytics/app/lib/data-sources.ts +28 -0
- package/corpus/templates/analytics/changelog/2026-07-10-agent-created-uptime-monitors-now-return-a-direct-link-to-th.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-10-dashboard-email-reports-still-arrive-when-screenshot-capture-temporarily-fails.md +6 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +3 -7
- package/corpus/templates/analytics/server/lib/credential-keys.ts +12 -0
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +5 -1
- package/corpus/templates/analytics/server/lib/provider-credentials.ts +2 -0
- package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +16 -0
- package/corpus/templates/assets/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/brain/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/calendar/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/calendar/app/components/calendar/CommandPalette.tsx +98 -108
- package/corpus/templates/calendar/app/components/calendar/EventAttendeesSection.tsx +97 -90
- package/corpus/templates/calendar/changelog/2026-07-10-event-guest-details-and-option-menus-now-use-valid-accessibl.md +6 -0
- package/corpus/templates/calendar/changelog/2026-07-10-natural-language-event-phrases-stay-available-as-quick-creat.md +6 -0
- package/corpus/templates/chat/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +6 -0
- package/corpus/templates/clips/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +17 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +8 -0
- package/corpus/templates/clips/AGENTS.md +8 -3
- package/corpus/templates/clips/actions/finalize-recording.ts +63 -23
- package/corpus/templates/clips/actions/get-recording-player-data.ts +6 -2
- package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +72 -9
- package/corpus/templates/clips/actions/list-recordings.ts +19 -3
- package/corpus/templates/clips/actions/navigate.ts +2 -0
- package/corpus/templates/clips/actions/reprocess-recording.ts +20 -6
- package/corpus/templates/clips/actions/request-transcript.ts +16 -31
- package/corpus/templates/clips/actions/view-screen.ts +57 -5
- package/corpus/templates/clips/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/clips/app/components/library/empty-state.tsx +2 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +69 -42
- package/corpus/templates/clips/app/components/library/library-layout.tsx +15 -1
- package/corpus/templates/clips/app/components/library/recording-card.tsx +81 -68
- package/corpus/templates/clips/app/components/library/search-bar.tsx +4 -3
- package/corpus/templates/clips/app/components/player/delete-recording-menu.tsx +9 -3
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +1 -1
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +27 -5
- package/corpus/templates/clips/app/hooks/use-library.ts +1 -1
- package/corpus/templates/clips/app/hooks/use-navigation-state.ts +10 -2
- package/corpus/templates/clips/app/hooks/use-player-shortcuts.ts +1 -0
- package/corpus/templates/clips/app/i18n/ar-SA.ts +7 -1
- package/corpus/templates/clips/app/i18n/de-DE.ts +7 -1
- package/corpus/templates/clips/app/i18n/en-US.ts +7 -1
- package/corpus/templates/clips/app/i18n/es-ES.ts +7 -1
- package/corpus/templates/clips/app/i18n/fr-FR.ts +7 -1
- package/corpus/templates/clips/app/i18n/hi-IN.ts +7 -1
- package/corpus/templates/clips/app/i18n/ja-JP.ts +7 -1
- package/corpus/templates/clips/app/i18n/ko-KR.ts +7 -1
- package/corpus/templates/clips/app/i18n/pt-BR.ts +7 -1
- package/corpus/templates/clips/app/i18n/zh-CN.ts +8 -1
- package/corpus/templates/clips/app/i18n/zh-TW.ts +8 -1
- package/corpus/templates/clips/app/lib/recording-visibility.ts +70 -0
- package/corpus/templates/clips/app/routes/_app.shared.tsx +20 -0
- package/corpus/templates/clips/app/routes/download.tsx +24 -8
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +115 -2
- package/corpus/templates/clips/app/routes/record.tsx +62 -0
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +25 -16
- package/corpus/templates/clips/changelog/2026-07-10-clips-desktop-is-now-available-for-linux-with-appimage-debia.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-clips-downloads-updates-sooner-in-the-background-and-offers-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-clips-shared-with-you-now-appear-in-a-searchable-shared-with.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-clips-with-missing-mobile-video-frames-can-be-repaired-witho.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-fixed-copying-agent-responses-and-transcript-text-from-recor.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-mobile-camera-recordings-pause-while-backgrounded.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-mp4-downloads-now-show-progress-immediately-after-the-option.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-recording-pages-now-open-as-soon-as-you-stop-with-a-share-li.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-recordings-now-seek-smoothly-downloads-use-the-correct-file-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-s3-compatible-storage-now-saves-hosted-recordings-without-re.md +6 -0
- package/corpus/templates/clips/desktop/README.md +22 -6
- package/corpus/templates/clips/desktop/package.json +1 -1
- package/corpus/templates/clips/desktop/src/app.tsx +32 -19
- package/corpus/templates/clips/desktop/src/components/ReadinessPanel.tsx +15 -9
- package/corpus/templates/clips/desktop/src/lib/finalization-guard.ts +22 -0
- package/corpus/templates/clips/desktop/src/lib/permissions.ts +3 -1
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +97 -120
- package/corpus/templates/clips/desktop/src/lib/updater.ts +26 -4
- package/corpus/templates/clips/desktop/src/overlays/finalizing.tsx +4 -8
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +2 -2
- package/corpus/templates/clips/desktop/src-tauri/src/permission_status.rs +11 -7
- package/corpus/templates/clips/desktop/src-tauri/tauri.linux.conf.json +11 -0
- package/corpus/templates/clips/netlify.toml +3 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +106 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +9 -1
- package/corpus/templates/clips/server/lib/resumable-upload-provider.ts +52 -0
- package/corpus/templates/clips/server/lib/s3-upload-provider.ts +433 -85
- package/corpus/templates/clips/server/lib/video-remux.ts +114 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +109 -0
- package/corpus/templates/clips/server/routes/api/clips-updater.json.get.ts +22 -11
- package/corpus/templates/clips/server/routes/api/public-recording.get.ts +4 -2
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/abort.post.ts +47 -5
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +10 -2
- package/corpus/templates/clips/shared/share-loader-response.ts +12 -0
- package/corpus/templates/clips/shared/transcript-status.ts +40 -0
- package/corpus/templates/content/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/content/.agents/skills/content/SKILL.md +57 -5
- package/corpus/templates/content/AGENTS.md +65 -55
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +92 -23
- package/corpus/templates/content/actions/_database-source-utils.ts +207 -41
- package/corpus/templates/content/actions/_property-utils.ts +30 -2
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +316 -121
- package/corpus/templates/content/actions/attach-content-database-source.ts +41 -17
- package/corpus/templates/content/actions/change-content-database-source-role.ts +46 -8
- package/corpus/templates/content/actions/submit-content-database-form.ts +497 -0
- package/corpus/templates/content/actions/suggest-source-join-key.ts +8 -1
- package/corpus/templates/content/actions/update-content-database-view.ts +8 -1
- package/corpus/templates/content/actions/view-screen.ts +4 -1
- package/corpus/templates/content/agent-native.app-skill.json +1 -1
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +250 -64
- package/corpus/templates/content/app/components/editor/database/FormView.tsx +460 -0
- package/corpus/templates/content/app/components/editor/database/navigation-state.ts +3 -0
- package/corpus/templates/content/app/components/editor/database/settings.tsx +30 -37
- package/corpus/templates/content/app/components/editor/database/shared.tsx +2 -0
- package/corpus/templates/content/app/components/editor/database/view-config.ts +29 -1
- package/corpus/templates/content/app/components/ui/textarea.tsx +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +22 -0
- package/corpus/templates/content/app/i18n/zh-TW.ts +21 -0
- package/corpus/templates/content/app/i18n-data.ts +225 -0
- package/corpus/templates/content/changelog/2026-07-09-builder-source-refreshes-now-keep-mapped-fields-such-as-topi.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-backed-properties-now-load-current-source-values-as-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-database-refreshes-now-stay-explicit-and-accurate.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-database-form-views-now-collect-ordered-required-answers-and.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-database-tables-now-use-a-quieter-more-compact-layout-with-c.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-slack-intake-routes-to-content-database-forms.md +6 -0
- package/corpus/templates/content/parity/matrix.md +1 -0
- package/corpus/templates/content/parity/matrix.ts +18 -0
- package/corpus/templates/content/shared/api.ts +28 -1
- package/corpus/templates/content/shared/database-form.ts +53 -0
- package/corpus/templates/design/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +26 -0
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +85 -12
- package/corpus/templates/design/AGENTS.md +72 -18
- package/corpus/templates/design/DESIGN.md +1 -1
- package/corpus/templates/design/DEVELOPING.md +1 -1
- package/corpus/templates/design/FIGMA_INTEROPERABILITY.md +116 -0
- package/corpus/templates/design/actions/create-design-from-template.ts +220 -0
- package/corpus/templates/design/actions/create-design-system.ts +92 -16
- package/corpus/templates/design/actions/delete-design-template.ts +28 -0
- package/corpus/templates/design/actions/delete-file.ts +7 -0
- package/corpus/templates/design/actions/edit-design.ts +3 -0
- package/corpus/templates/design/actions/export-design-as-figma-svg.ts +137 -5
- package/corpus/templates/design/actions/export-pdf.ts +1 -1
- package/corpus/templates/design/actions/generate-design.ts +3 -0
- package/corpus/templates/design/actions/get-design-snapshot.ts +9 -0
- package/corpus/templates/design/actions/get-figma-connection-status.ts +26 -0
- package/corpus/templates/design/actions/get-figma-design-context.ts +138 -0
- package/corpus/templates/design/actions/get-figma-styles.ts +2 -2
- package/corpus/templates/design/actions/import-figma-clipboard.ts +112 -16
- package/corpus/templates/design/actions/import-figma-frame.ts +15 -4
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +4 -0
- package/corpus/templates/design/actions/list-design-templates.ts +118 -0
- package/corpus/templates/design/actions/navigate.ts +16 -2
- package/corpus/templates/design/actions/provider-api-request.ts +11 -1
- package/corpus/templates/design/actions/save-design-as-template.ts +156 -0
- package/corpus/templates/design/actions/set-active-breakpoint.ts +13 -4
- package/corpus/templates/design/actions/take-design-screenshot.ts +73 -3
- package/corpus/templates/design/actions/update-file.ts +39 -22
- package/corpus/templates/design/actions/view-screen.ts +36 -1
- package/corpus/templates/design/actions/write-local-file.ts +50 -38
- package/corpus/templates/design/app/components/design/AutoLayoutSuggestionDialog.tsx +151 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +20 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +251 -22
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +3 -3
- package/corpus/templates/design/app/components/design/DesignImportPanel.tsx +384 -9
- package/corpus/templates/design/app/components/design/EditPanel.tsx +105 -32
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +58 -28
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +6 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +539 -53
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +40 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +1 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +1 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +5 -1
- package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +2 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +3 -1
- package/corpus/templates/design/app/components/design/code-workbench/workspace/types.ts +2 -0
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +19 -0
- package/corpus/templates/design/app/components/design/edit-panel/frame-presets-panel.tsx +1 -0
- package/corpus/templates/design/app/components/design/edit-panel/interaction-state-helpers.ts +27 -0
- package/corpus/templates/design/app/components/design/inspector/InteractionStatePanel.tsx +137 -81
- package/corpus/templates/design/app/components/design/inspector/frame-size-presets.ts +25 -5
- package/corpus/templates/design/app/components/design/multi-screen/chrome-transitions.ts +1 -1
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +220 -3
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +13 -0
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +22 -1
- package/corpus/templates/design/app/components/design/types.ts +4 -0
- package/corpus/templates/design/app/components/design-system/ProductionDesignSystemShowcase.tsx +208 -0
- package/corpus/templates/design/app/components/editor/FigmaLinkComposerBubble.tsx +321 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +24 -4
- package/corpus/templates/design/app/components/layout/Layout.tsx +16 -2
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -0
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +72 -0
- package/corpus/templates/design/app/global.css +2 -35
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +10 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +127 -5
- package/corpus/templates/design/app/i18n-breakpoints.ts +209 -0
- package/corpus/templates/design/app/i18n-data.ts +1317 -59
- package/corpus/templates/design/app/i18n-template-feature.ts +458 -0
- package/corpus/templates/design/app/lib/design-clipboard.ts +202 -0
- package/corpus/templates/design/app/lib/design-file-upload.ts +87 -0
- package/corpus/templates/design/app/lib/design-import.ts +168 -11
- package/corpus/templates/design/app/lib/desktop-design-preview.ts +423 -0
- package/corpus/templates/design/app/lib/figma-clipboard.ts +74 -8
- package/corpus/templates/design/app/lib/figma-connection.ts +161 -0
- package/corpus/templates/design/app/lib/figma-svg-copy.ts +814 -22
- package/corpus/templates/design/app/lib/figma-url.ts +77 -0
- package/corpus/templates/design/app/lib/pending-generation.ts +35 -0
- package/corpus/templates/design/app/pages/DesignSystems.tsx +236 -177
- package/corpus/templates/design/app/pages/Index.tsx +38 -0
- package/corpus/templates/design/app/pages/Templates.tsx +498 -0
- package/corpus/templates/design/app/pages/design-editor/auto-layout-suggestion.ts +328 -0
- package/corpus/templates/design/app/pages/design-editor/clone-idrefs.ts +113 -0
- package/corpus/templates/design/app/pages/design-editor/created-screen-navigation.ts +55 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +32 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +49 -2
- package/corpus/templates/design/app/pages/design-editor/export-capture.ts +296 -0
- package/corpus/templates/design/app/pages/design-editor/history.ts +101 -2
- package/corpus/templates/design/app/pages/design-editor/layout-operations.ts +28 -1
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +34 -0
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +202 -6
- package/corpus/templates/design/app/pages/design-editor/pending-structure-verification.ts +92 -0
- package/corpus/templates/design/app/pages/design-editor/save-failure.ts +58 -0
- package/corpus/templates/design/app/routes/templates.tsx +4 -6
- package/corpus/templates/design/changelog/2026-07-10-app-workspaces-now-use-clean-borderless-main-surfaces-throug.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-ask-chat-what-s-in-a-figma-file-or-frame-structure-screensho.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-canvas-edits-now-reject-malformed-html-before-it-can-corrupt.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-complex-designs-now-export-as-valid-secure-svgs-and-crisp-ra.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-complex-figma-masks-arcs-rich-text-transformed-images-and-ad.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-copied-layers-paste-across-designs-and-browser-tabs.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-copy-and-download-editable-figma-svg.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-copying-design-text-now-pastes-readable-text-into-other-apps.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-deleted-screens-can-be-restored-with-undo-and-removed-again-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-design-changes-now-save-before-switching-apps-and-retry-when.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-design-stays-usable-on-phones-by-keeping-editor-panels-and-f.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-download-all-screens-as-one-multi-page-pdf-from-the-overview.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-duplicated-layers-now-keep-labels-aria-relationships-fragmen.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fig-import-results-stay-compact.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-figma-imports-now-load-real-fonts-fix-rotated-gradient-dashe.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-figma-links-in-chat-and-the-import-tab-now-offer-secure-one-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-cmd-z-not-restoring-content-after-an-agent-driven-desi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-download-pdf-being-unreachable-from-the-export-panel-e.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-dragging-a-layer-out-of-an-auto-layout-row-column-no-l.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-figma-svg-export-text-wrapping-sizing-and-inner-layer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-hiding-or-locking-one-layer-no-longer-hides-or-blocks-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-png-screenshots-of-tall-screens-being-cropped-to-one-v.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-fixed-png-svg-exports-capturing-broken-layout-when-webfonts-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-frame-tool-now-offers-standard-ad-unit-size-presets-medium-r.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-full-view-controls-stay-within-their-frame-instead-of-coveri.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-hover-focus-focus-visible-pressed-and-disabled-states-now-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-layer-drops-now-land-in-the-intended-grid-row-stay-visually-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-local-code-workspaces-now-keep-unsaved-edits-across-panel-sw.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-local-visual-editing-now-keeps-authenticated-sessions-shared.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-long-running-agent-work-no-longer-shows-a-premature-stuck-wa.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-managed-figma-connections-are-recognized-automatically.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-designs-can-open-directly-in-the-editor-without-a-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-screens-are-selected-and-revealed-immediately.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-new-text-layers-undo-as-one-safe-creation.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-preview-and-apply-inferred-auto-layout-without-changing-yo.md +5 -0
- package/corpus/templates/design/changelog/2026-07-10-print-pdf-exports-and-paper-size-presets-letter-a4-now-match.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-responsive-frame-editing.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-reusable-design-templates.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-screen-overview-frames-now-use-a-clearer-interact-action-wit.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-start-designs-from-source-linked-material-3-carbon-or-primer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-tweaks-guidance.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-uploaded-fig-files-can-now-become-editable-design-screens-wi.md +6 -0
- package/corpus/templates/design/e2e/helpers.ts +3 -3
- package/corpus/templates/design/package.json +2 -0
- package/corpus/templates/design/scripts/qa-figma-stress-import.ts +96 -0
- package/corpus/templates/design/server/db/index.ts +10 -0
- package/corpus/templates/design/server/db/schema.ts +44 -0
- package/corpus/templates/design/server/handlers/import-design-file.ts +114 -80
- package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +19 -6
- package/corpus/templates/design/server/lib/design-export.ts +240 -3
- package/corpus/templates/design/server/lib/design-template-data.ts +89 -0
- package/corpus/templates/design/server/lib/design-to-figma-svg.ts +250 -26
- package/corpus/templates/design/server/lib/fig-file-decoder.ts +839 -0
- package/corpus/templates/design/server/lib/fig-file-import.ts +287 -0
- package/corpus/templates/design/server/lib/fig-file-limits.ts +3 -0
- package/corpus/templates/design/server/lib/fig-file-to-html.ts +2568 -0
- package/corpus/templates/design/server/lib/figma-design-context.ts +359 -0
- package/corpus/templates/design/server/lib/figma-node-import.ts +478 -22
- package/corpus/templates/design/server/lib/figma-node-to-html.ts +554 -29
- package/corpus/templates/design/server/lib/local-figma-qa-upload.ts +112 -0
- package/corpus/templates/design/server/lib/verify-write-grant.ts +16 -2
- package/corpus/templates/design/server/lib/visible-clipboard-html.ts +13 -3
- package/corpus/templates/design/server/plugins/agent-chat.ts +7 -0
- package/corpus/templates/design/server/plugins/db.ts +42 -0
- package/corpus/templates/design/server/plugins/local-figma-qa-upload.ts +7 -0
- package/corpus/templates/design/server/register-secrets.ts +8 -8
- package/corpus/templates/design/server/routes/api/qa-figma-import-assets/[assetId].get.ts +46 -0
- package/corpus/templates/design/server/source-workspace.ts +104 -12
- package/corpus/templates/design/shared/code-layer.ts +105 -28
- package/corpus/templates/design/shared/design-system-templates.ts +301 -0
- package/corpus/templates/design/shared/design-template-presets.ts +195 -0
- package/corpus/templates/design/shared/figma-url.ts +8 -0
- package/corpus/templates/design/shared/html-integrity.ts +306 -0
- package/corpus/templates/design/shared/interaction-states.ts +318 -23
- package/corpus/templates/design/shared/locked-layers.ts +151 -0
- package/corpus/templates/dispatch/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/dispatch/app/i18n/zh-TW.ts +48 -0
- package/corpus/templates/dispatch/app/i18n-data.ts +536 -1
- package/corpus/templates/dispatch/changelog/2026-07-10-connect-slack-workspaces-with-oauth-and-manage-channel-ident.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-10-microsoft-teams-bots-and-discord-slash-commands-can-now-conn.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-10-slack-and-telegram-now-route-uptime-monitor-requests-to-anal.md +6 -0
- package/corpus/templates/forms/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +7 -0
- package/corpus/templates/forms/AGENTS.md +4 -0
- package/corpus/templates/forms/actions/create-form.ts +44 -7
- package/corpus/templates/forms/actions/lib/assert-publishable-form.ts +38 -0
- package/corpus/templates/forms/actions/patch-form-fields.ts +4 -0
- package/corpus/templates/forms/actions/update-form.ts +2 -36
- package/corpus/templates/forms/app/i18n/ar-SA.ts +3 -0
- package/corpus/templates/forms/app/i18n/de-DE.ts +3 -0
- package/corpus/templates/forms/app/i18n/en-US.ts +3 -0
- package/corpus/templates/forms/app/i18n/es-ES.ts +3 -0
- package/corpus/templates/forms/app/i18n/fr-FR.ts +3 -0
- package/corpus/templates/forms/app/i18n/hi-IN.ts +3 -0
- package/corpus/templates/forms/app/i18n/ja-JP.ts +3 -0
- package/corpus/templates/forms/app/i18n/ko-KR.ts +3 -0
- package/corpus/templates/forms/app/i18n/pt-BR.ts +3 -0
- package/corpus/templates/forms/app/i18n/zh-CN.ts +2 -0
- package/corpus/templates/forms/app/i18n/zh-TW.ts +3 -0
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +17 -0
- package/corpus/templates/forms/changelog/2026-07-10-agent-created-published-forms-now-return-the-anonymous-publi.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-10-published-forms-can-no-longer-be-edited-into-an-unusable-emp.md +6 -0
- package/corpus/templates/forms/server/handlers/submissions.ts +4 -3
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/forms/shared/types.ts +5 -0
- package/corpus/templates/mail/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
- package/corpus/templates/mail/changelog/2026-07-10-mail-navigation-now-uses-a-clean-borderless-drawer.md +6 -0
- package/corpus/templates/plan/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/corpus/templates/plan/app/lib/plan-local-bridge.ts +4 -1
- package/corpus/templates/plan/changelog/2026-07-10-local-plans-now-keep-valid-content-visible-when-one-generate.md +6 -0
- package/corpus/templates/plan/server/lib/local-plan-files.ts +4 -1
- package/corpus/templates/slides/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +88 -2
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/a2a/client.d.ts +9 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +1 -0
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +24 -69
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/types.d.ts +2 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/agent/durable-background.d.ts +11 -0
- package/dist/agent/durable-background.d.ts.map +1 -1
- package/dist/agent/durable-background.js +17 -0
- package/dist/agent/durable-background.js.map +1 -1
- package/dist/agent/production-agent.d.ts +5 -3
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +34 -8
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts +44 -2
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +124 -18
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +109 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +274 -37
- package/dist/agent/run-store.js.map +1 -1
- package/dist/agent/types.d.ts +22 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/audit/record.d.ts.map +1 -1
- package/dist/audit/record.js +29 -0
- package/dist/audit/record.js.map +1 -1
- package/dist/audit/store.d.ts.map +1 -1
- package/dist/audit/store.js +62 -3
- package/dist/audit/store.js.map +1 -1
- package/dist/audit/types.d.ts +13 -0
- package/dist/audit/types.d.ts.map +1 -1
- package/dist/audit/types.js.map +1 -1
- package/dist/automation/index.d.ts +193 -0
- package/dist/automation/index.d.ts.map +1 -0
- package/dist/automation/index.js +464 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +10 -3
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +492 -35
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +7 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +32 -8
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +15 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +115 -47
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/RunStuckBanner.d.ts +14 -1
- package/dist/client/RunStuckBanner.d.ts.map +1 -1
- package/dist/client/RunStuckBanner.js +35 -7
- package/dist/client/RunStuckBanner.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts +4 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +97 -16
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/automation.d.ts +14 -0
- package/dist/client/automation.d.ts.map +1 -0
- package/dist/client/automation.js +9 -0
- package/dist/client/automation.js.map +1 -0
- package/dist/client/chat/run-recovery.d.ts +4 -0
- package/dist/client/chat/run-recovery.d.ts.map +1 -1
- package/dist/client/chat/run-recovery.js +12 -10
- package/dist/client/chat/run-recovery.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +8 -0
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/api.d.ts +115 -0
- package/dist/client/integrations/api.d.ts.map +1 -0
- package/dist/client/integrations/api.js +123 -0
- package/dist/client/integrations/api.js.map +1 -0
- package/dist/client/integrations/index.d.ts +1 -0
- package/dist/client/integrations/index.d.ts.map +1 -1
- package/dist/client/integrations/index.js +1 -0
- package/dist/client/integrations/index.js.map +1 -1
- package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
- package/dist/client/transcription/use-live-transcription.js +59 -5
- package/dist/client/transcription/use-live-transcription.js.map +1 -1
- package/dist/client/use-run-stuck-detection.d.ts +16 -1
- package/dist/client/use-run-stuck-detection.d.ts.map +1 -1
- package/dist/client/use-run-stuck-detection.js +23 -4
- package/dist/client/use-run-stuck-detection.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +49 -4
- package/dist/deploy/build.js.map +1 -1
- package/dist/deploy/workspace-deploy.d.ts.map +1 -1
- package/dist/deploy/workspace-deploy.js +31 -2
- package/dist/deploy/workspace-deploy.js.map +1 -1
- package/dist/file-upload/types.d.ts +2 -0
- package/dist/file-upload/types.d.ts.map +1 -1
- package/dist/file-upload/types.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
- package/dist/integrations/a2a-continuations-store.js +6 -4
- package/dist/integrations/a2a-continuations-store.js.map +1 -1
- package/dist/integrations/adapters/discord.d.ts +3 -0
- package/dist/integrations/adapters/discord.d.ts.map +1 -0
- package/dist/integrations/adapters/discord.js +261 -0
- package/dist/integrations/adapters/discord.js.map +1 -0
- package/dist/integrations/adapters/index.d.ts +4 -0
- package/dist/integrations/adapters/index.d.ts.map +1 -0
- package/dist/integrations/adapters/index.js +26 -0
- package/dist/integrations/adapters/index.js.map +1 -0
- package/dist/integrations/adapters/microsoft-teams.d.ts +5 -0
- package/dist/integrations/adapters/microsoft-teams.d.ts.map +1 -0
- package/dist/integrations/adapters/microsoft-teams.js +295 -0
- package/dist/integrations/adapters/microsoft-teams.js.map +1 -0
- package/dist/integrations/adapters/slack.d.ts +8 -2
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +736 -27
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/adapters/telegram.d.ts +0 -2
- package/dist/integrations/adapters/telegram.d.ts.map +1 -1
- package/dist/integrations/adapters/telegram.js +49 -15
- package/dist/integrations/adapters/telegram.js.map +1 -1
- package/dist/integrations/adapters/whatsapp.d.ts +0 -2
- package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
- package/dist/integrations/adapters/whatsapp.js +40 -17
- package/dist/integrations/adapters/whatsapp.js.map +1 -1
- package/dist/integrations/catalog.d.ts +75 -0
- package/dist/integrations/catalog.d.ts.map +1 -0
- package/dist/integrations/catalog.js +451 -0
- package/dist/integrations/catalog.js.map +1 -0
- package/dist/integrations/controls-store.d.ts +44 -0
- package/dist/integrations/controls-store.d.ts.map +1 -0
- package/dist/integrations/controls-store.js +129 -0
- package/dist/integrations/controls-store.js.map +1 -0
- package/dist/integrations/index.d.ts +13 -1
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js +9 -0
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/installations-store.d.ts +112 -0
- package/dist/integrations/installations-store.d.ts.map +1 -0
- package/dist/integrations/installations-store.js +493 -0
- package/dist/integrations/installations-store.js.map +1 -0
- package/dist/integrations/integration-memory.d.ts +24 -0
- package/dist/integrations/integration-memory.d.ts.map +1 -0
- package/dist/integrations/integration-memory.js +136 -0
- package/dist/integrations/integration-memory.js.map +1 -0
- package/dist/integrations/pending-tasks-retry-job.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-retry-job.js +6 -5
- package/dist/integrations/pending-tasks-retry-job.js.map +1 -1
- package/dist/integrations/pending-tasks-store.d.ts +17 -0
- package/dist/integrations/pending-tasks-store.d.ts.map +1 -1
- package/dist/integrations/pending-tasks-store.js +71 -5
- package/dist/integrations/pending-tasks-store.js.map +1 -1
- package/dist/integrations/plugin.d.ts.map +1 -1
- package/dist/integrations/plugin.js +520 -35
- package/dist/integrations/plugin.js.map +1 -1
- package/dist/integrations/scope-store.d.ts +65 -0
- package/dist/integrations/scope-store.d.ts.map +1 -0
- package/dist/integrations/scope-store.js +361 -0
- package/dist/integrations/scope-store.js.map +1 -0
- package/dist/integrations/slack-manifest.d.ts +66 -0
- package/dist/integrations/slack-manifest.d.ts.map +1 -0
- package/dist/integrations/slack-manifest.js +70 -0
- package/dist/integrations/slack-manifest.js.map +1 -0
- package/dist/integrations/slack-oauth.d.ts +99 -0
- package/dist/integrations/slack-oauth.d.ts.map +1 -0
- package/dist/integrations/slack-oauth.js +226 -0
- package/dist/integrations/slack-oauth.js.map +1 -0
- package/dist/integrations/types.d.ts +144 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js +16 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/integrations/usage-budget-store.d.ts +84 -0
- package/dist/integrations/usage-budget-store.d.ts.map +1 -0
- package/dist/integrations/usage-budget-store.js +650 -0
- package/dist/integrations/usage-budget-store.js.map +1 -0
- package/dist/integrations/webhook-handler.d.ts +4 -0
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +415 -47
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/jobs/scheduler.d.ts +6 -0
- package/dist/jobs/scheduler.d.ts.map +1 -1
- package/dist/jobs/scheduler.js +83 -4
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/jobs/tools.d.ts.map +1 -1
- package/dist/jobs/tools.js +43 -11
- package/dist/jobs/tools.js.map +1 -1
- package/dist/provider-api/index.d.ts +4 -4
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +72 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/resources/handlers.d.ts.map +1 -1
- package/dist/resources/handlers.js +57 -15
- package/dist/resources/handlers.js.map +1 -1
- package/dist/resources/script-helpers.d.ts.map +1 -1
- package/dist/resources/script-helpers.js +34 -8
- package/dist/resources/script-helpers.js.map +1 -1
- package/dist/resources/store.d.ts +10 -0
- package/dist/resources/store.d.ts.map +1 -1
- package/dist/resources/store.js +54 -47
- package/dist/resources/store.js.map +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +106 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +15 -4
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +248 -113
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +10 -14
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +3 -1
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +9 -2
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/edge.d.ts +1 -1
- package/dist/server/edge.d.ts.map +1 -1
- package/dist/server/edge.js +1 -1
- package/dist/server/edge.js.map +1 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/request-context.d.ts +18 -0
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/social-og-image.d.ts.map +1 -1
- package/dist/server/social-og-image.js +3 -2
- package/dist/server/social-og-image.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/styles/agent-native.css +62 -44
- package/dist/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/dist/templates/default/AGENTS.md +7 -3
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/dist/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
- package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
- package/dist/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
- package/dist/templates/workspace-core/AGENTS.md +3 -2
- package/dist/usage/store.d.ts +7 -0
- package/dist/usage/store.d.ts.map +1 -1
- package/dist/usage/store.js +24 -3
- package/dist/usage/store.js.map +1 -1
- package/docs/content/automation-connectors.mdx +80 -0
- package/docs/content/extensions.mdx +8 -0
- package/docs/content/locales/ar-SA/extensions.mdx +8 -0
- package/docs/content/locales/ar-SA/messaging.mdx +84 -15
- package/docs/content/locales/ar-SA/template-clips.mdx +1 -0
- package/docs/content/locales/ar-SA/template-design.mdx +1 -0
- package/docs/content/locales/de-DE/extensions.mdx +10 -0
- package/docs/content/locales/de-DE/messaging.mdx +92 -15
- package/docs/content/locales/de-DE/template-clips.mdx +1 -0
- package/docs/content/locales/de-DE/template-design.mdx +1 -0
- package/docs/content/locales/es-ES/extensions.mdx +10 -0
- package/docs/content/locales/es-ES/messaging.mdx +91 -15
- package/docs/content/locales/es-ES/template-clips.mdx +1 -0
- package/docs/content/locales/es-ES/template-design.mdx +1 -0
- package/docs/content/locales/fr-FR/extensions.mdx +10 -0
- package/docs/content/locales/fr-FR/messaging.mdx +91 -15
- package/docs/content/locales/fr-FR/template-clips.mdx +1 -0
- package/docs/content/locales/fr-FR/template-design.mdx +1 -0
- package/docs/content/locales/hi-IN/extensions.mdx +8 -0
- package/docs/content/locales/hi-IN/messaging.mdx +81 -15
- package/docs/content/locales/hi-IN/template-clips.mdx +1 -0
- package/docs/content/locales/hi-IN/template-design.mdx +1 -0
- package/docs/content/locales/ja-JP/extensions.mdx +9 -0
- package/docs/content/locales/ja-JP/messaging.mdx +81 -15
- package/docs/content/locales/ja-JP/template-clips.mdx +1 -0
- package/docs/content/locales/ja-JP/template-design.mdx +1 -0
- package/docs/content/locales/ko-KR/extensions.mdx +8 -0
- package/docs/content/locales/ko-KR/messaging.mdx +80 -15
- package/docs/content/locales/ko-KR/template-clips.mdx +1 -0
- package/docs/content/locales/ko-KR/template-design.mdx +1 -0
- package/docs/content/locales/pt-BR/extensions.mdx +9 -0
- package/docs/content/locales/pt-BR/messaging.mdx +88 -15
- package/docs/content/locales/pt-BR/template-clips.mdx +1 -0
- package/docs/content/locales/pt-BR/template-design.mdx +1 -0
- package/docs/content/locales/zh-CN/extensions.mdx +6 -0
- package/docs/content/locales/zh-CN/messaging.mdx +78 -15
- package/docs/content/locales/zh-CN/template-clips.mdx +1 -0
- package/docs/content/locales/zh-CN/template-design.mdx +1 -0
- package/docs/content/locales/zh-TW/extensions.mdx +6 -0
- package/docs/content/locales/zh-TW/messaging.mdx +78 -15
- package/docs/content/locales/zh-TW/template-clips.mdx +1 -0
- package/docs/content/locales/zh-TW/template-design.mdx +1 -0
- package/docs/content/messaging.mdx +227 -45
- package/docs/content/template-clips.mdx +3 -0
- package/docs/content/template-design.mdx +4 -0
- package/package.json +5 -1
- package/src/templates/default/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/src/templates/default/AGENTS.md +7 -3
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/capture-learnings/SKILL.md +22 -9
- package/src/templates/workspace-core/.agents/skills/extension-points/SKILL.md +6 -3
- package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +25 -0
- package/src/templates/workspace-core/.agents/skills/integration-webhooks/SKILL.md +15 -0
- package/src/templates/workspace-core/AGENTS.md +3 -2
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-neutral workflow automation connectors.
|
|
3
|
+
*
|
|
4
|
+
* This is intentionally separate from provider-api: an automation connector
|
|
5
|
+
* invokes a configured workflow or accepts a configured workflow callback. It
|
|
6
|
+
* is not an arbitrary provider HTTP escape hatch and it is not a chat channel.
|
|
7
|
+
*/
|
|
8
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
9
|
+
|
|
10
|
+
import { getHeader, getRouterParam, setResponseStatus } from "h3";
|
|
11
|
+
import type { H3Event } from "h3";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
import { defineAction } from "../action.js";
|
|
15
|
+
import { ssrfSafeFetch } from "../extensions/url-safety.js";
|
|
16
|
+
import { resolveKeyReferencesWithRequestScopes } from "../secrets/substitution.js";
|
|
17
|
+
import { getRequestUserEmail } from "../server/request-context.js";
|
|
18
|
+
|
|
19
|
+
const DEFAULT_MAX_REQUEST_BYTES = 64 * 1024;
|
|
20
|
+
const DEFAULT_MAX_RESPONSE_BYTES = 128 * 1024;
|
|
21
|
+
const DEFAULT_TIMEOUT_MS = 10_000;
|
|
22
|
+
const DEFAULT_MAX_ATTEMPTS = 2;
|
|
23
|
+
|
|
24
|
+
export type AutomationResponseMode = "synchronous" | "asynchronous";
|
|
25
|
+
export type AutomationInvocationStatus = "completed" | "accepted";
|
|
26
|
+
export type JsonSchema = Readonly<Record<string, unknown>>;
|
|
27
|
+
|
|
28
|
+
export interface AutomationRetryPolicy {
|
|
29
|
+
/** Total request attempts, including the first. Bounded to three. */
|
|
30
|
+
readonly maxAttempts?: number;
|
|
31
|
+
readonly retryDelayMs?: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface AutomationWorkflowCapabilities {
|
|
35
|
+
readonly invokesExternalWorkflow: boolean;
|
|
36
|
+
readonly receivesCallback: boolean;
|
|
37
|
+
readonly supportsIdempotency: boolean;
|
|
38
|
+
readonly supportsSynchronousResponse: boolean;
|
|
39
|
+
readonly supportsAsynchronousResponse: boolean;
|
|
40
|
+
readonly mayCauseExternalSideEffects: boolean;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface AutomationOutboundDefinition {
|
|
44
|
+
/** An explicit, static HTTPS origin such as https://automations.example.com. */
|
|
45
|
+
readonly baseUrl: string;
|
|
46
|
+
/** Additional explicit origins allowed for this workflow, if any. */
|
|
47
|
+
readonly allowedOrigins?: readonly string[];
|
|
48
|
+
/** A static path below baseUrl. It is never supplied by an agent. */
|
|
49
|
+
readonly path: string;
|
|
50
|
+
readonly method?: "POST" | "PUT" | "PATCH";
|
|
51
|
+
/**
|
|
52
|
+
* Static headers may use `${keys.NAME}` references. They are resolved only
|
|
53
|
+
* after an action call reaches the server and are redacted from all results.
|
|
54
|
+
*/
|
|
55
|
+
readonly headers?: Readonly<Record<string, string>>;
|
|
56
|
+
readonly credentialRequirements?: readonly string[];
|
|
57
|
+
readonly timeoutMs?: number;
|
|
58
|
+
readonly retry?: AutomationRetryPolicy;
|
|
59
|
+
readonly maxRequestBytes?: number;
|
|
60
|
+
readonly maxResponseBytes?: number;
|
|
61
|
+
readonly idempotencyHeader?: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export type AutomationCallbackAuthentication =
|
|
65
|
+
| {
|
|
66
|
+
readonly kind: "shared-secret";
|
|
67
|
+
readonly secretRef: string;
|
|
68
|
+
readonly header: string;
|
|
69
|
+
readonly prefix?: string;
|
|
70
|
+
}
|
|
71
|
+
| {
|
|
72
|
+
readonly kind: "hmac-sha256";
|
|
73
|
+
readonly secretRef: string;
|
|
74
|
+
readonly header: string;
|
|
75
|
+
readonly prefix?: string;
|
|
76
|
+
}
|
|
77
|
+
| {
|
|
78
|
+
readonly kind: "provider-auth";
|
|
79
|
+
/**
|
|
80
|
+
* Provider verification stays in the app adapter; the shared runtime
|
|
81
|
+
* never pretends every provider uses the same signature protocol.
|
|
82
|
+
*/
|
|
83
|
+
readonly verify: (input: {
|
|
84
|
+
readonly rawBody: string;
|
|
85
|
+
readonly headers: Headers;
|
|
86
|
+
}) => Promise<boolean>;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export interface AutomationInboundDefinition {
|
|
90
|
+
readonly authentication: AutomationCallbackAuthentication;
|
|
91
|
+
readonly eventIdHeader?: string;
|
|
92
|
+
readonly maxRequestBytes?: number;
|
|
93
|
+
/**
|
|
94
|
+
* Receiving a callback that starts agent work requires both durable callbacks
|
|
95
|
+
* below. The runtime rejects configurations that omit either one.
|
|
96
|
+
*/
|
|
97
|
+
readonly triggersAgentExecution?: boolean;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export interface AutomationWorkflowDefinition {
|
|
101
|
+
/** Stable app-owned ID; callers use this rather than a URL. */
|
|
102
|
+
readonly id: string;
|
|
103
|
+
readonly connectorId: string;
|
|
104
|
+
readonly name: string;
|
|
105
|
+
readonly inputSchema: JsonSchema;
|
|
106
|
+
readonly outputSchema?: JsonSchema;
|
|
107
|
+
readonly response: { readonly mode: AutomationResponseMode };
|
|
108
|
+
readonly capabilities: AutomationWorkflowCapabilities;
|
|
109
|
+
readonly outbound?: AutomationOutboundDefinition;
|
|
110
|
+
readonly inbound?: AutomationInboundDefinition;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface AutomationInvocation {
|
|
114
|
+
readonly workflowId: string;
|
|
115
|
+
readonly input: Record<string, unknown>;
|
|
116
|
+
readonly idempotencyKey?: string;
|
|
117
|
+
readonly userEmail: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface AutomationInvocationResult {
|
|
121
|
+
readonly workflowId: string;
|
|
122
|
+
readonly connectorId: string;
|
|
123
|
+
readonly status: AutomationInvocationStatus;
|
|
124
|
+
readonly responseMode: AutomationResponseMode;
|
|
125
|
+
readonly attempts: number;
|
|
126
|
+
readonly httpStatus: number;
|
|
127
|
+
readonly output?: unknown;
|
|
128
|
+
readonly responseTruncated: boolean;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
export interface AutomationCallbackInput {
|
|
132
|
+
readonly workflowId: string;
|
|
133
|
+
readonly rawBody: string;
|
|
134
|
+
readonly headers: Headers;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export interface AutomationCallbackResult {
|
|
138
|
+
readonly accepted: boolean;
|
|
139
|
+
readonly duplicate: boolean;
|
|
140
|
+
readonly eventId: string;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export class AutomationConnectorError extends Error {
|
|
144
|
+
constructor(
|
|
145
|
+
readonly code:
|
|
146
|
+
| "unknown_workflow"
|
|
147
|
+
| "unsupported_direction"
|
|
148
|
+
| "invalid_configuration"
|
|
149
|
+
| "blocked_target"
|
|
150
|
+
| "payload_too_large"
|
|
151
|
+
| "authentication_failed"
|
|
152
|
+
| "missing_idempotency"
|
|
153
|
+
| "timeout"
|
|
154
|
+
| "request_failed",
|
|
155
|
+
message: string,
|
|
156
|
+
) {
|
|
157
|
+
super(message);
|
|
158
|
+
this.name = "AutomationConnectorError";
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface AutomationRuntimeOptions {
|
|
163
|
+
readonly workflows: readonly AutomationWorkflowDefinition[];
|
|
164
|
+
/**
|
|
165
|
+
* Test-only transport injection. Production calls always use the framework
|
|
166
|
+
* SSRF-safe fetch path.
|
|
167
|
+
*/
|
|
168
|
+
readonly fetch?: typeof fetch;
|
|
169
|
+
/**
|
|
170
|
+
* The caller receives the raw secret only inside this server-side callback.
|
|
171
|
+
* Return a value for a configured secret reference; never log or return it.
|
|
172
|
+
*/
|
|
173
|
+
readonly resolveSecret?: (
|
|
174
|
+
secretRef: string,
|
|
175
|
+
context: { readonly userEmail?: string },
|
|
176
|
+
) => Promise<string | null>;
|
|
177
|
+
/**
|
|
178
|
+
* Durable, SQL-backed idempotency claim. Return false for an already-seen
|
|
179
|
+
* event. It is required when callbacks trigger agent execution.
|
|
180
|
+
*/
|
|
181
|
+
readonly claimInboundEvent?: (input: {
|
|
182
|
+
readonly workflow: AutomationWorkflowDefinition;
|
|
183
|
+
readonly eventId: string;
|
|
184
|
+
}) => Promise<boolean>;
|
|
185
|
+
/**
|
|
186
|
+
* Release a claim acquired by claimInboundEvent when durable enqueueing
|
|
187
|
+
* throws. It is required when callbacks trigger agent execution so a
|
|
188
|
+
* provider retry can claim the event again.
|
|
189
|
+
*/
|
|
190
|
+
readonly releaseInboundEvent?: (input: {
|
|
191
|
+
readonly workflow: AutomationWorkflowDefinition;
|
|
192
|
+
readonly eventId: string;
|
|
193
|
+
}) => Promise<void>;
|
|
194
|
+
/**
|
|
195
|
+
* Persist and dispatch agent work using the app's established durable queue.
|
|
196
|
+
* This must be idempotent for the workflow/event ID pair because a transport
|
|
197
|
+
* failure can make enqueue success ambiguous. Do not run an agent loop in a
|
|
198
|
+
* callback request.
|
|
199
|
+
*/
|
|
200
|
+
readonly enqueueInboundEvent?: (input: {
|
|
201
|
+
readonly workflow: AutomationWorkflowDefinition;
|
|
202
|
+
readonly eventId: string;
|
|
203
|
+
readonly payload: unknown;
|
|
204
|
+
}) => Promise<void>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface AutomationRuntime {
|
|
208
|
+
readonly listWorkflows: () => readonly AutomationWorkflowDefinition[];
|
|
209
|
+
readonly getWorkflow: (
|
|
210
|
+
workflowId: string,
|
|
211
|
+
) => AutomationWorkflowDefinition | undefined;
|
|
212
|
+
readonly invoke: (
|
|
213
|
+
input: AutomationInvocation,
|
|
214
|
+
) => Promise<AutomationInvocationResult>;
|
|
215
|
+
readonly receiveCallback: (
|
|
216
|
+
input: AutomationCallbackInput,
|
|
217
|
+
) => Promise<AutomationCallbackResult>;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function byteLength(value: string): number {
|
|
221
|
+
return new TextEncoder().encode(value).byteLength;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function bytesToString(
|
|
225
|
+
chunks: readonly Uint8Array[],
|
|
226
|
+
byteCount: number,
|
|
227
|
+
): string {
|
|
228
|
+
const bytes = new Uint8Array(byteCount);
|
|
229
|
+
let offset = 0;
|
|
230
|
+
for (const chunk of chunks) {
|
|
231
|
+
bytes.set(chunk, offset);
|
|
232
|
+
offset += chunk.byteLength;
|
|
233
|
+
}
|
|
234
|
+
return new TextDecoder().decode(bytes);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function clampBytes(value: number | undefined, fallback: number): number {
|
|
238
|
+
if (!Number.isFinite(value)) return fallback;
|
|
239
|
+
return Math.max(1, Math.min(Math.floor(value!), 1024 * 1024));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function normalizeAttempts(value: number | undefined): number {
|
|
243
|
+
if (!Number.isFinite(value)) return DEFAULT_MAX_ATTEMPTS;
|
|
244
|
+
return Math.max(1, Math.min(Math.floor(value!), 3));
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function redact(value: string, secretValues: readonly string[]): string {
|
|
248
|
+
return secretValues.reduce(
|
|
249
|
+
(result, secret) =>
|
|
250
|
+
secret ? result.split(secret).join("[REDACTED]") : result,
|
|
251
|
+
value,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function redactUnknown(
|
|
256
|
+
value: unknown,
|
|
257
|
+
secretValues: readonly string[],
|
|
258
|
+
): unknown {
|
|
259
|
+
if (typeof value === "string") return redact(value, secretValues);
|
|
260
|
+
if (Array.isArray(value)) {
|
|
261
|
+
return value.map((item) => redactUnknown(item, secretValues));
|
|
262
|
+
}
|
|
263
|
+
if (value && typeof value === "object") {
|
|
264
|
+
return Object.fromEntries(
|
|
265
|
+
Object.entries(value).map(([key, item]) => [
|
|
266
|
+
key,
|
|
267
|
+
redactUnknown(item, secretValues),
|
|
268
|
+
]),
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
return value;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
function responseTarget(url: URL): string {
|
|
275
|
+
return `${url.origin}${url.pathname}`;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function assertAllowedTarget(definition: AutomationOutboundDefinition): URL {
|
|
279
|
+
let base: URL;
|
|
280
|
+
let target: URL;
|
|
281
|
+
try {
|
|
282
|
+
base = new URL(definition.baseUrl);
|
|
283
|
+
target = new URL(definition.path, base);
|
|
284
|
+
} catch {
|
|
285
|
+
throw new AutomationConnectorError(
|
|
286
|
+
"invalid_configuration",
|
|
287
|
+
"Workflow has an invalid configured base URL or path.",
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
if (base.protocol !== "https:" || target.protocol !== "https:") {
|
|
291
|
+
throw new AutomationConnectorError(
|
|
292
|
+
"blocked_target",
|
|
293
|
+
"Automation workflow targets must use HTTPS.",
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
const allowedOrigins = new Set([
|
|
297
|
+
base.origin,
|
|
298
|
+
...(definition.allowedOrigins ?? []),
|
|
299
|
+
]);
|
|
300
|
+
if (!allowedOrigins.has(target.origin)) {
|
|
301
|
+
throw new AutomationConnectorError(
|
|
302
|
+
"blocked_target",
|
|
303
|
+
"Workflow target is outside its configured allow-listed origin.",
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
return target;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
async function resolveStaticHeaders(
|
|
310
|
+
headers: Readonly<Record<string, string>> | undefined,
|
|
311
|
+
userEmail: string,
|
|
312
|
+
resolveSecret: AutomationRuntimeOptions["resolveSecret"],
|
|
313
|
+
): Promise<{ headers: Record<string, string>; secretValues: string[] }> {
|
|
314
|
+
const output: Record<string, string> = {};
|
|
315
|
+
const secretValues: string[] = [];
|
|
316
|
+
for (const [name, value] of Object.entries(headers ?? {})) {
|
|
317
|
+
let resolved = value;
|
|
318
|
+
if (value.includes("${keys.")) {
|
|
319
|
+
const result = await resolveKeyReferencesWithRequestScopes(
|
|
320
|
+
value,
|
|
321
|
+
userEmail,
|
|
322
|
+
);
|
|
323
|
+
resolved = result.resolved;
|
|
324
|
+
secretValues.push(...result.secretValues);
|
|
325
|
+
}
|
|
326
|
+
output[name] = resolved;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// A small app adapter may use named secret refs rather than the app vault
|
|
330
|
+
// syntax. Resolve those only from static header values, never from agent args.
|
|
331
|
+
if (resolveSecret) {
|
|
332
|
+
for (const [name, value] of Object.entries(output)) {
|
|
333
|
+
const match = value.match(/^\$\{automationSecret\.([A-Za-z0-9_-]+)\}$/);
|
|
334
|
+
if (!match) continue;
|
|
335
|
+
const secret = await resolveSecret(match[1], { userEmail });
|
|
336
|
+
if (!secret) {
|
|
337
|
+
throw new AutomationConnectorError(
|
|
338
|
+
"invalid_configuration",
|
|
339
|
+
`A configured credential is unavailable for header "${name}".`,
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
output[name] = secret;
|
|
343
|
+
secretValues.push(secret);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
return { headers: output, secretValues };
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
async function readBoundedResponse(
|
|
350
|
+
response: Response,
|
|
351
|
+
maxBytes: number,
|
|
352
|
+
): Promise<{ value: unknown; truncated: boolean }> {
|
|
353
|
+
const reader = response.body?.getReader();
|
|
354
|
+
if (!reader) return { value: "", truncated: false };
|
|
355
|
+
|
|
356
|
+
const chunks: Uint8Array[] = [];
|
|
357
|
+
let byteCount = 0;
|
|
358
|
+
let truncated = false;
|
|
359
|
+
const declaredLength = Number(response.headers.get("content-length"));
|
|
360
|
+
const declaredOversize =
|
|
361
|
+
Number.isFinite(declaredLength) && declaredLength > maxBytes;
|
|
362
|
+
|
|
363
|
+
try {
|
|
364
|
+
while (true) {
|
|
365
|
+
const { done, value } = await reader.read();
|
|
366
|
+
if (done) break;
|
|
367
|
+
if (value.byteLength === 0) continue;
|
|
368
|
+
|
|
369
|
+
const remaining = maxBytes - byteCount;
|
|
370
|
+
if (value.byteLength > remaining) {
|
|
371
|
+
if (remaining > 0) chunks.push(value.subarray(0, remaining));
|
|
372
|
+
byteCount += remaining;
|
|
373
|
+
truncated = true;
|
|
374
|
+
await reader.cancel().catch(() => {});
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
chunks.push(value);
|
|
379
|
+
byteCount += value.byteLength;
|
|
380
|
+
if (byteCount === maxBytes && declaredOversize) {
|
|
381
|
+
truncated = true;
|
|
382
|
+
await reader.cancel().catch(() => {});
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
} finally {
|
|
387
|
+
reader.releaseLock();
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const bounded = bytesToString(chunks, byteCount);
|
|
391
|
+
try {
|
|
392
|
+
return { value: JSON.parse(bounded), truncated };
|
|
393
|
+
} catch {
|
|
394
|
+
return { value: bounded, truncated };
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
function payloadTooLarge(maxBytes: number): AutomationConnectorError {
|
|
399
|
+
return new AutomationConnectorError(
|
|
400
|
+
"payload_too_large",
|
|
401
|
+
`Callback exceeds the ${maxBytes}-byte limit.`,
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
async function readBoundedRequestBody(
|
|
406
|
+
event: H3Event,
|
|
407
|
+
maxBytes: number,
|
|
408
|
+
): Promise<string> {
|
|
409
|
+
const contentLength = getHeader(event, "content-length");
|
|
410
|
+
if (contentLength) {
|
|
411
|
+
const declared = Number(contentLength);
|
|
412
|
+
if (Number.isFinite(declared) && declared > maxBytes) {
|
|
413
|
+
throw payloadTooLarge(maxBytes);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
const body = event.req.body;
|
|
418
|
+
if (!body) return "";
|
|
419
|
+
|
|
420
|
+
const reader = body.getReader();
|
|
421
|
+
const chunks: Uint8Array[] = [];
|
|
422
|
+
let byteCount = 0;
|
|
423
|
+
try {
|
|
424
|
+
while (true) {
|
|
425
|
+
const { done, value } = await reader.read();
|
|
426
|
+
if (done) break;
|
|
427
|
+
if (value.byteLength === 0) continue;
|
|
428
|
+
if (byteCount + value.byteLength > maxBytes) {
|
|
429
|
+
await reader.cancel().catch(() => {});
|
|
430
|
+
throw payloadTooLarge(maxBytes);
|
|
431
|
+
}
|
|
432
|
+
chunks.push(value);
|
|
433
|
+
byteCount += value.byteLength;
|
|
434
|
+
}
|
|
435
|
+
} finally {
|
|
436
|
+
reader.releaseLock();
|
|
437
|
+
}
|
|
438
|
+
return bytesToString(chunks, byteCount);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function shouldRetry(status: number): boolean {
|
|
442
|
+
return status === 408 || status === 429 || status >= 500;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function secureEqual(left: string, right: string): boolean {
|
|
446
|
+
const leftBuffer = Buffer.from(left);
|
|
447
|
+
const rightBuffer = Buffer.from(right);
|
|
448
|
+
return (
|
|
449
|
+
leftBuffer.length === rightBuffer.length &&
|
|
450
|
+
timingSafeEqual(leftBuffer, rightBuffer)
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
export function createAutomationRuntime(
|
|
455
|
+
options: AutomationRuntimeOptions,
|
|
456
|
+
): AutomationRuntime {
|
|
457
|
+
const workflows = new Map(
|
|
458
|
+
options.workflows.map((workflow) => [workflow.id, workflow]),
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
async function invoke(
|
|
462
|
+
invocation: AutomationInvocation,
|
|
463
|
+
): Promise<AutomationInvocationResult> {
|
|
464
|
+
const workflow = workflows.get(invocation.workflowId);
|
|
465
|
+
if (!workflow) {
|
|
466
|
+
throw new AutomationConnectorError(
|
|
467
|
+
"unknown_workflow",
|
|
468
|
+
`Unknown automation workflow "${invocation.workflowId}".`,
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
if (!workflow.outbound || !workflow.capabilities.invokesExternalWorkflow) {
|
|
472
|
+
throw new AutomationConnectorError(
|
|
473
|
+
"unsupported_direction",
|
|
474
|
+
`Workflow "${workflow.id}" does not support outbound invocation.`,
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const target = assertAllowedTarget(workflow.outbound);
|
|
479
|
+
const body = JSON.stringify(invocation.input);
|
|
480
|
+
const maxRequestBytes = clampBytes(
|
|
481
|
+
workflow.outbound.maxRequestBytes,
|
|
482
|
+
DEFAULT_MAX_REQUEST_BYTES,
|
|
483
|
+
);
|
|
484
|
+
if (byteLength(body) > maxRequestBytes) {
|
|
485
|
+
throw new AutomationConnectorError(
|
|
486
|
+
"payload_too_large",
|
|
487
|
+
`Automation input exceeds the ${maxRequestBytes}-byte limit.`,
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
if (
|
|
491
|
+
workflow.outbound.idempotencyHeader &&
|
|
492
|
+
workflow.capabilities.supportsIdempotency &&
|
|
493
|
+
!invocation.idempotencyKey
|
|
494
|
+
) {
|
|
495
|
+
throw new AutomationConnectorError(
|
|
496
|
+
"missing_idempotency",
|
|
497
|
+
"This workflow requires an idempotency key.",
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
const { headers, secretValues } = await resolveStaticHeaders(
|
|
502
|
+
workflow.outbound.headers,
|
|
503
|
+
invocation.userEmail,
|
|
504
|
+
options.resolveSecret,
|
|
505
|
+
);
|
|
506
|
+
headers["content-type"] ??= "application/json";
|
|
507
|
+
if (workflow.outbound.idempotencyHeader && invocation.idempotencyKey) {
|
|
508
|
+
headers[workflow.outbound.idempotencyHeader] = invocation.idempotencyKey;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const attempts = normalizeAttempts(workflow.outbound.retry?.maxAttempts);
|
|
512
|
+
const timeoutMs = Math.max(
|
|
513
|
+
1,
|
|
514
|
+
Math.min(workflow.outbound.timeoutMs ?? DEFAULT_TIMEOUT_MS, 30_000),
|
|
515
|
+
);
|
|
516
|
+
const maxResponseBytes = clampBytes(
|
|
517
|
+
workflow.outbound.maxResponseBytes,
|
|
518
|
+
DEFAULT_MAX_RESPONSE_BYTES,
|
|
519
|
+
);
|
|
520
|
+
let lastError: unknown;
|
|
521
|
+
|
|
522
|
+
for (let attempt = 1; attempt <= attempts; attempt++) {
|
|
523
|
+
const abort = new AbortController();
|
|
524
|
+
const timer = setTimeout(() => abort.abort(), timeoutMs);
|
|
525
|
+
try {
|
|
526
|
+
const request: RequestInit = {
|
|
527
|
+
method: workflow.outbound.method ?? "POST",
|
|
528
|
+
headers,
|
|
529
|
+
body,
|
|
530
|
+
signal: abort.signal,
|
|
531
|
+
};
|
|
532
|
+
const response = options.fetch
|
|
533
|
+
? await options.fetch(target.href, { ...request, redirect: "manual" })
|
|
534
|
+
: await ssrfSafeFetch(target.href, request, {
|
|
535
|
+
httpsOnly: true,
|
|
536
|
+
maxRedirects: 0,
|
|
537
|
+
});
|
|
538
|
+
const parsed = await readBoundedResponse(response, maxResponseBytes);
|
|
539
|
+
if (
|
|
540
|
+
!response.ok &&
|
|
541
|
+
shouldRetry(response.status) &&
|
|
542
|
+
attempt < attempts
|
|
543
|
+
) {
|
|
544
|
+
await new Promise((resolve) =>
|
|
545
|
+
setTimeout(resolve, workflow.outbound!.retry?.retryDelayMs ?? 250),
|
|
546
|
+
);
|
|
547
|
+
continue;
|
|
548
|
+
}
|
|
549
|
+
if (!response.ok) {
|
|
550
|
+
throw new AutomationConnectorError(
|
|
551
|
+
"request_failed",
|
|
552
|
+
`Workflow request to ${responseTarget(target)} failed with HTTP ${response.status}.`,
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
return {
|
|
556
|
+
workflowId: workflow.id,
|
|
557
|
+
connectorId: workflow.connectorId,
|
|
558
|
+
status:
|
|
559
|
+
workflow.response.mode === "asynchronous"
|
|
560
|
+
? "accepted"
|
|
561
|
+
: "completed",
|
|
562
|
+
responseMode: workflow.response.mode,
|
|
563
|
+
attempts: attempt,
|
|
564
|
+
httpStatus: response.status,
|
|
565
|
+
output: redactUnknown(parsed.value, secretValues),
|
|
566
|
+
responseTruncated: parsed.truncated,
|
|
567
|
+
};
|
|
568
|
+
} catch (error) {
|
|
569
|
+
lastError = error;
|
|
570
|
+
if (abort.signal.aborted) {
|
|
571
|
+
lastError = new AutomationConnectorError(
|
|
572
|
+
"timeout",
|
|
573
|
+
`Workflow request to ${responseTarget(target)} timed out.`,
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
const retryable =
|
|
577
|
+
abort.signal.aborted ||
|
|
578
|
+
!(lastError instanceof AutomationConnectorError);
|
|
579
|
+
if (attempt < attempts && retryable) {
|
|
580
|
+
await new Promise((resolve) =>
|
|
581
|
+
setTimeout(resolve, workflow.outbound!.retry?.retryDelayMs ?? 250),
|
|
582
|
+
);
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
break;
|
|
586
|
+
} finally {
|
|
587
|
+
clearTimeout(timer);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
if (lastError instanceof AutomationConnectorError) throw lastError;
|
|
591
|
+
throw new AutomationConnectorError(
|
|
592
|
+
"request_failed",
|
|
593
|
+
`Workflow request to ${responseTarget(target)} failed after ${attempts} attempts.`,
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
async function receiveCallback(
|
|
598
|
+
input: AutomationCallbackInput,
|
|
599
|
+
): Promise<AutomationCallbackResult> {
|
|
600
|
+
const workflow = workflows.get(input.workflowId);
|
|
601
|
+
if (!workflow) {
|
|
602
|
+
throw new AutomationConnectorError(
|
|
603
|
+
"unknown_workflow",
|
|
604
|
+
"Unknown automation callback.",
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
if (!workflow.inbound || !workflow.capabilities.receivesCallback) {
|
|
608
|
+
throw new AutomationConnectorError(
|
|
609
|
+
"unsupported_direction",
|
|
610
|
+
"This workflow does not accept callbacks.",
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
const maxRequestBytes = clampBytes(
|
|
614
|
+
workflow.inbound.maxRequestBytes,
|
|
615
|
+
DEFAULT_MAX_REQUEST_BYTES,
|
|
616
|
+
);
|
|
617
|
+
if (byteLength(input.rawBody) > maxRequestBytes) {
|
|
618
|
+
throw new AutomationConnectorError(
|
|
619
|
+
"payload_too_large",
|
|
620
|
+
`Callback exceeds the ${maxRequestBytes}-byte limit.`,
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const auth = workflow.inbound.authentication;
|
|
625
|
+
let authenticated = false;
|
|
626
|
+
if (auth.kind === "provider-auth") {
|
|
627
|
+
authenticated = await auth.verify({
|
|
628
|
+
rawBody: input.rawBody,
|
|
629
|
+
headers: input.headers,
|
|
630
|
+
});
|
|
631
|
+
} else {
|
|
632
|
+
const secret = await options.resolveSecret?.(auth.secretRef, {});
|
|
633
|
+
if (!secret) {
|
|
634
|
+
throw new AutomationConnectorError(
|
|
635
|
+
"invalid_configuration",
|
|
636
|
+
"The configured automation callback credential is unavailable.",
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
const supplied = input.headers.get(auth.header) ?? "";
|
|
640
|
+
const expected =
|
|
641
|
+
auth.kind === "hmac-sha256"
|
|
642
|
+
? `${auth.prefix ?? "sha256="}${createHmac("sha256", secret).update(input.rawBody).digest("hex")}`
|
|
643
|
+
: `${auth.prefix ?? ""}${secret}`;
|
|
644
|
+
authenticated = secureEqual(supplied, expected);
|
|
645
|
+
}
|
|
646
|
+
if (!authenticated) {
|
|
647
|
+
throw new AutomationConnectorError(
|
|
648
|
+
"authentication_failed",
|
|
649
|
+
"Automation callback authentication failed.",
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
const suppliedEventId = input.headers
|
|
654
|
+
.get(workflow.inbound.eventIdHeader ?? "x-event-id")
|
|
655
|
+
?.trim();
|
|
656
|
+
let eventId: string;
|
|
657
|
+
if (workflow.inbound.triggersAgentExecution) {
|
|
658
|
+
if (
|
|
659
|
+
!options.claimInboundEvent ||
|
|
660
|
+
!options.releaseInboundEvent ||
|
|
661
|
+
!options.enqueueInboundEvent
|
|
662
|
+
) {
|
|
663
|
+
throw new AutomationConnectorError(
|
|
664
|
+
"invalid_configuration",
|
|
665
|
+
"Agent-triggering callbacks require durable claim, release, and queue handlers.",
|
|
666
|
+
);
|
|
667
|
+
}
|
|
668
|
+
if (!suppliedEventId) {
|
|
669
|
+
throw new AutomationConnectorError(
|
|
670
|
+
"missing_idempotency",
|
|
671
|
+
"Agent-triggering callbacks require a stable provider event ID.",
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
eventId = suppliedEventId;
|
|
675
|
+
const claimed = await options.claimInboundEvent({ workflow, eventId });
|
|
676
|
+
if (!claimed) return { accepted: true, duplicate: true, eventId };
|
|
677
|
+
let payload: unknown = input.rawBody;
|
|
678
|
+
try {
|
|
679
|
+
payload = JSON.parse(input.rawBody);
|
|
680
|
+
} catch {
|
|
681
|
+
// A plain-text callback is permitted; the payload bound above still applies.
|
|
682
|
+
}
|
|
683
|
+
try {
|
|
684
|
+
await options.enqueueInboundEvent({ workflow, eventId, payload });
|
|
685
|
+
} catch (error) {
|
|
686
|
+
await options.releaseInboundEvent({ workflow, eventId });
|
|
687
|
+
throw error;
|
|
688
|
+
}
|
|
689
|
+
} else {
|
|
690
|
+
eventId =
|
|
691
|
+
suppliedEventId ??
|
|
692
|
+
createHmac("sha256", workflow.id).update(input.rawBody).digest("hex");
|
|
693
|
+
}
|
|
694
|
+
return { accepted: true, duplicate: false, eventId };
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return {
|
|
698
|
+
listWorkflows: () => [...workflows.values()],
|
|
699
|
+
getWorkflow: (workflowId) => workflows.get(workflowId),
|
|
700
|
+
invoke,
|
|
701
|
+
receiveCallback,
|
|
702
|
+
};
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
const invokeAutomationWorkflowSchema = z.object({
|
|
706
|
+
workflowId: z.string().min(1),
|
|
707
|
+
input: z.record(z.string(), z.unknown()),
|
|
708
|
+
idempotencyKey: z.string().min(8).max(256).optional(),
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Creates the narrow action applications expose to their agent and UI. The
|
|
713
|
+
* workflow identity resolves to static server configuration; callers cannot
|
|
714
|
+
* supply arbitrary target URLs or credentials.
|
|
715
|
+
*/
|
|
716
|
+
export function createInvokeAutomationWorkflowAction(
|
|
717
|
+
runtime: AutomationRuntime,
|
|
718
|
+
options: {
|
|
719
|
+
readonly description?: string;
|
|
720
|
+
readonly requireApproval?: boolean;
|
|
721
|
+
} = {},
|
|
722
|
+
) {
|
|
723
|
+
return defineAction({
|
|
724
|
+
description:
|
|
725
|
+
options.description ??
|
|
726
|
+
"Invoke a configured external automation workflow by its stable workflow ID. This cannot call arbitrary URLs and never exposes credentials.",
|
|
727
|
+
schema: invokeAutomationWorkflowSchema,
|
|
728
|
+
http: false,
|
|
729
|
+
needsApproval: (args) =>
|
|
730
|
+
options.requireApproval ??
|
|
731
|
+
runtime.getWorkflow(args.workflowId)?.capabilities
|
|
732
|
+
.mayCauseExternalSideEffects !== false,
|
|
733
|
+
run: async (args) => {
|
|
734
|
+
const userEmail = getRequestUserEmail();
|
|
735
|
+
if (!userEmail)
|
|
736
|
+
throw new Error("You must be signed in to invoke a workflow.");
|
|
737
|
+
return runtime.invoke({ ...args, userEmail });
|
|
738
|
+
},
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/**
|
|
743
|
+
* Builds a route-only H3 callback handler. Mount it at
|
|
744
|
+
* `/_agent-native/automations/callback/:workflowId`; ordinary app operations
|
|
745
|
+
* still use actions. The callback only authenticates, deduplicates, and
|
|
746
|
+
* durably enqueues work before returning a quick acknowledgement.
|
|
747
|
+
*/
|
|
748
|
+
export function createAutomationCallbackHandler(runtime: AutomationRuntime) {
|
|
749
|
+
return async (event: H3Event) => {
|
|
750
|
+
const workflowId = getRouterParam(event, "workflowId");
|
|
751
|
+
if (!workflowId) {
|
|
752
|
+
setResponseStatus(event, 404);
|
|
753
|
+
return { error: "Unknown automation workflow." };
|
|
754
|
+
}
|
|
755
|
+
try {
|
|
756
|
+
const workflow = runtime.getWorkflow(workflowId);
|
|
757
|
+
if (!workflow?.inbound || !workflow.capabilities.receivesCallback) {
|
|
758
|
+
throw new AutomationConnectorError(
|
|
759
|
+
workflow ? "unsupported_direction" : "unknown_workflow",
|
|
760
|
+
"Unknown automation callback.",
|
|
761
|
+
);
|
|
762
|
+
}
|
|
763
|
+
const maxRequestBytes = clampBytes(
|
|
764
|
+
workflow.inbound.maxRequestBytes,
|
|
765
|
+
DEFAULT_MAX_REQUEST_BYTES,
|
|
766
|
+
);
|
|
767
|
+
const rawBody = await readBoundedRequestBody(event, maxRequestBytes);
|
|
768
|
+
const result = await runtime.receiveCallback({
|
|
769
|
+
workflowId,
|
|
770
|
+
rawBody,
|
|
771
|
+
headers: new Headers(event.headers),
|
|
772
|
+
});
|
|
773
|
+
setResponseStatus(event, result.duplicate ? 200 : 202);
|
|
774
|
+
return {
|
|
775
|
+
accepted: true,
|
|
776
|
+
duplicate: result.duplicate,
|
|
777
|
+
eventId: result.eventId,
|
|
778
|
+
};
|
|
779
|
+
} catch (error) {
|
|
780
|
+
let status = 500;
|
|
781
|
+
if (error instanceof AutomationConnectorError) {
|
|
782
|
+
switch (error.code) {
|
|
783
|
+
case "unknown_workflow":
|
|
784
|
+
case "unsupported_direction":
|
|
785
|
+
status = 404;
|
|
786
|
+
break;
|
|
787
|
+
case "authentication_failed":
|
|
788
|
+
status = 401;
|
|
789
|
+
break;
|
|
790
|
+
case "missing_idempotency":
|
|
791
|
+
status = 400;
|
|
792
|
+
break;
|
|
793
|
+
case "payload_too_large":
|
|
794
|
+
status = 413;
|
|
795
|
+
break;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
setResponseStatus(event, status);
|
|
799
|
+
return { error: "Automation callback rejected." };
|
|
800
|
+
}
|
|
801
|
+
};
|
|
802
|
+
}
|