@agent-native/core 0.115.4 → 0.116.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/agent-native.eject.json +1 -0
- package/corpus/README.md +3 -3
- package/corpus/core/CHANGELOG.md +28 -0
- package/corpus/core/agent-native.eject.json +1 -0
- package/corpus/core/docs/AGENTS.md +1 -1
- package/corpus/core/docs/content/agent-mentions.mdx +2 -2
- package/corpus/core/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
- package/corpus/core/docs/content/agent-teams.mdx +4 -4
- package/corpus/core/docs/content/dispatch.mdx +10 -10
- package/corpus/core/docs/content/drop-in-agent.mdx +4 -4
- package/corpus/core/docs/content/external-agents.mdx +1 -1
- package/corpus/core/docs/content/frames.mdx +1 -1
- package/corpus/core/docs/content/integrations.mdx +13 -2
- package/corpus/core/docs/content/key-concepts.mdx +2 -2
- package/corpus/core/docs/content/mcp-clients.mdx +7 -1
- package/corpus/core/docs/content/multi-app-workspace.mdx +3 -3
- package/corpus/core/docs/content/real-time-collaboration.mdx +33 -15
- package/corpus/core/docs/content/recurring-jobs.mdx +7 -7
- package/corpus/core/docs/content/skills-guide.mdx +4 -4
- package/corpus/core/docs/content/template-brain.mdx +1 -1
- package/corpus/core/docs/content/toolkit-collaboration.mdx +1 -1
- package/corpus/core/docs/content/using-your-agent.mdx +1 -1
- package/corpus/core/docs/content/what-is-agent-native.mdx +4 -4
- package/corpus/core/docs/content/workspace-management.mdx +4 -4
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +13 -3
- package/corpus/core/src/cli/doctor.ts +6 -1
- package/corpus/core/src/client/AgentPanel.tsx +79 -41
- package/corpus/core/src/client/AssistantChat.tsx +71 -25
- package/corpus/core/src/client/FeedbackButton.tsx +33 -7
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +6 -8
- package/corpus/core/src/client/agent-chat-adapter.ts +11 -2
- package/corpus/core/src/client/agent-page/AgentTabFrame.tsx +22 -3
- package/corpus/core/src/client/agent-page/AgentTabsPage.tsx +34 -19
- package/corpus/core/src/client/chat/message-components.tsx +43 -16
- package/corpus/core/src/client/chat/tool-call-display.tsx +30 -18
- package/corpus/core/src/client/chat/tool-render-registry.tsx +2 -0
- package/corpus/core/src/client/resources/McpConnectionSuggestion.tsx +19 -2
- package/corpus/core/src/client/resources/ResourceTree.tsx +7 -10
- package/corpus/core/src/client/resources/ResourcesPanel.tsx +33 -70
- package/corpus/core/src/client/resources/mcp-connection-resume.ts +107 -0
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +65 -12
- package/corpus/core/src/client/resources/mcp-integration-logos.ts +4 -0
- package/corpus/core/src/client/sse-event-processor.ts +50 -14
- package/corpus/core/src/client/use-db-sync.ts +16 -6
- package/corpus/core/src/connections/catalog.ts +7 -1
- package/corpus/core/src/eject/remote-mcp-presets.ts +37 -5
- package/corpus/core/src/guards/explicit-collab-access.ts +229 -0
- package/corpus/core/src/guards/index.ts +1 -0
- package/corpus/core/src/localization/default-messages.ts +54 -5
- package/corpus/core/src/mcp/connect-route.ts +34 -51
- package/corpus/core/src/provider-api/index.ts +1 -1
- package/corpus/core/src/server/collab-plugin.ts +137 -18
- package/corpus/core/src/server/index.ts +2 -0
- package/corpus/core/src/styles/agent-native.css +40 -0
- package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/analytics/AGENTS.md +7 -2
- package/corpus/templates/analytics/actions/export-dashboard-panel-to-google-sheet.ts +144 -0
- package/corpus/templates/analytics/app/components/layout/Layout.tsx +7 -88
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +34 -37
- package/corpus/templates/analytics/app/global.css +0 -4
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -7
- package/corpus/templates/analytics/app/i18n-data.ts +107 -0
- package/corpus/templates/analytics/app/lib/data-source-status.ts +9 -0
- package/corpus/templates/analytics/app/lib/sql-query.ts +1 -2
- package/corpus/templates/analytics/app/pages/Ask.tsx +2 -7
- package/corpus/templates/analytics/app/pages/DataSources.tsx +48 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +59 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +2 -0
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +3 -1
- package/corpus/templates/analytics/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-daily-dashboard-email-query-batches.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-export-table-panels-directly-to-google-sheets.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-22-recent-chats-can-expand-in-the-sidebar.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +8 -8
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +31 -0
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +3 -5
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +12 -0
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +3 -5
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +150 -21
- package/corpus/templates/analytics/server/lib/google-sheets-export.ts +188 -0
- package/corpus/templates/analytics/server/lib/provider-api.ts +7 -2
- package/corpus/templates/analytics/server/plugins/collab.ts +6 -3
- package/corpus/templates/analytics/shared/sql-query-limits.ts +1 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/assets/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +54 -62
- package/corpus/templates/assets/app/hooks/use-navigation-state.ts +2 -6
- package/corpus/templates/assets/app/routes/_index.tsx +8 -5
- package/corpus/templates/assets/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/assets/changelog/2026-07-22-recent-chats-expand-from-a-compact-list.md +6 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/brain/actions/rotate-source-ingest-token.ts +77 -0
- package/corpus/templates/brain/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -51
- package/corpus/templates/brain/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/brain/app/i18n-data.ts +120 -0
- package/corpus/templates/brain/app/routes/sources.tsx +156 -5
- package/corpus/templates/brain/changelog/2026-07-22-chat-runs-always-end-with-an-answer.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-clear-background-chat-progress.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-long-chat-titles-stay-inside-the-sidebar.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-22-new-clips-and-webhook-sources-now-show-their-secure-connecti.md +6 -0
- package/corpus/templates/brain/jobs/emit-netlify-brain-queue-cron.ts +125 -0
- package/corpus/templates/brain/netlify.toml +5 -1
- package/corpus/templates/brain/scripts/configure-prod-clips-source.ts +50 -0
- package/corpus/templates/brain/server/lib/capture-sanitization.ts +64 -6
- package/corpus/templates/brain/server/plugins/agent-chat.ts +4 -0
- package/corpus/templates/brain/server/plugins/brain-jobs.ts +1 -0
- package/corpus/templates/brain/server/routes/api/brain/queue/run.post.ts +55 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/corpus/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/corpus/templates/chat/app/routes/_index.tsx +8 -5
- package/corpus/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/clips/AGENTS.md +9 -1
- package/corpus/templates/clips/actions/export-to-brain.ts +82 -6
- package/corpus/templates/clips/actions/request-transcript.ts +25 -14
- package/corpus/templates/clips/changelog/2026-07-22-clips-transcripts-now-retry-brain-export.md +5 -0
- package/corpus/templates/clips/changelog/2026-07-22-german-umlauts-and-other-non-ascii-characters-now-paste-corr.md +6 -0
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +26 -3
- package/corpus/templates/clips/jobs/emit-netlify-brain-export-cron.ts +118 -0
- package/corpus/templates/clips/netlify.toml +4 -1
- package/corpus/templates/clips/scripts/configure-prod-brain-export.ts +92 -0
- package/corpus/templates/clips/server/jobs/brain-export.ts +182 -0
- package/corpus/templates/clips/server/lib/brain-export-state.ts +42 -0
- package/corpus/templates/clips/server/lib/post-finalize-dispatch.ts +5 -1
- package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
- package/corpus/templates/clips/server/register-secrets.ts +42 -0
- package/corpus/templates/clips/server/routes/api/_agent-native-background/post-finalize-worker.post.ts +10 -1
- package/corpus/templates/clips/server/routes/api/clips/brain-export/run.post.ts +45 -0
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +1 -1
- package/corpus/templates/content/server/plugins/collab.ts +1 -1
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/crm/actions/_crm-data-program-actions.ts +15 -0
- package/corpus/templates/crm/actions/get-crm-dashboard-panel.ts +2 -0
- package/corpus/templates/crm/actions/run.ts +2 -6
- package/corpus/templates/crm/actions/update-crm-record.ts +4 -2
- package/corpus/templates/crm/app/components/layout/CrmLayout.tsx +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-crm-field-validation-now-explains-which-fields-cannot-be-edi.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-fixed-hubspot-contact-syncs-missing-records-updated-after-th.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-fixed-pipeline-dashboard-panels-so-their-opportunity-data-lo.md +6 -0
- package/corpus/templates/crm/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/crm/server/crm/hubspot-adapter.ts +4 -1
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/design/server/plugins/collab.ts +11 -8
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/forms/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/forms/app/root.tsx +1 -6
- package/corpus/templates/forms/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +2 -2
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/plan/app/components/layout/Layout.tsx +5 -1
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +57 -72
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +2 -9
- package/corpus/templates/plan/app/lib/create-plan-routing.ts +2 -2
- package/corpus/templates/plan/app/pages/PlanChatPage.tsx +0 -1
- package/corpus/templates/plan/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-22-recent-chats-and-sidebar-controls-are-more-compact.md +6 -0
- package/corpus/templates/plan/server/plugins/collab.ts +5 -2
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/slides/server/plugins/collab.ts +11 -8
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/corpus/templates/tasks/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +5 -22
- package/corpus/templates/tasks/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/corpus/toolkit/CHANGELOG.md +7 -0
- package/corpus/toolkit/README.md +12 -3
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/chat-history/ChatHistoryRail.tsx +89 -0
- package/corpus/toolkit/src/chat-history/index.ts +5 -0
- package/corpus/toolkit/src/chat-history.css +59 -0
- package/corpus/toolkit/src/composer/RealtimeVoiceMode.tsx +106 -36
- package/corpus/toolkit/src/composer/VoiceButton.tsx +49 -0
- package/corpus/toolkit/src/composer/realtime-voice-audio-level.ts +2 -1
- package/corpus/toolkit/src/composer/useRealtimeVoiceMode.tsx +5 -3
- package/corpus/toolkit/src/styles.css +35 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +13 -3
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +5 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +1 -0
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +38 -18
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +55 -20
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/FeedbackButton.d.ts +4 -2
- package/dist/client/FeedbackButton.d.ts.map +1 -1
- package/dist/client/FeedbackButton.js +18 -2
- package/dist/client/FeedbackButton.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +2 -3
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +11 -3
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-page/AgentTabFrame.d.ts +3 -1
- package/dist/client/agent-page/AgentTabFrame.d.ts.map +1 -1
- package/dist/client/agent-page/AgentTabFrame.js +3 -2
- package/dist/client/agent-page/AgentTabFrame.js.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.d.ts +2 -0
- package/dist/client/agent-page/AgentTabsPage.d.ts.map +1 -1
- package/dist/client/agent-page/AgentTabsPage.js +26 -15
- package/dist/client/agent-page/AgentTabsPage.js.map +1 -1
- package/dist/client/chat/message-components.d.ts +6 -1
- package/dist/client/chat/message-components.d.ts.map +1 -1
- package/dist/client/chat/message-components.js +17 -11
- package/dist/client/chat/message-components.js.map +1 -1
- package/dist/client/chat/tool-call-display.d.ts +11 -1
- package/dist/client/chat/tool-call-display.d.ts.map +1 -1
- package/dist/client/chat/tool-call-display.js +16 -17
- package/dist/client/chat/tool-call-display.js.map +1 -1
- package/dist/client/chat/tool-render-registry.d.ts +2 -0
- package/dist/client/chat/tool-render-registry.d.ts.map +1 -1
- package/dist/client/chat/tool-render-registry.js.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.d.ts.map +1 -1
- package/dist/client/resources/McpConnectionSuggestion.js +15 -1
- package/dist/client/resources/McpConnectionSuggestion.js.map +1 -1
- package/dist/client/resources/ResourceTree.d.ts.map +1 -1
- package/dist/client/resources/ResourceTree.js +3 -3
- package/dist/client/resources/ResourceTree.js.map +1 -1
- package/dist/client/resources/ResourcesPanel.d.ts +1 -0
- package/dist/client/resources/ResourcesPanel.d.ts.map +1 -1
- package/dist/client/resources/ResourcesPanel.js +34 -20
- package/dist/client/resources/ResourcesPanel.js.map +1 -1
- package/dist/client/resources/mcp-connection-resume.d.ts +11 -0
- package/dist/client/resources/mcp-connection-resume.d.ts.map +1 -0
- package/dist/client/resources/mcp-connection-resume.js +95 -0
- package/dist/client/resources/mcp-connection-resume.js.map +1 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts +1 -0
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +63 -8
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/resources/mcp-integration-logos.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-logos.js +4 -0
- package/dist/client/resources/mcp-integration-logos.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts +5 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +39 -13
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +3 -2
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +17 -6
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/connections/catalog.d.ts +1 -1
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +7 -1
- package/dist/connections/catalog.js.map +1 -1
- package/dist/eject/remote-mcp-presets.d.ts.map +1 -1
- package/dist/eject/remote-mcp-presets.js +33 -3
- package/dist/eject/remote-mcp-presets.js.map +1 -1
- package/dist/guards/explicit-collab-access.d.ts +8 -0
- package/dist/guards/explicit-collab-access.d.ts.map +1 -0
- package/dist/guards/explicit-collab-access.js +214 -0
- package/dist/guards/explicit-collab-access.js.map +1 -0
- package/dist/guards/index.d.ts +1 -0
- package/dist/guards/index.d.ts.map +1 -1
- package/dist/guards/index.js +1 -0
- package/dist/guards/index.js.map +1 -1
- package/dist/localization/default-messages.d.ts +43 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +48 -5
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +34 -48
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.js +1 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/server/collab-plugin.d.ts +34 -3
- package/dist/server/collab-plugin.d.ts.map +1 -1
- package/dist/server/collab-plugin.js +65 -12
- package/dist/server/collab-plugin.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/styles/agent-native.css +40 -0
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/dist/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/dist/templates/chat/app/routes/_index.tsx +8 -5
- package/dist/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/dist/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/dist/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
- package/docs/AGENTS.md +1 -1
- package/docs/content/agent-mentions.mdx +2 -2
- package/docs/content/{workspace.mdx → agent-resources.mdx} +1 -7
- package/docs/content/agent-teams.mdx +4 -4
- package/docs/content/dispatch.mdx +10 -10
- package/docs/content/drop-in-agent.mdx +4 -4
- package/docs/content/external-agents.mdx +1 -1
- package/docs/content/frames.mdx +1 -1
- package/docs/content/integrations.mdx +13 -2
- package/docs/content/key-concepts.mdx +2 -2
- package/docs/content/mcp-clients.mdx +7 -1
- package/docs/content/multi-app-workspace.mdx +3 -3
- package/docs/content/real-time-collaboration.mdx +33 -15
- package/docs/content/recurring-jobs.mdx +7 -7
- package/docs/content/skills-guide.mdx +4 -4
- package/docs/content/template-brain.mdx +1 -1
- package/docs/content/toolkit-collaboration.mdx +1 -1
- package/docs/content/using-your-agent.mdx +1 -1
- package/docs/content/what-is-agent-native.mdx +4 -4
- package/docs/content/workspace-management.mdx +4 -4
- package/package.json +3 -3
- package/src/agent/production-agent.ts +13 -3
- package/src/cli/doctor.ts +6 -1
- package/src/client/AgentPanel.tsx +79 -41
- package/src/client/AssistantChat.tsx +71 -25
- package/src/client/FeedbackButton.tsx +33 -7
- package/src/client/MultiTabAssistantChat.tsx +6 -8
- package/src/client/agent-chat-adapter.ts +11 -2
- package/src/client/agent-page/AgentTabFrame.tsx +22 -3
- package/src/client/agent-page/AgentTabsPage.tsx +34 -19
- package/src/client/chat/message-components.tsx +43 -16
- package/src/client/chat/tool-call-display.tsx +30 -18
- package/src/client/chat/tool-render-registry.tsx +2 -0
- package/src/client/resources/McpConnectionSuggestion.tsx +19 -2
- package/src/client/resources/ResourceTree.tsx +7 -10
- package/src/client/resources/ResourcesPanel.tsx +33 -70
- package/src/client/resources/mcp-connection-resume.ts +107 -0
- package/src/client/resources/mcp-integration-catalog.ts +65 -12
- package/src/client/resources/mcp-integration-logos.ts +4 -0
- package/src/client/sse-event-processor.ts +50 -14
- package/src/client/use-db-sync.ts +16 -6
- package/src/connections/catalog.ts +7 -1
- package/src/eject/remote-mcp-presets.ts +37 -5
- package/src/guards/explicit-collab-access.ts +229 -0
- package/src/guards/index.ts +1 -0
- package/src/localization/default-messages.ts +54 -5
- package/src/mcp/connect-route.ts +34 -51
- package/src/provider-api/index.ts +1 -1
- package/src/server/collab-plugin.ts +137 -18
- package/src/server/index.ts +2 -0
- package/src/styles/agent-native.css +40 -0
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/chat/app/components/layout/Layout.tsx +1 -0
- package/src/templates/chat/app/components/layout/Sidebar.tsx +43 -67
- package/src/templates/chat/app/hooks/use-navigation-state.ts +2 -7
- package/src/templates/chat/app/routes/_index.tsx +8 -5
- package/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +6 -0
- package/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +6 -0
- package/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +6 -0
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +4 -1
- package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +35 -13
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +1 -1
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +12 -8
|
@@ -403,6 +403,18 @@ const enUS = {
|
|
|
403
403
|
noCapturesTitle: "No captures match this view",
|
|
404
404
|
noCapturesDetail:
|
|
405
405
|
"Try another status, run a source sync, or import a transcript.",
|
|
406
|
+
rotateIngestToken: "Rotate ingest token",
|
|
407
|
+
connectIngestSource: "Connect {{source}}",
|
|
408
|
+
ingestHandoffDescription:
|
|
409
|
+
"Save these values in the sending app now. The ingest token is shown only once and cannot be recovered after this dialog closes.",
|
|
410
|
+
endpoint: "Endpoint",
|
|
411
|
+
sourceKey: "Source key",
|
|
412
|
+
ingestToken: "Ingest token",
|
|
413
|
+
copied: "Copied",
|
|
414
|
+
copy: "Copy",
|
|
415
|
+
ingestTokenSecurity:
|
|
416
|
+
"For security, Brain stores only a hash of this token. Rotate the token whenever the receiving app needs a new credential.",
|
|
417
|
+
ingestHandoffSaved: "I saved these values",
|
|
406
418
|
tuneSource: "Tune source",
|
|
407
419
|
setupDescription:
|
|
408
420
|
"Configure what Brain may ingest. Credentials stay in the workspace credential store; this form only saves allow-lists, cursors, and review rules.",
|
|
@@ -3052,6 +3064,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
3052
3064
|
noCapturesDetail:
|
|
3053
3065
|
"جرب حالة أخرى، أو قم بتشغيل مزامنة المصدر، أو قم باستيراد نص.",
|
|
3054
3066
|
noCapturesTitle: "لا توجد لقطات تطابق هذا الرأي",
|
|
3067
|
+
rotateIngestToken: "تدوير رمز الإدخال",
|
|
3068
|
+
connectIngestSource: "ربط {{source}}",
|
|
3069
|
+
ingestHandoffDescription:
|
|
3070
|
+
"احفظ هذه القيم في التطبيق المرسل الآن. سيُعرض رمز الإدخال مرة واحدة فقط ولا يمكن استعادته بعد إغلاق هذا الحوار.",
|
|
3071
|
+
endpoint: "نقطة النهاية",
|
|
3072
|
+
sourceKey: "مفتاح المصدر",
|
|
3073
|
+
ingestToken: "رمز الإدخال",
|
|
3074
|
+
copied: "تم النسخ",
|
|
3075
|
+
copy: "نسخ",
|
|
3076
|
+
ingestTokenSecurity:
|
|
3077
|
+
"لأسباب أمنية، يخزّن Brain تجزئة هذا الرمز فقط. أدر الرمز كلما احتاج التطبيق المستلم إلى بيانات اعتماد جديدة.",
|
|
3078
|
+
ingestHandoffSaved: "حفظت هذه القيم",
|
|
3055
3079
|
noConnectionProviders:
|
|
3056
3080
|
"لا يتوفر أي موفري اتصال Brain من الكتالوج المشترك.",
|
|
3057
3081
|
noCredentialKeysRequired: "لا توجد مفاتيح الاعتماد المطلوبة",
|
|
@@ -3467,6 +3491,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
3467
3491
|
noCapturesDetail:
|
|
3468
3492
|
"Versuchen Sie es mit einem anderen Status, führen Sie eine Quellsynchronisierung durch oder importieren Sie ein Transkript.",
|
|
3469
3493
|
noCapturesTitle: "Keine Aufnahmen stimmen mit dieser Ansicht überein",
|
|
3494
|
+
rotateIngestToken: "Aufnahmetoken drehen",
|
|
3495
|
+
connectIngestSource: "{{source}} verbinden",
|
|
3496
|
+
ingestHandoffDescription:
|
|
3497
|
+
"Speichern Sie diese Werte jetzt in der sendenden App. Das Aufnahmetoken wird nur einmal angezeigt und kann nach dem Schließen dieses Dialogs nicht wiederhergestellt werden.",
|
|
3498
|
+
endpoint: "Endpunkt",
|
|
3499
|
+
sourceKey: "Quellschlüssel",
|
|
3500
|
+
ingestToken: "Aufnahmetoken",
|
|
3501
|
+
copied: "Kopiert",
|
|
3502
|
+
copy: "Kopieren",
|
|
3503
|
+
ingestTokenSecurity:
|
|
3504
|
+
"Aus Sicherheitsgründen speichert Brain nur einen Hash dieses Tokens. Drehen Sie das Token, sobald die empfangende App neue Anmeldedaten benötigt.",
|
|
3505
|
+
ingestHandoffSaved: "Ich habe diese Werte gespeichert",
|
|
3470
3506
|
noConnectionProviders:
|
|
3471
3507
|
"Im freigegebenen Katalog sind keine Brain-Verbindungsanbieter verfügbar.",
|
|
3472
3508
|
noCredentialKeysRequired:
|
|
@@ -3891,6 +3927,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
3891
3927
|
noCapturesDetail:
|
|
3892
3928
|
"Pruebe con otro estado, ejecute una sincronización de origen o importe una transcripción.",
|
|
3893
3929
|
noCapturesTitle: "Ninguna captura coincide con esta vista.",
|
|
3930
|
+
rotateIngestToken: "Rotar token de ingesta",
|
|
3931
|
+
connectIngestSource: "Conectar {{source}}",
|
|
3932
|
+
ingestHandoffDescription:
|
|
3933
|
+
"Guarde estos valores ahora en la aplicación emisora. El token de ingesta se muestra una sola vez y no se puede recuperar después de cerrar este diálogo.",
|
|
3934
|
+
endpoint: "Punto final",
|
|
3935
|
+
sourceKey: "Clave de origen",
|
|
3936
|
+
ingestToken: "Token de ingesta",
|
|
3937
|
+
copied: "Copiado",
|
|
3938
|
+
copy: "Copiar",
|
|
3939
|
+
ingestTokenSecurity:
|
|
3940
|
+
"Por seguridad, Brain solo almacena un hash de este token. Rote el token cuando la aplicación receptora necesite una credencial nueva.",
|
|
3941
|
+
ingestHandoffSaved: "He guardado estos valores",
|
|
3894
3942
|
noConnectionProviders:
|
|
3895
3943
|
"No hay proveedores de conexión Brain disponibles en el catálogo compartido.",
|
|
3896
3944
|
noCredentialKeysRequired: "No se requieren claves de credenciales",
|
|
@@ -4316,6 +4364,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
4316
4364
|
noCapturesDetail:
|
|
4317
4365
|
"Essayez un autre statut, exécutez une synchronisation source ou importez une transcription.",
|
|
4318
4366
|
noCapturesTitle: "Aucune capture ne correspond à cette vue",
|
|
4367
|
+
rotateIngestToken: "Faire pivoter le jeton d’ingestion",
|
|
4368
|
+
connectIngestSource: "Connecter {{source}}",
|
|
4369
|
+
ingestHandoffDescription:
|
|
4370
|
+
"Enregistrez maintenant ces valeurs dans l’application émettrice. Le jeton d’ingestion ne s’affiche qu’une seule fois et ne peut pas être récupéré après la fermeture de cette boîte de dialogue.",
|
|
4371
|
+
endpoint: "Point de terminaison",
|
|
4372
|
+
sourceKey: "Clé de source",
|
|
4373
|
+
ingestToken: "Jeton d’ingestion",
|
|
4374
|
+
copied: "Copié",
|
|
4375
|
+
copy: "Copier",
|
|
4376
|
+
ingestTokenSecurity:
|
|
4377
|
+
"Pour des raisons de sécurité, Brain ne stocke que le hachage de ce jeton. Faites pivoter le jeton lorsque l’application destinataire a besoin d’un nouvel identifiant.",
|
|
4378
|
+
ingestHandoffSaved: "J’ai enregistré ces valeurs",
|
|
4319
4379
|
noConnectionProviders:
|
|
4320
4380
|
"Aucun fournisseur de connexion Brain n’est disponible dans le catalogue partagé.",
|
|
4321
4381
|
noCredentialKeysRequired: "Aucune clé d'identification requise",
|
|
@@ -4717,6 +4777,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
4717
4777
|
noCapturesDetail:
|
|
4718
4778
|
"कोई अन्य स्थिति आज़माएँ, स्रोत सिंक चलाएँ, या एक प्रतिलेख आयात करें।",
|
|
4719
4779
|
noCapturesTitle: "कोई भी कैप्चर इस दृश्य से मेल नहीं खाता",
|
|
4780
|
+
rotateIngestToken: "इंजेस्ट टोकन घुमाएँ",
|
|
4781
|
+
connectIngestSource: "कनेक्ट करें: {{source}}",
|
|
4782
|
+
ingestHandoffDescription:
|
|
4783
|
+
"इन मानों को अभी भेजने वाले ऐप में सहेजें। इंजेस्ट टोकन केवल एक बार दिखाया जाता है और यह संवाद बंद होने के बाद इसे पुनर्प्राप्त नहीं किया जा सकता।",
|
|
4784
|
+
endpoint: "एंडपॉइंट",
|
|
4785
|
+
sourceKey: "सोर्स कुंजी",
|
|
4786
|
+
ingestToken: "इंजेस्ट टोकन",
|
|
4787
|
+
copied: "कॉपी किया गया",
|
|
4788
|
+
copy: "कॉपी करें",
|
|
4789
|
+
ingestTokenSecurity:
|
|
4790
|
+
"सुरक्षा के लिए, Brain इस टोकन का केवल हैश संग्रहीत करता है। जब प्राप्त करने वाले ऐप को नए क्रेडेंशियल की आवश्यकता हो, तब टोकन घुमाएँ।",
|
|
4791
|
+
ingestHandoffSaved: "मैंने ये मान सहेज लिए हैं",
|
|
4720
4792
|
noConnectionProviders: "साझा कैटलॉग से कोई Brain कनेक्शन प्रदाता उपलब्ध नहीं हैं।",
|
|
4721
4793
|
noCredentialKeysRequired: "किसी क्रेडेंशियल कुंजी की आवश्यकता नहीं है",
|
|
4722
4794
|
noCredentialRefs: "इस संबंध पर कोई क्रेडेंशियल संदर्भ नहीं है",
|
|
@@ -5111,6 +5183,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
5111
5183
|
noCapturesDetail:
|
|
5112
5184
|
"別のステータスを試すか、ソース同期を実行するか、トランスクリプトをインポートしてください。",
|
|
5113
5185
|
noCapturesTitle: "このビューに一致するキャプチャはありません",
|
|
5186
|
+
rotateIngestToken: "取り込みトークンをローテーション",
|
|
5187
|
+
connectIngestSource: "「{{source}}」を接続",
|
|
5188
|
+
ingestHandoffDescription:
|
|
5189
|
+
"これらの値を今すぐ送信元アプリに保存してください。取り込みトークンは一度しか表示されず、このダイアログを閉じると復元できません。",
|
|
5190
|
+
endpoint: "エンドポイント",
|
|
5191
|
+
sourceKey: "ソースキー",
|
|
5192
|
+
ingestToken: "取り込みトークン",
|
|
5193
|
+
copied: "コピーしました",
|
|
5194
|
+
copy: "コピー",
|
|
5195
|
+
ingestTokenSecurity:
|
|
5196
|
+
"セキュリティのため、Brain はこのトークンのハッシュのみを保存します。受信アプリに新しい認証情報が必要になったら、トークンをローテーションしてください。",
|
|
5197
|
+
ingestHandoffSaved: "これらの値を保存しました",
|
|
5114
5198
|
noConnectionProviders:
|
|
5115
5199
|
"共有カタログから使用できる Brain 接続プロバイダーはありません。",
|
|
5116
5200
|
noCredentialKeysRequired: "認証キーは必要ありません",
|
|
@@ -5511,6 +5595,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
5511
5595
|
noCapturesDetail:
|
|
5512
5596
|
"다른 상태를 시도하거나, 소스 동기화를 실행하거나, 스크립트를 가져오세요.",
|
|
5513
5597
|
noCapturesTitle: "이 보기와 일치하는 캡처가 없습니다.",
|
|
5598
|
+
rotateIngestToken: "수집 토큰 교체",
|
|
5599
|
+
connectIngestSource: "{{source}} 연결",
|
|
5600
|
+
ingestHandoffDescription:
|
|
5601
|
+
"지금 이 값을 보내는 앱에 저장하세요. 수집 토큰은 한 번만 표시되며 이 대화상자를 닫으면 복구할 수 없습니다.",
|
|
5602
|
+
endpoint: "엔드포인트",
|
|
5603
|
+
sourceKey: "소스 키",
|
|
5604
|
+
ingestToken: "수집 토큰",
|
|
5605
|
+
copied: "복사됨",
|
|
5606
|
+
copy: "복사",
|
|
5607
|
+
ingestTokenSecurity:
|
|
5608
|
+
"보안을 위해 Brain은 이 토큰의 해시만 저장합니다. 수신 앱에 새 자격 증명이 필요할 때 토큰을 교체하세요.",
|
|
5609
|
+
ingestHandoffSaved: "이 값을 저장했습니다",
|
|
5514
5610
|
noConnectionProviders:
|
|
5515
5611
|
"공유 카탈로그에서는 Brain 연결 공급자를 사용할 수 없습니다.",
|
|
5516
5612
|
noCredentialKeysRequired: "자격 증명 키가 필요하지 않습니다",
|
|
@@ -5921,6 +6017,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
5921
6017
|
noCapturesDetail:
|
|
5922
6018
|
"Tente outro status, execute uma sincronização de origem ou importe uma transcrição.",
|
|
5923
6019
|
noCapturesTitle: "Nenhuma captura corresponde a esta visualização",
|
|
6020
|
+
rotateIngestToken: "Alternar token de ingestão",
|
|
6021
|
+
connectIngestSource: "Conectar {{source}}",
|
|
6022
|
+
ingestHandoffDescription:
|
|
6023
|
+
"Salve estes valores agora no aplicativo emissor. O token de ingestão é exibido apenas uma vez e não pode ser recuperado depois que esta caixa de diálogo for fechada.",
|
|
6024
|
+
endpoint: "Endpoint",
|
|
6025
|
+
sourceKey: "Chave da fonte",
|
|
6026
|
+
ingestToken: "Token de ingestão",
|
|
6027
|
+
copied: "Copiado",
|
|
6028
|
+
copy: "Copiar",
|
|
6029
|
+
ingestTokenSecurity:
|
|
6030
|
+
"Por segurança, o Brain armazena apenas um hash deste token. Alterne o token sempre que o aplicativo receptor precisar de uma nova credencial.",
|
|
6031
|
+
ingestHandoffSaved: "Salvei estes valores",
|
|
5924
6032
|
noConnectionProviders:
|
|
5925
6033
|
"Nenhum provedor de conexão Brain está disponível no catálogo compartilhado.",
|
|
5926
6034
|
noCredentialKeysRequired: "Nenhuma chave de credencial necessária",
|
|
@@ -6300,6 +6408,18 @@ const exactEnglishDebtOverrides: Partial<
|
|
|
6300
6408
|
noBrainSourcesYet: "还没有 Brain 来源",
|
|
6301
6409
|
noCapturesDetail: "尝试其他状态、运行源同步或导入转录本。",
|
|
6302
6410
|
noCapturesTitle: "没有与此视图匹配的捕获",
|
|
6411
|
+
rotateIngestToken: "轮换摄取令牌",
|
|
6412
|
+
connectIngestSource: "连接 {{source}}",
|
|
6413
|
+
ingestHandoffDescription:
|
|
6414
|
+
"现在将这些值保存到发送应用中。摄取令牌只显示一次,关闭此对话框后将无法恢复。",
|
|
6415
|
+
endpoint: "端点",
|
|
6416
|
+
sourceKey: "源密钥",
|
|
6417
|
+
ingestToken: "摄取令牌",
|
|
6418
|
+
copied: "已复制",
|
|
6419
|
+
copy: "复制",
|
|
6420
|
+
ingestTokenSecurity:
|
|
6421
|
+
"出于安全考虑,Brain 只存储此令牌的哈希值。当接收应用需要新的凭据时,请轮换令牌。",
|
|
6422
|
+
ingestHandoffSaved: "我已保存这些值",
|
|
6303
6423
|
noConnectionProviders: "共享目录中没有可用的 Brain 连接提供程序。",
|
|
6304
6424
|
noCredentialKeysRequired: "无需凭证密钥",
|
|
6305
6425
|
noCredentialRefs: "此连接上没有凭据参考",
|
|
@@ -3,6 +3,14 @@ import {
|
|
|
3
3
|
useActionQuery,
|
|
4
4
|
} from "@agent-native/core/client/hooks";
|
|
5
5
|
import { useT } from "@agent-native/core/client/i18n";
|
|
6
|
+
import {
|
|
7
|
+
Dialog,
|
|
8
|
+
DialogContent,
|
|
9
|
+
DialogDescription,
|
|
10
|
+
DialogFooter,
|
|
11
|
+
DialogHeader,
|
|
12
|
+
DialogTitle,
|
|
13
|
+
} from "@agent-native/toolkit/ui/dialog";
|
|
6
14
|
import {
|
|
7
15
|
IconAlertTriangle,
|
|
8
16
|
IconArchive,
|
|
@@ -12,6 +20,7 @@ import {
|
|
|
12
20
|
IconCircleCheck,
|
|
13
21
|
IconCircleDashed,
|
|
14
22
|
IconClock,
|
|
23
|
+
IconCopy,
|
|
15
24
|
IconDatabaseImport,
|
|
16
25
|
IconDotsVertical,
|
|
17
26
|
IconExternalLink,
|
|
@@ -73,6 +82,7 @@ import {
|
|
|
73
82
|
type BrainCaptureReviewItem,
|
|
74
83
|
type EnqueueCapturesDistillationResponse,
|
|
75
84
|
type CapturesResponse,
|
|
85
|
+
type CreateSourceResponse,
|
|
76
86
|
type BrainSource,
|
|
77
87
|
type BrainWorkspaceConnectionGrantState,
|
|
78
88
|
type BrainWorkspaceConnectionStatus,
|
|
@@ -90,6 +100,10 @@ import {
|
|
|
90
100
|
sourceReviewRequired,
|
|
91
101
|
sourceType,
|
|
92
102
|
} from "@/lib/brain";
|
|
103
|
+
import {
|
|
104
|
+
createOneTimeIngestHandoff,
|
|
105
|
+
type OneTimeIngestHandoff,
|
|
106
|
+
} from "@/lib/ingest-handoff";
|
|
93
107
|
|
|
94
108
|
type Provider = "manual" | "generic" | "clips" | "slack" | "granola" | "github";
|
|
95
109
|
type CaptureStatusFilter = BrainCaptureReviewStatus | "all";
|
|
@@ -1499,16 +1513,25 @@ function SourceFact({ label, value }: { label: string; value: ReactNode }) {
|
|
|
1499
1513
|
);
|
|
1500
1514
|
}
|
|
1501
1515
|
|
|
1516
|
+
function ingestSourceKey(source: BrainSource) {
|
|
1517
|
+
const sourceKey = source.config?.sourceKey;
|
|
1518
|
+
return typeof sourceKey === "string" && sourceKey.trim()
|
|
1519
|
+
? sourceKey.trim()
|
|
1520
|
+
: null;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1502
1523
|
function SourceListItem({
|
|
1503
1524
|
source,
|
|
1504
1525
|
syncPending,
|
|
1505
1526
|
onReview,
|
|
1527
|
+
onRotateIngestToken,
|
|
1506
1528
|
onSync,
|
|
1507
1529
|
onTune,
|
|
1508
1530
|
}: {
|
|
1509
1531
|
source: BrainSource;
|
|
1510
1532
|
syncPending: boolean;
|
|
1511
1533
|
onReview: () => void;
|
|
1534
|
+
onRotateIngestToken?: () => void;
|
|
1512
1535
|
onSync: () => void;
|
|
1513
1536
|
onTune: () => void;
|
|
1514
1537
|
}) {
|
|
@@ -1602,6 +1625,12 @@ function SourceListItem({
|
|
|
1602
1625
|
<IconSettings2 className="size-4" />
|
|
1603
1626
|
{t("sources.tuneSource")}
|
|
1604
1627
|
</DropdownMenuItem>
|
|
1628
|
+
{onRotateIngestToken ? (
|
|
1629
|
+
<DropdownMenuItem onSelect={onRotateIngestToken}>
|
|
1630
|
+
<IconRefresh className="size-4" />
|
|
1631
|
+
{t("sources.rotateIngestToken")}
|
|
1632
|
+
</DropdownMenuItem>
|
|
1633
|
+
) : null}
|
|
1605
1634
|
</DropdownMenuContent>
|
|
1606
1635
|
</DropdownMenu>
|
|
1607
1636
|
</div>
|
|
@@ -1633,6 +1662,11 @@ export default function SourcesRoute() {
|
|
|
1633
1662
|
const type = params.get("type") ?? "all";
|
|
1634
1663
|
const [advancedOpen, setAdvancedOpen] = useState(false);
|
|
1635
1664
|
const [setupOpen, setSetupOpen] = useState(false);
|
|
1665
|
+
const [ingestHandoff, setIngestHandoff] =
|
|
1666
|
+
useState<OneTimeIngestHandoff | null>(null);
|
|
1667
|
+
const [copiedHandoffField, setCopiedHandoffField] = useState<string | null>(
|
|
1668
|
+
null,
|
|
1669
|
+
);
|
|
1636
1670
|
const [editingSource, setEditingSource] = useState<BrainSource | null>(null);
|
|
1637
1671
|
const [reviewSource, setReviewSource] = useState<BrainSource | null>(null);
|
|
1638
1672
|
const [captureStatus, setCaptureStatus] =
|
|
@@ -1672,7 +1706,7 @@ export default function SourcesRoute() {
|
|
|
1672
1706
|
}
|
|
1673
1707
|
>("update-source" as any);
|
|
1674
1708
|
const createSource = useActionMutation<
|
|
1675
|
-
|
|
1709
|
+
CreateSourceResponse,
|
|
1676
1710
|
{
|
|
1677
1711
|
title: string;
|
|
1678
1712
|
provider: Provider;
|
|
@@ -1681,6 +1715,10 @@ export default function SourcesRoute() {
|
|
|
1681
1715
|
sourceKey?: string;
|
|
1682
1716
|
}
|
|
1683
1717
|
>("create-source" as any);
|
|
1718
|
+
const rotateSourceIngestToken = useActionMutation<
|
|
1719
|
+
CreateSourceResponse,
|
|
1720
|
+
{ sourceId: string }
|
|
1721
|
+
>("rotate-source-ingest-token" as any);
|
|
1684
1722
|
const syncSource = useActionMutation<unknown, { sourceId: string }>(
|
|
1685
1723
|
"sync-source" as any,
|
|
1686
1724
|
);
|
|
@@ -1818,10 +1856,20 @@ export default function SourcesRoute() {
|
|
|
1818
1856
|
setForm((current) => ({ ...current, ...patch }));
|
|
1819
1857
|
}
|
|
1820
1858
|
|
|
1821
|
-
function
|
|
1859
|
+
function closeIngestHandoff() {
|
|
1860
|
+
setIngestHandoff(null);
|
|
1861
|
+
setCopiedHandoffField(null);
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
async function copyIngestHandoffValue(value: string, field: string) {
|
|
1865
|
+
await navigator.clipboard.writeText(value);
|
|
1866
|
+
setCopiedHandoffField(field);
|
|
1867
|
+
}
|
|
1868
|
+
|
|
1869
|
+
async function submitSource() {
|
|
1822
1870
|
const config = buildConfig(form);
|
|
1823
1871
|
if (editingSource) {
|
|
1824
|
-
updateSource.
|
|
1872
|
+
await updateSource.mutateAsync({
|
|
1825
1873
|
id: editingSource.id,
|
|
1826
1874
|
title: form.title.trim() || defaultTitle(form.provider, t),
|
|
1827
1875
|
status:
|
|
@@ -1829,17 +1877,39 @@ export default function SourcesRoute() {
|
|
|
1829
1877
|
config,
|
|
1830
1878
|
});
|
|
1831
1879
|
} else {
|
|
1832
|
-
createSource.
|
|
1880
|
+
const result = await createSource.mutateAsync({
|
|
1833
1881
|
title: form.title.trim() || defaultTitle(form.provider, t),
|
|
1834
1882
|
provider: form.provider,
|
|
1835
1883
|
visibility: "org",
|
|
1836
1884
|
config,
|
|
1837
1885
|
sourceKey: form.sourceKey.trim() || undefined,
|
|
1838
1886
|
});
|
|
1887
|
+
const handoff = createOneTimeIngestHandoff({
|
|
1888
|
+
origin: window.location.origin,
|
|
1889
|
+
provider: form.provider,
|
|
1890
|
+
result,
|
|
1891
|
+
sourceKey: form.sourceKey,
|
|
1892
|
+
});
|
|
1893
|
+
if (handoff) setIngestHandoff(handoff);
|
|
1839
1894
|
}
|
|
1840
1895
|
setSetupOpen(false);
|
|
1841
1896
|
}
|
|
1842
1897
|
|
|
1898
|
+
async function rotateIngestToken(source: BrainSource) {
|
|
1899
|
+
const sourceKey = ingestSourceKey(source);
|
|
1900
|
+
if (!sourceKey) return;
|
|
1901
|
+
const result = await rotateSourceIngestToken.mutateAsync({
|
|
1902
|
+
sourceId: source.id,
|
|
1903
|
+
});
|
|
1904
|
+
const handoff = createOneTimeIngestHandoff({
|
|
1905
|
+
origin: window.location.origin,
|
|
1906
|
+
provider: source.provider ?? "",
|
|
1907
|
+
result,
|
|
1908
|
+
sourceKey,
|
|
1909
|
+
});
|
|
1910
|
+
if (handoff) setIngestHandoff(handoff);
|
|
1911
|
+
}
|
|
1912
|
+
|
|
1843
1913
|
function toggleCaptureSelection(captureId: string, checked: boolean) {
|
|
1844
1914
|
setSelectedCaptureIds((current) => {
|
|
1845
1915
|
const next = new Set(current);
|
|
@@ -1909,8 +1979,17 @@ export default function SourcesRoute() {
|
|
|
1909
1979
|
<SourceListItem
|
|
1910
1980
|
key={source.id}
|
|
1911
1981
|
source={source}
|
|
1912
|
-
syncPending={
|
|
1982
|
+
syncPending={
|
|
1983
|
+
syncSource.isPending || rotateSourceIngestToken.isPending
|
|
1984
|
+
}
|
|
1913
1985
|
onReview={() => openCaptureReview(source)}
|
|
1986
|
+
onRotateIngestToken={
|
|
1987
|
+
(source.provider === "clips" ||
|
|
1988
|
+
source.provider === "generic") &&
|
|
1989
|
+
ingestSourceKey(source)
|
|
1990
|
+
? () => void rotateIngestToken(source)
|
|
1991
|
+
: undefined
|
|
1992
|
+
}
|
|
1914
1993
|
onSync={() => syncSource.mutate({ sourceId: source.id })}
|
|
1915
1994
|
onTune={() => openEdit(source)}
|
|
1916
1995
|
/>
|
|
@@ -1928,6 +2007,7 @@ export default function SourcesRoute() {
|
|
|
1928
2007
|
connectionProvidersQuery.isError ||
|
|
1929
2008
|
updateSource.isError ||
|
|
1930
2009
|
createSource.isError ||
|
|
2010
|
+
rotateSourceIngestToken.isError ||
|
|
1931
2011
|
syncSource.isError ||
|
|
1932
2012
|
syncDueSources.isError ||
|
|
1933
2013
|
enqueueCapturesDistillation.isError ? (
|
|
@@ -2302,6 +2382,77 @@ export default function SourcesRoute() {
|
|
|
2302
2382
|
</SheetContent>
|
|
2303
2383
|
</Sheet>
|
|
2304
2384
|
|
|
2385
|
+
<Dialog
|
|
2386
|
+
open={Boolean(ingestHandoff)}
|
|
2387
|
+
onOpenChange={(open) => {
|
|
2388
|
+
if (!open) closeIngestHandoff();
|
|
2389
|
+
}}
|
|
2390
|
+
>
|
|
2391
|
+
{ingestHandoff ? (
|
|
2392
|
+
<DialogContent className="max-w-xl gap-5">
|
|
2393
|
+
<DialogHeader>
|
|
2394
|
+
<DialogTitle>
|
|
2395
|
+
{t("sources.connectIngestSource", {
|
|
2396
|
+
source: ingestHandoff.source.title,
|
|
2397
|
+
})}
|
|
2398
|
+
</DialogTitle>
|
|
2399
|
+
<DialogDescription>
|
|
2400
|
+
{t("sources.ingestHandoffDescription")}
|
|
2401
|
+
</DialogDescription>
|
|
2402
|
+
</DialogHeader>
|
|
2403
|
+
|
|
2404
|
+
<div className="grid gap-4">
|
|
2405
|
+
{[
|
|
2406
|
+
[t("sources.endpoint"), ingestHandoff.endpoint, "endpoint"],
|
|
2407
|
+
[t("sources.sourceKey"), ingestHandoff.sourceKey, "source-key"],
|
|
2408
|
+
[
|
|
2409
|
+
t("sources.ingestToken"),
|
|
2410
|
+
ingestHandoff.ingestToken,
|
|
2411
|
+
"ingest-token",
|
|
2412
|
+
],
|
|
2413
|
+
].map(([label, value, field]) => (
|
|
2414
|
+
<div key={field} className="grid gap-2">
|
|
2415
|
+
<Label htmlFor={`ingest-handoff-${field}`}>{label}</Label>
|
|
2416
|
+
<div className="flex gap-2">
|
|
2417
|
+
<Input
|
|
2418
|
+
id={`ingest-handoff-${field}`}
|
|
2419
|
+
value={value}
|
|
2420
|
+
readOnly
|
|
2421
|
+
className="min-w-0 font-mono text-xs"
|
|
2422
|
+
/>
|
|
2423
|
+
<Button
|
|
2424
|
+
type="button"
|
|
2425
|
+
variant="outline"
|
|
2426
|
+
className="shrink-0"
|
|
2427
|
+
onClick={() => void copyIngestHandoffValue(value, field)}
|
|
2428
|
+
>
|
|
2429
|
+
{copiedHandoffField === field ? (
|
|
2430
|
+
<IconChecks className="size-4" />
|
|
2431
|
+
) : (
|
|
2432
|
+
<IconCopy className="size-4" />
|
|
2433
|
+
)}
|
|
2434
|
+
{copiedHandoffField === field
|
|
2435
|
+
? t("sources.copied")
|
|
2436
|
+
: t("sources.copy")}
|
|
2437
|
+
</Button>
|
|
2438
|
+
</div>
|
|
2439
|
+
</div>
|
|
2440
|
+
))}
|
|
2441
|
+
</div>
|
|
2442
|
+
|
|
2443
|
+
<div className="rounded-md border border-border bg-muted/25 p-3 text-sm leading-6 text-muted-foreground">
|
|
2444
|
+
{t("sources.ingestTokenSecurity")}
|
|
2445
|
+
</div>
|
|
2446
|
+
|
|
2447
|
+
<DialogFooter>
|
|
2448
|
+
<Button type="button" onClick={closeIngestHandoff}>
|
|
2449
|
+
{t("sources.ingestHandoffSaved")}
|
|
2450
|
+
</Button>
|
|
2451
|
+
</DialogFooter>
|
|
2452
|
+
</DialogContent>
|
|
2453
|
+
) : null}
|
|
2454
|
+
</Dialog>
|
|
2455
|
+
|
|
2305
2456
|
<Sheet open={setupOpen} onOpenChange={setSetupOpen}>
|
|
2306
2457
|
<SheetContent className="w-full overflow-y-auto sm:max-w-xl">
|
|
2307
2458
|
<SheetHeader>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
import { cpSync, existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
const FUNCTIONS_DIR = path.join(ROOT, ".netlify", "functions-internal");
|
|
10
|
+
const SERVER_DIR = path.join(FUNCTIONS_DIR, "server");
|
|
11
|
+
export const SCHEDULED_NAME = "brain-queue-cron";
|
|
12
|
+
export const WORKER_NAME = "brain-queue-sweep-background";
|
|
13
|
+
export const ROUTE_PATH = "/api/brain/queue/run";
|
|
14
|
+
export const SCHEDULE = "* * * * *";
|
|
15
|
+
|
|
16
|
+
function ensureDir(dir: string) {
|
|
17
|
+
mkdirSync(dir, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function scheduledTriggerSource(token: string) {
|
|
21
|
+
return `const WORKER_PATH = "/.netlify/functions/${WORKER_NAME}";
|
|
22
|
+
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
23
|
+
|
|
24
|
+
function siteOrigin(request) {
|
|
25
|
+
return new URL(request.url).origin;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default async function handler(request) {
|
|
29
|
+
const response = await fetch(new URL(WORKER_PATH, siteOrigin(request)), {
|
|
30
|
+
method: "POST",
|
|
31
|
+
headers: { "content-type": "application/json", "x-agent-native-brain-cron": CRON_TOKEN },
|
|
32
|
+
body: JSON.stringify({ scheduled: true }),
|
|
33
|
+
});
|
|
34
|
+
if (!response.ok && response.status !== 202) {
|
|
35
|
+
console.error("[brain-queue-cron] Background sweep trigger failed:", response.status);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const config = {
|
|
40
|
+
name: "brain queue cron trigger",
|
|
41
|
+
generator: "agent-native brain build",
|
|
42
|
+
schedule: ${JSON.stringify(SCHEDULE)},
|
|
43
|
+
};
|
|
44
|
+
`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function backgroundWorkerSource(token: string) {
|
|
48
|
+
return `globalThis.__AGENT_NATIVE_BRAIN_SCHEDULED_RUNTIME__ = true;
|
|
49
|
+
const CRON_TOKEN = ${JSON.stringify(token)};
|
|
50
|
+
const ROUTE_PATH = ${JSON.stringify(ROUTE_PATH)};
|
|
51
|
+
let cachedHandler;
|
|
52
|
+
|
|
53
|
+
function timingSafeEquals(a, b) {
|
|
54
|
+
if (a.length !== b.length) return false;
|
|
55
|
+
let diff = 0;
|
|
56
|
+
for (let i = 0; i < a.length; i += 1) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
57
|
+
return diff === 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default async function handler(request, context) {
|
|
61
|
+
const token = request.headers.get("x-agent-native-brain-cron") || "";
|
|
62
|
+
if (!timingSafeEquals(token, CRON_TOKEN)) return new Response("Unauthorized", { status: 401 });
|
|
63
|
+
cachedHandler ??= (await import("./main.mjs")).default;
|
|
64
|
+
const url = new URL(request.url);
|
|
65
|
+
url.pathname = ROUTE_PATH;
|
|
66
|
+
url.search = "";
|
|
67
|
+
return cachedHandler(new Request(url, {
|
|
68
|
+
method: "POST",
|
|
69
|
+
headers: { "content-type": "application/json" },
|
|
70
|
+
body: JSON.stringify({ scheduled: true }),
|
|
71
|
+
}), context);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export const config = {
|
|
75
|
+
name: "brain queue background sweep",
|
|
76
|
+
generator: "agent-native brain build",
|
|
77
|
+
background: true,
|
|
78
|
+
nodeBundler: "none",
|
|
79
|
+
includedFiles: ["**"],
|
|
80
|
+
preferStatic: false,
|
|
81
|
+
};
|
|
82
|
+
`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export function emitNetlifyBrainQueueCron(
|
|
86
|
+
options: {
|
|
87
|
+
functionsDir?: string;
|
|
88
|
+
serverDir?: string;
|
|
89
|
+
token?: string;
|
|
90
|
+
} = {},
|
|
91
|
+
) {
|
|
92
|
+
const functionsDir = options.functionsDir ?? FUNCTIONS_DIR;
|
|
93
|
+
const serverDir = options.serverDir ?? SERVER_DIR;
|
|
94
|
+
if (!existsSync(serverDir)) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
"Expected Nitro Netlify server output before emitting Brain cron functions.",
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
const token = options.token ?? randomBytes(32).toString("hex");
|
|
100
|
+
const scheduledDir = path.join(functionsDir, SCHEDULED_NAME);
|
|
101
|
+
const workerDir = path.join(functionsDir, WORKER_NAME);
|
|
102
|
+
rmSync(scheduledDir, { recursive: true, force: true });
|
|
103
|
+
rmSync(workerDir, { recursive: true, force: true });
|
|
104
|
+
ensureDir(scheduledDir);
|
|
105
|
+
cpSync(serverDir, workerDir, { recursive: true });
|
|
106
|
+
rmSync(path.join(workerDir, "server.mjs"), { force: true });
|
|
107
|
+
writeFileSync(
|
|
108
|
+
path.join(scheduledDir, `${SCHEDULED_NAME}.mjs`),
|
|
109
|
+
scheduledTriggerSource(token),
|
|
110
|
+
);
|
|
111
|
+
writeFileSync(
|
|
112
|
+
path.join(workerDir, `${WORKER_NAME}.mjs`),
|
|
113
|
+
backgroundWorkerSource(token),
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (
|
|
118
|
+
process.argv[1] &&
|
|
119
|
+
path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)
|
|
120
|
+
) {
|
|
121
|
+
emitNetlifyBrainQueueCron();
|
|
122
|
+
console.log(
|
|
123
|
+
"[brain-queue-cron] Emitted scheduled queue sweep and background worker.",
|
|
124
|
+
);
|
|
125
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[build]
|
|
2
2
|
ignore = "node ./scripts/netlify-ignore-build.mjs brain"
|
|
3
|
-
command = "export DATABASE_URL=${NETLIFY_DATABASE_URL:-$DATABASE_URL} && pnpm install && NITRO_PRESET=netlify pnpm --filter brain build"
|
|
3
|
+
command = "export DATABASE_URL=${NETLIFY_DATABASE_URL:-$DATABASE_URL} && pnpm install && NITRO_PRESET=netlify pnpm --filter brain build && pnpm exec tsx templates/brain/jobs/emit-netlify-brain-queue-cron.ts"
|
|
4
4
|
publish = "templates/brain/dist"
|
|
5
5
|
functions = "templates/brain/.netlify/functions-internal"
|
|
6
6
|
|
|
@@ -15,3 +15,7 @@ NPM_CONFIG_PRODUCTION = "false"
|
|
|
15
15
|
# auto-continuation path can hand off before Netlify kills the function.
|
|
16
16
|
[functions."*"]
|
|
17
17
|
timeout = 75
|
|
18
|
+
|
|
19
|
+
[functions.brain-queue-sweep-background]
|
|
20
|
+
timeout = 900
|
|
21
|
+
memory = "2gb"
|