@agent-native/core 0.98.17 → 0.99.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 +15 -0
- package/corpus/core/docs/content/actions.mdx +1 -1
- package/corpus/core/docs/content/authentication.mdx +1 -1
- package/corpus/core/docs/content/dispatch.mdx +3 -3
- package/corpus/core/docs/content/external-agents.mdx +30 -19
- package/corpus/core/docs/content/locales/ar-SA/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/ar-SA/external-agents.mdx +23 -19
- package/corpus/core/docs/content/locales/ar-SA/mcp-clients.mdx +31 -3
- package/corpus/core/docs/content/locales/ar-SA/mcp-protocol.mdx +29 -15
- package/corpus/core/docs/content/locales/ar-SA/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/ar-SA/server.mdx +2 -2
- package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/external-agents.mdx +23 -19
- package/corpus/core/docs/content/locales/de-DE/mcp-clients.mdx +37 -3
- package/corpus/core/docs/content/locales/de-DE/mcp-protocol.mdx +29 -15
- package/corpus/core/docs/content/locales/de-DE/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/de-DE/server.mdx +2 -2
- package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/es-ES/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/es-ES/external-agents.mdx +32 -19
- package/corpus/core/docs/content/locales/es-ES/mcp-clients.mdx +17 -3
- package/corpus/core/docs/content/locales/es-ES/mcp-protocol.mdx +38 -15
- package/corpus/core/docs/content/locales/es-ES/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/es-ES/server.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/fr-FR/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/fr-FR/external-agents.mdx +23 -19
- package/corpus/core/docs/content/locales/fr-FR/mcp-clients.mdx +17 -3
- package/corpus/core/docs/content/locales/fr-FR/mcp-protocol.mdx +29 -15
- package/corpus/core/docs/content/locales/fr-FR/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/fr-FR/server.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/hi-IN/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/hi-IN/external-agents.mdx +31 -19
- package/corpus/core/docs/content/locales/hi-IN/mcp-clients.mdx +17 -3
- package/corpus/core/docs/content/locales/hi-IN/mcp-protocol.mdx +36 -15
- package/corpus/core/docs/content/locales/hi-IN/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/hi-IN/server.mdx +2 -2
- package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/ja-JP/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/ja-JP/external-agents.mdx +23 -19
- package/corpus/core/docs/content/locales/ja-JP/mcp-clients.mdx +34 -3
- package/corpus/core/docs/content/locales/ja-JP/mcp-protocol.mdx +29 -15
- package/corpus/core/docs/content/locales/ja-JP/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/ja-JP/server.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/ko-KR/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/ko-KR/external-agents.mdx +30 -19
- package/corpus/core/docs/content/locales/ko-KR/mcp-clients.mdx +33 -3
- package/corpus/core/docs/content/locales/ko-KR/mcp-protocol.mdx +36 -15
- package/corpus/core/docs/content/locales/ko-KR/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/ko-KR/server.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/pt-BR/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/pt-BR/external-agents.mdx +32 -19
- package/corpus/core/docs/content/locales/pt-BR/mcp-clients.mdx +34 -3
- package/corpus/core/docs/content/locales/pt-BR/mcp-protocol.mdx +32 -15
- package/corpus/core/docs/content/locales/pt-BR/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/pt-BR/server.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-CN/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-CN/external-agents.mdx +23 -19
- package/corpus/core/docs/content/locales/zh-CN/mcp-clients.mdx +28 -3
- package/corpus/core/docs/content/locales/zh-CN/mcp-protocol.mdx +29 -15
- package/corpus/core/docs/content/locales/zh-CN/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-CN/server.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-TW/actions.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/authentication.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/dispatch.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-TW/external-agents.mdx +23 -19
- package/corpus/core/docs/content/locales/zh-TW/mcp-clients.mdx +28 -3
- package/corpus/core/docs/content/locales/zh-TW/mcp-protocol.mdx +30 -15
- package/corpus/core/docs/content/locales/zh-TW/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/locales/zh-TW/server.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/template-assets.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +3 -3
- package/corpus/core/docs/content/mcp-clients.mdx +31 -4
- package/corpus/core/docs/content/mcp-protocol.mdx +35 -15
- package/corpus/core/docs/content/plan-plugin.mdx +3 -3
- package/corpus/core/docs/content/server.mdx +2 -2
- package/corpus/core/docs/content/skills-guide.mdx +1 -1
- package/corpus/core/docs/content/template-assets.mdx +1 -1
- package/corpus/core/docs/content/template-dispatch.mdx +2 -2
- package/corpus/core/docs/content/template-plan.mdx +3 -3
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +3 -0
- package/corpus/core/src/a2a/handlers.ts +95 -7
- package/corpus/core/src/cli/connect.ts +50 -24
- package/corpus/core/src/cli/mcp-config-writers.ts +10 -0
- package/corpus/core/src/cli/mcp.ts +5 -5
- package/corpus/core/src/cli/skills-content/assets-skill.ts +1 -1
- package/corpus/core/src/cli/skills-content/design-exploration-skill.ts +1 -1
- package/corpus/core/src/cli/skills-content/help.ts +1 -1
- package/corpus/core/src/cli/skills-content/plan-setup-auth.ts +1 -1
- package/corpus/core/src/cli/skills-content/visual-plan-skill.ts +1 -1
- package/corpus/core/src/cli/skills-content/visual-recap-skill.ts +2 -2
- package/corpus/core/src/cli/skills.ts +23 -12
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +5 -0
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +17 -0
- package/corpus/core/src/embedding/agent.ts +8 -6
- package/corpus/core/src/localization/default-messages.ts +7 -0
- package/corpus/core/src/mcp/ask-app-inline-tasks.ts +125 -0
- package/corpus/core/src/mcp/build-server.ts +65 -3
- package/corpus/core/src/mcp/builtin-tools.ts +186 -22
- package/corpus/core/src/mcp/connect-route.ts +17 -14
- package/corpus/core/src/mcp/oauth-route.ts +38 -13
- package/corpus/core/src/mcp/route-paths.ts +34 -0
- package/corpus/core/src/mcp/server.ts +21 -10
- package/corpus/core/src/mcp/stdio.ts +34 -16
- package/corpus/core/src/mcp/workspace-resolve.ts +2 -1
- package/corpus/core/src/mcp-client/manager.ts +5 -3
- package/corpus/core/src/mcp-client/remote-store.ts +10 -10
- package/corpus/core/src/server/agent-chat-plugin.ts +42 -9
- package/corpus/core/src/server/auth.ts +22 -6
- package/corpus/core/src/server/core-routes-plugin.ts +30 -24
- package/corpus/core/src/server/csrf.ts +17 -0
- package/corpus/core/src/server/framework-request-handler.ts +8 -2
- package/corpus/core/src/server/google-oauth.ts +6 -0
- package/corpus/core/src/server/http-response-telemetry.ts +6 -1
- package/corpus/core/src/server/recap-image-route.ts +3 -3
- package/corpus/core/src/server/security-headers.ts +7 -1
- package/corpus/core/src/server/ssr-handler.ts +2 -0
- package/corpus/core/src/shared/cache-control.ts +6 -4
- package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +10 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +15 -6
- package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +16 -10
- package/corpus/core/src/templates/workspace-core/.agents/skills/performance/SKILL.md +20 -1
- package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/analytics/app/global.css +63 -4
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +8 -5
- package/corpus/templates/analytics/changelog/2026-07-13-daily-dashboard-emails-recover-more-reliably-from-serverless.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-13-session-replays-keep-a-visible-mac-style-cursor-over-the-vis.md +6 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +21 -2
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +57 -1
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +266 -28
- package/corpus/templates/analytics/server/routes/[...page].get.ts +0 -2
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/assets/agent-native.app-skill.json +1 -1
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/calendar/AGENTS.md +2 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +0 -19
- package/corpus/templates/calendar/app/lib/attendee-local-time.ts +14 -5
- package/corpus/templates/calendar/changelog/2026-07-13-your-local-time-now-follows-your-browser-timezone-and-event-.md +6 -0
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/clips/.agents/skills/recording/SKILL.md +7 -2
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/clips/AGENTS.md +7 -0
- package/corpus/templates/clips/actions/list-meetings.ts +19 -4
- package/corpus/templates/clips/actions/start-meeting-recording.ts +7 -1
- package/corpus/templates/clips/app/components/meetings/transcript-bubbles.tsx +75 -78
- package/corpus/templates/clips/app/components/recorder/confetti-canvas.tsx +18 -1
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +6 -12
- package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +19 -2
- package/corpus/templates/clips/app/lib/camera-composite.ts +70 -10
- package/corpus/templates/clips/app/routes/_app.meetings.$meetingId.tsx +1 -1
- package/corpus/templates/clips/app/routes/record.tsx +5 -25
- package/corpus/templates/clips/changelog/2026-07-13-clips-desktop-now-requires-macos-13-for-native-capture.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-13-clips-hide-solo-meeting-reminders.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-13-clips-now-removes-duplicate-mic-and-system-transcript-turns-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-13-desktop-recordings-run-cooler-and-quieter-live-transcription.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-13-meeting-recordings-now-stop-after-a-calendar-meeting-ends-an.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-13-meeting-transcripts-now-use-a-clean-agent-chat-style-reading.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-13-screen-recordings-use-less-processing-power-during-longer-ca.md +6 -0
- package/corpus/templates/clips/chrome-extension/src/background.ts +5 -3
- package/corpus/templates/clips/chrome-extension/src/offscreen.ts +17 -14
- package/corpus/templates/clips/chrome-extension/src/overlay.ts +8 -2
- package/corpus/templates/clips/desktop/README.md +3 -0
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +9 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -2
- package/corpus/templates/clips/desktop/src/lib/silence-events.ts +1 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-capture.ts +5 -0
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +134 -5
- package/corpus/templates/clips/desktop/src/lib/upload-video-stream.ts +28 -0
- package/corpus/templates/clips/desktop/src/overlays/flow-bar.tsx +10 -3
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +42 -9
- package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +10 -2
- package/corpus/templates/clips/desktop/src-tauri/Cargo.toml +6 -1
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +77 -1
- package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +104 -25
- package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +4 -0
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +287 -32
- package/corpus/templates/clips/desktop/src-tauri/tauri.conf.json +1 -1
- package/corpus/templates/clips/server/lib/calendar-event-classification.ts +28 -0
- package/corpus/templates/clips/server/routes/[...page].get.ts +1 -59
- package/corpus/templates/clips/shared/recording-capture.ts +37 -0
- package/corpus/templates/content/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/content/agent-native.app-skill.json +1 -1
- package/corpus/templates/content/server/routes/[...page].get.ts +1 -15
- package/corpus/templates/design/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/design/actions/connect-assets-mcp.ts +1 -1
- package/corpus/templates/design/agent-native.app-skill.json +1 -1
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +88 -12
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1 -0
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +4 -1
- package/corpus/templates/design/changelog/2026-07-13-adding-shapes-preserves-canvas-background.md +6 -0
- package/corpus/templates/design/changelog/2026-07-13-clicking-quickly-between-overlapping-elements-no-longer-bounc.md +6 -0
- package/corpus/templates/design/server/plugins/assets-mcp.ts +1 -1
- package/corpus/templates/design/server/routes/[...page].get.ts +0 -2
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/macros/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +10 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +1 -1
- package/corpus/templates/plan/.agents/skills/visual-recap/SKILL.md +2 -2
- package/corpus/templates/plan/agent-native.app-skill.json +1 -1
- package/corpus/templates/plan/app/lib/plan-local-bridge.ts +6 -1
- package/corpus/templates/plan/app/pages/PlansPage.tsx +15 -6
- package/corpus/templates/plan/changelog/2026-07-13-fixed-local-plan-previews-continuously-flickering-while-revi.md +6 -0
- package/corpus/templates/plan/server/routes/[...page].get.ts +0 -2
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +10 -0
- package/dist/a2a/client.d.ts +2 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +2 -0
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +84 -7
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/cli/connect.d.ts +2 -2
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +45 -23
- package/dist/cli/connect.js.map +1 -1
- package/dist/cli/mcp-config-writers.d.ts.map +1 -1
- package/dist/cli/mcp-config-writers.js +7 -0
- package/dist/cli/mcp-config-writers.js.map +1 -1
- package/dist/cli/mcp.js +5 -3
- package/dist/cli/mcp.js.map +1 -1
- package/dist/cli/skills-content/assets-skill.d.ts +1 -1
- package/dist/cli/skills-content/assets-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/assets-skill.js +1 -1
- package/dist/cli/skills-content/assets-skill.js.map +1 -1
- package/dist/cli/skills-content/design-exploration-skill.d.ts +1 -1
- package/dist/cli/skills-content/design-exploration-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/design-exploration-skill.js +1 -1
- package/dist/cli/skills-content/design-exploration-skill.js.map +1 -1
- package/dist/cli/skills-content/help.d.ts +1 -1
- package/dist/cli/skills-content/help.d.ts.map +1 -1
- package/dist/cli/skills-content/help.js +1 -1
- package/dist/cli/skills-content/help.js.map +1 -1
- package/dist/cli/skills-content/plan-setup-auth.d.ts +1 -1
- package/dist/cli/skills-content/plan-setup-auth.d.ts.map +1 -1
- package/dist/cli/skills-content/plan-setup-auth.js +1 -1
- package/dist/cli/skills-content/plan-setup-auth.js.map +1 -1
- package/dist/cli/skills-content/visual-plan-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-plan-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/visual-plan-skill.js +1 -1
- package/dist/cli/skills-content/visual-plan-skill.js.map +1 -1
- package/dist/cli/skills-content/visual-recap-skill.d.ts +1 -1
- package/dist/cli/skills-content/visual-recap-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/visual-recap-skill.js +2 -2
- package/dist/cli/skills-content/visual-recap-skill.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +16 -12
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +1 -1
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- 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 +14 -0
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/embedding/agent.d.ts.map +1 -1
- package/dist/embedding/agent.js +6 -7
- package/dist/embedding/agent.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +5 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +5 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp/ask-app-inline-tasks.d.ts +47 -0
- package/dist/mcp/ask-app-inline-tasks.d.ts.map +1 -0
- package/dist/mcp/ask-app-inline-tasks.js +87 -0
- package/dist/mcp/ask-app-inline-tasks.js.map +1 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +56 -3
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +141 -21
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/mcp/connect-route.d.ts +12 -10
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +17 -14
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/mcp/oauth-route.d.ts +1 -1
- package/dist/mcp/oauth-route.d.ts.map +1 -1
- package/dist/mcp/oauth-route.js +30 -13
- package/dist/mcp/oauth-route.js.map +1 -1
- package/dist/mcp/route-paths.d.ts +13 -0
- package/dist/mcp/route-paths.d.ts.map +1 -0
- package/dist/mcp/route-paths.js +27 -0
- package/dist/mcp/route-paths.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +14 -6
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.d.ts +7 -6
- package/dist/mcp/stdio.d.ts.map +1 -1
- package/dist/mcp/stdio.js +27 -15
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/mcp/workspace-resolve.d.ts +2 -1
- package/dist/mcp/workspace-resolve.d.ts.map +1 -1
- package/dist/mcp/workspace-resolve.js +2 -1
- package/dist/mcp/workspace-resolve.js.map +1 -1
- package/dist/mcp-client/manager.js +6 -3
- package/dist/mcp-client/manager.js.map +1 -1
- package/dist/mcp-client/remote-store.js +5 -7
- package/dist/mcp-client/remote-store.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +5 -5
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +43 -11
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +16 -6
- package/dist/server/auth.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +4 -3
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +20 -15
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/csrf.js +11 -0
- package/dist/server/csrf.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +8 -2
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/google-oauth.d.ts +2 -0
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +5 -0
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/server/http-response-telemetry.d.ts.map +1 -1
- package/dist/server/http-response-telemetry.js +4 -1
- package/dist/server/http-response-telemetry.js.map +1 -1
- package/dist/server/recap-image-route.js +3 -3
- package/dist/server/recap-image-route.js.map +1 -1
- package/dist/server/security-headers.d.ts.map +1 -1
- package/dist/server/security-headers.js +4 -1
- package/dist/server/security-headers.js.map +1 -1
- package/dist/server/ssr-handler.d.ts.map +1 -1
- package/dist/server/ssr-handler.js +3 -1
- package/dist/server/ssr-handler.js.map +1 -1
- package/dist/shared/cache-control.d.ts +7 -6
- package/dist/shared/cache-control.d.ts.map +1 -1
- package/dist/shared/cache-control.js +4 -3
- package/dist/shared/cache-control.js.map +1 -1
- package/dist/templates/default/.agents/skills/security/SKILL.md +10 -0
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +15 -6
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +16 -10
- package/dist/templates/workspace-core/.agents/skills/performance/SKILL.md +20 -1
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +10 -0
- package/docs/content/actions.mdx +1 -1
- package/docs/content/authentication.mdx +1 -1
- package/docs/content/dispatch.mdx +3 -3
- package/docs/content/external-agents.mdx +30 -19
- package/docs/content/locales/ar-SA/actions.mdx +1 -1
- package/docs/content/locales/ar-SA/authentication.mdx +1 -1
- package/docs/content/locales/ar-SA/dispatch.mdx +3 -3
- package/docs/content/locales/ar-SA/external-agents.mdx +23 -19
- package/docs/content/locales/ar-SA/mcp-clients.mdx +31 -3
- package/docs/content/locales/ar-SA/mcp-protocol.mdx +29 -15
- package/docs/content/locales/ar-SA/plan-plugin.mdx +3 -3
- package/docs/content/locales/ar-SA/server.mdx +2 -2
- package/docs/content/locales/ar-SA/skills-guide.mdx +1 -1
- package/docs/content/locales/ar-SA/template-assets.mdx +1 -1
- package/docs/content/locales/ar-SA/template-dispatch.mdx +2 -2
- package/docs/content/locales/ar-SA/template-plan.mdx +3 -3
- package/docs/content/locales/de-DE/actions.mdx +1 -1
- package/docs/content/locales/de-DE/authentication.mdx +1 -1
- package/docs/content/locales/de-DE/dispatch.mdx +3 -3
- package/docs/content/locales/de-DE/external-agents.mdx +23 -19
- package/docs/content/locales/de-DE/mcp-clients.mdx +37 -3
- package/docs/content/locales/de-DE/mcp-protocol.mdx +29 -15
- package/docs/content/locales/de-DE/plan-plugin.mdx +3 -3
- package/docs/content/locales/de-DE/server.mdx +2 -2
- package/docs/content/locales/de-DE/skills-guide.mdx +1 -1
- package/docs/content/locales/de-DE/template-assets.mdx +1 -1
- package/docs/content/locales/de-DE/template-dispatch.mdx +2 -2
- package/docs/content/locales/de-DE/template-plan.mdx +3 -3
- package/docs/content/locales/es-ES/actions.mdx +1 -1
- package/docs/content/locales/es-ES/authentication.mdx +1 -1
- package/docs/content/locales/es-ES/dispatch.mdx +3 -3
- package/docs/content/locales/es-ES/external-agents.mdx +32 -19
- package/docs/content/locales/es-ES/mcp-clients.mdx +17 -3
- package/docs/content/locales/es-ES/mcp-protocol.mdx +38 -15
- package/docs/content/locales/es-ES/plan-plugin.mdx +3 -3
- package/docs/content/locales/es-ES/server.mdx +2 -2
- package/docs/content/locales/es-ES/skills-guide.mdx +1 -1
- package/docs/content/locales/es-ES/template-assets.mdx +1 -1
- package/docs/content/locales/es-ES/template-dispatch.mdx +2 -2
- package/docs/content/locales/es-ES/template-plan.mdx +3 -3
- package/docs/content/locales/fr-FR/actions.mdx +1 -1
- package/docs/content/locales/fr-FR/authentication.mdx +1 -1
- package/docs/content/locales/fr-FR/dispatch.mdx +3 -3
- package/docs/content/locales/fr-FR/external-agents.mdx +23 -19
- package/docs/content/locales/fr-FR/mcp-clients.mdx +17 -3
- package/docs/content/locales/fr-FR/mcp-protocol.mdx +29 -15
- package/docs/content/locales/fr-FR/plan-plugin.mdx +3 -3
- package/docs/content/locales/fr-FR/server.mdx +2 -2
- package/docs/content/locales/fr-FR/skills-guide.mdx +1 -1
- package/docs/content/locales/fr-FR/template-assets.mdx +1 -1
- package/docs/content/locales/fr-FR/template-dispatch.mdx +2 -2
- package/docs/content/locales/fr-FR/template-plan.mdx +3 -3
- package/docs/content/locales/hi-IN/actions.mdx +1 -1
- package/docs/content/locales/hi-IN/authentication.mdx +1 -1
- package/docs/content/locales/hi-IN/dispatch.mdx +3 -3
- package/docs/content/locales/hi-IN/external-agents.mdx +31 -19
- package/docs/content/locales/hi-IN/mcp-clients.mdx +17 -3
- package/docs/content/locales/hi-IN/mcp-protocol.mdx +36 -15
- package/docs/content/locales/hi-IN/plan-plugin.mdx +3 -3
- package/docs/content/locales/hi-IN/server.mdx +2 -2
- package/docs/content/locales/hi-IN/skills-guide.mdx +1 -1
- package/docs/content/locales/hi-IN/template-assets.mdx +1 -1
- package/docs/content/locales/hi-IN/template-dispatch.mdx +2 -2
- package/docs/content/locales/hi-IN/template-plan.mdx +3 -3
- package/docs/content/locales/ja-JP/actions.mdx +1 -1
- package/docs/content/locales/ja-JP/authentication.mdx +1 -1
- package/docs/content/locales/ja-JP/dispatch.mdx +3 -3
- package/docs/content/locales/ja-JP/external-agents.mdx +23 -19
- package/docs/content/locales/ja-JP/mcp-clients.mdx +34 -3
- package/docs/content/locales/ja-JP/mcp-protocol.mdx +29 -15
- package/docs/content/locales/ja-JP/plan-plugin.mdx +3 -3
- package/docs/content/locales/ja-JP/server.mdx +2 -2
- package/docs/content/locales/ja-JP/skills-guide.mdx +1 -1
- package/docs/content/locales/ja-JP/template-assets.mdx +1 -1
- package/docs/content/locales/ja-JP/template-dispatch.mdx +2 -2
- package/docs/content/locales/ja-JP/template-plan.mdx +3 -3
- package/docs/content/locales/ko-KR/actions.mdx +1 -1
- package/docs/content/locales/ko-KR/authentication.mdx +1 -1
- package/docs/content/locales/ko-KR/dispatch.mdx +3 -3
- package/docs/content/locales/ko-KR/external-agents.mdx +30 -19
- package/docs/content/locales/ko-KR/mcp-clients.mdx +33 -3
- package/docs/content/locales/ko-KR/mcp-protocol.mdx +36 -15
- package/docs/content/locales/ko-KR/plan-plugin.mdx +3 -3
- package/docs/content/locales/ko-KR/server.mdx +2 -2
- package/docs/content/locales/ko-KR/skills-guide.mdx +1 -1
- package/docs/content/locales/ko-KR/template-assets.mdx +1 -1
- package/docs/content/locales/ko-KR/template-dispatch.mdx +2 -2
- package/docs/content/locales/ko-KR/template-plan.mdx +3 -3
- package/docs/content/locales/pt-BR/actions.mdx +1 -1
- package/docs/content/locales/pt-BR/authentication.mdx +1 -1
- package/docs/content/locales/pt-BR/dispatch.mdx +3 -3
- package/docs/content/locales/pt-BR/external-agents.mdx +32 -19
- package/docs/content/locales/pt-BR/mcp-clients.mdx +34 -3
- package/docs/content/locales/pt-BR/mcp-protocol.mdx +32 -15
- package/docs/content/locales/pt-BR/plan-plugin.mdx +3 -3
- package/docs/content/locales/pt-BR/server.mdx +2 -2
- package/docs/content/locales/pt-BR/skills-guide.mdx +1 -1
- package/docs/content/locales/pt-BR/template-assets.mdx +1 -1
- package/docs/content/locales/pt-BR/template-dispatch.mdx +2 -2
- package/docs/content/locales/pt-BR/template-plan.mdx +3 -3
- package/docs/content/locales/zh-CN/actions.mdx +1 -1
- package/docs/content/locales/zh-CN/authentication.mdx +1 -1
- package/docs/content/locales/zh-CN/dispatch.mdx +3 -3
- package/docs/content/locales/zh-CN/external-agents.mdx +23 -19
- package/docs/content/locales/zh-CN/mcp-clients.mdx +28 -3
- package/docs/content/locales/zh-CN/mcp-protocol.mdx +29 -15
- package/docs/content/locales/zh-CN/plan-plugin.mdx +3 -3
- package/docs/content/locales/zh-CN/server.mdx +2 -2
- package/docs/content/locales/zh-CN/skills-guide.mdx +1 -1
- package/docs/content/locales/zh-CN/template-assets.mdx +1 -1
- package/docs/content/locales/zh-CN/template-dispatch.mdx +2 -2
- package/docs/content/locales/zh-CN/template-plan.mdx +3 -3
- package/docs/content/locales/zh-TW/actions.mdx +1 -1
- package/docs/content/locales/zh-TW/authentication.mdx +1 -1
- package/docs/content/locales/zh-TW/dispatch.mdx +3 -3
- package/docs/content/locales/zh-TW/external-agents.mdx +23 -19
- package/docs/content/locales/zh-TW/mcp-clients.mdx +28 -3
- package/docs/content/locales/zh-TW/mcp-protocol.mdx +30 -15
- package/docs/content/locales/zh-TW/plan-plugin.mdx +3 -3
- package/docs/content/locales/zh-TW/server.mdx +2 -2
- package/docs/content/locales/zh-TW/skills-guide.mdx +1 -1
- package/docs/content/locales/zh-TW/template-assets.mdx +1 -1
- package/docs/content/locales/zh-TW/template-dispatch.mdx +2 -2
- package/docs/content/locales/zh-TW/template-plan.mdx +3 -3
- package/docs/content/mcp-clients.mdx +31 -4
- package/docs/content/mcp-protocol.mdx +35 -15
- package/docs/content/plan-plugin.mdx +3 -3
- package/docs/content/server.mdx +2 -2
- package/docs/content/skills-guide.mdx +1 -1
- package/docs/content/template-assets.mdx +1 -1
- package/docs/content/template-dispatch.mdx +2 -2
- package/docs/content/template-plan.mdx +3 -3
- package/package.json +1 -1
- package/src/templates/default/.agents/skills/security/SKILL.md +10 -0
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +15 -6
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +16 -10
- package/src/templates/workspace-core/.agents/skills/performance/SKILL.md +20 -1
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +10 -0
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Resolution priority for an attendee's IANA timezone:
|
|
5
5
|
* 1. Self attendee (`attendee.self` or email matches accountEmail) →
|
|
6
|
-
*
|
|
6
|
+
* the browser timezone, so an event owner's timezone is never shown as
|
|
7
|
+
* the signed-in user's local time
|
|
7
8
|
* 2. Optional `attendee.timeZone` on the attendee object
|
|
8
9
|
* 3. User-stored override from the `attendee-timezones` setting map
|
|
10
|
+
* 4. The event start timezone for the organizer when no more specific zone is
|
|
11
|
+
* available
|
|
9
12
|
*
|
|
10
13
|
* When no timezone is known, returns null — never invent a zone.
|
|
11
14
|
*/
|
|
@@ -13,6 +16,7 @@
|
|
|
13
16
|
export type AttendeeTimezoneSource = {
|
|
14
17
|
email: string;
|
|
15
18
|
self?: boolean;
|
|
19
|
+
organizer?: boolean;
|
|
16
20
|
timeZone?: string;
|
|
17
21
|
};
|
|
18
22
|
|
|
@@ -61,15 +65,16 @@ export function resolveAttendeeTimeZone(
|
|
|
61
65
|
} = input;
|
|
62
66
|
|
|
63
67
|
if (isSelfAttendee(attendee, accountEmail)) {
|
|
64
|
-
if (isValidIanaTimeZone(eventStartTimeZone)) {
|
|
65
|
-
return eventStartTimeZone!.trim();
|
|
66
|
-
}
|
|
67
68
|
const browser =
|
|
68
69
|
browserTimeZone?.trim() ||
|
|
69
70
|
(typeof Intl !== "undefined"
|
|
70
71
|
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
71
72
|
: undefined);
|
|
72
|
-
|
|
73
|
+
if (isValidIanaTimeZone(browser)) return browser!.trim();
|
|
74
|
+
|
|
75
|
+
return isValidIanaTimeZone(eventStartTimeZone)
|
|
76
|
+
? eventStartTimeZone!.trim()
|
|
77
|
+
: null;
|
|
73
78
|
}
|
|
74
79
|
|
|
75
80
|
if (isValidIanaTimeZone(attendee.timeZone)) {
|
|
@@ -82,6 +87,10 @@ export function resolveAttendeeTimeZone(
|
|
|
82
87
|
return override!.trim();
|
|
83
88
|
}
|
|
84
89
|
|
|
90
|
+
if (attendee.organizer && isValidIanaTimeZone(eventStartTimeZone)) {
|
|
91
|
+
return eventStartTimeZone!.trim();
|
|
92
|
+
}
|
|
93
|
+
|
|
85
94
|
return null;
|
|
86
95
|
}
|
|
87
96
|
|
|
@@ -147,6 +147,16 @@ export default defineEventHandler(async (event) => {
|
|
|
147
147
|
|
|
148
148
|
- Never create unprotected routes that modify data.
|
|
149
149
|
|
|
150
|
+
**Exception — the SSR HTML/`.data` catch-all is deliberately session-blind.**
|
|
151
|
+
The rule above is for routes that read or mutate user data. The SSR page
|
|
152
|
+
render and React Router `.data` route are different: they serve one
|
|
153
|
+
impersonal, public-cacheable shell to every visitor by design, and loaders on
|
|
154
|
+
that path render no user data. Do not "fix" this by adding `getSession`,
|
|
155
|
+
`private`, or `no-store` to it — that regresses the CDN cache contract for the
|
|
156
|
+
whole site. Data scoping lives in actions and API routes; the client gates
|
|
157
|
+
private UI after the shell loads. See the `authentication` skill and
|
|
158
|
+
`guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
|
|
159
|
+
|
|
150
160
|
## Human-in-the-Loop Approval for High-Consequence Actions
|
|
151
161
|
|
|
152
162
|
For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
|
|
@@ -44,7 +44,7 @@ Raw `MediaRecorder` files are not friendly to progressive HTTP playback, which
|
|
|
44
44
|
shows up as "clip takes minutes to load" and "re-buffers every time I seek"
|
|
45
45
|
even though the file downloads fine:
|
|
46
46
|
|
|
47
|
-
- **MP4** is written with the `moov` metadata atom
|
|
47
|
+
- **MP4** is written with the `moov` metadata atom _after_ `mdat`, so a player
|
|
48
48
|
must fetch the whole file before it can start or seek.
|
|
49
49
|
- **WebM** is a live stream with no Cues (seek index) and an unknown Segment
|
|
50
50
|
duration, so Chrome won't honor `currentTime = X` and has to scan/download.
|
|
@@ -116,7 +116,12 @@ different listing.
|
|
|
116
116
|
|
|
117
117
|
## Camera bubble
|
|
118
118
|
|
|
119
|
-
When mode is `screen+camera`,
|
|
119
|
+
When mode is `screen+camera`, "the bubble" is two different things:
|
|
120
|
+
|
|
121
|
+
- **On-screen self-view.** `CameraBubble` renders a plain, unrecorded `<video>` element the user drags around to frame themselves during countdown/recording. It is never captured — it's just local framing UI.
|
|
122
|
+
- **Recorded composite.** Display capture can't include that DOM element once the user records another window/app, so the saved video has to bake the camera circle in before `MediaRecorder` ever sees a frame. `createCameraCompositeStream` (`app/lib/camera-composite.ts`) draws the display video plus a clipped, mirrored camera circle onto an offscreen `<canvas>` and feeds `canvas.captureStream()` into a single `MediaRecorder`. There is **no** second `MediaRecorder` and **no** server-side ffmpeg stitching — the composite happens client-side, live, before upload.
|
|
123
|
+
|
|
124
|
+
Because that draw loop runs continuously for the whole recording, keep its CPU/GPU cost bounded: a Worker-based timer drives the draw loop at the capture frame rate (`SCREEN_CAPTURE_FRAME_RATE`, 24fps — falling back to `requestAnimationFrame` only if Worker creation fails, e.g. under a strict CSP), the canvas is hard-capped to 1080p-class dimensions (1920px on its longest edge) even if the source display track is Retina/4K, and the bubble's drop shadow is pre-rendered into a small cached sprite (keyed by bubble size) instead of re-blurring with `shadowBlur` every frame.
|
|
120
125
|
|
|
121
126
|
## Error recovery
|
|
122
127
|
|
|
@@ -147,6 +147,16 @@ export default defineEventHandler(async (event) => {
|
|
|
147
147
|
|
|
148
148
|
- Never create unprotected routes that modify data.
|
|
149
149
|
|
|
150
|
+
**Exception — the SSR HTML/`.data` catch-all is deliberately session-blind.**
|
|
151
|
+
The rule above is for routes that read or mutate user data. The SSR page
|
|
152
|
+
render and React Router `.data` route are different: they serve one
|
|
153
|
+
impersonal, public-cacheable shell to every visitor by design, and loaders on
|
|
154
|
+
that path render no user data. Do not "fix" this by adding `getSession`,
|
|
155
|
+
`private`, or `no-store` to it — that regresses the CDN cache contract for the
|
|
156
|
+
whole site. Data scoping lives in actions and API routes; the client gates
|
|
157
|
+
private UI after the shell loads. See the `authentication` skill and
|
|
158
|
+
`guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
|
|
159
|
+
|
|
150
160
|
## Human-in-the-Loop Approval for High-Consequence Actions
|
|
151
161
|
|
|
152
162
|
For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
|
|
@@ -36,6 +36,9 @@ Detailed media, meeting, dictation, editing, and sharing rules live in
|
|
|
36
36
|
generation run in the durable post-finalize path; do not hide a usable native
|
|
37
37
|
transcript behind failed metadata work, and keep heuristic titles replaceable
|
|
38
38
|
until the agent refinement lands.
|
|
39
|
+
- Desktop native transcripts merge microphone and system-audio streams while
|
|
40
|
+
removing overlapping duplicate speech and low-speech Whisper hallucinations;
|
|
41
|
+
keep system audio enabled when the meeting audio comes from another app.
|
|
39
42
|
- Use `request-transcript --recordingId=<id> --force=true` to retry a failed
|
|
40
43
|
transcript. Pass `--regenerate=true` to replace an existing ready transcript
|
|
41
44
|
from the stored recording media; if regeneration fails, keep the prior ready
|
|
@@ -95,6 +98,10 @@ Detailed media, meeting, dictation, editing, and sharing rules live in
|
|
|
95
98
|
(`connect-slack`, `/api/slack/oauth/callback`) so each Slack workspace gets
|
|
96
99
|
its own encrypted bot token in `app_secrets`. `SLACK_BOT_TOKEN` is only a
|
|
97
100
|
legacy single-workspace fallback and must remain behind the team allowlist.
|
|
101
|
+
- Atlassian/Jira is available through the shared MCP integration catalog. It
|
|
102
|
+
uses Atlassian Rovo MCP OAuth; explain that an Atlassian organization admin
|
|
103
|
+
may need to allow the Clips app domain and enable the required Read, Write,
|
|
104
|
+
and Search permissions before the connection can complete.
|
|
98
105
|
- Browser recordings can include redacted browser diagnostics captured during
|
|
99
106
|
the recording session. `save-browser-diagnostics` is UI/internal and stores
|
|
100
107
|
bounded console logs plus fetch/XHR method, URL path/query keys, status, and
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { defineAction } from "@agent-native/core";
|
|
17
|
+
import { getRequestUserEmail } from "@agent-native/core/server/request-context";
|
|
17
18
|
import { accessFilter } from "@agent-native/core/sharing";
|
|
18
19
|
import {
|
|
19
20
|
and,
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
import { z } from "zod";
|
|
32
33
|
|
|
33
34
|
import { getDb, schema } from "../server/db/index.js";
|
|
34
|
-
import {
|
|
35
|
+
import { isSoloCalendarEvent } from "../server/lib/calendar-event-classification.js";
|
|
35
36
|
import {
|
|
36
37
|
calendarEventToMeetingView,
|
|
37
38
|
eventEndIso,
|
|
@@ -86,12 +87,13 @@ export default defineAction({
|
|
|
86
87
|
excludePersonalSoloEvents: booleanParam
|
|
87
88
|
.default(false)
|
|
88
89
|
.describe(
|
|
89
|
-
"Exclude
|
|
90
|
+
"Exclude calendar events with no active attendee besides the current user. Used by desktop meeting reminders.",
|
|
90
91
|
),
|
|
91
92
|
}),
|
|
92
93
|
http: { method: "GET" },
|
|
93
94
|
run: async (args) => {
|
|
94
95
|
const db = getDb();
|
|
96
|
+
const currentUserEmail = getRequestUserEmail();
|
|
95
97
|
const now = new Date();
|
|
96
98
|
const nowIso = now.toISOString();
|
|
97
99
|
|
|
@@ -188,6 +190,11 @@ export default defineAction({
|
|
|
188
190
|
// event was emitted here — not merely because some other account returned
|
|
189
191
|
// data or errored.
|
|
190
192
|
const emittedLiveEventKeys = new Set<string>();
|
|
193
|
+
// Calendar events excluded from desktop reminders because they have no
|
|
194
|
+
// active attendee besides the current user. Keep the correlated
|
|
195
|
+
// persisted meeting ids here too, so materialized solo events cannot
|
|
196
|
+
// re-enter the reminder list through the fallback persisted-row merge.
|
|
197
|
+
const excludedLiveEventKeys = new Set<string>();
|
|
191
198
|
// Map a persisted meeting's `calendarEventId` (calendar_events.id) to the
|
|
192
199
|
// Google event externalId so we can match it against the emitted set.
|
|
193
200
|
const calendarEventIdToExternalId = new Map<string, string>();
|
|
@@ -269,10 +276,15 @@ export default defineAction({
|
|
|
269
276
|
for (const event of items) {
|
|
270
277
|
if (!event.id || event.status === "cancelled") continue;
|
|
271
278
|
if (!isTimedCalendarEvent(event)) continue;
|
|
279
|
+
const cached = cachedByExternalId.get(event.id);
|
|
272
280
|
if (
|
|
273
281
|
args.excludePersonalSoloEvents &&
|
|
274
|
-
|
|
282
|
+
isSoloCalendarEvent({ account, event, currentUserEmail })
|
|
275
283
|
) {
|
|
284
|
+
excludedLiveEventKeys.add(event.id);
|
|
285
|
+
if (cached?.meetingId) {
|
|
286
|
+
excludedLiveEventKeys.add(cached.meetingId);
|
|
287
|
+
}
|
|
276
288
|
continue;
|
|
277
289
|
}
|
|
278
290
|
const startIso = eventStartIso(event);
|
|
@@ -301,7 +313,6 @@ export default defineAction({
|
|
|
301
313
|
continue;
|
|
302
314
|
}
|
|
303
315
|
|
|
304
|
-
const cached = cachedByExternalId.get(event.id);
|
|
305
316
|
const persisted = cached?.meetingId
|
|
306
317
|
? persistedById.get(cached.meetingId)
|
|
307
318
|
: null;
|
|
@@ -344,6 +355,10 @@ export default defineAction({
|
|
|
344
355
|
const liveExternalId = meeting.calendarEventId
|
|
345
356
|
? calendarEventIdToExternalId.get(meeting.calendarEventId)
|
|
346
357
|
: undefined;
|
|
358
|
+
const liveEventExcluded =
|
|
359
|
+
excludedLiveEventKeys.has(meeting.id) ||
|
|
360
|
+
(liveExternalId ? excludedLiveEventKeys.has(liveExternalId) : false);
|
|
361
|
+
if (liveEventExcluded) continue;
|
|
347
362
|
const liveEventEmitted =
|
|
348
363
|
emittedLiveEventKeys.has(meeting.id) ||
|
|
349
364
|
(liveExternalId ? emittedLiveEventKeys.has(liveExternalId) : false);
|
|
@@ -71,6 +71,7 @@ export default defineAction({
|
|
|
71
71
|
recording: existing,
|
|
72
72
|
meetingId,
|
|
73
73
|
created: false,
|
|
74
|
+
scheduledEnd: meeting.scheduledEnd,
|
|
74
75
|
};
|
|
75
76
|
}
|
|
76
77
|
}
|
|
@@ -117,6 +118,11 @@ export default defineAction({
|
|
|
117
118
|
.where(eq(schema.recordings.id, recordingId))
|
|
118
119
|
.limit(1);
|
|
119
120
|
|
|
120
|
-
return {
|
|
121
|
+
return {
|
|
122
|
+
recording,
|
|
123
|
+
meetingId,
|
|
124
|
+
created: true,
|
|
125
|
+
scheduledEnd: meeting.scheduledEnd,
|
|
126
|
+
};
|
|
121
127
|
},
|
|
122
128
|
});
|
|
@@ -310,92 +310,89 @@ export function TranscriptBubbles({
|
|
|
310
310
|
)}
|
|
311
311
|
</div>
|
|
312
312
|
<div ref={containerRef} className="flex-1 overflow-y-auto p-4">
|
|
313
|
-
<div className="space-y-
|
|
313
|
+
<div className="mx-auto max-w-3xl space-y-6">
|
|
314
314
|
{groups.map((group, gi) => {
|
|
315
315
|
const isMe = group.source === "mic";
|
|
316
316
|
return (
|
|
317
|
-
<
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
"text-[10px] font-medium uppercase tracking-wide text-muted-foreground/70 px-1",
|
|
327
|
-
)}
|
|
328
|
-
>
|
|
317
|
+
<section key={gi} className="space-y-1.5">
|
|
318
|
+
<div className="flex items-center gap-2 px-1 text-[11px] font-medium tracking-wide text-muted-foreground">
|
|
319
|
+
<span
|
|
320
|
+
aria-hidden="true"
|
|
321
|
+
className={cn(
|
|
322
|
+
"h-1.5 w-1.5 rounded-full",
|
|
323
|
+
isMe ? "bg-primary" : "bg-muted-foreground/50",
|
|
324
|
+
)}
|
|
325
|
+
/>
|
|
329
326
|
{isMe
|
|
330
327
|
? t("transcriptBubbles.me")
|
|
331
328
|
: t("transcriptBubbles.them")}
|
|
332
329
|
</div>
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
<
|
|
338
|
-
<
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
330
|
+
<div className="space-y-0.5">
|
|
331
|
+
{group.segments.map(({ seg, index }) => {
|
|
332
|
+
const clickable = !!recordingId;
|
|
333
|
+
return (
|
|
334
|
+
<Tooltip key={index}>
|
|
335
|
+
<TooltipTrigger asChild>
|
|
336
|
+
<div
|
|
337
|
+
ref={(el) => {
|
|
338
|
+
segmentRefs.current[index] = el;
|
|
339
|
+
}}
|
|
340
|
+
role={clickable ? "button" : undefined}
|
|
341
|
+
tabIndex={clickable ? 0 : -1}
|
|
342
|
+
onClick={() => clickable && onSeek(seg.startMs)}
|
|
343
|
+
onKeyDown={(e) => {
|
|
344
|
+
if (
|
|
345
|
+
clickable &&
|
|
346
|
+
(e.key === "Enter" || e.key === " ")
|
|
347
|
+
) {
|
|
348
|
+
e.preventDefault();
|
|
349
|
+
onSeek(seg.startMs);
|
|
350
|
+
}
|
|
351
|
+
}}
|
|
352
|
+
className={cn(
|
|
353
|
+
"group/segment -mx-1 rounded-md px-1 py-1 text-left text-sm leading-relaxed text-foreground transition-colors",
|
|
347
354
|
clickable &&
|
|
348
|
-
|
|
349
|
-
)
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
</TooltipTrigger>
|
|
390
|
-
<TooltipContent side={isMe ? "left" : "right"}>
|
|
391
|
-
<span className="font-mono tabular-nums text-[11px]">
|
|
392
|
-
{formatTimestamp(seg.startMs)}
|
|
393
|
-
</span>
|
|
394
|
-
</TooltipContent>
|
|
395
|
-
</Tooltip>
|
|
396
|
-
);
|
|
397
|
-
})}
|
|
398
|
-
</div>
|
|
355
|
+
"cursor-pointer hover:bg-accent/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
356
|
+
)}
|
|
357
|
+
>
|
|
358
|
+
{seg.speaker && !isMe && (
|
|
359
|
+
<span className="me-2 text-[11px] font-medium text-muted-foreground">
|
|
360
|
+
{seg.speaker}
|
|
361
|
+
</span>
|
|
362
|
+
)}
|
|
363
|
+
<span className="whitespace-pre-wrap">
|
|
364
|
+
{normalizedQuery
|
|
365
|
+
? highlightRuns(seg.text, normalizedQuery).map(
|
|
366
|
+
(run, ri) =>
|
|
367
|
+
run.match ? (
|
|
368
|
+
<mark
|
|
369
|
+
key={ri}
|
|
370
|
+
className={cn(
|
|
371
|
+
"rounded-sm bg-yellow-400/70 text-foreground",
|
|
372
|
+
index === activeMatchIndex &&
|
|
373
|
+
"bg-yellow-400 ring-1 ring-yellow-600",
|
|
374
|
+
)}
|
|
375
|
+
>
|
|
376
|
+
{run.text}
|
|
377
|
+
</mark>
|
|
378
|
+
) : (
|
|
379
|
+
<span key={ri}>{run.text}</span>
|
|
380
|
+
),
|
|
381
|
+
)
|
|
382
|
+
: seg.text}
|
|
383
|
+
</span>
|
|
384
|
+
</div>
|
|
385
|
+
</TooltipTrigger>
|
|
386
|
+
<TooltipContent side="right">
|
|
387
|
+
<span className="font-mono tabular-nums text-[11px]">
|
|
388
|
+
{formatTimestamp(seg.startMs)}
|
|
389
|
+
</span>
|
|
390
|
+
</TooltipContent>
|
|
391
|
+
</Tooltip>
|
|
392
|
+
);
|
|
393
|
+
})}
|
|
394
|
+
</div>
|
|
395
|
+
</section>
|
|
399
396
|
);
|
|
400
397
|
})}
|
|
401
398
|
<div ref={liveEndRef} />
|
|
@@ -34,6 +34,7 @@ export const ConfettiCanvas = forwardRef<ConfettiHandle>(
|
|
|
34
34
|
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
35
35
|
const particlesRef = useRef<Particle[]>([]);
|
|
36
36
|
const rafRef = useRef<number | null>(null);
|
|
37
|
+
const startTickRef = useRef<() => void>(() => {});
|
|
37
38
|
|
|
38
39
|
useEffect(() => {
|
|
39
40
|
const canvas = canvasRef.current;
|
|
@@ -93,9 +94,24 @@ export const ConfettiCanvas = forwardRef<ConfettiHandle>(
|
|
|
93
94
|
live.push(p);
|
|
94
95
|
}
|
|
95
96
|
particlesRef.current = live;
|
|
97
|
+
|
|
98
|
+
// Stop instead of redrawing an empty canvas at full refresh rate for
|
|
99
|
+
// the rest of the page's lifetime — burst() restarts the loop.
|
|
100
|
+
if (live.length === 0) {
|
|
101
|
+
rafRef.current = null;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
96
104
|
rafRef.current = window.requestAnimationFrame(tick);
|
|
97
105
|
}
|
|
98
|
-
|
|
106
|
+
|
|
107
|
+
startTickRef.current = () => {
|
|
108
|
+
if (rafRef.current !== null) return;
|
|
109
|
+
// Reset the dt baseline so the first frame after a restart doesn't
|
|
110
|
+
// see a huge elapsed gap from the idle period.
|
|
111
|
+
lastTs = performance.now();
|
|
112
|
+
rafRef.current = window.requestAnimationFrame(tick);
|
|
113
|
+
};
|
|
114
|
+
|
|
99
115
|
return () => {
|
|
100
116
|
if (rafRef.current !== null)
|
|
101
117
|
window.cancelAnimationFrame(rafRef.current);
|
|
@@ -129,6 +145,7 @@ export const ConfettiCanvas = forwardRef<ConfettiHandle>(
|
|
|
129
145
|
life: 1.6 + Math.random() * 0.6,
|
|
130
146
|
});
|
|
131
147
|
}
|
|
148
|
+
startTickRef.current();
|
|
132
149
|
},
|
|
133
150
|
}));
|
|
134
151
|
|
|
@@ -18,6 +18,10 @@ import {
|
|
|
18
18
|
isLikelyPhoneMicLabel,
|
|
19
19
|
type AudioInputFallback,
|
|
20
20
|
} from "@shared/media-device-selection";
|
|
21
|
+
import {
|
|
22
|
+
SCREEN_CAPTURE_FRAME_RATE,
|
|
23
|
+
screenCaptureVideoConstraints,
|
|
24
|
+
} from "@shared/recording-capture";
|
|
21
25
|
import {
|
|
22
26
|
chunkUploadUrl,
|
|
23
27
|
pickMimeType,
|
|
@@ -234,9 +238,6 @@ const FINAL_CHUNK_UPLOAD_TIMEOUT_MS = 180_000;
|
|
|
234
238
|
const RETRYABLE_CHUNK_UPLOAD_STATUSES = new Set([
|
|
235
239
|
408, 425, 429, 500, 502, 503, 504,
|
|
236
240
|
]);
|
|
237
|
-
const SCREEN_CAPTURE_FRAME_RATE = 24;
|
|
238
|
-
const SCREEN_CAPTURE_MAX_WIDTH = 1920;
|
|
239
|
-
const SCREEN_CAPTURE_MAX_HEIGHT = 1080;
|
|
240
241
|
// Capture quality for the browser MediaRecorder. We no longer shrink files
|
|
241
242
|
// client-side (ffmpeg.wasm re-encode is disabled — see COMPRESSION_ENABLED in
|
|
242
243
|
// `@/lib/compress`) and the upload provider streams large files directly, so we
|
|
@@ -907,15 +908,7 @@ export class RecorderEngine {
|
|
|
907
908
|
this.opts.displaySurface ?? "window",
|
|
908
909
|
);
|
|
909
910
|
const displayOptions: ExtendedDisplayMediaOptions = {
|
|
910
|
-
video:
|
|
911
|
-
frameRate: {
|
|
912
|
-
ideal: SCREEN_CAPTURE_FRAME_RATE,
|
|
913
|
-
max: SCREEN_CAPTURE_FRAME_RATE,
|
|
914
|
-
},
|
|
915
|
-
width: { ideal: SCREEN_CAPTURE_MAX_WIDTH },
|
|
916
|
-
height: { ideal: SCREEN_CAPTURE_MAX_HEIGHT },
|
|
917
|
-
displaySurface,
|
|
918
|
-
},
|
|
911
|
+
video: screenCaptureVideoConstraints(displaySurface),
|
|
919
912
|
audio: wantsMic,
|
|
920
913
|
// Let "Browser tab" open the tab picker. preferCurrentTab turns it
|
|
921
914
|
// into a current-tab shortcut, which makes choosing another tab harder.
|
|
@@ -1834,6 +1827,7 @@ export class RecorderEngine {
|
|
|
1834
1827
|
displayStream: this.displayStream!,
|
|
1835
1828
|
cameraStream: this.cameraStream!,
|
|
1836
1829
|
bubbleSizeRatio: this.cameraBubbleSizeRatio(),
|
|
1830
|
+
frameRate: SCREEN_CAPTURE_FRAME_RATE,
|
|
1837
1831
|
});
|
|
1838
1832
|
const combined = new MediaStream();
|
|
1839
1833
|
for (const t of this.cameraComposite.stream.getVideoTracks())
|
|
@@ -16,7 +16,11 @@ import {
|
|
|
16
16
|
import { clampRectToViewport, type BubblePosition } from "./camera-positioner";
|
|
17
17
|
|
|
18
18
|
export interface RecordingToolbarProps {
|
|
19
|
-
|
|
19
|
+
/** Whether the elapsed-time ticker should run — true only while actively
|
|
20
|
+
* recording (not during upload/compress, which freeze the last value). */
|
|
21
|
+
active: boolean;
|
|
22
|
+
/** Reads the current elapsed time from the recorder engine on each tick. */
|
|
23
|
+
getElapsedMs: () => number;
|
|
20
24
|
isPaused: boolean;
|
|
21
25
|
onTogglePause: () => void;
|
|
22
26
|
onStop: () => void;
|
|
@@ -38,7 +42,8 @@ function formatElapsed(ms: number): string {
|
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
export function RecordingToolbar({
|
|
41
|
-
|
|
45
|
+
active,
|
|
46
|
+
getElapsedMs,
|
|
42
47
|
isPaused,
|
|
43
48
|
onTogglePause,
|
|
44
49
|
onStop,
|
|
@@ -46,6 +51,18 @@ export function RecordingToolbar({
|
|
|
46
51
|
}: RecordingToolbarProps) {
|
|
47
52
|
const t = useT();
|
|
48
53
|
const rootRef = useRef<HTMLDivElement>(null);
|
|
54
|
+
// Own the elapsed-time poll here instead of in the route component, so the
|
|
55
|
+
// 4x/sec tick only re-renders this toolbar rather than the whole record page.
|
|
56
|
+
const [elapsedMs, setElapsedMs] = useState(0);
|
|
57
|
+
const getElapsedMsRef = useRef(getElapsedMs);
|
|
58
|
+
getElapsedMsRef.current = getElapsedMs;
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (!active) return;
|
|
61
|
+
const id = window.setInterval(() => {
|
|
62
|
+
setElapsedMs(getElapsedMsRef.current());
|
|
63
|
+
}, 250);
|
|
64
|
+
return () => window.clearInterval(id);
|
|
65
|
+
}, [active]);
|
|
49
66
|
const [pos, setPos] = useState<BubblePosition>(() =>
|
|
50
67
|
typeof window === "undefined"
|
|
51
68
|
? { left: 16, top: 16, corner: "tl" }
|
|
@@ -128,16 +128,79 @@ function drawCover(
|
|
|
128
128
|
ctx.restore();
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// Hard ceiling on the composite canvas regardless of source resolution — keeps
|
|
132
|
+
// the per-frame drawImage + encode at 1080p-class cost even on a Retina/4K
|
|
133
|
+
// display or if a browser ignores getDisplayMedia's `max` constraint.
|
|
134
|
+
const MAX_CANVAS_DIMENSION_PX = 1920;
|
|
135
|
+
|
|
136
|
+
export function clampToMaxDimension(
|
|
137
|
+
width: number,
|
|
138
|
+
height: number,
|
|
139
|
+
): { width: number; height: number } {
|
|
140
|
+
const longest = Math.max(width, height);
|
|
141
|
+
if (longest <= MAX_CANVAS_DIMENSION_PX) {
|
|
142
|
+
return { width, height };
|
|
143
|
+
}
|
|
144
|
+
const scale = MAX_CANVAS_DIMENSION_PX / longest;
|
|
145
|
+
// Round to even numbers — odd canvas dimensions can trip up video encoders.
|
|
146
|
+
return {
|
|
147
|
+
width: Math.round((width * scale) / 2) * 2,
|
|
148
|
+
height: Math.round((height * scale) / 2) * 2,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
|
|
131
152
|
function resizeCanvasToDisplay(
|
|
132
153
|
canvas: HTMLCanvasElement,
|
|
133
154
|
displayVideo: HTMLVideoElement,
|
|
134
155
|
displayStream: MediaStream,
|
|
135
156
|
): void {
|
|
136
|
-
const
|
|
157
|
+
const source = videoDimensions(displayVideo, displayStream);
|
|
158
|
+
const { width, height } = clampToMaxDimension(source.width, source.height);
|
|
137
159
|
if (canvas.width !== width) canvas.width = width;
|
|
138
160
|
if (canvas.height !== height) canvas.height = height;
|
|
139
161
|
}
|
|
140
162
|
|
|
163
|
+
interface BubbleShadowSprite {
|
|
164
|
+
size: number;
|
|
165
|
+
canvas: HTMLCanvasElement;
|
|
166
|
+
pad: number;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// The drop shadow is a per-frame gaussian blur, which is expensive to redraw
|
|
170
|
+
// every frame. Cache the rendered shadow in an offscreen sprite keyed by
|
|
171
|
+
// bubble size — margin only shifts where the sprite is later placed, not its
|
|
172
|
+
// bitmap — and only re-render when the size actually changes.
|
|
173
|
+
let bubbleShadowSprite: BubbleShadowSprite | null = null;
|
|
174
|
+
|
|
175
|
+
function getBubbleShadowSprite(size: number): BubbleShadowSprite {
|
|
176
|
+
if (bubbleShadowSprite && bubbleShadowSprite.size === size) {
|
|
177
|
+
return bubbleShadowSprite;
|
|
178
|
+
}
|
|
179
|
+
const blur = Math.max(16, size * 0.12);
|
|
180
|
+
const offsetY = Math.max(8, size * 0.05);
|
|
181
|
+
// Padding wide enough that the blurred, offset shadow never clips at the
|
|
182
|
+
// sprite's edge.
|
|
183
|
+
const pad = Math.ceil(blur * 2 + offsetY);
|
|
184
|
+
const spriteSize = size + pad * 2;
|
|
185
|
+
const sprite = document.createElement("canvas");
|
|
186
|
+
sprite.width = spriteSize;
|
|
187
|
+
sprite.height = spriteSize;
|
|
188
|
+
const sctx = sprite.getContext("2d");
|
|
189
|
+
if (sctx) {
|
|
190
|
+
const radius = size / 2;
|
|
191
|
+
const center = pad + radius;
|
|
192
|
+
sctx.shadowColor = "rgba(0, 0, 0, 0.35)";
|
|
193
|
+
sctx.shadowBlur = blur;
|
|
194
|
+
sctx.shadowOffsetY = offsetY;
|
|
195
|
+
sctx.fillStyle = "#000";
|
|
196
|
+
sctx.beginPath();
|
|
197
|
+
sctx.arc(center, center, radius, 0, Math.PI * 2);
|
|
198
|
+
sctx.fill();
|
|
199
|
+
}
|
|
200
|
+
bubbleShadowSprite = { size, canvas: sprite, pad };
|
|
201
|
+
return bubbleShadowSprite;
|
|
202
|
+
}
|
|
203
|
+
|
|
141
204
|
function drawCameraBubble(
|
|
142
205
|
ctx: CanvasRenderingContext2D,
|
|
143
206
|
cameraVideo: HTMLVideoElement,
|
|
@@ -172,15 +235,12 @@ function drawCameraBubble(
|
|
|
172
235
|
const centerX = x + radius;
|
|
173
236
|
const centerY = y + radius;
|
|
174
237
|
|
|
175
|
-
|
|
176
|
-
ctx.
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
|
|
182
|
-
ctx.fill();
|
|
183
|
-
ctx.restore();
|
|
238
|
+
const shadow = getBubbleShadowSprite(size);
|
|
239
|
+
ctx.drawImage(
|
|
240
|
+
shadow.canvas,
|
|
241
|
+
centerX - shadow.pad - radius,
|
|
242
|
+
centerY - shadow.pad - radius,
|
|
243
|
+
);
|
|
184
244
|
|
|
185
245
|
ctx.save();
|
|
186
246
|
ctx.beginPath();
|
|
@@ -912,7 +912,7 @@ export default function MeetingDetailRoute() {
|
|
|
912
912
|
</div>
|
|
913
913
|
</div>
|
|
914
914
|
|
|
915
|
-
{/* Transcript pane — chat-
|
|
915
|
+
{/* Transcript pane — plain agent-chat-style text layout */}
|
|
916
916
|
<div className="rounded-lg border border-border bg-background min-h-[480px] lg:min-h-0 overflow-hidden flex flex-col">
|
|
917
917
|
<div className="flex shrink-0 items-center justify-between gap-2 border-b border-border px-4 py-2.5 bg-background">
|
|
918
918
|
<div className="flex items-center gap-1.5 text-xs font-medium">
|