@agent-native/core 0.137.8 → 0.138.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agent-native.eject.json +2 -0
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/analytics/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +15 -0
- package/corpus/templates/analytics/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/analytics/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/analytics/AGENTS.md +2 -2
- package/corpus/templates/analytics/actions/get-first-party-analytics-health.ts +65 -0
- package/corpus/templates/analytics/actions/provider-api-catalog.ts +3 -6
- package/corpus/templates/analytics/actions/provider-api-docs.ts +3 -6
- package/corpus/templates/analytics/actions/provider-api-request.ts +3 -6
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +3 -3
- package/corpus/templates/analytics/agent-native.json +12 -0
- package/corpus/templates/analytics/app/i18n-data.ts +162 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +126 -1
- package/corpus/templates/analytics/changelog/2026-08-05-analytics-now-flags-neon-pressure-and-guides-high-volume-tra.md +6 -0
- package/corpus/templates/analytics/changelog/2026-08-05-first-party-analytics-uses-compact-rollups-for-faster-usage-.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +52 -0
- package/corpus/templates/analytics/server/lib/credential-keys.ts +3 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-health.ts +397 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +182 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +86 -15
- package/corpus/templates/analytics/server/lib/provider-api.ts +20 -1
- package/corpus/templates/analytics/server/lib/replay-storage.ts +1 -1
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +1 -0
- package/corpus/templates/analytics/server/plugins/db.ts +60 -0
- package/corpus/templates/assets/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/assets/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/assets/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/assets/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/assets/agent-native.json +12 -0
- package/corpus/templates/assets/server/lib/generation.ts +8 -8
- package/corpus/templates/assets/server/lib/storage.ts +1 -1
- package/corpus/templates/assets/server/plugins/onboarding.ts +1 -1
- package/corpus/templates/brain/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/brain/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/brain/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/brain/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/brain/agent-native.json +12 -0
- package/corpus/templates/calendar/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/calendar/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/calendar/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/calendar/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/calendar/agent-native.json +12 -0
- package/corpus/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/chat/AGENTS.md +3 -0
- package/corpus/templates/chat/DESIGN.md +28 -0
- package/corpus/templates/chat/agent-native.json +12 -0
- package/corpus/templates/clips/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/clips/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/clips/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/clips/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/clips/actions/cleanup-transcript.ts +2 -2
- package/corpus/templates/clips/actions/delete-recording-permanent.ts +3 -0
- package/corpus/templates/clips/actions/get-playback-position.ts +68 -0
- package/corpus/templates/clips/actions/import-loom-recording.ts +2 -2
- package/corpus/templates/clips/actions/save-playback-position.ts +80 -0
- package/corpus/templates/clips/actions/set-thumbnail.ts +1 -1
- package/corpus/templates/clips/agent-native.json +12 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +54 -5
- package/corpus/templates/clips/app/hooks/use-playback-position.ts +188 -0
- package/corpus/templates/clips/app/hooks/use-view-tracking.ts +6 -24
- package/corpus/templates/clips/app/lib/playback-position.ts +99 -0
- package/corpus/templates/clips/app/lib/viewer-session.ts +29 -0
- package/corpus/templates/clips/changelog/2026-08-05-clip-buffering-now-uses-buffering-copy-after-playback.md +6 -0
- package/corpus/templates/clips/changelog/2026-08-05-clips-remembers-your-playback-position-when-you-reopen-a-cli.md +6 -0
- package/corpus/templates/clips/learnings.defaults.md +1 -1
- package/corpus/templates/clips/server/db/schema.ts +18 -0
- package/corpus/templates/clips/server/lib/public-agent-context.ts +1 -1
- package/corpus/templates/clips/server/lib/video-storage.ts +1 -1
- package/corpus/templates/clips/server/plugins/db.ts +15 -0
- package/corpus/templates/clips/server/routes/api/media/index.post.ts +1 -1
- package/corpus/templates/content/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/content/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +13 -0
- package/corpus/templates/content/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/content/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/content/AGENTS.md +1 -0
- package/corpus/templates/content/actions/_content-database-mutation-lock.ts +41 -0
- package/corpus/templates/content/actions/_content-database-row-migration.ts +569 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +82 -36
- package/corpus/templates/content/actions/_database-utils.ts +5 -0
- package/corpus/templates/content/actions/_delete-content-space.ts +25 -11
- package/corpus/templates/content/actions/add-database-item.ts +60 -42
- package/corpus/templates/content/actions/attach-content-database-source.ts +2 -0
- package/corpus/templates/content/actions/configure-document-property.ts +99 -104
- package/corpus/templates/content/actions/delete-content-database.ts +19 -7
- package/corpus/templates/content/actions/delete-document-property.ts +47 -58
- package/corpus/templates/content/actions/delete-document.ts +390 -167
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +41 -24
- package/corpus/templates/content/actions/duplicate-database-item.ts +63 -31
- package/corpus/templates/content/actions/duplicate-database-items.ts +86 -43
- package/corpus/templates/content/actions/duplicate-document-property.ts +37 -14
- package/corpus/templates/content/actions/migrate-content-database-rows.ts +830 -0
- package/corpus/templates/content/actions/move-database-item.ts +14 -0
- package/corpus/templates/content/actions/permanently-delete-document.ts +27 -6
- package/corpus/templates/content/actions/remove-database-items.ts +13 -0
- package/corpus/templates/content/actions/reorder-document-property.ts +45 -46
- package/corpus/templates/content/actions/set-document-property.ts +68 -28
- package/corpus/templates/content/actions/submit-content-database-form.ts +49 -0
- package/corpus/templates/content/actions/transcribe-media.ts +1 -1
- package/corpus/templates/content/agent-native.json +12 -0
- package/corpus/templates/content/app/components/editor/image-upload.ts +2 -2
- package/corpus/templates/content/app/i18n-data.ts +1 -1
- package/corpus/templates/content/changelog/2026-08-01-content-can-reorganize-every-row-in-an-existing-database-as-.md +6 -0
- package/corpus/templates/content/parity/matrix.md +1 -1
- package/corpus/templates/content/parity/matrix.ts +4 -2
- package/corpus/templates/content/server/db/schema.ts +30 -0
- package/corpus/templates/content/server/plugins/db.ts +24 -0
- package/corpus/templates/content/server/plugins/onboarding.ts +2 -2
- package/corpus/templates/crm/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/crm/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/crm/agent-native.json +12 -0
- package/corpus/templates/design/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/design/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/design/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/design/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +2 -2
- package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +2 -2
- package/corpus/templates/design/actions/apply-design-token-edit.ts +1 -1
- package/corpus/templates/design/actions/capture-design-state.ts +1 -1
- package/corpus/templates/design/actions/connect-builder-app.ts +2 -2
- package/corpus/templates/design/actions/create-design-branch.ts +1 -1
- package/corpus/templates/design/actions/create-fusion-app.ts +3 -3
- package/corpus/templates/design/actions/deploy-design-preview.ts +1 -1
- package/corpus/templates/design/actions/get-component-details.ts +1 -1
- package/corpus/templates/design/actions/get-design-branch-diff.ts +1 -1
- package/corpus/templates/design/actions/index-components.ts +3 -3
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/design/actions/migrate-inline-design-to-app.ts +3 -3
- package/corpus/templates/design/actions/open-component-source.ts +1 -1
- package/corpus/templates/design/actions/update-design.ts +61 -0
- package/corpus/templates/design/agent-native.json +12 -0
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +1 -1
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/design/scripts/qa-figma-stress-import.ts +1 -1
- package/corpus/templates/design/server/lib/figma-node-import.ts +1 -1
- package/corpus/templates/design/shared/design-source-capabilities.ts +25 -9
- package/corpus/templates/dispatch/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/dispatch/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/dispatch/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/dispatch/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/dispatch/agent-native.json +12 -0
- package/corpus/templates/factory/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/factory/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/factory/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/factory/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/factory/agent-native.json +12 -0
- package/corpus/templates/forms/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/forms/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/forms/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/forms/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/forms/actions/export-responses.ts +1 -1
- package/corpus/templates/forms/agent-native.json +12 -0
- package/corpus/templates/macros/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/macros/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/macros/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/macros/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/macros/agent-native.json +12 -0
- package/corpus/templates/mail/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/mail/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/mail/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/mail/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/mail/agent-native.json +12 -0
- package/corpus/templates/mail/app/i18n/en-US.ts +1 -1
- package/corpus/templates/mail/server/lib/media-upload.ts +1 -1
- package/corpus/templates/plan/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/plan/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/plan/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/plan/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/plan/agent-native.json +12 -0
- package/corpus/templates/plan/server/lib/plan-assets.ts +1 -1
- package/corpus/templates/slides/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/slides/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/slides/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/slides/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/slides/actions/generate-image-api.ts +1 -1
- package/corpus/templates/slides/actions/generate-slides-ai.ts +1 -1
- package/corpus/templates/slides/actions/import-file.ts +2 -2
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +1 -1
- package/corpus/templates/slides/agent-native.json +12 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +2 -2
- package/corpus/templates/slides/app/lib/deck-sorting.ts +19 -0
- package/corpus/templates/slides/app/lib/image-drop-to-agent.ts +1 -1
- package/corpus/templates/slides/app/pages/Index.tsx +7 -2
- package/corpus/templates/slides/changelog/2026-08-05-decks-are-now-sorted-by-most-recently-updated.md +6 -0
- package/corpus/templates/slides/server/handlers/assets.ts +1 -1
- package/corpus/templates/slides/server/handlers/uploads.ts +1 -1
- package/corpus/templates/tasks/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/corpus/templates/tasks/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/corpus/templates/tasks/.agents/skills/frontend-design/SKILL.md +23 -2
- package/corpus/templates/tasks/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/corpus/templates/tasks/agent-native.json +12 -0
- package/dist/action.d.ts +6 -0
- package/dist/agent/engine/builder-engine.js +2 -2
- package/dist/agent/engine/credential-errors.d.ts +1 -1
- package/dist/agent/engine/credential-errors.js +2 -2
- package/dist/agent/production-agent.js +3 -2
- package/dist/brand-kit/fig/index.js +1 -1
- package/dist/cli/agent.js +45 -3
- package/dist/cli/code-agent-executor.js +2 -1
- package/dist/cli/create.d.ts +9 -1
- package/dist/cli/create.js +94 -1
- package/dist/cli/doctor.d.ts +8 -11
- package/dist/cli/doctor.js +92 -24
- package/dist/cli/index.js +6 -5
- package/dist/client/AgentAskPopover.d.ts +3 -1
- package/dist/client/AgentAskPopover.js +2 -2
- package/dist/client/AgentPanel.js +9 -3
- package/dist/client/AssistantChat.js +54 -33
- package/dist/client/MultiTabAssistantChat.js +1 -1
- package/dist/client/RouteTransitionIndicator.d.ts +7 -0
- package/dist/client/RouteTransitionIndicator.js +31 -0
- package/dist/client/agent-engine-key.js +1 -1
- package/dist/client/app-providers.js +11 -2
- package/dist/client/chat/message-components.js +1 -1
- package/dist/client/chat/run-recovery.js +1 -1
- package/dist/client/chat/tool-call-display.d.ts +3 -1
- package/dist/client/chat/tool-call-display.js +4 -3
- package/dist/client/chat-model-groups.d.ts +6 -0
- package/dist/client/chat-model-groups.js +11 -0
- package/dist/client/error-format.js +1 -1
- package/dist/client/i18n.js +1 -1
- package/dist/client/onboarding/FirstRunOnboarding.d.ts +5 -1
- package/dist/client/onboarding/FirstRunOnboarding.js +29 -13
- package/dist/client/onboarding/first-run-enabled.d.ts +6 -1
- package/dist/client/onboarding/first-run-enabled.js +33 -3
- package/dist/client/onboarding/use-onboarding.js +16 -11
- package/dist/client/resources/mcp-integration-catalog.js +26 -0
- package/dist/client/resources/mcp-integration-logos.js +4 -0
- package/dist/client/route-warmup.js +56 -10
- package/dist/client/settings/AccountSettingsCard.js +78 -3
- package/dist/client/settings/SettingsPanel.js +1 -1
- package/dist/client/settings/VoiceTranscriptionSection.js +2 -2
- package/dist/client/settings/useBuilderStatus.js +1 -1
- package/dist/client/setup-connections/useBuilderConnectCardController.js +1 -1
- package/dist/client/ui/index.d.ts +1 -0
- package/dist/client/ui/index.js +1 -0
- package/dist/client/uploads/upload-editor-image.js +1 -1
- package/dist/client/use-chat-threads.js +3 -0
- package/dist/collab/routes.d.ts +2 -2
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/config.d.ts +48 -0
- package/dist/config.js +111 -0
- package/dist/db/migrations.js +5 -0
- package/dist/eject/provider-api-definitions.d.ts +1 -1
- package/dist/eject/provider-api-definitions.js +1 -0
- package/dist/eject/remote-mcp-presets.js +1 -0
- package/dist/extensions/web-search-tool.js +2 -2
- package/dist/file-upload/actions/upload-image.js +1 -1
- package/dist/file-upload/registry.js +1 -1
- package/dist/guards/index.d.ts +3 -0
- package/dist/guards/index.js +2 -0
- package/dist/guards/no-empty-migrations.d.ts +14 -0
- package/dist/guards/no-empty-migrations.js +126 -0
- package/dist/index.browser.d.ts +1 -0
- package/dist/index.browser.js +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/localization/default-messages.d.ts +24 -0
- package/dist/localization/default-messages.js +26 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/onboarding/app-profile.js +1 -1
- package/dist/onboarding/plugin.d.ts +2 -0
- package/dist/onboarding/plugin.js +29 -2
- package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/provider-api/index.d.ts +4 -4
- package/dist/provider-api/index.js +35 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/resources/handlers.js +1 -1
- package/dist/scripts/docs/framework-search.d.ts +9 -0
- package/dist/scripts/docs/framework-search.js +239 -0
- package/dist/scripts/docs/index.js +1 -0
- package/dist/scripts/docs/search.d.ts +10 -0
- package/dist/scripts/docs/search.js +1 -1
- package/dist/scripts/docs/source-search.d.ts +10 -2
- package/dist/scripts/docs/source-search.js +108 -41
- package/dist/search-utils/index.d.ts +11 -0
- package/dist/search-utils/index.js +72 -0
- package/dist/server/action-change.d.ts +6 -0
- package/dist/server/action-change.js +28 -14
- package/dist/server/action-discovery.js +9 -0
- package/dist/server/action-routes.js +1 -0
- package/dist/server/agent-chat/browser-team-tools.js +1 -1
- package/dist/server/agent-chat/script-entries.js +43 -2
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth-login-mode.d.ts +8 -0
- package/dist/server/auth-login-mode.js +17 -0
- package/dist/server/auth.js +100 -15
- package/dist/server/better-auth-instance.d.ts +36 -0
- package/dist/server/better-auth-instance.js +25 -3
- package/dist/server/builder-design-systems.js +1 -1
- package/dist/server/core-routes-plugin.js +17 -14
- package/dist/server/credential-provider.js +3 -3
- package/dist/server/email-templates.d.ts +7 -0
- package/dist/server/email-templates.js +24 -0
- package/dist/server/email.d.ts +17 -0
- package/dist/server/email.js +22 -1
- package/dist/server/framework-request-handler.js +6 -0
- package/dist/server/onboarding-html.d.ts +2 -0
- package/dist/server/onboarding-html.js +169 -8
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/realtime-voice.js +1 -1
- package/dist/server/sentry.d.ts +1 -1
- package/dist/server/transcribe-voice.js +3 -3
- package/dist/shared/first-run-onboarding.d.ts +1 -0
- package/dist/shared/first-run-onboarding.js +1 -0
- package/dist/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/chat/AGENTS.md +3 -0
- package/dist/templates/chat/DESIGN.md +28 -0
- package/dist/templates/chat/agent-native.json +12 -0
- package/dist/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/default/AGENTS.md +4 -0
- package/dist/templates/default/DESIGN.md +30 -0
- package/dist/templates/default/agent-native.json +9 -0
- package/dist/templates/default/app/i18n/ar-SA.ts +2 -2
- package/dist/templates/default/app/i18n/de-DE.ts +2 -2
- package/dist/templates/default/app/i18n/en-US.ts +2 -2
- package/dist/templates/default/app/i18n/es-ES.ts +2 -2
- package/dist/templates/default/app/i18n/fr-FR.ts +2 -2
- package/dist/templates/default/app/i18n/hi-IN.ts +2 -2
- package/dist/templates/default/app/i18n/ja-JP.ts +2 -2
- package/dist/templates/default/app/i18n/ko-KR.ts +2 -2
- package/dist/templates/default/app/i18n/pt-BR.ts +2 -2
- package/dist/templates/default/app/i18n/zh-CN.ts +2 -2
- package/dist/templates/default/app/i18n/zh-TW.ts +1 -1
- package/dist/templates/default/package.json +1 -0
- package/dist/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/headless/agent-native.json +9 -0
- package/dist/templates/headless/package.json +2 -0
- package/dist/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/dist/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/dist/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
- package/dist/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/dist/templates/workspace-core/AGENTS.md +3 -0
- package/dist/templates/workspace-core/DESIGN.md +35 -0
- package/dist/templates/workspace-root/AGENTS.md +3 -0
- package/dist/templates/workspace-root/DESIGN.md +35 -0
- package/dist/templates/workspace-root/agent-native.json +9 -0
- package/dist/templates/workspace-root/package.json +3 -0
- package/dist/transcription/builder-transcription.js +1 -1
- package/dist/user-profile/actions/change-password.d.ts +8 -0
- package/dist/user-profile/actions/change-password.js +24 -0
- package/dist/user-profile/actions/get-auth-methods.d.ts +6 -0
- package/dist/user-profile/actions/get-auth-methods.js +23 -0
- package/dist/user-profile/actions/set-password.d.ts +7 -0
- package/dist/user-profile/actions/set-password.js +23 -0
- package/dist/vite/client.d.ts +8 -1
- package/dist/vite/client.js +63 -12
- package/dist/vite/index.d.ts +1 -0
- package/dist/vite/index.js +1 -0
- package/docs/AGENTS.md +7 -2
- package/docs/SKILL.md +7 -5
- package/docs/content/agent-native-config.mdx +165 -0
- package/docs/content/agent-native-toolkit.mdx +1 -1
- package/docs/content/deployment.mdx +7 -2
- package/docs/content/doctor.mdx +21 -13
- package/docs/content/environment-variables.mdx +158 -0
- package/docs/content/file-uploads.mdx +1 -1
- package/docs/content/getting-started.mdx +1 -1
- package/docs/content/key-concepts.mdx +1 -1
- package/docs/content/multi-app-workspace.mdx +1 -1
- package/docs/content/template-clips-ai-and-editing.mdx +6 -6
- package/docs/content/template-clips-developers.mdx +3 -3
- package/docs/content/toolkit-settings.mdx +1 -1
- package/docs/content/voice-input.mdx +4 -4
- package/package.json +6 -2
- package/src/eject/provider-api-definitions.ts +1 -0
- package/src/eject/remote-mcp-presets.ts +1 -0
- package/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/chat/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/chat/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/chat/AGENTS.md +3 -0
- package/src/templates/chat/DESIGN.md +28 -0
- package/src/templates/chat/agent-native.json +12 -0
- package/src/templates/default/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/default/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/default/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/default/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/default/AGENTS.md +4 -0
- package/src/templates/default/DESIGN.md +30 -0
- package/src/templates/default/agent-native.json +9 -0
- package/src/templates/default/app/i18n/ar-SA.ts +2 -2
- package/src/templates/default/app/i18n/de-DE.ts +2 -2
- package/src/templates/default/app/i18n/en-US.ts +2 -2
- package/src/templates/default/app/i18n/es-ES.ts +2 -2
- package/src/templates/default/app/i18n/fr-FR.ts +2 -2
- package/src/templates/default/app/i18n/hi-IN.ts +2 -2
- package/src/templates/default/app/i18n/ja-JP.ts +2 -2
- package/src/templates/default/app/i18n/ko-KR.ts +2 -2
- package/src/templates/default/app/i18n/pt-BR.ts +2 -2
- package/src/templates/default/app/i18n/zh-CN.ts +2 -2
- package/src/templates/default/app/i18n/zh-TW.ts +1 -1
- package/src/templates/default/package.json +1 -0
- package/src/templates/headless/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/headless/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/headless/agent-native.json +9 -0
- package/src/templates/headless/package.json +2 -0
- package/src/templates/workspace-core/.agents/skills/agent-native-docs/SKILL.md +23 -3
- package/src/templates/workspace-core/.agents/skills/agent-native-toolkit/SKILL.md +16 -0
- package/src/templates/workspace-core/.agents/skills/frontend-design/SKILL.md +23 -2
- package/src/templates/workspace-core/.agents/skills/frontend-design/references/visual-direction.md +99 -0
- package/src/templates/workspace-core/AGENTS.md +3 -0
- package/src/templates/workspace-core/DESIGN.md +35 -0
- package/src/templates/workspace-root/AGENTS.md +3 -0
- package/src/templates/workspace-root/DESIGN.md +35 -0
- package/src/templates/workspace-root/agent-native.json +9 -0
- package/src/templates/workspace-root/package.json +3 -0
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
} from "@/components/ui/dropdown-menu";
|
|
29
29
|
import { Spinner } from "@/components/ui/spinner";
|
|
30
30
|
import { useMseVideoSource } from "@/hooks/use-mse-video-source";
|
|
31
|
+
import { usePlaybackPosition } from "@/hooks/use-playback-position";
|
|
31
32
|
import {
|
|
32
33
|
parsePlaybackSpeed,
|
|
33
34
|
readPlaybackSpeedPreference,
|
|
@@ -265,9 +266,12 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
265
266
|
[videoUrl],
|
|
266
267
|
);
|
|
267
268
|
const videoRef = useRef<HTMLVideoElement | null>(null);
|
|
269
|
+
const [playbackVideoEl, setPlaybackVideoEl] =
|
|
270
|
+
useState<HTMLVideoElement | null>(null);
|
|
268
271
|
const setVideoNode = useCallback(
|
|
269
272
|
(el: HTMLVideoElement | null) => {
|
|
270
273
|
videoRef.current = el;
|
|
274
|
+
setPlaybackVideoEl(el);
|
|
271
275
|
onVideoElementChange?.(el);
|
|
272
276
|
},
|
|
273
277
|
[onVideoElementChange],
|
|
@@ -408,6 +412,50 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
408
412
|
() => embedProvider === "loom" || isLoomEmbedUrl(activeVideoSrc),
|
|
409
413
|
[activeVideoSrc, embedProvider],
|
|
410
414
|
);
|
|
415
|
+
const restorePlaybackPosition = useCallback(
|
|
416
|
+
(positionMs: number) => {
|
|
417
|
+
const v = videoRef.current;
|
|
418
|
+
if (!v || (startMs && startMs > 0)) return;
|
|
419
|
+
if (hasPlaybackStarted && !autoPlay) return;
|
|
420
|
+
if (!autoPlay && isPlayPending) return;
|
|
421
|
+
if (!autoPlay && v.currentTime > 0.5) return;
|
|
422
|
+
|
|
423
|
+
const visibleMs = clampSeek(
|
|
424
|
+
skipExcludedRange(positionMs, excludedRanges, resolvedDurationMs),
|
|
425
|
+
v,
|
|
426
|
+
resolvedDurationMs,
|
|
427
|
+
);
|
|
428
|
+
if (visibleMs <= 0) return;
|
|
429
|
+
|
|
430
|
+
try {
|
|
431
|
+
initialVisibleFrameSeekedRef.current = true;
|
|
432
|
+
v.currentTime = visibleMs / 1000;
|
|
433
|
+
setCurrentMs(visibleMs);
|
|
434
|
+
setCanPlay(true);
|
|
435
|
+
setIsPreparing(false);
|
|
436
|
+
onTimeUpdate?.(visibleMs, resolvedDurationMs);
|
|
437
|
+
} catch (error) {
|
|
438
|
+
console.warn("[clips] playback position restore failed", error);
|
|
439
|
+
}
|
|
440
|
+
},
|
|
441
|
+
[
|
|
442
|
+
autoPlay,
|
|
443
|
+
excludedRanges,
|
|
444
|
+
hasPlaybackStarted,
|
|
445
|
+
isPlayPending,
|
|
446
|
+
onTimeUpdate,
|
|
447
|
+
resolvedDurationMs,
|
|
448
|
+
startMs,
|
|
449
|
+
],
|
|
450
|
+
);
|
|
451
|
+
usePlaybackPosition({
|
|
452
|
+
recordingId,
|
|
453
|
+
videoEl: playbackVideoEl,
|
|
454
|
+
durationMs,
|
|
455
|
+
explicitStartMs: startMs,
|
|
456
|
+
allowRestoreWhilePlaying: autoPlay,
|
|
457
|
+
onRestore: restorePlaybackPosition,
|
|
458
|
+
});
|
|
411
459
|
// Clips stores exactly one `videoUrl` per recording (no alternate-format
|
|
412
460
|
// fallback to select between), and every browser MediaRecorder-based
|
|
413
461
|
// recording is stored as `webm` — which Safari (desktop and iOS) cannot
|
|
@@ -1291,11 +1339,12 @@ export const VideoPlayer = forwardRef<VideoPlayerHandle, VideoPlayerProps>(
|
|
|
1291
1339
|
? "loading"
|
|
1292
1340
|
: "ready"
|
|
1293
1341
|
: null;
|
|
1294
|
-
const centerOverlayLabel =
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1342
|
+
const centerOverlayLabel =
|
|
1343
|
+
isPlayPending && !hasPlaybackStarted
|
|
1344
|
+
? "Starting playback"
|
|
1345
|
+
: isPlayPending || isBuffering
|
|
1346
|
+
? "Buffering"
|
|
1347
|
+
: "Preparing clip";
|
|
1299
1348
|
|
|
1300
1349
|
return (
|
|
1301
1350
|
<div
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { useEffect, useRef } from "react";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getPlaybackPosition,
|
|
5
|
+
savePlaybackPosition,
|
|
6
|
+
} from "@/lib/playback-position";
|
|
7
|
+
|
|
8
|
+
const SAVE_INTERVAL_MS = 5_000;
|
|
9
|
+
const MIN_POSITION_MS = 50;
|
|
10
|
+
const COMPLETION_TAIL_MS = 1_500;
|
|
11
|
+
|
|
12
|
+
export interface UsePlaybackPositionOptions {
|
|
13
|
+
recordingId: string;
|
|
14
|
+
videoEl: HTMLVideoElement | null;
|
|
15
|
+
durationMs: number;
|
|
16
|
+
explicitStartMs?: number;
|
|
17
|
+
allowRestoreWhilePlaying?: boolean;
|
|
18
|
+
onRestore?: (positionMs: number) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Persists the latest native-video position for the current viewer. This is
|
|
23
|
+
* separate from view analytics so the recording owner can resume without
|
|
24
|
+
* becoming one of the clip's counted viewers.
|
|
25
|
+
*/
|
|
26
|
+
export function usePlaybackPosition({
|
|
27
|
+
recordingId,
|
|
28
|
+
videoEl,
|
|
29
|
+
durationMs,
|
|
30
|
+
explicitStartMs,
|
|
31
|
+
allowRestoreWhilePlaying = false,
|
|
32
|
+
onRestore,
|
|
33
|
+
}: UsePlaybackPositionOptions) {
|
|
34
|
+
const durationMsRef = useRef(durationMs);
|
|
35
|
+
const onRestoreRef = useRef(onRestore);
|
|
36
|
+
|
|
37
|
+
durationMsRef.current = durationMs;
|
|
38
|
+
onRestoreRef.current = onRestore;
|
|
39
|
+
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
if (!videoEl || !recordingId) return;
|
|
42
|
+
|
|
43
|
+
const controller = new AbortController();
|
|
44
|
+
let cancelled = false;
|
|
45
|
+
let playbackStarted = false;
|
|
46
|
+
let restoreApplied = false;
|
|
47
|
+
let saveInFlight = false;
|
|
48
|
+
let pendingSave: { positionMs: number; keepalive: boolean } | null = null;
|
|
49
|
+
let lastSavedPositionMs = -1;
|
|
50
|
+
let lastSavedAt = -SAVE_INTERVAL_MS;
|
|
51
|
+
let removePendingRestoreListeners: (() => void) | null = null;
|
|
52
|
+
|
|
53
|
+
const readPositionMs = (): number | null => {
|
|
54
|
+
const seconds = videoEl.currentTime;
|
|
55
|
+
if (!Number.isFinite(seconds) || seconds < 0 || seconds >= 1e7) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return Math.floor(seconds * 1000);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const persist = (keepalive: boolean) => {
|
|
62
|
+
const positionMs = readPositionMs();
|
|
63
|
+
if (
|
|
64
|
+
positionMs === null ||
|
|
65
|
+
(!playbackStarted && positionMs < MIN_POSITION_MS)
|
|
66
|
+
) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const now = Date.now();
|
|
71
|
+
if (!keepalive && now - lastSavedAt < SAVE_INTERVAL_MS) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (saveInFlight) {
|
|
76
|
+
pendingSave = { positionMs, keepalive };
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
saveInFlight = true;
|
|
81
|
+
lastSavedPositionMs = positionMs;
|
|
82
|
+
lastSavedAt = now;
|
|
83
|
+
void savePlaybackPosition(recordingId, positionMs, { keepalive })
|
|
84
|
+
.catch((error) => {
|
|
85
|
+
if (!cancelled) {
|
|
86
|
+
console.warn("[clips] playback position save failed", error);
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
.finally(() => {
|
|
90
|
+
saveInFlight = false;
|
|
91
|
+
if (!pendingSave) return;
|
|
92
|
+
const next = pendingSave;
|
|
93
|
+
pendingSave = null;
|
|
94
|
+
persist(next.keepalive);
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const restore = (positionMs: number) => {
|
|
99
|
+
if (cancelled || restoreApplied || explicitStartMs) return;
|
|
100
|
+
if (positionMs <= 0) return;
|
|
101
|
+
const duration = durationMsRef.current;
|
|
102
|
+
if (duration > 0 && positionMs >= duration - COMPLETION_TAIL_MS) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (
|
|
106
|
+
playbackStarted &&
|
|
107
|
+
!allowRestoreWhilePlaying &&
|
|
108
|
+
readPositionMs() !== 0
|
|
109
|
+
) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
restoreApplied = true;
|
|
114
|
+
onRestoreRef.current?.(positionMs);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
const restoreWhenReady = (positionMs: number) => {
|
|
118
|
+
if (videoEl.readyState >= 1) {
|
|
119
|
+
restore(positionMs);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const apply = () => {
|
|
124
|
+
removePendingRestoreListeners?.();
|
|
125
|
+
removePendingRestoreListeners = null;
|
|
126
|
+
restore(positionMs);
|
|
127
|
+
};
|
|
128
|
+
videoEl.addEventListener("loadedmetadata", apply);
|
|
129
|
+
videoEl.addEventListener("loadeddata", apply);
|
|
130
|
+
removePendingRestoreListeners = () => {
|
|
131
|
+
videoEl.removeEventListener("loadedmetadata", apply);
|
|
132
|
+
videoEl.removeEventListener("loadeddata", apply);
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const onPlay = () => {
|
|
137
|
+
playbackStarted = true;
|
|
138
|
+
};
|
|
139
|
+
const onTimeUpdate = () => {
|
|
140
|
+
if (playbackStarted) persist(false);
|
|
141
|
+
};
|
|
142
|
+
const onPause = () => persist(true);
|
|
143
|
+
const onSeeked = () => persist(true);
|
|
144
|
+
const onEnded = () => persist(true);
|
|
145
|
+
const onPageHide = () => persist(true);
|
|
146
|
+
const onVisibilityChange = () => {
|
|
147
|
+
if (document.visibilityState === "hidden") persist(true);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
videoEl.addEventListener("play", onPlay);
|
|
151
|
+
videoEl.addEventListener("timeupdate", onTimeUpdate);
|
|
152
|
+
videoEl.addEventListener("pause", onPause);
|
|
153
|
+
videoEl.addEventListener("seeked", onSeeked);
|
|
154
|
+
videoEl.addEventListener("ended", onEnded);
|
|
155
|
+
window.addEventListener("pagehide", onPageHide);
|
|
156
|
+
document.addEventListener("visibilitychange", onVisibilityChange);
|
|
157
|
+
|
|
158
|
+
if (!explicitStartMs) {
|
|
159
|
+
void getPlaybackPosition(recordingId, { signal: controller.signal })
|
|
160
|
+
.then((positionMs) => {
|
|
161
|
+
if (positionMs !== null) restoreWhenReady(positionMs);
|
|
162
|
+
})
|
|
163
|
+
.catch((error) => {
|
|
164
|
+
if (
|
|
165
|
+
!cancelled &&
|
|
166
|
+
(error as { name?: string })?.name !== "AbortError"
|
|
167
|
+
) {
|
|
168
|
+
console.warn("[clips] playback position load failed", error);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return () => {
|
|
174
|
+
persist(true);
|
|
175
|
+
cancelled = true;
|
|
176
|
+
controller.abort();
|
|
177
|
+
removePendingRestoreListeners?.();
|
|
178
|
+
removePendingRestoreListeners = null;
|
|
179
|
+
videoEl.removeEventListener("play", onPlay);
|
|
180
|
+
videoEl.removeEventListener("timeupdate", onTimeUpdate);
|
|
181
|
+
videoEl.removeEventListener("pause", onPause);
|
|
182
|
+
videoEl.removeEventListener("seeked", onSeeked);
|
|
183
|
+
videoEl.removeEventListener("ended", onEnded);
|
|
184
|
+
window.removeEventListener("pagehide", onPageHide);
|
|
185
|
+
document.removeEventListener("visibilitychange", onVisibilityChange);
|
|
186
|
+
};
|
|
187
|
+
}, [allowRestoreWhilePlaying, explicitStartMs, recordingId, videoEl]);
|
|
188
|
+
}
|
|
@@ -1,27 +1,9 @@
|
|
|
1
1
|
import { appBasePath } from "@agent-native/core/client/api-path";
|
|
2
2
|
import { useEffect, useRef } from "react";
|
|
3
3
|
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
const SESSION_KEY = "clips-view-session-id";
|
|
4
|
+
import { getViewerSessionId } from "@/lib/viewer-session";
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
if (typeof window === "undefined") return "server";
|
|
10
|
-
try {
|
|
11
|
-
let id = localStorage.getItem(SESSION_KEY);
|
|
12
|
-
if (!id) {
|
|
13
|
-
id =
|
|
14
|
-
"s-" +
|
|
15
|
-
Date.now().toString(36) +
|
|
16
|
-
"-" +
|
|
17
|
-
Math.random().toString(36).slice(2, 8);
|
|
18
|
-
localStorage.setItem(SESSION_KEY, id);
|
|
19
|
-
}
|
|
20
|
-
return id;
|
|
21
|
-
} catch {
|
|
22
|
-
return "s-" + Math.random().toString(36).slice(2, 8);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
6
|
+
import { clampCompletionPct } from "../../shared/view-analytics";
|
|
25
7
|
|
|
26
8
|
function createViewSessionId(recordingId: string): string {
|
|
27
9
|
return [
|
|
@@ -118,7 +100,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
|
|
|
118
100
|
recordingId,
|
|
119
101
|
kind: "view-start",
|
|
120
102
|
timestampMs: 0,
|
|
121
|
-
sessionId:
|
|
103
|
+
sessionId: getViewerSessionId(),
|
|
122
104
|
viewSessionId: viewSessionRef.current,
|
|
123
105
|
totalWatchMs: 0,
|
|
124
106
|
completedPct: 0,
|
|
@@ -130,7 +112,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
|
|
|
130
112
|
}
|
|
131
113
|
|
|
132
114
|
const video = videoEl;
|
|
133
|
-
const sessionId =
|
|
115
|
+
const sessionId = getViewerSessionId();
|
|
134
116
|
viewSessionRef.current = createViewSessionId(recordingId);
|
|
135
117
|
let progressTimer: ReturnType<typeof setInterval> | null = null;
|
|
136
118
|
|
|
@@ -243,7 +225,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
|
|
|
243
225
|
body: JSON.stringify({
|
|
244
226
|
recordingId: recordingIdRef.current,
|
|
245
227
|
kind: "cta-click",
|
|
246
|
-
sessionId:
|
|
228
|
+
sessionId: getViewerSessionId(),
|
|
247
229
|
}),
|
|
248
230
|
}).catch(() => {});
|
|
249
231
|
},
|
|
@@ -255,7 +237,7 @@ export function useViewTracking(opts: UseViewTrackingOpts) {
|
|
|
255
237
|
body: JSON.stringify({
|
|
256
238
|
recordingId: recordingIdRef.current,
|
|
257
239
|
kind: "reaction",
|
|
258
|
-
sessionId:
|
|
240
|
+
sessionId: getViewerSessionId(),
|
|
259
241
|
payload: { emoji },
|
|
260
242
|
}),
|
|
261
243
|
}).catch(() => {});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import {
|
|
2
|
+
callAction,
|
|
3
|
+
tryCallActionKeepalive,
|
|
4
|
+
} from "@agent-native/core/client/hooks";
|
|
5
|
+
|
|
6
|
+
import { getViewerSessionId } from "./viewer-session";
|
|
7
|
+
|
|
8
|
+
export interface PlaybackPositionRecord {
|
|
9
|
+
recordingId: string;
|
|
10
|
+
viewerKey: string;
|
|
11
|
+
viewerEmail: string | null;
|
|
12
|
+
positionMs: number;
|
|
13
|
+
updatedAt: string | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface PlaybackPositionActionResult {
|
|
17
|
+
playbackPosition: PlaybackPositionRecord | null;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function parsePlaybackPosition(payload: unknown): number | null {
|
|
21
|
+
if (
|
|
22
|
+
!payload ||
|
|
23
|
+
typeof payload !== "object" ||
|
|
24
|
+
!("playbackPosition" in payload)
|
|
25
|
+
) {
|
|
26
|
+
throw new Error("Invalid playback position response");
|
|
27
|
+
}
|
|
28
|
+
const playbackPosition = (payload as { playbackPosition?: unknown })
|
|
29
|
+
.playbackPosition;
|
|
30
|
+
if (playbackPosition === null) return null;
|
|
31
|
+
if (typeof playbackPosition !== "object") {
|
|
32
|
+
throw new Error("Invalid playback position payload");
|
|
33
|
+
}
|
|
34
|
+
const positionMs = (playbackPosition as { positionMs?: unknown }).positionMs;
|
|
35
|
+
if (
|
|
36
|
+
typeof positionMs !== "number" ||
|
|
37
|
+
!Number.isFinite(positionMs) ||
|
|
38
|
+
positionMs < 0
|
|
39
|
+
) {
|
|
40
|
+
throw new Error("Invalid playback position payload");
|
|
41
|
+
}
|
|
42
|
+
return positionMs;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function getPlaybackPosition(
|
|
46
|
+
recordingId: string,
|
|
47
|
+
options: {
|
|
48
|
+
sessionId?: string;
|
|
49
|
+
signal?: AbortSignal;
|
|
50
|
+
} = {},
|
|
51
|
+
): Promise<number | null> {
|
|
52
|
+
const sessionId = options.sessionId ?? getViewerSessionId();
|
|
53
|
+
const payload = await callAction<PlaybackPositionActionResult>(
|
|
54
|
+
"get-playback-position",
|
|
55
|
+
{ recordingId, sessionId },
|
|
56
|
+
{ method: "GET", signal: options.signal },
|
|
57
|
+
);
|
|
58
|
+
return parsePlaybackPosition(payload);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function savePlaybackPosition(
|
|
62
|
+
recordingId: string,
|
|
63
|
+
positionMs: number,
|
|
64
|
+
options: {
|
|
65
|
+
sessionId?: string;
|
|
66
|
+
signal?: AbortSignal;
|
|
67
|
+
keepalive?: boolean;
|
|
68
|
+
} = {},
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
const sessionId = options.sessionId ?? getViewerSessionId();
|
|
71
|
+
const params = { recordingId, positionMs, sessionId };
|
|
72
|
+
|
|
73
|
+
if (options.keepalive) {
|
|
74
|
+
const request = tryCallActionKeepalive<PlaybackPositionActionResult>(
|
|
75
|
+
"save-playback-position",
|
|
76
|
+
params,
|
|
77
|
+
{ signal: options.signal },
|
|
78
|
+
);
|
|
79
|
+
if (!request.accepted) {
|
|
80
|
+
throw new Error(
|
|
81
|
+
`Failed to save playback position during unload (${request.reason})`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
const payload = await request.completion;
|
|
85
|
+
if (parsePlaybackPosition(payload) === null) {
|
|
86
|
+
throw new Error("Invalid playback position payload");
|
|
87
|
+
}
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const payload = await callAction<PlaybackPositionActionResult>(
|
|
92
|
+
"save-playback-position",
|
|
93
|
+
params,
|
|
94
|
+
{ signal: options.signal },
|
|
95
|
+
);
|
|
96
|
+
if (parsePlaybackPosition(payload) === null) {
|
|
97
|
+
throw new Error("Invalid playback position payload");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const VIEWER_SESSION_STORAGE_KEY = "clips-view-session-id";
|
|
2
|
+
let inMemoryViewerSessionId: string | null = null;
|
|
3
|
+
|
|
4
|
+
function fallbackSessionId(): string {
|
|
5
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function getViewerSessionId(): string {
|
|
9
|
+
if (typeof window === "undefined") {
|
|
10
|
+
if (inMemoryViewerSessionId) return inMemoryViewerSessionId;
|
|
11
|
+
inMemoryViewerSessionId = fallbackSessionId();
|
|
12
|
+
return inMemoryViewerSessionId;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const existing = window.localStorage.getItem(VIEWER_SESSION_STORAGE_KEY);
|
|
17
|
+
if (existing) return existing;
|
|
18
|
+
const next =
|
|
19
|
+
typeof window.crypto?.randomUUID === "function"
|
|
20
|
+
? window.crypto.randomUUID()
|
|
21
|
+
: fallbackSessionId();
|
|
22
|
+
window.localStorage.setItem(VIEWER_SESSION_STORAGE_KEY, next);
|
|
23
|
+
return next;
|
|
24
|
+
} catch {
|
|
25
|
+
if (inMemoryViewerSessionId) return inMemoryViewerSessionId;
|
|
26
|
+
inMemoryViewerSessionId = fallbackSessionId();
|
|
27
|
+
return inMemoryViewerSessionId;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
## Meetings & Dictate
|
|
25
25
|
|
|
26
26
|
- When a user says **"meeting"** they mean a Meetings tab entry, not a Clips recording — _unless_ the recording is linked to a meeting (i.e. `recordings.meeting_id` is non-null), in which case both interpretations are valid and worth mentioning.
|
|
27
|
-
- When suggesting how to enable transcript improvements (cleanup, summary, action items), **lead with Builder.io Connect** — it's the easiest path and requires no key. Mention a BYOK `GEMINI_API_KEY` only as a secondary fallback. The cleanup pipeline does not use direct Groq or OpenAI keys by default; it prefers Luna through Builder or OpenAI, with Gemini as the fallback.
|
|
27
|
+
- When suggesting how to enable transcript improvements (cleanup, summary, action items), **lead with Builder.io Connect** — its free tier is available, it's the easiest path, and it requires no key. Mention a BYOK `GEMINI_API_KEY` only as a secondary fallback. The cleanup pipeline does not use direct Groq or OpenAI keys by default; it prefers Luna through Builder or OpenAI, with Gemini as the fallback.
|
|
28
28
|
- **Per-attendee action items require attendees to actually speak in the recorded audio.** With mic + system audio capture (Meetings default) both sides are heard and tagged by source. With mic-only capture (and all Dictate dictations), remote attendees may be silent in the transcript — call this out before promising attendee-level coverage.
|
|
29
29
|
|
|
30
30
|
## Platform requirements
|
|
@@ -404,6 +404,24 @@ export const recordingViews = table("recording_views", {
|
|
|
404
404
|
viewedAt: text("viewed_at").notNull().default(now()),
|
|
405
405
|
});
|
|
406
406
|
|
|
407
|
+
export const recordingPlaybackPositions = table(
|
|
408
|
+
"recording_playback_positions",
|
|
409
|
+
{
|
|
410
|
+
id: text("id").primaryKey(),
|
|
411
|
+
recordingId: text("recording_id").notNull(),
|
|
412
|
+
viewerKey: text("viewer_key").notNull(),
|
|
413
|
+
viewerEmail: text("viewer_email"),
|
|
414
|
+
positionMs: integer("position_ms").notNull().default(0),
|
|
415
|
+
updatedAt: text("updated_at").notNull().default(now()),
|
|
416
|
+
createdAt: text("created_at").notNull().default(now()),
|
|
417
|
+
},
|
|
418
|
+
(position) => ({
|
|
419
|
+
recordingPlaybackPositionUnique: uniqueIndex(
|
|
420
|
+
"recording_playback_positions_recording_viewer_key_unique_idx",
|
|
421
|
+
).on(position.recordingId, position.viewerKey),
|
|
422
|
+
}),
|
|
423
|
+
);
|
|
424
|
+
|
|
407
425
|
// Agent views — one row per (clip, agent, time bucket). Deliberately separate
|
|
408
426
|
// from `recording_viewers` / `recording_views` so no human-view count can ever
|
|
409
427
|
// pick agents up by forgetting a filter: the human tables stay agent-free.
|
|
@@ -506,7 +506,7 @@ export function transcriptStatusInstructions(
|
|
|
506
506
|
|
|
507
507
|
if (status === "failed" && lowerReason.includes("credits exhausted")) {
|
|
508
508
|
return [
|
|
509
|
-
"Transcription failed because Builder transcription credits are exhausted. Tell the user to upgrade or connect Builder.io credits. Clips uses the browser/macOS native transcript first and Builder transcription on the original recording when native capture is unavailable.",
|
|
509
|
+
"Transcription failed because Builder transcription credits are exhausted. Tell the user to upgrade or connect Builder.io credits (free tier available). Clips uses the browser/macOS native transcript first and Builder transcription on the original recording when native capture is unavailable.",
|
|
510
510
|
];
|
|
511
511
|
}
|
|
512
512
|
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "@agent-native/core/server";
|
|
6
6
|
|
|
7
7
|
export const STORAGE_SETUP_REQUIRED_REASON =
|
|
8
|
-
"Video storage is not connected yet. Connect Builder.io or configure S3-compatible storage to upload clips.";
|
|
8
|
+
"Video storage is not connected yet. Connect Builder.io (free tier available) or configure S3-compatible storage to upload clips.";
|
|
9
9
|
|
|
10
10
|
function appDatabaseUrl(): string {
|
|
11
11
|
const appName = process.env.APP_NAME?.toUpperCase().replace(/-/g, "_");
|
|
@@ -931,6 +931,21 @@ const migrations = runMigrations(
|
|
|
931
931
|
// guard:allow-unscoped — startup migration normalizes a legacy placeholder across all rows.
|
|
932
932
|
sql: `UPDATE recording_agent_views SET agent_label = NULL WHERE agent_label = 'Agent'`,
|
|
933
933
|
},
|
|
934
|
+
{
|
|
935
|
+
version: 58,
|
|
936
|
+
name: "recording-playback-positions",
|
|
937
|
+
sql: `CREATE TABLE IF NOT EXISTS recording_playback_positions (
|
|
938
|
+
id TEXT PRIMARY KEY,
|
|
939
|
+
recording_id TEXT NOT NULL,
|
|
940
|
+
viewer_key TEXT NOT NULL,
|
|
941
|
+
viewer_email TEXT,
|
|
942
|
+
position_ms INTEGER NOT NULL DEFAULT 0,
|
|
943
|
+
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
944
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
945
|
+
);
|
|
946
|
+
CREATE UNIQUE INDEX IF NOT EXISTS recording_playback_positions_recording_viewer_key_unique_idx
|
|
947
|
+
ON recording_playback_positions (recording_id, viewer_key)`,
|
|
948
|
+
},
|
|
934
949
|
],
|
|
935
950
|
{ table: "clips_migrations" },
|
|
936
951
|
);
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
const MAX_BYTES = 5 * 1024 * 1024;
|
|
27
27
|
|
|
28
28
|
const STORAGE_SETUP_REQUIRED_REASON =
|
|
29
|
-
"File storage is not connected yet. Connect Builder.io or configure S3-compatible storage in Settings → File uploads, then retry.";
|
|
29
|
+
"File storage is not connected yet. Connect Builder.io (free tier available) or configure S3-compatible storage in Settings → File uploads, then retry.";
|
|
30
30
|
|
|
31
31
|
function randId(): string {
|
|
32
32
|
const chars =
|
|
@@ -31,6 +31,26 @@ the framework monorepo checkout.
|
|
|
31
31
|
|
|
32
32
|
From a generated app directory:
|
|
33
33
|
|
|
34
|
+
```bash
|
|
35
|
+
pnpm action framework-search --pattern "defineAction"
|
|
36
|
+
pnpm action framework-search --pattern "templates/*/actions/*.ts" --mode glob --scope source
|
|
37
|
+
pnpm action framework-search --pattern "Agent(?:Panel|Sidebar)" --mode regex --scope source
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Use `framework-search` first when a question may cross the docs and source
|
|
41
|
+
boundary. It searches the version-matched framework docs, runtime-visible
|
|
42
|
+
skills, readable Core or Toolkit package source, and first-party template
|
|
43
|
+
corpus in one bounded read-only call. Use `scope: docs` or `scope: source` to
|
|
44
|
+
narrow it, then use the existing focused readers for the page or file you need.
|
|
45
|
+
|
|
46
|
+
The same tool is available in the headless `pnpm agent` loop and every built-in
|
|
47
|
+
app agent. Its default substring mode is safest for ordinary questions; use
|
|
48
|
+
`glob` for wildcard paths, `sql-like` for `%` and `_` wildcards, and `regex`
|
|
49
|
+
for precise structural matches. Results are bounded, so refine the pattern or
|
|
50
|
+
path instead of treating a truncated result as exhaustive.
|
|
51
|
+
|
|
52
|
+
From a generated app directory, the lower-level readers remain available:
|
|
53
|
+
|
|
34
54
|
```bash
|
|
35
55
|
pnpm action docs-search --query "<feature>"
|
|
36
56
|
pnpm action docs-search --slug <slug>
|
|
@@ -41,9 +61,9 @@ pnpm action source-search --path templates/chat/actions/hello.ts
|
|
|
41
61
|
pnpm action source-search --list
|
|
42
62
|
```
|
|
43
63
|
|
|
44
|
-
The headless `pnpm agent` loop and built-in app agent also expose
|
|
45
|
-
`
|
|
46
|
-
|
|
64
|
+
The headless `pnpm agent` loop and built-in app agent also expose read-only
|
|
65
|
+
`framework-search`, `docs-search`, and `source-search` tools. Use the unified
|
|
66
|
+
tool for discovery, then the focused tools for full page or file reads.
|
|
47
67
|
|
|
48
68
|
If the action runner is unavailable, search the package directly:
|
|
49
69
|
|
|
@@ -65,6 +65,22 @@ Contextual agent UI is not a reason to expose every option at once. Start with
|
|
|
65
65
|
the domain task's primary action, reveal review or configuration only when the
|
|
66
66
|
current state needs it, and let the sidebar carry conversational depth.
|
|
67
67
|
|
|
68
|
+
## Visual Direction And Workspace Variety
|
|
69
|
+
|
|
70
|
+
Shared workspace behavior should be consistent without forcing every app into
|
|
71
|
+
the same visual skin. Keep shell and component tokens semantic, then let each
|
|
72
|
+
app declare a named direction in `DESIGN.md` before styling. A new app should
|
|
73
|
+
choose its palette family and composition from the product context, compare
|
|
74
|
+
nearby apps, and avoid inheriting their accent by default. Use the
|
|
75
|
+
`frontend-design` visual-direction reference for mode, palette, type, density,
|
|
76
|
+
shape, anti-references, and the `distill` / `typeset` / `colorize` / `layout` /
|
|
77
|
+
`polish` / `audit` review vocabulary.
|
|
78
|
+
|
|
79
|
+
Do not make warm beige plus terracotta the workspace fallback. Preserve a
|
|
80
|
+
workspace-level brand when one exists; otherwise keep shared chrome neutral and
|
|
81
|
+
allow app-owned accents to distinguish products while retaining accessible
|
|
82
|
+
semantic states and the shared AgentSidebar contract.
|
|
83
|
+
|
|
68
84
|
## Discover Before Building
|
|
69
85
|
|
|
70
86
|
Before creating an app-local version of repeated workspace or agent UI:
|
|
@@ -234,6 +234,19 @@ Use `create-content-database`, `create-inline-content-database`,
|
|
|
234
234
|
`duplicate-document-property`, and `delete-document-property`; do not edit
|
|
235
235
|
property rows or view config via raw SQL when an action can do it.
|
|
236
236
|
|
|
237
|
+
For a bounded migration that must rewrite every existing row body while adding
|
|
238
|
+
new property definitions and values, use `migrate-content-database-rows` rather
|
|
239
|
+
than looping the single-row actions. Its `validate` phase is read-only; `apply`
|
|
240
|
+
commits the complete plan with an idempotency receipt or writes nothing. Read
|
|
241
|
+
the database and every row independently after apply, then call its separate
|
|
242
|
+
`verify` phase with the saved post-apply digest. Only a verified receipt may
|
|
243
|
+
`finalize` the exact legacy property IDs stored in that receipt. `rollback` is
|
|
244
|
+
available before finalize only while the saved post-apply digest still matches,
|
|
245
|
+
so it never overwrites a later edit. The bounded migration accepts ordinary
|
|
246
|
+
databases without attached Sources; source-backed and system databases retain
|
|
247
|
+
their dedicated synchronization actions. If flushing a live row editor changes
|
|
248
|
+
its persisted revision, read the rows again and build a fresh plan.
|
|
249
|
+
|
|
237
250
|
When targeting more than one database row, call `duplicate-database-items` or
|
|
238
251
|
`remove-database-items` once with a native JSON array of `itemIds` or
|
|
239
252
|
`documentIds`. Do not loop `duplicate-database-item` or `delete-document` for
|