@agent-native/core 0.117.0 → 0.117.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 +16 -0
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/cli/context-xray-local.ts +1 -1
- package/corpus/core/src/client/extensions/ExtensionViewer.tsx +4 -4
- package/corpus/core/src/client/extensions/ExtensionsSidebarSection.tsx +11 -11
- package/corpus/core/src/client/extensions/agent-native-extension-runtime.ts +1 -1
- package/corpus/core/src/client/extensions/delete-extension.ts +2 -2
- package/corpus/core/src/client/org/OrgSwitcher.tsx +25 -1
- package/corpus/core/src/client/settings/SettingsPanel.tsx +102 -10
- package/corpus/core/src/client/sharing/ShareButton.tsx +7 -6
- package/corpus/core/src/db/client.ts +13 -10
- package/corpus/core/src/deploy/workspace-deploy.ts +14 -4
- package/corpus/core/src/extensions/actions.ts +13 -5
- package/corpus/core/src/extensions/local.ts +1 -0
- package/corpus/core/src/extensions/routes.ts +10 -5
- package/corpus/core/src/extensions/schema.ts +5 -0
- package/corpus/core/src/extensions/slots/store.ts +14 -4
- package/corpus/core/src/extensions/store.ts +55 -19
- package/corpus/core/src/extensions/theme.ts +1 -1
- package/corpus/core/src/file-upload/registry.ts +9 -0
- package/corpus/core/src/index.browser.ts +5 -0
- package/corpus/core/src/index.ts +1 -0
- package/corpus/core/src/localization/default-messages.ts +23 -6
- package/corpus/core/src/server/action-discovery.ts +8 -0
- package/corpus/core/src/server/better-auth-instance.ts +7 -2
- package/corpus/core/src/server/email-template.ts +18 -0
- package/corpus/core/src/server/email-templates.ts +3 -0
- package/corpus/core/src/server/email.ts +40 -4
- package/corpus/core/src/sharing/actions/share-resource.ts +1 -0
- package/corpus/core/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/core/src/templates/default/app/global.css +1 -1
- package/corpus/core/src/templates/default/app/i18n/ar-SA.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/de-DE.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/en-US.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/es-ES.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/fr-FR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/hi-IN.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/ja-JP.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/ko-KR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/pt-BR.ts +6 -6
- package/corpus/core/src/templates/default/app/i18n/zh-CN.ts +7 -7
- package/corpus/core/src/templates/default/app/i18n/zh-TW.ts +7 -7
- package/corpus/core/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/core/src/user-profile/actions/get-user-profile.ts +16 -0
- package/corpus/core/src/user-profile/actions/update-user-profile.ts +24 -0
- package/corpus/core/src/user-profile/index.ts +5 -0
- package/corpus/core/src/user-profile/shared.ts +14 -0
- package/corpus/core/src/user-profile/store.ts +50 -0
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/assets/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/assets/app/global.css +1 -1
- package/corpus/templates/assets/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/brain/app/global.css +2 -2
- package/corpus/templates/brain/app/lib/brain.ts +2 -2
- package/corpus/templates/brain/app/root.tsx +2 -2
- package/corpus/templates/brain/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +6 -2
- package/corpus/templates/calendar/app/global.css +1 -1
- package/corpus/templates/calendar/app/root.tsx +2 -2
- package/corpus/templates/calendar/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/chat/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/chat/app/global.css +1 -1
- package/corpus/templates/chat/app/root.tsx +2 -2
- package/corpus/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/clips/actions/export-to-brain.ts +1 -1
- package/corpus/templates/clips/actions/invite-member.ts +1 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +2 -2
- package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +20 -11
- package/corpus/templates/clips/app/global.css +1 -1
- package/corpus/templates/clips/app/root.tsx +7 -2
- package/corpus/templates/clips/app/routes/record.tsx +2 -88
- package/corpus/templates/clips/changelog/2026-07-22-builder-connected-recordings-start-resumable-upload-sessions.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-22-clip-thumbnails-now-come-from-the-recording-instead-of-the-p.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-22-clips-emails-now-render-the-agent-native-logo-in-gmail-and-o.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-22-dismissed-zoom-and-teams-meeting-note-prompts-now-stay-dismi.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-22-quieter-permissions-and-rewind-controls.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +86 -52
- package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +31 -0
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +4 -167
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +10 -1
- package/corpus/templates/clips/desktop/src/styles.css +98 -36
- package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +67 -4
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/meetings_watcher.rs +51 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +5 -1
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +0 -189
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +62 -0
- package/corpus/templates/clips/server/plugins/db.ts +6 -2
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +3 -3
- package/corpus/templates/content/app/global.css +1 -1
- package/corpus/templates/content/app/root.tsx +2 -2
- package/corpus/templates/content/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/crm/app/global.css +1 -1
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +19 -1
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +12 -1
- package/corpus/templates/design/app/components/design/EditPanel.tsx +177 -52
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +179 -59
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +74 -27
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +2 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/design/app/global.css +1 -1
- package/corpus/templates/design/app/hooks/use-navigation-state.ts +6 -5
- package/corpus/templates/design/app/root.tsx +2 -2
- package/corpus/templates/design/changelog/2026-07-22-design-owners-can-keep-editing-their-designs-after-switching.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-inspector-tabs-keep-their-text-labels-at-narrow-widths.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-narrow-breakpoint-previews-keep-their-device-labels-readable.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-removed-the-draft-status-chip-from-the-design-editor.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-responsive-breakpoint-controls-stay-within-narrow-sidebars.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-responsive-peers-now-use-a-softer-selection-highlight-withou.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-rotate-from-context-menu.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-the-selection-outline-now-stays-attached-while-moving-screen.md +6 -0
- package/corpus/templates/design/changelog/2026-07-22-view-only-designs-now-support-figma-style-layer-inspection-w.md +6 -0
- package/corpus/templates/design/server/db/index.ts +4 -0
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/dispatch/app/dispatch-extensions.tsx +2 -2
- package/corpus/templates/dispatch/app/global.css +1 -1
- package/corpus/templates/dispatch/app/root.tsx +2 -2
- package/corpus/templates/dispatch/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/forms/app/components/layout/Layout.tsx +1 -1
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +3 -3
- package/corpus/templates/forms/app/global.css +1 -1
- package/corpus/templates/forms/app/hooks/use-forms.ts +55 -2
- package/corpus/templates/forms/app/i18n/en-US.ts +2 -0
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +3 -3
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +23 -6
- package/corpus/templates/forms/app/root.tsx +2 -2
- package/corpus/templates/forms/changelog/2026-07-22-forms-now-archive-with-optimistic-feedback.md +6 -0
- package/corpus/templates/forms/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/macros/app/components/layout/AppLayout.tsx +2 -2
- package/corpus/templates/macros/app/root.tsx +2 -2
- package/corpus/templates/macros/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/mail/app/components/layout/AppLayout.tsx +3 -3
- package/corpus/templates/mail/app/components/layout/CommandPalette.tsx +2 -2
- package/corpus/templates/mail/app/global.css +1 -1
- package/corpus/templates/mail/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/plan/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/plan/app/global.css +1 -1
- package/corpus/templates/plan/app/root.tsx +2 -2
- package/corpus/templates/plan/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/slides/app/components/layout/Sidebar.tsx +2 -2
- package/corpus/templates/slides/app/root.tsx +2 -2
- package/corpus/templates/slides/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-22-slides-no-longer-fail-intermittently-on-fresh-server-instances.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-22-uploaded-screenshots-can-now-be-analyzed-and-recreated-as-ed.md +6 -0
- package/corpus/templates/slides/server/lib/chat-attachments.ts +7 -3
- package/corpus/templates/slides/server/plugins/db.ts +44 -17
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/corpus/templates/tasks/app/global.css +1 -1
- package/dist/cli/context-xray-local.js +1 -1
- package/dist/cli/context-xray-local.js.map +1 -1
- package/dist/client/extensions/ExtensionViewer.js +2 -2
- package/dist/client/extensions/ExtensionViewer.js.map +1 -1
- package/dist/client/extensions/ExtensionsSidebarSection.js +11 -11
- package/dist/client/extensions/ExtensionsSidebarSection.js.map +1 -1
- package/dist/client/extensions/agent-native-extension-runtime.js +1 -1
- package/dist/client/extensions/agent-native-extension-runtime.js.map +1 -1
- package/dist/client/extensions/delete-extension.d.ts +1 -1
- package/dist/client/extensions/delete-extension.d.ts.map +1 -1
- package/dist/client/extensions/delete-extension.js +1 -1
- package/dist/client/extensions/delete-extension.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts +3 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +12 -4
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +37 -4
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/sharing/ShareButton.d.ts +3 -4
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +3 -2
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/db/client.d.ts +7 -7
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +13 -10
- package/dist/db/client.js.map +1 -1
- package/dist/deploy/workspace-deploy.js +14 -4
- package/dist/deploy/workspace-deploy.js.map +1 -1
- package/dist/extensions/actions.d.ts.map +1 -1
- package/dist/extensions/actions.js +8 -5
- package/dist/extensions/actions.js.map +1 -1
- package/dist/extensions/local.d.ts.map +1 -1
- package/dist/extensions/local.js +1 -0
- package/dist/extensions/local.js.map +1 -1
- package/dist/extensions/routes.d.ts.map +1 -1
- package/dist/extensions/routes.js +9 -4
- package/dist/extensions/routes.js.map +1 -1
- package/dist/extensions/schema.d.ts +23 -2
- package/dist/extensions/schema.d.ts.map +1 -1
- package/dist/extensions/schema.js +5 -0
- package/dist/extensions/schema.js.map +1 -1
- package/dist/extensions/slots/store.d.ts +1 -1
- package/dist/extensions/slots/store.d.ts.map +1 -1
- package/dist/extensions/slots/store.js +4 -4
- package/dist/extensions/slots/store.js.map +1 -1
- package/dist/extensions/store.d.ts +1 -0
- package/dist/extensions/store.d.ts.map +1 -1
- package/dist/extensions/store.js +38 -21
- package/dist/extensions/store.js.map +1 -1
- package/dist/extensions/theme.js +1 -1
- package/dist/extensions/theme.js.map +1 -1
- package/dist/file-upload/registry.d.ts.map +1 -1
- package/dist/file-upload/registry.js +9 -0
- package/dist/file-upload/registry.js.map +1 -1
- package/dist/index.browser.d.ts +1 -0
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -0
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/localization/default-messages.d.ts +16 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +22 -6
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +8 -0
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/better-auth-instance.d.ts +7 -2
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/email-template.d.ts +3 -0
- package/dist/server/email-template.d.ts.map +1 -1
- package/dist/server/email-template.js +13 -0
- package/dist/server/email-template.js.map +1 -1
- package/dist/server/email-templates.d.ts.map +1 -1
- package/dist/server/email-templates.js +3 -0
- package/dist/server/email-templates.js.map +1 -1
- package/dist/server/email.d.ts.map +1 -1
- package/dist/server/email.js +27 -4
- package/dist/server/email.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/sharing/actions/share-resource.js +1 -0
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/dist/templates/chat/app/components/layout/Sidebar.tsx +2 -2
- package/dist/templates/chat/app/global.css +1 -1
- package/dist/templates/chat/app/root.tsx +2 -2
- package/dist/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/dist/templates/default/app/global.css +1 -1
- package/dist/templates/default/app/i18n/ar-SA.ts +6 -6
- package/dist/templates/default/app/i18n/de-DE.ts +6 -6
- package/dist/templates/default/app/i18n/en-US.ts +6 -6
- package/dist/templates/default/app/i18n/es-ES.ts +6 -6
- package/dist/templates/default/app/i18n/fr-FR.ts +6 -6
- package/dist/templates/default/app/i18n/hi-IN.ts +6 -6
- package/dist/templates/default/app/i18n/ja-JP.ts +6 -6
- package/dist/templates/default/app/i18n/ko-KR.ts +6 -6
- package/dist/templates/default/app/i18n/pt-BR.ts +6 -6
- package/dist/templates/default/app/i18n/zh-CN.ts +7 -7
- package/dist/templates/default/app/i18n/zh-TW.ts +7 -7
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/dist/user-profile/actions/get-user-profile.d.ts +4 -0
- package/dist/user-profile/actions/get-user-profile.d.ts.map +1 -0
- package/dist/user-profile/actions/get-user-profile.js +14 -0
- package/dist/user-profile/actions/get-user-profile.js.map +1 -0
- package/dist/user-profile/actions/update-user-profile.d.ts +6 -0
- package/dist/user-profile/actions/update-user-profile.d.ts.map +1 -0
- package/dist/user-profile/actions/update-user-profile.js +20 -0
- package/dist/user-profile/actions/update-user-profile.js.map +1 -0
- package/dist/user-profile/index.d.ts +2 -0
- package/dist/user-profile/index.d.ts.map +1 -0
- package/dist/user-profile/index.js +2 -0
- package/dist/user-profile/index.js.map +1 -0
- package/dist/user-profile/shared.d.ts +7 -0
- package/dist/user-profile/shared.d.ts.map +1 -0
- package/dist/user-profile/shared.js +6 -0
- package/dist/user-profile/shared.js.map +1 -0
- package/dist/user-profile/store.d.ts +4 -0
- package/dist/user-profile/store.d.ts.map +1 -0
- package/dist/user-profile/store.js +38 -0
- package/dist/user-profile/store.js.map +1 -0
- package/package.json +2 -1
- package/src/cli/context-xray-local.ts +1 -1
- package/src/client/extensions/ExtensionViewer.tsx +4 -4
- package/src/client/extensions/ExtensionsSidebarSection.tsx +11 -11
- package/src/client/extensions/agent-native-extension-runtime.ts +1 -1
- package/src/client/extensions/delete-extension.ts +2 -2
- package/src/client/org/OrgSwitcher.tsx +25 -1
- package/src/client/settings/SettingsPanel.tsx +102 -10
- package/src/client/sharing/ShareButton.tsx +7 -6
- package/src/db/client.ts +13 -10
- package/src/deploy/workspace-deploy.ts +14 -4
- package/src/extensions/actions.ts +13 -5
- package/src/extensions/local.ts +1 -0
- package/src/extensions/routes.ts +10 -5
- package/src/extensions/schema.ts +5 -0
- package/src/extensions/slots/store.ts +14 -4
- package/src/extensions/store.ts +55 -19
- package/src/extensions/theme.ts +1 -1
- package/src/file-upload/registry.ts +9 -0
- package/src/index.browser.ts +5 -0
- package/src/index.ts +1 -0
- package/src/localization/default-messages.ts +23 -6
- package/src/server/action-discovery.ts +8 -0
- package/src/server/better-auth-instance.ts +7 -2
- package/src/server/email-template.ts +18 -0
- package/src/server/email-templates.ts +3 -0
- package/src/server/email.ts +40 -4
- package/src/sharing/actions/share-resource.ts +1 -0
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/src/templates/chat/app/components/layout/Sidebar.tsx +2 -2
- package/src/templates/chat/app/global.css +1 -1
- package/src/templates/chat/app/root.tsx +2 -2
- package/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +6 -0
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/src/templates/default/app/global.css +1 -1
- package/src/templates/default/app/i18n/ar-SA.ts +6 -6
- package/src/templates/default/app/i18n/de-DE.ts +6 -6
- package/src/templates/default/app/i18n/en-US.ts +6 -6
- package/src/templates/default/app/i18n/es-ES.ts +6 -6
- package/src/templates/default/app/i18n/fr-FR.ts +6 -6
- package/src/templates/default/app/i18n/hi-IN.ts +6 -6
- package/src/templates/default/app/i18n/ja-JP.ts +6 -6
- package/src/templates/default/app/i18n/ko-KR.ts +6 -6
- package/src/templates/default/app/i18n/pt-BR.ts +6 -6
- package/src/templates/default/app/i18n/zh-CN.ts +7 -7
- package/src/templates/default/app/i18n/zh-TW.ts +7 -7
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +6 -0
- package/src/user-profile/actions/get-user-profile.ts +16 -0
- package/src/user-profile/actions/update-user-profile.ts +24 -0
- package/src/user-profile/index.ts +5 -0
- package/src/user-profile/shared.ts +14 -0
- package/src/user-profile/store.ts +50 -0
|
@@ -56,6 +56,38 @@ struct AdhocMeetingsWatcherInner {
|
|
|
56
56
|
session_notified: HashMap<String, bool>,
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
impl AdhocMeetingsWatcherInner {
|
|
60
|
+
fn refresh_suppression(&mut self, platform: &str, now_ts: i64) {
|
|
61
|
+
self.session_notified.insert(platform.to_string(), true);
|
|
62
|
+
self.cooldown_until
|
|
63
|
+
.insert(platform.to_string(), now_ts + COOLDOWN_SECS);
|
|
64
|
+
self.dwell_platform = None;
|
|
65
|
+
self.dwell_since = None;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
fn is_suppressed(&self, platform: &str, now_ts: i64) -> bool {
|
|
69
|
+
self.cooldown_until.get(platform).copied().unwrap_or(0) > now_ts
|
|
70
|
+
|| self
|
|
71
|
+
.session_notified
|
|
72
|
+
.get(platform)
|
|
73
|
+
.copied()
|
|
74
|
+
.unwrap_or(false)
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
pub fn refresh_dismissal_suppression(app: &AppHandle, platform: &str) -> Result<(), String> {
|
|
79
|
+
let platform = platform.trim().to_lowercase();
|
|
80
|
+
if platform.is_empty() {
|
|
81
|
+
return Ok(());
|
|
82
|
+
}
|
|
83
|
+
let state = app
|
|
84
|
+
.try_state::<AdhocMeetingsWatcherState>()
|
|
85
|
+
.ok_or_else(|| "no AdhocMeetingsWatcherState".to_string())?;
|
|
86
|
+
let mut g = state.inner.lock().map_err(|e| e.to_string())?;
|
|
87
|
+
g.refresh_suppression(&platform, chrono::Utc::now().timestamp());
|
|
88
|
+
Ok(())
|
|
89
|
+
}
|
|
90
|
+
|
|
59
91
|
/// Spawn the long-running adhoc watcher. Idempotent — gated by OnceLock.
|
|
60
92
|
pub fn spawn_watcher(app: AppHandle) {
|
|
61
93
|
use std::sync::OnceLock;
|
|
@@ -170,10 +202,7 @@ async fn tick_macos(
|
|
|
170
202
|
// Prune expired cooldowns.
|
|
171
203
|
g.cooldown_until.retain(|_, until| *until > now_ts);
|
|
172
204
|
|
|
173
|
-
if g.
|
|
174
|
-
return Ok(());
|
|
175
|
-
}
|
|
176
|
-
if g.session_notified.get(platform).copied().unwrap_or(false) {
|
|
205
|
+
if g.is_suppressed(platform, now_ts) {
|
|
177
206
|
return Ok(());
|
|
178
207
|
}
|
|
179
208
|
|
|
@@ -263,6 +292,40 @@ async fn tick_macos(
|
|
|
263
292
|
Ok(())
|
|
264
293
|
}
|
|
265
294
|
|
|
295
|
+
#[cfg(test)]
|
|
296
|
+
mod tests {
|
|
297
|
+
use super::*;
|
|
298
|
+
|
|
299
|
+
#[test]
|
|
300
|
+
fn dismissal_refreshes_the_existing_cooldown_and_clears_dwell() {
|
|
301
|
+
let now_ts = 1_000;
|
|
302
|
+
let mut state = AdhocMeetingsWatcherInner {
|
|
303
|
+
dwell_platform: Some("zoom".to_string()),
|
|
304
|
+
dwell_since: Some(Instant::now()),
|
|
305
|
+
..Default::default()
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
state.refresh_suppression("zoom", now_ts);
|
|
309
|
+
state.session_notified.remove("zoom");
|
|
310
|
+
|
|
311
|
+
assert!(state.is_suppressed("zoom", now_ts + COOLDOWN_SECS - 1));
|
|
312
|
+
assert!(!state.is_suppressed("zoom", now_ts + COOLDOWN_SECS));
|
|
313
|
+
assert_eq!(state.dwell_platform, None);
|
|
314
|
+
assert_eq!(state.dwell_since, None);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
#[test]
|
|
318
|
+
fn dismissal_suppression_remains_platform_scoped() {
|
|
319
|
+
let now_ts = 1_000;
|
|
320
|
+
let mut state = AdhocMeetingsWatcherInner::default();
|
|
321
|
+
|
|
322
|
+
state.refresh_suppression("zoom", now_ts);
|
|
323
|
+
|
|
324
|
+
assert!(state.is_suppressed("zoom", now_ts));
|
|
325
|
+
assert!(!state.is_suppressed("teams", now_ts));
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
266
329
|
fn reset_dwell(app: &AppHandle) {
|
|
267
330
|
if let Some(state) = app.try_state::<AdhocMeetingsWatcherState>() {
|
|
268
331
|
if let Ok(mut g) = state.inner.lock() {
|
|
@@ -147,7 +147,6 @@ pub fn run() {
|
|
|
147
147
|
native_screen::native_fullscreen_claim_upload_open,
|
|
148
148
|
native_screen::native_fullscreen_recording_warm,
|
|
149
149
|
native_screen::native_fullscreen_recording_begin,
|
|
150
|
-
native_screen::native_fullscreen_capture_thumbnail,
|
|
151
150
|
native_screen::native_fullscreen_recording_stop_and_upload,
|
|
152
151
|
native_screen::native_fullscreen_recording_stop_and_save,
|
|
153
152
|
native_screen::native_fullscreen_recording_cancel,
|
|
@@ -204,6 +203,7 @@ pub fn run() {
|
|
|
204
203
|
// notifications
|
|
205
204
|
notifications::take_pending_meeting_notification,
|
|
206
205
|
notifications::notify_meeting_starting,
|
|
206
|
+
notifications::dismiss_meeting_notification,
|
|
207
207
|
// meetings watcher (background poller)
|
|
208
208
|
meetings_watcher::meetings_watcher_set_server_url,
|
|
209
209
|
meetings_watcher::meetings_watcher_set_session,
|
|
@@ -145,6 +145,8 @@ struct MeetingItem {
|
|
|
145
145
|
join_url: Option<String>,
|
|
146
146
|
#[serde(default)]
|
|
147
147
|
platform: Option<String>,
|
|
148
|
+
#[serde(default)]
|
|
149
|
+
source: Option<String>,
|
|
148
150
|
}
|
|
149
151
|
|
|
150
152
|
#[derive(Debug, Deserialize)]
|
|
@@ -345,6 +347,9 @@ async fn tick_once(app: &AppHandle, client: &reqwest::Client) -> Result<(), Stri
|
|
|
345
347
|
let now = chrono::Utc::now();
|
|
346
348
|
let now_ts = now.timestamp();
|
|
347
349
|
for m in meetings {
|
|
350
|
+
if !is_calendar_reminder_candidate(&m) {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
348
353
|
let Some(start_str) = m.scheduled_start.as_deref() else {
|
|
349
354
|
continue;
|
|
350
355
|
};
|
|
@@ -445,6 +450,10 @@ async fn tick_once(app: &AppHandle, client: &reqwest::Client) -> Result<(), Stri
|
|
|
445
450
|
Ok(())
|
|
446
451
|
}
|
|
447
452
|
|
|
453
|
+
fn is_calendar_reminder_candidate(meeting: &MeetingItem) -> bool {
|
|
454
|
+
meeting.source.as_deref() != Some("adhoc")
|
|
455
|
+
}
|
|
456
|
+
|
|
448
457
|
fn parse_meetings(body: &serde_json::Value) -> Vec<MeetingItem> {
|
|
449
458
|
if let Ok(parsed) = serde_json::from_value::<ListMeetingsResponse>(body.clone()) {
|
|
450
459
|
if let Some(v) = parsed.upcoming {
|
|
@@ -462,3 +471,45 @@ fn parse_meetings(body: &serde_json::Value) -> Vec<MeetingItem> {
|
|
|
462
471
|
}
|
|
463
472
|
Vec::new()
|
|
464
473
|
}
|
|
474
|
+
|
|
475
|
+
#[cfg(test)]
|
|
476
|
+
mod tests {
|
|
477
|
+
use super::{is_calendar_reminder_candidate, parse_meetings};
|
|
478
|
+
|
|
479
|
+
#[test]
|
|
480
|
+
fn excludes_adhoc_meetings_from_calendar_reminders() {
|
|
481
|
+
let meetings = parse_meetings(&serde_json::json!({
|
|
482
|
+
"meetings": [
|
|
483
|
+
{
|
|
484
|
+
"id": "adhoc-meeting",
|
|
485
|
+
"scheduledStart": "2026-07-22T19:10:00Z",
|
|
486
|
+
"source": "adhoc"
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
"id": "calendar-meeting",
|
|
490
|
+
"scheduledStart": "2026-07-22T19:10:00Z",
|
|
491
|
+
"source": "calendar"
|
|
492
|
+
}
|
|
493
|
+
]
|
|
494
|
+
}));
|
|
495
|
+
|
|
496
|
+
assert_eq!(meetings.len(), 2);
|
|
497
|
+
assert!(!is_calendar_reminder_candidate(&meetings[0]));
|
|
498
|
+
assert!(is_calendar_reminder_candidate(&meetings[1]));
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
#[test]
|
|
502
|
+
fn keeps_meetings_without_source_eligible_for_legacy_payloads() {
|
|
503
|
+
let meetings = parse_meetings(&serde_json::json!({
|
|
504
|
+
"meetings": [
|
|
505
|
+
{
|
|
506
|
+
"id": "legacy-meeting",
|
|
507
|
+
"scheduledStart": "2026-07-22T19:10:00Z"
|
|
508
|
+
}
|
|
509
|
+
]
|
|
510
|
+
}));
|
|
511
|
+
|
|
512
|
+
assert_eq!(meetings.len(), 1);
|
|
513
|
+
assert!(is_calendar_reminder_candidate(&meetings[0]));
|
|
514
|
+
}
|
|
515
|
+
}
|
|
@@ -2629,7 +2629,11 @@ fn decode_samples_to_f32(bytes: &[u8], is_float: bool, bits: u32) -> Vec<f32> {
|
|
|
2629
2629
|
.map(|c| {
|
|
2630
2630
|
// Reconstruct a 24-bit little-endian signed integer and sign-extend to i32.
|
|
2631
2631
|
let raw = (c[0] as i32) | ((c[1] as i32) << 8) | ((c[2] as i32) << 16);
|
|
2632
|
-
let signed = if raw & 0x800000 != 0 {
|
|
2632
|
+
let signed = if raw & 0x800000 != 0 {
|
|
2633
|
+
raw | !0x00FF_FFFFi32
|
|
2634
|
+
} else {
|
|
2635
|
+
raw
|
|
2636
|
+
};
|
|
2633
2637
|
signed as f32 / 8_388_608.0
|
|
2634
2638
|
})
|
|
2635
2639
|
.collect(),
|
|
@@ -155,10 +155,6 @@ const FFMPEG_CANDIDATE_PATHS: &[&str] = &[
|
|
|
155
155
|
];
|
|
156
156
|
const PENDING_UPLOADS_DIR: &str = "pending-recording-uploads";
|
|
157
157
|
const CLIP_DRAFTS_DIR: &str = "Drafts";
|
|
158
|
-
const THUMBNAIL_MIME_TYPE: &str = "image/jpeg";
|
|
159
|
-
const THUMBNAIL_MAX_BYTES: u64 = 2 * 1024 * 1024;
|
|
160
|
-
const THUMBNAIL_WIDTH: &str = "1280";
|
|
161
|
-
const SIPS_PATH: &str = "/usr/bin/sips";
|
|
162
158
|
// Minimum free space required to start recording; below this we hard-block.
|
|
163
159
|
pub(crate) const DISK_SPACE_BLOCK_BYTES: u64 = 500 * 1024 * 1024;
|
|
164
160
|
// Free space below this at start time is logged as a warning but not blocked.
|
|
@@ -2018,31 +2014,6 @@ pub async fn native_fullscreen_recording_stop_and_save(
|
|
|
2018
2014
|
save_finalized_native_artifact_to_local_export(&app, &artifact, &folder_name, &file_role)
|
|
2019
2015
|
}
|
|
2020
2016
|
|
|
2021
|
-
#[tauri::command]
|
|
2022
|
-
pub async fn native_fullscreen_capture_thumbnail(
|
|
2023
|
-
app: AppHandle,
|
|
2024
|
-
server_url: String,
|
|
2025
|
-
recording_id: String,
|
|
2026
|
-
auth_token: Option<String>,
|
|
2027
|
-
cookie: Option<String>,
|
|
2028
|
-
) -> Result<(), String> {
|
|
2029
|
-
let bytes = capture_thumbnail_bytes(&app, &recording_id)?;
|
|
2030
|
-
tauri::async_runtime::spawn(async move {
|
|
2031
|
-
if let Err(err) = upload_thumbnail_bytes(
|
|
2032
|
-
server_url,
|
|
2033
|
-
recording_id.clone(),
|
|
2034
|
-
auth_token.unwrap_or_default(),
|
|
2035
|
-
cookie.unwrap_or_default(),
|
|
2036
|
-
bytes,
|
|
2037
|
-
)
|
|
2038
|
-
.await
|
|
2039
|
-
{
|
|
2040
|
-
eprintln!("[clips-tray] native thumbnail upload failed for {recording_id}: {err}");
|
|
2041
|
-
}
|
|
2042
|
-
});
|
|
2043
|
-
Ok(())
|
|
2044
|
-
}
|
|
2045
|
-
|
|
2046
2017
|
/// Called from the app's exit path (tray Quit / Cmd+Q) so a live `screencapture`
|
|
2047
2018
|
/// fallback process doesn't survive the app quitting. `app.exit()` triggers
|
|
2048
2019
|
/// `std::process::exit` under the hood, which does not run Rust destructors,
|
|
@@ -3455,117 +3426,6 @@ fn saved_recording_metadata_path(app: &AppHandle, recording_id: &str) -> Result<
|
|
|
3455
3426
|
Ok(pending_uploads_dir(app)?.join(format!("{safe_id}.json")))
|
|
3456
3427
|
}
|
|
3457
3428
|
|
|
3458
|
-
fn thumbnail_path(app: &AppHandle, recording_id: &str) -> Result<PathBuf, String> {
|
|
3459
|
-
let safe_id = sanitize_recording_id(recording_id);
|
|
3460
|
-
pending_recording_path(app, &format!("{safe_id}-thumb"), "jpg")
|
|
3461
|
-
}
|
|
3462
|
-
|
|
3463
|
-
fn resized_thumbnail_path(path: &Path) -> PathBuf {
|
|
3464
|
-
let stem = path
|
|
3465
|
-
.file_stem()
|
|
3466
|
-
.and_then(|value| value.to_str())
|
|
3467
|
-
.unwrap_or("thumbnail");
|
|
3468
|
-
path.with_file_name(format!("{stem}-1280.jpg"))
|
|
3469
|
-
}
|
|
3470
|
-
|
|
3471
|
-
fn thumbnail_file_for_upload(path: &Path) -> Result<PathBuf, String> {
|
|
3472
|
-
let original_bytes = std::fs::metadata(path)
|
|
3473
|
-
.map_err(|e| format!("thumbnail metadata unavailable: {e}"))?
|
|
3474
|
-
.len();
|
|
3475
|
-
if original_bytes <= THUMBNAIL_MAX_BYTES || !std::path::Path::new(SIPS_PATH).exists() {
|
|
3476
|
-
return Ok(path.to_path_buf());
|
|
3477
|
-
}
|
|
3478
|
-
|
|
3479
|
-
let resized_path = resized_thumbnail_path(path);
|
|
3480
|
-
let _ = std::fs::remove_file(&resized_path);
|
|
3481
|
-
let status = Command::new(SIPS_PATH)
|
|
3482
|
-
.arg("--resampleWidth")
|
|
3483
|
-
.arg(THUMBNAIL_WIDTH)
|
|
3484
|
-
.arg("--setProperty")
|
|
3485
|
-
.arg("format")
|
|
3486
|
-
.arg("jpeg")
|
|
3487
|
-
.arg("--setProperty")
|
|
3488
|
-
.arg("formatOptions")
|
|
3489
|
-
.arg("85")
|
|
3490
|
-
.arg(path)
|
|
3491
|
-
.arg("--out")
|
|
3492
|
-
.arg(&resized_path)
|
|
3493
|
-
.stdin(Stdio::null())
|
|
3494
|
-
.stdout(Stdio::null())
|
|
3495
|
-
.stderr(Stdio::null())
|
|
3496
|
-
.status()
|
|
3497
|
-
.map_err(|e| format!("thumbnail resize failed: {e}"))?;
|
|
3498
|
-
|
|
3499
|
-
if !status.success() {
|
|
3500
|
-
let _ = std::fs::remove_file(&resized_path);
|
|
3501
|
-
return Ok(path.to_path_buf());
|
|
3502
|
-
}
|
|
3503
|
-
|
|
3504
|
-
let resized_bytes = std::fs::metadata(&resized_path)
|
|
3505
|
-
.map_err(|e| format!("resized thumbnail metadata unavailable: {e}"))?
|
|
3506
|
-
.len();
|
|
3507
|
-
if resized_bytes == 0 || resized_bytes > original_bytes {
|
|
3508
|
-
let _ = std::fs::remove_file(&resized_path);
|
|
3509
|
-
return Ok(path.to_path_buf());
|
|
3510
|
-
}
|
|
3511
|
-
|
|
3512
|
-
Ok(resized_path)
|
|
3513
|
-
}
|
|
3514
|
-
|
|
3515
|
-
fn capture_thumbnail_bytes(app: &AppHandle, recording_id: &str) -> Result<Vec<u8>, String> {
|
|
3516
|
-
#[cfg(not(target_os = "macos"))]
|
|
3517
|
-
{
|
|
3518
|
-
let _ = (app, recording_id);
|
|
3519
|
-
Err("Native full-screen thumbnails are currently macOS-only.".into())
|
|
3520
|
-
}
|
|
3521
|
-
|
|
3522
|
-
#[cfg(target_os = "macos")]
|
|
3523
|
-
{
|
|
3524
|
-
if !std::path::Path::new("/usr/sbin/screencapture").exists() {
|
|
3525
|
-
return Err("macOS screencapture is unavailable on this machine.".into());
|
|
3526
|
-
}
|
|
3527
|
-
|
|
3528
|
-
let path = thumbnail_path(app, recording_id)?;
|
|
3529
|
-
let _ = std::fs::remove_file(&path);
|
|
3530
|
-
let thumb_display_flag = tray_display_id(app)
|
|
3531
|
-
.and_then(|id| {
|
|
3532
|
-
CGDisplay::active_displays().ok().and_then(|ids| {
|
|
3533
|
-
ids.iter()
|
|
3534
|
-
.position(|&aid| aid == id)
|
|
3535
|
-
.map(|p| format!("-D{}", p + 1))
|
|
3536
|
-
})
|
|
3537
|
-
})
|
|
3538
|
-
.unwrap_or_else(|| "-D1".to_string());
|
|
3539
|
-
let status = Command::new("/usr/sbin/screencapture")
|
|
3540
|
-
.arg("-x")
|
|
3541
|
-
.arg("-t")
|
|
3542
|
-
.arg("jpg")
|
|
3543
|
-
.arg(thumb_display_flag)
|
|
3544
|
-
.arg(&path)
|
|
3545
|
-
.stdin(Stdio::null())
|
|
3546
|
-
.stdout(Stdio::null())
|
|
3547
|
-
.stderr(Stdio::null())
|
|
3548
|
-
.status()
|
|
3549
|
-
.map_err(|e| format!("thumbnail capture failed: {e}"))?;
|
|
3550
|
-
if !status.success() {
|
|
3551
|
-
let _ = std::fs::remove_file(&path);
|
|
3552
|
-
return Err(format!("thumbnail capture exited with {status}"));
|
|
3553
|
-
}
|
|
3554
|
-
|
|
3555
|
-
let upload_path = thumbnail_file_for_upload(&path)?;
|
|
3556
|
-
let bytes =
|
|
3557
|
-
std::fs::read(&upload_path).map_err(|e| format!("thumbnail read failed: {e}"))?;
|
|
3558
|
-
if upload_path != path {
|
|
3559
|
-
let _ = std::fs::remove_file(&upload_path);
|
|
3560
|
-
}
|
|
3561
|
-
let _ = std::fs::remove_file(&path);
|
|
3562
|
-
if bytes.is_empty() {
|
|
3563
|
-
return Err("Thumbnail capture produced an empty file.".into());
|
|
3564
|
-
}
|
|
3565
|
-
Ok(bytes)
|
|
3566
|
-
}
|
|
3567
|
-
}
|
|
3568
|
-
|
|
3569
3429
|
fn saved_recording_from_session(
|
|
3570
3430
|
session: &NativeFullscreenSession,
|
|
3571
3431
|
server_url: &str,
|
|
@@ -4767,55 +4627,6 @@ async fn reset_upload_chunks(
|
|
|
4767
4627
|
Ok(NativeUploadMode::from_reset_response(&body))
|
|
4768
4628
|
}
|
|
4769
4629
|
|
|
4770
|
-
async fn upload_thumbnail_bytes(
|
|
4771
|
-
server_url: String,
|
|
4772
|
-
recording_id: String,
|
|
4773
|
-
auth_token: String,
|
|
4774
|
-
cookie: String,
|
|
4775
|
-
bytes: Vec<u8>,
|
|
4776
|
-
) -> Result<(), String> {
|
|
4777
|
-
let url = thumbnail_upload_url(&server_url, &recording_id)?;
|
|
4778
|
-
let client = reqwest::Client::builder()
|
|
4779
|
-
.timeout(Duration::from_secs(30))
|
|
4780
|
-
.build()
|
|
4781
|
-
.map_err(|e| format!("thumbnail upload client failed: {e}"))?;
|
|
4782
|
-
let mut request = client
|
|
4783
|
-
.post(url)
|
|
4784
|
-
.header("Content-Type", THUMBNAIL_MIME_TYPE)
|
|
4785
|
-
.header("X-Request-Source", "clips-desktop")
|
|
4786
|
-
.body(bytes);
|
|
4787
|
-
let trimmed_token = auth_token.trim();
|
|
4788
|
-
if !trimmed_token.is_empty() {
|
|
4789
|
-
request = request.bearer_auth(trimmed_token);
|
|
4790
|
-
}
|
|
4791
|
-
let trimmed_cookie = cookie.trim();
|
|
4792
|
-
if !trimmed_cookie.is_empty() {
|
|
4793
|
-
request = request.header("Cookie", trimmed_cookie);
|
|
4794
|
-
}
|
|
4795
|
-
|
|
4796
|
-
let response = request
|
|
4797
|
-
.send()
|
|
4798
|
-
.await
|
|
4799
|
-
.map_err(|e| format!("native thumbnail upload failed: {e}"))?;
|
|
4800
|
-
let status = response.status();
|
|
4801
|
-
let body = response.text().await.unwrap_or_default();
|
|
4802
|
-
if !status.is_success() {
|
|
4803
|
-
return Err(format!(
|
|
4804
|
-
"native thumbnail upload returned {status}: {}",
|
|
4805
|
-
body.chars().take(400).collect::<String>()
|
|
4806
|
-
));
|
|
4807
|
-
}
|
|
4808
|
-
Ok(())
|
|
4809
|
-
}
|
|
4810
|
-
|
|
4811
|
-
fn thumbnail_upload_url(server_url: &str, recording_id: &str) -> Result<url::Url, String> {
|
|
4812
|
-
let base = server_url.trim_end_matches('/');
|
|
4813
|
-
url::Url::parse(&format!(
|
|
4814
|
-
"{base}/api/recordings/{recording_id}/thumbnail?replace=auto"
|
|
4815
|
-
))
|
|
4816
|
-
.map_err(|e| format!("invalid thumbnail upload URL: {e}"))
|
|
4817
|
-
}
|
|
4818
|
-
|
|
4819
4630
|
async fn send_upload_post(
|
|
4820
4631
|
client: &reqwest::Client,
|
|
4821
4632
|
server_url: &str,
|
|
@@ -194,6 +194,50 @@ pub fn take_pending_meeting_notification(app: AppHandle) -> Result<Option<Value>
|
|
|
194
194
|
Ok(pending.take())
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
fn clear_pending_notification(pending: &mut Option<Value>, meeting_id: &str) -> bool {
|
|
198
|
+
let matches = pending
|
|
199
|
+
.as_ref()
|
|
200
|
+
.and_then(|payload| payload.get("meetingId"))
|
|
201
|
+
.and_then(Value::as_str)
|
|
202
|
+
== Some(meeting_id);
|
|
203
|
+
if matches {
|
|
204
|
+
*pending = None;
|
|
205
|
+
}
|
|
206
|
+
matches
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
#[tauri::command]
|
|
210
|
+
pub fn dismiss_meeting_notification(
|
|
211
|
+
app: AppHandle,
|
|
212
|
+
meeting_id: String,
|
|
213
|
+
notification_type: String,
|
|
214
|
+
platform: Option<String>,
|
|
215
|
+
scheduled_start: Option<String>,
|
|
216
|
+
scheduled_end: Option<String>,
|
|
217
|
+
) -> Result<(), String> {
|
|
218
|
+
let state = app.state::<MeetingNotificationState>();
|
|
219
|
+
let mut pending = state
|
|
220
|
+
.0
|
|
221
|
+
.lock()
|
|
222
|
+
.map_err(|_| "meeting notification state lock poisoned".to_string())?;
|
|
223
|
+
clear_pending_notification(&mut pending, &meeting_id);
|
|
224
|
+
drop(pending);
|
|
225
|
+
|
|
226
|
+
if let Some(platform) = platform.as_deref() {
|
|
227
|
+
crate::adhoc_meetings_watcher::refresh_dismissal_suppression(&app, platform)?;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
dlog!(
|
|
231
|
+
"[clips-tray] meeting notification dismissed type={} id={} platform={:?} start={:?} end={:?}",
|
|
232
|
+
notification_type,
|
|
233
|
+
meeting_id,
|
|
234
|
+
platform,
|
|
235
|
+
scheduled_start,
|
|
236
|
+
scheduled_end
|
|
237
|
+
);
|
|
238
|
+
Ok(())
|
|
239
|
+
}
|
|
240
|
+
|
|
197
241
|
fn format_time_range_subtitle(
|
|
198
242
|
scheduled_start: Option<&str>,
|
|
199
243
|
scheduled_end: Option<&str>,
|
|
@@ -285,3 +329,21 @@ pub async fn notify_meeting_starting(
|
|
|
285
329
|
|
|
286
330
|
Ok(())
|
|
287
331
|
}
|
|
332
|
+
|
|
333
|
+
#[cfg(test)]
|
|
334
|
+
mod tests {
|
|
335
|
+
use super::*;
|
|
336
|
+
|
|
337
|
+
#[test]
|
|
338
|
+
fn clears_only_the_matching_pending_notification() {
|
|
339
|
+
let mut pending = Some(serde_json::json!({
|
|
340
|
+
"meetingId": "meeting-1",
|
|
341
|
+
"type": "adhoc"
|
|
342
|
+
}));
|
|
343
|
+
|
|
344
|
+
assert!(!clear_pending_notification(&mut pending, "meeting-2"));
|
|
345
|
+
assert!(pending.is_some());
|
|
346
|
+
assert!(clear_pending_notification(&mut pending, "meeting-1"));
|
|
347
|
+
assert!(pending.is_none());
|
|
348
|
+
}
|
|
349
|
+
}
|
|
@@ -1280,7 +1280,9 @@ function rowNumber(value: unknown): number {
|
|
|
1280
1280
|
* rows forever. We only delete sessions whose recording row is gone, or whose
|
|
1281
1281
|
* recording reached a terminal status more than an hour ago. Abandoned browser
|
|
1282
1282
|
* uploads can leave the recording stuck in `uploading`, so those are swept only
|
|
1283
|
-
* after a much longer grace window.
|
|
1283
|
+
* after a much longer grace window. Resumable session activity is the heartbeat
|
|
1284
|
+
* for in-progress uploads because streaming chunks do not update the recording
|
|
1285
|
+
* row on every provider relay.
|
|
1284
1286
|
*/
|
|
1285
1287
|
async function sweepOrphanedResumableSessions(): Promise<void> {
|
|
1286
1288
|
const exec = getDbExec();
|
|
@@ -1331,6 +1333,8 @@ async function sweepOrphanedResumableSessions(): Promise<void> {
|
|
|
1331
1333
|
if (!key.startsWith(prefix)) continue;
|
|
1332
1334
|
const recordingId = key.slice(prefix.length);
|
|
1333
1335
|
if (!recordingId) continue;
|
|
1336
|
+
const sessionUpdatedAt =
|
|
1337
|
+
typeof row.updated_at === "string" ? row.updated_at : "";
|
|
1334
1338
|
|
|
1335
1339
|
let shouldSweep = false;
|
|
1336
1340
|
try {
|
|
@@ -1353,7 +1357,7 @@ async function sweepOrphanedResumableSessions(): Promise<void> {
|
|
|
1353
1357
|
} else if (
|
|
1354
1358
|
(recording.status === "uploading" ||
|
|
1355
1359
|
recording.status === "processing") &&
|
|
1356
|
-
(recording.updated_at
|
|
1360
|
+
(sessionUpdatedAt || recording.updated_at || "") < staleInProgressIso
|
|
1357
1361
|
) {
|
|
1358
1362
|
try {
|
|
1359
1363
|
await exec.execute({
|
|
@@ -59,6 +59,12 @@ quick controls and deep links such as:
|
|
|
59
59
|
- `/settings/usage`
|
|
60
60
|
- `/settings/apps/:appId`
|
|
61
61
|
|
|
62
|
+
The shared Account section is the canonical profile surface at
|
|
63
|
+
`/settings#account`. It owns the editable display name and existing avatar
|
|
64
|
+
control through the authenticated `get-user-profile` and `update-user-profile`
|
|
65
|
+
actions. Shared workspace chrome such as `OrgSwitcher` should link to this
|
|
66
|
+
surface rather than creating an app-local profile page.
|
|
67
|
+
|
|
62
68
|
When adding a new API key, OAuth grant, provider connection, model selector, app
|
|
63
69
|
preference, notification preference, or usage/billing surface, register it as a
|
|
64
70
|
settings tab or app settings panel first. Only add sidebar UI when it is needed
|
|
@@ -36,7 +36,7 @@ import type {
|
|
|
36
36
|
} from "@shared/api";
|
|
37
37
|
import { CONTENT_DATABASE_PERSONAL_VIEW_OVERRIDES_VERSION } from "@shared/api";
|
|
38
38
|
import {
|
|
39
|
-
|
|
39
|
+
IconHierarchy2,
|
|
40
40
|
IconFolder,
|
|
41
41
|
IconFolderOpen,
|
|
42
42
|
IconPlus,
|
|
@@ -1282,7 +1282,7 @@ export function DocumentSidebar({
|
|
|
1282
1282
|
: "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
|
|
1283
1283
|
)}
|
|
1284
1284
|
>
|
|
1285
|
-
<
|
|
1285
|
+
<IconHierarchy2 size={15} className="shrink-0" />
|
|
1286
1286
|
<span className="min-w-0 flex-1 truncate text-start">
|
|
1287
1287
|
{t("navigation.agent")}
|
|
1288
1288
|
</span>
|
|
@@ -1849,7 +1849,7 @@ export function DocumentSidebar({
|
|
|
1849
1849
|
: "text-muted-foreground hover:text-foreground",
|
|
1850
1850
|
)}
|
|
1851
1851
|
>
|
|
1852
|
-
<
|
|
1852
|
+
<IconHierarchy2 size={16} />
|
|
1853
1853
|
</Link>
|
|
1854
1854
|
</TooltipTrigger>
|
|
1855
1855
|
<TooltipContent>{t("navigation.agent")}</TooltipContent>
|
|
@@ -26,7 +26,7 @@ import type { ListContentDatabasesResponse } from "@shared/api";
|
|
|
26
26
|
import {
|
|
27
27
|
IconDatabase,
|
|
28
28
|
IconDeviceDesktop,
|
|
29
|
-
|
|
29
|
+
IconHierarchy2,
|
|
30
30
|
IconFileText,
|
|
31
31
|
IconFolderOpen,
|
|
32
32
|
IconLoader2,
|
|
@@ -539,7 +539,7 @@ function ContentCommandMenu({
|
|
|
539
539
|
>
|
|
540
540
|
<CommandMenu.Group heading={t("root.commandContent")}>
|
|
541
541
|
<CommandMenu.Item onSelect={() => navigate("/agent")}>
|
|
542
|
-
<
|
|
542
|
+
<IconHierarchy2 size={16} />
|
|
543
543
|
{t("root.openAgent")}
|
|
544
544
|
</CommandMenu.Item>
|
|
545
545
|
</CommandMenu.Group>
|
|
@@ -59,6 +59,12 @@ quick controls and deep links such as:
|
|
|
59
59
|
- `/settings/usage`
|
|
60
60
|
- `/settings/apps/:appId`
|
|
61
61
|
|
|
62
|
+
The shared Account section is the canonical profile surface at
|
|
63
|
+
`/settings#account`. It owns the editable display name and existing avatar
|
|
64
|
+
control through the authenticated `get-user-profile` and `update-user-profile`
|
|
65
|
+
actions. Shared workspace chrome such as `OrgSwitcher` should link to this
|
|
66
|
+
surface rather than creating an app-local profile page.
|
|
67
|
+
|
|
62
68
|
When adding a new API key, OAuth grant, provider connection, model selector, app
|
|
63
69
|
preference, notification preference, or usage/billing surface, register it as a
|
|
64
70
|
settings tab or app settings panel first. Only add sidebar UI when it is needed
|
|
@@ -59,6 +59,12 @@ quick controls and deep links such as:
|
|
|
59
59
|
- `/settings/usage`
|
|
60
60
|
- `/settings/apps/:appId`
|
|
61
61
|
|
|
62
|
+
The shared Account section is the canonical profile surface at
|
|
63
|
+
`/settings#account`. It owns the editable display name and existing avatar
|
|
64
|
+
control through the authenticated `get-user-profile` and `update-user-profile`
|
|
65
|
+
actions. Shared workspace chrome such as `OrgSwitcher` should link to this
|
|
66
|
+
surface rather than creating an app-local profile page.
|
|
67
|
+
|
|
62
68
|
When adding a new API key, OAuth grant, provider connection, model selector, app
|
|
63
69
|
preference, notification preference, or usage/billing surface, register it as a
|
|
64
70
|
settings tab or app settings panel first. Only add sidebar UI when it is needed
|