@agent-native/core 0.85.7 → 0.86.1
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 +1 -1
- package/corpus/core/CHANGELOG.md +133 -1
- package/corpus/core/README.md +0 -11
- package/corpus/core/docs/content/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ar-SA/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ar-SA/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ar-SA/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ar-SA/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ar-SA/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ar-SA/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ar-SA/workspace-connections.mdx +11 -11
- package/corpus/core/docs/content/locales/de-DE/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/de-DE/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/de-DE/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/de-DE/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/de-DE/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/de-DE/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/de-DE/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/es-ES/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/es-ES/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/es-ES/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/es-ES/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/es-ES/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/es-ES/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/fr-FR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/fr-FR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/fr-FR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/fr-FR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/fr-FR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/fr-FR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/hi-IN/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/hi-IN/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/hi-IN/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/hi-IN/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/hi-IN/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/hi-IN/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ja-JP/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ja-JP/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ja-JP/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ja-JP/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ja-JP/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ja-JP/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/ko-KR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/ko-KR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/ko-KR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/ko-KR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/ko-KR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/ko-KR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/pt-BR/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/pt-BR/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/pt-BR/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/pt-BR/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/pt-BR/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/pt-BR/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/zh-CN/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/zh-CN/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/zh-CN/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/zh-CN/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/zh-CN/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-CN/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/cloneable-saas.mdx +0 -1
- package/corpus/core/docs/content/locales/zh-TW/plan-plugin.mdx +10 -9
- package/corpus/core/docs/content/locales/zh-TW/sharing.mdx +1 -2
- package/corpus/core/docs/content/locales/zh-TW/skills-guide.mdx +2 -3
- package/corpus/core/docs/content/locales/zh-TW/template-plan.mdx +23 -7
- package/corpus/core/docs/content/locales/zh-TW/tracking.mdx +1 -1
- package/corpus/core/docs/content/locales/zh-TW/workspace-connections.mdx +1 -1
- package/corpus/core/docs/content/plan-plugin.mdx +12 -11
- package/corpus/core/docs/content/sharing.mdx +1 -2
- package/corpus/core/docs/content/skills-guide.mdx +4 -3
- package/corpus/core/docs/content/template-plan.mdx +37 -6
- package/corpus/core/docs/content/tracking.mdx +1 -1
- package/corpus/core/docs/content/workspace-connections.mdx +1 -1
- package/corpus/core/package.json +7 -6
- package/corpus/core/src/agent/run-store.ts +1 -1
- package/corpus/core/src/chat-threads/store.ts +73 -11
- package/corpus/core/src/checkpoints/store.ts +13 -2
- package/corpus/core/src/cli/create.ts +3 -4
- package/corpus/core/src/cli/design-connect.ts +469 -9
- package/corpus/core/src/cli/index.ts +13 -0
- package/corpus/core/src/cli/plan-local.ts +281 -24
- package/corpus/core/src/cli/skills.ts +177 -21
- package/corpus/core/src/cli/templates-meta.ts +0 -13
- package/corpus/core/src/cli/visualize-repo.ts +715 -0
- package/corpus/core/src/client/AgentPanel.tsx +10 -0
- package/corpus/core/src/client/AssistantChat.tsx +194 -21
- package/corpus/core/src/client/ErrorBoundary.tsx +67 -12
- package/corpus/core/src/client/ErrorReportActions.tsx +69 -0
- package/corpus/core/src/client/FeedbackButton.tsx +8 -4
- package/corpus/core/src/client/agent-chat-adapter.ts +6 -5
- package/corpus/core/src/client/app-providers.tsx +2 -2
- package/corpus/core/src/client/collab/index.ts +31 -0
- package/corpus/core/src/client/components/LiveCursorOverlay.tsx +16 -1
- package/corpus/core/src/client/components/PresenceBar.tsx +14 -1
- package/corpus/core/src/client/components/RecentEditHighlights.tsx +219 -0
- package/corpus/core/src/client/components/RemoteSelectionRings.tsx +40 -6
- package/corpus/core/src/client/db-admin/DbAdminPage.tsx +41 -13
- package/corpus/core/src/client/db-admin/SqlEditor.tsx +10 -3
- package/corpus/core/src/client/db-admin/TableEditor.tsx +12 -5
- package/corpus/core/src/client/db-admin/useAgentSync.ts +10 -3
- package/corpus/core/src/client/db-admin/useDbAdmin.ts +65 -16
- package/corpus/core/src/client/error-reporting.ts +100 -0
- package/corpus/core/src/client/index.ts +59 -0
- package/corpus/core/src/client/org/OrgSwitcher.tsx +0 -4
- package/corpus/core/src/client/org/RequireActiveOrg.tsx +12 -0
- package/corpus/core/src/client/rich-markdown-editor/SharedRichEditor.tsx +49 -32
- package/corpus/core/src/client/rich-markdown-editor/index.ts +6 -0
- package/corpus/core/src/client/rich-markdown-editor/surgical-apply.ts +192 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +59 -8
- package/corpus/core/src/client/session-replay.ts +181 -15
- package/corpus/core/src/client/sse-event-processor.ts +90 -1
- package/corpus/core/src/client/use-action.ts +123 -25
- package/corpus/core/src/client/use-agent-engine-configured.ts +7 -1
- package/corpus/core/src/client/use-chat-threads.ts +18 -7
- package/corpus/core/src/client/use-db-sync.ts +104 -19
- package/corpus/core/src/client/visual-style-controls.tsx +1088 -0
- package/corpus/core/src/collab/agent-presence.ts +191 -62
- package/corpus/core/src/collab/awareness.ts +83 -6
- package/corpus/core/src/collab/client.ts +89 -146
- package/corpus/core/src/collab/index.ts +34 -0
- package/corpus/core/src/collab/recent-edits.ts +171 -0
- package/corpus/core/src/collab/undo.ts +432 -0
- package/corpus/core/src/collab/ydoc-manager.ts +68 -0
- package/corpus/core/src/connections/catalog.ts +2 -3
- package/corpus/core/src/db/create-get-db.ts +86 -1
- package/corpus/core/src/db/ensure-additive-columns.ts +430 -0
- package/corpus/core/src/db/index.ts +6 -0
- package/corpus/core/src/db/migrations.ts +236 -35
- package/corpus/core/src/db-admin/index.ts +26 -0
- package/corpus/core/src/db-admin/operations.ts +87 -49
- package/corpus/core/src/jobs/scheduler.ts +17 -14
- package/corpus/core/src/localization/default-messages.ts +4 -0
- package/corpus/core/src/observability/traces.ts +182 -1
- package/corpus/core/src/org/context.ts +79 -2
- package/corpus/core/src/server/agent-chat-plugin.ts +10 -6
- package/corpus/core/src/server/auth-marketing.ts +0 -11
- package/corpus/core/src/server/auth.ts +11 -4
- package/corpus/core/src/server/builder-design-systems.ts +328 -9
- package/corpus/core/src/server/collab-plugin.ts +56 -13
- package/corpus/core/src/server/design-token-utils.ts +1 -1
- package/corpus/core/src/server/fusion-app.ts +447 -0
- package/corpus/core/src/server/index.ts +28 -0
- package/corpus/core/src/server/onboarding-html.ts +3 -4
- package/corpus/core/src/server/poll-events.ts +14 -2
- package/corpus/core/src/server/poll.ts +219 -12
- package/corpus/core/src/server/schema-prompt.ts +28 -9
- package/corpus/core/src/settings/store.ts +33 -2
- package/corpus/core/src/sharing/actions/set-resource-visibility.ts +2 -0
- package/corpus/core/src/sharing/actions/share-resource.ts +3 -0
- package/corpus/core/src/sharing/actions/unshare-resource.ts +2 -0
- package/corpus/core/src/styles/agent-native.css +0 -5
- package/corpus/core/src/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/core/src/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/core/src/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/core/src/templates/default/app/root.tsx +47 -0
- package/corpus/core/src/templates/default/package.json +3 -3
- package/corpus/core/src/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/core/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/corpus/core/src/tracking/providers.ts +22 -1
- package/corpus/templates/analytics/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +20 -5
- package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/analytics/AGENTS.md +35 -6
- package/corpus/templates/analytics/actions/delete-db-admin-connection.ts +19 -0
- package/corpus/templates/analytics/actions/list-db-admin-connections.ts +18 -0
- package/corpus/templates/analytics/actions/navigate.ts +28 -4
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +1 -1
- package/corpus/templates/analytics/actions/save-db-admin-connection.ts +33 -0
- package/corpus/templates/analytics/actions/view-screen.ts +65 -0
- package/corpus/templates/analytics/app/components/layout/CommandPalette.tsx +23 -1
- package/corpus/templates/analytics/app/components/layout/Header.tsx +1 -0
- package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +21 -0
- package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +16 -0
- package/corpus/templates/analytics/app/i18n/zh-TW.ts +36 -1
- package/corpus/templates/analytics/app/i18n-data.ts +361 -10
- package/corpus/templates/analytics/app/pages/Agents.tsx +512 -0
- package/corpus/templates/analytics/app/pages/DataSources.tsx +11 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDevToolsPanel.tsx +76 -40
- package/corpus/templates/analytics/app/pages/sessions/session-replay-devtools.ts +5 -0
- package/corpus/templates/analytics/app/routes/agents.tsx +10 -0
- package/corpus/templates/analytics/changelog/2026-07-03-agent-admin-tools-page.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-03-agent-llm-observability-dashboard.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-03-connect-other-app-databases-from-analytics.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-03-session-recordings-now-include-response-bodies-for-5xx-error.md +6 -0
- package/corpus/templates/analytics/docs/schemas/first-party-analytics.md +34 -0
- package/corpus/templates/analytics/docs/schemas/tracked-events.md +6 -0
- package/corpus/templates/analytics/package.json +3 -3
- package/corpus/templates/analytics/seeds/dashboards/agent-observability-llm.json +173 -0
- package/corpus/templates/analytics/server/db/schema.ts +27 -0
- package/corpus/templates/analytics/server/jobs/analytics-alerts.ts +23 -5
- package/corpus/templates/analytics/server/lib/analytics-alerts.ts +58 -13
- package/corpus/templates/analytics/server/lib/dashboard-catalog.ts +23 -0
- package/corpus/templates/analytics/server/lib/dashboard-seeds.ts +5 -0
- package/corpus/templates/analytics/server/lib/db-admin-connections.ts +458 -0
- package/corpus/templates/analytics/server/lib/session-replay-agent-context.ts +120 -8
- package/corpus/templates/analytics/server/lib/session-replay.ts +3 -2
- package/corpus/templates/analytics/server/plugins/db.ts +128 -2
- package/corpus/templates/analytics/server/routes/[base]/_agent-native/analytics-db-admin/[...path].ts +1 -0
- package/corpus/templates/analytics/server/routes/_agent-native/analytics-db-admin/[...path].ts +160 -0
- package/corpus/templates/analytics/server/routes/api/session-replay/agent-diagnostics.json.get.ts +45 -1
- package/corpus/templates/analytics/shared/session-replay-diagnostics.ts +10 -0
- package/corpus/templates/assets/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/corpus/templates/assets/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/assets/package.json +3 -3
- package/corpus/templates/assets/server/plugins/db.ts +63 -2
- package/corpus/templates/brain/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/brain/package.json +3 -3
- package/corpus/templates/brain/server/plugins/db.ts +75 -2
- package/corpus/templates/calendar/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/calendar/package.json +3 -3
- package/corpus/templates/calendar/server/plugins/db.ts +64 -2
- package/corpus/templates/chat/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/chat/package.json +3 -3
- package/corpus/templates/clips/actions/finalize-recording.ts +50 -40
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +8 -6
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +3 -3
- package/corpus/templates/clips/changelog/2026-07-03-mobile-recording-pages-keep-videos-in-a-16-9-player-with-act.md +6 -0
- package/corpus/templates/clips/package.json +3 -3
- package/corpus/templates/clips/server/lib/recording-upload-state.ts +56 -0
- package/corpus/templates/clips/server/plugins/db.ts +68 -1
- package/corpus/templates/clips/server/routes/api/uploads/[recordingId]/chunk.post.ts +27 -3
- package/corpus/templates/content/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/content/actions/edit-document.ts +48 -1
- package/corpus/templates/content/actions/list-documents.ts +101 -94
- package/corpus/templates/content/actions/search-documents.ts +19 -3
- package/corpus/templates/content/actions/update-document.ts +54 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +127 -7
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +97 -2
- package/corpus/templates/content/app/root.tsx +9 -0
- package/corpus/templates/content/changelog/2026-07-03-agent-document-edits-now-appear-as-a-live-collaborator-prese.md +6 -0
- package/corpus/templates/content/changelog/2026-07-03-document-search-and-list-views-load-faster-on-large-workspac.md +6 -0
- package/corpus/templates/content/changelog/2026-07-03-error-screens-now-include-a-feedback-button-with-debug-info.md +6 -0
- package/corpus/templates/content/package.json +3 -3
- package/corpus/templates/content/server/plugins/db.ts +57 -1
- package/corpus/templates/design/.agents/skills/full-app-build/SKILL.md +140 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +20 -0
- package/corpus/templates/design/AGENTS.md +63 -19
- package/corpus/templates/design/actions/add-fusion-screens.ts +91 -0
- package/corpus/templates/design/actions/apply-a11y-fix.ts +5 -1
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +10 -2
- package/corpus/templates/design/actions/apply-fusion-edits.ts +161 -0
- package/corpus/templates/design/actions/apply-visual-edit.ts +34 -1
- package/corpus/templates/design/actions/create-component.ts +5 -1
- package/corpus/templates/design/actions/create-fusion-app.ts +202 -0
- package/corpus/templates/design/actions/deploy-fusion-app.ts +123 -0
- package/corpus/templates/design/actions/edit-design.ts +13 -16
- package/corpus/templates/design/actions/get-design-system.ts +21 -0
- package/corpus/templates/design/actions/get-fusion-deploy-status.ts +86 -0
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +14 -37
- package/corpus/templates/design/actions/list-fusion-edits.ts +96 -0
- package/corpus/templates/design/actions/list-local-files.ts +133 -0
- package/corpus/templates/design/actions/push-fusion-app.ts +62 -0
- package/corpus/templates/design/actions/queue-fusion-edit.ts +112 -0
- package/corpus/templates/design/actions/read-local-file.ts +139 -0
- package/corpus/templates/design/actions/send-fusion-message.ts +69 -0
- package/corpus/templates/design/actions/sync-fusion-app.ts +196 -0
- package/corpus/templates/design/actions/write-local-file.ts +115 -14
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +12 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +379 -0
- package/corpus/templates/design/app/components/design/EditPanel.tsx +149 -73
- package/corpus/templates/design/app/components/design/FusionAppBanner.tsx +328 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +148 -30
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +1 -1
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +567 -6
- package/corpus/templates/design/app/components/design/TweaksPanel.tsx +7 -98
- package/corpus/templates/design/app/components/design/code-workbench/ActivityBar.tsx +85 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +466 -0
- package/corpus/templates/design/app/components/design/code-workbench/SideBar.tsx +114 -0
- package/corpus/templates/design/app/components/design/code-workbench/commands.ts +339 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/Breadcrumbs.tsx +42 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/BufferSync.tsx +128 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/EditorTabs.tsx +372 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +268 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/StatusBar.tsx +208 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-setup.ts +61 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-theme-palette.ts +191 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/monaco-theme.ts +29 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/status-bar-lang.ts +21 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/tab-drag.ts +27 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/ExplorerView.tsx +161 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +555 -0
- package/corpus/templates/design/app/components/design/code-workbench/explorer/file-icons.tsx +115 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +65 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/prettier-format.ts +182 -0
- package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +133 -0
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/QuickInput.tsx +563 -0
- package/corpus/templates/design/app/components/design/code-workbench/quickinput/fuzzy.ts +170 -0
- package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +508 -0
- package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +280 -0
- package/corpus/templates/design/app/components/design/code-workbench/store.tsx +782 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/create-providers.ts +39 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/inline-provider.ts +196 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/localhost-provider.ts +177 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/tree.ts +110 -0
- package/corpus/templates/design/app/components/design/code-workbench/workspace/types.ts +103 -0
- package/corpus/templates/design/app/components/design/code-workbench-theme.ts +68 -0
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +127 -10
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +52 -29
- package/corpus/templates/design/app/components/design/inspector/index.ts +9 -0
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +56 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +80 -1
- package/corpus/templates/design/app/components/visual-editor/SaveStatusIndicator.tsx +6 -16
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +6 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +17 -15
- package/corpus/templates/design/app/i18n-data.ts +185 -160
- package/corpus/templates/design/app/pages/DesignEditor.tsx +1474 -175
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +32 -14
- package/corpus/templates/design/app/pages/Index.tsx +90 -17
- package/corpus/templates/design/changelog/2026-07-03-design-system-setup-now-indexes-figma-code-and-design-md-sou.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-the-ai-now-edits-like-a-collaborator-on-canvas-its-cursor-gl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-the-code-editor-is-easier-to-use-with-top-sidebar-tabs-clear.md +6 -0
- package/corpus/templates/design/changelog/2026-07-03-the-code-panel-is-now-a-full-vs-code-style-editor-with-a-fil.md +6 -0
- package/corpus/templates/design/package.json +4 -3
- package/corpus/templates/design/server/db/schema.ts +31 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +16 -106
- package/corpus/templates/design/server/lib/fusion-screens.ts +246 -0
- package/corpus/templates/design/server/plugins/db.ts +89 -2
- package/corpus/templates/design/shared/collab-selection.ts +52 -0
- package/corpus/templates/design/shared/full-app.ts +126 -0
- package/corpus/templates/design/shared/pen-path.ts +296 -0
- package/corpus/templates/dispatch/package.json +3 -3
- package/corpus/templates/forms/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/forms/package.json +3 -3
- package/corpus/templates/forms/server/plugins/db.ts +62 -2
- package/corpus/templates/macros/package.json +3 -3
- package/corpus/templates/macros/server/plugins/db.ts +63 -2
- package/corpus/templates/mail/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +8 -0
- package/corpus/templates/mail/app/root.tsx +60 -1
- package/corpus/templates/mail/changelog/2026-07-03-error-screens-now-include-a-feedback-button-with-debug-info.md +6 -0
- package/corpus/templates/mail/package.json +3 -3
- package/corpus/templates/mail/server/lib/contact-frequency.ts +42 -15
- package/corpus/templates/mail/server/plugins/db.ts +63 -2
- package/corpus/templates/plan/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/corpus/templates/plan/.agents/skills/visual-plan/SKILL.md +9 -3
- package/corpus/templates/plan/.agents/skills/visualize-repo/SKILL.md +92 -0
- package/corpus/templates/plan/actions/export-visual-plan.ts +5 -0
- package/corpus/templates/plan/actions/get-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/get-plan-version.ts +6 -16
- package/corpus/templates/plan/actions/list-plan-versions.ts +48 -20
- package/corpus/templates/plan/actions/patch-visual-plan-source.ts +41 -1
- package/corpus/templates/plan/actions/promote-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/update-local-plan-comments.ts +4 -2
- package/corpus/templates/plan/actions/update-local-plan-folder.ts +4 -22
- package/corpus/templates/plan/actions/update-visual-plan.ts +60 -1
- package/corpus/templates/plan/agent-native.app-skill.json +10 -0
- package/corpus/templates/plan/app/components/editor/PlanDocumentEditor.tsx +138 -39
- package/corpus/templates/plan/app/components/editor/usePlanUndoStack.ts +165 -23
- package/corpus/templates/plan/app/components/plan/PlanContentRenderer.tsx +80 -4
- package/corpus/templates/plan/app/global.css +11 -9
- package/corpus/templates/plan/app/hooks/use-navigation-state.ts +10 -1
- package/corpus/templates/plan/app/hooks/use-plan-presence.ts +66 -0
- package/corpus/templates/plan/app/i18n/ar-SA.ts +3 -0
- package/corpus/templates/plan/app/i18n/de-DE.ts +4 -0
- package/corpus/templates/plan/app/i18n/en-US.ts +4 -0
- package/corpus/templates/plan/app/i18n/es-ES.ts +4 -0
- package/corpus/templates/plan/app/i18n/fr-FR.ts +4 -0
- package/corpus/templates/plan/app/i18n/hi-IN.ts +3 -0
- package/corpus/templates/plan/app/i18n/ja-JP.ts +4 -0
- package/corpus/templates/plan/app/i18n/ko-KR.ts +4 -0
- package/corpus/templates/plan/app/i18n/pt-BR.ts +4 -0
- package/corpus/templates/plan/app/i18n/zh-CN.ts +3 -0
- package/corpus/templates/plan/app/i18n/zh-TW.ts +3 -0
- package/corpus/templates/plan/app/pages/PlansPage.tsx +289 -66
- package/corpus/templates/plan/changelog/2026-07-03-error-screens-now-include-a-feedback-button-with-debug-info.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-local-visual-plans-and-recaps-can-save-comments-without-sign.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plan-tabs-render-nested-text-instead-of-raw-json.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plans-are-now-fully-real-time-collaborative-multiple-people-.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-plans-open-and-refresh-faster-especially-long-lived-plans-wi.md +6 -0
- package/corpus/templates/plan/changelog/2026-07-03-undo-now-survives-agent-edits-cmd-z-keeps-working-on-your-ow.md +6 -0
- package/corpus/templates/plan/package.json +5 -3
- package/corpus/templates/plan/server/db/schema.ts +12 -0
- package/corpus/templates/plan/server/lib/local-plan-kind.ts +25 -0
- package/corpus/templates/plan/server/lib/plan-versions.ts +83 -1
- package/corpus/templates/plan/server/lib/public-action-paths.ts +0 -2
- package/corpus/templates/plan/server/plans.ts +26 -3
- package/corpus/templates/plan/server/plugins/db.ts +105 -2
- package/corpus/templates/slides/.agents/skills/slide-editing/SKILL.md +8 -4
- package/corpus/templates/slides/AGENTS.md +11 -3
- package/corpus/templates/slides/actions/_agent-presence.ts +48 -0
- package/corpus/templates/slides/actions/add-slide.ts +16 -18
- package/corpus/templates/slides/actions/get-design-system.ts +21 -0
- package/corpus/templates/slides/actions/import-file.ts +15 -7
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +14 -37
- package/corpus/templates/slides/actions/patch-deck.ts +4 -2
- package/corpus/templates/slides/actions/update-slide.ts +114 -77
- package/corpus/templates/slides/actions/view-screen.ts +39 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +32 -8
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +47 -3
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +34 -39
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +507 -72
- package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +346 -0
- package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +56 -6
- package/corpus/templates/slides/app/components/editor/TweaksPanel.tsx +46 -96
- package/corpus/templates/slides/app/components/layout/Layout.tsx +6 -1
- package/corpus/templates/slides/app/components/visual-editor/SaveStatusIndicator.tsx +8 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +589 -176
- package/corpus/templates/slides/app/hooks/use-deck-presence.ts +84 -42
- package/corpus/templates/slides/app/i18n/ar-SA.ts +54 -7
- package/corpus/templates/slides/app/i18n/de-DE.ts +53 -8
- package/corpus/templates/slides/app/i18n/en-US.ts +54 -7
- package/corpus/templates/slides/app/i18n/es-ES.ts +53 -8
- package/corpus/templates/slides/app/i18n/fr-FR.ts +53 -8
- package/corpus/templates/slides/app/i18n/hi-IN.ts +54 -7
- package/corpus/templates/slides/app/i18n/ja-JP.ts +53 -8
- package/corpus/templates/slides/app/i18n/ko-KR.ts +53 -7
- package/corpus/templates/slides/app/i18n/pt-BR.ts +53 -8
- package/corpus/templates/slides/app/i18n/zh-CN.ts +54 -7
- package/corpus/templates/slides/app/i18n/zh-TW.ts +54 -7
- package/corpus/templates/slides/app/lib/canvas-zoom.ts +16 -1
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +28 -16
- package/corpus/templates/slides/changelog/2026-07-03-design-system-setup-now-indexes-figma-code-and-design-md-sou.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-03-figma-style-slide-editing.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-03-see-the-ai-working-with-you-when-the-agent-edits-a-slide-it-.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-03-slide-editing-now-keeps-thumbnails-speaker-notes-styling-and.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-03-undo-redo-is-now-precise-and-safe-with-collaborators-it-only.md +6 -0
- package/corpus/templates/slides/package.json +3 -3
- package/corpus/templates/slides/server/handlers/decks.ts +31 -3
- package/corpus/templates/slides/server/lib/builder-design-system-proxy.ts +16 -104
- package/corpus/templates/slides/server/plugins/db.ts +65 -2
- package/corpus/templates/videos/netlify.toml +1 -12
- package/dist/agent/run-store.js +1 -1
- package/dist/agent/run-store.js.map +1 -1
- package/dist/chat-threads/store.d.ts +9 -1
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +63 -11
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/checkpoints/store.d.ts.map +1 -1
- package/dist/checkpoints/store.js +10 -2
- package/dist/checkpoints/store.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +3 -5
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/design-connect.d.ts +49 -1
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +414 -9
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/index.js +12 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/plan-local.d.ts +24 -0
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +188 -20
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/skills.d.ts +3 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +173 -21
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/templates-meta.d.ts.map +1 -1
- package/dist/cli/templates-meta.js +0 -14
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/cli/visualize-repo.d.ts +49 -0
- package/dist/cli/visualize-repo.d.ts.map +1 -0
- package/dist/cli/visualize-repo.js +561 -0
- package/dist/cli/visualize-repo.js.map +1 -0
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +2 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +175 -18
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/ErrorBoundary.d.ts.map +1 -1
- package/dist/client/ErrorBoundary.js +37 -2
- package/dist/client/ErrorBoundary.js.map +1 -1
- package/dist/client/ErrorReportActions.d.ts +13 -0
- package/dist/client/ErrorReportActions.d.ts.map +1 -0
- package/dist/client/ErrorReportActions.js +14 -0
- package/dist/client/ErrorReportActions.js.map +1 -0
- package/dist/client/FeedbackButton.d.ts +3 -1
- package/dist/client/FeedbackButton.d.ts.map +1 -1
- package/dist/client/FeedbackButton.js +6 -5
- package/dist/client/FeedbackButton.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +6 -5
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/app-providers.d.ts +2 -2
- package/dist/client/app-providers.js.map +1 -1
- package/dist/client/collab/index.d.ts +4 -1
- package/dist/client/collab/index.d.ts.map +1 -1
- package/dist/client/collab/index.js +3 -0
- package/dist/client/collab/index.js.map +1 -1
- package/dist/client/components/LiveCursorOverlay.d.ts.map +1 -1
- package/dist/client/components/LiveCursorOverlay.js +11 -3
- package/dist/client/components/LiveCursorOverlay.js.map +1 -1
- package/dist/client/components/PresenceBar.d.ts.map +1 -1
- package/dist/client/components/PresenceBar.js +6 -1
- package/dist/client/components/PresenceBar.js.map +1 -1
- package/dist/client/components/RecentEditHighlights.d.ts +43 -0
- package/dist/client/components/RecentEditHighlights.d.ts.map +1 -0
- package/dist/client/components/RecentEditHighlights.js +146 -0
- package/dist/client/components/RecentEditHighlights.js.map +1 -0
- package/dist/client/components/RemoteSelectionRings.d.ts +9 -0
- package/dist/client/components/RemoteSelectionRings.d.ts.map +1 -1
- package/dist/client/components/RemoteSelectionRings.js +22 -8
- package/dist/client/components/RemoteSelectionRings.js.map +1 -1
- package/dist/client/db-admin/DbAdminPage.d.ts +9 -1
- package/dist/client/db-admin/DbAdminPage.d.ts.map +1 -1
- package/dist/client/db-admin/DbAdminPage.js +17 -13
- package/dist/client/db-admin/DbAdminPage.js.map +1 -1
- package/dist/client/db-admin/SqlEditor.d.ts +3 -1
- package/dist/client/db-admin/SqlEditor.d.ts.map +1 -1
- package/dist/client/db-admin/SqlEditor.js +3 -3
- package/dist/client/db-admin/SqlEditor.js.map +1 -1
- package/dist/client/db-admin/TableEditor.d.ts +3 -1
- package/dist/client/db-admin/TableEditor.d.ts.map +1 -1
- package/dist/client/db-admin/TableEditor.js +6 -6
- package/dist/client/db-admin/TableEditor.js.map +1 -1
- package/dist/client/db-admin/useAgentSync.d.ts +3 -2
- package/dist/client/db-admin/useAgentSync.d.ts.map +1 -1
- package/dist/client/db-admin/useAgentSync.js +8 -4
- package/dist/client/db-admin/useAgentSync.js.map +1 -1
- package/dist/client/db-admin/useDbAdmin.d.ts +11 -7
- package/dist/client/db-admin/useDbAdmin.d.ts.map +1 -1
- package/dist/client/db-admin/useDbAdmin.js +45 -20
- package/dist/client/db-admin/useDbAdmin.js.map +1 -1
- package/dist/client/error-reporting.d.ts +19 -0
- package/dist/client/error-reporting.d.ts.map +1 -0
- package/dist/client/error-reporting.js +71 -0
- package/dist/client/error-reporting.js.map +1 -0
- package/dist/client/index.d.ts +8 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +9 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/org/OrgSwitcher.d.ts.map +1 -1
- package/dist/client/org/OrgSwitcher.js +1 -3
- package/dist/client/org/OrgSwitcher.js.map +1 -1
- package/dist/client/org/RequireActiveOrg.d.ts.map +1 -1
- package/dist/client/org/RequireActiveOrg.js +2 -1
- package/dist/client/org/RequireActiveOrg.js.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +8 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/SharedRichEditor.js +8 -2
- package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
- package/dist/client/rich-markdown-editor/index.d.ts +1 -0
- package/dist/client/rich-markdown-editor/index.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/index.js +1 -0
- package/dist/client/rich-markdown-editor/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/surgical-apply.d.ts +66 -0
- package/dist/client/rich-markdown-editor/surgical-apply.d.ts.map +1 -0
- package/dist/client/rich-markdown-editor/surgical-apply.js +147 -0
- package/dist/client/rich-markdown-editor/surgical-apply.js.map +1 -0
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts +18 -2
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +39 -8
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/client/session-replay.d.ts +10 -1
- package/dist/client/session-replay.d.ts.map +1 -1
- package/dist/client/session-replay.js +134 -7
- package/dist/client/session-replay.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +81 -1
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/client/use-action.d.ts +24 -0
- package/dist/client/use-action.d.ts.map +1 -1
- package/dist/client/use-action.js +109 -27
- package/dist/client/use-action.js.map +1 -1
- package/dist/client/use-agent-engine-configured.d.ts.map +1 -1
- package/dist/client/use-agent-engine-configured.js +7 -1
- package/dist/client/use-agent-engine-configured.js.map +1 -1
- package/dist/client/use-chat-threads.d.ts.map +1 -1
- package/dist/client/use-chat-threads.js +11 -3
- package/dist/client/use-chat-threads.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +36 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +68 -12
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/visual-style-controls.d.ts +90 -0
- package/dist/client/visual-style-controls.d.ts.map +1 -0
- package/dist/client/visual-style-controls.js +499 -0
- package/dist/client/visual-style-controls.js.map +1 -0
- package/dist/collab/agent-presence.d.ts +51 -5
- package/dist/collab/agent-presence.d.ts.map +1 -1
- package/dist/collab/agent-presence.js +144 -58
- package/dist/collab/agent-presence.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +32 -0
- package/dist/collab/awareness-store.d.ts.map +1 -0
- package/dist/collab/awareness-store.js +0 -0
- package/dist/collab/awareness-store.js.map +1 -0
- package/dist/collab/awareness.d.ts +12 -1
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/awareness.js +53 -5
- package/dist/collab/awareness.js.map +1 -1
- package/dist/collab/client.d.ts +2 -0
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +79 -119
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/index.d.ts +3 -1
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +5 -1
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/recent-edits.d.ts +87 -0
- package/dist/collab/recent-edits.d.ts.map +1 -0
- package/dist/collab/recent-edits.js +116 -0
- package/dist/collab/recent-edits.js.map +1 -0
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/undo.d.ts +121 -0
- package/dist/collab/undo.d.ts.map +1 -0
- package/dist/collab/undo.js +244 -0
- package/dist/collab/undo.js.map +1 -0
- package/dist/collab/ydoc-manager.d.ts +10 -0
- package/dist/collab/ydoc-manager.d.ts.map +1 -1
- package/dist/collab/ydoc-manager.js +57 -0
- package/dist/collab/ydoc-manager.js.map +1 -1
- package/dist/connections/catalog.d.ts +2 -2
- package/dist/connections/catalog.d.ts.map +1 -1
- package/dist/connections/catalog.js +1 -1
- package/dist/connections/catalog.js.map +1 -1
- package/dist/db/create-get-db.d.ts +22 -0
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +73 -1
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/db/ensure-additive-columns.d.ts +93 -0
- package/dist/db/ensure-additive-columns.d.ts.map +1 -0
- package/dist/db/ensure-additive-columns.js +355 -0
- package/dist/db/ensure-additive-columns.js.map +1 -0
- package/dist/db/index.d.ts +1 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -0
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +70 -0
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +196 -33
- package/dist/db/migrations.js.map +1 -1
- package/dist/db-admin/index.d.ts +3 -0
- package/dist/db-admin/index.d.ts.map +1 -0
- package/dist/db-admin/index.js +2 -0
- package/dist/db-admin/index.js.map +1 -0
- package/dist/db-admin/operations.d.ts +26 -5
- package/dist/db-admin/operations.d.ts.map +1 -1
- package/dist/db-admin/operations.js +66 -55
- package/dist/db-admin/operations.js.map +1 -1
- package/dist/jobs/scheduler.js +17 -10
- package/dist/jobs/scheduler.js.map +1 -1
- package/dist/localization/default-messages.d.ts +3 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +3 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +2 -2
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +155 -1
- package/dist/observability/traces.js.map +1 -1
- package/dist/org/context.d.ts +7 -0
- package/dist/org/context.d.ts.map +1 -1
- package/dist/org/context.js +54 -2
- package/dist/org/context.js.map +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +10 -6
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth-marketing.d.ts.map +1 -1
- package/dist/server/auth-marketing.js +0 -10
- package/dist/server/auth-marketing.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +6 -4
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +61 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +219 -14
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/collab-plugin.d.ts.map +1 -1
- package/dist/server/collab-plugin.js +45 -13
- package/dist/server/collab-plugin.js.map +1 -1
- package/dist/server/design-token-utils.d.ts +1 -1
- package/dist/server/design-token-utils.js +1 -1
- package/dist/server/design-token-utils.js.map +1 -1
- package/dist/server/fusion-app.d.ts +107 -0
- package/dist/server/fusion-app.d.ts.map +1 -0
- package/dist/server/fusion-app.js +371 -0
- package/dist/server/fusion-app.js.map +1 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +3 -4
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/poll-events.d.ts +2 -0
- package/dist/server/poll-events.d.ts.map +1 -1
- package/dist/server/poll-events.js +7 -2
- package/dist/server/poll-events.js.map +1 -1
- package/dist/server/poll.d.ts +47 -3
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +176 -10
- package/dist/server/poll.js.map +1 -1
- package/dist/server/schema-prompt.d.ts.map +1 -1
- package/dist/server/schema-prompt.js +24 -7
- package/dist/server/schema-prompt.js.map +1 -1
- package/dist/settings/store.d.ts.map +1 -1
- package/dist/settings/store.js +32 -3
- package/dist/settings/store.js.map +1 -1
- package/dist/sharing/actions/set-resource-visibility.js +2 -0
- package/dist/sharing/actions/set-resource-visibility.js.map +1 -1
- package/dist/sharing/actions/share-resource.d.ts.map +1 -1
- package/dist/sharing/actions/share-resource.js +3 -0
- package/dist/sharing/actions/share-resource.js.map +1 -1
- package/dist/sharing/actions/unshare-resource.js +2 -0
- package/dist/sharing/actions/unshare-resource.js.map +1 -1
- package/dist/styles/agent-native.css +0 -5
- package/dist/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/dist/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/dist/templates/default/app/root.tsx +47 -0
- package/dist/templates/default/package.json +3 -3
- package/dist/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/dist/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/dist/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/dist/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/dist/tracking/providers.d.ts.map +1 -1
- package/dist/tracking/providers.js +17 -1
- package/dist/tracking/providers.js.map +1 -1
- package/docs/content/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ar-SA/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ar-SA/plan-plugin.mdx +10 -9
- package/docs/content/locales/ar-SA/sharing.mdx +1 -2
- package/docs/content/locales/ar-SA/skills-guide.mdx +2 -3
- package/docs/content/locales/ar-SA/template-plan.mdx +23 -7
- package/docs/content/locales/ar-SA/tracking.mdx +1 -1
- package/docs/content/locales/ar-SA/workspace-connections.mdx +11 -11
- package/docs/content/locales/de-DE/cloneable-saas.mdx +0 -1
- package/docs/content/locales/de-DE/plan-plugin.mdx +10 -9
- package/docs/content/locales/de-DE/sharing.mdx +1 -2
- package/docs/content/locales/de-DE/skills-guide.mdx +2 -3
- package/docs/content/locales/de-DE/template-plan.mdx +23 -7
- package/docs/content/locales/de-DE/tracking.mdx +1 -1
- package/docs/content/locales/de-DE/workspace-connections.mdx +1 -1
- package/docs/content/locales/es-ES/cloneable-saas.mdx +0 -1
- package/docs/content/locales/es-ES/plan-plugin.mdx +10 -9
- package/docs/content/locales/es-ES/sharing.mdx +1 -2
- package/docs/content/locales/es-ES/skills-guide.mdx +2 -3
- package/docs/content/locales/es-ES/template-plan.mdx +23 -7
- package/docs/content/locales/es-ES/tracking.mdx +1 -1
- package/docs/content/locales/es-ES/workspace-connections.mdx +1 -1
- package/docs/content/locales/fr-FR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/fr-FR/plan-plugin.mdx +10 -9
- package/docs/content/locales/fr-FR/sharing.mdx +1 -2
- package/docs/content/locales/fr-FR/skills-guide.mdx +2 -3
- package/docs/content/locales/fr-FR/template-plan.mdx +23 -7
- package/docs/content/locales/fr-FR/tracking.mdx +1 -1
- package/docs/content/locales/fr-FR/workspace-connections.mdx +1 -1
- package/docs/content/locales/hi-IN/cloneable-saas.mdx +0 -1
- package/docs/content/locales/hi-IN/plan-plugin.mdx +10 -9
- package/docs/content/locales/hi-IN/sharing.mdx +1 -2
- package/docs/content/locales/hi-IN/skills-guide.mdx +2 -3
- package/docs/content/locales/hi-IN/template-plan.mdx +23 -7
- package/docs/content/locales/hi-IN/tracking.mdx +1 -1
- package/docs/content/locales/hi-IN/workspace-connections.mdx +1 -1
- package/docs/content/locales/ja-JP/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ja-JP/plan-plugin.mdx +10 -9
- package/docs/content/locales/ja-JP/sharing.mdx +1 -2
- package/docs/content/locales/ja-JP/skills-guide.mdx +2 -3
- package/docs/content/locales/ja-JP/template-plan.mdx +23 -7
- package/docs/content/locales/ja-JP/tracking.mdx +1 -1
- package/docs/content/locales/ja-JP/workspace-connections.mdx +1 -1
- package/docs/content/locales/ko-KR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/ko-KR/plan-plugin.mdx +10 -9
- package/docs/content/locales/ko-KR/sharing.mdx +1 -2
- package/docs/content/locales/ko-KR/skills-guide.mdx +2 -3
- package/docs/content/locales/ko-KR/template-plan.mdx +23 -7
- package/docs/content/locales/ko-KR/tracking.mdx +1 -1
- package/docs/content/locales/ko-KR/workspace-connections.mdx +1 -1
- package/docs/content/locales/pt-BR/cloneable-saas.mdx +0 -1
- package/docs/content/locales/pt-BR/plan-plugin.mdx +10 -9
- package/docs/content/locales/pt-BR/sharing.mdx +1 -2
- package/docs/content/locales/pt-BR/skills-guide.mdx +2 -3
- package/docs/content/locales/pt-BR/template-plan.mdx +23 -7
- package/docs/content/locales/pt-BR/tracking.mdx +1 -1
- package/docs/content/locales/pt-BR/workspace-connections.mdx +1 -1
- package/docs/content/locales/zh-CN/cloneable-saas.mdx +0 -1
- package/docs/content/locales/zh-CN/plan-plugin.mdx +10 -9
- package/docs/content/locales/zh-CN/sharing.mdx +1 -2
- package/docs/content/locales/zh-CN/skills-guide.mdx +2 -3
- package/docs/content/locales/zh-CN/template-plan.mdx +23 -7
- package/docs/content/locales/zh-CN/tracking.mdx +1 -1
- package/docs/content/locales/zh-CN/workspace-connections.mdx +1 -1
- package/docs/content/locales/zh-TW/cloneable-saas.mdx +0 -1
- package/docs/content/locales/zh-TW/plan-plugin.mdx +10 -9
- package/docs/content/locales/zh-TW/sharing.mdx +1 -2
- package/docs/content/locales/zh-TW/skills-guide.mdx +2 -3
- package/docs/content/locales/zh-TW/template-plan.mdx +23 -7
- package/docs/content/locales/zh-TW/tracking.mdx +1 -1
- package/docs/content/locales/zh-TW/workspace-connections.mdx +1 -1
- package/docs/content/plan-plugin.mdx +12 -11
- package/docs/content/sharing.mdx +1 -2
- package/docs/content/skills-guide.mdx +4 -3
- package/docs/content/template-plan.mdx +37 -6
- package/docs/content/tracking.mdx +1 -1
- package/docs/content/workspace-connections.mdx +1 -1
- package/package.json +7 -6
- package/src/templates/default/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/src/templates/default/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +8 -0
- package/src/templates/default/app/root.tsx +47 -0
- package/src/templates/default/package.json +3 -3
- package/src/templates/workspace-core/.agents/skills/client-methods/SKILL.md +8 -0
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +22 -0
- package/src/templates/workspace-core/.agents/skills/real-time-collab/SKILL.md +82 -19
- package/src/templates/workspace-core/.agents/skills/real-time-sync/SKILL.md +15 -0
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +8 -0
- package/src/templates/workspace-core/.agents/skills/tracking/SKILL.md +1 -0
- package/corpus/core/docs/content/locales/ar-SA/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/de-DE/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/es-ES/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/fr-FR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/hi-IN/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/ja-JP/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/ko-KR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/pt-BR/template-videos.mdx +0 -336
- package/corpus/core/docs/content/locales/zh-CN/template-videos.mdx +0 -334
- package/corpus/core/docs/content/locales/zh-TW/template-videos.mdx +0 -334
- package/corpus/core/docs/content/template-videos.mdx +0 -332
- package/corpus/templates/design/app/components/design/CodeWorkbenchHost.tsx +0 -697
- package/corpus/templates/slides/app/components/editor/CodeEditor.tsx +0 -49
- package/corpus/templates/videos/.agents/skills/actions/SKILL.md +0 -432
- package/corpus/templates/videos/.agents/skills/animation-tracks/SKILL.md +0 -99
- package/corpus/templates/videos/.agents/skills/capture-learnings/SKILL.md +0 -76
- package/corpus/templates/videos/.agents/skills/composition-management/SKILL.md +0 -106
- package/corpus/templates/videos/.agents/skills/create-skill/SKILL.md +0 -221
- package/corpus/templates/videos/.agents/skills/delegate-to-agent/SKILL.md +0 -263
- package/corpus/templates/videos/.agents/skills/frontend-design/SKILL.md +0 -112
- package/corpus/templates/videos/.agents/skills/security/SKILL.md +0 -263
- package/corpus/templates/videos/.agents/skills/self-modifying-code/SKILL.md +0 -88
- package/corpus/templates/videos/.agents/skills/shadcn-ui/SKILL.md +0 -95
- package/corpus/templates/videos/.builder/ANIMATED_PROPERTIES.md +0 -335
- package/corpus/templates/videos/.builder/KEYFRAME_SYNC.md +0 -166
- package/corpus/templates/videos/.builder/SEAMLESS_SYNC.md +0 -211
- package/corpus/templates/videos/.builder/rules/deploy-app.mdc +0 -22
- package/corpus/templates/videos/.builder/rules/organize-ui.mdc +0 -9
- package/corpus/templates/videos/.builder/skills/remotion/SKILL.md +0 -29
- package/corpus/templates/videos/.builder/skills/remotion/rules/animations.md +0 -27
- package/corpus/templates/videos/.builder/skills/remotion/rules/assets.md +0 -43
- package/corpus/templates/videos/.builder/skills/remotion/rules/audio.md +0 -58
- package/corpus/templates/videos/.builder/skills/remotion/rules/compositions.md +0 -129
- package/corpus/templates/videos/.builder/skills/remotion/rules/fonts.md +0 -47
- package/corpus/templates/videos/.builder/skills/remotion/rules/images.md +0 -41
- package/corpus/templates/videos/.builder/skills/remotion/rules/parameters.md +0 -59
- package/corpus/templates/videos/.builder/skills/remotion/rules/sequencing.md +0 -54
- package/corpus/templates/videos/.builder/skills/remotion/rules/tailwind.md +0 -11
- package/corpus/templates/videos/.builder/skills/remotion/rules/text-animations.md +0 -18
- package/corpus/templates/videos/.builder/skills/remotion/rules/timing.md +0 -103
- package/corpus/templates/videos/.builder/skills/remotion/rules/transparent-videos.md +0 -35
- package/corpus/templates/videos/.builder/skills/remotion/rules/trimming.md +0 -38
- package/corpus/templates/videos/.builder/skills/remotion/rules/videos.md +0 -54
- package/corpus/templates/videos/.dockerignore +0 -62
- package/corpus/templates/videos/.env.example +0 -4
- package/corpus/templates/videos/.oxfmtrc.json +0 -8
- package/corpus/templates/videos/AGENTS.md +0 -46
- package/corpus/templates/videos/CHANGELOG.md +0 -10
- package/corpus/templates/videos/DEVELOPING.md +0 -143
- package/corpus/templates/videos/README.md +0 -33
- package/corpus/templates/videos/actions/analyze-brand-assets.ts +0 -151
- package/corpus/templates/videos/actions/apply-design-system.ts +0 -35
- package/corpus/templates/videos/actions/create-design-system.ts +0 -84
- package/corpus/templates/videos/actions/create-folder.ts +0 -48
- package/corpus/templates/videos/actions/db-connect.ts +0 -45
- package/corpus/templates/videos/actions/db-health.ts +0 -24
- package/corpus/templates/videos/actions/db-status.ts +0 -28
- package/corpus/templates/videos/actions/delete-composition.ts +0 -272
- package/corpus/templates/videos/actions/delete-folder.ts +0 -27
- package/corpus/templates/videos/actions/generate-animated-component.ts +0 -470
- package/corpus/templates/videos/actions/get-composition.ts +0 -36
- package/corpus/templates/videos/actions/get-design-system.ts +0 -35
- package/corpus/templates/videos/actions/import-code.ts +0 -67
- package/corpus/templates/videos/actions/import-design-project.ts +0 -42
- package/corpus/templates/videos/actions/import-document.ts +0 -125
- package/corpus/templates/videos/actions/import-from-url.ts +0 -18
- package/corpus/templates/videos/actions/import-github.ts +0 -182
- package/corpus/templates/videos/actions/list-compositions.ts +0 -32
- package/corpus/templates/videos/actions/list-design-systems.ts +0 -66
- package/corpus/templates/videos/actions/list-folders.ts +0 -61
- package/corpus/templates/videos/actions/move-composition-to-folder.ts +0 -59
- package/corpus/templates/videos/actions/navigate.ts +0 -40
- package/corpus/templates/videos/actions/rename-folder.ts +0 -41
- package/corpus/templates/videos/actions/run.ts +0 -2
- package/corpus/templates/videos/actions/save-composition.ts +0 -114
- package/corpus/templates/videos/actions/set-default-design-system.ts +0 -40
- package/corpus/templates/videos/actions/update-composition.ts +0 -81
- package/corpus/templates/videos/actions/update-design-system.ts +0 -68
- package/corpus/templates/videos/actions/validate-compositions.ts +0 -502
- package/corpus/templates/videos/actions/view-screen.ts +0 -48
- package/corpus/templates/videos/app/components/CameraControls.tsx +0 -442
- package/corpus/templates/videos/app/components/CameraToolbar.tsx +0 -437
- package/corpus/templates/videos/app/components/CloudUpgrade.tsx +0 -287
- package/corpus/templates/videos/app/components/CollabPresenceBar.tsx +0 -81
- package/corpus/templates/videos/app/components/CompSettingsEditor.tsx +0 -107
- package/corpus/templates/videos/app/components/ComponentLibrarySidebar.tsx +0 -457
- package/corpus/templates/videos/app/components/ComponentPropsPanel.tsx +0 -227
- package/corpus/templates/videos/app/components/ComponentsSidebar.tsx +0 -70
- package/corpus/templates/videos/app/components/CompositionCard.tsx +0 -147
- package/corpus/templates/videos/app/components/CurrentElementPanel.tsx +0 -835
- package/corpus/templates/videos/app/components/CursorControls.tsx +0 -664
- package/corpus/templates/videos/app/components/CursorPositioningOverlay.tsx +0 -238
- package/corpus/templates/videos/app/components/LibraryFolderRow.tsx +0 -235
- package/corpus/templates/videos/app/components/MotionCurveSelect.tsx +0 -61
- package/corpus/templates/videos/app/components/NewCompositionPopover.tsx +0 -192
- package/corpus/templates/videos/app/components/PropsEditor.tsx +0 -210
- package/corpus/templates/videos/app/components/QuestionFlow.tsx +0 -40
- package/corpus/templates/videos/app/components/Sidebar.tsx +0 -609
- package/corpus/templates/videos/app/components/StudioHeader.tsx +0 -109
- package/corpus/templates/videos/app/components/Timeline.tsx +0 -2067
- package/corpus/templates/videos/app/components/TrackPropertiesPanel.tsx +0 -922
- package/corpus/templates/videos/app/components/TweaksPanel.tsx +0 -277
- package/corpus/templates/videos/app/components/VideoPlayer.tsx +0 -487
- package/corpus/templates/videos/app/components/design-system/DesignSystemCard.tsx +0 -134
- package/corpus/templates/videos/app/components/design-system/DesignSystemPreview.tsx +0 -176
- package/corpus/templates/videos/app/components/design-system/DesignSystemSetup.tsx +0 -707
- package/corpus/templates/videos/app/components/keyframes/KeyframeActionButtons.tsx +0 -78
- package/corpus/templates/videos/app/components/keyframes/KeyframeNavigation.tsx +0 -59
- package/corpus/templates/videos/app/components/keyframes/PropertyNumberInput.tsx +0 -56
- package/corpus/templates/videos/app/components/layout/Header.tsx +0 -64
- package/corpus/templates/videos/app/components/layout/HeaderActions.tsx +0 -84
- package/corpus/templates/videos/app/components/layout/Layout.tsx +0 -132
- package/corpus/templates/videos/app/components/layout/NavSidebar.tsx +0 -180
- package/corpus/templates/videos/app/components/ui/accordion.tsx +0 -56
- package/corpus/templates/videos/app/components/ui/alert-dialog.tsx +0 -139
- package/corpus/templates/videos/app/components/ui/alert.tsx +0 -59
- package/corpus/templates/videos/app/components/ui/aspect-ratio.tsx +0 -5
- package/corpus/templates/videos/app/components/ui/avatar.tsx +0 -48
- package/corpus/templates/videos/app/components/ui/badge.tsx +0 -37
- package/corpus/templates/videos/app/components/ui/breadcrumb.tsx +0 -115
- package/corpus/templates/videos/app/components/ui/button.tsx +0 -57
- package/corpus/templates/videos/app/components/ui/calendar.tsx +0 -68
- package/corpus/templates/videos/app/components/ui/card.tsx +0 -86
- package/corpus/templates/videos/app/components/ui/carousel.tsx +0 -260
- package/corpus/templates/videos/app/components/ui/chart.tsx +0 -375
- package/corpus/templates/videos/app/components/ui/checkbox.tsx +0 -28
- package/corpus/templates/videos/app/components/ui/collapsible.tsx +0 -9
- package/corpus/templates/videos/app/components/ui/command.tsx +0 -154
- package/corpus/templates/videos/app/components/ui/context-menu.tsx +0 -202
- package/corpus/templates/videos/app/components/ui/dialog.tsx +0 -130
- package/corpus/templates/videos/app/components/ui/drawer.tsx +0 -116
- package/corpus/templates/videos/app/components/ui/dropdown-menu.tsx +0 -212
- package/corpus/templates/videos/app/components/ui/form.tsx +0 -177
- package/corpus/templates/videos/app/components/ui/hover-card.tsx +0 -27
- package/corpus/templates/videos/app/components/ui/input-otp.tsx +0 -69
- package/corpus/templates/videos/app/components/ui/input.tsx +0 -22
- package/corpus/templates/videos/app/components/ui/label.tsx +0 -24
- package/corpus/templates/videos/app/components/ui/menubar.tsx +0 -234
- package/corpus/templates/videos/app/components/ui/navigation-menu.tsx +0 -128
- package/corpus/templates/videos/app/components/ui/pagination.tsx +0 -121
- package/corpus/templates/videos/app/components/ui/popover.tsx +0 -44
- package/corpus/templates/videos/app/components/ui/progress.tsx +0 -26
- package/corpus/templates/videos/app/components/ui/radio-group.tsx +0 -42
- package/corpus/templates/videos/app/components/ui/resizable.tsx +0 -43
- package/corpus/templates/videos/app/components/ui/scroll-area.tsx +0 -46
- package/corpus/templates/videos/app/components/ui/select.tsx +0 -158
- package/corpus/templates/videos/app/components/ui/separator.tsx +0 -29
- package/corpus/templates/videos/app/components/ui/sheet.tsx +0 -160
- package/corpus/templates/videos/app/components/ui/sidebar.tsx +0 -782
- package/corpus/templates/videos/app/components/ui/skeleton.tsx +0 -15
- package/corpus/templates/videos/app/components/ui/slider.tsx +0 -26
- package/corpus/templates/videos/app/components/ui/sonner.tsx +0 -58
- package/corpus/templates/videos/app/components/ui/spinner.tsx +0 -17
- package/corpus/templates/videos/app/components/ui/switch.tsx +0 -27
- package/corpus/templates/videos/app/components/ui/table.tsx +0 -117
- package/corpus/templates/videos/app/components/ui/tabs.tsx +0 -53
- package/corpus/templates/videos/app/components/ui/textarea.tsx +0 -23
- package/corpus/templates/videos/app/components/ui/toast.tsx +0 -127
- package/corpus/templates/videos/app/components/ui/toaster.tsx +0 -33
- package/corpus/templates/videos/app/components/ui/toggle-group.tsx +0 -59
- package/corpus/templates/videos/app/components/ui/toggle.tsx +0 -43
- package/corpus/templates/videos/app/components/ui/tooltip.tsx +0 -30
- package/corpus/templates/videos/app/components/ui/use-toast.ts +0 -3
- package/corpus/templates/videos/app/config/constants.ts +0 -204
- package/corpus/templates/videos/app/contexts/CompositionContext.tsx +0 -437
- package/corpus/templates/videos/app/contexts/CurrentElementContext.tsx +0 -247
- package/corpus/templates/videos/app/contexts/PlaybackContext.tsx +0 -65
- package/corpus/templates/videos/app/contexts/TimelineContext.tsx +0 -433
- package/corpus/templates/videos/app/entry.client.tsx +0 -19
- package/corpus/templates/videos/app/entry.server.tsx +0 -10
- package/corpus/templates/videos/app/global.css +0 -171
- package/corpus/templates/videos/app/hooks/use-composition-collab.ts +0 -269
- package/corpus/templates/videos/app/hooks/use-composition-design-system.ts +0 -47
- package/corpus/templates/videos/app/hooks/use-database-compositions.ts +0 -144
- package/corpus/templates/videos/app/hooks/use-db-status.ts +0 -30
- package/corpus/templates/videos/app/hooks/use-design-systems.ts +0 -21
- package/corpus/templates/videos/app/hooks/use-folders.ts +0 -199
- package/corpus/templates/videos/app/hooks/use-mobile.tsx +0 -21
- package/corpus/templates/videos/app/hooks/use-navigation-state.ts +0 -52
- package/corpus/templates/videos/app/hooks/use-question-flow.ts +0 -14
- package/corpus/templates/videos/app/hooks/use-toast.ts +0 -188
- package/corpus/templates/videos/app/hooks/useUnsavedChanges.ts +0 -48
- package/corpus/templates/videos/app/i18n/ar-SA.ts +0 -446
- package/corpus/templates/videos/app/i18n/de-DE.ts +0 -470
- package/corpus/templates/videos/app/i18n/en-US.ts +0 -452
- package/corpus/templates/videos/app/i18n/es-ES.ts +0 -468
- package/corpus/templates/videos/app/i18n/fr-FR.ts +0 -469
- package/corpus/templates/videos/app/i18n/hi-IN.ts +0 -446
- package/corpus/templates/videos/app/i18n/index.ts +0 -34
- package/corpus/templates/videos/app/i18n/ja-JP.ts +0 -460
- package/corpus/templates/videos/app/i18n/ko-KR.ts +0 -453
- package/corpus/templates/videos/app/i18n/pt-BR.ts +0 -461
- package/corpus/templates/videos/app/i18n/zh-CN.ts +0 -437
- package/corpus/templates/videos/app/i18n/zh-TW.ts +0 -437
- package/corpus/templates/videos/app/lib/database-compositions.ts +0 -67
- package/corpus/templates/videos/app/lib/design-systems.ts +0 -234
- package/corpus/templates/videos/app/lib/tab-id.ts +0 -1
- package/corpus/templates/videos/app/lib/utils.ts +0 -1
- package/corpus/templates/videos/app/pages/ComponentLibrary.tsx +0 -134
- package/corpus/templates/videos/app/pages/ComponentLibraryView.tsx +0 -362
- package/corpus/templates/videos/app/pages/CompositionView.tsx +0 -715
- package/corpus/templates/videos/app/pages/DesignSystems.tsx +0 -180
- package/corpus/templates/videos/app/pages/Index.tsx +0 -258
- package/corpus/templates/videos/app/pages/NewComposition.tsx +0 -95
- package/corpus/templates/videos/app/pages/NotFound.tsx +0 -36
- package/corpus/templates/videos/app/remotion/CameraHost.tsx +0 -223
- package/corpus/templates/videos/app/remotion/animations/useElementAnimations.ts +0 -231
- package/corpus/templates/videos/app/remotion/componentRegistry.ts +0 -473
- package/corpus/templates/videos/app/remotion/components/AnimatedElement.tsx +0 -436
- package/corpus/templates/videos/app/remotion/components/InteractiveElement.tsx +0 -159
- package/corpus/templates/videos/app/remotion/components/InteractiveZoneEditor.tsx +0 -273
- package/corpus/templates/videos/app/remotion/compositions/BlankComposition.tsx +0 -204
- package/corpus/templates/videos/app/remotion/compositions/index.ts +0 -2
- package/corpus/templates/videos/app/remotion/createComponentCursorTrack.ts +0 -132
- package/corpus/templates/videos/app/remotion/docs/CURSOR_TRACKS.md +0 -285
- package/corpus/templates/videos/app/remotion/easingFunctions.ts +0 -255
- package/corpus/templates/videos/app/remotion/hooks/createInteractiveComposition.tsx +0 -283
- package/corpus/templates/videos/app/remotion/hooks/useCursorHistory.ts +0 -72
- package/corpus/templates/videos/app/remotion/hooks/useCursorTypeFromHover.ts +0 -35
- package/corpus/templates/videos/app/remotion/hooks/useEditableZones.tsx +0 -267
- package/corpus/templates/videos/app/remotion/hooks/useHoverAnimation.ts +0 -90
- package/corpus/templates/videos/app/remotion/hooks/useHoverAnimationSmooth.ts +0 -146
- package/corpus/templates/videos/app/remotion/hooks/useInteractiveComponent.ts +0 -711
- package/corpus/templates/videos/app/remotion/hooks/useRegisterInteractiveElement.ts +0 -56
- package/corpus/templates/videos/app/remotion/library-components/Button.tsx +0 -252
- package/corpus/templates/videos/app/remotion/library-components/Card.tsx +0 -241
- package/corpus/templates/videos/app/remotion/library-components/CodePanel.tsx +0 -1005
- package/corpus/templates/videos/app/remotion/library-components/FileItem.tsx +0 -196
- package/corpus/templates/videos/app/remotion/library-components/FolderItem.tsx +0 -199
- package/corpus/templates/videos/app/remotion/library-components/PrimaryButton.tsx +0 -177
- package/corpus/templates/videos/app/remotion/library-components/SecondaryButton.tsx +0 -167
- package/corpus/templates/videos/app/remotion/library-components/SectionHeader.tsx +0 -108
- package/corpus/templates/videos/app/remotion/library-components/TEMPLATE.tsx +0 -211
- package/corpus/templates/videos/app/remotion/library-components/index.ts +0 -10
- package/corpus/templates/videos/app/remotion/registry.ts +0 -91
- package/corpus/templates/videos/app/remotion/testing/animationTestUtils.ts +0 -366
- package/corpus/templates/videos/app/remotion/trackAnimation.ts +0 -179
- package/corpus/templates/videos/app/remotion/trackHelpers.ts +0 -110
- package/corpus/templates/videos/app/remotion/ui-components/Cursor.tsx +0 -182
- package/corpus/templates/videos/app/remotion/ui-components/InteractiveButton.tsx +0 -116
- package/corpus/templates/videos/app/remotion/ui-components/InteractiveCard.tsx +0 -126
- package/corpus/templates/videos/app/remotion/ui-components/index.ts +0 -16
- package/corpus/templates/videos/app/remotion/utils/animationHelpers.ts +0 -444
- package/corpus/templates/videos/app/remotion/utils/interactiveElements.ts +0 -235
- package/corpus/templates/videos/app/remotion/utils/springAnimation.ts +0 -76
- package/corpus/templates/videos/app/root.tsx +0 -165
- package/corpus/templates/videos/app/routes/$.tsx +0 -10
- package/corpus/templates/videos/app/routes/_index.tsx +0 -25
- package/corpus/templates/videos/app/routes/c.$compositionId.tsx +0 -10
- package/corpus/templates/videos/app/routes/components.tsx +0 -10
- package/corpus/templates/videos/app/routes/design-systems.tsx +0 -10
- package/corpus/templates/videos/app/routes/extensions.$id.$slug.tsx +0 -2
- package/corpus/templates/videos/app/routes/extensions.$id.tsx +0 -5
- package/corpus/templates/videos/app/routes/extensions._index.tsx +0 -5
- package/corpus/templates/videos/app/routes/extensions.tsx +0 -5
- package/corpus/templates/videos/app/routes/settings.tsx +0 -88
- package/corpus/templates/videos/app/routes/team.tsx +0 -11
- package/corpus/templates/videos/app/routes.ts +0 -4
- package/corpus/templates/videos/app/state.ts +0 -77
- package/corpus/templates/videos/app/types/elementAnimations.ts +0 -121
- package/corpus/templates/videos/app/types.ts +0 -200
- package/corpus/templates/videos/app/utils/compositionHelpers.ts +0 -445
- package/corpus/templates/videos/app/utils/debug.ts +0 -63
- package/corpus/templates/videos/app/utils/keyframeUtils.ts +0 -331
- package/corpus/templates/videos/app/utils/timelineCoordinates.ts +0 -79
- package/corpus/templates/videos/app/vite-env.d.ts +0 -6
- package/corpus/templates/videos/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-28-left-sidebar-collapses-into-an-animated-icon-rail.md +0 -6
- package/corpus/templates/videos/changelog/2026-06-29-video-layouts-adapt-when-the-agent-sidebar-is-open.md +0 -6
- package/corpus/templates/videos/components.json +0 -20
- package/corpus/templates/videos/data/sync-config.json +0 -3
- package/corpus/templates/videos/docs/examples/create-composition.example.ts +0 -128
- package/corpus/templates/videos/drizzle.config.ts +0 -3
- package/corpus/templates/videos/learnings.defaults.md +0 -5
- package/corpus/templates/videos/package.json +0 -114
- package/corpus/templates/videos/public/agent-native-icon-dark.svg +0 -10
- package/corpus/templates/videos/public/agent-native-icon-light.svg +0 -10
- package/corpus/templates/videos/public/agent-native-logo-dark.svg +0 -21
- package/corpus/templates/videos/public/agent-native-logo-light.svg +0 -21
- package/corpus/templates/videos/public/favicon.svg +0 -1
- package/corpus/templates/videos/public/icon-180.svg +0 -1
- package/corpus/templates/videos/public/icon-192.svg +0 -1
- package/corpus/templates/videos/public/icon-512.svg +0 -1
- package/corpus/templates/videos/public/manifest.json +0 -21
- package/corpus/templates/videos/public/placeholder.svg +0 -1
- package/corpus/templates/videos/public/robots.txt +0 -14
- package/corpus/templates/videos/react-router.config.ts +0 -7
- package/corpus/templates/videos/server/db/index.ts +0 -37
- package/corpus/templates/videos/server/db/schema.ts +0 -55
- package/corpus/templates/videos/server/middleware/auth.ts +0 -15
- package/corpus/templates/videos/server/plugins/agent-chat.ts +0 -29
- package/corpus/templates/videos/server/plugins/auth.ts +0 -14
- package/corpus/templates/videos/server/plugins/collab.ts +0 -11
- package/corpus/templates/videos/server/plugins/core-routes.ts +0 -22
- package/corpus/templates/videos/server/plugins/db.ts +0 -160
- package/corpus/templates/videos/server/routes/[...page].get.ts +0 -5
- package/corpus/templates/videos/server/routes/[...page].head.ts +0 -1
- package/corpus/templates/videos/server/routes/api/save-composition-defaults.post.ts +0 -274
- package/corpus/templates/videos/shared/api.ts +0 -75
- package/corpus/templates/videos/ssr-entry.ts +0 -15
- package/corpus/templates/videos/tsconfig.json +0 -21
- package/corpus/templates/videos/vite.config.ts +0 -19
- package/corpus/templates/videos/vitest.config.ts +0 -16
- package/docs/content/locales/ar-SA/template-videos.mdx +0 -336
- package/docs/content/locales/de-DE/template-videos.mdx +0 -336
- package/docs/content/locales/es-ES/template-videos.mdx +0 -336
- package/docs/content/locales/fr-FR/template-videos.mdx +0 -336
- package/docs/content/locales/hi-IN/template-videos.mdx +0 -336
- package/docs/content/locales/ja-JP/template-videos.mdx +0 -336
- package/docs/content/locales/ko-KR/template-videos.mdx +0 -336
- package/docs/content/locales/pt-BR/template-videos.mdx +0 -336
- package/docs/content/locales/zh-CN/template-videos.mdx +0 -334
- package/docs/content/locales/zh-TW/template-videos.mdx +0 -334
- package/docs/content/template-videos.mdx +0 -332
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visual-style-controls.js","sourceRoot":"","sources":["../../src/client/visual-style-controls.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconColorPicker } from \"@tabler/icons-react\";\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type KeyboardEvent,\n type PointerEvent,\n type ReactNode,\n} from \"react\";\n\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"./components/ui/popover.js\";\nimport { cn } from \"./utils.js\";\n\nexport type VisualControlValue = string | number | boolean;\n\nexport interface VisualControlOption {\n label: string;\n value: string;\n color?: string;\n}\n\nexport interface VisualTweakDefinition {\n id: string;\n label: string;\n type: \"color-swatch\" | \"color-swatches\" | \"segment\" | \"slider\" | \"toggle\";\n options?: VisualControlOption[];\n min?: number;\n max?: number;\n step?: number;\n defaultValue: VisualControlValue;\n cssVar?: string;\n unit?: string;\n}\n\nfunction clampNumber(value: number, min?: number, max?: number) {\n let next = value;\n if (typeof min === \"number\") next = Math.max(min, next);\n if (typeof max === \"number\") next = Math.min(max, next);\n return next;\n}\n\nfunction formatNumber(value: number, unit?: string) {\n const rounded = Number.isInteger(value) ? value : Number(value.toFixed(2));\n return unit ? `${rounded}${unit}` : String(rounded);\n}\n\nfunction parseDraftNumber(value: string, fallback: number) {\n const match = value.trim().match(/-?\\d+(?:\\.\\d+)?/);\n if (!match) return fallback;\n const next = Number(match[0]);\n return Number.isFinite(next) ? next : fallback;\n}\n\ninterface RgbaColor {\n r: number;\n g: number;\n b: number;\n a: number;\n}\n\ninterface HsvaColor {\n h: number;\n s: number;\n v: number;\n a: number;\n}\n\nconst CHECKERBOARD_IMAGE =\n \"linear-gradient(45deg, #d4d4d4 25%, transparent 25%), linear-gradient(-45deg, #d4d4d4 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #d4d4d4 75%), linear-gradient(-45deg, transparent 75%, #d4d4d4 75%)\";\nconst FALLBACK_RGBA: RgbaColor = { r: 0, g: 0, b: 0, a: 1 };\n\nfunction normalizeRgba(color: RgbaColor): RgbaColor {\n return {\n r: clamp(color.r, 0, 255),\n g: clamp(color.g, 0, 255),\n b: clamp(color.b, 0, 255),\n a: clampFloat(color.a, 0, 1),\n };\n}\n\nfunction normalizeHexColor(value: string): string | null {\n const trimmed = value.trim();\n if (/^#[0-9a-f]{6}$/i.test(trimmed)) return trimmed.toUpperCase();\n if (/^[0-9a-f]{6}$/i.test(trimmed)) return `#${trimmed}`.toUpperCase();\n if (/^#[0-9a-f]{3}$/i.test(trimmed)) {\n return `#${trimmed\n .slice(1)\n .split(\"\")\n .map((char) => char + char)\n .join(\"\")}`.toUpperCase();\n }\n if (/^[0-9a-f]{3}$/i.test(trimmed)) {\n return `#${trimmed\n .split(\"\")\n .map((char) => char + char)\n .join(\"\")}`.toUpperCase();\n }\n return null;\n}\n\nfunction parseCssColor(value: string): RgbaColor | null {\n const trimmed = value.trim();\n if (!trimmed) return null;\n const normalizedHex = normalizeHexColor(trimmed);\n if (normalizedHex) {\n return normalizeRgba({\n r: Number.parseInt(normalizedHex.slice(1, 3), 16),\n g: Number.parseInt(normalizedHex.slice(3, 5), 16),\n b: Number.parseInt(normalizedHex.slice(5, 7), 16),\n a: 1,\n });\n }\n const rgb = trimmed.match(\n /^rgba?\\(\\s*(\\d+(?:\\.\\d+)?)\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*,\\s*(\\d+(?:\\.\\d+)?)(?:\\s*,\\s*([0-9.]+%?))?/i,\n );\n if (rgb) {\n return normalizeRgba({\n r: Number(rgb[1]),\n g: Number(rgb[2]),\n b: Number(rgb[3]),\n a: parseAlpha(rgb[4]),\n });\n }\n const lower = trimmed.toLowerCase();\n if (lower === \"transparent\" || lower === \"rgba(0, 0, 0, 0)\") {\n return { r: 0, g: 0, b: 0, a: 0 };\n }\n return null;\n}\n\nfunction channelToHex(value: number): string {\n return clamp(value, 0, 255).toString(16).padStart(2, \"0\");\n}\n\nfunction rgbaToHex(color: RgbaColor): string {\n const normalized = normalizeRgba(color);\n return `#${channelToHex(normalized.r)}${channelToHex(normalized.g)}${channelToHex(normalized.b)}`.toUpperCase();\n}\n\nfunction rgbaToCss(color: RgbaColor): string {\n const normalized = normalizeRgba(color);\n if (normalized.a >= 1) return rgbaToHex(normalized);\n return `rgba(${normalized.r}, ${normalized.g}, ${normalized.b}, ${trimNumber(normalized.a)})`;\n}\n\nfunction parseAlpha(value: string | undefined): number {\n if (!value) return 1;\n if (value.endsWith(\"%\")) return Number(value.slice(0, -1)) / 100;\n return Number(value);\n}\n\nfunction trimNumber(value: number) {\n return Number(value.toFixed(2)).toString();\n}\n\nfunction rgbaToHsv(color: RgbaColor): HsvaColor {\n const normalized = normalizeRgba(color);\n const r = normalized.r / 255;\n const g = normalized.g / 255;\n const b = normalized.b / 255;\n const max = Math.max(r, g, b);\n const min = Math.min(r, g, b);\n const delta = max - min;\n\n let h = 0;\n if (delta !== 0) {\n if (max === r) h = ((g - b) / delta) % 6;\n else if (max === g) h = (b - r) / delta + 2;\n else h = (r - g) / delta + 4;\n h *= 60;\n if (h < 0) h += 360;\n }\n\n return {\n h: Math.round(h),\n s: max === 0 ? 0 : Math.round((delta / max) * 100),\n v: Math.round(max * 100),\n a: normalized.a,\n };\n}\n\nfunction hsvToRgba(color: HsvaColor): RgbaColor {\n const h = ((color.h % 360) + 360) % 360;\n const s = clampFloat(color.s, 0, 100) / 100;\n const v = clampFloat(color.v, 0, 100) / 100;\n const chroma = v * s;\n const x = chroma * (1 - Math.abs(((h / 60) % 2) - 1));\n const m = v - chroma;\n\n let r = 0;\n let g = 0;\n let b = 0;\n if (h < 60) [r, g, b] = [chroma, x, 0];\n else if (h < 120) [r, g, b] = [x, chroma, 0];\n else if (h < 180) [r, g, b] = [0, chroma, x];\n else if (h < 240) [r, g, b] = [0, x, chroma];\n else if (h < 300) [r, g, b] = [x, 0, chroma];\n else [r, g, b] = [chroma, 0, x];\n\n return normalizeRgba({\n r: Math.round((r + m) * 255),\n g: Math.round((g + m) * 255),\n b: Math.round((b + m) * 255),\n a: clampFloat(color.a, 0, 1),\n });\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return min;\n return Math.max(min, Math.min(max, Math.round(value)));\n}\n\nfunction clampFloat(value: number, min: number, max: number): number {\n if (!Number.isFinite(value)) return min;\n return Math.max(min, Math.min(max, value));\n}\n\nfunction swatchBackground(value: string) {\n if (value === \"transparent\" || value === \"rgba(0, 0, 0, 0)\") {\n return {\n background: CHECKERBOARD_IMAGE,\n backgroundPosition: \"0 0, 0 4px, 4px -4px, -4px 0\",\n backgroundSize: \"8px 8px\",\n };\n }\n return { background: value };\n}\n\nexport function VisualInspectorPanel({\n title,\n subtitle,\n children,\n className,\n headerAction,\n}: {\n title: ReactNode;\n subtitle?: ReactNode;\n children: ReactNode;\n className?: string;\n headerAction?: ReactNode;\n}) {\n return (\n <aside\n className={cn(\n \"w-64 overflow-hidden rounded-xl border border-border bg-card/95 text-card-foreground shadow-2xl shadow-black/35 backdrop-blur\",\n className,\n )}\n >\n <div className=\"flex min-h-10 items-start justify-between gap-2 border-b border-border/70 px-3 py-2.5\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\">\n {title}\n </div>\n {subtitle && (\n <div className=\"mt-0.5 truncate text-[12px] text-foreground\">\n {subtitle}\n </div>\n )}\n </div>\n {headerAction}\n </div>\n <div className=\"max-h-[min(680px,calc(100vh-7rem))] overflow-y-auto p-2\">\n {children}\n </div>\n </aside>\n );\n}\n\nexport function VisualInspectorSection({\n title,\n children,\n className,\n}: {\n title: ReactNode;\n children: ReactNode;\n className?: string;\n}) {\n return (\n <section className={cn(\"rounded-lg px-1.5 py-2\", className)}>\n <div className=\"mb-2 px-1 text-[10px] font-semibold uppercase tracking-wide text-muted-foreground/75\">\n {title}\n </div>\n <div className=\"space-y-2\">{children}</div>\n </section>\n );\n}\n\nexport function VisualControlRow({\n label,\n children,\n className,\n}: {\n label: ReactNode;\n children: ReactNode;\n className?: string;\n}) {\n return (\n <div className={cn(\"grid gap-1\", className)}>\n <span className=\"text-[11px] text-muted-foreground\">{label}</span>\n {children}\n </div>\n );\n}\n\nexport function VisualSwatchControl({\n options,\n value,\n onChange,\n columns = 8,\n className,\n}: {\n options: VisualControlOption[];\n value: string;\n onChange: (value: string) => void;\n columns?: number;\n className?: string;\n}) {\n return (\n <div\n className={cn(\"grid gap-1.5\", className)}\n style={{ gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))` }}\n >\n {options.map((option) => {\n const swatch = option.color ?? option.value;\n const isTransparent = swatch === \"transparent\";\n return (\n <button\n key={`${option.value}-${option.label}`}\n type=\"button\"\n title={option.label}\n aria-label={option.label}\n onClick={() => onChange(option.value)}\n className={cn(\n \"size-5 cursor-pointer rounded-md border border-border/70 transition-all hover:scale-105 hover:border-foreground/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n value === option.value &&\n \"border-foreground/70 ring-2 ring-foreground/40 ring-offset-1 ring-offset-card\",\n )}\n style={{\n background: isTransparent\n ? \"linear-gradient(45deg, hsl(var(--muted)) 25%, transparent 25%), linear-gradient(-45deg, hsl(var(--muted)) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, hsl(var(--muted)) 75%), linear-gradient(-45deg, transparent 75%, hsl(var(--muted)) 75%)\"\n : swatch,\n backgroundPosition: isTransparent\n ? \"0 0, 0 4px, 4px -4px, -4px 0\"\n : undefined,\n backgroundSize: isTransparent ? \"8px 8px\" : undefined,\n }}\n />\n );\n })}\n </div>\n );\n}\n\nexport function VisualColorPicker({\n label,\n value,\n onChange,\n documentColors = [],\n allowTransparent = false,\n hexLabel = \"Hex\",\n documentColorsLabel = \"Document colors\",\n transparentLabel = \"Transparent\",\n className,\n}: {\n label: string;\n value: string;\n onChange: (value: string) => void;\n documentColors?: string[];\n allowTransparent?: boolean;\n hexLabel?: string;\n documentColorsLabel?: string;\n transparentLabel?: string;\n className?: string;\n}) {\n const [open, setOpen] = useState(false);\n const color = parseCssColor(value) ?? FALLBACK_RGBA;\n const colorHex = rgbaToHex(color);\n const [draft, setDraft] = useState(colorHex.replace(/^#/, \"\"));\n const [picking, setPicking] = useState(false);\n const hasEyeDropper = typeof window !== \"undefined\" && \"EyeDropper\" in window;\n\n useEffect(() => {\n if (!open) setDraft(colorHex.replace(/^#/, \"\"));\n }, [colorHex, open]);\n\n const commitDraft = (nextDraft = draft) => {\n const normalized = normalizeHexColor(nextDraft);\n if (!normalized) {\n setDraft(colorHex.replace(/^#/, \"\"));\n return;\n }\n setDraft(normalized.replace(/^#/, \"\"));\n onChange(normalized);\n };\n\n const emitHsv = (nextHsv: HsvaColor) => {\n const nextColor = hsvToRgba({ ...nextHsv, a: color.a });\n const nextValue = rgbaToCss(nextColor);\n setDraft(rgbaToHex(nextColor).replace(/^#/, \"\"));\n onChange(nextValue);\n };\n\n const pickScreenColor = async () => {\n if (!hasEyeDropper || picking) return;\n try {\n setPicking(true);\n const EyeDropperCtor = (\n window as unknown as {\n EyeDropper?: new () => { open: () => Promise<{ sRGBHex: string }> };\n }\n ).EyeDropper;\n if (!EyeDropperCtor) return;\n const result = await new EyeDropperCtor().open();\n if (result?.sRGBHex) {\n const next = normalizeHexColor(result.sRGBHex);\n if (next) {\n setDraft(next.replace(/^#/, \"\"));\n onChange(next);\n }\n }\n } finally {\n setPicking(false);\n }\n };\n\n const uniqueDocumentColors = Array.from(\n new Set(\n documentColors\n .map((color) =>\n color === \"transparent\" ? color : normalizeHexColor(color),\n )\n .filter(Boolean) as string[],\n ),\n ).slice(0, 16);\n const displayValue =\n value === \"transparent\" || color.a === 0\n ? transparentLabel\n : colorHex.replace(/^#/, \"\");\n const hsv = rgbaToHsv(color);\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-label={label}\n className={cn(\n \"flex h-7 w-full cursor-pointer items-center gap-1.5 rounded-md border border-border bg-background/70 px-2 text-[11px] shadow-none transition-colors hover:bg-accent/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n className,\n )}\n >\n <span\n className=\"size-4 shrink-0 rounded-[3px] border border-border/70\"\n style={swatchBackground(value)}\n />\n <span className=\"min-w-0 flex-1 truncate text-left font-medium tabular-nums text-foreground\">\n {displayValue}\n </span>\n <span\n aria-hidden=\"true\"\n className=\"size-0 border-x-[4px] border-t-[5px] border-x-transparent border-t-muted-foreground/70\"\n />\n </button>\n </PopoverTrigger>\n <PopoverContent\n side=\"left\"\n align=\"start\"\n sideOffset={8}\n className=\"z-[10000] w-[252px] p-0 text-[11px] shadow-xl\"\n onFocusOutside={(event) => event.preventDefault()}\n >\n <div className=\"rounded-md bg-popover text-popover-foreground\">\n <VisualSaturationBrightnessField\n hsv={hsv}\n label={label}\n onChange={emitHsv}\n />\n\n <div className=\"mt-2.5 px-3\">\n <div className=\"grid grid-cols-[1.5rem_1fr] items-center gap-x-2\">\n <div className=\"flex items-center justify-center\">\n <button\n type=\"button\"\n aria-label={label}\n disabled={!hasEyeDropper || picking}\n onClick={() => void pickScreenColor()}\n className={cn(\n \"flex size-6 cursor-pointer items-center justify-center rounded-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n (!hasEyeDropper || picking) &&\n \"pointer-events-none opacity-40\",\n picking &&\n \"bg-primary/10 text-primary ring-1 ring-primary/50\",\n )}\n >\n <IconColorPicker className=\"size-4\" />\n </button>\n </div>\n <VisualColorTrack\n label={label}\n value={hsv.h}\n min={0}\n max={360}\n backgroundImage=\"linear-gradient(90deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000)\"\n onChange={(nextHue) =>\n emitHsv({ ...hsv, h: nextHue === 360 ? 0 : nextHue })\n }\n />\n <span\n className=\"mt-2 size-[18px] shrink-0 rounded-[3px] border border-border/60\"\n style={swatchBackground(rgbaToCss(color))}\n />\n <VisualColorTrack\n label={transparentLabel}\n value={Math.round(color.a * 100)}\n min={0}\n max={100}\n backgroundImage={`${CHECKERBOARD_IMAGE}, linear-gradient(90deg, rgba(${color.r}, ${color.g}, ${color.b}, 0), rgba(${color.r}, ${color.g}, ${color.b}, 1))`}\n backgroundSize=\"8px 8px, 8px 8px, 8px 8px, 8px 8px, 100% 100%\"\n backgroundPosition=\"0 0, 0 4px, 4px -4px, -4px 0, 0 0\"\n onChange={(nextOpacity) => {\n const nextColor = normalizeRgba({\n ...color,\n a: nextOpacity / 100,\n });\n const nextValue = rgbaToCss(nextColor);\n setDraft(rgbaToHex(nextColor).replace(/^#/, \"\"));\n onChange(nextValue);\n }}\n />\n </div>\n </div>\n\n <div className=\"mt-2.5 grid grid-cols-[4.5rem_1fr] items-center gap-1 border-b border-border/70 px-3 pb-3\">\n <span className=\"text-[11px] font-medium text-muted-foreground\">\n {hexLabel}\n </span>\n <input\n value={draft}\n spellCheck={false}\n onChange={(event) => setDraft(event.currentTarget.value)}\n onFocus={(event) => event.currentTarget.select()}\n onBlur={() => commitDraft()}\n onKeyDown={(event) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n commitDraft();\n event.currentTarget.blur();\n }\n if (event.key === \"Escape\") {\n event.preventDefault();\n setDraft(colorHex.replace(/^#/, \"\"));\n event.currentTarget.blur();\n }\n }}\n className=\"h-6 min-w-0 rounded-md border border-input bg-background/70 px-2 text-right text-[11px] uppercase tabular-nums outline-none transition-colors focus:border-ring focus:ring-1 focus:ring-ring\"\n />\n </div>\n {(allowTransparent || uniqueDocumentColors.length > 0) && (\n <div className=\"px-3 py-2.5\">\n <div className=\"mb-2 flex h-5 items-center justify-between text-[11px] text-muted-foreground\">\n <span>{documentColorsLabel}</span>\n </div>\n <div className=\"grid grid-cols-8 gap-1\">\n {allowTransparent && (\n <button\n type=\"button\"\n aria-label={transparentLabel}\n aria-pressed={value === \"transparent\"}\n className={cn(\n \"size-5 cursor-pointer rounded-sm border transition-transform hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n value === \"transparent\" || color.a === 0\n ? \"border-primary ring-1 ring-primary\"\n : \"border-border/60\",\n )}\n style={swatchBackground(\"transparent\")}\n onClick={() => {\n setDraft(colorHex.replace(/^#/, \"\"));\n onChange(\"transparent\");\n }}\n />\n )}\n {uniqueDocumentColors.map((color) => (\n <button\n key={color}\n type=\"button\"\n title={color}\n aria-label={color}\n aria-pressed={colorHex === color}\n className={cn(\n \"size-5 cursor-pointer rounded-sm border transition-transform hover:scale-110 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n colorHex === color\n ? \"border-primary ring-1 ring-primary\"\n : \"border-border/60\",\n )}\n style={swatchBackground(color)}\n onClick={() => {\n setDraft(color);\n onChange(color);\n }}\n />\n ))}\n </div>\n </div>\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction VisualSaturationBrightnessField({\n hsv,\n label,\n onChange,\n}: {\n hsv: HsvaColor;\n label: string;\n onChange: (value: HsvaColor) => void;\n}) {\n const fieldRef = useRef<HTMLDivElement>(null);\n const draggingRef = useRef(false);\n const hueColor = rgbaToCss(hsvToRgba({ h: hsv.h, s: 100, v: 100, a: 1 }));\n\n const updateFromPointer = (event: PointerEvent<HTMLDivElement>) => {\n const rect = fieldRef.current?.getBoundingClientRect();\n if (!rect) return;\n onChange({\n ...hsv,\n s: clamp(((event.clientX - rect.left) / rect.width) * 100, 0, 100),\n v: clamp(100 - ((event.clientY - rect.top) / rect.height) * 100, 0, 100),\n });\n };\n\n const stepWithKeyboard = (event: KeyboardEvent<HTMLDivElement>) => {\n const step = event.shiftKey ? 10 : 1;\n if (event.key === \"ArrowRight\") {\n event.preventDefault();\n onChange({ ...hsv, s: clamp(hsv.s + step, 0, 100) });\n }\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n onChange({ ...hsv, s: clamp(hsv.s - step, 0, 100) });\n }\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n onChange({ ...hsv, v: clamp(hsv.v + step, 0, 100) });\n }\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n onChange({ ...hsv, v: clamp(hsv.v - step, 0, 100) });\n }\n };\n\n return (\n <div\n ref={fieldRef}\n tabIndex={0}\n aria-label={label}\n onPointerDown={(event) => {\n draggingRef.current = true;\n event.currentTarget.setPointerCapture(event.pointerId);\n updateFromPointer(event);\n }}\n onPointerMove={(event) => {\n if (!draggingRef.current) return;\n updateFromPointer(event);\n }}\n onPointerUp={(event) => {\n draggingRef.current = false;\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n }}\n onPointerCancel={() => {\n draggingRef.current = false;\n }}\n onKeyDown={stepWithKeyboard}\n className=\"relative h-40 w-full cursor-crosshair overflow-hidden rounded-t-md outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset active:cursor-grabbing\"\n style={{\n backgroundImage: `linear-gradient(to top, #000 0%, transparent 100%), linear-gradient(to right, #fff 0%, ${hueColor} 100%)`,\n }}\n >\n <span\n className=\"pointer-events-none absolute size-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-[0_0_0_1px_hsl(var(--foreground)/0.6)]\"\n style={{\n left: `${hsv.s}%`,\n top: `${100 - hsv.v}%`,\n }}\n />\n </div>\n );\n}\n\nfunction VisualColorTrack({\n label,\n value,\n min,\n max,\n backgroundImage,\n backgroundSize,\n backgroundPosition,\n onChange,\n}: {\n label: string;\n value: number;\n min: number;\n max: number;\n backgroundImage: string;\n backgroundSize?: string;\n backgroundPosition?: string;\n onChange: (value: number) => void;\n}) {\n const trackRef = useRef<HTMLDivElement>(null);\n const draggingRef = useRef(false);\n const percent = ((value - min) / (max - min)) * 100;\n\n const updateFromPointer = (event: PointerEvent<HTMLDivElement>) => {\n const rect = trackRef.current?.getBoundingClientRect();\n if (!rect) return;\n const next = min + ((event.clientX - rect.left) / rect.width) * (max - min);\n onChange(clamp(next, min, max));\n };\n\n const stepWithKeyboard = (event: KeyboardEvent<HTMLDivElement>) => {\n const step = event.shiftKey ? 10 : 1;\n if (event.key === \"ArrowRight\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n onChange(clamp(value + step, min, max));\n }\n if (event.key === \"ArrowLeft\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n onChange(clamp(value - step, min, max));\n }\n if (event.key === \"Home\") {\n event.preventDefault();\n onChange(min);\n }\n if (event.key === \"End\") {\n event.preventDefault();\n onChange(max);\n }\n };\n\n return (\n <div\n ref={trackRef}\n role=\"slider\"\n tabIndex={0}\n aria-label={label}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuenow={Math.round(value)}\n onKeyDown={stepWithKeyboard}\n onPointerDown={(event) => {\n draggingRef.current = true;\n event.currentTarget.setPointerCapture(event.pointerId);\n updateFromPointer(event);\n }}\n onPointerMove={(event) => {\n if (!draggingRef.current) return;\n updateFromPointer(event);\n }}\n onPointerUp={(event) => {\n draggingRef.current = false;\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n }}\n onPointerCancel={() => {\n draggingRef.current = false;\n }}\n className=\"relative h-3.5 cursor-pointer rounded-full border border-border/60 outline-none ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 active:cursor-grabbing\"\n style={{ backgroundImage, backgroundSize, backgroundPosition }}\n >\n <span\n className=\"pointer-events-none absolute top-1/2 size-4 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-white shadow-[0_0_0_1px_hsl(var(--foreground)/0.6)]\"\n style={{ left: `${clamp(percent, 0, 100)}%` }}\n />\n </div>\n );\n}\n\nexport function VisualSegmentedControl({\n options,\n value,\n onChange,\n className,\n}: {\n options: VisualControlOption[];\n value: string;\n onChange: (value: string) => void;\n className?: string;\n}) {\n return (\n <div\n className={cn(\n \"flex min-h-7 overflow-hidden rounded-md border border-border bg-background/60\",\n className,\n )}\n >\n {options.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n onClick={() => onChange(option.value)}\n className={cn(\n \"min-w-0 flex-1 cursor-pointer px-2 text-[11px] font-medium text-muted-foreground transition-colors hover:bg-accent/70 hover:text-foreground\",\n value === option.value && \"bg-accent text-foreground\",\n )}\n >\n <span className=\"truncate\">{option.label}</span>\n </button>\n ))}\n </div>\n );\n}\n\nexport function VisualToggleControl({\n checked,\n onChange,\n label,\n}: {\n checked: boolean;\n onChange: (checked: boolean) => void;\n label?: string;\n}) {\n return (\n <button\n type=\"button\"\n aria-pressed={checked}\n aria-label={label}\n onClick={() => onChange(!checked)}\n className={cn(\n \"relative h-5 w-9 cursor-pointer rounded-full border border-border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring\",\n checked ? \"bg-primary/35\" : \"bg-muted\",\n )}\n >\n <span\n className={cn(\n \"absolute top-1/2 size-3.5 -translate-y-1/2 rounded-full bg-foreground shadow transition-transform\",\n checked ? \"translate-x-[18px]\" : \"translate-x-[3px]\",\n )}\n />\n </button>\n );\n}\n\nexport function VisualSliderControl({\n value,\n onChange,\n min = 0,\n max = 100,\n step = 1,\n unit,\n}: {\n value: number;\n onChange: (value: number) => void;\n min?: number;\n max?: number;\n step?: number;\n unit?: string;\n}) {\n const safeValue = clampNumber(Number.isFinite(value) ? value : min, min, max);\n return (\n <div className=\"flex h-7 items-center gap-2\">\n <input\n type=\"range\"\n min={min}\n max={max}\n step={step}\n value={safeValue}\n onChange={(event) => onChange(Number(event.currentTarget.value))}\n className=\"min-w-0 flex-1 cursor-pointer accent-foreground\"\n />\n <span className=\"w-9 text-right text-[11px] tabular-nums text-muted-foreground\">\n {formatNumber(safeValue, unit)}\n </span>\n </div>\n );\n}\n\nexport function VisualScrubInput({\n label,\n value,\n onChange,\n min,\n max,\n step = 1,\n unit,\n disabled = false,\n}: {\n label: string;\n value: number;\n onChange: (value: number) => void;\n min?: number;\n max?: number;\n step?: number;\n unit?: string;\n disabled?: boolean;\n}) {\n const id = useId();\n const [draft, setDraft] = useState(() => formatNumber(value, unit));\n const [focused, setFocused] = useState(false);\n const dragRef = useRef<{\n pointerId: number;\n prevX: number;\n dragged: boolean;\n } | null>(null);\n\n useEffect(() => {\n if (!focused) setDraft(formatNumber(value, unit));\n }, [focused, unit, value]);\n\n const commit = (nextDraft = draft) => {\n const parsed = parseDraftNumber(nextDraft, value);\n const next = clampNumber(parsed, min, max);\n onChange(next);\n setDraft(formatNumber(next, unit));\n };\n\n const setNext = (next: number) => {\n const clamped = clampNumber(next, min, max);\n onChange(clamped);\n setDraft(formatNumber(clamped, unit));\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {\n if (event.key === \"Enter\") {\n event.preventDefault();\n commit();\n event.currentTarget.blur();\n return;\n }\n if (event.key === \"Escape\") {\n event.preventDefault();\n setDraft(formatNumber(value, unit));\n event.currentTarget.blur();\n return;\n }\n if (event.key === \"ArrowUp\" || event.key === \"ArrowDown\") {\n event.preventDefault();\n const mult =\n event.shiftKey || event.metaKey ? 10 : event.altKey ? 0.1 : 1;\n const direction = event.key === \"ArrowUp\" ? 1 : -1;\n const base = parseDraftNumber(draft, value);\n setNext(base + direction * step * mult);\n }\n };\n\n const onPointerDown = (event: PointerEvent<HTMLLabelElement>) => {\n if (disabled || event.button !== 0) return;\n event.preventDefault();\n dragRef.current = {\n pointerId: event.pointerId,\n prevX: event.clientX,\n dragged: false,\n };\n event.currentTarget.setPointerCapture(event.pointerId);\n };\n\n const onPointerMove = (event: PointerEvent<HTMLLabelElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== event.pointerId) return;\n const delta = event.clientX - drag.prevX;\n if (delta === 0) return;\n drag.prevX = event.clientX;\n drag.dragged = true;\n const mult = event.shiftKey || event.metaKey ? 10 : event.altKey ? 0.1 : 1;\n setNext(value + delta * step * mult);\n };\n\n const onPointerUp = (event: PointerEvent<HTMLLabelElement>) => {\n const drag = dragRef.current;\n if (!drag || drag.pointerId !== event.pointerId) return;\n event.currentTarget.releasePointerCapture(event.pointerId);\n dragRef.current = null;\n if (!drag.dragged) {\n document.getElementById(id)?.focus();\n }\n };\n\n return (\n <div className=\"flex items-center gap-1.5\">\n <label\n htmlFor={id}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n className={cn(\n \"flex w-8 shrink-0 cursor-ew-resize select-none items-center justify-center rounded border border-transparent px-1 text-[10px] font-semibold text-muted-foreground hover:border-border hover:bg-accent/60\",\n disabled && \"cursor-not-allowed opacity-50\",\n )}\n >\n {label}\n </label>\n <input\n id={id}\n value={draft}\n disabled={disabled}\n onFocus={() => setFocused(true)}\n onBlur={() => {\n setFocused(false);\n commit();\n }}\n onChange={(event) => setDraft(event.currentTarget.value)}\n onKeyDown={onKeyDown}\n className=\"h-7 min-w-0 flex-1 rounded-md border border-input bg-background/70 px-2 text-right text-[11px] tabular-nums text-foreground outline-none transition-colors focus:border-ring focus:ring-1 focus:ring-ring disabled:opacity-50\"\n />\n </div>\n );\n}\n\nexport function VisualTweakControl({\n tweak,\n value,\n onChange,\n className,\n}: {\n tweak: VisualTweakDefinition;\n value: VisualControlValue;\n onChange: (value: VisualControlValue) => void;\n className?: string;\n}) {\n if (tweak.type === \"toggle\") {\n return (\n <div\n className={cn(\"flex h-7 items-center justify-between gap-2\", className)}\n >\n <span className=\"truncate text-[11px] text-muted-foreground\">\n {tweak.label}\n </span>\n <VisualToggleControl\n checked={Boolean(value)}\n onChange={onChange}\n label={tweak.label}\n />\n </div>\n );\n }\n\n const numericValue =\n typeof value === \"number\"\n ? value\n : typeof value === \"string\"\n ? Number(value)\n : Number(tweak.defaultValue);\n\n return (\n <VisualControlRow label={tweak.label} className={className}>\n {((tweak.type as string) === \"color-swatch\" ||\n (tweak.type as string) === \"color-swatches\") && (\n <VisualColorPicker\n label={tweak.label}\n value={String(value)}\n documentColors={(tweak.options ?? []).map(\n (option) => option.color ?? option.value,\n )}\n onChange={onChange}\n />\n )}\n {tweak.type === \"segment\" && (\n <VisualSegmentedControl\n options={tweak.options ?? []}\n value={String(value)}\n onChange={onChange}\n />\n )}\n {tweak.type === \"slider\" && (\n <VisualSliderControl\n min={tweak.min ?? 0}\n max={tweak.max ?? 100}\n step={tweak.step ?? 1}\n unit={\n tweak.unit ??\n (tweak.cssVar?.toLowerCase().includes(\"radius\") ? \"px\" : undefined)\n }\n value={Number.isFinite(numericValue) ? numericValue : 0}\n onChange={onChange}\n />\n )}\n </VisualControlRow>\n );\n}\n"]}
|
|
@@ -5,26 +5,72 @@
|
|
|
5
5
|
* collaborator — it "enters" a document, its edits are visible with
|
|
6
6
|
* durable presence, and it "leaves" when done. Actions call these
|
|
7
7
|
* instead of hand-rolling HTTP awareness calls.
|
|
8
|
+
*
|
|
9
|
+
* Presence lingers after the agent finishes editing (default 6s) so viewers
|
|
10
|
+
* get a moment to see who just changed what — the same way a human
|
|
11
|
+
* collaborator's cursor doesn't vanish the instant they stop typing. Recent
|
|
12
|
+
* edits are attributed in the awareness state (`recentEdits`, `lastEditAt`)
|
|
13
|
+
* so clients can render fading highlights over the edited regions.
|
|
14
|
+
*
|
|
15
|
+
* On serverless hosts the linger timer may never fire after the response is
|
|
16
|
+
* sent; the 30s awareness expiry then removes the entry, so presence degrades
|
|
17
|
+
* to "up to 30s" instead of leaking.
|
|
8
18
|
*/
|
|
19
|
+
import { type RecentEdit } from "./recent-edits.js";
|
|
20
|
+
/** How long agent presence lingers after leave/last edit before clearing. */
|
|
21
|
+
export declare const AGENT_PRESENCE_LINGER_MS = 6000;
|
|
9
22
|
/**
|
|
10
23
|
* Mark the agent as present on a document.
|
|
11
24
|
*
|
|
12
25
|
* Sets an awareness entry for the agent and starts a heartbeat that
|
|
13
|
-
* keeps it alive. If the agent is already present on this doc
|
|
14
|
-
* refreshes
|
|
26
|
+
* keeps it alive. If the agent is already present on this doc (including
|
|
27
|
+
* lingering after a previous edit), refreshes state without creating a
|
|
28
|
+
* second interval.
|
|
15
29
|
*/
|
|
16
30
|
export declare function agentEnterDocument(docId: string, metadata?: Record<string, unknown>): void;
|
|
31
|
+
export interface AgentLeaveOptions {
|
|
32
|
+
/**
|
|
33
|
+
* How long presence lingers before the awareness entry clears.
|
|
34
|
+
* Defaults to {@link AGENT_PRESENCE_LINGER_MS}. Pass 0 to clear
|
|
35
|
+
* immediately (e.g. when an operation failed before editing anything).
|
|
36
|
+
*/
|
|
37
|
+
lingerMs?: number;
|
|
38
|
+
}
|
|
17
39
|
/**
|
|
18
|
-
*
|
|
40
|
+
* Release the agent's presence on a document.
|
|
19
41
|
*
|
|
20
|
-
*
|
|
42
|
+
* Decrements the reference count; when it reaches zero the awareness entry
|
|
43
|
+
* lingers for `lingerMs` (default 6s) and is then removed. Viewers see the
|
|
44
|
+
* agent avatar/highlights for a beat after the edit completes instead of an
|
|
45
|
+
* instant disappearance.
|
|
21
46
|
*/
|
|
22
|
-
export declare function agentLeaveDocument(docId: string): void;
|
|
47
|
+
export declare function agentLeaveDocument(docId: string, options?: AgentLeaveOptions): void;
|
|
23
48
|
/**
|
|
24
49
|
* Update the agent's awareness state to include selection info
|
|
25
50
|
* (e.g., which track, panel, or element the agent is working on).
|
|
26
51
|
*/
|
|
27
52
|
export declare function agentUpdateSelection(docId: string, selection: Record<string, unknown>): void;
|
|
53
|
+
export interface AgentTouchOptions {
|
|
54
|
+
/** Region descriptor + label recorded in the agent's recentEdits ring. */
|
|
55
|
+
edit?: Omit<RecentEdit, "at"> & {
|
|
56
|
+
at?: number;
|
|
57
|
+
};
|
|
58
|
+
/** Extra awareness fields to merge (e.g. `selection`). */
|
|
59
|
+
metadata?: Record<string, unknown>;
|
|
60
|
+
/** Linger before auto-clearing when no enter/leave pair is active. */
|
|
61
|
+
lingerMs?: number;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Record an agent edit on a document without requiring an explicit
|
|
65
|
+
* enter/leave pair. Used by the collab write paths so ANY agent edit
|
|
66
|
+
* produces visible presence + lingering attribution automatically.
|
|
67
|
+
*
|
|
68
|
+
* - Upserts the agent awareness entry (identity preserved/merged).
|
|
69
|
+
* - Appends to the `recentEdits` ring and bumps `lastEditAt`.
|
|
70
|
+
* - When no explicit operation is in flight (refcount 0), (re)schedules a
|
|
71
|
+
* linger removal so presence fades out on its own.
|
|
72
|
+
*/
|
|
73
|
+
export declare function agentTouchDocument(docId: string, options?: AgentTouchOptions): void;
|
|
28
74
|
/**
|
|
29
75
|
* Apply search-and-replace edits incrementally so each one appears
|
|
30
76
|
* as a separate poll event to connected clients.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-presence.d.ts","sourceRoot":"","sources":["../../src/collab/agent-presence.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"agent-presence.d.ts","sourceRoot":"","sources":["../../src/collab/agent-presence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AASH,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAKtE,6EAA6E;AAC7E,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAoH9C;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,IAAI,CAUN;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,iBAAiB,GAC1B,IAAI,CASN;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,IAAI,CAGN;AAED,MAAM,WAAW,iBAAiB;IAChC,0EAA0E;IAC1E,IAAI,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,GAAG;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,sEAAsE;IACtE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,iBAAiB,GAC1B,IAAI,CAoBN;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAChD,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/C,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;GAKG;AACH,wBAAsB,8BAA8B,CAClD,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,KAAK,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,CAAC,EACF,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7B,OAAO,CAAC,IAAI,CAAC,CAiCf"}
|
|
@@ -5,41 +5,70 @@
|
|
|
5
5
|
* collaborator — it "enters" a document, its edits are visible with
|
|
6
6
|
* durable presence, and it "leaves" when done. Actions call these
|
|
7
7
|
* instead of hand-rolling HTTP awareness calls.
|
|
8
|
+
*
|
|
9
|
+
* Presence lingers after the agent finishes editing (default 6s) so viewers
|
|
10
|
+
* get a moment to see who just changed what — the same way a human
|
|
11
|
+
* collaborator's cursor doesn't vanish the instant they stop typing. Recent
|
|
12
|
+
* edits are attributed in the awareness state (`recentEdits`, `lastEditAt`)
|
|
13
|
+
* so clients can render fading highlights over the edited regions.
|
|
14
|
+
*
|
|
15
|
+
* On serverless hosts the linger timer may never fire after the response is
|
|
16
|
+
* sent; the 30s awareness expiry then removes the entry, so presence degrades
|
|
17
|
+
* to "up to 30s" instead of leaking.
|
|
8
18
|
*/
|
|
9
19
|
import { AGENT_CLIENT_ID, DEFAULT_AGENT_IDENTITY } from "./agent-identity.js";
|
|
10
|
-
import {
|
|
20
|
+
import { deleteAwarenessRow, upsertAwarenessRow } from "./awareness-store.js";
|
|
21
|
+
import { emitAwarenessChange, getDocAwareness, } from "./awareness.js";
|
|
22
|
+
import { appendRecentEdit } from "./recent-edits.js";
|
|
11
23
|
import { searchAndReplace } from "./ydoc-manager.js";
|
|
12
24
|
const HEARTBEAT_INTERVAL = 10_000; // 10 seconds
|
|
25
|
+
/** How long agent presence lingers after leave/last edit before clearing. */
|
|
26
|
+
export const AGENT_PRESENCE_LINGER_MS = 6_000;
|
|
13
27
|
// docId → heartbeat interval handle
|
|
14
28
|
const _heartbeats = new Map();
|
|
15
29
|
// docId → reference count (how many concurrent operations are using this doc)
|
|
16
30
|
const _refCounts = new Map();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
// docId → pending linger-removal timer
|
|
32
|
+
const _lingerTimers = new Map();
|
|
33
|
+
function cancelLinger(docId) {
|
|
34
|
+
const timer = _lingerTimers.get(docId);
|
|
35
|
+
if (timer) {
|
|
36
|
+
clearTimeout(timer);
|
|
37
|
+
_lingerTimers.delete(docId);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function removeAgentPresence(docId) {
|
|
41
|
+
cancelLinger(docId);
|
|
25
42
|
const map = getDocAwareness(docId);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
map.delete(AGENT_CLIENT_ID);
|
|
44
|
+
emitAwarenessChange(docId, currentAwarenessStates(map));
|
|
45
|
+
// Cross-instance removal (serverless) — best-effort, never blocks.
|
|
46
|
+
void deleteAwarenessRow(docId, AGENT_CLIENT_ID);
|
|
47
|
+
const interval = _heartbeats.get(docId);
|
|
48
|
+
if (interval) {
|
|
49
|
+
clearInterval(interval);
|
|
50
|
+
_heartbeats.delete(docId);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function scheduleLingerRemoval(docId, lingerMs) {
|
|
54
|
+
cancelLinger(docId);
|
|
55
|
+
if (lingerMs <= 0) {
|
|
56
|
+
removeAgentPresence(docId);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const timer = setTimeout(() => {
|
|
60
|
+
_lingerTimers.delete(docId);
|
|
61
|
+
// A new operation may have re-entered while we waited.
|
|
62
|
+
if ((_refCounts.get(docId) ?? 0) > 0)
|
|
63
|
+
return;
|
|
64
|
+
removeAgentPresence(docId);
|
|
65
|
+
}, lingerMs);
|
|
66
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
67
|
+
timer.unref();
|
|
68
|
+
}
|
|
69
|
+
_lingerTimers.set(docId, timer);
|
|
70
|
+
}
|
|
71
|
+
function ensureHeartbeat(docId) {
|
|
43
72
|
if (_heartbeats.has(docId))
|
|
44
73
|
return;
|
|
45
74
|
const interval = setInterval(() => {
|
|
@@ -47,6 +76,9 @@ export function agentEnterDocument(docId, metadata) {
|
|
|
47
76
|
const existing = m.get(AGENT_CLIENT_ID);
|
|
48
77
|
if (existing) {
|
|
49
78
|
existing.lastSeen = Date.now();
|
|
79
|
+
// Keep the SQL mirror fresh too, or remote-instance pollers would see
|
|
80
|
+
// the agent expire mid-operation (store throttles unchanged writes).
|
|
81
|
+
void upsertAwarenessRow(docId, AGENT_CLIENT_ID, existing.state, existing.lastSeen);
|
|
50
82
|
}
|
|
51
83
|
}, HEARTBEAT_INTERVAL);
|
|
52
84
|
// Don't block Node from exiting if this is the only timer left
|
|
@@ -55,54 +87,108 @@ export function agentEnterDocument(docId, metadata) {
|
|
|
55
87
|
}
|
|
56
88
|
_heartbeats.set(docId, interval);
|
|
57
89
|
}
|
|
90
|
+
function currentAwarenessStates(map) {
|
|
91
|
+
return Array.from(map, ([clientId, entry]) => ({
|
|
92
|
+
clientId,
|
|
93
|
+
state: entry.state,
|
|
94
|
+
}));
|
|
95
|
+
}
|
|
96
|
+
function readAgentState(docId) {
|
|
97
|
+
const existing = getDocAwareness(docId).get(AGENT_CLIENT_ID);
|
|
98
|
+
if (existing) {
|
|
99
|
+
try {
|
|
100
|
+
return JSON.parse(existing.state);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
// Invalid state — fall through to defaults
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
user: {
|
|
108
|
+
name: DEFAULT_AGENT_IDENTITY.name,
|
|
109
|
+
email: DEFAULT_AGENT_IDENTITY.email,
|
|
110
|
+
color: DEFAULT_AGENT_IDENTITY.color,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function writeAgentState(docId, state) {
|
|
115
|
+
const entry = {
|
|
116
|
+
clientId: AGENT_CLIENT_ID,
|
|
117
|
+
state: JSON.stringify(state),
|
|
118
|
+
lastSeen: Date.now(),
|
|
119
|
+
};
|
|
120
|
+
const map = getDocAwareness(docId);
|
|
121
|
+
map.set(AGENT_CLIENT_ID, entry);
|
|
122
|
+
emitAwarenessChange(docId, currentAwarenessStates(map));
|
|
123
|
+
// Mirror to SQL so pollers on other instances see the agent — an action
|
|
124
|
+
// often runs in a different serverless invocation than the poll route.
|
|
125
|
+
void upsertAwarenessRow(docId, AGENT_CLIENT_ID, entry.state, entry.lastSeen);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Mark the agent as present on a document.
|
|
129
|
+
*
|
|
130
|
+
* Sets an awareness entry for the agent and starts a heartbeat that
|
|
131
|
+
* keeps it alive. If the agent is already present on this doc (including
|
|
132
|
+
* lingering after a previous edit), refreshes state without creating a
|
|
133
|
+
* second interval.
|
|
134
|
+
*/
|
|
135
|
+
export function agentEnterDocument(docId, metadata) {
|
|
136
|
+
cancelLinger(docId);
|
|
137
|
+
const state = { ...readAgentState(docId), ...metadata };
|
|
138
|
+
writeAgentState(docId, state);
|
|
139
|
+
// Increment reference count
|
|
140
|
+
_refCounts.set(docId, (_refCounts.get(docId) ?? 0) + 1);
|
|
141
|
+
ensureHeartbeat(docId);
|
|
142
|
+
}
|
|
58
143
|
/**
|
|
59
|
-
*
|
|
144
|
+
* Release the agent's presence on a document.
|
|
60
145
|
*
|
|
61
|
-
*
|
|
146
|
+
* Decrements the reference count; when it reaches zero the awareness entry
|
|
147
|
+
* lingers for `lingerMs` (default 6s) and is then removed. Viewers see the
|
|
148
|
+
* agent avatar/highlights for a beat after the edit completes instead of an
|
|
149
|
+
* instant disappearance.
|
|
62
150
|
*/
|
|
63
|
-
export function agentLeaveDocument(docId) {
|
|
151
|
+
export function agentLeaveDocument(docId, options) {
|
|
64
152
|
const count = (_refCounts.get(docId) ?? 1) - 1;
|
|
65
153
|
if (count > 0) {
|
|
66
154
|
_refCounts.set(docId, count);
|
|
67
155
|
return;
|
|
68
156
|
}
|
|
69
157
|
_refCounts.delete(docId);
|
|
70
|
-
|
|
71
|
-
map.delete(AGENT_CLIENT_ID);
|
|
72
|
-
const interval = _heartbeats.get(docId);
|
|
73
|
-
if (interval) {
|
|
74
|
-
clearInterval(interval);
|
|
75
|
-
_heartbeats.delete(docId);
|
|
76
|
-
}
|
|
158
|
+
scheduleLingerRemoval(docId, options?.lingerMs ?? AGENT_PRESENCE_LINGER_MS);
|
|
77
159
|
}
|
|
78
160
|
/**
|
|
79
161
|
* Update the agent's awareness state to include selection info
|
|
80
162
|
* (e.g., which track, panel, or element the agent is working on).
|
|
81
163
|
*/
|
|
82
164
|
export function agentUpdateSelection(docId, selection) {
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
165
|
+
const state = { ...readAgentState(docId), ...selection };
|
|
166
|
+
writeAgentState(docId, state);
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Record an agent edit on a document without requiring an explicit
|
|
170
|
+
* enter/leave pair. Used by the collab write paths so ANY agent edit
|
|
171
|
+
* produces visible presence + lingering attribution automatically.
|
|
172
|
+
*
|
|
173
|
+
* - Upserts the agent awareness entry (identity preserved/merged).
|
|
174
|
+
* - Appends to the `recentEdits` ring and bumps `lastEditAt`.
|
|
175
|
+
* - When no explicit operation is in flight (refcount 0), (re)schedules a
|
|
176
|
+
* linger removal so presence fades out on its own.
|
|
177
|
+
*/
|
|
178
|
+
export function agentTouchDocument(docId, options) {
|
|
179
|
+
cancelLinger(docId);
|
|
180
|
+
const state = { ...readAgentState(docId), ...(options?.metadata ?? {}) };
|
|
181
|
+
const now = Date.now();
|
|
182
|
+
if (options?.edit) {
|
|
183
|
+
const { at, ...rest } = options.edit;
|
|
184
|
+
state.recentEdits = appendRecentEdit(state.recentEdits, { ...rest, at: at ?? now });
|
|
185
|
+
}
|
|
186
|
+
state.lastEditAt = now;
|
|
187
|
+
writeAgentState(docId, state);
|
|
188
|
+
ensureHeartbeat(docId);
|
|
189
|
+
if ((_refCounts.get(docId) ?? 0) === 0) {
|
|
190
|
+
scheduleLingerRemoval(docId, options?.lingerMs ?? AGENT_PRESENCE_LINGER_MS);
|
|
99
191
|
}
|
|
100
|
-
const state = JSON.stringify({ ...parsed, ...selection });
|
|
101
|
-
map.set(AGENT_CLIENT_ID, {
|
|
102
|
-
clientId: AGENT_CLIENT_ID,
|
|
103
|
-
state,
|
|
104
|
-
lastSeen: Date.now(),
|
|
105
|
-
});
|
|
106
192
|
}
|
|
107
193
|
/**
|
|
108
194
|
* Apply search-and-replace edits incrementally so each one appears
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-presence.js","sourceRoot":"","sources":["../../src/collab/agent-presence.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Server-side agent presence lifecycle for collaborative editing.\n *\n * Provides enter/leave semantics so the agent behaves like a real\n * collaborator — it \"enters\" a document, its edits are visible with\n * durable presence, and it \"leaves\" when done. Actions call these\n * instead of hand-rolling HTTP awareness calls.\n */\n\nimport { AGENT_CLIENT_ID, DEFAULT_AGENT_IDENTITY } from \"./agent-identity.js\";\nimport { getDocAwareness, type AwarenessEntry } from \"./awareness.js\";\nimport { searchAndReplace } from \"./ydoc-manager.js\";\n\nconst HEARTBEAT_INTERVAL = 10_000; // 10 seconds\n\n// docId → heartbeat interval handle\nconst _heartbeats = new Map<string, NodeJS.Timeout>();\n// docId → reference count (how many concurrent operations are using this doc)\nconst _refCounts = new Map<string, number>();\n\n/**\n * Mark the agent as present on a document.\n *\n * Sets an awareness entry for the agent and starts a heartbeat that\n * keeps it alive. If the agent is already present on this doc, just\n * refreshes `lastSeen` without creating a second interval.\n */\nexport function agentEnterDocument(\n docId: string,\n metadata?: Record<string, unknown>,\n): void {\n const map = getDocAwareness(docId);\n\n const state = JSON.stringify({\n user: {\n name: DEFAULT_AGENT_IDENTITY.name,\n email: DEFAULT_AGENT_IDENTITY.email,\n color: DEFAULT_AGENT_IDENTITY.color,\n },\n ...metadata,\n });\n\n const entry: AwarenessEntry = {\n clientId: AGENT_CLIENT_ID,\n state,\n lastSeen: Date.now(),\n };\n map.set(AGENT_CLIENT_ID, entry);\n\n // Increment reference count\n _refCounts.set(docId, (_refCounts.get(docId) ?? 0) + 1);\n\n // Don't create another interval if one already exists\n if (_heartbeats.has(docId)) return;\n\n const interval = setInterval(() => {\n const m = getDocAwareness(docId);\n const existing = m.get(AGENT_CLIENT_ID);\n if (existing) {\n existing.lastSeen = Date.now();\n }\n }, HEARTBEAT_INTERVAL);\n\n // Don't block Node from exiting if this is the only timer left\n if (typeof interval === \"object\" && \"unref\" in interval) {\n interval.unref();\n }\n\n _heartbeats.set(docId, interval);\n}\n\n/**\n * Remove the agent's presence from a document.\n *\n * Clears the awareness entry and stops the heartbeat.\n */\nexport function agentLeaveDocument(docId: string): void {\n const count = (_refCounts.get(docId) ?? 1) - 1;\n if (count > 0) {\n _refCounts.set(docId, count);\n return;\n }\n _refCounts.delete(docId);\n\n const map = getDocAwareness(docId);\n map.delete(AGENT_CLIENT_ID);\n\n const interval = _heartbeats.get(docId);\n if (interval) {\n clearInterval(interval);\n _heartbeats.delete(docId);\n }\n}\n\n/**\n * Update the agent's awareness state to include selection info\n * (e.g., which track, panel, or element the agent is working on).\n */\nexport function agentUpdateSelection(\n docId: string,\n selection: Record<string, unknown>,\n): void {\n const map = getDocAwareness(docId);\n const existing = map.get(AGENT_CLIENT_ID);\n\n let parsed: Record<string, unknown> = {\n user: {\n name: DEFAULT_AGENT_IDENTITY.name,\n email: DEFAULT_AGENT_IDENTITY.email,\n color: DEFAULT_AGENT_IDENTITY.color,\n },\n };\n\n if (existing) {\n try {\n parsed = JSON.parse(existing.state) as Record<string, unknown>;\n } catch {\n // Invalid state — use defaults\n }\n }\n\n const state = JSON.stringify({ ...parsed, ...selection });\n map.set(AGENT_CLIENT_ID, {\n clientId: AGENT_CLIENT_ID,\n state,\n lastSeen: Date.now(),\n });\n}\n\n/**\n * Apply search-and-replace edits incrementally so each one appears\n * as a separate poll event to connected clients.\n *\n * Enters the document before editing and leaves in a finally block.\n */\nexport async function agentApplyEditsIncrementally(\n docId: string,\n edits: Array<{ find: string; replace: string }>,\n options?: { delayMs?: number },\n): Promise<void> {\n const delayMs = options?.delayMs ?? 150;\n agentEnterDocument(docId);\n\n try {\n for (const edit of edits) {\n await searchAndReplace(docId, edit.find, edit.replace, \"agent\");\n if (delayMs > 0) {\n await new Promise((r) => setTimeout(r, delayMs));\n }\n }\n } finally {\n agentLeaveDocument(docId);\n }\n}\n\n/**\n * Apply structured data patches incrementally so each one appears\n * as a separate poll event to connected clients.\n *\n * Enters the document before patching and leaves in a finally block.\n */\nexport async function agentApplyPatchesIncrementally(\n docId: string,\n fieldName: string,\n patches: Array<{\n op: string;\n path: string;\n value?: unknown;\n index?: number;\n from?: number;\n to?: number;\n }>,\n options?: { delayMs?: number },\n): Promise<void> {\n const delayMs = options?.delayMs ?? 150;\n agentEnterDocument(docId);\n\n try {\n // Resolve applyPatchOps dynamically so a build that strips it (or a partial\n // upgrade) fails loudly here rather than at module load time.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let applyPatchOps: any;\n try {\n const mod = await import(\"./ydoc-manager.js\");\n applyPatchOps = (mod as Record<string, unknown>).applyPatchOps;\n } catch {\n throw new Error(\n \"applyPatchOps is not available yet — Phase 1 must complete first\",\n );\n }\n\n if (typeof applyPatchOps !== \"function\") {\n throw new Error(\n \"applyPatchOps is not available yet — Phase 1 must complete first\",\n );\n }\n\n for (const patch of patches) {\n await applyPatchOps(docId, [patch], fieldName, \"agent\");\n if (delayMs > 0) {\n await new Promise((r) => setTimeout(r, delayMs));\n }\n }\n } finally {\n agentLeaveDocument(docId);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agent-presence.js","sourceRoot":"","sources":["../../src/collab/agent-presence.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Server-side agent presence lifecycle for collaborative editing.\n *\n * Provides enter/leave semantics so the agent behaves like a real\n * collaborator — it \"enters\" a document, its edits are visible with\n * durable presence, and it \"leaves\" when done. Actions call these\n * instead of hand-rolling HTTP awareness calls.\n *\n * Presence lingers after the agent finishes editing (default 6s) so viewers\n * get a moment to see who just changed what — the same way a human\n * collaborator's cursor doesn't vanish the instant they stop typing. Recent\n * edits are attributed in the awareness state (`recentEdits`, `lastEditAt`)\n * so clients can render fading highlights over the edited regions.\n *\n * On serverless hosts the linger timer may never fire after the response is\n * sent; the 30s awareness expiry then removes the entry, so presence degrades\n * to \"up to 30s\" instead of leaking.\n */\n\nimport { AGENT_CLIENT_ID, DEFAULT_AGENT_IDENTITY } from \"./agent-identity.js\";\nimport { deleteAwarenessRow, upsertAwarenessRow } from \"./awareness-store.js\";\nimport {\n emitAwarenessChange,\n getDocAwareness,\n type AwarenessEntry,\n} from \"./awareness.js\";\nimport { appendRecentEdit, type RecentEdit } from \"./recent-edits.js\";\nimport { searchAndReplace } from \"./ydoc-manager.js\";\n\nconst HEARTBEAT_INTERVAL = 10_000; // 10 seconds\n\n/** How long agent presence lingers after leave/last edit before clearing. */\nexport const AGENT_PRESENCE_LINGER_MS = 6_000;\n\n// docId → heartbeat interval handle\nconst _heartbeats = new Map<string, NodeJS.Timeout>();\n// docId → reference count (how many concurrent operations are using this doc)\nconst _refCounts = new Map<string, number>();\n// docId → pending linger-removal timer\nconst _lingerTimers = new Map<string, NodeJS.Timeout>();\n\nfunction cancelLinger(docId: string): void {\n const timer = _lingerTimers.get(docId);\n if (timer) {\n clearTimeout(timer);\n _lingerTimers.delete(docId);\n }\n}\n\nfunction removeAgentPresence(docId: string): void {\n cancelLinger(docId);\n const map = getDocAwareness(docId);\n map.delete(AGENT_CLIENT_ID);\n emitAwarenessChange(docId, currentAwarenessStates(map));\n // Cross-instance removal (serverless) — best-effort, never blocks.\n void deleteAwarenessRow(docId, AGENT_CLIENT_ID);\n\n const interval = _heartbeats.get(docId);\n if (interval) {\n clearInterval(interval);\n _heartbeats.delete(docId);\n }\n}\n\nfunction scheduleLingerRemoval(docId: string, lingerMs: number): void {\n cancelLinger(docId);\n if (lingerMs <= 0) {\n removeAgentPresence(docId);\n return;\n }\n const timer = setTimeout(() => {\n _lingerTimers.delete(docId);\n // A new operation may have re-entered while we waited.\n if ((_refCounts.get(docId) ?? 0) > 0) return;\n removeAgentPresence(docId);\n }, lingerMs);\n if (typeof timer === \"object\" && \"unref\" in timer) {\n timer.unref();\n }\n _lingerTimers.set(docId, timer);\n}\n\nfunction ensureHeartbeat(docId: string): void {\n if (_heartbeats.has(docId)) return;\n\n const interval = setInterval(() => {\n const m = getDocAwareness(docId);\n const existing = m.get(AGENT_CLIENT_ID);\n if (existing) {\n existing.lastSeen = Date.now();\n // Keep the SQL mirror fresh too, or remote-instance pollers would see\n // the agent expire mid-operation (store throttles unchanged writes).\n void upsertAwarenessRow(\n docId,\n AGENT_CLIENT_ID,\n existing.state,\n existing.lastSeen,\n );\n }\n }, HEARTBEAT_INTERVAL);\n\n // Don't block Node from exiting if this is the only timer left\n if (typeof interval === \"object\" && \"unref\" in interval) {\n interval.unref();\n }\n\n _heartbeats.set(docId, interval);\n}\n\nfunction currentAwarenessStates(map: Map<number, AwarenessEntry>) {\n return Array.from(map, ([clientId, entry]) => ({\n clientId,\n state: entry.state,\n }));\n}\n\nfunction readAgentState(docId: string): Record<string, unknown> {\n const existing = getDocAwareness(docId).get(AGENT_CLIENT_ID);\n if (existing) {\n try {\n return JSON.parse(existing.state) as Record<string, unknown>;\n } catch {\n // Invalid state — fall through to defaults\n }\n }\n return {\n user: {\n name: DEFAULT_AGENT_IDENTITY.name,\n email: DEFAULT_AGENT_IDENTITY.email,\n color: DEFAULT_AGENT_IDENTITY.color,\n },\n };\n}\n\nfunction writeAgentState(docId: string, state: Record<string, unknown>): void {\n const entry: AwarenessEntry = {\n clientId: AGENT_CLIENT_ID,\n state: JSON.stringify(state),\n lastSeen: Date.now(),\n };\n const map = getDocAwareness(docId);\n map.set(AGENT_CLIENT_ID, entry);\n emitAwarenessChange(docId, currentAwarenessStates(map));\n // Mirror to SQL so pollers on other instances see the agent — an action\n // often runs in a different serverless invocation than the poll route.\n void upsertAwarenessRow(docId, AGENT_CLIENT_ID, entry.state, entry.lastSeen);\n}\n\n/**\n * Mark the agent as present on a document.\n *\n * Sets an awareness entry for the agent and starts a heartbeat that\n * keeps it alive. If the agent is already present on this doc (including\n * lingering after a previous edit), refreshes state without creating a\n * second interval.\n */\nexport function agentEnterDocument(\n docId: string,\n metadata?: Record<string, unknown>,\n): void {\n cancelLinger(docId);\n\n const state = { ...readAgentState(docId), ...metadata };\n writeAgentState(docId, state);\n\n // Increment reference count\n _refCounts.set(docId, (_refCounts.get(docId) ?? 0) + 1);\n\n ensureHeartbeat(docId);\n}\n\nexport interface AgentLeaveOptions {\n /**\n * How long presence lingers before the awareness entry clears.\n * Defaults to {@link AGENT_PRESENCE_LINGER_MS}. Pass 0 to clear\n * immediately (e.g. when an operation failed before editing anything).\n */\n lingerMs?: number;\n}\n\n/**\n * Release the agent's presence on a document.\n *\n * Decrements the reference count; when it reaches zero the awareness entry\n * lingers for `lingerMs` (default 6s) and is then removed. Viewers see the\n * agent avatar/highlights for a beat after the edit completes instead of an\n * instant disappearance.\n */\nexport function agentLeaveDocument(\n docId: string,\n options?: AgentLeaveOptions,\n): void {\n const count = (_refCounts.get(docId) ?? 1) - 1;\n if (count > 0) {\n _refCounts.set(docId, count);\n return;\n }\n _refCounts.delete(docId);\n\n scheduleLingerRemoval(docId, options?.lingerMs ?? AGENT_PRESENCE_LINGER_MS);\n}\n\n/**\n * Update the agent's awareness state to include selection info\n * (e.g., which track, panel, or element the agent is working on).\n */\nexport function agentUpdateSelection(\n docId: string,\n selection: Record<string, unknown>,\n): void {\n const state = { ...readAgentState(docId), ...selection };\n writeAgentState(docId, state);\n}\n\nexport interface AgentTouchOptions {\n /** Region descriptor + label recorded in the agent's recentEdits ring. */\n edit?: Omit<RecentEdit, \"at\"> & { at?: number };\n /** Extra awareness fields to merge (e.g. `selection`). */\n metadata?: Record<string, unknown>;\n /** Linger before auto-clearing when no enter/leave pair is active. */\n lingerMs?: number;\n}\n\n/**\n * Record an agent edit on a document without requiring an explicit\n * enter/leave pair. Used by the collab write paths so ANY agent edit\n * produces visible presence + lingering attribution automatically.\n *\n * - Upserts the agent awareness entry (identity preserved/merged).\n * - Appends to the `recentEdits` ring and bumps `lastEditAt`.\n * - When no explicit operation is in flight (refcount 0), (re)schedules a\n * linger removal so presence fades out on its own.\n */\nexport function agentTouchDocument(\n docId: string,\n options?: AgentTouchOptions,\n): void {\n cancelLinger(docId);\n\n const state = { ...readAgentState(docId), ...(options?.metadata ?? {}) };\n const now = Date.now();\n if (options?.edit) {\n const { at, ...rest } = options.edit;\n state.recentEdits = appendRecentEdit(\n state.recentEdits as RecentEdit[] | undefined,\n { ...rest, at: at ?? now },\n );\n }\n state.lastEditAt = now;\n writeAgentState(docId, state);\n\n ensureHeartbeat(docId);\n\n if ((_refCounts.get(docId) ?? 0) === 0) {\n scheduleLingerRemoval(docId, options?.lingerMs ?? AGENT_PRESENCE_LINGER_MS);\n }\n}\n\n/**\n * Apply search-and-replace edits incrementally so each one appears\n * as a separate poll event to connected clients.\n *\n * Enters the document before editing and leaves in a finally block.\n */\nexport async function agentApplyEditsIncrementally(\n docId: string,\n edits: Array<{ find: string; replace: string }>,\n options?: { delayMs?: number },\n): Promise<void> {\n const delayMs = options?.delayMs ?? 150;\n agentEnterDocument(docId);\n\n try {\n for (const edit of edits) {\n await searchAndReplace(docId, edit.find, edit.replace, \"agent\");\n if (delayMs > 0) {\n await new Promise((r) => setTimeout(r, delayMs));\n }\n }\n } finally {\n agentLeaveDocument(docId);\n }\n}\n\n/**\n * Apply structured data patches incrementally so each one appears\n * as a separate poll event to connected clients.\n *\n * Enters the document before patching and leaves in a finally block.\n */\nexport async function agentApplyPatchesIncrementally(\n docId: string,\n fieldName: string,\n patches: Array<{\n op: string;\n path: string;\n value?: unknown;\n index?: number;\n from?: number;\n to?: number;\n }>,\n options?: { delayMs?: number },\n): Promise<void> {\n const delayMs = options?.delayMs ?? 150;\n agentEnterDocument(docId);\n\n try {\n // Resolve applyPatchOps dynamically so a build that strips it (or a partial\n // upgrade) fails loudly here rather than at module load time.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let applyPatchOps: any;\n try {\n const mod = await import(\"./ydoc-manager.js\");\n applyPatchOps = (mod as Record<string, unknown>).applyPatchOps;\n } catch {\n throw new Error(\n \"applyPatchOps is not available yet — Phase 1 must complete first\",\n );\n }\n\n if (typeof applyPatchOps !== \"function\") {\n throw new Error(\n \"applyPatchOps is not available yet — Phase 1 must complete first\",\n );\n }\n\n for (const patch of patches) {\n await applyPatchOps(docId, [patch], fieldName, \"agent\");\n if (delayMs > 0) {\n await new Promise((r) => setTimeout(r, delayMs));\n }\n }\n } finally {\n agentLeaveDocument(docId);\n }\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQL-backed awareness store — makes presence work across serverless
|
|
3
|
+
* instances.
|
|
4
|
+
*
|
|
5
|
+
* The in-memory awareness map in `awareness.ts` is per-process: on a
|
|
6
|
+
* multi-instance/serverless deployment, a cursor published to instance A is
|
|
7
|
+
* invisible to a client polling instance B, and an agent action running in
|
|
8
|
+
* its own invocation can't reach the SSE instance's memory at all. This
|
|
9
|
+
* store mirrors awareness rows into a `_collab_awareness` table (SQLite +
|
|
10
|
+
* Postgres portable) so every instance serves the same participant set.
|
|
11
|
+
*
|
|
12
|
+
* Everything here is best-effort: presence must never fail or slow down an
|
|
13
|
+
* edit. Writes are throttled per (docId, clientId) and skipped when the
|
|
14
|
+
* state hasn't changed; expired rows are purged opportunistically.
|
|
15
|
+
*/
|
|
16
|
+
import type { AwarenessEntry } from "./awareness.js";
|
|
17
|
+
/**
|
|
18
|
+
* Mirror a client's awareness state to SQL. Throttled: unchanged state is
|
|
19
|
+
* rewritten at most every {@link WRITE_THROTTLE_MS} (to refresh last_seen).
|
|
20
|
+
* Never throws.
|
|
21
|
+
*/
|
|
22
|
+
export declare function upsertAwarenessRow(docId: string, clientId: number, state: string, lastSeen: number): Promise<void>;
|
|
23
|
+
/** Remove a client's row (participant left). Never throws. */
|
|
24
|
+
export declare function deleteAwarenessRow(docId: string, clientId: number): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Load non-expired awareness rows for a document. Returns [] on any
|
|
27
|
+
* failure (memory-only degradation).
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadAwarenessRows(docId: string, now?: number): Promise<AwarenessEntry[]>;
|
|
30
|
+
/** Test hook: reset module-level throttles. */
|
|
31
|
+
export declare function _resetAwarenessStoreForTests(): void;
|
|
32
|
+
//# sourceMappingURL=awareness-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"awareness-store.d.ts","sourceRoot":"","sources":["../../src/collab/awareness-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAkDrD;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAmCf;AAED,8DAA8D;AAC9D,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,GAAG,GAAE,MAAmB,GACvB,OAAO,CAAC,cAAc,EAAE,CAAC,CAiB3B;AAaD,+CAA+C;AAC/C,wBAAgB,4BAA4B,IAAI,IAAI,CAInD"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"awareness-store.js","sourceRoot":"","sources":["../../src/collab/awareness-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * SQL-backed awareness store — makes presence work across serverless\n * instances.\n *\n * The in-memory awareness map in `awareness.ts` is per-process: on a\n * multi-instance/serverless deployment, a cursor published to instance A is\n * invisible to a client polling instance B, and an agent action running in\n * its own invocation can't reach the SSE instance's memory at all. This\n * store mirrors awareness rows into a `_collab_awareness` table (SQLite +\n * Postgres portable) so every instance serves the same participant set.\n *\n * Everything here is best-effort: presence must never fail or slow down an\n * edit. Writes are throttled per (docId, clientId) and skipped when the\n * state hasn't changed; expired rows are purged opportunistically.\n */\n\nimport { getDbExec, isPostgres } from \"../db/client.js\";\nimport { ensureTableExists } from \"../db/ddl-guard.js\";\nimport type { AwarenessEntry } from \"./awareness.js\";\n\n/** Rows older than this are treated as expired (matches AWARENESS_TIMEOUT). */\nconst ROW_TTL_MS = 30_000;\n\n/** Minimum interval between DB writes for an unchanged (docId, clientId). */\nconst WRITE_THROTTLE_MS = 2_000;\n\n/** Minimum interval between opportunistic purges per document. */\nconst PURGE_INTERVAL_MS = 30_000;\n\nlet _initPromise: Promise<void> | undefined;\n\nasync function ensureTable(): Promise<void> {\n if (!_initPromise) {\n _initPromise = (async () => {\n const client = getDbExec();\n // client_id is a Yjs uint32 (can exceed int32 max) and last_seen is\n // epoch milliseconds — both need BIGINT-range columns.\n const createSql = `\n CREATE TABLE IF NOT EXISTS _collab_awareness (\n doc_id TEXT NOT NULL,\n client_id BIGINT NOT NULL,\n state TEXT NOT NULL,\n last_seen BIGINT NOT NULL,\n PRIMARY KEY (doc_id, client_id)\n )\n `;\n if (isPostgres()) {\n await ensureTableExists(\"_collab_awareness\", createSql);\n return;\n }\n await client.execute(createSql);\n })().catch((err) => {\n _initPromise = undefined;\n throw err;\n });\n }\n return _initPromise;\n}\n\n// (docId\u0000clientId) → { state, writtenAt } for write throttling.\nconst _lastWrites = new Map<string, { state: string; writtenAt: number }>();\n// docId → last purge time.\nconst _lastPurges = new Map<string, number>();\n\nfunction writeKey(docId: string, clientId: number): string {\n return `${docId}\u0000${clientId}`;\n}\n\n/**\n * Mirror a client's awareness state to SQL. Throttled: unchanged state is\n * rewritten at most every {@link WRITE_THROTTLE_MS} (to refresh last_seen).\n * Never throws.\n */\nexport async function upsertAwarenessRow(\n docId: string,\n clientId: number,\n state: string,\n lastSeen: number,\n): Promise<void> {\n try {\n const key = writeKey(docId, clientId);\n const prev = _lastWrites.get(key);\n if (\n prev &&\n prev.state === state &&\n lastSeen - prev.writtenAt < WRITE_THROTTLE_MS\n ) {\n return;\n }\n\n await ensureTable();\n const client = getDbExec();\n if (isPostgres()) {\n await client.execute({\n sql: `INSERT INTO _collab_awareness (doc_id, client_id, state, last_seen)\n VALUES (?, ?, ?, ?)\n ON CONFLICT (doc_id, client_id)\n DO UPDATE SET state = EXCLUDED.state, last_seen = EXCLUDED.last_seen`,\n args: [docId, clientId, state, lastSeen],\n });\n } else {\n await client.execute({\n sql: `INSERT OR REPLACE INTO _collab_awareness (doc_id, client_id, state, last_seen)\n VALUES (?, ?, ?, ?)`,\n args: [docId, clientId, state, lastSeen],\n });\n }\n _lastWrites.set(key, { state, writtenAt: lastSeen });\n\n await maybePurge(docId, lastSeen);\n } catch {\n // Best-effort — presence never fails a request.\n }\n}\n\n/** Remove a client's row (participant left). Never throws. */\nexport async function deleteAwarenessRow(\n docId: string,\n clientId: number,\n): Promise<void> {\n try {\n await ensureTable();\n const client = getDbExec();\n await client.execute({\n sql: `DELETE FROM _collab_awareness WHERE doc_id = ? AND client_id = ?`,\n args: [docId, clientId],\n });\n _lastWrites.delete(writeKey(docId, clientId));\n } catch {\n // Best-effort.\n }\n}\n\n/**\n * Load non-expired awareness rows for a document. Returns [] on any\n * failure (memory-only degradation).\n */\nexport async function loadAwarenessRows(\n docId: string,\n now: number = Date.now(),\n): Promise<AwarenessEntry[]> {\n try {\n await ensureTable();\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `SELECT client_id, state, last_seen FROM _collab_awareness\n WHERE doc_id = ? AND last_seen >= ?`,\n args: [docId, now - ROW_TTL_MS],\n });\n return rows.map((row: any) => ({\n clientId: Number(row.client_id),\n state: String(row.state),\n lastSeen: Number(row.last_seen),\n }));\n } catch {\n return [];\n }\n}\n\nasync function maybePurge(docId: string, now: number): Promise<void> {\n const last = _lastPurges.get(docId) ?? 0;\n if (now - last < PURGE_INTERVAL_MS) return;\n _lastPurges.set(docId, now);\n const client = getDbExec();\n await client.execute({\n sql: `DELETE FROM _collab_awareness WHERE doc_id = ? AND last_seen < ?`,\n args: [docId, now - ROW_TTL_MS * 2],\n });\n}\n\n/** Test hook: reset module-level throttles. */\nexport function _resetAwarenessStoreForTests(): void {\n _lastWrites.clear();\n _lastPurges.clear();\n _initPromise = undefined;\n}\n"]}
|