@agent-native/core 0.98.0 → 0.98.2
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 +32 -0
- package/corpus/core/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
- package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +1 -1
- package/corpus/core/docs/content/pr-visual-recap.mdx +50 -1
- package/corpus/core/docs/content/template-plan.mdx +1 -1
- package/corpus/core/package.json +2 -2
- package/corpus/core/src/action-change-marker.ts +8 -1
- package/corpus/core/src/changelog/parse.ts +8 -3
- package/corpus/core/src/cli/plan-local.ts +43 -11
- package/corpus/core/src/cli/pr-visual-recap-workflow.ts +2 -9
- package/corpus/core/src/cli/recap.ts +356 -4
- package/corpus/core/src/cli/skills-content/local-files.ts +17 -12
- package/corpus/core/src/client/AgentPanel.tsx +2 -3
- package/corpus/core/src/client/AssistantChat.tsx +83 -39
- package/corpus/core/src/client/analytics.ts +125 -14
- package/corpus/core/src/client/blocks/library/wireframe-kit.tsx +16 -2
- package/corpus/core/src/client/chat-model-groups.ts +28 -0
- package/corpus/core/src/client/composer/RealtimeVoiceMode.tsx +442 -85
- package/corpus/core/src/client/composer/TiptapComposer.tsx +46 -29
- package/corpus/core/src/client/composer/VoiceButton.tsx +2 -1
- package/corpus/core/src/client/composer/index.ts +5 -0
- package/corpus/core/src/client/composer/useRealtimeVoiceMode.tsx +1206 -67
- package/corpus/core/src/client/index.ts +10 -0
- package/corpus/core/src/client/progress/RunsTray.tsx +13 -1
- package/corpus/core/src/client/session-replay.ts +10 -0
- package/corpus/core/src/client/settings/DemoModeSection.tsx +4 -28
- package/corpus/core/src/client/settings/SecretsSection.tsx +387 -266
- package/corpus/core/src/client/settings/SettingsPanel.tsx +117 -38
- package/corpus/core/src/client/url-scrub.ts +13 -0
- package/corpus/core/src/client/use-action.ts +12 -0
- package/corpus/core/src/client/use-agent-chat-home-handoff.ts +8 -1
- package/corpus/core/src/client/use-agent-engine-configured.ts +17 -3
- package/corpus/core/src/client/use-db-sync.ts +84 -34
- package/corpus/core/src/client/use-demo-mode-status.ts +44 -0
- package/corpus/core/src/client/use-pausing-interval.ts +14 -4
- package/corpus/core/src/integrations/scope-store.ts +1 -1
- package/corpus/core/src/integrations/usage-budget-store.ts +1 -1
- package/corpus/core/src/localization/default-messages.ts +44 -1
- package/corpus/core/src/mcp-client/workspace-servers.ts +4 -4
- package/corpus/core/src/secrets/crypto.ts +28 -8
- package/corpus/core/src/server/action-change.ts +5 -1
- package/corpus/core/src/server/action-routes.ts +8 -0
- package/corpus/core/src/server/poll.ts +1 -0
- package/corpus/core/src/server/realtime-voice.ts +299 -13
- package/corpus/core/src/styles/agent-native.css +2 -2
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
- package/corpus/core/src/vite/client.ts +9 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +10 -5
- package/corpus/templates/analytics/AGENTS.md +17 -13
- package/corpus/templates/analytics/actions/navigate.ts +59 -5
- package/corpus/templates/analytics/actions/view-screen.ts +3 -6
- package/corpus/templates/analytics/app/components/ProviderCorpusJobNotifier.tsx +20 -3
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +20 -5
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +21 -6
- package/corpus/templates/analytics/app/global.css +19 -20
- package/corpus/templates/analytics/app/lib/demo-chart-trend.ts +156 -0
- package/corpus/templates/analytics/app/lib/provider-corpus-job-sync.ts +26 -0
- package/corpus/templates/analytics/app/pages/Settings.tsx +35 -341
- package/corpus/templates/analytics/app/pages/monitoring/ErrorsPanel.tsx +38 -7
- package/corpus/templates/analytics/app/pages/monitoring/MonitoringPage.tsx +1 -1
- package/corpus/templates/analytics/app/pages/monitoring/errors/i18n.ts +3 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +333 -272
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +72 -17
- package/corpus/templates/analytics/app/pages/sessions/SessionsPage.tsx +297 -108
- package/corpus/templates/analytics/app/root.tsx +28 -8
- package/corpus/templates/analytics/changelog/2026-06-24-first-party-signup-and-pageview-panels-now-honor-dashboard-filters.md +2 -1
- package/corpus/templates/analytics/changelog/2026-06-25-referrer-dashboard-panels-show-external-domains.md +2 -1
- package/corpus/templates/analytics/changelog/2026-07-06-mobile-chat-header-is-more-compact-and-the-menu-button-opens-navigation.md +1 -0
- package/corpus/templates/analytics/changelog/2026-07-08-dashboard-history-and-chat-context.md +1 -0
- package/corpus/templates/analytics/changelog/2026-07-08-settings-are-cleaner-searchable-and-alerts-have-their-own-tab.md +1 -0
- package/corpus/templates/analytics/changelog/2026-07-08-sidebar-sections-stay-collapsed-until-opened.md +1 -0
- package/corpus/templates/analytics/changelog/2026-07-11-analytics-no-longer-repeatedly-restarts-background-requests-.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-analytics-only-asks-for-replay-storage-when-you-enable-sessi.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-charts-now-show-their-loading-skeleton-while-refreshing.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-realtime-voice-now-shows-a-clear-connection-indicator-comple.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-replay-event-counts-stay-hidden-until-recordings-finish-load.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-replay-storage-key-mismatches-show-actionable-setup-guidance.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-replay-timelines-group-continuous-scrolling-and-dev-tools-co.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-filters-now-stay-compact-in-a-settings-menu-at-mediu.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-replay-console-errors-now-link-to-matching-issues-or.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-replays-load-large-recordings-faster-and-surface-fai.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-replays-preserve-recorded-styles-and-viewport-layout.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-11-session-replays-stay-centered-instead-of-clipping-wide-recor.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-daily-dashboard-emails-reliably-include-the-complete-dashboa.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-12-demo-mode-charts-trend-upward.md +6 -0
- package/corpus/templates/analytics/package.json +1 -1
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +1 -303
- package/corpus/templates/analytics/server/handlers/session-replay.ts +57 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +2 -0
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +1 -1
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +17 -33
- package/corpus/templates/analytics/server/lib/demo-dashboards.ts +16 -3
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +12 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +208 -2
- package/corpus/templates/analytics/server/plugins/onboarding.ts +7 -79
- package/corpus/templates/analytics/server/routes/api/session-replay/recordings/[recordingId]/chunks.get.ts +1 -0
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/assets/app/global.css +4 -4
- package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +0 -1
- package/corpus/templates/assets/app/routes/library.tsx +0 -1
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/brain/app/global.css +5 -5
- package/corpus/templates/brain/app/root.tsx +0 -3
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/calendar/app/root.tsx +1 -0
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/clips/app/components/player/video-player.tsx +5 -1
- package/corpus/templates/clips/app/hooks/use-auto-title.ts +74 -8
- package/corpus/templates/clips/app/hooks/use-library.ts +12 -25
- package/corpus/templates/clips/app/routes/_app.settings._index.tsx +20 -22
- package/corpus/templates/clips/changelog/2026-07-11-clips-no-longer-stay-stuck-on-preparing-clip-when-they-are-r.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-11-generated-titles-no-longer-cause-continuous-background-refreshes.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-11-s3-storage-setup-stays-collapsed-until-you-choose-it-as-the-.md +6 -0
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +2 -2
- package/corpus/templates/content/app/hooks/use-comments.ts +0 -1
- package/corpus/templates/content/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
- package/corpus/templates/content/changelog/2026-07-12-the-left-sidebar-stays-fixed-horizontally-while-scrolling-on.md +6 -0
- package/corpus/templates/design/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +1 -2
- package/corpus/templates/macros/app/root.tsx +0 -3
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/mail/app/hooks/use-compose-state.ts +1 -0
- package/corpus/templates/mail/app/root.tsx +1 -12
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/corpus/templates/plan/.agents/skills/visual-plan/references/local-files.md +17 -12
- package/corpus/templates/plan/.agents/skills/visual-recap/references/local-files.md +17 -12
- package/corpus/templates/plan/actions/validate-local-plan-source.ts +4 -4
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -1
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +5 -2
- package/corpus/templates/plan/app/hooks/use-plans.ts +6 -13
- package/corpus/templates/plan/app/lib/plan-local-bridge.ts +41 -0
- package/corpus/templates/plan/app/lib/plan-tracking.ts +3 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +14 -36
- package/corpus/templates/plan/app/root.tsx +13 -3
- package/corpus/templates/plan/changelog/2026-07-11-plan-refreshes-only-when-content-changes.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-12-local-plan-source-now-stays-on-device.md +6 -0
- package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +4 -1
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +1 -1
- package/corpus/templates/slides/app/components/layout/Header.tsx +1 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +1 -0
- package/corpus/templates/slides/app/hooks/use-slide-comments.ts +7 -31
- package/corpus/templates/slides/changelog/2026-07-11-comments-now-update-from-live-collaboration-events-without-c.md +6 -0
- package/dist/action-change-marker.d.ts +1 -0
- package/dist/action-change-marker.d.ts.map +1 -1
- package/dist/action-change-marker.js +7 -1
- package/dist/action-change-marker.js.map +1 -1
- package/dist/changelog/parse.d.ts +4 -2
- package/dist/changelog/parse.d.ts.map +1 -1
- package/dist/changelog/parse.js +5 -3
- package/dist/changelog/parse.js.map +1 -1
- package/dist/cli/plan-local.d.ts +6 -6
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +36 -7
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.d.ts +2 -8
- package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
- package/dist/cli/pr-visual-recap-workflow.js +2 -8
- package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
- package/dist/cli/recap.d.ts +22 -1
- package/dist/cli/recap.d.ts.map +1 -1
- package/dist/cli/recap.js +286 -2
- package/dist/cli/recap.js.map +1 -1
- package/dist/cli/skills-content/local-files.d.ts +1 -1
- package/dist/cli/skills-content/local-files.d.ts.map +1 -1
- package/dist/cli/skills-content/local-files.js +17 -12
- package/dist/cli/skills-content/local-files.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +2 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +7 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +62 -40
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/analytics.d.ts +8 -0
- package/dist/client/analytics.d.ts.map +1 -1
- package/dist/client/analytics.js +103 -13
- package/dist/client/analytics.js.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.d.ts +2 -0
- package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe-kit.js +9 -2
- package/dist/client/blocks/library/wireframe-kit.js.map +1 -1
- package/dist/client/chat-model-groups.d.ts.map +1 -1
- package/dist/client/chat-model-groups.js +24 -0
- package/dist/client/chat-model-groups.js.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.d.ts +40 -4
- package/dist/client/composer/RealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/RealtimeVoiceMode.js +172 -42
- package/dist/client/composer/RealtimeVoiceMode.js.map +1 -1
- package/dist/client/composer/TiptapComposer.d.ts +4 -0
- package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
- package/dist/client/composer/TiptapComposer.js +47 -29
- package/dist/client/composer/TiptapComposer.js.map +1 -1
- package/dist/client/composer/VoiceButton.d.ts.map +1 -1
- package/dist/client/composer/VoiceButton.js +2 -2
- package/dist/client/composer/VoiceButton.js.map +1 -1
- package/dist/client/composer/index.d.ts +2 -2
- package/dist/client/composer/index.d.ts.map +1 -1
- package/dist/client/composer/index.js +1 -1
- package/dist/client/composer/index.js.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.d.ts +100 -3
- package/dist/client/composer/useRealtimeVoiceMode.d.ts.map +1 -1
- package/dist/client/composer/useRealtimeVoiceMode.js +952 -51
- package/dist/client/composer/useRealtimeVoiceMode.js.map +1 -1
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +3 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/progress/RunsTray.d.ts.map +1 -1
- package/dist/client/progress/RunsTray.js +10 -1
- package/dist/client/progress/RunsTray.js.map +1 -1
- package/dist/client/session-replay.d.ts +2 -0
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +7 -0
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/settings/DemoModeSection.d.ts.map +1 -1
- package/dist/client/settings/DemoModeSection.js +4 -23
- package/dist/client/settings/DemoModeSection.js.map +1 -1
- package/dist/client/settings/SecretsSection.d.ts +2 -3
- package/dist/client/settings/SecretsSection.d.ts.map +1 -1
- package/dist/client/settings/SecretsSection.js +46 -22
- package/dist/client/settings/SecretsSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts +9 -0
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +46 -12
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/url-scrub.d.ts.map +1 -1
- package/dist/client/url-scrub.js +14 -0
- package/dist/client/url-scrub.js.map +1 -1
- package/dist/client/use-action.d.ts +2 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +10 -0
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.d.ts +2 -0
- package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -1
- package/dist/client/use-agent-chat-home-handoff.js +7 -1
- package/dist/client/use-agent-chat-home-handoff.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +17 -3
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +8 -2
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +57 -32
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/use-demo-mode-status.d.ts +12 -0
- package/dist/client/use-demo-mode-status.d.ts.map +1 -0
- package/dist/client/use-demo-mode-status.js +30 -0
- package/dist/client/use-demo-mode-status.js.map +1 -0
- package/dist/client/use-pausing-interval.d.ts.map +1 -1
- package/dist/client/use-pausing-interval.js +16 -4
- package/dist/client/use-pausing-interval.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/integrations/scope-store.js +1 -1
- package/dist/integrations/scope-store.js.map +1 -1
- package/dist/integrations/usage-budget-store.js +1 -1
- package/dist/integrations/usage-budget-store.js.map +1 -1
- package/dist/localization/default-messages.d.ts +41 -1
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +41 -1
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/mcp-client/workspace-servers.js +4 -4
- package/dist/mcp-client/workspace-servers.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/secrets/crypto.d.ts +7 -6
- package/dist/secrets/crypto.d.ts.map +1 -1
- package/dist/secrets/crypto.js +30 -11
- package/dist/secrets/crypto.js.map +1 -1
- package/dist/server/action-change.d.ts +1 -0
- package/dist/server/action-change.d.ts.map +1 -1
- package/dist/server/action-change.js +4 -1
- package/dist/server/action-change.js.map +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +5 -0
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +1 -0
- package/dist/server/poll.js.map +1 -1
- package/dist/server/realtime-voice.d.ts +7 -0
- package/dist/server/realtime-voice.d.ts.map +1 -1
- package/dist/server/realtime-voice.js +222 -12
- package/dist/server/realtime-voice.js.map +1 -1
- package/dist/styles/agent-native.css +2 -2
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
- package/dist/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +6 -1
- package/dist/vite/client.js.map +1 -1
- package/docs/content/locales/ar-SA/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ar-SA/template-plan.mdx +1 -1
- package/docs/content/locales/de-DE/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/de-DE/template-plan.mdx +1 -1
- package/docs/content/locales/es-ES/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/es-ES/template-plan.mdx +1 -1
- package/docs/content/locales/fr-FR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/fr-FR/template-plan.mdx +1 -1
- package/docs/content/locales/hi-IN/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/hi-IN/template-plan.mdx +1 -1
- package/docs/content/locales/ja-JP/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ja-JP/template-plan.mdx +1 -1
- package/docs/content/locales/ko-KR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/ko-KR/template-plan.mdx +1 -1
- package/docs/content/locales/pt-BR/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/pt-BR/template-plan.mdx +1 -1
- package/docs/content/locales/zh-CN/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/zh-CN/template-plan.mdx +1 -1
- package/docs/content/locales/zh-TW/pr-visual-recap.mdx +25 -1
- package/docs/content/locales/zh-TW/template-plan.mdx +1 -1
- package/docs/content/pr-visual-recap.mdx +50 -1
- package/docs/content/template-plan.mdx +1 -1
- package/package.json +2 -2
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +2 -2
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +7 -3
- package/src/templates/workspace-core/.agents/skills/voice-transcription/SKILL.md +39 -9
|
@@ -164,12 +164,14 @@ function SettingsSelect({
|
|
|
164
164
|
value,
|
|
165
165
|
options,
|
|
166
166
|
onValueChange,
|
|
167
|
+
disabled = false,
|
|
167
168
|
}: {
|
|
168
169
|
label: string;
|
|
169
170
|
labelAdornment?: React.ReactNode;
|
|
170
171
|
value: string;
|
|
171
172
|
options: SettingsSelectOption[];
|
|
172
173
|
onValueChange: (value: string) => void;
|
|
174
|
+
disabled?: boolean;
|
|
173
175
|
}) {
|
|
174
176
|
const isPage = useSettingsSurface() === "page";
|
|
175
177
|
const controlStyle = isPage ? CONTROL_STYLE_PAGE : CONTROL_STYLE;
|
|
@@ -181,10 +183,14 @@ function SettingsSelect({
|
|
|
181
183
|
<p className={fieldLabelClass(isPage)}>{label}</p>
|
|
182
184
|
{labelAdornment}
|
|
183
185
|
</div>
|
|
184
|
-
<SelectPrimitive.Root
|
|
186
|
+
<SelectPrimitive.Root
|
|
187
|
+
value={value}
|
|
188
|
+
onValueChange={onValueChange}
|
|
189
|
+
disabled={disabled}
|
|
190
|
+
>
|
|
185
191
|
<SelectPrimitive.Trigger
|
|
186
192
|
className={cn(
|
|
187
|
-
"flex w-full items-center justify-between rounded-md border border-border bg-background px-3 text-start text-foreground outline-none transition-colors hover:bg-accent/40 data-[placeholder]:text-muted-foreground",
|
|
193
|
+
"flex w-full items-center justify-between rounded-md border border-border bg-background px-3 text-start text-foreground outline-none transition-colors hover:bg-accent/40 data-[placeholder]:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-60",
|
|
188
194
|
isPage ? "h-10 text-sm" : "h-9 text-[12px]",
|
|
189
195
|
)}
|
|
190
196
|
aria-label={label}
|
|
@@ -624,8 +630,31 @@ function friendlyModelName(model: string): string {
|
|
|
624
630
|
const tier = claude[1][0].toUpperCase() + claude[1].slice(1);
|
|
625
631
|
return `${tier} ${claude[2]}${claude[3] ? `.${claude[3]}` : ""}`;
|
|
626
632
|
}
|
|
627
|
-
if (model.startsWith("gpt-"))
|
|
633
|
+
if (model.startsWith("gpt-")) {
|
|
634
|
+
const rest = model.slice(4);
|
|
635
|
+
const gpt = rest.match(/^(\d+)[.-](\d+)(?:[.-](.+))?$/);
|
|
636
|
+
if (gpt) {
|
|
637
|
+
const suffix = gpt[3]
|
|
638
|
+
? ` ${gpt[3]
|
|
639
|
+
.split("-")
|
|
640
|
+
.map((part) => part[0].toUpperCase() + part.slice(1))
|
|
641
|
+
.join(" ")}`
|
|
642
|
+
: "";
|
|
643
|
+
return `GPT-${gpt[1]}.${gpt[2]}${suffix}`;
|
|
644
|
+
}
|
|
645
|
+
return `GPT-${rest}`;
|
|
646
|
+
}
|
|
628
647
|
if (/^o\d/.test(model)) return model;
|
|
648
|
+
const geminiVersioned = model.match(
|
|
649
|
+
/^gemini-(\d+)-(\d+)-(.+?)(?:-preview)?$/,
|
|
650
|
+
);
|
|
651
|
+
if (geminiVersioned) {
|
|
652
|
+
const variant = geminiVersioned[3]
|
|
653
|
+
.split("-")
|
|
654
|
+
.map((part) => part[0].toUpperCase() + part.slice(1))
|
|
655
|
+
.join(" ");
|
|
656
|
+
return `Gemini ${geminiVersioned[1]}.${geminiVersioned[2]} ${variant}`;
|
|
657
|
+
}
|
|
629
658
|
const gemini = model.match(/^gemini-(.+?)(?:-preview)?$/);
|
|
630
659
|
if (gemini) {
|
|
631
660
|
const parts = gemini[1]
|
|
@@ -682,6 +711,77 @@ function latestModelsOnly(models: string[]): string[] {
|
|
|
682
711
|
});
|
|
683
712
|
}
|
|
684
713
|
|
|
714
|
+
export function AppDefaultModelField({
|
|
715
|
+
engine,
|
|
716
|
+
models,
|
|
717
|
+
value,
|
|
718
|
+
defaultModel,
|
|
719
|
+
disabled,
|
|
720
|
+
onValueChange,
|
|
721
|
+
onEnter,
|
|
722
|
+
}: {
|
|
723
|
+
engine: string;
|
|
724
|
+
models: string[];
|
|
725
|
+
value: string;
|
|
726
|
+
defaultModel?: string;
|
|
727
|
+
disabled?: boolean;
|
|
728
|
+
onValueChange: (value: string) => void;
|
|
729
|
+
onEnter?: () => void;
|
|
730
|
+
}) {
|
|
731
|
+
const isPage = useSettingsSurface() === "page";
|
|
732
|
+
const modelOptions: SettingsSelectOption[] = latestModelsOnly(models).map(
|
|
733
|
+
(model) => ({ value: model, label: friendlyModelName(model) }),
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
// Builder models are a closed catalog (and are validated server-side), so a
|
|
737
|
+
// real select keeps every available model visible even when one is already
|
|
738
|
+
// selected. Native datalists filter against the current input value, which
|
|
739
|
+
// made this field appear to contain only the active model.
|
|
740
|
+
if (engine === "builder" && modelOptions.length > 0) {
|
|
741
|
+
return (
|
|
742
|
+
<SettingsSelect
|
|
743
|
+
label="Model"
|
|
744
|
+
value={value}
|
|
745
|
+
options={modelOptions}
|
|
746
|
+
onValueChange={onValueChange}
|
|
747
|
+
disabled={disabled}
|
|
748
|
+
/>
|
|
749
|
+
);
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
return (
|
|
753
|
+
<div className="space-y-1.5">
|
|
754
|
+
<p className={fieldLabelClass(isPage)}>Model</p>
|
|
755
|
+
<input
|
|
756
|
+
type="text"
|
|
757
|
+
list={`app-model-suggestions-${engine}`}
|
|
758
|
+
value={value}
|
|
759
|
+
disabled={disabled}
|
|
760
|
+
onChange={(event) => onValueChange(event.target.value)}
|
|
761
|
+
onKeyDown={(event) => {
|
|
762
|
+
if (event.key === "Enter") onEnter?.();
|
|
763
|
+
}}
|
|
764
|
+
placeholder={defaultModel ?? "model-id"}
|
|
765
|
+
spellCheck={false}
|
|
766
|
+
autoComplete="off"
|
|
767
|
+
className={cn(textInputClass(isPage), "disabled:opacity-60")}
|
|
768
|
+
style={isPage ? CONTROL_STYLE_PAGE : CONTROL_STYLE}
|
|
769
|
+
/>
|
|
770
|
+
{modelOptions.length > 0 && (
|
|
771
|
+
<datalist id={`app-model-suggestions-${engine}`}>
|
|
772
|
+
{modelOptions.map((option) => (
|
|
773
|
+
<option
|
|
774
|
+
key={option.value}
|
|
775
|
+
value={option.value}
|
|
776
|
+
label={option.label}
|
|
777
|
+
/>
|
|
778
|
+
))}
|
|
779
|
+
</datalist>
|
|
780
|
+
)}
|
|
781
|
+
</div>
|
|
782
|
+
);
|
|
783
|
+
}
|
|
784
|
+
|
|
685
785
|
// ─── LLM Section ────────────────────────────────────────────────────────────
|
|
686
786
|
|
|
687
787
|
interface EngineInfo {
|
|
@@ -1388,9 +1488,6 @@ function AppModelDefaultsSectionInner({
|
|
|
1388
1488
|
? `Install ${engine.installPackage ?? "the provider packages"} to use this provider`
|
|
1389
1489
|
: "Credentials not detected yet",
|
|
1390
1490
|
}));
|
|
1391
|
-
const modelOptions: SettingsSelectOption[] = latestModelsOnly(
|
|
1392
|
-
selectedEngineInfo?.supportedModels ?? [],
|
|
1393
|
-
).map((model) => ({ value: model, label: friendlyModelName(model) }));
|
|
1394
1491
|
const hasPendingChange =
|
|
1395
1492
|
!!settings &&
|
|
1396
1493
|
settings.canUpdate &&
|
|
@@ -1536,38 +1633,20 @@ function AppModelDefaultsSectionInner({
|
|
|
1536
1633
|
}}
|
|
1537
1634
|
/>
|
|
1538
1635
|
|
|
1539
|
-
<
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
placeholder={selectedEngineInfo?.defaultModel ?? "model-id"}
|
|
1554
|
-
spellCheck={false}
|
|
1555
|
-
autoComplete="off"
|
|
1556
|
-
className={cn(textInputClass(isPage), "disabled:opacity-60")}
|
|
1557
|
-
style={isPage ? CONTROL_STYLE_PAGE : CONTROL_STYLE}
|
|
1558
|
-
/>
|
|
1559
|
-
{modelOptions.length > 0 && (
|
|
1560
|
-
<datalist id={`app-model-suggestions-${selectedEngine}`}>
|
|
1561
|
-
{modelOptions.map((option) => (
|
|
1562
|
-
<option
|
|
1563
|
-
key={option.value}
|
|
1564
|
-
value={option.value}
|
|
1565
|
-
label={option.label}
|
|
1566
|
-
/>
|
|
1567
|
-
))}
|
|
1568
|
-
</datalist>
|
|
1569
|
-
)}
|
|
1570
|
-
</div>
|
|
1636
|
+
<AppDefaultModelField
|
|
1637
|
+
engine={selectedEngine}
|
|
1638
|
+
models={selectedEngineInfo?.supportedModels ?? []}
|
|
1639
|
+
value={selectedModel}
|
|
1640
|
+
defaultModel={selectedEngineInfo?.defaultModel}
|
|
1641
|
+
disabled={!settings.canUpdate || saving}
|
|
1642
|
+
onValueChange={(value) => {
|
|
1643
|
+
setSelectedModel(value);
|
|
1644
|
+
setError(null);
|
|
1645
|
+
}}
|
|
1646
|
+
onEnter={() => {
|
|
1647
|
+
if (hasPendingChange) void save();
|
|
1648
|
+
}}
|
|
1649
|
+
/>
|
|
1571
1650
|
|
|
1572
1651
|
<div className="flex items-center gap-1.5">
|
|
1573
1652
|
<button
|
|
@@ -12,6 +12,7 @@ const SENSITIVE_QUERY_PARAMS = new Set([
|
|
|
12
12
|
"code",
|
|
13
13
|
"share",
|
|
14
14
|
"share_token",
|
|
15
|
+
"bridge",
|
|
15
16
|
]);
|
|
16
17
|
|
|
17
18
|
export function scrubUrl(url: string | undefined): string | undefined {
|
|
@@ -26,6 +27,18 @@ export function scrubUrl(url: string | undefined): string | undefined {
|
|
|
26
27
|
mutated = true;
|
|
27
28
|
}
|
|
28
29
|
}
|
|
30
|
+
if (u.hash.includes("=")) {
|
|
31
|
+
const hashParams = new URLSearchParams(u.hash.slice(1));
|
|
32
|
+
let hashMutated = false;
|
|
33
|
+
for (const key of Array.from(hashParams.keys())) {
|
|
34
|
+
if (SENSITIVE_QUERY_PARAMS.has(key.toLowerCase())) {
|
|
35
|
+
hashParams.set(key, "<redacted>");
|
|
36
|
+
mutated = true;
|
|
37
|
+
hashMutated = true;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (hashMutated) u.hash = hashParams.toString();
|
|
41
|
+
}
|
|
29
42
|
if (!mutated) return url;
|
|
30
43
|
// If the original URL was relative, return only the path/query/fragment.
|
|
31
44
|
if (u.origin === "http://placeholder.local") {
|
|
@@ -28,6 +28,7 @@ import type {
|
|
|
28
28
|
} from "@tanstack/react-query";
|
|
29
29
|
|
|
30
30
|
import { agentNativePath } from "./api-path.js";
|
|
31
|
+
import { getBrowserTabId } from "./browser-tab-id.js";
|
|
31
32
|
import { ensureEmbedAuthFetchInterceptor } from "./embed-auth.js";
|
|
32
33
|
|
|
33
34
|
const ACTION_PREFIX = agentNativePath("/_agent-native/actions");
|
|
@@ -216,6 +217,8 @@ export interface ActionFetchOptions {
|
|
|
216
217
|
keepalive?: boolean;
|
|
217
218
|
/** Pre-serialized mutation body used by the keepalive budget coordinator. */
|
|
218
219
|
serializedBody?: string;
|
|
220
|
+
/** Omit the tab echo-suppression tag for imperative callers. */
|
|
221
|
+
includeRequestSource?: boolean;
|
|
219
222
|
}
|
|
220
223
|
|
|
221
224
|
/**
|
|
@@ -264,6 +267,14 @@ async function actionFetch<T>(
|
|
|
264
267
|
// safe to expose: CORS allows it (see action-routes.ts) and it carries
|
|
265
268
|
// no auth weight — it only narrows the caller tag.
|
|
266
269
|
"X-Agent-Native-Frontend": "1",
|
|
270
|
+
...(options?.includeRequestSource !== false
|
|
271
|
+
? {
|
|
272
|
+
// The server copies this onto the emitted action sync event.
|
|
273
|
+
// useDbSync can then ignore the echo in this tab while other tabs
|
|
274
|
+
// still refresh.
|
|
275
|
+
"X-Request-Source": getBrowserTabId(),
|
|
276
|
+
}
|
|
277
|
+
: {}),
|
|
267
278
|
};
|
|
268
279
|
const tz = resolveUserTimezone();
|
|
269
280
|
if (tz) headers["x-user-timezone"] = tz;
|
|
@@ -426,6 +437,7 @@ export function callAction<
|
|
|
426
437
|
return actionFetch<R>(actionName, options.method ?? "POST", params, {
|
|
427
438
|
signal: options.signal,
|
|
428
439
|
timeoutMs: options.timeoutMs,
|
|
440
|
+
includeRequestSource: false,
|
|
429
441
|
});
|
|
430
442
|
}
|
|
431
443
|
|
|
@@ -79,6 +79,10 @@ function isStaticAssetPath(pathname: string): boolean {
|
|
|
79
79
|
return /\.[A-Za-z0-9]{1,12}$/.test(lastSegment);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
function isSettingsPath(pathname: string): boolean {
|
|
83
|
+
return pathname === "/settings" || pathname.startsWith("/settings/");
|
|
84
|
+
}
|
|
85
|
+
|
|
82
86
|
function localPathFromAnchor(anchor: HTMLAnchorElement): string | null {
|
|
83
87
|
if (!anchor.href) return null;
|
|
84
88
|
try {
|
|
@@ -135,6 +139,8 @@ export function useAgentChatHomeHandoff({
|
|
|
135
139
|
/**
|
|
136
140
|
* Intercepts ordinary in-app links clicked from a full-page chat route so the
|
|
137
141
|
* page chat can morph into the destination AgentSidebar and keep its thread.
|
|
142
|
+
* Settings is intentionally excluded: a user opening it keeps chat full-page.
|
|
143
|
+
* Agent-driven navigation can still opt into the handoff by marking it first.
|
|
138
144
|
*/
|
|
139
145
|
export function useAgentChatHomeHandoffLinks({
|
|
140
146
|
storageKey,
|
|
@@ -170,7 +176,8 @@ export function useAgentChatHomeHandoffLinks({
|
|
|
170
176
|
!path ||
|
|
171
177
|
matchesChatPath(pathname) ||
|
|
172
178
|
isFrameworkOrApiPath(pathname) ||
|
|
173
|
-
isStaticAssetPath(pathname)
|
|
179
|
+
isStaticAssetPath(pathname) ||
|
|
180
|
+
isSettingsPath(pathname)
|
|
174
181
|
) {
|
|
175
182
|
return;
|
|
176
183
|
}
|
|
@@ -30,6 +30,7 @@ export interface UseAgentEngineConfiguredOptions {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
const DEFAULT_STATUS_CHECK_TIMEOUT_MS = 2500;
|
|
33
|
+
const UNKNOWN_STATUS_RETRY_MS = 2000;
|
|
33
34
|
|
|
34
35
|
async function fetchStatusJson(
|
|
35
36
|
path: string,
|
|
@@ -129,9 +130,15 @@ export async function fetchAgentEngineConfiguredState(
|
|
|
129
130
|
(builderStatusKnown && builderStatus.configured) ||
|
|
130
131
|
(engineStatusKnown && engineStatus.configured);
|
|
131
132
|
if (anyConfigured) return "configured";
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
|
|
134
|
+
// The engine status route is the canonical readiness check: it resolves
|
|
135
|
+
// Builder, scoped BYOK secrets, deployment credentials, and custom engines.
|
|
136
|
+
// Once it has answered `configured: false`, a slow legacy env/Builder status
|
|
137
|
+
// request must not leave the composer permissively stuck in `unknown`.
|
|
138
|
+
if (engineStatusKnown) return "missing";
|
|
139
|
+
|
|
140
|
+
// Compatibility fallback for older hosts without the canonical route.
|
|
141
|
+
return envKeysKnown && builderStatusKnown ? "missing" : "unknown";
|
|
135
142
|
}
|
|
136
143
|
|
|
137
144
|
/**
|
|
@@ -149,16 +156,22 @@ export function useAgentEngineConfigured(
|
|
|
149
156
|
|
|
150
157
|
useEffect(() => {
|
|
151
158
|
let cancelled = false;
|
|
159
|
+
let retryId: ReturnType<typeof setTimeout> | undefined;
|
|
152
160
|
// Monotonic call counter: overlapping checks (mount + a
|
|
153
161
|
// `agent-engine:configured-changed` fired right after a key is saved) can
|
|
154
162
|
// resolve out of order; only the latest call may write state, or a slow
|
|
155
163
|
// stale "missing" response would overwrite the fresh "configured" one.
|
|
156
164
|
let requestSeq = 0;
|
|
157
165
|
const check = async (options?: { missingFallback?: boolean }) => {
|
|
166
|
+
if (retryId !== undefined) {
|
|
167
|
+
clearTimeout(retryId);
|
|
168
|
+
retryId = undefined;
|
|
169
|
+
}
|
|
158
170
|
const seq = ++requestSeq;
|
|
159
171
|
const nextState = await fetchAgentEngineConfiguredState(enabled, options);
|
|
160
172
|
if (cancelled || seq !== requestSeq) return;
|
|
161
173
|
if (nextState === "unknown") {
|
|
174
|
+
retryId = setTimeout(() => void check(), UNKNOWN_STATUS_RETRY_MS);
|
|
162
175
|
return;
|
|
163
176
|
}
|
|
164
177
|
setState(nextState);
|
|
@@ -185,6 +198,7 @@ export function useAgentEngineConfigured(
|
|
|
185
198
|
window.addEventListener("agent-chat:missing-api-key", onMissing);
|
|
186
199
|
return () => {
|
|
187
200
|
cancelled = true;
|
|
201
|
+
if (retryId !== undefined) clearTimeout(retryId);
|
|
188
202
|
window.removeEventListener(
|
|
189
203
|
"agent-engine:configured-changed",
|
|
190
204
|
onConfiguredChanged,
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
refreshDemoModeFetchInterceptor,
|
|
6
6
|
} from "../demo/fetch-interceptor.js";
|
|
7
7
|
import { agentNativePath } from "./api-path.js";
|
|
8
|
+
import { getBrowserTabId } from "./browser-tab-id.js";
|
|
8
9
|
import {
|
|
9
10
|
ensureEmbedAuthFetchInterceptor,
|
|
10
11
|
isEmbedAuthActive,
|
|
@@ -16,15 +17,25 @@ interface Query {
|
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
interface QueryClient {
|
|
19
|
-
invalidateQueries(
|
|
20
|
+
invalidateQueries(
|
|
21
|
+
opts?: {
|
|
22
|
+
queryKey?: string[];
|
|
23
|
+
predicate?: (query: Query) => boolean;
|
|
24
|
+
},
|
|
25
|
+
options?: { cancelRefetch?: boolean },
|
|
26
|
+
): unknown;
|
|
27
|
+
isFetching?(filters?: {
|
|
20
28
|
queryKey?: string[];
|
|
21
29
|
predicate?: (query: Query) => boolean;
|
|
22
|
-
}):
|
|
30
|
+
}): number;
|
|
23
31
|
}
|
|
24
32
|
|
|
25
33
|
const POLL_ABORT_MIN_MS = 10_000;
|
|
26
|
-
|
|
27
|
-
|
|
34
|
+
// SSE delivers changes immediately in the normal path. The poll is a
|
|
35
|
+
// cross-process/serverless safety net, so an idle tab should not bill the host
|
|
36
|
+
// four times per minute forever. Focus and active agent work still poll now.
|
|
37
|
+
const SSE_FALLBACK_INTERVAL_MS = 60_000;
|
|
38
|
+
const IDLE_POLL_INTERVAL_MS = 60_000;
|
|
28
39
|
const POLL_AUTH_FAILURE_COOLDOWN_MS = 60_000;
|
|
29
40
|
/**
|
|
30
41
|
* Max cadence for SSE/poll-driven query invalidation in `useDbSync`. Events
|
|
@@ -356,7 +367,7 @@ class SyncTransport {
|
|
|
356
367
|
// full cadence. Resets on the first successful poll.
|
|
357
368
|
const delay =
|
|
358
369
|
this.consecutiveFailures > 0
|
|
359
|
-
? Math.min(base * 2 ** Math.min(this.consecutiveFailures, 5),
|
|
370
|
+
? Math.min(base * 2 ** Math.min(this.consecutiveFailures, 5), 300_000)
|
|
360
371
|
: base;
|
|
361
372
|
this.timer = setTimeout(() => {
|
|
362
373
|
this.timer = null;
|
|
@@ -675,7 +686,7 @@ export function subscribeSyncEvents(
|
|
|
675
686
|
* @param options.onEvent - Optional callback for each change event
|
|
676
687
|
* @param options.interval - Poll interval in ms. Default: 2000
|
|
677
688
|
* @param options.fallbackInterval - Poll interval while SSE is connected.
|
|
678
|
-
* Default:
|
|
689
|
+
* Default: 60000
|
|
679
690
|
* @param options.pauseWhenHidden - Pause polling while the tab is hidden.
|
|
680
691
|
* Default: true
|
|
681
692
|
* @param options.ignoreSource - Skip events whose `requestSource` matches this
|
|
@@ -798,9 +809,15 @@ export function useDbSync(
|
|
|
798
809
|
|
|
799
810
|
function invalidateForEvents(events: SyncEvent[]) {
|
|
800
811
|
const ignore = ignoreSourceRef.current;
|
|
801
|
-
const
|
|
802
|
-
|
|
803
|
-
|
|
812
|
+
const ownBrowserSource = getBrowserTabId();
|
|
813
|
+
const relevant = events.filter(
|
|
814
|
+
(event) =>
|
|
815
|
+
!(
|
|
816
|
+
event.source === "action" &&
|
|
817
|
+
event.requestSource === ownBrowserSource
|
|
818
|
+
) &&
|
|
819
|
+
(!ignore || event.requestSource !== ignore),
|
|
820
|
+
);
|
|
804
821
|
const suppressedActions = new Set(
|
|
805
822
|
suppressActionInvalidationForRef.current ?? [],
|
|
806
823
|
);
|
|
@@ -838,18 +855,43 @@ export function useDbSync(
|
|
|
838
855
|
const invalidating = relevant.filter((e) => e.source !== "awareness");
|
|
839
856
|
|
|
840
857
|
if (invalidating.length > 0 && queryClient) {
|
|
858
|
+
// Sync events describe completed writes. If a matching read is already
|
|
859
|
+
// in flight, let it finish instead of aborting and immediately
|
|
860
|
+
// launching the same request again. Repeated action events otherwise
|
|
861
|
+
// turn a slow endpoint into a cancel/restart loop that never settles.
|
|
862
|
+
const invalidateWithoutCancel = (filters?: {
|
|
863
|
+
queryKey?: string[];
|
|
864
|
+
predicate?: (query: Query) => boolean;
|
|
865
|
+
}) => {
|
|
866
|
+
const needsTrailingRefresh =
|
|
867
|
+
(queryClient.isFetching?.(filters) ?? 0) > 0;
|
|
868
|
+
const completion = queryClient.invalidateQueries(filters, {
|
|
869
|
+
cancelRefetch: false,
|
|
870
|
+
});
|
|
871
|
+
// TanStack Query deliberately leaves an in-flight fetch alone when
|
|
872
|
+
// cancelRefetch is false. Queue one post-settlement invalidation so
|
|
873
|
+
// a write that landed after that read began cannot be cleared as
|
|
874
|
+
// fresh by the older response.
|
|
875
|
+
if (needsTrailingRefresh && completion instanceof Promise) {
|
|
876
|
+
void completion.then(
|
|
877
|
+
() => queryClient.invalidateQueries(filters),
|
|
878
|
+
() => {},
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
};
|
|
841
882
|
const hasActionEvent = invalidating.some(
|
|
842
883
|
(evt) => evt.source === "action" && !isSuppressedActionEvent(evt),
|
|
843
884
|
);
|
|
844
885
|
if (hasActionEvent) {
|
|
845
|
-
//
|
|
846
|
-
//
|
|
847
|
-
//
|
|
848
|
-
//
|
|
849
|
-
//
|
|
850
|
-
// storms from noisy domain-specific writes.
|
|
886
|
+
// Action-backed reads share the ["action"] prefix. Keep the default
|
|
887
|
+
// refresh targeted to those queries; invalidating every active query
|
|
888
|
+
// makes one agent write fan out across unrelated provider reads,
|
|
889
|
+
// dashboards, and background status checks. Older apps that still
|
|
890
|
+
// need broad compatibility can opt in with a predicate.
|
|
851
891
|
const predicate = actionInvalidatePredicateRef.current;
|
|
852
|
-
|
|
892
|
+
invalidateWithoutCancel(
|
|
893
|
+
predicate ? { predicate } : { queryKey: ["action"] },
|
|
894
|
+
);
|
|
853
895
|
}
|
|
854
896
|
|
|
855
897
|
// Framework-level invalidate: a small, fixed list of query-key
|
|
@@ -880,32 +922,40 @@ export function useDbSync(
|
|
|
880
922
|
const hasDataChangingEvent = invalidating.some(
|
|
881
923
|
(evt) => evt.source !== "app-state",
|
|
882
924
|
);
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
925
|
+
if (hasDataChangingEvent) {
|
|
926
|
+
const hasFrameworkPrefixEvent = invalidating.some((evt) =>
|
|
927
|
+
["extensions", "extension", "tool", "tools", "slots"].includes(
|
|
928
|
+
evt.source ?? "",
|
|
929
|
+
),
|
|
930
|
+
);
|
|
931
|
+
// The action-specific invalidation above already refreshed
|
|
932
|
+
// ["action"]. A mixed action + extension/tool batch still needs
|
|
933
|
+
// the independent framework prefixes, while pure action batches
|
|
934
|
+
// retain their narrow storm-resistant invalidation.
|
|
935
|
+
if (!hasActionEvent) {
|
|
936
|
+
invalidateWithoutCancel({ queryKey: ["action"] });
|
|
937
|
+
}
|
|
938
|
+
if (!hasActionEvent || hasFrameworkPrefixEvent) {
|
|
939
|
+
invalidateWithoutCancel({ queryKey: ["extension"] });
|
|
940
|
+
invalidateWithoutCancel({ queryKey: ["extensions"] });
|
|
941
|
+
invalidateWithoutCancel({ queryKey: ["extension-slots"] });
|
|
942
|
+
invalidateWithoutCancel({ queryKey: ["slot-installs"] });
|
|
943
|
+
invalidateWithoutCancel({ queryKey: ["slot-available"] });
|
|
944
|
+
invalidateWithoutCancel({ queryKey: ["tool"] });
|
|
945
|
+
invalidateWithoutCancel({ queryKey: ["tools"] });
|
|
946
|
+
}
|
|
897
947
|
}
|
|
898
948
|
if (invalidating.some((evt) => evt.source === "app-state")) {
|
|
899
|
-
|
|
949
|
+
invalidateWithoutCancel({ queryKey: ["app-state"] });
|
|
900
950
|
}
|
|
901
951
|
if (hasAppStateEvent(invalidating, "navigate")) {
|
|
902
|
-
|
|
952
|
+
invalidateWithoutCancel({ queryKey: ["navigate-command"] });
|
|
903
953
|
}
|
|
904
954
|
if (hasAppStateEvent(invalidating, "show-questions")) {
|
|
905
|
-
|
|
955
|
+
invalidateWithoutCancel({ queryKey: ["show-questions"] });
|
|
906
956
|
}
|
|
907
957
|
if (hasAppStateEvent(invalidating, "__set_url__")) {
|
|
908
|
-
|
|
958
|
+
invalidateWithoutCancel({ queryKey: ["__set_url__"] });
|
|
909
959
|
}
|
|
910
960
|
}
|
|
911
961
|
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useQuery } from "@tanstack/react-query";
|
|
2
|
+
|
|
3
|
+
import { agentNativePath } from "./api-path.js";
|
|
4
|
+
import { useChangeVersion } from "./use-change-version.js";
|
|
5
|
+
|
|
6
|
+
interface DemoModeStatusResponse {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
forced?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DemoModeStatus {
|
|
12
|
+
enabled: boolean;
|
|
13
|
+
forced: boolean;
|
|
14
|
+
isLoading: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const DEMO_STATUS_URL = agentNativePath("/_agent-native/demo/status");
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Reads the effective Demo mode status for the current user. The shared
|
|
21
|
+
* change-version stream advances after Demo mode application state changes,
|
|
22
|
+
* so mounted consumers refresh without polling or duplicating the route call.
|
|
23
|
+
*/
|
|
24
|
+
export function useDemoModeStatus(): DemoModeStatus {
|
|
25
|
+
const demoModeVersion = useChangeVersion("app-state:demo-mode");
|
|
26
|
+
|
|
27
|
+
const { data, isLoading } = useQuery({
|
|
28
|
+
queryKey: ["agent-native", "demo-mode", demoModeVersion],
|
|
29
|
+
queryFn: async () => {
|
|
30
|
+
const res = await fetch(DEMO_STATUS_URL, {
|
|
31
|
+
credentials: "same-origin",
|
|
32
|
+
});
|
|
33
|
+
if (!res.ok) return null;
|
|
34
|
+
return (await res.json()) as DemoModeStatusResponse | null;
|
|
35
|
+
},
|
|
36
|
+
staleTime: Infinity,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
enabled: data?.enabled === true,
|
|
41
|
+
forced: data?.forced === true,
|
|
42
|
+
isLoading,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -17,9 +17,19 @@ export function usePausingInterval(
|
|
|
17
17
|
useEffect(() => {
|
|
18
18
|
if (pollMs <= 0) return;
|
|
19
19
|
let id: ReturnType<typeof setInterval> | null = null;
|
|
20
|
+
let running = false;
|
|
20
21
|
const isHidden = () => typeof document !== "undefined" && document.hidden;
|
|
22
|
+
const run = async () => {
|
|
23
|
+
if (running) return;
|
|
24
|
+
running = true;
|
|
25
|
+
try {
|
|
26
|
+
await callback();
|
|
27
|
+
} finally {
|
|
28
|
+
running = false;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
21
31
|
const start = () => {
|
|
22
|
-
if (id == null) id = setInterval(
|
|
32
|
+
if (id == null) id = setInterval(() => void run(), pollMs);
|
|
23
33
|
};
|
|
24
34
|
const stop = () => {
|
|
25
35
|
if (id != null) {
|
|
@@ -29,7 +39,7 @@ export function usePausingInterval(
|
|
|
29
39
|
};
|
|
30
40
|
|
|
31
41
|
if (!pauseWhenHidden) {
|
|
32
|
-
|
|
42
|
+
void run();
|
|
33
43
|
start();
|
|
34
44
|
return () => stop();
|
|
35
45
|
}
|
|
@@ -38,12 +48,12 @@ export function usePausingInterval(
|
|
|
38
48
|
if (document.hidden) {
|
|
39
49
|
stop();
|
|
40
50
|
} else {
|
|
41
|
-
|
|
51
|
+
void run();
|
|
42
52
|
start();
|
|
43
53
|
}
|
|
44
54
|
};
|
|
45
55
|
if (!isHidden()) {
|
|
46
|
-
|
|
56
|
+
void run();
|
|
47
57
|
start();
|
|
48
58
|
}
|
|
49
59
|
document.addEventListener("visibilitychange", onVisibility);
|
|
@@ -216,7 +216,7 @@ function serviceOwnerForScope(
|
|
|
216
216
|
|
|
217
217
|
function authorizationSql(alias = ""): string {
|
|
218
218
|
const prefix = alias ? `${alias}.` : "";
|
|
219
|
-
return `((${prefix}org_id = ? AND ? IS NOT NULL) OR (${prefix}org_id IS NULL AND ${prefix}owner_email = ?))`;
|
|
219
|
+
return `((${prefix}org_id = ? AND CAST(? AS TEXT) IS NOT NULL) OR (${prefix}org_id IS NULL AND ${prefix}owner_email = ?))`;
|
|
220
220
|
}
|
|
221
221
|
|
|
222
222
|
function authorizationArgs(
|
|
@@ -232,7 +232,7 @@ function requirePeriod(
|
|
|
232
232
|
|
|
233
233
|
function authorizationSql(alias = ""): string {
|
|
234
234
|
const prefix = alias ? `${alias}.` : "";
|
|
235
|
-
return `((${prefix}subject_type = 'user' AND ${prefix}owner_email = ?) OR (${prefix}subject_type <> 'user' AND ((${prefix}org_id = ? AND ? IS NOT NULL) OR (${prefix}org_id IS NULL AND ${prefix}owner_email = ?))))`;
|
|
235
|
+
return `((${prefix}subject_type = 'user' AND ${prefix}owner_email = ?) OR (${prefix}subject_type <> 'user' AND ((${prefix}org_id = ? AND CAST(? AS TEXT) IS NOT NULL) OR (${prefix}org_id IS NULL AND ${prefix}owner_email = ?))))`;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
function authorizationArgs(
|