@agent-native/core 0.131.5 → 0.131.7
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 +3 -3
- package/corpus/core/CHANGELOG.md +70 -0
- package/corpus/core/docs/content/agent-native-toolkit.mdx +13 -6
- package/corpus/core/docs/content/cloneable-saas.mdx +5 -5
- package/corpus/core/docs/content/creating-templates.mdx +9 -0
- package/corpus/core/docs/content/deployment.mdx +18 -12
- package/corpus/core/docs/content/doctor.mdx +8 -1
- package/corpus/core/docs/content/drop-in-agent.mdx +1 -1
- package/corpus/core/docs/content/extensions.mdx +18 -18
- package/corpus/core/docs/content/faq.mdx +4 -4
- package/corpus/core/docs/content/key-concepts.mdx +30 -21
- package/corpus/core/docs/content/security.mdx +2 -2
- package/corpus/core/docs/content/template-brain-developers.mdx +4 -1
- package/corpus/core/docs/content/template-mail-developers.mdx +4 -1
- package/corpus/core/docs/content/what-is-agent-native.mdx +6 -6
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +449 -66
- package/corpus/core/src/a2a/correlation.ts +31 -0
- package/corpus/core/src/a2a/invoke.ts +4 -2
- package/corpus/core/src/a2a/types.ts +4 -0
- package/corpus/core/src/action.ts +3 -0
- package/corpus/core/src/agent/action-continuation-guidance.ts +2 -1
- package/corpus/core/src/agent/engine/registry.ts +98 -6
- package/corpus/core/src/agent/production-agent.ts +151 -18
- package/corpus/core/src/agent/run-loop-with-resume.ts +190 -3
- package/corpus/core/src/agent/run-manager.ts +117 -41
- package/corpus/core/src/agent/thread-debug-history.ts +86 -0
- package/corpus/core/src/agent/types.ts +3 -1
- package/corpus/core/src/cli/create.ts +11 -1
- package/corpus/core/src/cli/templates-meta.ts +2 -2
- package/corpus/core/src/client/agent-chat-adapter.ts +91 -13
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +11 -9
- package/corpus/core/src/client/sse-event-processor.ts +17 -3
- package/corpus/core/src/db/client.ts +57 -17
- package/corpus/core/src/guards/no-env-credentials.ts +2 -0
- package/corpus/core/src/integrations/adapters/slack.ts +8 -3
- package/corpus/core/src/localization/default-messages.ts +44 -0
- package/corpus/core/src/observability/traces.ts +78 -5
- package/corpus/core/src/scripts/call-agent.ts +294 -11
- package/corpus/core/src/scripts/describe-workspace-apps.ts +2 -2
- package/corpus/core/src/secrets/crypto.ts +156 -35
- package/corpus/core/src/secrets/storage.ts +64 -26
- package/corpus/core/src/server/agent-capabilities.ts +1 -1
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +113 -7
- package/corpus/core/src/server/agent-chat/context-tools.ts +2 -0
- package/corpus/core/src/server/agent-chat/plugin-options.ts +34 -1
- package/corpus/core/src/server/agent-chat/prompt-resources.ts +1 -1
- package/corpus/core/src/server/agent-chat-plugin.ts +91 -59
- package/corpus/core/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
- package/corpus/core/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
- package/corpus/core/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
- package/corpus/core/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
- package/corpus/core/src/vite/client.ts +1 -0
- package/corpus/templates/analytics/.agents/skills/dashboard-ops/SKILL.md +5 -4
- package/corpus/templates/analytics/.agents/skills/gong/SKILL.md +6 -4
- package/corpus/templates/analytics/AGENTS.md +7 -4
- package/corpus/templates/analytics/actions/query-agent-native-analytics.ts +4 -3
- package/corpus/templates/analytics/changelog/2026-07-30-delegated-analytics-questions-now-return-a-useful-current-me.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-30-scheduled-dashboard-emails-complete-every-panel-without-pool.md +6 -0
- package/corpus/templates/analytics/scripts/emit-netlify-dashboard-report-cron.ts +28 -1
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +18 -11
- package/corpus/templates/analytics/server/lib/analytics-connector-catalog.ts +4 -4
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -5
- package/corpus/templates/analytics/server/lib/dashboard-panel-query.ts +6 -2
- package/corpus/templates/analytics/server/lib/dashboard-panel-source-resolver.ts +11 -4
- package/corpus/templates/analytics/server/lib/dashboard-report-render.ts +49 -31
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +16 -8
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +9 -3
- package/corpus/templates/analytics/server/lib/production-serverless-runtime.ts +11 -0
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +10 -0
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +3 -2
- package/corpus/templates/analytics/server/plugins/analytics-alert-jobs.ts +2 -1
- package/corpus/templates/analytics/server/plugins/dashboard-report-jobs.ts +2 -1
- package/corpus/templates/analytics/server/plugins/uptime-monitor-jobs.ts +1 -12
- package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +54 -6
- package/corpus/templates/brain/.agents/skills/brain/SKILL.md +20 -9
- package/corpus/templates/brain/.agents/skills/ingestion-and-connectors/SKILL.md +33 -1
- package/corpus/templates/brain/AGENTS.md +3 -1
- package/corpus/templates/brain/README.md +4 -1
- package/corpus/templates/brain/actions/_schemas.ts +30 -8
- package/corpus/templates/brain/actions/ask-brain.ts +124 -14
- package/corpus/templates/brain/actions/create-source.ts +18 -2
- package/corpus/templates/brain/actions/enqueue-captures-distillation.ts +8 -123
- package/corpus/templates/brain/actions/enqueue-distillation.ts +6 -127
- package/corpus/templates/brain/actions/import-capture.ts +17 -5
- package/corpus/templates/brain/actions/import-transcript.ts +17 -5
- package/corpus/templates/brain/actions/update-source.ts +25 -5
- package/corpus/templates/brain/app/components/layout/Sidebar.tsx +1 -1
- package/corpus/templates/brain/changelog/2026-07-30-blessed-resources-can-feed-cited-company-answers.md +6 -0
- package/corpus/templates/brain/changelog/2026-07-30-the-left-sidebar-no-longer-shows-a-blank-organization-placeh.md +6 -0
- package/corpus/templates/brain/server/lib/brain.ts +49 -19
- package/corpus/templates/brain/server/lib/distillation-queue.ts +147 -0
- package/corpus/templates/brain/server/lib/source-policy.ts +264 -0
- package/corpus/templates/brain/server/plugins/agent-chat.ts +3 -2
- package/corpus/templates/brain/server/routes/api/_agent-native/brain/ingest.post.ts +116 -19
- package/corpus/templates/clips/app/components/meetings/google-oauth-identity-notice.tsx +51 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +4 -0
- package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +3 -1
- package/corpus/templates/clips/changelog/2026-07-30-google-calendar-warning.md +6 -0
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +72 -8
- package/corpus/templates/content/changelog/2026-07-30-the-slash-command-hint-now-stays-on-only-the-active-empty-li.md +6 -0
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +506 -11
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +148 -17
- package/corpus/templates/design/app/components/design/canvas-interactions/design-canvas-interactions.ts +357 -0
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +7 -466
- package/corpus/templates/design/app/components/design/inspector/scrub-input-utils.ts +15 -311
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +19 -997
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +8 -1216
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +31 -38
- package/corpus/templates/design/package.json +0 -1
- package/corpus/templates/dispatch/AGENTS.md +8 -0
- package/corpus/templates/dispatch/DEVELOPING.md +29 -0
- package/corpus/templates/dispatch/actions/view-screen.ts +34 -2
- package/corpus/templates/dispatch/app/i18n-data.ts +457 -0
- package/corpus/templates/dispatch/changelog/2026-07-30-delegated-dispatch-work-continues-reliably-in-the-background.md +6 -0
- package/corpus/templates/dispatch/changelog/2026-07-30-find-failed-runs-across-apps.md +6 -0
- package/corpus/templates/dispatch/netlify.toml +3 -0
- package/corpus/templates/plan/actions/get-visual-plan.ts +10 -6
- package/corpus/templates/plan/actions/patch-visual-plan-source.ts +117 -1
- package/corpus/templates/plan/actions/update-visual-plan.ts +56 -14
- package/corpus/templates/plan/app/pages/PlansPage.tsx +1 -1
- package/corpus/templates/plan/changelog/2026-07-30-plan-agents-recover-with-targeted-writes.md +6 -0
- package/corpus/templates/plan/shared/plan-content.ts +35 -0
- package/corpus/templates/slides/.agents/skills/analytics-data-for-decks/SKILL.md +8 -12
- package/corpus/templates/slides/AGENTS.md +4 -4
- package/corpus/templates/slides/actions/create-deck.ts +1 -1
- package/corpus/templates/slides/actions/duplicate-deck.ts +19 -4
- package/corpus/templates/slides/app/components/deck/DeckCard.tsx +2 -10
- package/corpus/templates/slides/app/components/deck/MermaidRenderer.tsx +12 -1
- package/corpus/templates/slides/app/components/deck/SlideRenderer.tsx +30 -13
- package/corpus/templates/slides/app/components/editor/DeckEditorSkeleton.tsx +35 -0
- package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +63 -56
- package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +21 -76
- package/corpus/templates/slides/app/components/editor/SlideEditor.tsx +1110 -292
- package/corpus/templates/slides/app/components/editor/SlideOverflowWarning.tsx +53 -0
- package/corpus/templates/slides/app/components/editor/SlideStyleInspector.tsx +235 -18
- package/corpus/templates/slides/app/components/editor/SpeakerNotesPanel.tsx +4 -1
- package/corpus/templates/slides/app/components/editor/canvas-interactions/index.ts +11 -0
- package/corpus/templates/slides/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +129 -0
- package/corpus/templates/slides/app/components/editor/selection-overlay-measurement.ts +70 -0
- package/corpus/templates/slides/app/components/editor/slide-object-interactions.ts +519 -65
- package/corpus/templates/slides/app/components/visual-editor/CanvasCommentPins.tsx +36 -426
- package/corpus/templates/slides/app/components/visual-editor/DrawOverlay.tsx +19 -458
- package/corpus/templates/slides/app/context/DeckContext.tsx +179 -72
- package/corpus/templates/slides/app/global.css +105 -0
- package/corpus/templates/slides/app/i18n/en-US.ts +8 -0
- package/corpus/templates/slides/app/lib/deck-editor-loading.ts +26 -0
- package/corpus/templates/slides/app/lib/mermaid-blocks.ts +27 -0
- package/corpus/templates/slides/app/pages/DeckEditor.tsx +71 -38
- package/corpus/templates/slides/app/pages/Index.tsx +98 -41
- package/corpus/templates/slides/changelog/2026-07-30-deck-loading-no-longer-flashes-an-unavailable-message.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-duplicating-a-deck-from-the-deck-list-now-opens-the-copy-imm.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-layout-overflow-warning-is-readable-and-dismissible.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-new-decks-now-start-with-an-empty-slide-list-when-no-slides-.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-shared-canvas-annotations.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-slide-objects-can-be-moved-as-a-group-copied-and-pasted-with.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-slide-text-editing-and-object-controls-now-match-google-slides.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-style-panel-now-scrolls-with-speaker-notes-open-shows-the-sl.md +6 -0
- package/corpus/templates/slides/changelog/2026-07-30-top-toolbar-controls-now-use-consistent-sizing-with-undo-and.md +6 -0
- package/corpus/templates/slides/netlify.toml +3 -1
- package/corpus/templates/slides/package.json +0 -1
- package/corpus/templates/slides/server/lib/chat-attachments.ts +18 -0
- package/corpus/templates/slides/server/plugins/agent-chat.ts +5 -0
- package/corpus/templates/slides/vite.config.ts +0 -1
- package/corpus/toolkit/CHANGELOG.md +13 -0
- package/corpus/toolkit/README.md +19 -0
- package/corpus/toolkit/agent-native.eject.json +38 -0
- package/corpus/toolkit/package.json +29 -1
- package/corpus/toolkit/src/canvas-annotations/CanvasCommentPins.tsx +861 -0
- package/corpus/toolkit/src/canvas-annotations/DrawOverlay.tsx +1233 -0
- package/corpus/toolkit/src/canvas-annotations/index.ts +15 -0
- package/corpus/toolkit/src/canvas-annotations/types.ts +14 -0
- package/corpus/toolkit/src/canvas-interactions/canvas-interactions.ts +933 -0
- package/corpus/toolkit/src/canvas-interactions/index.ts +67 -0
- package/corpus/toolkit/src/design-tweaks/scrub-input-utils.ts +311 -0
- package/corpus/toolkit/src/design-tweaks/scrub-input.tsx +491 -0
- package/corpus/toolkit/src/design-tweaks/visual-style-controls.tsx +26 -171
- package/corpus/toolkit/src/index.ts +1 -0
- package/dist/a2a/client.d.ts +23 -0
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +309 -44
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/correlation.d.ts +1 -0
- package/dist/a2a/correlation.d.ts.map +1 -1
- package/dist/a2a/correlation.js +27 -0
- package/dist/a2a/correlation.js.map +1 -1
- package/dist/a2a/invoke.d.ts.map +1 -1
- package/dist/a2a/invoke.js +4 -2
- package/dist/a2a/invoke.js.map +1 -1
- package/dist/a2a/types.d.ts +4 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/action.d.ts +3 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js.map +1 -1
- package/dist/agent/action-continuation-guidance.d.ts.map +1 -1
- package/dist/agent/action-continuation-guidance.js +2 -1
- package/dist/agent/action-continuation-guidance.js.map +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +82 -8
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/production-agent.d.ts +40 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +113 -15
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts +21 -0
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +163 -4
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/run-manager.d.ts +16 -9
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +93 -42
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/thread-debug-history.d.ts +10 -0
- package/dist/agent/thread-debug-history.d.ts.map +1 -0
- package/dist/agent/thread-debug-history.js +68 -0
- package/dist/agent/thread-debug-history.js.map +1 -0
- package/dist/agent/types.d.ts +3 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +6 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/templates-meta.js +2 -2
- package/dist/cli/templates-meta.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +76 -13
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +1 -1
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +12 -3
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +48 -17
- package/dist/db/client.js.map +1 -1
- package/dist/guards/no-env-credentials.d.ts.map +1 -1
- package/dist/guards/no-env-credentials.js +2 -0
- package/dist/guards/no-env-credentials.js.map +1 -1
- package/dist/integrations/adapters/slack.js +7 -3
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/localization/default-messages.d.ts +43 -0
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +43 -0
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/observability/traces.d.ts +3 -1
- package/dist/observability/traces.d.ts.map +1 -1
- package/dist/observability/traces.js +73 -4
- package/dist/observability/traces.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +13 -13
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +237 -12
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/scripts/describe-workspace-apps.js +2 -2
- package/dist/scripts/describe-workspace-apps.js.map +1 -1
- package/dist/secrets/crypto.d.ts +36 -21
- package/dist/secrets/crypto.d.ts.map +1 -1
- package/dist/secrets/crypto.js +134 -33
- package/dist/secrets/crypto.js.map +1 -1
- package/dist/secrets/storage.d.ts +6 -6
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +43 -26
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/agent-capabilities.js +1 -1
- package/dist/server/agent-capabilities.js.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.d.ts +17 -3
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +94 -3
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-chat/context-tools.d.ts.map +1 -1
- package/dist/server/agent-chat/context-tools.js +2 -0
- package/dist/server/agent-chat/context-tools.js.map +1 -1
- package/dist/server/agent-chat/plugin-options.d.ts +23 -0
- package/dist/server/agent-chat/plugin-options.d.ts.map +1 -1
- package/dist/server/agent-chat/plugin-options.js +4 -1
- package/dist/server/agent-chat/plugin-options.js.map +1 -1
- package/dist/server/agent-chat/prompt-resources.js +1 -1
- package/dist/server/agent-chat/prompt-resources.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +2 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +79 -56
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/default/.agents/skills/secrets/SKILL.md +19 -7
- package/dist/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
- package/dist/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
- package/dist/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +1 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/agent-native-toolkit.mdx +13 -6
- package/docs/content/cloneable-saas.mdx +5 -5
- package/docs/content/creating-templates.mdx +9 -0
- package/docs/content/deployment.mdx +18 -12
- package/docs/content/doctor.mdx +8 -1
- package/docs/content/drop-in-agent.mdx +1 -1
- package/docs/content/extensions.mdx +18 -18
- package/docs/content/faq.mdx +4 -4
- package/docs/content/key-concepts.mdx +30 -21
- package/docs/content/security.mdx +2 -2
- package/docs/content/template-brain-developers.mdx +4 -1
- package/docs/content/template-mail-developers.mdx +4 -1
- package/docs/content/what-is-agent-native.mdx +6 -6
- package/package.json +3 -3
- package/src/a2a/client.ts +449 -66
- package/src/a2a/correlation.ts +31 -0
- package/src/a2a/invoke.ts +4 -2
- package/src/a2a/types.ts +4 -0
- package/src/action.ts +3 -0
- package/src/agent/action-continuation-guidance.ts +2 -1
- package/src/agent/engine/registry.ts +98 -6
- package/src/agent/production-agent.ts +151 -18
- package/src/agent/run-loop-with-resume.ts +190 -3
- package/src/agent/run-manager.ts +117 -41
- package/src/agent/thread-debug-history.ts +86 -0
- package/src/agent/types.ts +3 -1
- package/src/cli/create.ts +11 -1
- package/src/cli/templates-meta.ts +2 -2
- package/src/client/agent-chat-adapter.ts +91 -13
- package/src/client/resources/McpIntegrationDialog.tsx +11 -9
- package/src/client/sse-event-processor.ts +17 -3
- package/src/db/client.ts +57 -17
- package/src/guards/no-env-credentials.ts +2 -0
- package/src/integrations/adapters/slack.ts +8 -3
- package/src/localization/default-messages.ts +44 -0
- package/src/observability/traces.ts +78 -5
- package/src/scripts/call-agent.ts +294 -11
- package/src/scripts/describe-workspace-apps.ts +2 -2
- package/src/secrets/crypto.ts +156 -35
- package/src/secrets/storage.ts +64 -26
- package/src/server/agent-capabilities.ts +1 -1
- package/src/server/agent-chat/action-filters-a2a.ts +113 -7
- package/src/server/agent-chat/context-tools.ts +2 -0
- package/src/server/agent-chat/plugin-options.ts +34 -1
- package/src/server/agent-chat/prompt-resources.ts +1 -1
- package/src/server/agent-chat-plugin.ts +91 -59
- package/src/templates/default/.agents/skills/secrets/SKILL.md +19 -7
- package/src/templates/headless/.agents/skills/secrets/SKILL.md +19 -7
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +18 -7
- package/src/templates/workspace-core/.agents/skills/composable-mini-apps/SKILL.md +15 -14
- package/src/templates/workspace-core/.agents/skills/secrets/SKILL.md +19 -7
- package/src/vite/client.ts +1 -0
|
@@ -28,6 +28,73 @@ import {
|
|
|
28
28
|
} from "../server/plans.js";
|
|
29
29
|
import type { PlanContent } from "../shared/plan-content.js";
|
|
30
30
|
|
|
31
|
+
const agentPlanMdxSourcePatchesSchema = z
|
|
32
|
+
.array(
|
|
33
|
+
z.discriminatedUnion("op", [
|
|
34
|
+
z.object({
|
|
35
|
+
op: z.literal("replace-markdown-block"),
|
|
36
|
+
blockId: z.string().min(1),
|
|
37
|
+
markdown: z.string().max(16_000),
|
|
38
|
+
title: z.string().optional(),
|
|
39
|
+
}),
|
|
40
|
+
z.object({
|
|
41
|
+
op: z.literal("update-component-prop"),
|
|
42
|
+
file: z.enum(["plan.mdx", "canvas.mdx", "prototype.mdx"]),
|
|
43
|
+
componentId: z.string().min(1),
|
|
44
|
+
prop: z.string().min(1),
|
|
45
|
+
value: z.unknown(),
|
|
46
|
+
}),
|
|
47
|
+
z.object({
|
|
48
|
+
op: z.literal("update-wireframe-node"),
|
|
49
|
+
nodeId: z.string().min(1),
|
|
50
|
+
patch: z.record(z.string(), z.unknown()),
|
|
51
|
+
}),
|
|
52
|
+
z.object({
|
|
53
|
+
op: z.literal("update-annotation"),
|
|
54
|
+
annotationId: z.string().min(1),
|
|
55
|
+
patch: z.object({
|
|
56
|
+
type: z.enum(["note", "text", "callout", "arrow"]).optional(),
|
|
57
|
+
title: z.string().optional(),
|
|
58
|
+
text: z.string().max(2_000).optional(),
|
|
59
|
+
points: z
|
|
60
|
+
.array(z.object({ x: z.number(), y: z.number() }))
|
|
61
|
+
.min(1)
|
|
62
|
+
.max(12)
|
|
63
|
+
.optional(),
|
|
64
|
+
style: z
|
|
65
|
+
.object({
|
|
66
|
+
tone: z
|
|
67
|
+
.enum(["default", "accent", "warn", "ok", "muted"])
|
|
68
|
+
.optional(),
|
|
69
|
+
stroke: z.enum(["solid", "dashed"]).optional(),
|
|
70
|
+
width: z.number().min(1).max(12).optional(),
|
|
71
|
+
})
|
|
72
|
+
.optional(),
|
|
73
|
+
targetId: z.string().optional(),
|
|
74
|
+
placement: z
|
|
75
|
+
.enum([
|
|
76
|
+
"top",
|
|
77
|
+
"right",
|
|
78
|
+
"bottom",
|
|
79
|
+
"left",
|
|
80
|
+
"top-left",
|
|
81
|
+
"top-right",
|
|
82
|
+
"bottom-left",
|
|
83
|
+
"bottom-right",
|
|
84
|
+
])
|
|
85
|
+
.optional(),
|
|
86
|
+
x: z.number().optional(),
|
|
87
|
+
y: z.number().optional(),
|
|
88
|
+
}),
|
|
89
|
+
}),
|
|
90
|
+
]),
|
|
91
|
+
)
|
|
92
|
+
.max(80)
|
|
93
|
+
.describe(
|
|
94
|
+
"Small exported-MDX patches only. Never send replace-file or replace-artboard " +
|
|
95
|
+
"from an agent; for a live plan use update-visual-plan contentPatches instead.",
|
|
96
|
+
);
|
|
97
|
+
|
|
31
98
|
type PlanSurfaceCounts = {
|
|
32
99
|
blocks: number;
|
|
33
100
|
canvasFrames: number;
|
|
@@ -42,6 +109,28 @@ function planSurfaceCounts(content: PlanContent | null | undefined) {
|
|
|
42
109
|
} satisfies PlanSurfaceCounts;
|
|
43
110
|
}
|
|
44
111
|
|
|
112
|
+
function compactAgentWriteResult(
|
|
113
|
+
bundle: Awaited<ReturnType<typeof loadPlanBundle>>,
|
|
114
|
+
changed: Record<string, unknown>,
|
|
115
|
+
) {
|
|
116
|
+
return {
|
|
117
|
+
planId: bundle.plan.id,
|
|
118
|
+
plan: {
|
|
119
|
+
id: bundle.plan.id,
|
|
120
|
+
title: bundle.plan.title,
|
|
121
|
+
brief: bundle.plan.brief,
|
|
122
|
+
kind: bundle.plan.kind,
|
|
123
|
+
status: bundle.plan.status,
|
|
124
|
+
currentFocus: bundle.plan.currentFocus,
|
|
125
|
+
updatedAt: bundle.plan.updatedAt,
|
|
126
|
+
surfaces: planSurfaceCounts(bundle.plan.content),
|
|
127
|
+
},
|
|
128
|
+
changed,
|
|
129
|
+
path: planPath(bundle.plan.id, bundle.plan.kind),
|
|
130
|
+
url: planPath(bundle.plan.id, bundle.plan.kind),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
|
|
45
134
|
function stableJson(value: unknown): string {
|
|
46
135
|
if (value === null) return "null";
|
|
47
136
|
if (value === undefined) return "undefined";
|
|
@@ -140,7 +229,7 @@ function assertNoUnexpectedSurfaceCollapse(
|
|
|
140
229
|
|
|
141
230
|
export default defineAction({
|
|
142
231
|
description:
|
|
143
|
-
"Patch the MDX source for an Agent-Native Plan by stable semantic IDs, then normalize it back into runtime JSON. Use ONLY when working with exported MDX source files (repo check-in workflows); for live plans prefer update-visual-plan with contentPatches.
|
|
232
|
+
"Patch the MDX source for an Agent-Native Plan by stable semantic IDs, then normalize it back into runtime JSON. Use ONLY when working with exported MDX source files (repo check-in workflows); for live plans prefer update-visual-plan with contentPatches. For agent calls, use only small semantic patches and never resend replace-file or replace-artboard payloads.",
|
|
144
233
|
schema: z.object({
|
|
145
234
|
planId: z.string().describe("Plan ID"),
|
|
146
235
|
expectedUpdatedAt: z
|
|
@@ -162,6 +251,21 @@ export default defineAction({
|
|
|
162
251
|
),
|
|
163
252
|
note: z.string().optional().describe("Short audit note for plan history."),
|
|
164
253
|
}),
|
|
254
|
+
agentInputSchema: z.object({
|
|
255
|
+
planId: z.string().describe("Plan ID"),
|
|
256
|
+
expectedUpdatedAt: z
|
|
257
|
+
.string()
|
|
258
|
+
.min(1)
|
|
259
|
+
.optional()
|
|
260
|
+
.describe("Revision from the latest plan read when required."),
|
|
261
|
+
allowDestructive: z
|
|
262
|
+
.boolean()
|
|
263
|
+
.optional()
|
|
264
|
+
.default(false)
|
|
265
|
+
.describe("Allow an intentional nonempty-to-empty collapse."),
|
|
266
|
+
patches: agentPlanMdxSourcePatchesSchema,
|
|
267
|
+
note: z.string().optional().describe("Short audit note for plan history."),
|
|
268
|
+
}),
|
|
165
269
|
publicAgent: {
|
|
166
270
|
expose: true,
|
|
167
271
|
readOnly: false,
|
|
@@ -321,6 +425,18 @@ export default defineAction({
|
|
|
321
425
|
),
|
|
322
426
|
})
|
|
323
427
|
: null;
|
|
428
|
+
if (isAgentCaller) {
|
|
429
|
+
return {
|
|
430
|
+
...compactAgentWriteResult(updated, {
|
|
431
|
+
patchOps: args.patches.map((patch) => patch.op),
|
|
432
|
+
counts: {
|
|
433
|
+
before: beforeCounts,
|
|
434
|
+
after: afterCounts,
|
|
435
|
+
},
|
|
436
|
+
}),
|
|
437
|
+
...(local?.written ? { localFiles: local } : {}),
|
|
438
|
+
};
|
|
439
|
+
}
|
|
324
440
|
return {
|
|
325
441
|
...updated,
|
|
326
442
|
planId: updated.plan.id,
|
|
@@ -49,8 +49,7 @@ import {
|
|
|
49
49
|
sectionInputSchema,
|
|
50
50
|
} from "../server/plans.js";
|
|
51
51
|
import {
|
|
52
|
-
|
|
53
|
-
agentPlanContentSchema,
|
|
52
|
+
agentPlanIncrementalContentPatchesSchema,
|
|
54
53
|
applyPlanContentPatches,
|
|
55
54
|
planContentPatchesSchema,
|
|
56
55
|
planContentSchema,
|
|
@@ -454,6 +453,32 @@ const CONTENT_DESCRIPTION =
|
|
|
454
453
|
const CONTENT_PATCHES_DESCRIPTION =
|
|
455
454
|
"Targeted structured content edits addressed by stable id. Prefer granular operations for live plans. The destructive replace-blocks operation requires expectedUpdatedAt from a fresh read. patch-visual-plan-source is only for exported MDX folders. Supported ops: set-metadata for title/brief; set-visual-render-mode to persist `design` (high fidelity, authored CSS, no rough.js for any viewer) or `wireframe` across canvas, linked blocks, and prototype screens; set-prototype / remove-prototype / update-prototype-screen / patch-prototype-html for live prototype surfaces; update-block / replace-block, update-rich-text, patch-wireframe-html, patch-diagram-html, update-wireframe-node, replace-wireframe-screen, update-canvas-frame, update-canvas-annotation / append-canvas-annotation, append-block / remove-block, update-custom-html. A fidelity upgrade must also replace or patch the existing screen HTML/CSS with deliberate branded design; changing render mode alone only removes the sketch treatment.";
|
|
456
455
|
|
|
456
|
+
function compactAgentWriteResult(
|
|
457
|
+
bundle: Awaited<ReturnType<typeof loadPlanBundle>>,
|
|
458
|
+
changed: Record<string, unknown>,
|
|
459
|
+
) {
|
|
460
|
+
return {
|
|
461
|
+
planId: bundle.plan.id,
|
|
462
|
+
plan: {
|
|
463
|
+
id: bundle.plan.id,
|
|
464
|
+
title: bundle.plan.title,
|
|
465
|
+
brief: bundle.plan.brief,
|
|
466
|
+
kind: bundle.plan.kind,
|
|
467
|
+
status: bundle.plan.status,
|
|
468
|
+
currentFocus: bundle.plan.currentFocus,
|
|
469
|
+
updatedAt: bundle.plan.updatedAt,
|
|
470
|
+
surfaces: {
|
|
471
|
+
blocks: bundle.plan.content?.blocks.length ?? 0,
|
|
472
|
+
canvasFrames: bundle.plan.content?.canvas?.frames.length ?? 0,
|
|
473
|
+
prototypeScreens: bundle.plan.content?.prototype?.screens.length ?? 0,
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
changed,
|
|
477
|
+
path: planPath(bundle.plan.id, bundle.plan.kind),
|
|
478
|
+
url: planPath(bundle.plan.id, bundle.plan.kind),
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
|
|
457
482
|
// Named so `agentInputSchema` below can `.extend()` it with compact
|
|
458
483
|
// `content`/`contentPatches` fields instead of duplicating every other key.
|
|
459
484
|
const updateVisualPlanSchema = z.object({
|
|
@@ -527,21 +552,26 @@ const updateVisualPlanSchema = z.object({
|
|
|
527
552
|
.describe("Short label saved as the version-history snapshot label."),
|
|
528
553
|
});
|
|
529
554
|
|
|
555
|
+
// ADVERTISED-ONLY: agent edits to an existing plan must stay incremental. The
|
|
556
|
+
// runtime schema above still accepts full replacements for the browser editor
|
|
557
|
+
// and explicit callers that have intentionally chosen that workflow.
|
|
558
|
+
const agentUpdateVisualPlanSchema = updateVisualPlanSchema
|
|
559
|
+
.omit({ content: true, html: true, markdown: true, sections: true })
|
|
560
|
+
.extend({
|
|
561
|
+
contentPatches: agentPlanIncrementalContentPatchesSchema
|
|
562
|
+
.optional()
|
|
563
|
+
.default([])
|
|
564
|
+
.describe(
|
|
565
|
+
"Small targeted edits only. Do not send full content or replace-blocks; " +
|
|
566
|
+
"append or patch one existing block at a time.",
|
|
567
|
+
),
|
|
568
|
+
});
|
|
569
|
+
|
|
530
570
|
export default defineAction({
|
|
531
571
|
description:
|
|
532
|
-
"Update an Agent-Native Plan's structured content blocks, prototype screens, visual fidelity, sections, comments, or status.
|
|
572
|
+
"Update an Agent-Native Plan's structured content blocks, prototype screens, visual fidelity, sections, comments, or status. For an existing plan, use small contentPatches such as append-block, update-rich-text, or a text patch; do not resend the full document for an incremental edit. When a user asks for higher fidelity on an existing plan, update that same plan in place: use set-visual-render-mode with design and provide polished screen HTML/CSS in the same call instead of creating a duplicate plan or only toggling the viewer-local clean style. Use a full replacement only for an explicit broad rebuild. Works on plans and recaps alike when you have editor access; with viewer access (common on PR recaps published by CI) only comment-only calls succeed - to change a recap you cannot edit, publish a replacement with create-visual-recap instead of retrying this call.",
|
|
533
573
|
schema: updateVisualPlanSchema,
|
|
534
|
-
|
|
535
|
-
// swap the deep per-block-type union for a compact `type`-enum stand-in.
|
|
536
|
-
// Runtime validation always runs the full schema above — see the `actions`
|
|
537
|
-
// skill.
|
|
538
|
-
agentInputSchema: updateVisualPlanSchema.extend({
|
|
539
|
-
content: agentPlanContentSchema.optional().describe(CONTENT_DESCRIPTION),
|
|
540
|
-
contentPatches: agentPlanContentPatchesSchema
|
|
541
|
-
.optional()
|
|
542
|
-
.default([])
|
|
543
|
-
.describe(CONTENT_PATCHES_DESCRIPTION),
|
|
544
|
-
}),
|
|
574
|
+
agentInputSchema: agentUpdateVisualPlanSchema,
|
|
545
575
|
publicAgent: {
|
|
546
576
|
expose: true,
|
|
547
577
|
readOnly: false,
|
|
@@ -1173,6 +1203,18 @@ export default defineAction({
|
|
|
1173
1203
|
),
|
|
1174
1204
|
})
|
|
1175
1205
|
: null;
|
|
1206
|
+
if (isAgentCaller) {
|
|
1207
|
+
return {
|
|
1208
|
+
...compactAgentWriteResult(bundle, {
|
|
1209
|
+
titleChanged: args.title !== undefined,
|
|
1210
|
+
briefChanged: args.brief !== undefined,
|
|
1211
|
+
statusChanged: args.status !== undefined,
|
|
1212
|
+
contentPatchOps: args.contentPatches.map((patch) => patch.op),
|
|
1213
|
+
commentCount: insertedCommentIds.length,
|
|
1214
|
+
}),
|
|
1215
|
+
...(local?.written ? { localFiles: local } : {}),
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1176
1218
|
return {
|
|
1177
1219
|
...bundle,
|
|
1178
1220
|
planId: bundle.plan.id,
|
|
@@ -1602,7 +1602,7 @@ export function buildPlanAgentContext(input: {
|
|
|
1602
1602
|
: [
|
|
1603
1603
|
"Fast iteration workflow:",
|
|
1604
1604
|
"1. Call get-visual-plan with this plan ID to read structured content, exported HTML, sections, comments, and activity.",
|
|
1605
|
-
'2. Prefer update-visual-plan contentPatches for
|
|
1605
|
+
'2. Prefer small update-visual-plan contentPatches for every edit to an existing plan. Examples: append-block for new tasks, update-rich-text for a bounded copy change, patch-prototype-html / update-prototype-screen for live prototype states, update-wireframe-node for one kit-tree node, update-canvas-frame for frame layout, append-canvas-annotation / update-canvas-annotation for canvas markup, or remove-block for one block. Never resend the full plan, use replace-blocks, or use patch-visual-plan-source replace-file for an incremental change - those payloads can be truncated before the tool receives them. When the user asks for higher fidelity, polished mockups, production-like UI, real design, or anything "not sketchy," update this same plan in place: rewrite the relevant screen HTML/CSS and include set-visual-render-mode with renderMode design. Do not create a second plan, put CSS in style tags, or treat the viewer-local Clean toggle as a fidelity upgrade. Use a full replacement only for an explicit broad rebuild. Use html only when preserving or importing a legacy standalone HTML artifact.',
|
|
1606
1606
|
"3. Preserve the user's existing annotation comments and intent unless the user asks to remove or resolve them.",
|
|
1607
1607
|
"4. Match the requested fidelity: ordinary UI planning can use sketch diagrams and wireframes; high-fidelity requests need the persisted Design surface with deliberate branded HTML/CSS and stable data-design-id targets.",
|
|
1608
1608
|
"5. After applying feedback, keep the plan scannable, editable, and serious instead of turning it into a marketing page.",
|
|
@@ -2944,6 +2944,41 @@ export const agentPlanContentPatchesSchema = z
|
|
|
2944
2944
|
"replace-block / replace-blocks / append-block.",
|
|
2945
2945
|
);
|
|
2946
2946
|
|
|
2947
|
+
/**
|
|
2948
|
+
* Model-facing patch vocabulary for edits to an existing hosted plan. Full
|
|
2949
|
+
* block/content replacement remains valid at runtime for the browser editor
|
|
2950
|
+
* and explicit callers, but advertising it to an agent makes it too easy to
|
|
2951
|
+
* resend the whole document and hit the provider's streamed-JSON limit.
|
|
2952
|
+
*/
|
|
2953
|
+
const AGENT_INCREMENTAL_PATCH_EXCLUDED_OPS = new Set([
|
|
2954
|
+
"set-prototype",
|
|
2955
|
+
"replace-block",
|
|
2956
|
+
"replace-blocks",
|
|
2957
|
+
"replace-wireframe-screen",
|
|
2958
|
+
]);
|
|
2959
|
+
|
|
2960
|
+
const agentIncrementalPlanContentPatchOptions =
|
|
2961
|
+
agentPlanContentPatchOptions.filter((option) => {
|
|
2962
|
+
const op = (option.shape as { op: { value: string } }).op.value;
|
|
2963
|
+
return !AGENT_INCREMENTAL_PATCH_EXCLUDED_OPS.has(op);
|
|
2964
|
+
});
|
|
2965
|
+
|
|
2966
|
+
export const agentPlanIncrementalContentPatchesSchema = z
|
|
2967
|
+
.array(
|
|
2968
|
+
z.discriminatedUnion(
|
|
2969
|
+
"op",
|
|
2970
|
+
agentIncrementalPlanContentPatchOptions as unknown as Parameters<
|
|
2971
|
+
typeof z.discriminatedUnion
|
|
2972
|
+
>[1],
|
|
2973
|
+
),
|
|
2974
|
+
)
|
|
2975
|
+
.max(80)
|
|
2976
|
+
.describe(
|
|
2977
|
+
"Small targeted edits to an existing plan. Prefer append-block, update-rich-text, " +
|
|
2978
|
+
"patch-wireframe-html, patch-prototype-html, or update-block. Do not " +
|
|
2979
|
+
"resend the full plan; use get-visual-plan for context and keep each call incremental.",
|
|
2980
|
+
);
|
|
2981
|
+
|
|
2947
2982
|
export function applyPlanContentPatches(
|
|
2948
2983
|
content: PlanContent,
|
|
2949
2984
|
patches: PlanContentPatch[],
|
|
@@ -17,18 +17,14 @@ other analytics data.
|
|
|
17
17
|
|
|
18
18
|
## Delegation
|
|
19
19
|
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
`account-deep-dive` for a named account or renewal/risk review, `gong-calls`
|
|
29
|
-
for quotes/counts/transcripts and coverage, and `gong-native-insights` for
|
|
30
|
-
bounded narrative synthesis. For first-party product activity, send a
|
|
31
|
-
natural-language message and let Analytics choose its query.
|
|
20
|
+
- Use `call-agent` with `agent: "analytics"` and a natural-language `message`
|
|
21
|
+
by default. Describe the business question, requested window or cohort, and
|
|
22
|
+
the concise result shape the deck needs. Analytics decides which sources,
|
|
23
|
+
tools, queries, and joins answer it.
|
|
24
|
+
- A direct `action` + `input` call is optional only when an exact bounded
|
|
25
|
+
semantic read and its complete schema are already known. It is not a fallback
|
|
26
|
+
for slow, failed, or unavailable agent delegation. Never invent an Analytics
|
|
27
|
+
action contract to make a demo pass.
|
|
32
28
|
- Slides must not write SQL, choose a warehouse or provider, call HubSpot/Gong
|
|
33
29
|
directly, or interpret a provider schema itself. Analytics owns source
|
|
34
30
|
selection, data dictionary interpretation, filters, joins, and query
|
|
@@ -41,10 +41,10 @@ ladder.
|
|
|
41
41
|
- Use image-generation and image-selection actions only when the deck genuinely
|
|
42
42
|
needs imagery; keep citations/asset provenance when available.
|
|
43
43
|
- Use framework sharing actions for deck visibility and grants.
|
|
44
|
-
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
- Ask a sibling app's agent with a natural-language `call-agent` message by
|
|
45
|
+
default. Let that specialist use its own instructions, skills, sources, and
|
|
46
|
+
tools. Direct action invocation is only for an exact bounded read with a
|
|
47
|
+
fully known schema; never use it as a workaround for slow or failed A2A.
|
|
48
48
|
- For data requests, read `.agents/skills/analytics-data-for-decks/SKILL.md` and
|
|
49
49
|
delegate via Analytics over A2A; do not write SQL or call providers directly.
|
|
50
50
|
- When the user names no reference deck or design system, call
|
|
@@ -75,7 +75,7 @@ const SlideSchema = z.object({
|
|
|
75
75
|
|
|
76
76
|
// Accept either a parsed array (HTTP/agent) or a JSON string (CLI)
|
|
77
77
|
const SlidesSchema = z.preprocess(
|
|
78
|
-
(v) => (typeof v === "string" ? JSON.parse(v) : v),
|
|
78
|
+
(v) => (v === undefined ? [] : typeof v === "string" ? JSON.parse(v) : v),
|
|
79
79
|
z.array(SlideSchema),
|
|
80
80
|
);
|
|
81
81
|
|
|
@@ -26,8 +26,15 @@ export default defineAction({
|
|
|
26
26
|
.describe(
|
|
27
27
|
"Optional client-supplied id for the new deck. Lets the UI pick the id ahead of time so it can navigate optimistically before the server responds.",
|
|
28
28
|
),
|
|
29
|
+
slideIds: z
|
|
30
|
+
.array(z.string().min(1).max(64))
|
|
31
|
+
.max(1000)
|
|
32
|
+
.optional()
|
|
33
|
+
.describe(
|
|
34
|
+
"Optional client-supplied ids for the copied slides, in slide order. Same purpose as `newId`: when the UI opens an optimistic copy the user can edit immediately, its slide ids must match the persisted copy or those edits address slides the server never had.",
|
|
35
|
+
),
|
|
29
36
|
}),
|
|
30
|
-
run: async ({ deckId, title, newId: clientNewId }) => {
|
|
37
|
+
run: async ({ deckId, title, newId: clientNewId, slideIds }) => {
|
|
31
38
|
const access = await resolveAccess("deck", deckId);
|
|
32
39
|
if (!access) throw new Error(`Deck not found: ${deckId}`);
|
|
33
40
|
|
|
@@ -37,9 +44,17 @@ export default defineAction({
|
|
|
37
44
|
const now = new Date().toISOString();
|
|
38
45
|
const deckData = JSON.parse(source.data);
|
|
39
46
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
47
|
+
// New IDs for all slides so edits to the copy don't collide with the
|
|
48
|
+
// original. A caller that already rendered an optimistic copy supplies the
|
|
49
|
+
// ids it used; anything it did not cover still gets a fresh one.
|
|
50
|
+
const slides = deckData.slides || [];
|
|
51
|
+
for (const [index, slide] of slides.entries()) {
|
|
52
|
+
slide.id = slideIds?.[index] ?? `slide-${nanoid(8)}`;
|
|
53
|
+
}
|
|
54
|
+
if (
|
|
55
|
+
new Set(slides.map((s: { id: string }) => s.id)).size !== slides.length
|
|
56
|
+
) {
|
|
57
|
+
throw new Error("slideIds must be unique");
|
|
43
58
|
}
|
|
44
59
|
|
|
45
60
|
const newTitle = title || `Copy of ${source.title}`;
|
|
@@ -32,7 +32,6 @@ interface DeckCardProps {
|
|
|
32
32
|
onRename: (id: string, newTitle: string) => void;
|
|
33
33
|
onDuplicate: (id: string) => void;
|
|
34
34
|
onToggleStar: (id: string, starred: boolean) => void;
|
|
35
|
-
isDuplicating?: boolean;
|
|
36
35
|
designSystemTitle?: string | null;
|
|
37
36
|
isWorkspaceDefault?: boolean;
|
|
38
37
|
canSetWorkspaceDefault?: boolean;
|
|
@@ -45,7 +44,6 @@ export default function DeckCard({
|
|
|
45
44
|
onRename,
|
|
46
45
|
onDuplicate,
|
|
47
46
|
onToggleStar,
|
|
48
|
-
isDuplicating = false,
|
|
49
47
|
designSystemTitle,
|
|
50
48
|
isWorkspaceDefault = false,
|
|
51
49
|
canSetWorkspaceDefault = false,
|
|
@@ -230,15 +228,9 @@ export default function DeckCard({
|
|
|
230
228
|
<IconPencil className="w-3.5 h-3.5 me-2" />
|
|
231
229
|
Rename
|
|
232
230
|
</DropdownMenuItem>
|
|
233
|
-
<DropdownMenuItem
|
|
234
|
-
onSelect={() => {
|
|
235
|
-
if (isDuplicating) return;
|
|
236
|
-
onDuplicate(deck.id);
|
|
237
|
-
}}
|
|
238
|
-
disabled={isDuplicating}
|
|
239
|
-
>
|
|
231
|
+
<DropdownMenuItem onSelect={() => onDuplicate(deck.id)}>
|
|
240
232
|
<IconCopy className="w-3.5 h-3.5 me-2" />
|
|
241
|
-
|
|
233
|
+
Duplicate
|
|
242
234
|
</DropdownMenuItem>
|
|
243
235
|
<DropdownMenuItem
|
|
244
236
|
onSelect={(event) => {
|
|
@@ -46,11 +46,13 @@ let idCounter = 0;
|
|
|
46
46
|
interface MermaidRendererProps {
|
|
47
47
|
definition: string;
|
|
48
48
|
className?: string;
|
|
49
|
+
index?: number;
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
export function MermaidRenderer({
|
|
52
53
|
definition,
|
|
53
54
|
className,
|
|
55
|
+
index,
|
|
54
56
|
}: MermaidRendererProps) {
|
|
55
57
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
56
58
|
const [svg, setSvg] = useState<string>("");
|
|
@@ -98,6 +100,7 @@ export function MermaidRenderer({
|
|
|
98
100
|
if (error) {
|
|
99
101
|
return (
|
|
100
102
|
<div
|
|
103
|
+
data-mermaid-index={index}
|
|
101
104
|
className={`flex items-center justify-center p-4 text-xs text-red-400/70 ${className || ""}`}
|
|
102
105
|
>
|
|
103
106
|
<pre className="whitespace-pre-wrap">{error}</pre>
|
|
@@ -105,11 +108,19 @@ export function MermaidRenderer({
|
|
|
105
108
|
);
|
|
106
109
|
}
|
|
107
110
|
|
|
108
|
-
if (!svg)
|
|
111
|
+
if (!svg) {
|
|
112
|
+
// Mermaid's import + render is async, so this placeholder is the only
|
|
113
|
+
// thing in the DOM until it resolves. Without it, an edit to another
|
|
114
|
+
// element on the same slide made while the diagram is still loading
|
|
115
|
+
// would see zero `[data-mermaid-index]` nodes when serializing the
|
|
116
|
+
// slide, and silently drop the diagram from the saved content.
|
|
117
|
+
return <div data-mermaid-index={index} className={className} />;
|
|
118
|
+
}
|
|
109
119
|
|
|
110
120
|
return (
|
|
111
121
|
<div
|
|
112
122
|
ref={containerRef}
|
|
123
|
+
data-mermaid-index={index}
|
|
113
124
|
className={`flex items-center justify-center [&_svg]:max-w-full [&_svg]:max-h-full ${className || ""}`}
|
|
114
125
|
dangerouslySetInnerHTML={{ __html: svg }}
|
|
115
126
|
/>
|
|
@@ -14,6 +14,7 @@ import rehypeRaw from "rehype-raw";
|
|
|
14
14
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
15
15
|
import type { Slide } from "@/context/DeckContext";
|
|
16
16
|
import { type AspectRatio, getAspectRatioDims } from "@/lib/aspect-ratios";
|
|
17
|
+
import { extractMermaidBlocks } from "@/lib/mermaid-blocks";
|
|
17
18
|
import {
|
|
18
19
|
sanitizeCssValue,
|
|
19
20
|
sanitizeSlideHtml,
|
|
@@ -37,6 +38,8 @@ interface SlideRendererProps {
|
|
|
37
38
|
* The renderer no longer shrinks slides for vertical overflow — instead the
|
|
38
39
|
* editor surfaces this so the agent can rewrite the slide to fit. */
|
|
39
40
|
onOverflowChange?: (info: SlideOverflowInfo) => void;
|
|
41
|
+
/** Fires after AutoFit has applied its final transform for this render. */
|
|
42
|
+
onAutofitSettled?: () => void;
|
|
40
43
|
}
|
|
41
44
|
|
|
42
45
|
export const layoutClasses: Record<string, string> = {
|
|
@@ -311,9 +314,12 @@ function useSlideAutofit(
|
|
|
311
314
|
canvasHeight: number,
|
|
312
315
|
fitKey: string,
|
|
313
316
|
onOverflowChange?: (info: SlideOverflowInfo) => void,
|
|
317
|
+
onAutofitSettled?: () => void,
|
|
314
318
|
) {
|
|
315
319
|
const overflowCallbackRef = useRef(onOverflowChange);
|
|
316
320
|
overflowCallbackRef.current = onOverflowChange;
|
|
321
|
+
const autofitSettledRef = useRef(onAutofitSettled);
|
|
322
|
+
autofitSettledRef.current = onAutofitSettled;
|
|
317
323
|
|
|
318
324
|
useIsomorphicLayoutEffect(() => {
|
|
319
325
|
const root = ref.current;
|
|
@@ -395,6 +401,7 @@ function useSlideAutofit(
|
|
|
395
401
|
viewportHeight: 0,
|
|
396
402
|
},
|
|
397
403
|
);
|
|
404
|
+
autofitSettledRef.current?.();
|
|
398
405
|
}
|
|
399
406
|
};
|
|
400
407
|
|
|
@@ -437,6 +444,7 @@ function AutoFitContent({
|
|
|
437
444
|
className = "",
|
|
438
445
|
children,
|
|
439
446
|
onOverflowChange,
|
|
447
|
+
onAutofitSettled,
|
|
440
448
|
}: {
|
|
441
449
|
canvasWidth: number;
|
|
442
450
|
canvasHeight: number;
|
|
@@ -444,9 +452,17 @@ function AutoFitContent({
|
|
|
444
452
|
className?: string;
|
|
445
453
|
children: ReactNode;
|
|
446
454
|
onOverflowChange?: (info: SlideOverflowInfo) => void;
|
|
455
|
+
onAutofitSettled?: () => void;
|
|
447
456
|
}) {
|
|
448
457
|
const ref = useRef<HTMLDivElement>(null);
|
|
449
|
-
useSlideAutofit(
|
|
458
|
+
useSlideAutofit(
|
|
459
|
+
ref,
|
|
460
|
+
canvasWidth,
|
|
461
|
+
canvasHeight,
|
|
462
|
+
fitKey,
|
|
463
|
+
onOverflowChange,
|
|
464
|
+
onAutofitSettled,
|
|
465
|
+
);
|
|
450
466
|
|
|
451
467
|
return (
|
|
452
468
|
<div
|
|
@@ -469,18 +485,9 @@ function BlankSlideContent({ content }: { content: string }) {
|
|
|
469
485
|
// includes the per-block `contentEditable="true"` set by SlideEditor's
|
|
470
486
|
// double-click-to-edit flow, which made inline text editing appear to do nothing.
|
|
471
487
|
const { mermaidBlocks, htmlWithPlaceholders, dangerousHtml } = useMemo(() => {
|
|
472
|
-
// Extract mermaid blocks BEFORE sanitization
|
|
473
|
-
//
|
|
474
|
-
|
|
475
|
-
// `A --> B` and breaks the mermaid parser.
|
|
476
|
-
const blocks: string[] = [];
|
|
477
|
-
const contentWithPlaceholders = content.replace(
|
|
478
|
-
/<div\s+class="mermaid"[^>]*>([\s\S]*?)<\/div>/gi,
|
|
479
|
-
(_, definition) => {
|
|
480
|
-
blocks.push(String(definition).trim());
|
|
481
|
-
return `<div data-mermaid-index="${blocks.length - 1}"></div>`;
|
|
482
|
-
},
|
|
483
|
-
);
|
|
488
|
+
// Extract mermaid blocks BEFORE sanitization — see mermaid-blocks.ts for
|
|
489
|
+
// why (sanitizer HTML-escaping breaks the mermaid parser).
|
|
490
|
+
const { blocks, contentWithPlaceholders } = extractMermaidBlocks(content);
|
|
484
491
|
|
|
485
492
|
// Apply white filter to all logo images (brandfetch, logo.dev, etc.) for dark backgrounds
|
|
486
493
|
const processed = sanitizeSlideHtml(
|
|
@@ -547,6 +554,7 @@ function MermaidHtmlContent({
|
|
|
547
554
|
<MermaidRenderer
|
|
548
555
|
key={`mermaid-${i}`}
|
|
549
556
|
definition={mermaidBlocks[idx]}
|
|
557
|
+
index={idx}
|
|
550
558
|
className="my-4 w-full"
|
|
551
559
|
/>
|
|
552
560
|
);
|
|
@@ -564,11 +572,13 @@ export function SlideInner({
|
|
|
564
572
|
designSystem,
|
|
565
573
|
aspectRatio,
|
|
566
574
|
onOverflowChange,
|
|
575
|
+
onAutofitSettled,
|
|
567
576
|
}: {
|
|
568
577
|
slide: Slide;
|
|
569
578
|
designSystem?: DesignSystemData;
|
|
570
579
|
aspectRatio?: AspectRatio;
|
|
571
580
|
onOverflowChange?: (info: SlideOverflowInfo) => void;
|
|
581
|
+
onAutofitSettled?: () => void;
|
|
572
582
|
}) {
|
|
573
583
|
const t = useT();
|
|
574
584
|
const dims = getAspectRatioDims(aspectRatio);
|
|
@@ -651,6 +661,7 @@ export function SlideInner({
|
|
|
651
661
|
fitKey={left}
|
|
652
662
|
className="slide-content text-white/90"
|
|
653
663
|
onOverflowChange={onOverflowChange}
|
|
664
|
+
onAutofitSettled={onAutofitSettled}
|
|
654
665
|
>
|
|
655
666
|
<ReactMarkdown
|
|
656
667
|
components={markdownComponents}
|
|
@@ -664,6 +675,7 @@ export function SlideInner({
|
|
|
664
675
|
canvasHeight={dims.height}
|
|
665
676
|
fitKey={right}
|
|
666
677
|
className="slide-content text-white/90"
|
|
678
|
+
onAutofitSettled={onAutofitSettled}
|
|
667
679
|
>
|
|
668
680
|
<ReactMarkdown
|
|
669
681
|
components={markdownComponents}
|
|
@@ -689,6 +701,7 @@ export function SlideInner({
|
|
|
689
701
|
fitKey={content}
|
|
690
702
|
className="h-full w-full"
|
|
691
703
|
onOverflowChange={onOverflowChange}
|
|
704
|
+
onAutofitSettled={onAutofitSettled}
|
|
692
705
|
>
|
|
693
706
|
<BlankSlideContent content={content} />
|
|
694
707
|
</AutoFitContent>
|
|
@@ -714,6 +727,7 @@ export function SlideInner({
|
|
|
714
727
|
fitKey={content}
|
|
715
728
|
className="slide-content text-white/90 w-full"
|
|
716
729
|
onOverflowChange={onOverflowChange}
|
|
730
|
+
onAutofitSettled={onAutofitSettled}
|
|
717
731
|
>
|
|
718
732
|
<ReactMarkdown
|
|
719
733
|
components={markdownComponents}
|
|
@@ -733,6 +747,7 @@ export default function SlideRenderer({
|
|
|
733
747
|
designSystem,
|
|
734
748
|
aspectRatio,
|
|
735
749
|
onOverflowChange,
|
|
750
|
+
onAutofitSettled,
|
|
736
751
|
}: SlideRendererProps) {
|
|
737
752
|
const dims = getAspectRatioDims(aspectRatio);
|
|
738
753
|
|
|
@@ -753,6 +768,7 @@ export default function SlideRenderer({
|
|
|
753
768
|
designSystem={designSystem}
|
|
754
769
|
aspectRatio={aspectRatio}
|
|
755
770
|
onOverflowChange={onOverflowChange}
|
|
771
|
+
onAutofitSettled={onAutofitSettled}
|
|
756
772
|
/>
|
|
757
773
|
</div>
|
|
758
774
|
<ScaleHelper
|
|
@@ -783,6 +799,7 @@ export default function SlideRenderer({
|
|
|
783
799
|
designSystem={designSystem}
|
|
784
800
|
aspectRatio={aspectRatio}
|
|
785
801
|
onOverflowChange={onOverflowChange}
|
|
802
|
+
onAutofitSettled={onAutofitSettled}
|
|
786
803
|
/>
|
|
787
804
|
</div>
|
|
788
805
|
<ScaleHelper targetWidth={dims.width} />
|