@agent-native/core 0.92.12 → 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 +39 -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 +15 -3
- package/corpus/core/src/agent/run-manager.ts +130 -10
- package/corpus/core/src/agent/run-store.ts +225 -15
- 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 +54 -5
- 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/hooks/use-library.ts +1 -1
- package/corpus/templates/clips/app/hooks/use-navigation-state.ts +10 -2
- 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-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 +10 -16
- package/corpus/templates/content/actions/_database-source-utils.ts +58 -11
- package/corpus/templates/content/actions/_property-utils.ts +30 -2
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +312 -114
- package/corpus/templates/content/actions/submit-content-database-form.ts +497 -0
- 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-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 +27 -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 +2 -2
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +15 -5
- 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 +90 -9
- 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 +206 -15
- 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 +49 -4
- 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/struct-routes.d.ts +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/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +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 +3 -3
- 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
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
import { createError, getHeader, readRawBody } from "h3";
|
|
2
2
|
import { resolveSecret } from "../../server/credential-provider.js";
|
|
3
|
+
import { getRequestContext } from "../../server/request-context.js";
|
|
4
|
+
import { getIntegrationRequestContext } from "../../server/request-context.js";
|
|
5
|
+
import { createIntegrationControl } from "../controls-store.js";
|
|
6
|
+
import { getActiveIntegrationInstallationByKey, getActiveIntegrationInstallationForTenant, listIntegrationInstallations, resolveIntegrationTokenBundle, } from "../installations-store.js";
|
|
7
|
+
import { hasActivePendingTask } from "../pending-tasks-store.js";
|
|
8
|
+
import { slackInstallationKey } from "../slack-oauth.js";
|
|
3
9
|
/** Slack's max message length */
|
|
4
10
|
const SLACK_MAX_LENGTH = 4000;
|
|
5
11
|
const SLACK_SECTION_TEXT_MAX_LENGTH = 3000;
|
|
6
12
|
const SLACK_API_TIMEOUT_MS = 10_000;
|
|
13
|
+
// Permalink lookup happens on Slack's acknowledgement path, so keep it well
|
|
14
|
+
// inside Slack's three-second Events API deadline. Failure is non-fatal: the
|
|
15
|
+
// normalized message still carries channel/thread ids for replies.
|
|
16
|
+
const SLACK_PERMALINK_TIMEOUT_MS = 1_000;
|
|
17
|
+
const SLACK_CONTEXT_MESSAGE_LIMIT = 15;
|
|
18
|
+
const SLACK_CONTEXT_TEXT_LIMIT = 2_000;
|
|
7
19
|
/**
|
|
8
20
|
* Create a Slack platform adapter.
|
|
9
21
|
*
|
|
@@ -24,18 +36,44 @@ const SLACK_API_TIMEOUT_MS = 10_000;
|
|
|
24
36
|
* (`api_app_id`) to additionally pin events to. Useful when the same
|
|
25
37
|
* signing secret rotation surfaces multiple app installs.
|
|
26
38
|
*/
|
|
27
|
-
export function slackAdapter() {
|
|
39
|
+
export function slackAdapter(options = {}) {
|
|
40
|
+
const resolveBotToken = async (incoming) => (await options.resolveBotToken?.(incoming)) ??
|
|
41
|
+
(await resolveManagedSlackBotToken(incoming)) ??
|
|
42
|
+
(await resolveSecret("SLACK_BOT_TOKEN")) ??
|
|
43
|
+
undefined;
|
|
28
44
|
return {
|
|
29
45
|
platform: "slack",
|
|
30
46
|
label: "Slack",
|
|
47
|
+
capabilities: {
|
|
48
|
+
replyText: true,
|
|
49
|
+
proactiveMessages: true,
|
|
50
|
+
nativeThreads: true,
|
|
51
|
+
contextualReplies: true,
|
|
52
|
+
deferredWebhookResponse: false,
|
|
53
|
+
interactionOnly: false,
|
|
54
|
+
nativeContextHydration: true,
|
|
55
|
+
liveRunProgress: true,
|
|
56
|
+
},
|
|
31
57
|
getRequiredEnvKeys() {
|
|
32
58
|
return [
|
|
33
59
|
{
|
|
34
60
|
key: "SLACK_BOT_TOKEN",
|
|
35
61
|
label: "Slack Bot Token",
|
|
36
|
-
required:
|
|
62
|
+
required: false,
|
|
37
63
|
helpText: "In your Slack app's left nav: OAuth & Permissions → Bot User OAuth Token (starts with `xoxb-`).",
|
|
38
64
|
},
|
|
65
|
+
{
|
|
66
|
+
key: "SLACK_CLIENT_ID",
|
|
67
|
+
label: "Slack OAuth Client ID",
|
|
68
|
+
required: false,
|
|
69
|
+
helpText: "Slack app Basic Information → App Credentials → Client ID.",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
key: "SLACK_CLIENT_SECRET",
|
|
73
|
+
label: "Slack OAuth Client Secret",
|
|
74
|
+
required: false,
|
|
75
|
+
helpText: "Slack app Basic Information → App Credentials → Client Secret.",
|
|
76
|
+
},
|
|
39
77
|
{
|
|
40
78
|
key: "SLACK_SIGNING_SECRET",
|
|
41
79
|
label: "Slack Signing Secret",
|
|
@@ -107,7 +145,7 @@ export function slackAdapter() {
|
|
|
107
145
|
// handler, so this is purely a tenant-isolation gate (not a forgery
|
|
108
146
|
// defense). When unset in production we surface a one-time warning
|
|
109
147
|
// recommending it be configured.
|
|
110
|
-
enforceWorkspaceAllowlist(payload);
|
|
148
|
+
await enforceWorkspaceAllowlist(payload);
|
|
111
149
|
// Handle Events API wrapper
|
|
112
150
|
if (payload.type === "event_callback") {
|
|
113
151
|
const e = payload.event;
|
|
@@ -119,35 +157,91 @@ export function slackAdapter() {
|
|
|
119
157
|
// Ignore message edits and deletes
|
|
120
158
|
if (e.subtype === "message_changed" || e.subtype === "message_deleted")
|
|
121
159
|
return null;
|
|
122
|
-
// Handle
|
|
160
|
+
// Handle DMs and explicit mentions. Ordinary channel replies are only
|
|
161
|
+
// accepted while this exact workspace-qualified thread has queued or
|
|
162
|
+
// executing work; broad message subscriptions must never invoke the
|
|
163
|
+
// agent for general channel chatter.
|
|
123
164
|
const text = e.text?.trim();
|
|
124
165
|
if (!text)
|
|
125
166
|
return null;
|
|
167
|
+
const teamId = typeof payload.team_id === "string" ? payload.team_id : "unknown";
|
|
168
|
+
const apiAppId = typeof payload.api_app_id === "string"
|
|
169
|
+
? payload.api_app_id
|
|
170
|
+
: "unknown";
|
|
171
|
+
const agentContext = normalizeSlackAgentContext(e.app_context, teamId);
|
|
172
|
+
const isDm = typeof e.channel_type === "string"
|
|
173
|
+
? e.channel_type === "im"
|
|
174
|
+
: typeof e.channel === "string" && e.channel.startsWith("D");
|
|
175
|
+
const isMention = e.type === "app_mention";
|
|
176
|
+
const isThreadReply = !isDm && !isMention && !!e.thread_ts;
|
|
177
|
+
if (!isDm && !isMention && !isThreadReply)
|
|
178
|
+
return null;
|
|
126
179
|
// Remove bot mention from text (e.g., "<@U123> do something" → "do something")
|
|
127
180
|
const cleanText = text.replace(/<@[A-Z0-9]+>/g, "").trim();
|
|
128
181
|
if (!cleanText)
|
|
129
182
|
return null;
|
|
130
183
|
// Thread ID: use thread_ts if in a thread, otherwise message ts
|
|
131
184
|
const threadTs = e.thread_ts || e.ts;
|
|
132
|
-
const externalThreadId = `${e.channel}:${threadTs}`;
|
|
133
|
-
|
|
185
|
+
const externalThreadId = `${apiAppId}:${teamId}:${e.channel}:${threadTs}`;
|
|
186
|
+
const partialIncoming = {
|
|
134
187
|
platform: "slack",
|
|
135
188
|
externalThreadId,
|
|
136
189
|
text: cleanText,
|
|
137
190
|
senderName: e.user,
|
|
138
191
|
senderId: e.user,
|
|
192
|
+
triggerKind: isDm ? "dm" : isMention ? "mention" : "thread_reply",
|
|
193
|
+
conversationType: isDm ? "dm" : "unknown",
|
|
194
|
+
tenantId: teamId,
|
|
195
|
+
actorTrust: { memberType: "unknown", verified: true },
|
|
139
196
|
platformContext: {
|
|
140
197
|
channelId: e.channel,
|
|
141
|
-
|
|
198
|
+
channelType: e.channel_type,
|
|
199
|
+
threadTs,
|
|
142
200
|
messageTs: e.ts,
|
|
143
|
-
teamId
|
|
201
|
+
teamId,
|
|
202
|
+
apiAppId,
|
|
203
|
+
enterpriseId: typeof payload.enterprise_id === "string"
|
|
204
|
+
? payload.enterprise_id
|
|
205
|
+
: undefined,
|
|
144
206
|
eventId: payload.event_id,
|
|
207
|
+
...(agentContext
|
|
208
|
+
? {
|
|
209
|
+
agentContext: agentContext.entities,
|
|
210
|
+
activeContextChannelId: agentContext.channelId,
|
|
211
|
+
}
|
|
212
|
+
: {}),
|
|
145
213
|
},
|
|
214
|
+
threadRef: threadTs,
|
|
215
|
+
replyRef: e.ts,
|
|
146
216
|
timestamp: Math.floor(parseFloat(e.ts) * 1000),
|
|
147
217
|
};
|
|
218
|
+
if (isThreadReply) {
|
|
219
|
+
const active = options.isThreadActive
|
|
220
|
+
? await options.isThreadActive(partialIncoming)
|
|
221
|
+
: await hasActivePendingTask("slack", externalThreadId);
|
|
222
|
+
if (!active)
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
const token = await resolveBotToken(partialIncoming);
|
|
226
|
+
const threadPermalink = await resolveSlackThreadPermalink(e.channel, threadTs, token);
|
|
227
|
+
return {
|
|
228
|
+
...partialIncoming,
|
|
229
|
+
platformContext: {
|
|
230
|
+
...partialIncoming.platformContext,
|
|
231
|
+
...(threadPermalink ? { threadPermalink } : {}),
|
|
232
|
+
},
|
|
233
|
+
...(threadPermalink ? { sourceUrl: threadPermalink } : {}),
|
|
234
|
+
};
|
|
148
235
|
}
|
|
149
236
|
return null;
|
|
150
237
|
},
|
|
238
|
+
getLegacyExternalThreadIds(incoming) {
|
|
239
|
+
const channelId = incoming.platformContext.channelId;
|
|
240
|
+
const threadTs = incoming.platformContext.threadTs;
|
|
241
|
+
return typeof channelId === "string" && typeof threadTs === "string"
|
|
242
|
+
? [`${channelId}:${threadTs}`]
|
|
243
|
+
: [];
|
|
244
|
+
},
|
|
151
245
|
async postProcessingPlaceholder(incoming) {
|
|
152
246
|
// No placeholder reply in the thread — Slack's native assistant
|
|
153
247
|
// status bar ("agent-native is thinking…", below the composer) is the
|
|
@@ -155,21 +249,34 @@ export function slackAdapter() {
|
|
|
155
249
|
// redundant and added an extra chunk that we then had to overwrite.
|
|
156
250
|
// We just set the native status and return null so sendResponse posts
|
|
157
251
|
// the final reply as a fresh message.
|
|
158
|
-
const token = await
|
|
252
|
+
const token = await resolveBotToken(incoming);
|
|
159
253
|
if (!token)
|
|
160
254
|
return null;
|
|
161
255
|
const channelId = incoming.platformContext.channelId;
|
|
162
256
|
const threadTs = incoming.platformContext.threadTs;
|
|
163
257
|
if (!channelId || !threadTs)
|
|
164
258
|
return null;
|
|
165
|
-
// Best-effort: flip the native
|
|
166
|
-
//
|
|
167
|
-
//
|
|
259
|
+
// Best-effort: flip the native Agent "is thinking…" status bar in the
|
|
260
|
+
// channel input area. Slack accepts chat:write for this method. The
|
|
261
|
+
// canonical manifest separately requests assistant:write for Agent View
|
|
262
|
+
// and app_context_changed events.
|
|
168
263
|
setSlackAssistantStatus(token, channelId, threadTs, "is thinking…");
|
|
169
264
|
return null;
|
|
170
265
|
},
|
|
266
|
+
async hydrateIncomingMessage(incoming) {
|
|
267
|
+
const token = await resolveBotToken(incoming);
|
|
268
|
+
if (!token)
|
|
269
|
+
return incoming;
|
|
270
|
+
return hydrateSlackContext(token, incoming);
|
|
271
|
+
},
|
|
272
|
+
async startRunProgress(incoming) {
|
|
273
|
+
const token = await resolveBotToken(incoming);
|
|
274
|
+
if (!token)
|
|
275
|
+
return null;
|
|
276
|
+
return startSlackRunProgress(token, incoming);
|
|
277
|
+
},
|
|
171
278
|
async sendResponse(message, context, opts) {
|
|
172
|
-
const token = await
|
|
279
|
+
const token = await resolveBotToken(context);
|
|
173
280
|
if (!token) {
|
|
174
281
|
console.error("[slack] SLACK_BOT_TOKEN not configured");
|
|
175
282
|
return;
|
|
@@ -247,7 +354,19 @@ export function slackAdapter() {
|
|
|
247
354
|
}
|
|
248
355
|
},
|
|
249
356
|
async sendMessageToTarget(message, target) {
|
|
250
|
-
const
|
|
357
|
+
const targetContext = {
|
|
358
|
+
platform: "slack",
|
|
359
|
+
externalThreadId: `${target.tenantId ?? "unknown"}:${target.destination}:${target.threadRef ?? "root"}`,
|
|
360
|
+
text: "",
|
|
361
|
+
platformContext: {
|
|
362
|
+
channelId: target.destination,
|
|
363
|
+
threadTs: target.threadRef,
|
|
364
|
+
teamId: target.tenantId,
|
|
365
|
+
},
|
|
366
|
+
tenantId: target.tenantId,
|
|
367
|
+
timestamp: Date.now(),
|
|
368
|
+
};
|
|
369
|
+
const token = await resolveBotToken(targetContext);
|
|
251
370
|
if (!token) {
|
|
252
371
|
console.error("[slack] SLACK_BOT_TOKEN not configured");
|
|
253
372
|
return;
|
|
@@ -293,7 +412,15 @@ export function slackAdapter() {
|
|
|
293
412
|
async getStatus(_baseUrl) {
|
|
294
413
|
const hasToken = !!(await resolveSecret("SLACK_BOT_TOKEN"));
|
|
295
414
|
const hasSecret = !!(await resolveSecret("SLACK_SIGNING_SECRET"));
|
|
296
|
-
const
|
|
415
|
+
const ctx = getRequestContext();
|
|
416
|
+
const managedInstallations = ctx?.userEmail
|
|
417
|
+
? await listIntegrationInstallations({
|
|
418
|
+
userEmail: ctx.userEmail,
|
|
419
|
+
orgId: ctx.orgId ?? null,
|
|
420
|
+
}, "slack").catch(() => [])
|
|
421
|
+
: [];
|
|
422
|
+
const connectedInstallations = managedInstallations.filter((installation) => installation.status === "connected");
|
|
423
|
+
const configured = hasSecret && (hasToken || connectedInstallations.length > 0);
|
|
297
424
|
return {
|
|
298
425
|
platform: "slack",
|
|
299
426
|
label: "Slack",
|
|
@@ -302,9 +429,18 @@ export function slackAdapter() {
|
|
|
302
429
|
details: {
|
|
303
430
|
hasToken,
|
|
304
431
|
hasSecret,
|
|
432
|
+
managedInstallationCount: connectedInstallations.length,
|
|
433
|
+
managedInstallations: connectedInstallations.map((installation) => ({
|
|
434
|
+
id: installation.id,
|
|
435
|
+
teamId: installation.teamId,
|
|
436
|
+
teamName: installation.teamName,
|
|
437
|
+
enterpriseId: installation.enterpriseId,
|
|
438
|
+
health: installation.health,
|
|
439
|
+
scopes: installation.scopes,
|
|
440
|
+
})),
|
|
305
441
|
},
|
|
306
442
|
error: !configured
|
|
307
|
-
? "
|
|
443
|
+
? "Connect a Slack workspace with OAuth or save a bot token and signing secret"
|
|
308
444
|
: undefined,
|
|
309
445
|
};
|
|
310
446
|
},
|
|
@@ -327,6 +463,36 @@ function parseAllowlistEnv(name) {
|
|
|
327
463
|
return null;
|
|
328
464
|
return new Set(values);
|
|
329
465
|
}
|
|
466
|
+
async function resolveManagedSlackBotToken(incoming) {
|
|
467
|
+
const teamId = typeof incoming.platformContext.teamId === "string"
|
|
468
|
+
? incoming.platformContext.teamId
|
|
469
|
+
: incoming.tenantId;
|
|
470
|
+
const apiAppId = typeof incoming.platformContext.apiAppId === "string"
|
|
471
|
+
? incoming.platformContext.apiAppId
|
|
472
|
+
: undefined;
|
|
473
|
+
const enterpriseId = typeof incoming.platformContext.enterpriseId === "string"
|
|
474
|
+
? incoming.platformContext.enterpriseId
|
|
475
|
+
: undefined;
|
|
476
|
+
if (!teamId && !enterpriseId)
|
|
477
|
+
return undefined;
|
|
478
|
+
try {
|
|
479
|
+
let installation = apiAppId
|
|
480
|
+
? await getActiveIntegrationInstallationByKey("slack", slackInstallationKey({ teamId, enterpriseId, apiAppId }))
|
|
481
|
+
: null;
|
|
482
|
+
if (!installation && teamId) {
|
|
483
|
+
installation = await getActiveIntegrationInstallationForTenant("slack", teamId);
|
|
484
|
+
}
|
|
485
|
+
if (!installation && enterpriseId) {
|
|
486
|
+
installation = await getActiveIntegrationInstallationForTenant("slack", enterpriseId);
|
|
487
|
+
}
|
|
488
|
+
const key = installation?.installationKey ??
|
|
489
|
+
slackInstallationKey({ teamId, enterpriseId, apiAppId });
|
|
490
|
+
return (await resolveIntegrationTokenBundle("slack", key))?.accessToken;
|
|
491
|
+
}
|
|
492
|
+
catch {
|
|
493
|
+
return undefined;
|
|
494
|
+
}
|
|
495
|
+
}
|
|
330
496
|
let _missingAllowlistWarned = false;
|
|
331
497
|
/**
|
|
332
498
|
* Enforce that an incoming Slack event comes from an allowlisted workspace.
|
|
@@ -354,17 +520,25 @@ let _missingAllowlistWarned = false;
|
|
|
354
520
|
* received, which the integrations plugin surfaces to the caller as
|
|
355
521
|
* "Unrecognized Slack workspace" without enqueuing the event.
|
|
356
522
|
*/
|
|
357
|
-
function enforceWorkspaceAllowlist(payload) {
|
|
523
|
+
async function enforceWorkspaceAllowlist(payload) {
|
|
358
524
|
const teamId = typeof payload?.team_id === "string" ? payload.team_id : undefined;
|
|
359
525
|
const apiAppId = typeof payload?.api_app_id === "string" ? payload.api_app_id : undefined;
|
|
360
526
|
const allowedTeamIds = parseAllowlistEnv("SLACK_ALLOWED_TEAM_IDS");
|
|
361
527
|
const allowedAppIds = parseAllowlistEnv("SLACK_ALLOWED_API_APP_IDS");
|
|
362
528
|
if (!allowedTeamIds) {
|
|
363
529
|
if (process.env.NODE_ENV === "production") {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
530
|
+
let managed = false;
|
|
531
|
+
try {
|
|
532
|
+
const key = slackInstallationKey({ teamId, apiAppId });
|
|
533
|
+
managed = !!(await getActiveIntegrationInstallationByKey("slack", key));
|
|
534
|
+
}
|
|
535
|
+
catch { }
|
|
536
|
+
if (!managed) {
|
|
537
|
+
throw createError({
|
|
538
|
+
statusCode: 401,
|
|
539
|
+
statusMessage: "Slack workspace is not connected",
|
|
540
|
+
});
|
|
541
|
+
}
|
|
368
542
|
}
|
|
369
543
|
if (!_missingAllowlistWarned) {
|
|
370
544
|
_missingAllowlistWarned = true;
|
|
@@ -489,10 +663,10 @@ function markdownToSlackMrkdwn(text) {
|
|
|
489
663
|
.replace(/\*\*([^*]{1,5000})\*\*/g, "*$1*"));
|
|
490
664
|
}
|
|
491
665
|
/**
|
|
492
|
-
* Optionally set Slack's native
|
|
493
|
-
*
|
|
494
|
-
*
|
|
495
|
-
*
|
|
666
|
+
* Optionally set Slack's native Agent status indicator (the small "is
|
|
667
|
+
* thinking…" line under the message composer). The method uses chat:write;
|
|
668
|
+
* Agent View itself is configured separately by the Slack app manifest.
|
|
669
|
+
* Pure best-effort — failures never block the response.
|
|
496
670
|
*/
|
|
497
671
|
function setSlackAssistantStatus(token, channelId, threadTs, status) {
|
|
498
672
|
slackApiFetch("https://slack.com/api/assistant.threads.setStatus", {
|
|
@@ -566,10 +740,10 @@ async function postFresh(token, channelId, threadTs, body) {
|
|
|
566
740
|
throw new Error(data.error || "chat.postMessage failed");
|
|
567
741
|
}
|
|
568
742
|
}
|
|
569
|
-
async function slackApiFetch(url, init) {
|
|
743
|
+
async function slackApiFetch(url, init, timeoutMs = SLACK_API_TIMEOUT_MS) {
|
|
570
744
|
const controller = typeof AbortController !== "undefined" ? new AbortController() : undefined;
|
|
571
745
|
const timer = controller
|
|
572
|
-
? setTimeout(() => controller.abort(),
|
|
746
|
+
? setTimeout(() => controller.abort(), timeoutMs)
|
|
573
747
|
: undefined;
|
|
574
748
|
try {
|
|
575
749
|
return await fetch(url, {
|
|
@@ -582,4 +756,539 @@ async function slackApiFetch(url, init) {
|
|
|
582
756
|
clearTimeout(timer);
|
|
583
757
|
}
|
|
584
758
|
}
|
|
759
|
+
async function resolveSlackThreadPermalink(channelId, threadTs, resolvedToken) {
|
|
760
|
+
if (typeof channelId !== "string" || typeof threadTs !== "string") {
|
|
761
|
+
return undefined;
|
|
762
|
+
}
|
|
763
|
+
const token = resolvedToken ?? (await resolveSecret("SLACK_BOT_TOKEN"));
|
|
764
|
+
if (!token)
|
|
765
|
+
return undefined;
|
|
766
|
+
try {
|
|
767
|
+
const url = new URL("https://slack.com/api/chat.getPermalink");
|
|
768
|
+
url.searchParams.set("channel", channelId);
|
|
769
|
+
url.searchParams.set("message_ts", threadTs);
|
|
770
|
+
const res = await slackApiFetch(url.toString(), { headers: { Authorization: `Bearer ${token}` } }, SLACK_PERMALINK_TIMEOUT_MS);
|
|
771
|
+
const data = (await res.json());
|
|
772
|
+
if (!data.ok || typeof data.permalink !== "string")
|
|
773
|
+
return undefined;
|
|
774
|
+
const permalink = new URL(data.permalink);
|
|
775
|
+
const isSlackHost = permalink.hostname === "slack.com" ||
|
|
776
|
+
permalink.hostname.endsWith(".slack.com");
|
|
777
|
+
if (permalink.protocol !== "https:" || !isSlackHost)
|
|
778
|
+
return undefined;
|
|
779
|
+
return permalink.toString();
|
|
780
|
+
}
|
|
781
|
+
catch {
|
|
782
|
+
return undefined;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
function boundedSlackText(value) {
|
|
786
|
+
return typeof value === "string"
|
|
787
|
+
? value.slice(0, SLACK_CONTEXT_TEXT_LIMIT)
|
|
788
|
+
: "";
|
|
789
|
+
}
|
|
790
|
+
function normalizeSlackAgentContext(value, eventTeamId) {
|
|
791
|
+
if (!value || typeof value !== "object")
|
|
792
|
+
return null;
|
|
793
|
+
const rawEntities = value.entities;
|
|
794
|
+
if (!Array.isArray(rawEntities))
|
|
795
|
+
return null;
|
|
796
|
+
const entities = rawEntities.slice(0, 10).flatMap((entity) => {
|
|
797
|
+
if (!entity || typeof entity !== "object")
|
|
798
|
+
return [];
|
|
799
|
+
const record = entity;
|
|
800
|
+
if (typeof record.type !== "string" || typeof record.value !== "string") {
|
|
801
|
+
return [];
|
|
802
|
+
}
|
|
803
|
+
const teamId = typeof record.team_id === "string" ? record.team_id : undefined;
|
|
804
|
+
if (teamId && eventTeamId !== "unknown" && teamId !== eventTeamId) {
|
|
805
|
+
return [];
|
|
806
|
+
}
|
|
807
|
+
return [
|
|
808
|
+
{
|
|
809
|
+
type: record.type.slice(0, 100),
|
|
810
|
+
value: record.value.slice(0, 200),
|
|
811
|
+
...(teamId ? { teamId } : {}),
|
|
812
|
+
},
|
|
813
|
+
];
|
|
814
|
+
});
|
|
815
|
+
if (!entities.length)
|
|
816
|
+
return null;
|
|
817
|
+
const channelId = entities.find((entity) => entity.type === "slack#/types/channel_id" &&
|
|
818
|
+
/^[CDG][A-Z0-9]+$/.test(entity.value))?.value;
|
|
819
|
+
return { entities, ...(channelId ? { channelId } : {}) };
|
|
820
|
+
}
|
|
821
|
+
function slackFileReference(value) {
|
|
822
|
+
if (!value || typeof value !== "object")
|
|
823
|
+
return null;
|
|
824
|
+
const file = value;
|
|
825
|
+
if (typeof file.id !== "string")
|
|
826
|
+
return null;
|
|
827
|
+
return {
|
|
828
|
+
id: file.id,
|
|
829
|
+
...(typeof file.name === "string" ? { name: file.name } : {}),
|
|
830
|
+
...(typeof file.mimetype === "string" ? { mimetype: file.mimetype } : {}),
|
|
831
|
+
...(typeof file.size === "number" ? { size: file.size } : {}),
|
|
832
|
+
...(typeof file.permalink === "string"
|
|
833
|
+
? { permalink: file.permalink }
|
|
834
|
+
: {}),
|
|
835
|
+
...(typeof file.url_private_download === "string"
|
|
836
|
+
? { downloadUrl: file.url_private_download }
|
|
837
|
+
: {}),
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
async function slackJson(token, method, params, timeoutMs = 2_000) {
|
|
841
|
+
try {
|
|
842
|
+
const url = new URL(`https://slack.com/api/${method}`);
|
|
843
|
+
for (const [key, value] of Object.entries(params)) {
|
|
844
|
+
url.searchParams.set(key, value);
|
|
845
|
+
}
|
|
846
|
+
const response = await slackApiFetch(url.toString(), { headers: { Authorization: `Bearer ${token}` } }, timeoutMs);
|
|
847
|
+
const body = (await response.json());
|
|
848
|
+
return body.ok ? body : null;
|
|
849
|
+
}
|
|
850
|
+
catch {
|
|
851
|
+
return null;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
async function hydrateSlackContext(token, incoming) {
|
|
855
|
+
const channelId = incoming.platformContext.channelId;
|
|
856
|
+
const threadTs = incoming.platformContext.threadTs;
|
|
857
|
+
const senderId = incoming.senderId;
|
|
858
|
+
if (typeof channelId !== "string" || typeof threadTs !== "string") {
|
|
859
|
+
return incoming;
|
|
860
|
+
}
|
|
861
|
+
const [thread, history, pins, conversation, user] = await Promise.all([
|
|
862
|
+
slackJson(token, "conversations.replies", {
|
|
863
|
+
channel: channelId,
|
|
864
|
+
ts: threadTs,
|
|
865
|
+
limit: String(SLACK_CONTEXT_MESSAGE_LIMIT),
|
|
866
|
+
}),
|
|
867
|
+
slackJson(token, "conversations.history", {
|
|
868
|
+
channel: channelId,
|
|
869
|
+
latest: String(incoming.platformContext.messageTs ?? threadTs),
|
|
870
|
+
inclusive: "true",
|
|
871
|
+
limit: String(SLACK_CONTEXT_MESSAGE_LIMIT),
|
|
872
|
+
}),
|
|
873
|
+
slackJson(token, "pins.list", { channel: channelId }),
|
|
874
|
+
slackJson(token, "conversations.info", { channel: channelId }),
|
|
875
|
+
senderId ? slackJson(token, "users.info", { user: senderId }) : null,
|
|
876
|
+
]);
|
|
877
|
+
// Agent View can attach the Slack surface the user is currently viewing to
|
|
878
|
+
// a DM. Treat it only as a context hint: Slack requires us to prove the bot
|
|
879
|
+
// can access the referenced channel with conversations.info before reading
|
|
880
|
+
// any history from it.
|
|
881
|
+
const activeContextChannelId = typeof incoming.platformContext.activeContextChannelId === "string"
|
|
882
|
+
? incoming.platformContext.activeContextChannelId
|
|
883
|
+
: null;
|
|
884
|
+
const activeContextConversation = activeContextChannelId && activeContextChannelId !== channelId
|
|
885
|
+
? await slackJson(token, "conversations.info", {
|
|
886
|
+
channel: activeContextChannelId,
|
|
887
|
+
})
|
|
888
|
+
: null;
|
|
889
|
+
const activeContextHistory = activeContextConversation
|
|
890
|
+
? await slackJson(token, "conversations.history", {
|
|
891
|
+
channel: activeContextChannelId,
|
|
892
|
+
limit: "5",
|
|
893
|
+
})
|
|
894
|
+
: null;
|
|
895
|
+
const activeContextName = typeof activeContextConversation?.channel?.name === "string"
|
|
896
|
+
? activeContextConversation.channel.name
|
|
897
|
+
: null;
|
|
898
|
+
const activeContextMessages = Array.isArray(activeContextHistory?.messages)
|
|
899
|
+
? activeContextHistory.messages.map((message) => ({
|
|
900
|
+
...message,
|
|
901
|
+
text: `[Active Slack context${activeContextName ? ` #${activeContextName}` : ""}] ${boundedSlackText(message.text)}`,
|
|
902
|
+
}))
|
|
903
|
+
: [];
|
|
904
|
+
const rawMessages = [
|
|
905
|
+
...(Array.isArray(history?.messages) ? history.messages : []),
|
|
906
|
+
...(Array.isArray(pins?.items)
|
|
907
|
+
? pins.items
|
|
908
|
+
.map((item) => item.message)
|
|
909
|
+
.filter(Boolean)
|
|
910
|
+
: []),
|
|
911
|
+
...(Array.isArray(thread?.messages) ? thread.messages : []),
|
|
912
|
+
...activeContextMessages,
|
|
913
|
+
];
|
|
914
|
+
const uniqueMessages = [
|
|
915
|
+
...new Map(rawMessages.map((message, index) => [
|
|
916
|
+
typeof message.ts === "string" ? message.ts : `unknown:${index}`,
|
|
917
|
+
message,
|
|
918
|
+
])).values(),
|
|
919
|
+
].slice(-SLACK_CONTEXT_MESSAGE_LIMIT);
|
|
920
|
+
const messages = uniqueMessages.length
|
|
921
|
+
? uniqueMessages.map((message) => {
|
|
922
|
+
const files = Array.isArray(message.files)
|
|
923
|
+
? message.files
|
|
924
|
+
.map(slackFileReference)
|
|
925
|
+
.filter((file) => file !== null)
|
|
926
|
+
: undefined;
|
|
927
|
+
const reactions = Array.isArray(message.reactions)
|
|
928
|
+
? message.reactions
|
|
929
|
+
.filter((reaction) => typeof reaction?.name === "string" &&
|
|
930
|
+
typeof reaction?.count === "number")
|
|
931
|
+
.map((reaction) => ({
|
|
932
|
+
name: reaction.name,
|
|
933
|
+
count: reaction.count,
|
|
934
|
+
}))
|
|
935
|
+
: undefined;
|
|
936
|
+
return {
|
|
937
|
+
...(typeof message.user === "string"
|
|
938
|
+
? { senderId: message.user }
|
|
939
|
+
: {}),
|
|
940
|
+
text: boundedSlackText(message.text),
|
|
941
|
+
timestamp: typeof message.ts === "string"
|
|
942
|
+
? Math.floor(parseFloat(message.ts) * 1000)
|
|
943
|
+
: incoming.timestamp,
|
|
944
|
+
...(reactions?.length ? { reactions } : {}),
|
|
945
|
+
...(files?.length ? { files } : {}),
|
|
946
|
+
};
|
|
947
|
+
})
|
|
948
|
+
: [];
|
|
949
|
+
const profile = user?.user?.profile;
|
|
950
|
+
const isGuest = user?.user?.is_restricted === true;
|
|
951
|
+
const isExternal = user?.user?.is_ultra_restricted === true;
|
|
952
|
+
const isPrivate = conversation?.channel?.is_private === true;
|
|
953
|
+
const isExternalShared = conversation?.channel?.is_ext_shared === true;
|
|
954
|
+
const isMpim = conversation?.channel?.is_mpim === true;
|
|
955
|
+
const isIm = conversation?.channel?.is_im === true;
|
|
956
|
+
const conversationType = isIm
|
|
957
|
+
? "dm"
|
|
958
|
+
: isMpim
|
|
959
|
+
? "group_dm"
|
|
960
|
+
: isPrivate
|
|
961
|
+
? "private_channel"
|
|
962
|
+
: "channel";
|
|
963
|
+
const attachedFiles = messages.flatMap((message) => message.files ?? []);
|
|
964
|
+
const detailedFiles = await Promise.all([...new Set(attachedFiles.map((file) => file.id))]
|
|
965
|
+
.slice(0, 5)
|
|
966
|
+
.map(async (fileId) => {
|
|
967
|
+
const result = await slackJson(token, "files.info", { file: fileId });
|
|
968
|
+
return slackFileReference(result?.file);
|
|
969
|
+
}));
|
|
970
|
+
const fileById = new Map(detailedFiles
|
|
971
|
+
.filter((file) => file !== null)
|
|
972
|
+
.map((file) => [file.id, file]));
|
|
973
|
+
const hydratedMessages = messages.map((message) => ({
|
|
974
|
+
...message,
|
|
975
|
+
...(message.files?.length
|
|
976
|
+
? {
|
|
977
|
+
files: message.files.map((file) => ({
|
|
978
|
+
...file,
|
|
979
|
+
...(fileById.get(file.id) ?? {}),
|
|
980
|
+
})),
|
|
981
|
+
}
|
|
982
|
+
: {}),
|
|
983
|
+
}));
|
|
984
|
+
const hydratedFiles = hydratedMessages.flatMap((message) => message.files ?? []);
|
|
985
|
+
return {
|
|
986
|
+
...incoming,
|
|
987
|
+
...(typeof profile?.display_name === "string" && profile.display_name
|
|
988
|
+
? { senderName: profile.display_name }
|
|
989
|
+
: typeof profile?.real_name === "string" && profile.real_name
|
|
990
|
+
? { senderName: profile.real_name }
|
|
991
|
+
: {}),
|
|
992
|
+
...(typeof profile?.email === "string"
|
|
993
|
+
? { senderEmail: profile.email, senderVerified: true }
|
|
994
|
+
: {}),
|
|
995
|
+
conversationType,
|
|
996
|
+
actorTrust: {
|
|
997
|
+
memberType: isExternal ? "external" : isGuest ? "guest" : "member",
|
|
998
|
+
verified: true,
|
|
999
|
+
},
|
|
1000
|
+
contextMessages: hydratedMessages,
|
|
1001
|
+
...(hydratedFiles.length ? { files: hydratedFiles.slice(0, 20) } : {}),
|
|
1002
|
+
platformContext: {
|
|
1003
|
+
...incoming.platformContext,
|
|
1004
|
+
channelName: typeof conversation?.channel?.name === "string"
|
|
1005
|
+
? conversation.channel.name
|
|
1006
|
+
: undefined,
|
|
1007
|
+
isExternalShared,
|
|
1008
|
+
...(activeContextChannelId
|
|
1009
|
+
? {
|
|
1010
|
+
activeContextChannelId,
|
|
1011
|
+
...(activeContextName
|
|
1012
|
+
? { activeContextChannelName: activeContextName }
|
|
1013
|
+
: {}),
|
|
1014
|
+
}
|
|
1015
|
+
: {}),
|
|
1016
|
+
},
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
function shortTaskTitle(value) {
|
|
1020
|
+
const text = typeof value === "string" ? value : "Working";
|
|
1021
|
+
return text.replace(/[-_]/g, " ").slice(0, 200);
|
|
1022
|
+
}
|
|
1023
|
+
async function postSlackJson(token, method, body) {
|
|
1024
|
+
const response = await slackApiFetch(`https://slack.com/api/${method}`, {
|
|
1025
|
+
method: "POST",
|
|
1026
|
+
headers: {
|
|
1027
|
+
Authorization: `Bearer ${token}`,
|
|
1028
|
+
"Content-Type": "application/json",
|
|
1029
|
+
},
|
|
1030
|
+
body: JSON.stringify(body),
|
|
1031
|
+
});
|
|
1032
|
+
const data = (await response.json());
|
|
1033
|
+
if (!data.ok)
|
|
1034
|
+
throw new Error(data.error || `${method} failed`);
|
|
1035
|
+
return data;
|
|
1036
|
+
}
|
|
1037
|
+
async function startSlackRunProgress(token, incoming) {
|
|
1038
|
+
const channel = incoming.platformContext.channelId;
|
|
1039
|
+
const threadTs = incoming.platformContext.threadTs;
|
|
1040
|
+
if (typeof channel !== "string" || typeof threadTs !== "string")
|
|
1041
|
+
return null;
|
|
1042
|
+
let started;
|
|
1043
|
+
try {
|
|
1044
|
+
started = await postSlackJson(token, "chat.startStream", {
|
|
1045
|
+
channel,
|
|
1046
|
+
thread_ts: threadTs,
|
|
1047
|
+
...(incoming.tenantId ? { recipient_team_id: incoming.tenantId } : {}),
|
|
1048
|
+
...(incoming.senderId ? { recipient_user_id: incoming.senderId } : {}),
|
|
1049
|
+
task_display_mode: "plan",
|
|
1050
|
+
markdown_text: "Working on your request…",
|
|
1051
|
+
chunks: [
|
|
1052
|
+
{
|
|
1053
|
+
type: "plan_update",
|
|
1054
|
+
title: "Working on your request",
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
type: "task_update",
|
|
1058
|
+
id: "agent-native:context",
|
|
1059
|
+
title: "Understand the request",
|
|
1060
|
+
status: "in_progress",
|
|
1061
|
+
details: "Loading relevant context",
|
|
1062
|
+
},
|
|
1063
|
+
],
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
catch {
|
|
1067
|
+
return null;
|
|
1068
|
+
}
|
|
1069
|
+
const streamTs = started.ts;
|
|
1070
|
+
if (typeof streamTs !== "string")
|
|
1071
|
+
return null;
|
|
1072
|
+
const tasks = new Map();
|
|
1073
|
+
const toolTaskIds = new Map();
|
|
1074
|
+
tasks.set("agent-native:context", {
|
|
1075
|
+
title: "Understand the request",
|
|
1076
|
+
status: "in_progress",
|
|
1077
|
+
});
|
|
1078
|
+
let sequence = 0;
|
|
1079
|
+
let lastWriteAt = 0;
|
|
1080
|
+
let pending = null;
|
|
1081
|
+
let pendingTimer = null;
|
|
1082
|
+
let approvalControls = null;
|
|
1083
|
+
let cancelControl = null;
|
|
1084
|
+
const append = async (chunk) => {
|
|
1085
|
+
const now = Date.now();
|
|
1086
|
+
const write = async (value) => {
|
|
1087
|
+
lastWriteAt = Date.now();
|
|
1088
|
+
await postSlackJson(token, "chat.appendStream", {
|
|
1089
|
+
channel,
|
|
1090
|
+
ts: streamTs,
|
|
1091
|
+
markdown_text: "Progress updated.",
|
|
1092
|
+
chunks: [value],
|
|
1093
|
+
}).catch(() => { });
|
|
1094
|
+
};
|
|
1095
|
+
if (now - lastWriteAt >= 900) {
|
|
1096
|
+
await write(chunk);
|
|
1097
|
+
return;
|
|
1098
|
+
}
|
|
1099
|
+
pending = chunk;
|
|
1100
|
+
if (!pendingTimer) {
|
|
1101
|
+
pendingTimer = setTimeout(() => {
|
|
1102
|
+
const value = pending;
|
|
1103
|
+
pending = null;
|
|
1104
|
+
pendingTimer = null;
|
|
1105
|
+
if (value)
|
|
1106
|
+
void write(value);
|
|
1107
|
+
}, 900 - (now - lastWriteAt));
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
const taskId = (prefix, explicit) => `${prefix}:${explicit || ++sequence}`.slice(0, 240);
|
|
1111
|
+
return {
|
|
1112
|
+
async onEvent(event) {
|
|
1113
|
+
if (!cancelControl) {
|
|
1114
|
+
const context = getIntegrationRequestContext();
|
|
1115
|
+
const ownerEmail = getRequestContext()?.userEmail;
|
|
1116
|
+
if (context?.lineage?.runId &&
|
|
1117
|
+
ownerEmail &&
|
|
1118
|
+
incoming.senderId &&
|
|
1119
|
+
incoming.tenantId) {
|
|
1120
|
+
cancelControl = await createIntegrationControl({
|
|
1121
|
+
action: "cancel",
|
|
1122
|
+
ownerEmail,
|
|
1123
|
+
orgId: getRequestContext()?.orgId ?? null,
|
|
1124
|
+
requesterId: incoming.senderId,
|
|
1125
|
+
teamId: incoming.tenantId,
|
|
1126
|
+
apiAppId: typeof incoming.platformContext.apiAppId === "string"
|
|
1127
|
+
? incoming.platformContext.apiAppId
|
|
1128
|
+
: null,
|
|
1129
|
+
channelId: channel,
|
|
1130
|
+
messageTs: streamTs,
|
|
1131
|
+
runId: context.lineage.runId,
|
|
1132
|
+
incoming,
|
|
1133
|
+
});
|
|
1134
|
+
await append({
|
|
1135
|
+
type: "blocks",
|
|
1136
|
+
blocks: [
|
|
1137
|
+
{
|
|
1138
|
+
type: "actions",
|
|
1139
|
+
block_id: `agent-native-running-${Date.now()}`,
|
|
1140
|
+
elements: [
|
|
1141
|
+
{
|
|
1142
|
+
type: "button",
|
|
1143
|
+
text: { type: "plain_text", text: "Cancel" },
|
|
1144
|
+
style: "danger",
|
|
1145
|
+
action_id: "agent_native_cancel",
|
|
1146
|
+
value: cancelControl,
|
|
1147
|
+
},
|
|
1148
|
+
],
|
|
1149
|
+
},
|
|
1150
|
+
],
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
if (event.type === "approval_required") {
|
|
1155
|
+
const context = getIntegrationRequestContext();
|
|
1156
|
+
const ownerEmail = getRequestContext()?.userEmail;
|
|
1157
|
+
if (context && ownerEmail && incoming.senderId && incoming.tenantId) {
|
|
1158
|
+
const common = {
|
|
1159
|
+
ownerEmail,
|
|
1160
|
+
orgId: getRequestContext()?.orgId ?? null,
|
|
1161
|
+
requesterId: incoming.senderId,
|
|
1162
|
+
teamId: incoming.tenantId,
|
|
1163
|
+
apiAppId: typeof incoming.platformContext.apiAppId === "string"
|
|
1164
|
+
? incoming.platformContext.apiAppId
|
|
1165
|
+
: null,
|
|
1166
|
+
channelId: channel,
|
|
1167
|
+
messageTs: streamTs,
|
|
1168
|
+
runId: context.lineage?.runId ?? null,
|
|
1169
|
+
approvalKey: event.approvalKey,
|
|
1170
|
+
incoming,
|
|
1171
|
+
};
|
|
1172
|
+
const [approve, deny] = await Promise.all([
|
|
1173
|
+
createIntegrationControl({ ...common, action: "approve" }),
|
|
1174
|
+
createIntegrationControl({ ...common, action: "deny" }),
|
|
1175
|
+
]);
|
|
1176
|
+
approvalControls = { approve, deny };
|
|
1177
|
+
}
|
|
1178
|
+
await append({
|
|
1179
|
+
type: "task_update",
|
|
1180
|
+
id: "agent-native:approval",
|
|
1181
|
+
title: `Approve ${shortTaskTitle(event.tool)}`,
|
|
1182
|
+
status: "pending",
|
|
1183
|
+
details: "Waiting for the requester",
|
|
1184
|
+
});
|
|
1185
|
+
}
|
|
1186
|
+
else if (event.type === "tool_start") {
|
|
1187
|
+
const key = event.id || event.tool;
|
|
1188
|
+
const id = taskId("tool", event.id);
|
|
1189
|
+
toolTaskIds.set(key, id);
|
|
1190
|
+
const title = shortTaskTitle(event.tool);
|
|
1191
|
+
tasks.set(id, { title, status: "in_progress" });
|
|
1192
|
+
await append({
|
|
1193
|
+
type: "task_update",
|
|
1194
|
+
id,
|
|
1195
|
+
title,
|
|
1196
|
+
status: "in_progress",
|
|
1197
|
+
});
|
|
1198
|
+
}
|
|
1199
|
+
else if (event.type === "tool_done") {
|
|
1200
|
+
const key = event.id || event.tool;
|
|
1201
|
+
const id = toolTaskIds.get(key) ?? taskId("tool", event.id);
|
|
1202
|
+
const title = tasks.get(id)?.title ?? shortTaskTitle(event.tool);
|
|
1203
|
+
tasks.set(id, {
|
|
1204
|
+
title,
|
|
1205
|
+
status: event.isError ? "error" : "complete",
|
|
1206
|
+
});
|
|
1207
|
+
await append({
|
|
1208
|
+
type: "task_update",
|
|
1209
|
+
id,
|
|
1210
|
+
title,
|
|
1211
|
+
status: event.isError ? "error" : "complete",
|
|
1212
|
+
});
|
|
1213
|
+
}
|
|
1214
|
+
else if (event.type === "agent_call") {
|
|
1215
|
+
const id = taskId("agent", event.agent);
|
|
1216
|
+
const status = event.status === "start"
|
|
1217
|
+
? "in_progress"
|
|
1218
|
+
: event.status === "done"
|
|
1219
|
+
? "complete"
|
|
1220
|
+
: "error";
|
|
1221
|
+
const title = `Ask ${shortTaskTitle(event.agent)}`;
|
|
1222
|
+
tasks.set(id, { title, status });
|
|
1223
|
+
await append({ type: "task_update", id, title, status });
|
|
1224
|
+
}
|
|
1225
|
+
else if (event.type === "activity") {
|
|
1226
|
+
await append({
|
|
1227
|
+
type: "task_update",
|
|
1228
|
+
id: "agent-native:context",
|
|
1229
|
+
title: "Understand the request",
|
|
1230
|
+
status: "in_progress",
|
|
1231
|
+
details: shortTaskTitle(event.label),
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
},
|
|
1235
|
+
async complete(message) {
|
|
1236
|
+
if (pendingTimer)
|
|
1237
|
+
clearTimeout(pendingTimer);
|
|
1238
|
+
const finalChunks = [...tasks.entries()].map(([id, task]) => ({
|
|
1239
|
+
type: "task_update",
|
|
1240
|
+
id,
|
|
1241
|
+
title: task.title,
|
|
1242
|
+
status: task.status === "in_progress" ? "complete" : task.status,
|
|
1243
|
+
}));
|
|
1244
|
+
const messageBlocks = Array.isArray(message.platformContext.blocks)
|
|
1245
|
+
? message.platformContext.blocks
|
|
1246
|
+
: [];
|
|
1247
|
+
const controlBlocks = approvalControls
|
|
1248
|
+
? [
|
|
1249
|
+
{
|
|
1250
|
+
type: "actions",
|
|
1251
|
+
block_id: `agent-native-approval-${Date.now()}`,
|
|
1252
|
+
elements: [
|
|
1253
|
+
{
|
|
1254
|
+
type: "button",
|
|
1255
|
+
text: { type: "plain_text", text: "Approve" },
|
|
1256
|
+
style: "primary",
|
|
1257
|
+
action_id: "agent_native_approve",
|
|
1258
|
+
value: approvalControls.approve,
|
|
1259
|
+
},
|
|
1260
|
+
{
|
|
1261
|
+
type: "button",
|
|
1262
|
+
text: { type: "plain_text", text: "Deny" },
|
|
1263
|
+
style: "danger",
|
|
1264
|
+
action_id: "agent_native_deny",
|
|
1265
|
+
value: approvalControls.deny,
|
|
1266
|
+
},
|
|
1267
|
+
],
|
|
1268
|
+
},
|
|
1269
|
+
]
|
|
1270
|
+
: [];
|
|
1271
|
+
await postSlackJson(token, "chat.stopStream", {
|
|
1272
|
+
channel,
|
|
1273
|
+
ts: streamTs,
|
|
1274
|
+
markdown_text: message.text || "Done.",
|
|
1275
|
+
...(finalChunks.length ? { chunks: finalChunks } : {}),
|
|
1276
|
+
...(messageBlocks.length || controlBlocks.length
|
|
1277
|
+
? { blocks: [...messageBlocks, ...controlBlocks].slice(0, 50) }
|
|
1278
|
+
: {}),
|
|
1279
|
+
});
|
|
1280
|
+
setSlackAssistantStatus(token, channel, threadTs, "");
|
|
1281
|
+
},
|
|
1282
|
+
async fail(message) {
|
|
1283
|
+
if (pendingTimer)
|
|
1284
|
+
clearTimeout(pendingTimer);
|
|
1285
|
+
await postSlackJson(token, "chat.stopStream", {
|
|
1286
|
+
channel,
|
|
1287
|
+
ts: streamTs,
|
|
1288
|
+
markdown_text: message.slice(0, SLACK_MAX_LENGTH),
|
|
1289
|
+
}).catch(() => { });
|
|
1290
|
+
setSlackAssistantStatus(token, channel, threadTs, "");
|
|
1291
|
+
},
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
585
1294
|
//# sourceMappingURL=slack.js.map
|