@agent-native/core 0.127.3 → 0.128.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +80 -0
- package/corpus/core/README.md +5 -26
- package/corpus/core/docs/content/actions.mdx +47 -4
- package/corpus/core/docs/content/native-chat-ui.mdx +7 -0
- package/corpus/core/docs/content/organizations-teams-permissions.mdx +109 -3
- package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
- package/corpus/core/docs/content/toolkit-org-team.mdx +72 -12
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/artifact-response.ts +36 -29
- package/corpus/core/src/action.ts +83 -2
- package/corpus/core/src/chat-threads/store.ts +48 -43
- package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
- package/corpus/core/src/client/AgentPanel.tsx +26 -6
- package/corpus/core/src/client/AssistantChat.tsx +63 -7
- package/corpus/core/src/client/DefaultSpinner.tsx +29 -0
- package/corpus/core/src/client/org/TeamPage.tsx +161 -6
- package/corpus/core/src/client/org/hooks.ts +67 -0
- package/corpus/core/src/client/org/index.ts +9 -0
- package/corpus/core/src/client/transcription/use-live-transcription.ts +62 -10
- package/corpus/core/src/db/client.ts +42 -3
- package/corpus/core/src/db/ensure-additive-columns.ts +60 -33
- package/corpus/core/src/deploy/build.ts +31 -2
- package/corpus/core/src/mcp-client/routes.ts +10 -1
- package/corpus/core/src/org/app-roles-handlers.ts +152 -0
- package/corpus/core/src/org/app-roles.ts +355 -0
- package/corpus/core/src/org/index.ts +27 -1
- package/corpus/core/src/org/migrations.ts +22 -0
- package/corpus/core/src/org/plugin.ts +27 -0
- package/corpus/core/src/org/schema.ts +15 -0
- package/corpus/core/src/scripts/docs/search.ts +17 -0
- package/corpus/core/src/scripts/docs/source-search.ts +10 -0
- package/corpus/core/src/server/agent-chat/script-entries.ts +3 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +53 -52
- package/corpus/core/src/server/core-routes-plugin.ts +6 -1
- package/corpus/core/src/server/framework-request-handler.ts +44 -6
- package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/analytics/actions/data-source-status.ts +21 -12
- package/corpus/templates/analytics/app/global.css +7 -7
- package/corpus/templates/analytics/app/i18n-data.ts +30 -0
- package/corpus/templates/analytics/app/lib/data-source-status.ts +2 -1
- package/corpus/templates/analytics/app/pages/DataSources.tsx +54 -10
- package/corpus/templates/analytics/changelog/2026-07-28-analytics-pages-load-reliably-with-large-dashboard-workspaces.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-28-dashboard-loading-shimmer-now-flows-smoothly-in-one-directi.md +6 -0
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +5 -4
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +54 -42
- package/corpus/templates/analytics/server/plugins/db.ts +1 -18
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/clips/actions/request-transcript.ts +77 -11
- package/corpus/templates/clips/actions/save-browser-transcript.ts +28 -7
- package/corpus/templates/clips/app/routes/record.tsx +11 -3
- package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-save-a-truncated-transcript-as-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-stop-transcribing-partway-throu.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-desktop-full-screen-clips-now-get-an-instant-local-transcrip.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-long-transcriptions-no-longer-show-a-false-transcription-sto.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-restarting-for-an-update-now-installs-the-newest-release-ins.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-the-meeting-recording-pill-now-anchors-to-the-right-edge-of-.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +31 -2
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +114 -13
- package/corpus/templates/clips/desktop/src/lib/updater.ts +12 -4
- package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +40 -15
- package/corpus/templates/clips/desktop/src/styles.css +10 -7
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -14
- package/corpus/templates/clips/shared/transcript-status.ts +10 -0
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/content/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +46 -3
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +7 -5
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -4
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +10 -4
- package/corpus/templates/design/app/lib/design-ui-events.ts +5 -0
- package/corpus/templates/design/app/root.tsx +18 -1
- package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +6 -0
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/macros/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +4 -0
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +30 -29
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/action.d.ts +36 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +37 -2
- package/dist/action.js.map +1 -1
- package/dist/chat-threads/store.d.ts +12 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +48 -42
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.js +46 -3
- package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +11 -9
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +57 -6
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/DefaultSpinner.d.ts +7 -0
- package/dist/client/DefaultSpinner.d.ts.map +1 -1
- package/dist/client/DefaultSpinner.js +25 -1
- package/dist/client/DefaultSpinner.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts +13 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +41 -11
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/org/hooks.d.ts +37 -0
- package/dist/client/org/hooks.d.ts.map +1 -1
- package/dist/client/org/hooks.js +37 -0
- package/dist/client/org/hooks.js.map +1 -1
- package/dist/client/org/index.d.ts +3 -2
- package/dist/client/org/index.d.ts.map +1 -1
- package/dist/client/org/index.js +1 -1
- package/dist/client/org/index.js.map +1 -1
- package/dist/client/transcription/use-live-transcription.d.ts +8 -0
- package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
- package/dist/client/transcription/use-live-transcription.js +38 -11
- package/dist/client/transcription/use-live-transcription.js.map +1 -1
- package/dist/collab/routes.d.ts +2 -2
- package/dist/db/client.d.ts +12 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +40 -3
- package/dist/db/client.js.map +1 -1
- package/dist/db/ensure-additive-columns.d.ts.map +1 -1
- package/dist/db/ensure-additive-columns.js +54 -32
- package/dist/db/ensure-additive-columns.js.map +1 -1
- package/dist/deploy/build.d.ts +1 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +23 -2
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp-client/routes.d.ts +3 -1
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +8 -2
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/app-roles-handlers.d.ts +27 -0
- package/dist/org/app-roles-handlers.d.ts.map +1 -0
- package/dist/org/app-roles-handlers.js +125 -0
- package/dist/org/app-roles-handlers.js.map +1 -0
- package/dist/org/app-roles.d.ts +136 -0
- package/dist/org/app-roles.d.ts.map +1 -0
- package/dist/org/app-roles.js +216 -0
- package/dist/org/app-roles.js.map +1 -0
- package/dist/org/index.d.ts +4 -1
- package/dist/org/index.d.ts.map +1 -1
- package/dist/org/index.js +3 -1
- package/dist/org/index.js.map +1 -1
- package/dist/org/migrations.d.ts.map +1 -1
- package/dist/org/migrations.js +22 -0
- package/dist/org/migrations.js.map +1 -1
- package/dist/org/plugin.d.ts +2 -0
- package/dist/org/plugin.d.ts.map +1 -1
- package/dist/org/plugin.js +20 -0
- package/dist/org/plugin.js.map +1 -1
- package/dist/org/schema.d.ts +143 -0
- package/dist/org/schema.d.ts.map +1 -1
- package/dist/org/schema.js +14 -0
- package/dist/org/schema.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
- package/dist/provider-api/actions/provider-api.d.ts +12 -12
- package/dist/scripts/docs/search.d.ts.map +1 -1
- package/dist/scripts/docs/search.js +15 -0
- package/dist/scripts/docs/search.js.map +1 -1
- package/dist/scripts/docs/source-search.d.ts +7 -0
- package/dist/scripts/docs/source-search.d.ts.map +1 -1
- package/dist/scripts/docs/source-search.js +9 -0
- package/dist/scripts/docs/source-search.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
- package/dist/server/agent-chat/script-entries.js +3 -0
- package/dist/server/agent-chat/script-entries.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +46 -48
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +6 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +42 -6
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/docs/content/actions.mdx +47 -4
- package/docs/content/native-chat-ui.mdx +7 -0
- package/docs/content/organizations-teams-permissions.mdx +109 -3
- package/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
- package/docs/content/toolkit-org-team.mdx +72 -12
- package/package.json +1 -1
- package/src/a2a/artifact-response.ts +36 -29
- package/src/action.ts +83 -2
- package/src/chat-threads/store.ts +48 -43
- package/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
- package/src/client/AgentPanel.tsx +26 -6
- package/src/client/AssistantChat.tsx +63 -7
- package/src/client/DefaultSpinner.tsx +29 -0
- package/src/client/org/TeamPage.tsx +161 -6
- package/src/client/org/hooks.ts +67 -0
- package/src/client/org/index.ts +9 -0
- package/src/client/transcription/use-live-transcription.ts +62 -10
- package/src/db/client.ts +42 -3
- package/src/db/ensure-additive-columns.ts +60 -33
- package/src/deploy/build.ts +31 -2
- package/src/mcp-client/routes.ts +10 -1
- package/src/org/app-roles-handlers.ts +152 -0
- package/src/org/app-roles.ts +355 -0
- package/src/org/index.ts +27 -1
- package/src/org/migrations.ts +22 -0
- package/src/org/plugin.ts +27 -0
- package/src/org/schema.ts +15 -0
- package/src/scripts/docs/search.ts +17 -0
- package/src/scripts/docs/source-search.ts +10 -0
- package/src/server/agent-chat/script-entries.ts +3 -0
- package/src/server/agent-chat-plugin.ts +53 -52
- package/src/server/core-routes-plugin.ts +6 -1
- package/src/server/framework-request-handler.ts +44 -6
- package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/core/src/templates/chat/.agents/skills/actions/SKILL.md +0 -530
- package/corpus/core/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +0 -191
- package/corpus/core/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +0 -115
- package/corpus/core/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +0 -177
- package/corpus/core/src/templates/chat/.agents/skills/capture-learnings/SKILL.md +0 -89
- package/corpus/core/src/templates/chat/.agents/skills/create-skill/SKILL.md +0 -221
- package/corpus/core/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +0 -220
- package/corpus/core/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +0 -263
- package/corpus/core/src/templates/chat/.agents/skills/feature-flags/SKILL.md +0 -169
- package/corpus/core/src/templates/chat/.agents/skills/frontend-design/SKILL.md +0 -174
- package/corpus/core/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +0 -232
- package/corpus/core/src/templates/chat/.agents/skills/security/SKILL.md +0 -282
- package/corpus/core/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +0 -119
- package/corpus/core/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +0 -123
- package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +0 -122
- package/corpus/core/src/templates/chat/.env.example +0 -5
- package/corpus/core/src/templates/chat/.ignore +0 -0
- package/corpus/core/src/templates/chat/.oxfmtrc.json +0 -8
- package/corpus/core/src/templates/chat/AGENTS.md +0 -77
- package/corpus/core/src/templates/chat/CHANGELOG.md +0 -10
- package/corpus/core/src/templates/chat/DEVELOPING.md +0 -185
- package/corpus/core/src/templates/chat/README.md +0 -32
- package/corpus/core/src/templates/chat/_gitignore +0 -46
- package/corpus/core/src/templates/chat/actions/hello.ts +0 -13
- package/corpus/core/src/templates/chat/actions/navigate.ts +0 -41
- package/corpus/core/src/templates/chat/actions/run.ts +0 -2
- package/corpus/core/src/templates/chat/actions/view-screen.ts +0 -31
- package/corpus/core/src/templates/chat/app/components/layout/Header.tsx +0 -60
- package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +0 -188
- package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +0 -505
- package/corpus/core/src/templates/chat/app/components/ui/button.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/card.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/dropdown-menu.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/input.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/label.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/sheet.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/toolkit-provider.tsx +0 -17
- package/corpus/core/src/templates/chat/app/components/ui/tooltip.tsx +0 -1
- package/corpus/core/src/templates/chat/app/design-system.ts +0 -3
- package/corpus/core/src/templates/chat/app/entry.client.tsx +0 -22
- package/corpus/core/src/templates/chat/app/entry.server.tsx +0 -10
- package/corpus/core/src/templates/chat/app/global.css +0 -93
- package/corpus/core/src/templates/chat/app/hooks/use-navigation-state.ts +0 -93
- package/corpus/core/src/templates/chat/app/i18n/ar-SA.ts +0 -68
- package/corpus/core/src/templates/chat/app/i18n/de-DE.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/en-US.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/es-ES.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/fr-FR.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/hi-IN.ts +0 -69
- package/corpus/core/src/templates/chat/app/i18n/index.ts +0 -34
- package/corpus/core/src/templates/chat/app/i18n/ja-JP.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/ko-KR.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/pt-BR.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/zh-CN.ts +0 -66
- package/corpus/core/src/templates/chat/app/i18n/zh-TW.ts +0 -66
- package/corpus/core/src/templates/chat/app/i18n-data.ts +0 -556
- package/corpus/core/src/templates/chat/app/lib/agent-page.tsx +0 -49
- package/corpus/core/src/templates/chat/app/lib/app-config.ts +0 -11
- package/corpus/core/src/templates/chat/app/lib/tab-id.ts +0 -1
- package/corpus/core/src/templates/chat/app/lib/utils.ts +0 -1
- package/corpus/core/src/templates/chat/app/root.tsx +0 -173
- package/corpus/core/src/templates/chat/app/routes/_index.tsx +0 -94
- package/corpus/core/src/templates/chat/app/routes/agent.tsx +0 -24
- package/corpus/core/src/templates/chat/app/routes/chat.$threadId.tsx +0 -1
- package/corpus/core/src/templates/chat/app/routes/database.tsx +0 -17
- package/corpus/core/src/templates/chat/app/routes/extensions.$id.$slug.tsx +0 -2
- package/corpus/core/src/templates/chat/app/routes/extensions.$id.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes/extensions.tsx +0 -5
- package/corpus/core/src/templates/chat/app/routes/observability.tsx +0 -19
- package/corpus/core/src/templates/chat/app/routes/settings.tsx +0 -89
- package/corpus/core/src/templates/chat/app/routes/team.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes.ts +0 -4
- package/corpus/core/src/templates/chat/app/vite-env.d.ts +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +0 -5
- package/corpus/core/src/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +0 -6
- package/corpus/core/src/templates/chat/components.json +0 -20
- package/corpus/core/src/templates/chat/learnings.defaults.md +0 -5
- package/corpus/core/src/templates/chat/netlify.toml +0 -11
- package/corpus/core/src/templates/chat/package.json +0 -92
- package/corpus/core/src/templates/chat/public/agent-native-icon-dark.svg +0 -10
- package/corpus/core/src/templates/chat/public/agent-native-icon-light.svg +0 -10
- package/corpus/core/src/templates/chat/public/agent-native-logo-dark.svg +0 -21
- package/corpus/core/src/templates/chat/public/agent-native-logo-light.svg +0 -21
- package/corpus/core/src/templates/chat/public/favicon.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-180.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-192.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-512.svg +0 -1
- package/corpus/core/src/templates/chat/public/manifest.json +0 -21
- package/corpus/core/src/templates/chat/react-router.config.ts +0 -7
- package/corpus/core/src/templates/chat/server/middleware/auth.ts +0 -15
- package/corpus/core/src/templates/chat/server/plugins/agent-chat.ts +0 -21
- package/corpus/core/src/templates/chat/server/plugins/auth.ts +0 -17
- package/corpus/core/src/templates/chat/server/routes/[...page].get.ts +0 -5
- package/corpus/core/src/templates/chat/ssr-entry.ts +0 -15
- package/corpus/core/src/templates/chat/tsconfig.json +0 -21
- package/corpus/core/src/templates/chat/vite.config.ts +0 -19
|
@@ -2054,6 +2054,11 @@ export default function RecordRoute() {
|
|
|
2054
2054
|
// (from Web Speech API) with no API key required.
|
|
2055
2055
|
const browserTranscript = await liveTranscription.stopAndWait();
|
|
2056
2056
|
const trimmedTranscript = browserTranscript.trim();
|
|
2057
|
+
// Non-null when Web Speech died before we asked it to stop, so whatever
|
|
2058
|
+
// it captured covers only part of the recording. Send it with the text:
|
|
2059
|
+
// a partial transcript must never be stored as the finished one, or the
|
|
2060
|
+
// cloud fallback is suppressed and the user keeps the first few lines.
|
|
2061
|
+
const incompleteReason = liveTranscription.getIncompleteReason();
|
|
2057
2062
|
if (trimmedTranscript) {
|
|
2058
2063
|
const transcriptRes = await fetch(
|
|
2059
2064
|
agentNativePath("/_agent-native/actions/save-browser-transcript"),
|
|
@@ -2064,6 +2069,7 @@ export default function RecordRoute() {
|
|
|
2064
2069
|
recordingId: pending.id,
|
|
2065
2070
|
fullText: trimmedTranscript,
|
|
2066
2071
|
source: "web-speech",
|
|
2072
|
+
failureReason: incompleteReason ?? undefined,
|
|
2067
2073
|
}),
|
|
2068
2074
|
},
|
|
2069
2075
|
).catch((err) => {
|
|
@@ -2086,9 +2092,11 @@ export default function RecordRoute() {
|
|
|
2086
2092
|
recordingId: pending.id,
|
|
2087
2093
|
fullText: "",
|
|
2088
2094
|
source: "web-speech",
|
|
2089
|
-
failureReason:
|
|
2090
|
-
|
|
2091
|
-
|
|
2095
|
+
failureReason:
|
|
2096
|
+
incompleteReason ??
|
|
2097
|
+
(liveTranscription.supported
|
|
2098
|
+
? "Browser native transcription returned no speech before recording stopped."
|
|
2099
|
+
: "Browser Web Speech recognition is unavailable in this browser."),
|
|
2092
2100
|
}),
|
|
2093
2101
|
},
|
|
2094
2102
|
).catch((err) => {
|
|
@@ -14,7 +14,12 @@ export const METER_IDLE_HEIGHT = 0.14;
|
|
|
14
14
|
export const METER_LEVEL_DECAY = 0.82;
|
|
15
15
|
/** Floor a new sample must clear, so the meter falls smoothly instead of snapping. */
|
|
16
16
|
export const METER_ATTACK_DECAY = 0.55;
|
|
17
|
-
|
|
17
|
+
/**
|
|
18
|
+
* How long the meter waits for the next capture buffer before decaying on its
|
|
19
|
+
* own. Capture drives the bars; this only covers pause / teardown, where the
|
|
20
|
+
* events stop and a frozen tall bar would claim someone is still talking.
|
|
21
|
+
*/
|
|
22
|
+
export const METER_IDLE_MS = 120;
|
|
18
23
|
|
|
19
24
|
/** Fold an incoming 0-1 audio level into the current level. */
|
|
20
25
|
export function nextMeterLevel(current: number, incoming: number): number {
|
|
@@ -23,6 +28,30 @@ export function nextMeterLevel(current: number, incoming: number): number {
|
|
|
23
28
|
return Math.max(current * METER_ATTACK_DECAY, clamped);
|
|
24
29
|
}
|
|
25
30
|
|
|
31
|
+
export type MeterSource = "mic" | "system";
|
|
32
|
+
export type MeterSourceLevels = Record<MeterSource, number>;
|
|
33
|
+
|
|
34
|
+
export const EMPTY_METER_SOURCES: MeterSourceLevels = { mic: 0, system: 0 };
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Fold one capture buffer into the per-source levels. Mic and system audio
|
|
38
|
+
* interleave on a single event, so each stream has to decay on its own frames
|
|
39
|
+
* only — one shared level lets a silent mic halve the level of whoever is
|
|
40
|
+
* actually talking on every other event, which pins the meter to its floor.
|
|
41
|
+
*/
|
|
42
|
+
export function foldMeterSources(
|
|
43
|
+
levels: MeterSourceLevels,
|
|
44
|
+
source: MeterSource,
|
|
45
|
+
incoming: number,
|
|
46
|
+
): MeterSourceLevels {
|
|
47
|
+
return { ...levels, [source]: nextMeterLevel(levels[source], incoming) };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** What the bars show: whichever side of the conversation is louder. */
|
|
51
|
+
export function combinedMeterLevel(levels: MeterSourceLevels): number {
|
|
52
|
+
return Math.max(levels.mic, levels.system);
|
|
53
|
+
}
|
|
54
|
+
|
|
26
55
|
/** One decay tick. Snaps to silence below a threshold so bars settle at rest. */
|
|
27
56
|
export function decayMeterLevel(current: number): number {
|
|
28
57
|
const decayed = current * METER_LEVEL_DECAY;
|
|
@@ -46,6 +75,6 @@ export function advanceMeterLevels(levels: number[], sample: number): number[] {
|
|
|
46
75
|
export function meterBarHeight(level: number, barIndex: number): number {
|
|
47
76
|
const gain = METER_BAR_GAINS[barIndex] ?? 1;
|
|
48
77
|
const safe = Number.isFinite(level) ? Math.max(0, Math.min(1, level)) : 0;
|
|
49
|
-
const shaped = safe > 0 ? Math.min(1, Math.pow(safe, 0.
|
|
78
|
+
const shaped = safe > 0 ? Math.min(1, Math.pow(safe, 0.45) * 1.25) : 0;
|
|
50
79
|
return (METER_IDLE_HEIGHT + shaped * gain * (1 - METER_IDLE_HEIGHT)) * 100;
|
|
51
80
|
}
|
|
@@ -138,6 +138,10 @@ const CLOUD_RECORDING_VIDEO_BITRATE_BPS = 8_000_000;
|
|
|
138
138
|
const CLOUD_RECORDING_AUDIO_BITRATE_BPS = 128_000;
|
|
139
139
|
const TRANSCRIPT_SAVE_TIMEOUT_MS = 8_000;
|
|
140
140
|
const FINALIZING_RESULT_STORAGE_KEY = "clips-finalizing-result";
|
|
141
|
+
const NO_SPEECH_TRANSCRIPT_FAILURE =
|
|
142
|
+
"No speech was captured during this recording. If you spoke or played system audio, check System Audio, Microphone input, Speech Recognition permission, and the selected mic, then retry transcription.";
|
|
143
|
+
const TRANSCRIPTION_START_FAILURE =
|
|
144
|
+
"macOS Speech recognition could not start for this recording. Check Speech Recognition, System Audio, and Microphone permissions, then retry transcription.";
|
|
141
145
|
|
|
142
146
|
function isMacPlatform(): boolean {
|
|
143
147
|
if (typeof navigator === "undefined") return false;
|
|
@@ -2117,6 +2121,51 @@ async function tryStartRewindFullscreenRecording(
|
|
|
2117
2121
|
const hasAudio = includeMic || includeSystemAudio;
|
|
2118
2122
|
let id = folderName;
|
|
2119
2123
|
let uploadMode: UploadMode = "buffered";
|
|
2124
|
+
let transcriptionCapture: TranscriptionCapture | null = null;
|
|
2125
|
+
let transcriptionAborted = false;
|
|
2126
|
+
let transcriptFailureSaved = false;
|
|
2127
|
+
const saveTranscriptFailure = async (
|
|
2128
|
+
failureReason: string,
|
|
2129
|
+
): Promise<boolean> => {
|
|
2130
|
+
if (localOnly || !hasAudio || transcriptFailureSaved || !id) return false;
|
|
2131
|
+
transcriptFailureSaved = true;
|
|
2132
|
+
return saveRecordingTranscriptFailure(
|
|
2133
|
+
params.serverUrl,
|
|
2134
|
+
id,
|
|
2135
|
+
failureReason,
|
|
2136
|
+
params.authToken,
|
|
2137
|
+
);
|
|
2138
|
+
};
|
|
2139
|
+
// Whisper always subscribes to the shared Rewind producer's microphone leg,
|
|
2140
|
+
// so a mic-off clip can only fall back to a competing physical capture. Leave
|
|
2141
|
+
// those to server-side transcription instead of fighting the live producer.
|
|
2142
|
+
const canTranscribeLocally = !localOnly && includeMic;
|
|
2143
|
+
const startRewindTranscription = async () => {
|
|
2144
|
+
if (!canTranscribeLocally || transcriptionCapture) return;
|
|
2145
|
+
// Runs after `rewind_clip_prepare`, so the Rewind producer already carries
|
|
2146
|
+
// mic (+system) and whisper attaches to it instead of opening its own
|
|
2147
|
+
// ScreenCaptureKit stream — which would mute the clip's own audio legs.
|
|
2148
|
+
// This runs inside the countdown's Promise.all: a transcription failure
|
|
2149
|
+
// must never reject there, or it would abort the recording itself.
|
|
2150
|
+
const capture = await startTranscriptionCapture(
|
|
2151
|
+
{ deviceId: params.micId, label: params.micLabel },
|
|
2152
|
+
includeSystemAudio,
|
|
2153
|
+
{ voiceProcessing: false },
|
|
2154
|
+
).catch((err) => {
|
|
2155
|
+
console.warn("[clips-recorder] rewind transcription start failed:", err);
|
|
2156
|
+
return null;
|
|
2157
|
+
});
|
|
2158
|
+
// A countdown cancel can land while the engine was still starting; the
|
|
2159
|
+
// catch below already ran, so tear this down instead of leaking capture.
|
|
2160
|
+
if (transcriptionAborted) {
|
|
2161
|
+
await capture?.cancel().catch(() => {});
|
|
2162
|
+
return;
|
|
2163
|
+
}
|
|
2164
|
+
transcriptionCapture = capture;
|
|
2165
|
+
if (!capture && shouldSaveLocalTranscriptionStartupFailure()) {
|
|
2166
|
+
void saveTranscriptFailure(TRANSCRIPTION_START_FAILURE);
|
|
2167
|
+
}
|
|
2168
|
+
};
|
|
2120
2169
|
await invoke("show_preparing");
|
|
2121
2170
|
const recordingPromise = localOnly
|
|
2122
2171
|
? Promise.resolve<{ id: string; uploadMode: UploadMode }>({
|
|
@@ -2165,7 +2214,12 @@ async function tryStartRewindFullscreenRecording(
|
|
|
2165
2214
|
async countdown() {
|
|
2166
2215
|
console.log("[rewind-latency] countdown shown after preparation");
|
|
2167
2216
|
await invoke("hide_preparing").catch(() => {});
|
|
2168
|
-
|
|
2217
|
+
// Overlap whisper startup with the countdown so the capture boundary
|
|
2218
|
+
// never waits on it, but have both settled before activation.
|
|
2219
|
+
await Promise.all([
|
|
2220
|
+
runRecordingCountdown(true),
|
|
2221
|
+
startRewindTranscription(),
|
|
2222
|
+
]);
|
|
2169
2223
|
console.log("[rewind-latency] countdown completed");
|
|
2170
2224
|
},
|
|
2171
2225
|
async activate(preparedRecording) {
|
|
@@ -2174,6 +2228,13 @@ async function tryStartRewindFullscreenRecording(
|
|
|
2174
2228
|
console.log(
|
|
2175
2229
|
`[rewind-latency] countdown completion to start acknowledgement ${Math.round(performance.now() - activationStarted)}ms`,
|
|
2176
2230
|
);
|
|
2231
|
+
// Rebase transcript segment timestamps onto the real recording start.
|
|
2232
|
+
await transcriptionCapture?.resetTimeline().catch((err) => {
|
|
2233
|
+
console.warn(
|
|
2234
|
+
"[clips-recorder] transcription timeline reset failed:",
|
|
2235
|
+
err,
|
|
2236
|
+
);
|
|
2237
|
+
});
|
|
2177
2238
|
return preparedRecording;
|
|
2178
2239
|
},
|
|
2179
2240
|
onActivated() {
|
|
@@ -2194,6 +2255,13 @@ async function tryStartRewindFullscreenRecording(
|
|
|
2194
2255
|
}
|
|
2195
2256
|
} catch (err) {
|
|
2196
2257
|
await invoke("hide_preparing").catch(() => {});
|
|
2258
|
+
transcriptionAborted = true;
|
|
2259
|
+
// Cast: `transcriptionCapture` is only assigned inside the
|
|
2260
|
+
// `startRewindTranscription` closure, which TS's control-flow analysis
|
|
2261
|
+
// cannot see past — it narrows this read to `never`.
|
|
2262
|
+
await (transcriptionCapture as TranscriptionCapture | null)
|
|
2263
|
+
?.cancel()
|
|
2264
|
+
.catch(() => {});
|
|
2197
2265
|
if (id) forgetRewindClipOrigin(id);
|
|
2198
2266
|
await invoke("rewind_clip_cancel").catch(() => {});
|
|
2199
2267
|
audioCue.cleanup();
|
|
@@ -2300,6 +2368,25 @@ async function tryStartRewindFullscreenRecording(
|
|
|
2300
2368
|
`[rewind-latency] stop command dispatched in ${Math.round(performance.now() - stopStarted)}ms`,
|
|
2301
2369
|
);
|
|
2302
2370
|
uploadPromise.catch(() => {});
|
|
2371
|
+
// Stop transcription only after the clip stop is dispatched (Rust
|
|
2372
|
+
// measures duration when it runs, and stop() blocks on a settle
|
|
2373
|
+
// window), then persist it alongside the upload.
|
|
2374
|
+
const capturedTranscript = await transcriptionCapture
|
|
2375
|
+
?.stop()
|
|
2376
|
+
.catch((err) => {
|
|
2377
|
+
console.warn("[clips-recorder] transcript stop failed:", err);
|
|
2378
|
+
return null;
|
|
2379
|
+
});
|
|
2380
|
+
const transcriptSavePromise = capturedTranscript?.text.trim()
|
|
2381
|
+
? saveRecordingTranscript(
|
|
2382
|
+
params.serverUrl,
|
|
2383
|
+
id,
|
|
2384
|
+
capturedTranscript,
|
|
2385
|
+
params.authToken,
|
|
2386
|
+
)
|
|
2387
|
+
: hasAudio
|
|
2388
|
+
? saveTranscriptFailure(NO_SPEECH_TRANSCRIPT_FAILURE)
|
|
2389
|
+
: Promise.resolve(true);
|
|
2303
2390
|
await invoke("hide_recording_chrome").catch(() => {});
|
|
2304
2391
|
if (wantsCamera) await invoke("close_bubble").catch(() => {});
|
|
2305
2392
|
await openNativeUploadUrl(
|
|
@@ -2315,6 +2402,19 @@ async function tryStartRewindFullscreenRecording(
|
|
|
2315
2402
|
authToken: params.authToken,
|
|
2316
2403
|
});
|
|
2317
2404
|
}
|
|
2405
|
+
if (
|
|
2406
|
+
!(await transcriptSavePromise) &&
|
|
2407
|
+
capturedTranscript?.text.trim()
|
|
2408
|
+
) {
|
|
2409
|
+
// The first write races the upload; retry once after finalize so
|
|
2410
|
+
// a pre-ready action request can't strand a captured transcript.
|
|
2411
|
+
void saveRecordingTranscript(
|
|
2412
|
+
params.serverUrl,
|
|
2413
|
+
id,
|
|
2414
|
+
capturedTranscript,
|
|
2415
|
+
params.authToken,
|
|
2416
|
+
);
|
|
2417
|
+
}
|
|
2318
2418
|
return { recordingId: uploaded.recordingId, viewUrl };
|
|
2319
2419
|
} catch (err) {
|
|
2320
2420
|
if (
|
|
@@ -2346,6 +2446,10 @@ async function tryStartRewindFullscreenRecording(
|
|
|
2346
2446
|
cancelPromise = (async () => {
|
|
2347
2447
|
stopped = true;
|
|
2348
2448
|
cleanupUi();
|
|
2449
|
+
transcriptionAborted = true;
|
|
2450
|
+
void transcriptionCapture?.cancel().catch((err) => {
|
|
2451
|
+
console.warn("[clips-recorder] transcription cancel failed:", err);
|
|
2452
|
+
});
|
|
2349
2453
|
await invoke("rewind_clip_cancel").catch(() => {});
|
|
2350
2454
|
audioCue.cleanup();
|
|
2351
2455
|
await invoke("hide_overlays").catch(() => {});
|
|
@@ -2376,6 +2480,11 @@ async function tryStartRewindFullscreenRecording(
|
|
|
2376
2480
|
pausedAt = null;
|
|
2377
2481
|
}
|
|
2378
2482
|
pauseRequestedAt = null;
|
|
2483
|
+
// The Rewind producer keeps running while a clip is paused, so the
|
|
2484
|
+
// transcript would otherwise keep collecting speech the clip never saw.
|
|
2485
|
+
void (
|
|
2486
|
+
paused ? transcriptionCapture?.pause() : transcriptionCapture?.resume()
|
|
2487
|
+
)?.catch(() => {});
|
|
2379
2488
|
emitState(paused);
|
|
2380
2489
|
},
|
|
2381
2490
|
onError(_err, _attemptedPaused) {
|
|
@@ -2459,9 +2568,7 @@ async function startNativeFullscreenRecording(
|
|
|
2459
2568
|
!transcriptionCapture &&
|
|
2460
2569
|
shouldSaveLocalTranscriptionStartupFailure()
|
|
2461
2570
|
) {
|
|
2462
|
-
void saveTranscriptFailure(
|
|
2463
|
-
"macOS Speech recognition could not start for this recording. Check Speech Recognition, System Audio, and Microphone permissions, then retry transcription.",
|
|
2464
|
-
);
|
|
2571
|
+
void saveTranscriptFailure(TRANSCRIPTION_START_FAILURE);
|
|
2465
2572
|
}
|
|
2466
2573
|
};
|
|
2467
2574
|
|
|
@@ -2965,9 +3072,7 @@ async function startNativeFullscreenRecording(
|
|
|
2965
3072
|
params.authToken,
|
|
2966
3073
|
)
|
|
2967
3074
|
: wantsRecordedAudio
|
|
2968
|
-
? saveTranscriptFailure(
|
|
2969
|
-
"No speech was captured during this recording. If you spoke or played system audio, check System Audio, Microphone input, Speech Recognition permission, and the selected mic, then retry transcription.",
|
|
2970
|
-
)
|
|
3075
|
+
? saveTranscriptFailure(NO_SPEECH_TRANSCRIPT_FAILURE)
|
|
2971
3076
|
: Promise.resolve(true);
|
|
2972
3077
|
|
|
2973
3078
|
// The finalizing window owns the whole stop -> optimized upload ->
|
|
@@ -4127,9 +4232,7 @@ async function startRecordingInner(
|
|
|
4127
4232
|
!transcriptionCapture &&
|
|
4128
4233
|
shouldSaveLocalTranscriptionStartupFailure()
|
|
4129
4234
|
) {
|
|
4130
|
-
void saveTranscriptFailure(
|
|
4131
|
-
"macOS Speech recognition could not start for this recording. Check Speech Recognition, System Audio, and Microphone permissions, then retry transcription.",
|
|
4132
|
-
);
|
|
4235
|
+
void saveTranscriptFailure(TRANSCRIPTION_START_FAILURE);
|
|
4133
4236
|
}
|
|
4134
4237
|
|
|
4135
4238
|
// 6. Bubble + toolbar visibility are owned by the popover's session
|
|
@@ -4275,9 +4378,7 @@ async function startRecordingInner(
|
|
|
4275
4378
|
params.authToken,
|
|
4276
4379
|
);
|
|
4277
4380
|
} else if (wantsRecordedAudio) {
|
|
4278
|
-
await saveTranscriptFailure(
|
|
4279
|
-
"No speech was captured during this recording. If you spoke or played system audio, check System Audio, Microphone input, Speech Recognition permission, and the selected mic, then retry transcription.",
|
|
4280
|
-
);
|
|
4381
|
+
await saveTranscriptFailure(NO_SPEECH_TRANSCRIPT_FAILURE);
|
|
4281
4382
|
}
|
|
4282
4383
|
}
|
|
4283
4384
|
if (popoverOwnsCamera) {
|
|
@@ -44,18 +44,27 @@ function setStatus(next: UpdateStatus) {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
async function runCheck() {
|
|
47
|
-
if (cachedStatus.state === "downloaded") return;
|
|
48
47
|
if (checkInFlight) return checkInFlight;
|
|
49
48
|
|
|
49
|
+
// A staged update keeps checking on the normal cadence. Stopping here is what
|
|
50
|
+
// made "Restart to update" land on a binary that was already out of date and
|
|
51
|
+
// immediately ask to restart again — every check runs against the *running*
|
|
52
|
+
// version, so it re-offers the staged version until a newer one ships.
|
|
53
|
+
const staged =
|
|
54
|
+
cachedStatus.state === "downloaded" ? cachedStatus.version : null;
|
|
55
|
+
|
|
50
56
|
lastCheckStartedAt = Date.now();
|
|
51
57
|
checkInFlight = (async () => {
|
|
52
58
|
try {
|
|
53
|
-
setStatus({ state: "checking" });
|
|
59
|
+
if (!staged) setStatus({ state: "checking" });
|
|
54
60
|
const update = await check();
|
|
55
61
|
if (!update) {
|
|
56
|
-
|
|
62
|
+
// The endpoint answering "current" while a newer bundle sits staged is
|
|
63
|
+
// a contradiction, not a reason to drop the download. Keep it staged.
|
|
64
|
+
if (!staged) setStatus({ state: "not-available" });
|
|
57
65
|
return;
|
|
58
66
|
}
|
|
67
|
+
if (staged && update.version === staged) return;
|
|
59
68
|
pendingUpdate = update;
|
|
60
69
|
const version = update.version;
|
|
61
70
|
const notes = update.body ?? undefined;
|
|
@@ -98,7 +107,6 @@ async function runCheck() {
|
|
|
98
107
|
|
|
99
108
|
function maybeCheckForUpdate() {
|
|
100
109
|
if (!canRunUpdateChecks()) return;
|
|
101
|
-
if (cachedStatus.state === "downloaded") return;
|
|
102
110
|
if (
|
|
103
111
|
checkInFlight ||
|
|
104
112
|
Date.now() - lastCheckStartedAt < UPDATE_FOCUS_CHECK_MIN_INTERVAL_MS
|
|
@@ -3,12 +3,16 @@ import { useEffect, useRef, useState } from "react";
|
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
advanceMeterLevels,
|
|
6
|
+
combinedMeterLevel,
|
|
6
7
|
decayMeterLevel,
|
|
8
|
+
EMPTY_METER_SOURCES,
|
|
9
|
+
foldMeterSources,
|
|
7
10
|
METER_BAR_COUNT,
|
|
8
11
|
METER_BAR_GAINS,
|
|
9
|
-
|
|
12
|
+
METER_IDLE_MS,
|
|
10
13
|
meterBarHeight,
|
|
11
|
-
|
|
14
|
+
type MeterSource,
|
|
15
|
+
type MeterSourceLevels,
|
|
12
16
|
} from "../lib/audio-meter";
|
|
13
17
|
|
|
14
18
|
interface LiveAudioBarsProps {
|
|
@@ -28,24 +32,33 @@ export function LiveAudioBars({
|
|
|
28
32
|
const [levels, setLevels] = useState<number[]>(() =>
|
|
29
33
|
new Array(METER_BAR_COUNT).fill(0),
|
|
30
34
|
);
|
|
31
|
-
const
|
|
35
|
+
const sourcesRef = useRef<MeterSourceLevels>(EMPTY_METER_SOURCES);
|
|
36
|
+
const lastEventRef = useRef(0);
|
|
32
37
|
|
|
33
38
|
useEffect(() => {
|
|
34
39
|
let stopped = false;
|
|
35
40
|
let unlisten: (() => void) | null = null;
|
|
36
41
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
setLevels((prev) => advanceMeterLevels(prev, current));
|
|
41
|
-
}, METER_SAMPLE_MS);
|
|
42
|
-
|
|
43
|
-
listen<{ level?: number }>("voice:audio-level", (event) => {
|
|
44
|
-
levelRef.current = nextMeterLevel(
|
|
45
|
-
levelRef.current,
|
|
46
|
-
Number(event.payload?.level),
|
|
42
|
+
const push = () =>
|
|
43
|
+
setLevels((prev) =>
|
|
44
|
+
advanceMeterLevels(prev, combinedMeterLevel(sourcesRef.current)),
|
|
47
45
|
);
|
|
48
|
-
|
|
46
|
+
|
|
47
|
+
// Drive the bars straight off the capture events rather than resampling on
|
|
48
|
+
// a timer — both taps already emit at ~25 Hz, and a timer tick landing
|
|
49
|
+
// between them just showed a decayed copy of a live level.
|
|
50
|
+
listen<{ level?: number; source?: MeterSource }>(
|
|
51
|
+
"voice:audio-level",
|
|
52
|
+
(event) => {
|
|
53
|
+
sourcesRef.current = foldMeterSources(
|
|
54
|
+
sourcesRef.current,
|
|
55
|
+
event.payload?.source === "system" ? "system" : "mic",
|
|
56
|
+
Number(event.payload?.level),
|
|
57
|
+
);
|
|
58
|
+
lastEventRef.current = Date.now();
|
|
59
|
+
push();
|
|
60
|
+
},
|
|
61
|
+
)
|
|
49
62
|
.then((cleanup) => {
|
|
50
63
|
if (stopped) {
|
|
51
64
|
cleanup();
|
|
@@ -55,9 +68,21 @@ export function LiveAudioBars({
|
|
|
55
68
|
})
|
|
56
69
|
.catch(() => {});
|
|
57
70
|
|
|
71
|
+
// Capture buffers keep arriving through silence, so they settle the meter on
|
|
72
|
+
// their own. This only covers pause / teardown, where the events stop.
|
|
73
|
+
const idleTimer = window.setInterval(() => {
|
|
74
|
+
if (Date.now() - lastEventRef.current < METER_IDLE_MS) return;
|
|
75
|
+
if (combinedMeterLevel(sourcesRef.current) === 0) return;
|
|
76
|
+
sourcesRef.current = {
|
|
77
|
+
mic: decayMeterLevel(sourcesRef.current.mic),
|
|
78
|
+
system: decayMeterLevel(sourcesRef.current.system),
|
|
79
|
+
};
|
|
80
|
+
push();
|
|
81
|
+
}, METER_IDLE_MS);
|
|
82
|
+
|
|
58
83
|
return () => {
|
|
59
84
|
stopped = true;
|
|
60
|
-
window.clearInterval(
|
|
85
|
+
window.clearInterval(idleTimer);
|
|
61
86
|
unlisten?.();
|
|
62
87
|
};
|
|
63
88
|
}, []);
|
|
@@ -824,14 +824,14 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
824
824
|
|
|
825
825
|
.live-audio-bars-compact {
|
|
826
826
|
width: 24px;
|
|
827
|
-
height:
|
|
828
|
-
gap:
|
|
827
|
+
height: 24px;
|
|
828
|
+
gap: 3.5px;
|
|
829
829
|
}
|
|
830
830
|
|
|
831
831
|
.live-audio-bar {
|
|
832
832
|
display: block;
|
|
833
|
-
width:
|
|
834
|
-
min-height:
|
|
833
|
+
width: 3.5px;
|
|
834
|
+
min-height: 3.5px;
|
|
835
835
|
border-radius: 999px;
|
|
836
836
|
background: rgba(132, 204, 22, 0.98);
|
|
837
837
|
box-shadow: 0 0 5px rgba(132, 204, 22, 0.35);
|
|
@@ -5499,7 +5499,10 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5499
5499
|
.pill-inner-compact {
|
|
5500
5500
|
width: fit-content;
|
|
5501
5501
|
height: fit-content;
|
|
5502
|
-
|
|
5502
|
+
/* Stadium, not a squircle — the collapsed capsule reads as a pill at any
|
|
5503
|
+
height. A fixed radius on the ~44x64 vertical form looks like a rounded
|
|
5504
|
+
rectangle. */
|
|
5505
|
+
border-radius: 999px;
|
|
5503
5506
|
cursor: pointer;
|
|
5504
5507
|
transition:
|
|
5505
5508
|
background 120ms ease,
|
|
@@ -5574,7 +5577,7 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5574
5577
|
gap: 6px;
|
|
5575
5578
|
height: auto;
|
|
5576
5579
|
width: auto;
|
|
5577
|
-
padding: 12px 10px
|
|
5580
|
+
padding: 12px 10px;
|
|
5578
5581
|
cursor: pointer;
|
|
5579
5582
|
}
|
|
5580
5583
|
|
|
@@ -5589,7 +5592,7 @@ body[data-clips-route="recording-pill"] #root {
|
|
|
5589
5592
|
}
|
|
5590
5593
|
|
|
5591
5594
|
.pill-vertical .pill-wave-meter {
|
|
5592
|
-
height:
|
|
5595
|
+
height: 24px;
|
|
5593
5596
|
width: 24px;
|
|
5594
5597
|
}
|
|
5595
5598
|
|
|
@@ -86,7 +86,8 @@ const PILL_DETACHED_W_LOGICAL: u32 = 180;
|
|
|
86
86
|
const PILL_DETACHED_H_LOGICAL: u32 = 40;
|
|
87
87
|
const PILL_DETACHED_TOP_MARGIN_LOGICAL: u32 = 24;
|
|
88
88
|
const PILL_DETACHED_RIGHT_MARGIN_LOGICAL: u32 = 24;
|
|
89
|
-
|
|
89
|
+
/// Gap between the visible capsule and the right screen edge, logical px.
|
|
90
|
+
const PILL_RIGHT_MARGIN_LOGICAL: u32 = 28;
|
|
90
91
|
const OVERLAY_SHADOW_GUTTER_LOGICAL: f64 = 18.0;
|
|
91
92
|
|
|
92
93
|
#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
|
|
@@ -107,6 +108,15 @@ fn overlay_shadow_gutter_physical(app: &AppHandle) -> u32 {
|
|
|
107
108
|
(OVERLAY_SHADOW_GUTTER_LOGICAL * scale_factor(app).max(1.0)).round() as u32
|
|
108
109
|
}
|
|
109
110
|
|
|
111
|
+
/// Screen-edge margin for the *visible* capsule. The window is padded out with
|
|
112
|
+
/// a transparent shadow gutter, so that gutter comes off the window margin —
|
|
113
|
+
/// measured from the window frame the pill floats a whole gutter further from
|
|
114
|
+
/// the edge than the constant says.
|
|
115
|
+
fn edge_margin_physical(app: &AppHandle, logical: u32) -> i32 {
|
|
116
|
+
let margin = (logical as f64 * scale_factor(app)) as i32;
|
|
117
|
+
(margin - overlay_shadow_gutter_physical(app) as i32).max(0)
|
|
118
|
+
}
|
|
119
|
+
|
|
110
120
|
/// Persist the last-known pill position so the next `show` re-opens at the
|
|
111
121
|
/// user's chosen spot.
|
|
112
122
|
fn pill_position_path(app: &AppHandle) -> Option<PathBuf> {
|
|
@@ -236,8 +246,7 @@ fn default_bottom_center(app: &AppHandle, w: u32, h: u32) -> (i32, i32) {
|
|
|
236
246
|
}
|
|
237
247
|
|
|
238
248
|
fn default_center_right(app: &AppHandle, w: u32, h: u32) -> (i32, i32) {
|
|
239
|
-
let
|
|
240
|
-
let right_margin = (PILL_RIGHT_MARGIN_LOGICAL as f64 * scale) as i32;
|
|
249
|
+
let right_margin = edge_margin_physical(app, PILL_RIGHT_MARGIN_LOGICAL);
|
|
241
250
|
let (mx, my, mw, mh) = tray_monitor_physical_rect(app);
|
|
242
251
|
let x = (mx + mw as i32 - w as i32 - right_margin).max(mx);
|
|
243
252
|
// Center whatever is actually on screen — meetings now open collapsed, so
|
|
@@ -283,9 +292,8 @@ fn pill_size_physical(app: &AppHandle, expanded: bool) -> (u32, u32) {
|
|
|
283
292
|
|
|
284
293
|
/// Default top-right anchor (physical px) for detached mode.
|
|
285
294
|
fn default_top_right(app: &AppHandle, w: u32, _h: u32) -> (i32, i32) {
|
|
286
|
-
let
|
|
287
|
-
let
|
|
288
|
-
let right_margin = (PILL_DETACHED_RIGHT_MARGIN_LOGICAL as f64 * scale) as i32;
|
|
295
|
+
let top_margin = edge_margin_physical(app, PILL_DETACHED_TOP_MARGIN_LOGICAL);
|
|
296
|
+
let right_margin = edge_margin_physical(app, PILL_DETACHED_RIGHT_MARGIN_LOGICAL);
|
|
289
297
|
let (mx, my, mw, _mh) = tray_monitor_physical_rect(app);
|
|
290
298
|
let x = (mx + mw as i32 - w as i32 - right_margin).max(mx);
|
|
291
299
|
let y = (my + top_margin).max(my);
|
|
@@ -398,15 +406,14 @@ pub async fn recording_pill_show(
|
|
|
398
406
|
);
|
|
399
407
|
|
|
400
408
|
if let Some(existing) = app.get_webview_window(PILL_LABEL) {
|
|
401
|
-
// Already alive — re-emit context and bring it back into view.
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
};
|
|
409
|
+
// Already alive — re-emit context and bring it back into view. Re-anchor
|
|
410
|
+
// from the saved/default position for this mode, never from where the
|
|
411
|
+
// window happens to sit: the pill window is reused across sessions, so
|
|
412
|
+
// carrying the previous rect over pins a meeting pill to the last clip
|
|
413
|
+
// recording's bottom-center spot. `previous` exists for expand/collapse,
|
|
414
|
+
// where the anchor must not move.
|
|
408
415
|
let expanded = PILL_EXPANDED.load(Ordering::Relaxed);
|
|
409
|
-
let (w, h, x, y) = anchored_rect(&app, expanded,
|
|
416
|
+
let (w, h, x, y) = anchored_rect(&app, expanded, None);
|
|
410
417
|
let _ = existing.set_size(tauri::Size::Physical(PhysicalSize::new(w, h)));
|
|
411
418
|
let _ = existing.set_position(PhysicalPosition::new(x, y));
|
|
412
419
|
use tauri::Emitter;
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
export const STALE_PENDING_TRANSCRIPT_MS = 5 * 60 * 1000;
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* How often a worker that is still transcribing must re-stamp its pending row.
|
|
5
|
+
*
|
|
6
|
+
* `updatedAt` is the only liveness signal a pending row carries, so this must
|
|
7
|
+
* stay well under STALE_PENDING_TRANSCRIPT_MS: a run whose slowest single step
|
|
8
|
+
* (media fetch, ffmpeg extraction, provider call) outlives the heartbeat is
|
|
9
|
+
* indistinguishable from a worker that died.
|
|
10
|
+
*/
|
|
11
|
+
export const PENDING_TRANSCRIPT_HEARTBEAT_MS = 60 * 1000;
|
|
12
|
+
|
|
3
13
|
export const STALE_PENDING_TRANSCRIPT_REASON =
|
|
4
14
|
"Transcription stopped before it finished. Retry transcription to start a fresh attempt.";
|
|
5
15
|
|
|
@@ -305,6 +305,38 @@ export default defineAction({
|
|
|
305
305
|
|
|
306
306
|
On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
|
|
307
307
|
|
|
308
|
+
### Authorization (`authorize`)
|
|
309
|
+
|
|
310
|
+
`authorize` decides whether the caller may run the action at all. It wraps
|
|
311
|
+
`run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
|
|
312
|
+
hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
|
|
313
|
+
agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
|
|
314
|
+
to ask a human to bless one call a permitted caller is already allowed to make.
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
318
|
+
|
|
319
|
+
export default defineAction({
|
|
320
|
+
description: "Archive a client roster.",
|
|
321
|
+
schema: z.object({ id: z.string() }),
|
|
322
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
323
|
+
run: async (args) => {
|
|
324
|
+
/* ... */
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
The wrappers compose as `validate input -> authorize -> run -> validate output
|
|
330
|
+
-> audit`: the gate sits inside input validation, so a guard reading `args` gets
|
|
331
|
+
the parsed, coerced value, and auditing is outermost, so denials are recorded.
|
|
332
|
+
|
|
333
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
334
|
+
generically; anything else (including `undefined`) allows. A guarded action
|
|
335
|
+
needs a user identity, so an unattended CLI/cron caller with no user email is
|
|
336
|
+
denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
|
|
337
|
+
scope which rows a permitted caller may touch. See the `authentication` skill
|
|
338
|
+
for `defineAppRoles` and the `sharing` skill for row scoping.
|
|
339
|
+
|
|
308
340
|
### Human-in-the-Loop Approval (`needsApproval`)
|
|
309
341
|
|
|
310
342
|
For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
|