@agent-native/core-corpus 0.214.0 → 0.216.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/analytics/CHANGELOG.md +1 -0
- package/corpus/templates/analytics/changelog/2026-10-21-session-replay-quotas-count-the-compressed-size-analytics-st.md +6 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +40 -9
- package/corpus/templates/assets/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/brain/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/calendar/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/clips/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/community/qr/package.json +1 -1
- package/corpus/templates/content/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/content/.agents/skills/content-product-development/references/verification.md +36 -0
- package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +10 -0
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +11 -0
- package/corpus/templates/content/.agents/skills/notion-integration/SKILL.md +4 -2
- package/corpus/templates/content/CHANGELOG.md +46 -0
- package/corpus/templates/content/acceptance/_writers.ts +604 -0
- package/corpus/templates/content/acceptance/generate-action-registry.ts +10 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/create-document.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/duplicate-page.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/edit-document-find-and-replace-without-a-revision.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/edit-document-find-and-replace.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/edit-document-initializecontent.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/import-content.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/local-files-import-content-source-existing-page.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/local-files-import-content-source-new-page.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/local-files-sync-local-folder-source-changed-file.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/local-files-sync-local-folder-source-new-file.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/restore-document-version.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/set-document-property-primary-blocks-field.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/set-image-alt-text.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/undo-content-import.json +75 -0
- package/corpus/templates/content/acceptance/golden/gate-off-stored-bytes/update-document-browser-full-rewrite.json +75 -0
- package/corpus/templates/content/acceptance/known-loss.ts +69 -0
- package/corpus/templates/content/acceptance/round-trip-corpus.ts +1397 -0
- package/corpus/templates/content/actions/_blocks-field-identity.ts +35 -1
- package/corpus/templates/content/actions/_content-database-lifecycle.ts +11 -11
- package/corpus/templates/content/actions/_content-database-personal-view.ts +2 -0
- package/corpus/templates/content/actions/_content-favorites.ts +37 -0
- package/corpus/templates/content/actions/_database-membership-lock.ts +39 -8
- package/corpus/templates/content/actions/_database-navigation.ts +19 -21
- package/corpus/templates/content/actions/_database-row-batch.ts +41 -18
- package/corpus/templates/content/actions/_database-row-mutation.ts +17 -28
- package/corpus/templates/content/actions/_database-source-utils.ts +18 -1
- package/corpus/templates/content/actions/_database-utils.ts +3 -0
- package/corpus/templates/content/actions/_database-view-setup.ts +16 -0
- package/corpus/templates/content/actions/_document-edit-mutation.ts +33 -32
- package/corpus/templates/content/actions/_document-flush.ts +593 -171
- package/corpus/templates/content/actions/_document-save-locks.ts +54 -0
- package/corpus/templates/content/actions/_document-save-row.ts +133 -0
- package/corpus/templates/content/actions/_github-source.ts +18 -8
- package/corpus/templates/content/actions/_move-page-to-space.ts +189 -25
- package/corpus/templates/content/actions/_nfm-syntax.ts +2 -0
- package/corpus/templates/content/actions/_row-lock-order.ts +115 -0
- package/corpus/templates/content/actions/create-content-database.ts +11 -0
- package/corpus/templates/content/actions/create-document.ts +13 -1
- package/corpus/templates/content/actions/delete-content-database.ts +17 -14
- package/corpus/templates/content/actions/delete-document-property.ts +5 -0
- package/corpus/templates/content/actions/delete-document.ts +270 -97
- package/corpus/templates/content/actions/edit-document.ts +18 -5
- package/corpus/templates/content/actions/export-document.ts +3 -0
- package/corpus/templates/content/actions/get-blocks-field-word-count.ts +22 -5
- package/corpus/templates/content/actions/import-content-source.ts +170 -54
- package/corpus/templates/content/actions/move-document.ts +191 -73
- package/corpus/templates/content/actions/pull-document.ts +8 -2
- package/corpus/templates/content/actions/remove-database-items.ts +23 -4
- package/corpus/templates/content/actions/restore-content-database.ts +76 -55
- package/corpus/templates/content/actions/restore-document-version.ts +19 -35
- package/corpus/templates/content/actions/restore-document.ts +65 -53
- package/corpus/templates/content/actions/rollback-created-slash-document.ts +11 -16
- package/corpus/templates/content/actions/set-document-property.ts +15 -1
- package/corpus/templates/content/actions/share-local-file-document.ts +18 -14
- package/corpus/templates/content/actions/suggest-document-edit.ts +2 -3
- package/corpus/templates/content/actions/sync-local-folder-source.ts +35 -1
- package/corpus/templates/content/actions/undo-content-import.ts +16 -12
- package/corpus/templates/content/actions/update-content-database-view.ts +2 -0
- package/corpus/templates/content/actions/update-document.ts +19 -14
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +1 -6
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +49 -3
- package/corpus/templates/content/app/components/editor/ContentImportDialog.tsx +2 -0
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +53 -11
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +608 -353
- package/corpus/templates/content/app/components/editor/StaticDocumentBody.tsx +765 -0
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +233 -80
- package/corpus/templates/content/app/components/editor/blockFieldSaveController.ts +32 -3
- package/corpus/templates/content/app/components/editor/blockFieldSaveRegistry.ts +88 -23
- package/corpus/templates/content/app/components/editor/comment-anchors.ts +19 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +205 -71
- package/corpus/templates/content/app/components/editor/document-flush-participant.ts +253 -0
- package/corpus/templates/content/app/components/editor/editor-transaction-meta.ts +28 -0
- package/corpus/templates/content/app/components/editor/extensions/AudioBlock.tsx +2 -1
- package/corpus/templates/content/app/components/editor/extensions/ImageBlock.tsx +27 -6
- package/corpus/templates/content/app/components/editor/extensions/LocalMdxComponentNode.tsx +0 -1
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +4 -4
- package/corpus/templates/content/app/components/editor/extensions/SuggestionHighlight.ts +24 -2
- package/corpus/templates/content/app/components/editor/extensions/VideoBlock.tsx +25 -6
- package/corpus/templates/content/app/components/editor/pending-document-persistence.ts +59 -1
- package/corpus/templates/content/app/components/editor/stored-body-images.ts +27 -0
- package/corpus/templates/content/app/components/editor/suggestions/presentation-rebase.ts +17 -0
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +11 -4
- package/corpus/templates/content/app/components/trash/TrashBrowser.tsx +4 -1
- package/corpus/templates/content/app/global.css +21 -0
- package/corpus/templates/content/app/hooks/use-content-trash.ts +8 -0
- package/corpus/templates/content/app/import-messages.ts +25 -0
- package/corpus/templates/content/app/trash-messages.ts +16 -0
- package/corpus/templates/content/changelog/2026-10-16-a-page-open-in-a-tab-that-shows-it-s-in-the-trash-reopens-wi.md +6 -0
- package/corpus/templates/content/changelog/2026-10-16-a-page-restored-from-trash-returns-to-its-place-in-its-colle.md +6 -0
- package/corpus/templates/content/changelog/2026-10-16-agent-written-markdown-keeps-nested-lists-indented-with-spac.md +6 -0
- package/corpus/templates/content/changelog/2026-10-16-opening-a-page-you-can-edit-no-longer-rebuilds-its-editor-on.md +6 -0
- package/corpus/templates/content/changelog/2026-10-16-pages-moved-or-imported-at-the-same-time-can-no-longer-end-u.md +6 -0
- package/corpus/templates/content/changelog/2026-10-16-re-importing-a-markdown-export-of-a-page-no-longer-reports-t.md +6 -0
- package/corpus/templates/content/changelog/2026-10-16-saving-a-page-or-restoring-one-of-its-versions-no-longer-fai.md +6 -0
- package/corpus/templates/content/changelog/2026-10-17-agents-reading-a-page-you-have-open-no-longer-wait-or-fail-w.md +6 -0
- package/corpus/templates/content/changelog/2026-10-19-fresh-document-reads-require-confirmation-from-every-open-ed.md +6 -0
- package/corpus/templates/content/changelog/2026-10-20-html-table-cells-preserve-a-trailing-backslash-when-opening-.md +6 -0
- package/corpus/templates/content/changelog/2026-10-20-preserve-empty-paragraph-colors-and-refuse-unsupported-inlin.md +6 -0
- package/corpus/templates/content/changelog/2026-10-20-the-advanced-filter-and-each-filter-group-inside-it-have-the.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-blocks-fields-keep-unconfirmed-saves-visible-and-agent-reads.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-preserve-compact-table-row-groups-and-report-invalid-block-colors.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-suggested-edits-show-an-agent-s-whole-reason-open-a-group-to.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-suggestions-keep-refusing-unmatched-emphasis-in-stored-markd.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-accept-remaining-and-reject-remaining-show-the-result-for-ev.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-accepting-a-group-of-suggested-edits-saves-faster-and-adds-o.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-agents-read-saved-page-text-after-failed-icon-change.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-changes-made-from-a-menu-or-popover-such-as-an-image-s-alt-t.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-text-an-agent-writes-inside-a-callout-column-or-synced-block.md +6 -0
- package/corpus/templates/content/e2e/auth-files.ts +28 -0
- package/corpus/templates/content/e2e/convergence-summary.ts +84 -29
- package/corpus/templates/content/e2e/gate-arm.ts +15 -0
- package/corpus/templates/content/e2e/global-setup.ts +43 -75
- package/corpus/templates/content/e2e/global-teardown.ts +34 -0
- package/corpus/templates/content/e2e/helpers.ts +598 -92
- package/corpus/templates/content/e2e/live-body-gate.ts +188 -0
- package/corpus/templates/content/e2e/playwright.config.ts +12 -3
- package/corpus/templates/content/e2e/server-identity.ts +47 -0
- package/corpus/templates/content/e2e/stored-form/collab-blocks.ts +123 -0
- package/corpus/templates/content/package.json +1 -1
- package/corpus/templates/content/scripts/_stored-form-census-kinds.ts +30 -2
- package/corpus/templates/content/scripts/historical-icon-apply.ts +9 -1
- package/corpus/templates/content/scripts/trace-startup.mjs +460 -133
- package/corpus/templates/content/server/db/exec.ts +58 -0
- package/corpus/templates/content/server/db/schema.ts +1 -0
- package/corpus/templates/content/server/lib/content-trash-purge.ts +208 -144
- package/corpus/templates/content/server/lib/document-metadata-updated-at.ts +43 -1
- package/corpus/templates/content/server/lib/document-revision.ts +23 -0
- package/corpus/templates/content/server/lib/live-body-writer.ts +199 -0
- package/corpus/templates/content/server/lib/notion-sync.ts +63 -29
- package/corpus/templates/content/server/lib/notion.ts +5 -5
- package/corpus/templates/content/server/lib/suggested-edits.ts +357 -230
- package/corpus/templates/content/server/plugins/db.ts +5 -0
- package/corpus/templates/content/server/routes/api/documents/[id]/move.patch.ts +50 -168
- package/corpus/templates/content/shared/api.ts +2 -0
- package/corpus/templates/content/shared/blocks-fields-manifest.ts +106 -0
- package/corpus/templates/content/shared/database-query.ts +192 -30
- package/corpus/templates/content/shared/document-export.ts +12 -14
- package/corpus/templates/content/shared/document-flush-protocol.ts +88 -0
- package/corpus/templates/content/shared/editor-save-state.ts +97 -0
- package/corpus/templates/content/shared/feature-flags.ts +10 -0
- package/corpus/templates/content/shared/import/markdown.ts +91 -7
- package/corpus/templates/content/shared/import/types.ts +2 -0
- package/corpus/templates/content/shared/inline-math.ts +6 -4
- package/corpus/templates/content/shared/nfm-fidelity.ts +247 -0
- package/corpus/templates/content/shared/nfm.ts +1933 -340
- package/corpus/templates/content/shared/suggestion-diff.ts +13 -0
- package/corpus/templates/content/shared/suggestion-formatting.ts +143 -20
- package/corpus/templates/content/shared/suggestion-text.ts +39 -0
- package/corpus/templates/content/vitest.config.ts +10 -0
- package/corpus/templates/crm/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/design/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/design/.agents/skills/native-effects/SKILL.md +9 -2
- package/corpus/templates/design/.generated/bridge/shader-fill-preview.generated.ts +3 -249
- package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +5 -88
- package/corpus/templates/design/AGENTS.md +1 -3
- package/corpus/templates/design/CHANGELOG.md +32 -0
- package/corpus/templates/design/CODE_NATIVE_DESIGN_STUDIO_IMPLEMENTATION_PLAN.md +1 -6
- package/corpus/templates/design/DESIGN-STUDIO-PLAN.md +5 -7
- package/corpus/templates/design/actions/_native-local-export-server.ts +44 -31
- package/corpus/templates/design/actions/_native-render-contexts.ts +76 -21
- package/corpus/templates/design/actions/claim-native-local-export.ts +5 -0
- package/corpus/templates/design/actions/finish-native-local-export.ts +13 -2
- package/corpus/templates/design/actions/get-native-shader-approvals.ts +35 -0
- package/corpus/templates/design/actions/get-shader.ts +134 -219
- package/corpus/templates/design/actions/list-design-extensions.ts +3 -58
- package/corpus/templates/design/actions/request-native-local-export.ts +32 -6
- package/corpus/templates/design/actions/run-design-extension-action.ts +0 -29
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +131 -108
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +0 -218
- package/corpus/templates/design/app/components/design/DesignThumbnail.tsx +59 -3
- package/corpus/templates/design/app/components/design/EditPanel.tsx +35 -47
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +242 -62
- package/corpus/templates/design/app/components/design/NativePreviewErrorBoundary.tsx +53 -0
- package/corpus/templates/design/app/components/design/bridge/codegen.ts +18 -3
- package/corpus/templates/design/app/components/design/bridge/native-composition-clock.ts +5 -4
- package/corpus/templates/design/app/components/design/bridge/native-dom.ts +37 -0
- package/corpus/templates/design/app/components/design/bridge/native-intrinsic-image.ts +2 -1
- package/corpus/templates/design/app/components/design/bridge/native-mesh-grid.ts +90 -0
- package/corpus/templates/design/app/components/design/bridge/native-opaque-public-asset.ts +363 -0
- package/corpus/templates/design/app/components/design/bridge/native-opaque-worker-lease.ts +179 -0
- package/corpus/templates/design/app/components/design/bridge/native-preview-geometry.ts +132 -7
- package/corpus/templates/design/app/components/design/bridge/native-preview-policy.ts +4 -0
- package/corpus/templates/design/app/components/design/bridge/native-preview-viewport-transport.ts +378 -0
- package/corpus/templates/design/app/components/design/bridge/native-scene-body-transform.ts +62 -0
- package/corpus/templates/design/app/components/design/bridge/native-scene-presentation-element.ts +10 -0
- package/corpus/templates/design/app/components/design/bridge/native-shader-runtime.bridge.ts +646 -167
- package/corpus/templates/design/app/components/design/bridge/native-source-provider.ts +246 -192
- package/corpus/templates/design/app/components/design/bridge/native-stateful-resource.ts +2 -2
- package/corpus/templates/design/app/components/design/bridge/native-stateless-compute.ts +5 -2
- package/corpus/templates/design/app/components/design/bridge/native-svg-source.ts +11 -1
- package/corpus/templates/design/app/components/design/bridge/native-worker-broker.ts +6 -0
- package/corpus/templates/design/app/components/design/bridge/native-worker-entry.ts +761 -303
- package/corpus/templates/design/app/components/design/bridge/native-worker-fill.ts +16 -6
- package/corpus/templates/design/app/components/design/bridge/native-worker-gpu.ts +854 -91
- package/corpus/templates/design/app/components/design/bridge/native-worker-host.ts +15 -1
- package/corpus/templates/design/app/components/design/bridge/native-worker-input-assets.ts +200 -0
- package/corpus/templates/design/app/components/design/bridge/native-worker-protocol.ts +40 -1
- package/corpus/templates/design/app/components/design/bridge/native-worker-scene-host.ts +425 -126
- package/corpus/templates/design/app/components/design/bridge/native-worker-source-snapshot.ts +21 -0
- package/corpus/templates/design/app/components/design/bridge/shader-fill-preview.bridge.ts +5 -371
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +4 -146
- package/corpus/templates/design/app/components/design/design-canvas/interact-document.ts +5 -9
- package/corpus/templates/design/app/components/design/design-canvas/native-preview-surface.ts +150 -0
- package/corpus/templates/design/app/components/design/design-canvas/native-public-asset-preview.ts +409 -0
- package/corpus/templates/design/app/components/design/design-canvas/native-public-worker-preview.ts +1086 -0
- package/corpus/templates/design/app/components/design/design-canvas/private-replay-screenshot-preview.ts +2 -2
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +15 -26
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +74 -67
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +7 -19
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +39 -30
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +4 -0
- package/corpus/templates/design/app/components/design/inspector/NativeShaderColorControls.tsx +3 -7
- package/corpus/templates/design/app/components/design/inspector/NativeShaderPaintControls.tsx +12 -5
- package/corpus/templates/design/app/components/design/inspector/NativeShaderPanel.tsx +705 -190
- package/corpus/templates/design/app/components/design/inspector/fill-field-reading.ts +1 -2
- package/corpus/templates/design/app/components/design/inspector/index.ts +0 -6
- package/corpus/templates/design/app/components/design/inspector/native-catalog-display.ts +26 -5
- package/corpus/templates/design/app/components/design/inspector/native-shader-catalog-fixture.ts +42 -0
- package/corpus/templates/design/app/components/design/inspector/native-shader-catalog-preview.ts +51 -33
- package/corpus/templates/design/app/components/design/inspector/native-shader-paint.ts +1 -0
- package/corpus/templates/design/app/components/design/inspector/native-shader-property-draft.ts +89 -23
- package/corpus/templates/design/app/components/design/inspector/saved-glsl-shader.tsx +243 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +54 -5
- package/corpus/templates/design/app/components/design/shader-source-coordination.ts +66 -0
- package/corpus/templates/design/app/components/design/use-native-shader-approvals.ts +36 -8
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +60 -3
- package/corpus/templates/design/app/i18n/en-US.ts +78 -2
- package/corpus/templates/design/app/pages/Present.tsx +36 -1
- package/corpus/templates/design/app/pages/design-editor/commands/apply-file-content-update.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/apply-local-content-update.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +2 -3
- package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/layer-move-to-screen.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/paste-selection.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/paste-svg-layer.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/prepare-content-history-replay.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/redo.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/render-png-blob.ts +84 -41
- package/corpus/templates/design/app/pages/design-editor/commands/shader-source-edit.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/commands/undo.ts +1 -1
- package/corpus/templates/design/app/pages/design-editor/design-editor-view.tsx +0 -2
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-content-and-components.ts +4 -33
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-export-and-handoff.ts +2 -2
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-history.ts +0 -11
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-layer-models.ts +2 -55
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-screen-rendering.tsx +0 -3
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-selection-and-styles.ts +0 -24
- package/corpus/templates/design/app/pages/design-editor/text-edit-utils.ts +0 -16
- package/corpus/templates/design/app/pages/design-editor/use-native-local-export-requests.ts +70 -11
- package/corpus/templates/design/app/pages/design-editor/view/single-screen-canvas.tsx +0 -2
- package/corpus/templates/design/changelog/2026-10-20-folded-mesh-adds-an-animated-sculpted-fill-with-editable-col.md +6 -0
- package/corpus/templates/design/changelog/2026-10-20-read-only-design-views-render-native-shader-previews-in-nest.md +6 -0
- package/corpus/templates/design/changelog/2026-10-20-selected-screens-with-shader-effects-can-be-exported-togethe.md +6 -0
- package/corpus/templates/design/changelog/2026-10-20-shader-previews-reuse-validated-scene-data-while-panning-inc.md +6 -0
- package/corpus/templates/design/changelog/2026-10-20-shader-previews-stay-aligned-while-you-zoom.md +6 -0
- package/corpus/templates/design/changelog/2026-10-20-signed-out-sessions-no-longer-watch-for-private-png-export-r.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-effect-thumbnails-show-richer-previews.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-native-effects-render-across-previews.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-native-shader-previews-use-less-gpu-memory-when-many-mesh-ef.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-opening-design-no-longer-shows-png-export-errors-when-no-exp.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-pulsing-border-controls-grouped.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-pulsing-border-follows-element-outlines.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-remove-obsolete-shader-fills.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-shader-previews-recover-from-temporary-gpu-and-image-failure.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-shader-fills-and-effects-render-correctly-on-canvas-elements.md +6 -0
- package/corpus/templates/design/package.json +0 -1
- package/corpus/templates/design/playwright.config.ts +1 -1
- package/corpus/templates/design/scripts/runtime-budget-zoom.ts +9 -21
- package/corpus/templates/design/scripts/runtime-budget.ts +10 -24
- package/corpus/templates/design/server/plugins/agent-chat.ts +0 -2
- package/corpus/templates/design/shared/effect-graph.ts +46 -1
- package/corpus/templates/design/shared/generation-output-receipt.ts +0 -1
- package/corpus/templates/design/shared/native-effect-animation-capability.ts +6 -0
- package/corpus/templates/design/shared/native-effect-folded-mesh-v1.ts +268 -0
- package/corpus/templates/design/shared/native-effect-folded-mesh-v2.ts +310 -0
- package/corpus/templates/design/shared/native-effect-folded-mesh.ts +489 -0
- package/corpus/templates/design/shared/native-effect-gallery-additions.ts +2 -2
- package/corpus/templates/design/shared/native-effect-paint.ts +8 -0
- package/corpus/templates/design/shared/native-effect-parameter-constraints.ts +8 -1
- package/corpus/templates/design/shared/native-effect-presets.ts +18 -1
- package/corpus/templates/design/shared/native-effect-property-presentation.ts +81 -0
- package/corpus/templates/design/shared/native-effect-pulsing-border-v3.ts +281 -0
- package/corpus/templates/design/shared/native-effect-pulsing-border-v4.ts +284 -0
- package/corpus/templates/design/shared/native-effect-pulsing-border.ts +300 -0
- package/corpus/templates/design/shared/native-effect-trust.ts +6 -0
- package/corpus/templates/design/shared/native-effect-wgsl.ts +12 -0
- package/corpus/templates/design/shared/native-effects.ts +528 -15
- package/corpus/templates/design/shared/native-input-resources.ts +36 -0
- package/corpus/templates/design/shared/native-local-export.ts +14 -0
- package/corpus/templates/design/shared/native-parameter-animation.ts +1 -0
- package/corpus/templates/design/shared/native-pointer-input.ts +9 -11
- package/corpus/templates/design/shared/shader-fills.ts +0 -513
- package/corpus/templates/design/vitest.setup.ts +7 -1
- package/corpus/templates/dispatch/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +20 -18
- package/corpus/templates/factory/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
- package/corpus/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
- package/corpus/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
- package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +20 -18
- package/corpus/templates/forms/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/mail/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/plan/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/slides/.agents/skills/actions/references/action-fields.md +1 -1
- package/corpus/templates/slides-2/.agents/skills/actions/SKILL.md +199 -0
- package/corpus/templates/slides-2/.agents/skills/actions/references/action-fields.md +145 -0
- package/corpus/templates/slides-2/.agents/skills/actions/references/examples.md +96 -0
- package/corpus/templates/slides-2/.agents/skills/actions/references/provider-apis.md +95 -0
- package/corpus/templates/slides-2/.agents/skills/adding-a-feature/SKILL.md +235 -0
- package/corpus/templates/slides-2/.agents/skills/agent-native-docs/SKILL.md +161 -0
- package/corpus/templates/slides-2/.agents/skills/agent-native-toolkit/SKILL.md +314 -0
- package/corpus/templates/slides-2/.agents/skills/analytics-data-for-decks/SKILL.md +44 -0
- package/corpus/templates/slides-2/.agents/skills/apply-slide-comments/SKILL.md +63 -0
- package/corpus/templates/slides-2/.agents/skills/client-side-routing/SKILL.md +87 -0
- package/corpus/templates/slides-2/.agents/skills/context-awareness/SKILL.md +282 -0
- package/corpus/templates/slides-2/.agents/skills/create-deck/SKILL.md +263 -0
- package/corpus/templates/slides-2/.agents/skills/create-deck/references/reference-inputs.md +72 -0
- package/corpus/templates/slides-2/.agents/skills/create-deck/references/slide-templates.md +93 -0
- package/corpus/templates/slides-2/.agents/skills/create-deck/references/source-material.md +16 -0
- package/corpus/templates/slides-2/.agents/skills/creative-context/SKILL.md +134 -0
- package/corpus/templates/slides-2/.agents/skills/customizing-agent-native/SKILL.md +219 -0
- package/corpus/templates/slides-2/.agents/skills/deck-management/SKILL.md +182 -0
- package/corpus/templates/slides-2/.agents/skills/delegate-to-agent/SKILL.md +62 -0
- package/corpus/templates/slides-2/.agents/skills/design-systems/SKILL.md +233 -0
- package/corpus/templates/slides-2/.agents/skills/external-agents/SKILL.md +549 -0
- package/corpus/templates/slides-2/.agents/skills/external-agents/references/mcp-apps-embedding.md +169 -0
- package/corpus/templates/slides-2/.agents/skills/frontend-design/SKILL.md +102 -0
- package/corpus/templates/slides-2/.agents/skills/frontend-design/references/visual-direction.md +102 -0
- package/corpus/templates/slides-2/.agents/skills/image-generation-via-a2a/SKILL.md +134 -0
- package/corpus/templates/slides-2/.agents/skills/performance/SKILL.md +79 -0
- package/corpus/templates/slides-2/.agents/skills/portability/SKILL.md +108 -0
- package/corpus/templates/slides-2/.agents/skills/real-time-sync/SKILL.md +146 -0
- package/corpus/templates/slides-2/.agents/skills/reliable-mutations/SKILL.md +72 -0
- package/corpus/templates/slides-2/.agents/skills/secrets/SKILL.md +82 -0
- package/corpus/templates/slides-2/.agents/skills/security/SKILL.md +80 -0
- package/corpus/templates/slides-2/.agents/skills/self-modifying-code/SKILL.md +123 -0
- package/corpus/templates/slides-2/.agents/skills/shadcn-ui/SKILL.md +71 -0
- package/corpus/templates/slides-2/.agents/skills/sharing/SKILL.md +286 -0
- package/corpus/templates/slides-2/.agents/skills/slide-design/SKILL.md +144 -0
- package/corpus/templates/slides-2/.agents/skills/slide-editing/SKILL.md +284 -0
- package/corpus/templates/slides-2/.agents/skills/slide-editing/references/animations.md +33 -0
- package/corpus/templates/slides-2/.agents/skills/slide-editing/references/freeform-objects.md +22 -0
- package/corpus/templates/slides-2/.agents/skills/slide-editing/references/restyling.md +69 -0
- package/corpus/templates/slides-2/.agents/skills/slide-editing/references/transitions.md +26 -0
- package/corpus/templates/slides-2/.agents/skills/slide-editing/references/video.md +45 -0
- package/corpus/templates/slides-2/.agents/skills/slide-images/SKILL.md +136 -0
- package/corpus/templates/slides-2/.agents/skills/storing-data/SKILL.md +234 -0
- package/corpus/templates/slides-2/.agents/skills/turn-into-skill/SKILL.md +112 -0
- package/corpus/templates/slides-2/.agents/skills/turn-into-skill/agents/openai.yaml +4 -0
- package/corpus/templates/slides-2/.agents/skills/workspace-conventions/SKILL.md +103 -0
- package/corpus/templates/slides-2/.builder/rules/deploy-app.mdc +22 -0
- package/corpus/templates/slides-2/.builder/rules/organize-ui.mdc +9 -0
- package/corpus/templates/slides-2/.dockerignore +61 -0
- package/corpus/templates/slides-2/.env.example +23 -0
- package/corpus/templates/slides-2/.ignore +3 -0
- package/corpus/templates/slides-2/.mcp.json +8 -0
- package/corpus/templates/slides-2/.oxfmtrc.json +8 -0
- package/corpus/templates/slides-2/AGENTS.md +66 -0
- package/corpus/templates/slides-2/CHANGELOG.md +76 -0
- package/corpus/templates/slides-2/DEVELOPING.md +157 -0
- package/corpus/templates/slides-2/README.md +58 -0
- package/corpus/templates/slides-2/THIRD_PARTY_NOTICES.md +33 -0
- package/corpus/templates/slides-2/_gitignore +38 -0
- package/corpus/templates/slides-2/actions/_agent-presence.ts +29 -0
- package/corpus/templates/slides-2/actions/_app-url.ts +37 -0
- package/corpus/templates/slides-2/actions/_deck-app-scope.ts +30 -0
- package/corpus/templates/slides-2/actions/_deck-tracking.ts +260 -0
- package/corpus/templates/slides-2/actions/_deck-write.ts +206 -0
- package/corpus/templates/slides-2/actions/_imported-slide-source.ts +162 -0
- package/corpus/templates/slides-2/actions/_inline-image-storage.ts +1013 -0
- package/corpus/templates/slides-2/actions/_linked-design-system.ts +83 -0
- package/corpus/templates/slides-2/actions/_presenter-notes.ts +83 -0
- package/corpus/templates/slides-2/actions/_render-artifacts.ts +111 -0
- package/corpus/templates/slides-2/actions/_slide-source.ts +344 -0
- package/corpus/templates/slides-2/actions/_tab-state.ts +51 -0
- package/corpus/templates/slides-2/actions/_test-brandfetch.ts +31 -0
- package/corpus/templates/slides-2/actions/_uploaded-files.ts +114 -0
- package/corpus/templates/slides-2/actions/add-deck.ts +123 -0
- package/corpus/templates/slides-2/actions/add-slide-comment.ts +267 -0
- package/corpus/templates/slides-2/actions/add-slide.ts +888 -0
- package/corpus/templates/slides-2/actions/analyze-brand-assets.ts +66 -0
- package/corpus/templates/slides-2/actions/apply-design-system.ts +111 -0
- package/corpus/templates/slides-2/actions/approve-deck-access-request.ts +287 -0
- package/corpus/templates/slides-2/actions/audit-contrast.ts +143 -0
- package/corpus/templates/slides-2/actions/check-image-gen.ts +17 -0
- package/corpus/templates/slides-2/actions/clone-context-slide.ts +340 -0
- package/corpus/templates/slides-2/actions/clone-creative-context-deck.ts +143 -0
- package/corpus/templates/slides-2/actions/control-deck-history.ts +186 -0
- package/corpus/templates/slides-2/actions/control-presenter.ts +117 -0
- package/corpus/templates/slides-2/actions/control-slide-editor.ts +267 -0
- package/corpus/templates/slides-2/actions/create-deck-from-template.ts +274 -0
- package/corpus/templates/slides-2/actions/create-deck.ts +1243 -0
- package/corpus/templates/slides-2/actions/create-design-system.ts +131 -0
- package/corpus/templates/slides-2/actions/create-share-link.ts +127 -0
- package/corpus/templates/slides-2/actions/db-health.ts +22 -0
- package/corpus/templates/slides-2/actions/delete-asset.ts +154 -0
- package/corpus/templates/slides-2/actions/delete-deck.ts +427 -0
- package/corpus/templates/slides-2/actions/delete-design-system.ts +167 -0
- package/corpus/templates/slides-2/actions/delete-slide-comment.ts +143 -0
- package/corpus/templates/slides-2/actions/delete-staged-dataset.ts +30 -0
- package/corpus/templates/slides-2/actions/duplicate-deck.ts +299 -0
- package/corpus/templates/slides-2/actions/export-google-slides.ts +41 -0
- package/corpus/templates/slides-2/actions/export-html.ts +770 -0
- package/corpus/templates/slides-2/actions/export-pptx.ts +2203 -0
- package/corpus/templates/slides-2/actions/extract-pdf.ts +49 -0
- package/corpus/templates/slides-2/actions/generate-image-api.ts +671 -0
- package/corpus/templates/slides-2/actions/generate-image.ts +492 -0
- package/corpus/templates/slides-2/actions/get-agent-access-deck.ts +52 -0
- package/corpus/templates/slides-2/actions/get-deck-access-status.ts +130 -0
- package/corpus/templates/slides-2/actions/get-deck-design-tokens.ts +62 -0
- package/corpus/templates/slides-2/actions/get-deck-reference-context.ts +232 -0
- package/corpus/templates/slides-2/actions/get-deck-template.ts +38 -0
- package/corpus/templates/slides-2/actions/get-deck-version.ts +85 -0
- package/corpus/templates/slides-2/actions/get-deck.ts +562 -0
- package/corpus/templates/slides-2/actions/get-design-system-decode-job-status.ts +57 -0
- package/corpus/templates/slides-2/actions/get-design-system-tier-limit.ts +12 -0
- package/corpus/templates/slides-2/actions/get-design-system.ts +453 -0
- package/corpus/templates/slides-2/actions/get-google-docs-status.ts +106 -0
- package/corpus/templates/slides-2/actions/get-google-picker-token.ts +84 -0
- package/corpus/templates/slides-2/actions/get-home-suggestions.ts +52 -0
- package/corpus/templates/slides-2/actions/get-layout-overflows.ts +192 -0
- package/corpus/templates/slides-2/actions/get-slide-render.ts +125 -0
- package/corpus/templates/slides-2/actions/get-slide-source.ts +115 -0
- package/corpus/templates/slides-2/actions/get-slide-theme-preview.ts +64 -0
- package/corpus/templates/slides-2/actions/get-slide-theme.ts +44 -0
- package/corpus/templates/slides-2/actions/get-slides-2-upload-storage-status.ts +17 -0
- package/corpus/templates/slides-2/actions/get-slides-notification-prefs.ts +37 -0
- package/corpus/templates/slides-2/actions/get-workspace-defaults.ts +51 -0
- package/corpus/templates/slides-2/actions/image-gen-status.ts +35 -0
- package/corpus/templates/slides-2/actions/import-code.ts +26 -0
- package/corpus/templates/slides-2/actions/import-design-project.ts +49 -0
- package/corpus/templates/slides-2/actions/import-document.ts +125 -0
- package/corpus/templates/slides-2/actions/import-docx.ts +57 -0
- package/corpus/templates/slides-2/actions/import-file.ts +1273 -0
- package/corpus/templates/slides-2/actions/import-from-url.ts +25 -0
- package/corpus/templates/slides-2/actions/import-google-doc.ts +208 -0
- package/corpus/templates/slides-2/actions/import-google-font.ts +110 -0
- package/corpus/templates/slides-2/actions/import-google-slides-reference.ts +667 -0
- package/corpus/templates/slides-2/actions/import-pptx.ts +564 -0
- package/corpus/templates/slides-2/actions/import-svgl-logo.ts +115 -0
- package/corpus/templates/slides-2/actions/index-design-system-with-builder.ts +181 -0
- package/corpus/templates/slides-2/actions/index-uploaded-design-system-files.ts +77 -0
- package/corpus/templates/slides-2/actions/list-assets.ts +286 -0
- package/corpus/templates/slides-2/actions/list-deck-templates.ts +83 -0
- package/corpus/templates/slides-2/actions/list-deck-versions.ts +185 -0
- package/corpus/templates/slides-2/actions/list-decks.ts +591 -0
- package/corpus/templates/slides-2/actions/list-design-systems.ts +180 -0
- package/corpus/templates/slides-2/actions/list-slide-comments.ts +128 -0
- package/corpus/templates/slides-2/actions/list-slide-themes.ts +17 -0
- package/corpus/templates/slides-2/actions/list-staged-datasets.ts +14 -0
- package/corpus/templates/slides-2/actions/logo-config.ts +13 -0
- package/corpus/templates/slides-2/actions/navigate.ts +158 -0
- package/corpus/templates/slides-2/actions/patch-deck.ts +2378 -0
- package/corpus/templates/slides-2/actions/provider-api-catalog.ts +25 -0
- package/corpus/templates/slides-2/actions/provider-api-docs.ts +83 -0
- package/corpus/templates/slides-2/actions/provider-api-request.ts +222 -0
- package/corpus/templates/slides-2/actions/query-staged-dataset.ts +83 -0
- package/corpus/templates/slides-2/actions/read-composer-source.ts +108 -0
- package/corpus/templates/slides-2/actions/request-deck-access.ts +803 -0
- package/corpus/templates/slides-2/actions/restore-deck-version.ts +203 -0
- package/corpus/templates/slides-2/actions/run.ts +2 -0
- package/corpus/templates/slides-2/actions/save-deck.ts +313 -0
- package/corpus/templates/slides-2/actions/search-google-fonts.ts +61 -0
- package/corpus/templates/slides-2/actions/search-images.ts +30 -0
- package/corpus/templates/slides-2/actions/search-logos.ts +23 -0
- package/corpus/templates/slides-2/actions/search-svgl-logos.ts +42 -0
- package/corpus/templates/slides-2/actions/set-default-design-system.ts +88 -0
- package/corpus/templates/slides-2/actions/set-workspace-defaults.ts +61 -0
- package/corpus/templates/slides-2/actions/start-design-system-upload.ts +80 -0
- package/corpus/templates/slides-2/actions/sync-design-system-with-builder.ts +84 -0
- package/corpus/templates/slides-2/actions/toggle-slide-comment-reaction.ts +150 -0
- package/corpus/templates/slides-2/actions/transform-slide-objects.ts +1528 -0
- package/corpus/templates/slides-2/actions/update-asset.ts +499 -0
- package/corpus/templates/slides-2/actions/update-deck-aspect-ratio.ts +95 -0
- package/corpus/templates/slides-2/actions/update-deck-design-tokens.ts +175 -0
- package/corpus/templates/slides-2/actions/update-design-system.ts +95 -0
- package/corpus/templates/slides-2/actions/update-slide-comment.ts +213 -0
- package/corpus/templates/slides-2/actions/update-slide-source.ts +353 -0
- package/corpus/templates/slides-2/actions/update-slide.ts +850 -0
- package/corpus/templates/slides-2/actions/update-slides-notification-prefs.ts +55 -0
- package/corpus/templates/slides-2/actions/view-screen.ts +1098 -0
- package/corpus/templates/slides-2/agent-native.app-skill.json +165 -0
- package/corpus/templates/slides-2/agent-native.config.ts +20 -0
- package/corpus/templates/slides-2/agent-native.json +18 -0
- package/corpus/templates/slides-2/app/components/ThemeToggle.tsx +47 -0
- package/corpus/templates/slides-2/app/components/comments/SlideCommentPins.tsx +781 -0
- package/corpus/templates/slides-2/app/components/comments/SlideCommentsPanel.tsx +1075 -0
- package/corpus/templates/slides-2/app/components/deck/DeckCard.tsx +304 -0
- package/corpus/templates/slides-2/app/components/deck/DeckFilterMenu.tsx +83 -0
- package/corpus/templates/slides-2/app/components/deck/ExcalidrawSlide.tsx +183 -0
- package/corpus/templates/slides-2/app/components/deck/MermaidRenderer.tsx +126 -0
- package/corpus/templates/slides-2/app/components/deck/SlideRenderer.tsx +1553 -0
- package/corpus/templates/slides-2/app/components/design-system/DesignSystemCard.tsx +235 -0
- package/corpus/templates/slides-2/app/components/design-system/DesignSystemSetup.tsx +2021 -0
- package/corpus/templates/slides-2/app/components/design-system/builder-design-system-upload.ts +200 -0
- package/corpus/templates/slides-2/app/components/design-system/builder-index-response.ts +104 -0
- package/corpus/templates/slides-2/app/components/editor/AddSlidePopover.tsx +461 -0
- package/corpus/templates/slides-2/app/components/editor/AiEditingMarker.tsx +24 -0
- package/corpus/templates/slides-2/app/components/editor/AlignmentGuides.tsx +82 -0
- package/corpus/templates/slides-2/app/components/editor/AnimationsPanel.tsx +698 -0
- package/corpus/templates/slides-2/app/components/editor/AppMenu.tsx +356 -0
- package/corpus/templates/slides-2/app/components/editor/AssetLibraryPanel.tsx +508 -0
- package/corpus/templates/slides-2/app/components/editor/BlockBubbleMenu.tsx +548 -0
- package/corpus/templates/slides-2/app/components/editor/DeckAccessDeniedPage.tsx +173 -0
- package/corpus/templates/slides-2/app/components/editor/DeckEditorSkeleton.tsx +35 -0
- package/corpus/templates/slides-2/app/components/editor/DeferredPopoverFallback.tsx +148 -0
- package/corpus/templates/slides-2/app/components/editor/EditorActionCluster.tsx +217 -0
- package/corpus/templates/slides-2/app/components/editor/EditorSidebar.tsx +1047 -0
- package/corpus/templates/slides-2/app/components/editor/EditorToolbar.tsx +1285 -0
- package/corpus/templates/slides-2/app/components/editor/ExportMenu.tsx +579 -0
- package/corpus/templates/slides-2/app/components/editor/GeneratingOverlay.tsx +21 -0
- package/corpus/templates/slides-2/app/components/editor/GeneratingSlidePreview.tsx +73 -0
- package/corpus/templates/slides-2/app/components/editor/GoogleDocImportHint.tsx +378 -0
- package/corpus/templates/slides-2/app/components/editor/GoogleDriveConnectionCta.tsx +154 -0
- package/corpus/templates/slides-2/app/components/editor/GoogleSlidesReferenceImport.tsx +299 -0
- package/corpus/templates/slides-2/app/components/editor/HistoryPanel.tsx +354 -0
- package/corpus/templates/slides-2/app/components/editor/HomeQuickStartDialog.tsx +202 -0
- package/corpus/templates/slides-2/app/components/editor/ImageCropOverlay.tsx +820 -0
- package/corpus/templates/slides-2/app/components/editor/ImageDropPromptPopover.tsx +280 -0
- package/corpus/templates/slides-2/app/components/editor/ImageGenPanel.tsx +244 -0
- package/corpus/templates/slides-2/app/components/editor/ImageOverlay.tsx +280 -0
- package/corpus/templates/slides-2/app/components/editor/ImageSearchPanel.tsx +183 -0
- package/corpus/templates/slides-2/app/components/editor/ImportDeckButton.tsx +247 -0
- package/corpus/templates/slides-2/app/components/editor/LogoSearchPanel.tsx +366 -0
- package/corpus/templates/slides-2/app/components/editor/MermaidToExcalidrawPanel.tsx +99 -0
- package/corpus/templates/slides-2/app/components/editor/MissingDeckAccessPane.tsx +219 -0
- package/corpus/templates/slides-2/app/components/editor/NewDeckReferenceStep.tsx +812 -0
- package/corpus/templates/slides-2/app/components/editor/PromptDialog.tsx +963 -0
- package/corpus/templates/slides-2/app/components/editor/QuestionFlow.tsx +119 -0
- package/corpus/templates/slides-2/app/components/editor/RequestDeckAccessDialog.tsx +101 -0
- package/corpus/templates/slides-2/app/components/editor/ShareDialog.tsx +126 -0
- package/corpus/templates/slides-2/app/components/editor/SlideContextToolbar.tsx +1471 -0
- package/corpus/templates/slides-2/app/components/editor/SlideEditor.tsx +11183 -0
- package/corpus/templates/slides-2/app/components/editor/SlideOverflowWarning.tsx +82 -0
- package/corpus/templates/slides-2/app/components/editor/SlideScrollStack.tsx +307 -0
- package/corpus/templates/slides-2/app/components/editor/SlideSlashCommandMenu.tsx +692 -0
- package/corpus/templates/slides-2/app/components/editor/SlideThumbnailContextMenu.tsx +52 -0
- package/corpus/templates/slides-2/app/components/editor/SlideTransitionControl.tsx +184 -0
- package/corpus/templates/slides-2/app/components/editor/SlidesComposerContext.tsx +789 -0
- package/corpus/templates/slides-2/app/components/editor/SlidesComposerContextProvider.tsx +74 -0
- package/corpus/templates/slides-2/app/components/editor/SlidesLayersPanel.tsx +377 -0
- package/corpus/templates/slides-2/app/components/editor/SpeakerNotesPanel.tsx +119 -0
- package/corpus/templates/slides-2/app/components/editor/TweaksPanel.tsx +77 -0
- package/corpus/templates/slides-2/app/components/editor/UploadStorageGate.tsx +37 -0
- package/corpus/templates/slides-2/app/components/editor/bullet-editing.ts +880 -0
- package/corpus/templates/slides-2/app/components/editor/canvas-interactions/index.ts +12 -0
- package/corpus/templates/slides-2/app/components/editor/canvas-interactions/slides-canvas-adapter.ts +119 -0
- package/corpus/templates/slides-2/app/components/editor/commit-active-edit.ts +14 -0
- package/corpus/templates/slides-2/app/components/editor/editor-command-model.ts +35 -0
- package/corpus/templates/slides-2/app/components/editor/fit-text-object.ts +31 -0
- package/corpus/templates/slides-2/app/components/editor/in-place-text-session.browser-cases.json +983 -0
- package/corpus/templates/slides-2/app/components/editor/in-place-text-session.browser-host.ts +747 -0
- package/corpus/templates/slides-2/app/components/editor/in-place-text-session.ts +6891 -0
- package/corpus/templates/slides-2/app/components/editor/inline-edit-session.ts +26 -0
- package/corpus/templates/slides-2/app/components/editor/list-editing.ts +501 -0
- package/corpus/templates/slides-2/app/components/editor/rich-text-selection.ts +975 -0
- package/corpus/templates/slides-2/app/components/editor/rte-test-utils.ts +265 -0
- package/corpus/templates/slides-2/app/components/editor/selection-overlay-measurement.ts +191 -0
- package/corpus/templates/slides-2/app/components/editor/slide-escape-arbiter.ts +34 -0
- package/corpus/templates/slides-2/app/components/editor/slide-object-interactions.ts +6362 -0
- package/corpus/templates/slides-2/app/components/editor/slide-object-transform.browser-host.ts +19 -0
- package/corpus/templates/slides-2/app/components/editor/slide-pointer-target.ts +432 -0
- package/corpus/templates/slides-2/app/components/editor/slide-presence.ts +13 -0
- package/corpus/templates/slides-2/app/components/editor/slide-style.ts +243 -0
- package/corpus/templates/slides-2/app/components/editor/slide-text-targets.ts +540 -0
- package/corpus/templates/slides-2/app/components/editor/style-clipboard.ts +102 -0
- package/corpus/templates/slides-2/app/components/editor/use-prompt-import.ts +159 -0
- package/corpus/templates/slides-2/app/components/home/SlidesHomeLibrary.tsx +79 -0
- package/corpus/templates/slides-2/app/components/layout/AgentWorkIndicator.tsx +193 -0
- package/corpus/templates/slides-2/app/components/layout/Header.tsx +110 -0
- package/corpus/templates/slides-2/app/components/layout/Layout.tsx +492 -0
- package/corpus/templates/slides-2/app/components/layout/Sidebar.tsx +109 -0
- package/corpus/templates/slides-2/app/components/layout/layout-route-policy.ts +28 -0
- package/corpus/templates/slides-2/app/components/presentation/PresentationView.tsx +1116 -0
- package/corpus/templates/slides-2/app/components/presentation/PresenterView.tsx +526 -0
- package/corpus/templates/slides-2/app/components/presentation/SlideTransitionStage.tsx +297 -0
- package/corpus/templates/slides-2/app/components/presentation/present-channel.ts +31 -0
- package/corpus/templates/slides-2/app/components/presentation/slide-build-steps.ts +231 -0
- package/corpus/templates/slides-2/app/components/presentation/slide-navigation.ts +273 -0
- package/corpus/templates/slides-2/app/components/presentation/slide-transition-motion.ts +258 -0
- package/corpus/templates/slides-2/app/components/presentation/voice-navigation.ts +61 -0
- package/corpus/templates/slides-2/app/components/settings/notification-settings.tsx +93 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2AssetBrowser.tsx +726 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2CommandMenu.tsx +453 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2Comments.tsx +571 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2DesignTokens.tsx +345 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2Editor.tsx +4804 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2ExportMenu.tsx +671 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2FontBrowser.tsx +342 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2ImageCropControls.tsx +487 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2Inspector.tsx +950 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/Slides2SvglLogoSearchDialog.tsx +332 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/cross-slide-edit-history.ts +151 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/design-token-presets.ts +140 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/editor-action-errors.ts +47 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/editor-export-errors.ts +60 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/geometry.ts +275 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/image-crop-style.ts +82 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/inline-text-editor.tsx +631 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/keyboard-shortcuts.ts +104 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/object-insertion.ts +13 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/preview-patches.ts +54 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/sandbox-render-errors.ts +23 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/source-structure.ts +634 -0
- package/corpus/templates/slides-2/app/components/slides-2-editor/types.ts +85 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/Slides2BlackoutOverlay.tsx +13 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/Slides2ControlBar.tsx +285 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/Slides2HelpDialog.tsx +72 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/Slides2JumpInput.tsx +38 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/Slides2LaserPointer.tsx +67 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/Slides2Overview.tsx +161 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/Slides2Player.tsx +839 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/Slides2ProgressBar.tsx +23 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/keyboard.ts +36 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/presenter-channel.ts +131 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/use-presenter-action-bridge.ts +296 -0
- package/corpus/templates/slides-2/app/components/slides-2-presenter/useSlides2TouchSwipe.ts +80 -0
- package/corpus/templates/slides-2/app/components/slides-2-runtime/SandboxedSlide.tsx +724 -0
- package/corpus/templates/slides-2/app/components/slides-2-runtime/SlideContentRenderer.tsx +137 -0
- package/corpus/templates/slides-2/app/components/slides-2-runtime/Slides2Canvas.tsx +99 -0
- package/corpus/templates/slides-2/app/components/slides-2-runtime/constants.ts +4 -0
- package/corpus/templates/slides-2/app/components/slides-2-runtime/protocol.ts +1400 -0
- package/corpus/templates/slides-2/app/components/slides-2-runtime/transition-frame.ts +439 -0
- package/corpus/templates/slides-2/app/components/templates/DeckTemplateLibrary.tsx +314 -0
- package/corpus/templates/slides-2/app/components/templates/DeckTemplatePreview.tsx +60 -0
- package/corpus/templates/slides-2/app/components/templates/DeckTemplateStage.tsx +45 -0
- package/corpus/templates/slides-2/app/components/ui/alert-dialog.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/avatar.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/button-group.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/button.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/card.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/command.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/context-menu.tsx +32 -0
- package/corpus/templates/slides-2/app/components/ui/dialog.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/dropdown-menu.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/filter-trigger.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/input.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/label.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/popover.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/progress.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/scroll-area.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/select.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/separator.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/sheet.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/skeleton.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/slider.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/spinner.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/switch.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/tabs.tsx +59 -0
- package/corpus/templates/slides-2/app/components/ui/textarea.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/toggle-group.tsx +1 -0
- package/corpus/templates/slides-2/app/components/ui/toolkit-provider.tsx +17 -0
- package/corpus/templates/slides-2/app/components/ui/tooltip.tsx +1 -0
- package/corpus/templates/slides-2/app/components/visual-editor/CanvasCommentPins.tsx +46 -0
- package/corpus/templates/slides-2/app/components/visual-editor/DrawOverlay.tsx +27 -0
- package/corpus/templates/slides-2/app/components/visual-editor/MultiSelectChip.tsx +97 -0
- package/corpus/templates/slides-2/app/components/visual-editor/SaveStatusIndicator.tsx +273 -0
- package/corpus/templates/slides-2/app/components/visual-editor/index.ts +4 -0
- package/corpus/templates/slides-2/app/context/DeckContext.tsx +7486 -0
- package/corpus/templates/slides-2/app/design-system.ts +3 -0
- package/corpus/templates/slides-2/app/entry.client.tsx +10 -0
- package/corpus/templates/slides-2/app/entry.server.tsx +10 -0
- package/corpus/templates/slides-2/app/global.css +1626 -0
- package/corpus/templates/slides-2/app/hooks/use-agent-generating.ts +517 -0
- package/corpus/templates/slides-2/app/hooks/use-compact-editor-layout.ts +26 -0
- package/corpus/templates/slides-2/app/hooks/use-contrast-audit-bridge.ts +49 -0
- package/corpus/templates/slides-2/app/hooks/use-deck-access-reload.ts +70 -0
- package/corpus/templates/slides-2/app/hooks/use-deck-access.ts +50 -0
- package/corpus/templates/slides-2/app/hooks/use-deck-design-system.ts +146 -0
- package/corpus/templates/slides-2/app/hooks/use-deck-history-action-bridge.ts +266 -0
- package/corpus/templates/slides-2/app/hooks/use-deck-presence.ts +89 -0
- package/corpus/templates/slides-2/app/hooks/use-deck-role.ts +46 -0
- package/corpus/templates/slides-2/app/hooks/use-deck-versions.ts +43 -0
- package/corpus/templates/slides-2/app/hooks/use-design-system-workflows.ts +11 -0
- package/corpus/templates/slides-2/app/hooks/use-design-systems.ts +31 -0
- package/corpus/templates/slides-2/app/hooks/use-generating-slide-preview.ts +115 -0
- package/corpus/templates/slides-2/app/hooks/use-navigation-state.ts +229 -0
- package/corpus/templates/slides-2/app/hooks/use-new-deck-generation-signal.ts +46 -0
- package/corpus/templates/slides-2/app/hooks/use-new-deck-generation.ts +710 -0
- package/corpus/templates/slides-2/app/hooks/use-sidebar-collapsed.ts +95 -0
- package/corpus/templates/slides-2/app/hooks/use-slide-comments.ts +202 -0
- package/corpus/templates/slides-2/app/hooks/use-slide-file-storage-status.ts +55 -0
- package/corpus/templates/slides-2/app/hooks/use-undo-selection.ts +66 -0
- package/corpus/templates/slides-2/app/hooks/use-workspace-defaults.ts +31 -0
- package/corpus/templates/slides-2/app/i18n/en-US.ts +1507 -0
- package/corpus/templates/slides-2/app/i18n/index.ts +19 -0
- package/corpus/templates/slides-2/app/lib/agent-visible-message.ts +21 -0
- package/corpus/templates/slides-2/app/lib/aspect-ratios.ts +7 -0
- package/corpus/templates/slides-2/app/lib/asset-error-copy.ts +59 -0
- package/corpus/templates/slides-2/app/lib/canvas-zoom.ts +47 -0
- package/corpus/templates/slides-2/app/lib/composer-context.ts +152 -0
- package/corpus/templates/slides-2/app/lib/composer-draft.ts +34 -0
- package/corpus/templates/slides-2/app/lib/contrast-audit.ts +390 -0
- package/corpus/templates/slides-2/app/lib/contrast-resolve.ts +240 -0
- package/corpus/templates/slides-2/app/lib/create-deck-generation.ts +938 -0
- package/corpus/templates/slides-2/app/lib/deck-access-lost.ts +4 -0
- package/corpus/templates/slides-2/app/lib/deck-backup.ts +186 -0
- package/corpus/templates/slides-2/app/lib/deck-editor-loading.ts +91 -0
- package/corpus/templates/slides-2/app/lib/deck-export-file-client.ts +77 -0
- package/corpus/templates/slides-2/app/lib/deck-filter.ts +52 -0
- package/corpus/templates/slides-2/app/lib/deck-list-loading.ts +16 -0
- package/corpus/templates/slides-2/app/lib/deck-preview-frame.ts +15 -0
- package/corpus/templates/slides-2/app/lib/deck-share-links.ts +9 -0
- package/corpus/templates/slides-2/app/lib/deck-sorting.ts +19 -0
- package/corpus/templates/slides-2/app/lib/deferred-editor-surfaces.ts +24 -0
- package/corpus/templates/slides-2/app/lib/design-system-selection.ts +11 -0
- package/corpus/templates/slides-2/app/lib/design-systems.ts +231 -0
- package/corpus/templates/slides-2/app/lib/dynamic-import.ts +50 -0
- package/corpus/templates/slides-2/app/lib/editor-agent-handoff.ts +92 -0
- package/corpus/templates/slides-2/app/lib/editor-shortcuts.ts +153 -0
- package/corpus/templates/slides-2/app/lib/export-google-slides-client.ts +168 -0
- package/corpus/templates/slides-2/app/lib/export-pdf-client.ts +684 -0
- package/corpus/templates/slides-2/app/lib/export-pptx-client.ts +2420 -0
- package/corpus/templates/slides-2/app/lib/generation-lifecycle.ts +24 -0
- package/corpus/templates/slides-2/app/lib/generation-state.ts +247 -0
- package/corpus/templates/slides-2/app/lib/google-docs-client.ts +110 -0
- package/corpus/templates/slides-2/app/lib/google-slides-export-availability-client.ts +53 -0
- package/corpus/templates/slides-2/app/lib/google-slides-reference-source.ts +18 -0
- package/corpus/templates/slides-2/app/lib/image-download.ts +85 -0
- package/corpus/templates/slides-2/app/lib/image-drop-to-agent.ts +210 -0
- package/corpus/templates/slides-2/app/lib/import-uploaded-deck.ts +132 -0
- package/corpus/templates/slides-2/app/lib/inline-edit-remote.ts +55 -0
- package/corpus/templates/slides-2/app/lib/localize-slides-changelog.ts +47 -0
- package/corpus/templates/slides-2/app/lib/mermaid-blocks.ts +18 -0
- package/corpus/templates/slides-2/app/lib/new-deck-reference-selection.ts +174 -0
- package/corpus/templates/slides-2/app/lib/normalize-slide-padding.ts +74 -0
- package/corpus/templates/slides-2/app/lib/pending-deck-changes.ts +33 -0
- package/corpus/templates/slides-2/app/lib/portaled-layer.ts +7 -0
- package/corpus/templates/slides-2/app/lib/pptx-google-slides.ts +204 -0
- package/corpus/templates/slides-2/app/lib/prompt-attachment-adapter.ts +37 -0
- package/corpus/templates/slides-2/app/lib/prompt-file-uploads.ts +557 -0
- package/corpus/templates/slides-2/app/lib/recent-references.ts +106 -0
- package/corpus/templates/slides-2/app/lib/reference-document-hydration.ts +406 -0
- package/corpus/templates/slides-2/app/lib/register-chat-renderers.tsx +645 -0
- package/corpus/templates/slides-2/app/lib/reveal-after-delete.ts +55 -0
- package/corpus/templates/slides-2/app/lib/sanitize-slide-html.ts +752 -0
- package/corpus/templates/slides-2/app/lib/slide-agent-context.ts +148 -0
- package/corpus/templates/slides-2/app/lib/slide-animation-elements.ts +900 -0
- package/corpus/templates/slides-2/app/lib/slide-clipboard.ts +534 -0
- package/corpus/templates/slides-2/app/lib/slide-comment-anchor.ts +286 -0
- package/corpus/templates/slides-2/app/lib/slide-content-merge.ts +295 -0
- package/corpus/templates/slides-2/app/lib/slide-image-replacement.ts +1919 -0
- package/corpus/templates/slides-2/app/lib/slide-live-remote.ts +215 -0
- package/corpus/templates/slides-2/app/lib/slide-scroll.ts +56 -0
- package/corpus/templates/slides-2/app/lib/slide-source-map.ts +1099 -0
- package/corpus/templates/slides-2/app/lib/slide-video.ts +390 -0
- package/corpus/templates/slides-2/app/lib/slides-relay-tracking.ts +114 -0
- package/corpus/templates/slides-2/app/lib/streaming-slide-html.ts +77 -0
- package/corpus/templates/slides-2/app/lib/tab-id.ts +3 -0
- package/corpus/templates/slides-2/app/lib/template-navigation.ts +15 -0
- package/corpus/templates/slides-2/app/lib/text-tool-shortcut.ts +75 -0
- package/corpus/templates/slides-2/app/lib/undo-reveal.ts +332 -0
- package/corpus/templates/slides-2/app/lib/upload-response.ts +107 -0
- package/corpus/templates/slides-2/app/lib/utils.ts +38 -0
- package/corpus/templates/slides-2/app/lib/validate-native-slide-html.ts +177 -0
- package/corpus/templates/slides-2/app/lib/video-upload.ts +354 -0
- package/corpus/templates/slides-2/app/pages/DeckEditor.tsx +6158 -0
- package/corpus/templates/slides-2/app/pages/DesignSystems.tsx +363 -0
- package/corpus/templates/slides-2/app/pages/Index.tsx +3254 -0
- package/corpus/templates/slides-2/app/pages/NotFound.tsx +33 -0
- package/corpus/templates/slides-2/app/pages/Presentation.tsx +120 -0
- package/corpus/templates/slides-2/app/pages/SharedPresentation.tsx +174 -0
- package/corpus/templates/slides-2/app/pages/SlideThemeDetail.tsx +227 -0
- package/corpus/templates/slides-2/app/pages/SlideThemes.tsx +155 -0
- package/corpus/templates/slides-2/app/pages/Slides2EditorPage.tsx +1618 -0
- package/corpus/templates/slides-2/app/pages/Slides2PresenterConsolePage.tsx +937 -0
- package/corpus/templates/slides-2/app/pages/Slides2PresenterPage.tsx +979 -0
- package/corpus/templates/slides-2/app/pages/Templates.tsx +32 -0
- package/corpus/templates/slides-2/app/root.tsx +391 -0
- package/corpus/templates/slides-2/app/routes/$.tsx +10 -0
- package/corpus/templates/slides-2/app/routes/_index.tsx +1 -0
- package/corpus/templates/slides-2/app/routes/access-request.approve.tsx +276 -0
- package/corpus/templates/slides-2/app/routes/agent.tsx +19 -0
- package/corpus/templates/slides-2/app/routes/chat.$threadId.tsx +1 -0
- package/corpus/templates/slides-2/app/routes/chat.tsx +190 -0
- package/corpus/templates/slides-2/app/routes/deck.$id.tsx +10 -0
- package/corpus/templates/slides-2/app/routes/deck.$id_.present.tsx +10 -0
- package/corpus/templates/slides-2/app/routes/design-systems.tsx +10 -0
- package/corpus/templates/slides-2/app/routes/extensions.$id.$slug.tsx +2 -0
- package/corpus/templates/slides-2/app/routes/extensions.$id.tsx +5 -0
- package/corpus/templates/slides-2/app/routes/extensions._index.tsx +5 -0
- package/corpus/templates/slides-2/app/routes/extensions.tsx +5 -0
- package/corpus/templates/slides-2/app/routes/home-layout.tsx +31 -0
- package/corpus/templates/slides-2/app/routes/home.tsx +22 -0
- package/corpus/templates/slides-2/app/routes/p.$id.tsx +195 -0
- package/corpus/templates/slides-2/app/routes/settings.$.tsx +1 -0
- package/corpus/templates/slides-2/app/routes/settings.tsx +131 -0
- package/corpus/templates/slides-2/app/routes/share.$token.tsx +137 -0
- package/corpus/templates/slides-2/app/routes/slide.tsx +209 -0
- package/corpus/templates/slides-2/app/routes/team.tsx +11 -0
- package/corpus/templates/slides-2/app/routes/templates.tsx +1 -0
- package/corpus/templates/slides-2/app/routes/themes.$id.tsx +1 -0
- package/corpus/templates/slides-2/app/routes/themes.tsx +1 -0
- package/corpus/templates/slides-2/app/routes.ts +24 -0
- package/corpus/templates/slides-2/app/vite-env.d.ts +24 -0
- package/corpus/templates/slides-2/changelog/2026-10-17-find-and-switch-decks-from-the-presenter-console.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-17-meet-slides-2-create-and-refine-editable-slide-decks-with-an.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-17-pptx-image-export.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-17-visual-editor.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-18-apply-an-accessible-design-system-to-an-existing-deck-before.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-18-choose-a-template-or-start-a-new-presentation-from-the-slide.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-18-generate-decks-from-a-prompt-then-edit-slide-elements-direct.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-18-generate-presentation-decks-from-a-prompt-and-edit-every-sli.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-18-new-presentation-drafts-save-before-generation-starts-so-you.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-18-the-assistant-can-undo-redo-and-save-pending-edits-in-the-vi.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-agents-can-insert-duplicate-and-delete-canvas-objects-in-sou.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-browse-slide-themes.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-clicking-a-slide-preview-in-overview-selects-that-slide.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-create-decks-from-a-prompt-and-edit-slides-directly-on-the-c.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-creating-and-editing-decks-now-starts-with-the-tools-most-re.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-deleting-decks-revokes-public-links.md +7 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-escape-cancels-an-in-progress-slide-drag-without-losing-earl.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-import-failures-now-show-clear-localized-descriptions-instea.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-presenter-controls-stay-responsive-when-moving-over-the-slid.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-presenter-notes-stay-private-from-viewers-and-commenters.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-preview-generated-slides-in-chat.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-remote-image-previews-accept-supported-raster-formats.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-search-the-svgl-catalog-and-add-svg-logos-to-a-deck-or-the-g.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-slide-generation-explains-when-react-effect-hooks-cannot-run.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-the-editor-highlights-hovered-objects-and-keeps-image-replac.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-19-the-slide-editor-uses-the-shared-agent-native-controls.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-20-deck-editing-controls-match-the-workspace.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-20-google-slides-imports-now-report-missing-image-data-instead-.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-20-imports-and-previews-handle-large-content-safely.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-20-public-deck-pages-can-export-source-backed-slides-to-pdf.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-20-saved-slide-images-stay-available.md +6 -0
- package/corpus/templates/slides-2/changelog/2026-10-20-scope-global-media-picks-to-assets-the-current-deck-can-reso.md +6 -0
- package/corpus/templates/slides-2/components.json +20 -0
- package/corpus/templates/slides-2/drizzle.config.ts +3 -0
- package/corpus/templates/slides-2/learnings.defaults.md +5 -0
- package/corpus/templates/slides-2/netlify.toml +24 -0
- package/corpus/templates/slides-2/package.json +147 -0
- package/corpus/templates/slides-2/public/agent-native-icon-dark.svg +10 -0
- package/corpus/templates/slides-2/public/agent-native-icon-light.svg +10 -0
- package/corpus/templates/slides-2/public/agent-native-logo-dark.svg +21 -0
- package/corpus/templates/slides-2/public/agent-native-logo-light.svg +21 -0
- package/corpus/templates/slides-2/public/assets/builder-logo-white.svg +15 -0
- package/corpus/templates/slides-2/public/assets/generated/preview.html +61 -0
- package/corpus/templates/slides-2/public/assets/intuit-logo-white.svg +6 -0
- package/corpus/templates/slides-2/public/assets/walmart-logo-white.svg +6 -0
- package/corpus/templates/slides-2/public/chatgpt-plugin-icon.svg +7 -0
- package/corpus/templates/slides-2/public/favicon.svg +1 -0
- package/corpus/templates/slides-2/public/icon-180.svg +1 -0
- package/corpus/templates/slides-2/public/icon-192.svg +1 -0
- package/corpus/templates/slides-2/public/icon-512.svg +1 -0
- package/corpus/templates/slides-2/public/manifest.json +20 -0
- package/corpus/templates/slides-2/public/placeholder.svg +1 -0
- package/corpus/templates/slides-2/public/robots.txt +14 -0
- package/corpus/templates/slides-2/public/visual-edit-structure-proof.html +99 -0
- package/corpus/templates/slides-2/react-router.config.ts +7 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/README.md +499 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/authoring-fuzz.ts +9517 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/baseline.json +16427 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/dev-server-url.ts +10 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/lib/in-page.ts +1975 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/lib/metrics.ts +1401 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/retry-infra.ts +7 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/run-options.ts +21 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/run-outcomes.ts +127 -0
- package/corpus/templates/slides-2/scripts/edit-fidelity/run.ts +8451 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/README.md +116 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/compare-layout-lib.ts +241 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/compare-layout.ts +30 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/diff.ts +222 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/export.ts +765 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/fixtures/agent-dark-deck.json +48 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/generate-calibration.ts +765 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/google-export.ts +137 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/google-layout.ts +82 -0
- package/corpus/templates/slides-2/scripts/export-fidelity/resolve-pkg.ts +29 -0
- package/corpus/templates/slides-2/scripts/migrate-production.ts +22 -0
- package/corpus/templates/slides-2/server/db/index.ts +73 -0
- package/corpus/templates/slides-2/server/db/schema.ts +189 -0
- package/corpus/templates/slides-2/server/handlers/assets-url.ts +13 -0
- package/corpus/templates/slides-2/server/handlers/assets.ts +3217 -0
- package/corpus/templates/slides-2/server/handlers/decks.ts +185 -0
- package/corpus/templates/slides-2/server/handlers/demo.ts +9 -0
- package/corpus/templates/slides-2/server/handlers/design-systems.ts +219 -0
- package/corpus/templates/slides-2/server/handlers/google-docs-auth.ts +165 -0
- package/corpus/templates/slides-2/server/handlers/image-gen.ts +153 -0
- package/corpus/templates/slides-2/server/handlers/image-providers/gemini.ts +209 -0
- package/corpus/templates/slides-2/server/handlers/image-providers/index.ts +61 -0
- package/corpus/templates/slides-2/server/handlers/image-providers/openai.ts +288 -0
- package/corpus/templates/slides-2/server/handlers/image-providers/types.ts +35 -0
- package/corpus/templates/slides-2/server/handlers/import/docx-parser.ts +31 -0
- package/corpus/templates/slides-2/server/handlers/import/html-converter.ts +1534 -0
- package/corpus/templates/slides-2/server/handlers/import/pdf-fidelity-parser.ts +1039 -0
- package/corpus/templates/slides-2/server/handlers/import/pdf-sidecar-reader.ts +81 -0
- package/corpus/templates/slides-2/server/handlers/import/pdf-style-digest.ts +187 -0
- package/corpus/templates/slides-2/server/handlers/import/pptx-assets.ts +155 -0
- package/corpus/templates/slides-2/server/handlers/import/pptx-parser.ts +57 -0
- package/corpus/templates/slides-2/server/handlers/request-auth-context.ts +108 -0
- package/corpus/templates/slides-2/server/handlers/share.ts +52 -0
- package/corpus/templates/slides-2/server/handlers/uploads-chunked.ts +1066 -0
- package/corpus/templates/slides-2/server/handlers/uploads.ts +457 -0
- package/corpus/templates/slides-2/server/lib/access-request-email.ts +66 -0
- package/corpus/templates/slides-2/server/lib/assets-image-delegation.ts +331 -0
- package/corpus/templates/slides-2/server/lib/bounded-multipart.ts +49 -0
- package/corpus/templates/slides-2/server/lib/builder-design-system-proxy.ts +122 -0
- package/corpus/templates/slides-2/server/lib/chat-attachments.ts +425 -0
- package/corpus/templates/slides-2/server/lib/chatgpt-directory-tools.ts +246 -0
- package/corpus/templates/slides-2/server/lib/chunked-upload-session.ts +195 -0
- package/corpus/templates/slides-2/server/lib/comment-notifications.ts +184 -0
- package/corpus/templates/slides-2/server/lib/deck-access-requests.ts +102 -0
- package/corpus/templates/slides-2/server/lib/deck-asset-scope.ts +150 -0
- package/corpus/templates/slides-2/server/lib/deck-export-tracking.ts +119 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/a-case-study.ts +154 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/a-company.ts +160 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/a-pitch.ts +151 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/a-quarterly.ts +264 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/a-shared.ts +35 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/a-update.ts +188 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/a-workshop.ts +196 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/b-keynote.ts +131 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/b-lesson.ts +209 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/b-manifesto.ts +149 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/b-portfolio.ts +144 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/b-research.ts +221 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/b-roadmap.ts +264 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/b-shared.ts +44 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/group-a.ts +16 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/group-b.ts +16 -0
- package/corpus/templates/slides-2/server/lib/deck-templates/legacy.ts +567 -0
- package/corpus/templates/slides-2/server/lib/deck-templates.ts +60 -0
- package/corpus/templates/slides-2/server/lib/deck-versions.ts +233 -0
- package/corpus/templates/slides-2/server/lib/design-system-workflows.ts +22 -0
- package/corpus/templates/slides-2/server/lib/emails.ts +84 -0
- package/corpus/templates/slides-2/server/lib/env-config.ts +15 -0
- package/corpus/templates/slides-2/server/lib/fetch-remote-image.ts +245 -0
- package/corpus/templates/slides-2/server/lib/generation-completion.ts +278 -0
- package/corpus/templates/slides-2/server/lib/google-docs-access.ts +51 -0
- package/corpus/templates/slides-2/server/lib/google-docs-error.ts +54 -0
- package/corpus/templates/slides-2/server/lib/google-docs-oauth.ts +422 -0
- package/corpus/templates/slides-2/server/lib/google-fonts.ts +509 -0
- package/corpus/templates/slides-2/server/lib/google-oauth-preflight.ts +119 -0
- package/corpus/templates/slides-2/server/lib/google-slides-export-availability.ts +55 -0
- package/corpus/templates/slides-2/server/lib/image-proxy-response.ts +16 -0
- package/corpus/templates/slides-2/server/lib/image-proxy-url.ts +155 -0
- package/corpus/templates/slides-2/server/lib/import-asset-storage.ts +214 -0
- package/corpus/templates/slides-2/server/lib/imported-asset-batch.ts +218 -0
- package/corpus/templates/slides-2/server/lib/legacy-slide-source.ts +692 -0
- package/corpus/templates/slides-2/server/lib/media-search-providers.ts +216 -0
- package/corpus/templates/slides-2/server/lib/native-creative-context.ts +295 -0
- package/corpus/templates/slides-2/server/lib/pdf-parse-setup.ts +115 -0
- package/corpus/templates/slides-2/server/lib/provider-api.ts +57 -0
- package/corpus/templates/slides-2/server/lib/request-wait-until.ts +30 -0
- package/corpus/templates/slides-2/server/lib/shared-deck.ts +29 -0
- package/corpus/templates/slides-2/server/lib/slide-asset-references.ts +309 -0
- package/corpus/templates/slides-2/server/lib/slide-content-patch.ts +1004 -0
- package/corpus/templates/slides-2/server/lib/slide-hygiene.ts +731 -0
- package/corpus/templates/slides-2/server/lib/slide-image-insertion.ts +136 -0
- package/corpus/templates/slides-2/server/lib/slide-reveal-issues.ts +41 -0
- package/corpus/templates/slides-2/server/lib/slide-source-editing/babel-walk.ts +117 -0
- package/corpus/templates/slides-2/server/lib/slide-source-editing/batch-edit.ts +152 -0
- package/corpus/templates/slides-2/server/lib/slide-source-editing/edit-ops.ts +1478 -0
- package/corpus/templates/slides-2/server/lib/slide-source-editing/image-target.ts +128 -0
- package/corpus/templates/slides-2/server/lib/slide-source-editing/text-diff.ts +23 -0
- package/corpus/templates/slides-2/server/lib/slide-source-limits.ts +9 -0
- package/corpus/templates/slides-2/server/lib/slide-source.ts +1786 -0
- package/corpus/templates/slides-2/server/lib/slide-theme-demo-sources.ts +2106 -0
- package/corpus/templates/slides-2/server/lib/slide-themes.ts +2174 -0
- package/corpus/templates/slides-2/server/lib/slide-worker-runtime.ts +1995 -0
- package/corpus/templates/slides-2/server/lib/slides-tracking.ts +73 -0
- package/corpus/templates/slides-2/server/lib/source-import.ts +213 -0
- package/corpus/templates/slides-2/server/lib/svgl.ts +364 -0
- package/corpus/templates/slides-2/server/lib/tenant-files.ts +179 -0
- package/corpus/templates/slides-2/server/lib/upload-storage-status.ts +9 -0
- package/corpus/templates/slides-2/server/lib/uploaded-asset-cleanup-outbox.ts +521 -0
- package/corpus/templates/slides-2/server/lib/uploaded-asset-object-lifecycle.ts +404 -0
- package/corpus/templates/slides-2/server/lib/uploaded-fonts.ts +696 -0
- package/corpus/templates/slides-2/server/lib/uploaded-reference-storage.ts +77 -0
- package/corpus/templates/slides-2/server/lib/validate-slide-animations.ts +341 -0
- package/corpus/templates/slides-2/server/middleware/auth.ts +6 -0
- package/corpus/templates/slides-2/server/plugins/_dev-upload-stub.ts +6 -0
- package/corpus/templates/slides-2/server/plugins/agent-chat.ts +402 -0
- package/corpus/templates/slides-2/server/plugins/auth.ts +31 -0
- package/corpus/templates/slides-2/server/plugins/collab.ts +30 -0
- package/corpus/templates/slides-2/server/plugins/config.ts +6 -0
- package/corpus/templates/slides-2/server/plugins/core-routes.ts +30 -0
- package/corpus/templates/slides-2/server/plugins/creative-context.ts +187 -0
- package/corpus/templates/slides-2/server/plugins/db.ts +462 -0
- package/corpus/templates/slides-2/server/plugins/feature-flags.ts +5 -0
- package/corpus/templates/slides-2/server/plugins/labs.ts +8 -0
- package/corpus/templates/slides-2/server/plugins/orphaned-asset-cleanup.ts +17 -0
- package/corpus/templates/slides-2/server/plugins/otel.ts +6 -0
- package/corpus/templates/slides-2/server/plugins/transactional-emails.ts +5 -0
- package/corpus/templates/slides-2/server/register-secrets.ts +209 -0
- package/corpus/templates/slides-2/server/routes/[...page].get.ts +5 -0
- package/corpus/templates/slides-2/server/routes/[...page].head.ts +1 -0
- package/corpus/templates/slides-2/server/routes/[base]/_agent-native/google-docs/auth-url.get.ts +1 -0
- package/corpus/templates/slides-2/server/routes/[base]/_agent-native/google-docs/callback.get.ts +1 -0
- package/corpus/templates/slides-2/server/routes/_agent-native/google-docs/auth-url.get.ts +1 -0
- package/corpus/templates/slides-2/server/routes/_agent-native/google-docs/callback.get.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/assets/upload-video.post.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/assets/upload.post.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/assets/video-uploads.delete.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/deck-agent-context.json.get.ts +105 -0
- package/corpus/templates/slides-2/server/routes/api/decks/events.get.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/demo.get.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/exports/[filename].get.ts +221 -0
- package/corpus/templates/slides-2/server/routes/api/exports/google-slides.post.ts +240 -0
- package/corpus/templates/slides-2/server/routes/api/exports/html.post.ts +67 -0
- package/corpus/templates/slides-2/server/routes/api/exports/pptx.post.ts +100 -0
- package/corpus/templates/slides-2/server/routes/api/gen-preview/[...].get.ts +24 -0
- package/corpus/templates/slides-2/server/routes/api/generated/[...].get.ts +24 -0
- package/corpus/templates/slides-2/server/routes/api/image-proxy.get.ts +518 -0
- package/corpus/templates/slides-2/server/routes/api/import-assets/[token].get.ts +70 -0
- package/corpus/templates/slides-2/server/routes/api/preview-images.get.ts +20 -0
- package/corpus/templates/slides-2/server/routes/api/share/[token].get.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/uploads-chunked/[sessionId]/chunk.post.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/uploads-chunked/[sessionId]/status.get.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/uploads-chunked/[sessionId].delete.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/uploads-chunked/start.post.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/uploads.delete.ts +1 -0
- package/corpus/templates/slides-2/server/routes/api/uploads.post.ts +1 -0
- package/corpus/templates/slides-2/server/workspace-defaults.ts +196 -0
- package/corpus/templates/slides-2/shared/action-ui.ts +147 -0
- package/corpus/templates/slides-2/shared/agent-readable.ts +2 -0
- package/corpus/templates/slides-2/shared/api.ts +406 -0
- package/corpus/templates/slides-2/shared/app-state-tabs.ts +30 -0
- package/corpus/templates/slides-2/shared/app-storage.ts +9 -0
- package/corpus/templates/slides-2/shared/aspect-ratios.ts +49 -0
- package/corpus/templates/slides-2/shared/blank-slide.ts +179 -0
- package/corpus/templates/slides-2/shared/client-compatibility.ts +2 -0
- package/corpus/templates/slides-2/shared/contrast-audit.ts +255 -0
- package/corpus/templates/slides-2/shared/deck-access.ts +26 -0
- package/corpus/templates/slides-2/shared/deck-app-scope.ts +14 -0
- package/corpus/templates/slides-2/shared/deck-content.ts +37 -0
- package/corpus/templates/slides-2/shared/deck-history-control.ts +79 -0
- package/corpus/templates/slides-2/shared/deck-scope.ts +5 -0
- package/corpus/templates/slides-2/shared/deck-title.ts +199 -0
- package/corpus/templates/slides-2/shared/deck-write.ts +61 -0
- package/corpus/templates/slides-2/shared/design-flags.ts +7 -0
- package/corpus/templates/slides-2/shared/design-system-validation.ts +88 -0
- package/corpus/templates/slides-2/shared/editor-control.ts +120 -0
- package/corpus/templates/slides-2/shared/generation-timing.ts +19 -0
- package/corpus/templates/slides-2/shared/google-docs.ts +69 -0
- package/corpus/templates/slides-2/shared/labs.ts +10 -0
- package/corpus/templates/slides-2/shared/overview-navigation.ts +34 -0
- package/corpus/templates/slides-2/shared/ownership.ts +6 -0
- package/corpus/templates/slides-2/shared/pdf-sidecar.ts +130 -0
- package/corpus/templates/slides-2/shared/presenter-control.ts +111 -0
- package/corpus/templates/slides-2/shared/representative-slide.ts +89 -0
- package/corpus/templates/slides-2/shared/slide-background.ts +30 -0
- package/corpus/templates/slides-2/shared/slide-comment-anchor.ts +117 -0
- package/corpus/templates/slides-2/shared/slide-comment-reactions.ts +47 -0
- package/corpus/templates/slides-2/shared/slide-design-tokens.ts +92 -0
- package/corpus/templates/slides-2/shared/slide-fit.ts +78 -0
- package/corpus/templates/slides-2/shared/slide-ids.ts +133 -0
- package/corpus/templates/slides-2/shared/slide-number.ts +124 -0
- package/corpus/templates/slides-2/shared/slide-object-structure.ts +790 -0
- package/corpus/templates/slides-2/shared/slide-text-range-selection.ts +50 -0
- package/corpus/templates/slides-2/shared/slide-transitions.ts +70 -0
- package/corpus/templates/slides-2/shared/slides-2-transition.ts +194 -0
- package/corpus/templates/slides-2/shared/slides-user-prefs.ts +22 -0
- package/corpus/templates/slides-2/shared/source-import-errors.ts +12 -0
- package/corpus/templates/slides-2/shared/source-runtime-export.ts +76 -0
- package/corpus/templates/slides-2/shared/upload-types.ts +41 -0
- package/corpus/templates/slides-2/ssr-entry.ts +11 -0
- package/corpus/templates/slides-2/tsconfig.json +27 -0
- package/corpus/templates/slides-2/vite.config.ts +77 -0
- package/corpus/templates/slides-2/vitest.config.ts +28 -0
- package/corpus/templates/tasks/.agents/skills/actions/references/action-fields.md +1 -1
- package/package.json +1 -1
- package/corpus/templates/design/.agents/skills/shader-fills/SKILL.md +0 -182
- package/corpus/templates/design/actions/apply-shader-fill.ts +0 -450
- package/corpus/templates/design/actions/apply-shader.ts +0 -257
- package/corpus/templates/design/actions/preview-shader-fill.ts +0 -157
- package/corpus/templates/design/app/components/design/inspector/GlslShaderPanel.tsx +0 -1144
- package/corpus/templates/design/app/components/design/inspector/SHADER_INTEGRATION.md +0 -450
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.stories.tsx +0 -71
- package/corpus/templates/design/app/components/design/inspector/ShaderControls.tsx +0 -555
- package/corpus/templates/design/app/components/design/inspector/ShaderEffectRow.tsx +0 -105
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +0 -433
- package/corpus/templates/design/app/components/design/inspector/color-picker-shader-pane.tsx +0 -648
- package/corpus/templates/design/shared/shader-fill.ts +0 -174
- package/corpus/templates/design/shared/shader-presets.ts +0 -1523
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
appendFileSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
readFileSync,
|
|
7
|
+
rmSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from "node:fs";
|
|
3
10
|
import path from "node:path";
|
|
4
11
|
|
|
5
12
|
import {
|
|
6
13
|
expect,
|
|
14
|
+
type APIRequestContext,
|
|
7
15
|
type BrowserContext,
|
|
8
16
|
type Page,
|
|
9
17
|
type Request,
|
|
@@ -11,12 +19,15 @@ import {
|
|
|
11
19
|
type Route,
|
|
12
20
|
type TestInfo,
|
|
13
21
|
} from "@playwright/test";
|
|
22
|
+
import type { Editor } from "@tiptap/core";
|
|
14
23
|
|
|
24
|
+
import { AUTH_FILES } from "./auth-files";
|
|
15
25
|
import {
|
|
16
26
|
appendFixtureInput,
|
|
17
27
|
captureFixtureInput,
|
|
18
28
|
type FixtureInputSnapshot,
|
|
19
29
|
} from "./editor-input-lineage";
|
|
30
|
+
import { GATE_ARM } from "./gate-arm";
|
|
20
31
|
import {
|
|
21
32
|
SaveLineageCapture,
|
|
22
33
|
type SaveLineageCheckpointName,
|
|
@@ -31,11 +42,64 @@ export const ACTION_HEADERS = {
|
|
|
31
42
|
};
|
|
32
43
|
|
|
33
44
|
export const EDITOR = ".content-editor.ProseMirror";
|
|
45
|
+
export const ACTIVE_EDITOR = `${EDITOR}:not([hidden] *)`;
|
|
46
|
+
|
|
47
|
+
export async function getActionResponse(
|
|
48
|
+
page: Page,
|
|
49
|
+
name: string,
|
|
50
|
+
params: Record<string, string>,
|
|
51
|
+
) {
|
|
52
|
+
return page.request.get(`/_agent-native/actions/${name}`, {
|
|
53
|
+
params,
|
|
54
|
+
headers: ACTION_HEADERS,
|
|
55
|
+
timeout: 30_000,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function readAppState<T>(
|
|
60
|
+
page: Page,
|
|
61
|
+
key: string,
|
|
62
|
+
): Promise<T | null> {
|
|
63
|
+
const response = await page.request.get(
|
|
64
|
+
`/_agent-native/application-state/${encodeURIComponent(key)}`,
|
|
65
|
+
);
|
|
66
|
+
const body = await response.text();
|
|
67
|
+
expect(
|
|
68
|
+
response.ok(),
|
|
69
|
+
`application-state (${response.status()}): ${body}`,
|
|
70
|
+
).toBe(true);
|
|
71
|
+
return body === "" ? null : (JSON.parse(body) as T | null);
|
|
72
|
+
}
|
|
34
73
|
|
|
35
74
|
const SAVE_PATH = "/_agent-native/actions/update-document";
|
|
36
75
|
const SESSION_PATH = "/_agent-native/auth/session";
|
|
37
76
|
const EVENTS_PATH = "/_agent-native/events";
|
|
38
77
|
const POLL_PATH = "/_agent-native/poll";
|
|
78
|
+
const COLLAB_UPDATE_PATH = /^\/_agent-native\/collab\/[^/]+\/update$/;
|
|
79
|
+
export const OUTBOX_PREFIX = "agent-native-collab-outbox-v1:";
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* The request that saves a tab's typing. A legacy page saves its whole body
|
|
83
|
+
* through update-document. A page switched to its live copy sends no body
|
|
84
|
+
* saves: its collab updates are the save, and it keeps the ones the server
|
|
85
|
+
* has not acknowledged in its outbox. Gate-on tests switch their page before
|
|
86
|
+
* any tab opens it, so the arm decides.
|
|
87
|
+
*/
|
|
88
|
+
export const BODY_SAVES: "update-document" | "collab-update" =
|
|
89
|
+
GATE_ARM === "on" ? "collab-update" : "update-document";
|
|
90
|
+
|
|
91
|
+
function savesBody(pathname: string): boolean {
|
|
92
|
+
return BODY_SAVES === "collab-update"
|
|
93
|
+
? COLLAB_UPDATE_PATH.test(pathname)
|
|
94
|
+
: pathname === SAVE_PATH;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** update-document, and on a switched page the collab updates that carry its body. */
|
|
98
|
+
function isSave(request: Request): boolean {
|
|
99
|
+
if (request.method() !== "POST") return false;
|
|
100
|
+
const { pathname } = new URL(request.url());
|
|
101
|
+
return pathname === SAVE_PATH || savesBody(pathname);
|
|
102
|
+
}
|
|
39
103
|
|
|
40
104
|
// The text a person sees when a save did not go through cleanly. Read from
|
|
41
105
|
// app/i18n-data.ts; a renamed string makes these needles go quiet, so the
|
|
@@ -53,6 +117,63 @@ export const RECOVERY_UI = [
|
|
|
53
117
|
"Something went wrong",
|
|
54
118
|
];
|
|
55
119
|
|
|
120
|
+
export interface SignInResult {
|
|
121
|
+
loginStatus: number;
|
|
122
|
+
loginError?: string;
|
|
123
|
+
registerStatus?: number;
|
|
124
|
+
registerError?: string;
|
|
125
|
+
sessionEmail?: string;
|
|
126
|
+
firstRunStatus?: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Sign the request's browser context in as `email`, registering the account
|
|
131
|
+
* the first time this database sees it, and complete first-run so its survey
|
|
132
|
+
* does not cover the page. Every call goes through the request client: the
|
|
133
|
+
* sign-in page reloads once a session appears, which destroys a page script
|
|
134
|
+
* still awaiting the login.
|
|
135
|
+
*/
|
|
136
|
+
export async function signInAccount(
|
|
137
|
+
request: APIRequestContext,
|
|
138
|
+
baseURL: string,
|
|
139
|
+
account: { email: string; password: string; name: string },
|
|
140
|
+
): Promise<SignInResult> {
|
|
141
|
+
const headers = {
|
|
142
|
+
Origin: new URL(baseURL).origin,
|
|
143
|
+
Referer: new URL("/sign-in", baseURL).href,
|
|
144
|
+
};
|
|
145
|
+
const credentials = { email: account.email, password: account.password };
|
|
146
|
+
const logIn = () =>
|
|
147
|
+
request.post("/_agent-native/auth/login", { data: credentials, headers });
|
|
148
|
+
let login = await logIn();
|
|
149
|
+
const result: SignInResult = { loginStatus: login.status() };
|
|
150
|
+
if (!login.ok()) {
|
|
151
|
+
const register = await request.post("/_agent-native/auth/register", {
|
|
152
|
+
data: { ...credentials, name: account.name, callbackURL: "/" },
|
|
153
|
+
headers,
|
|
154
|
+
});
|
|
155
|
+
result.registerStatus = register.status();
|
|
156
|
+
if (!register.ok())
|
|
157
|
+
result.registerError = (await register.text()).slice(0, 300);
|
|
158
|
+
login = await logIn();
|
|
159
|
+
result.loginStatus = login.status();
|
|
160
|
+
if (!login.ok()) result.loginError = (await login.text()).slice(0, 300);
|
|
161
|
+
}
|
|
162
|
+
const session = await request.get(SESSION_PATH, {
|
|
163
|
+
headers: { Accept: "application/json" },
|
|
164
|
+
});
|
|
165
|
+
if (session.ok())
|
|
166
|
+
result.sessionEmail = ((await session.json()) as { email?: string }).email;
|
|
167
|
+
if (login.ok()) {
|
|
168
|
+
const firstRun = await request.post(
|
|
169
|
+
"/_agent-native/onboarding/first-run/complete",
|
|
170
|
+
{ data: {}, headers },
|
|
171
|
+
);
|
|
172
|
+
result.firstRunStatus = firstRun.status();
|
|
173
|
+
}
|
|
174
|
+
return result;
|
|
175
|
+
}
|
|
176
|
+
|
|
56
177
|
/**
|
|
57
178
|
* Actions that need approval run over HTTP only for the signed-in app UI, which
|
|
58
179
|
* proves itself with this capability cookie. A spec that calls one directly
|
|
@@ -78,6 +199,30 @@ export async function postAction<T = Record<string, unknown>>(
|
|
|
78
199
|
return JSON.parse(text) as T;
|
|
79
200
|
}
|
|
80
201
|
|
|
202
|
+
/**
|
|
203
|
+
* POST a uiOnly action the way the app UI does. The server answers those only
|
|
204
|
+
* for a same-origin request carrying the capability cookie that
|
|
205
|
+
* /_agent-native/ui-capability sets; without either it refuses with 403
|
|
206
|
+
* ui_capability_required, which the caller must see as a failure.
|
|
207
|
+
*/
|
|
208
|
+
export async function postUiAction(
|
|
209
|
+
page: Page,
|
|
210
|
+
name: string,
|
|
211
|
+
data: Record<string, unknown>,
|
|
212
|
+
) {
|
|
213
|
+
const capability = await page.request.get("/_agent-native/ui-capability", {
|
|
214
|
+
headers: ACTION_HEADERS,
|
|
215
|
+
});
|
|
216
|
+
expect(
|
|
217
|
+
capability.ok(),
|
|
218
|
+
`ui-capability (${capability.status()}): ${await capability.text()}`,
|
|
219
|
+
).toBe(true);
|
|
220
|
+
return page.request.post(`/_agent-native/actions/${name}`, {
|
|
221
|
+
data,
|
|
222
|
+
headers: { ...ACTION_HEADERS, Origin: new URL(capability.url()).origin },
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
81
226
|
export async function getDocument(page: Page, id: string) {
|
|
82
227
|
const response = await page.request.get(
|
|
83
228
|
"/_agent-native/actions/get-document",
|
|
@@ -168,13 +313,18 @@ export class Markers {
|
|
|
168
313
|
}
|
|
169
314
|
|
|
170
315
|
/** Open a page and wait until its editor accepts input. */
|
|
171
|
-
export async function gotoEditor(
|
|
316
|
+
export async function gotoEditor(
|
|
317
|
+
page: Page,
|
|
318
|
+
id: string,
|
|
319
|
+
{ tabs, label = "editor" }: { tabs?: TabSet; label?: string } = {},
|
|
320
|
+
): Promise<void> {
|
|
321
|
+
if (tabs) await tabs.track(label, page);
|
|
172
322
|
await page.goto(`/page/${id}`, { waitUntil: "domcontentloaded" });
|
|
173
323
|
await expectEditorReady(page);
|
|
174
324
|
}
|
|
175
325
|
|
|
176
326
|
export async function expectEditorReady(page: Page): Promise<void> {
|
|
177
|
-
await expect(page.locator(
|
|
327
|
+
await expect(page.locator(ACTIVE_EDITOR)).toHaveAttribute(
|
|
178
328
|
"contenteditable",
|
|
179
329
|
"true",
|
|
180
330
|
{ timeout: 60_000 },
|
|
@@ -245,6 +395,33 @@ const OBSERVER = `
|
|
|
245
395
|
})();
|
|
246
396
|
`;
|
|
247
397
|
|
|
398
|
+
const CLIENT_SAVE_PATH =
|
|
399
|
+
/^\/_agent-native\/(?:actions\/update-document|collab\/[^/]+\/update)$/;
|
|
400
|
+
|
|
401
|
+
// Counts the saves a tab's own code still awaits. A save the tab gives up on,
|
|
402
|
+
// such as one its collab client aborts and resends, leaves this count even when
|
|
403
|
+
// the browser never reports a response for it, which a count of intercepted
|
|
404
|
+
// requests cannot tell from a save still on its way.
|
|
405
|
+
const PENDING_SAVES = `
|
|
406
|
+
(() => {
|
|
407
|
+
const save = new RegExp(${JSON.stringify(CLIENT_SAVE_PATH.source)});
|
|
408
|
+
const send = globalThis.fetch;
|
|
409
|
+
globalThis.__pendingSaves = 0;
|
|
410
|
+
globalThis.fetch = function (input, init) {
|
|
411
|
+
const request = input instanceof Request ? input : null;
|
|
412
|
+
const method = String(init?.method ?? request?.method ?? "GET").toUpperCase();
|
|
413
|
+
const url = new URL(request ? request.url : String(input), location.href);
|
|
414
|
+
if (method !== "POST" || !save.test(url.pathname))
|
|
415
|
+
return send.apply(this, arguments);
|
|
416
|
+
globalThis.__pendingSaves++;
|
|
417
|
+
const settle = () => { globalThis.__pendingSaves--; };
|
|
418
|
+
const sent = send.apply(this, arguments);
|
|
419
|
+
sent.then(settle, settle);
|
|
420
|
+
return sent;
|
|
421
|
+
};
|
|
422
|
+
})();
|
|
423
|
+
`;
|
|
424
|
+
|
|
248
425
|
export type SaveOutcome =
|
|
249
426
|
| "written"
|
|
250
427
|
| "replayed"
|
|
@@ -268,7 +445,7 @@ export interface TabRecord {
|
|
|
268
445
|
* `stranded` for a save still in flight when its page went away.
|
|
269
446
|
*/
|
|
270
447
|
saveCodes: Record<string, number>;
|
|
271
|
-
/** Answers to
|
|
448
|
+
/** Answers to aborted saves, which already count once in `saveOutcomes`. */
|
|
272
449
|
lateSaveOutcomes: Partial<Record<SaveOutcome, number>>;
|
|
273
450
|
saveLineage: SaveLineageEvent[];
|
|
274
451
|
saveLineageDropped: number;
|
|
@@ -370,6 +547,35 @@ export async function classifySave(response: SaveAnswer): Promise<{
|
|
|
370
547
|
return { outcome: "written", bodyState, body };
|
|
371
548
|
}
|
|
372
549
|
|
|
550
|
+
/** The save-code prefix of a collab update the server did not build the body from. */
|
|
551
|
+
export const NOT_DERIVED = "live-copy:not_derived:";
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* A collab update's answer on a switched page. The tab drops an update from
|
|
555
|
+
* its outbox only on a readable acknowledgment, and `not_derived` sends it
|
|
556
|
+
* back to update-document saves for the rest of the visit.
|
|
557
|
+
*/
|
|
558
|
+
async function classifyCollabUpdate(
|
|
559
|
+
response: SaveAnswer,
|
|
560
|
+
): Promise<{ outcome: SaveOutcome; code?: string }> {
|
|
561
|
+
if (!response.ok())
|
|
562
|
+
return { outcome: "refused", code: `HTTP ${response.status()}` };
|
|
563
|
+
let ack: { liveCopy?: unknown; liveCopyReason?: unknown } | null;
|
|
564
|
+
try {
|
|
565
|
+
ack = JSON.parse(await response.text()) as typeof ack;
|
|
566
|
+
} catch {
|
|
567
|
+
// coercion-ok: the tab keeps and resends an update whose acknowledgment it
|
|
568
|
+
// cannot read, so the tally counts it as refused, under its own code.
|
|
569
|
+
return { outcome: "refused", code: "collab-update:unreadable-ack" };
|
|
570
|
+
}
|
|
571
|
+
if (ack?.liveCopy === "not_derived")
|
|
572
|
+
return {
|
|
573
|
+
outcome: "written",
|
|
574
|
+
code: `${NOT_DERIVED}${String(ack.liveCopyReason ?? "no reason")}`,
|
|
575
|
+
};
|
|
576
|
+
return { outcome: "written" };
|
|
577
|
+
}
|
|
578
|
+
|
|
373
579
|
export function isCollabPollQuery(params: URLSearchParams): boolean {
|
|
374
580
|
const since = params.get("since");
|
|
375
581
|
const cursor = params.has("cursor");
|
|
@@ -392,6 +598,7 @@ const tabSets = new WeakMap<BrowserContext, TabSet>();
|
|
|
392
598
|
* visibility shim and the observer. Unless the server already refuses it, every
|
|
393
599
|
* realtime stream request is answered 204, as a Netlify function answers it,
|
|
394
600
|
* so both tabs fall back to the 12 s poll that beta and production run on.
|
|
601
|
+
* Saves are counted and timed as `BODY_SAVES` describes.
|
|
395
602
|
*/
|
|
396
603
|
export class TabSet {
|
|
397
604
|
readonly tabs = new Map<Page, TabRecord>();
|
|
@@ -405,6 +612,7 @@ export class TabSet {
|
|
|
405
612
|
>();
|
|
406
613
|
private readonly activeSaveLineage = new Set<UpdateDocumentRequestLineage>();
|
|
407
614
|
private readonly inFlight = new Set<Request>();
|
|
615
|
+
private readonly recordsByRequest = new WeakMap<Request, TabRecord>();
|
|
408
616
|
// Once a tab's document is gone, Playwright drops the saves it had in flight:
|
|
409
617
|
// no answer or failure event follows, and a SaveGate's continue() or fulfill()
|
|
410
618
|
// resolves. The set numbers each tab's documents so it can settle them itself.
|
|
@@ -428,6 +636,7 @@ export class TabSet {
|
|
|
428
636
|
tabSets.set(context, set);
|
|
429
637
|
await context.addInitScript(TAB_VISIBILITY);
|
|
430
638
|
await context.addInitScript(OBSERVER);
|
|
639
|
+
await context.addInitScript(PENDING_SAVES);
|
|
431
640
|
await context.exposeBinding(
|
|
432
641
|
"__convergenceReport",
|
|
433
642
|
({ page }, kind: string, detail: string) =>
|
|
@@ -446,6 +655,12 @@ export class TabSet {
|
|
|
446
655
|
|
|
447
656
|
async open(label: string, id: string, page?: Page): Promise<Page> {
|
|
448
657
|
const tab = page ?? (await this.context.newPage());
|
|
658
|
+
await this.track(label, tab);
|
|
659
|
+
await gotoEditor(tab, id);
|
|
660
|
+
return tab;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
async track(label: string, tab: Page): Promise<void> {
|
|
449
664
|
this.tabs.set(tab, emptyTab(label));
|
|
450
665
|
tab.on("load", () => {
|
|
451
666
|
const record = this.tabs.get(tab);
|
|
@@ -462,8 +677,6 @@ export class TabSet {
|
|
|
462
677
|
});
|
|
463
678
|
await cdp.send("Page.enable");
|
|
464
679
|
tab.on("close", () => this.leaveDocument(tab));
|
|
465
|
-
await gotoEditor(tab, id);
|
|
466
|
-
return tab;
|
|
467
680
|
}
|
|
468
681
|
|
|
469
682
|
record(page: Page): TabRecord {
|
|
@@ -509,9 +722,28 @@ export class TabSet {
|
|
|
509
722
|
.toBeGreaterThanOrEqual(count);
|
|
510
723
|
}
|
|
511
724
|
|
|
725
|
+
/**
|
|
726
|
+
* Wait until everything a tab has typed is saved. A legacy tab saves it in
|
|
727
|
+
* one debounced save. A switched tab sends its collab updates one at a
|
|
728
|
+
* time, so its first can be answered while the rest still wait to go; its
|
|
729
|
+
* typing is saved once its outbox is empty.
|
|
730
|
+
*/
|
|
731
|
+
async waitForTypingSaved(page: Page, documentId: string): Promise<void> {
|
|
732
|
+
await this.waitForSaveAnswers(page, 1);
|
|
733
|
+
if (BODY_SAVES === "update-document") return;
|
|
734
|
+
await expect
|
|
735
|
+
.poll(() => outboxEntries(page, documentId), {
|
|
736
|
+
message: `${this.record(page).label}'s outbox should empty once its updates are answered`,
|
|
737
|
+
timeout: 30_000,
|
|
738
|
+
})
|
|
739
|
+
.toEqual([]);
|
|
740
|
+
}
|
|
741
|
+
|
|
512
742
|
/** Wait until an open tab's editor shows text another tab or agent wrote. */
|
|
513
743
|
async waitForText(page: Page, text: string): Promise<void> {
|
|
514
|
-
await expect(page.locator(
|
|
744
|
+
await expect(page.locator(ACTIVE_EDITOR)).toContainText(text, {
|
|
745
|
+
timeout: 30_000,
|
|
746
|
+
});
|
|
515
747
|
}
|
|
516
748
|
|
|
517
749
|
/** Wait for every classified save response the tabs have produced. */
|
|
@@ -539,38 +771,74 @@ export class TabSet {
|
|
|
539
771
|
}
|
|
540
772
|
|
|
541
773
|
/**
|
|
542
|
-
* Wait until
|
|
543
|
-
*
|
|
544
|
-
*
|
|
774
|
+
* Wait until every open tab's client awaits no save and has no outbox
|
|
775
|
+
* update, and no save is on the wire or being fetched at a gate. Reloading
|
|
776
|
+
* before both settle would race the refresh check with the last save.
|
|
545
777
|
*/
|
|
546
778
|
async quiet(): Promise<void> {
|
|
547
779
|
await expect
|
|
548
|
-
.poll(
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
780
|
+
.poll(
|
|
781
|
+
async () => [...(await this.unsettledClients()), ...this.unanswered()],
|
|
782
|
+
{
|
|
783
|
+
message:
|
|
784
|
+
"a client, outbox or save answer is still pending after the scenario ended",
|
|
785
|
+
timeout: CONVERGENCE_DEADLINE_MS,
|
|
786
|
+
},
|
|
787
|
+
)
|
|
552
788
|
.toEqual([]);
|
|
553
789
|
await this.settled();
|
|
554
790
|
}
|
|
555
791
|
|
|
792
|
+
private async unsettledClients(): Promise<string[]> {
|
|
793
|
+
const unsettled: string[] = [];
|
|
794
|
+
for (const [page, record] of this.tabs) {
|
|
795
|
+
if (page.isClosed()) continue;
|
|
796
|
+
const state = await page
|
|
797
|
+
.evaluate((prefix) => {
|
|
798
|
+
let outbox = 0;
|
|
799
|
+
for (let index = 0; index < localStorage.length; index++) {
|
|
800
|
+
const key = localStorage.key(index);
|
|
801
|
+
if (key?.startsWith(prefix) && localStorage.getItem(key)) outbox++;
|
|
802
|
+
}
|
|
803
|
+
const pending = (globalThis as { __pendingSaves?: unknown })
|
|
804
|
+
.__pendingSaves;
|
|
805
|
+
return {
|
|
806
|
+
pending: typeof pending === "number" ? pending : null,
|
|
807
|
+
outbox,
|
|
808
|
+
};
|
|
809
|
+
}, OUTBOX_PREFIX)
|
|
810
|
+
.catch((error: unknown) => String(error).slice(0, 120));
|
|
811
|
+
if (typeof state === "string")
|
|
812
|
+
unsettled.push(`${record.label}: unreadable (${state})`);
|
|
813
|
+
else if (state.pending === null)
|
|
814
|
+
unsettled.push(`${record.label}: its save counter never loaded`);
|
|
815
|
+
else if (state.pending > 0 || state.outbox > 0)
|
|
816
|
+
unsettled.push(
|
|
817
|
+
`${record.label}: ${state.pending} saves awaited, ${state.outbox} outbox entries`,
|
|
818
|
+
);
|
|
819
|
+
}
|
|
820
|
+
return unsettled;
|
|
821
|
+
}
|
|
822
|
+
|
|
556
823
|
/** True once a save's page went away with the save in flight. */
|
|
557
824
|
isStranded(request: Request): boolean {
|
|
558
825
|
return this.stranded.has(request);
|
|
559
826
|
}
|
|
560
827
|
|
|
561
828
|
/**
|
|
562
|
-
* Fetch the answer to a save a SaveGate holds, and keep it.
|
|
563
|
-
*
|
|
829
|
+
* Fetch the answer to a save a SaveGate holds, and keep it. If the save
|
|
830
|
+
* already settled, the set records the answer as late instead.
|
|
564
831
|
* The fetch outlives the save's page, so `quiet()` waits for it either way.
|
|
565
832
|
*/
|
|
566
833
|
async fetchAnswer<T extends SaveAnswer>(
|
|
567
834
|
request: Request,
|
|
568
835
|
fetch: () => Promise<T>,
|
|
569
836
|
): Promise<T> {
|
|
837
|
+
this.recordOf(request);
|
|
570
838
|
this.fetching.add(request);
|
|
571
839
|
try {
|
|
572
840
|
const answer = await fetch();
|
|
573
|
-
if (this.
|
|
841
|
+
if (!this.inFlight.has(request)) this.recordAnswer(request, answer);
|
|
574
842
|
else this.heldAnswers.set(request, answer);
|
|
575
843
|
return answer;
|
|
576
844
|
} finally {
|
|
@@ -587,8 +855,6 @@ export class TabSet {
|
|
|
587
855
|
if (sender?.tab !== tab || sender.document !== document) continue;
|
|
588
856
|
this.stranded.add(request);
|
|
589
857
|
this.settleAborted(request, "stranded");
|
|
590
|
-
const answer = this.heldAnswers.get(request);
|
|
591
|
-
if (answer) this.recordAnswer(request, answer);
|
|
592
858
|
}
|
|
593
859
|
}
|
|
594
860
|
|
|
@@ -606,6 +872,8 @@ export class TabSet {
|
|
|
606
872
|
this.activeSaveLineage.delete(lineage.entry);
|
|
607
873
|
this.saveLineage.failRequest(lineage.entry);
|
|
608
874
|
}
|
|
875
|
+
const answer = this.heldAnswers.get(request);
|
|
876
|
+
if (answer) this.recordAnswer(request, answer);
|
|
609
877
|
}
|
|
610
878
|
|
|
611
879
|
/**
|
|
@@ -621,8 +889,9 @@ export class TabSet {
|
|
|
621
889
|
}
|
|
622
890
|
|
|
623
891
|
private recordOf(request: Request): TabRecord {
|
|
624
|
-
const
|
|
625
|
-
|
|
892
|
+
const record = this.recordsByRequest.get(request);
|
|
893
|
+
if (!record) throw new Error("save answer has no tracked request");
|
|
894
|
+
return record;
|
|
626
895
|
}
|
|
627
896
|
|
|
628
897
|
diagnosticSnapshot() {
|
|
@@ -632,6 +901,8 @@ export class TabSet {
|
|
|
632
901
|
|
|
633
902
|
return {
|
|
634
903
|
savesInFlight: this.inFlight.size,
|
|
904
|
+
pendingAnswerFetches: this.fetching.size,
|
|
905
|
+
unanswered: this.unanswered(),
|
|
635
906
|
retainedLineageInFlight: activeLineageOrders.length,
|
|
636
907
|
unmatchedSavesInFlight: this.inFlight.size - activeLineageOrders.length,
|
|
637
908
|
activeLineageOrders,
|
|
@@ -640,6 +911,7 @@ export class TabSet {
|
|
|
640
911
|
saveRequests: record.saveRequests,
|
|
641
912
|
saveOutcomes: record.saveOutcomes,
|
|
642
913
|
saveCodes: record.saveCodes,
|
|
914
|
+
lateSaveOutcomes: record.lateSaveOutcomes,
|
|
643
915
|
saveLineage: record.saveLineage,
|
|
644
916
|
saveLineageDropped: record.saveLineageDropped,
|
|
645
917
|
saveDurationsMs: record.saveDurationsMs,
|
|
@@ -669,14 +941,19 @@ export class TabSet {
|
|
|
669
941
|
const url = new URL(request.url());
|
|
670
942
|
const page = pageOf(request);
|
|
671
943
|
const record = (page && this.tabs.get(page)) || this.detached;
|
|
672
|
-
if (
|
|
944
|
+
if (isSave(request)) {
|
|
945
|
+
if (this.recordsByRequest.has(request)) return;
|
|
673
946
|
record.saveRequests++;
|
|
674
947
|
this.inFlight.add(request);
|
|
675
948
|
this.sentAt.set(request, Date.now());
|
|
949
|
+
this.recordsByRequest.set(request, record);
|
|
676
950
|
const document = page ? this.documents.get(page) : undefined;
|
|
677
951
|
if (page && document !== undefined)
|
|
678
952
|
this.documentOf.set(request, { tab: page, document });
|
|
679
|
-
const entry =
|
|
953
|
+
const entry =
|
|
954
|
+
url.pathname === SAVE_PATH
|
|
955
|
+
? this.saveLineage.captureRequest(record, request.postData())
|
|
956
|
+
: undefined;
|
|
680
957
|
if (entry) {
|
|
681
958
|
this.lineageByRequest.set(request, { record, entry });
|
|
682
959
|
this.activeSaveLineage.add(entry);
|
|
@@ -700,7 +977,7 @@ export class TabSet {
|
|
|
700
977
|
if (response.status() === 200) record.realtimeStreams++;
|
|
701
978
|
return;
|
|
702
979
|
}
|
|
703
|
-
if (
|
|
980
|
+
if (!isSave(request)) return;
|
|
704
981
|
this.recordAnswer(request, response);
|
|
705
982
|
}
|
|
706
983
|
|
|
@@ -708,15 +985,27 @@ export class TabSet {
|
|
|
708
985
|
// A reload racing a gate's release can deliver both the gate's held copy
|
|
709
986
|
// of an answer and the tab's own; the first one is the save's answer.
|
|
710
987
|
if (this.answered.has(request)) return;
|
|
988
|
+
const record = this.recordOf(request);
|
|
711
989
|
this.answered.add(request);
|
|
712
990
|
this.heldAnswers.delete(request);
|
|
713
|
-
|
|
714
|
-
// A save settled as stranded already counted once, as aborted. Its answer
|
|
991
|
+
// A save settled as aborted already counted once. Its answer
|
|
715
992
|
// is still the server's word on it, so a History diversion stays noise.
|
|
716
993
|
const late = !this.inFlight.delete(request);
|
|
717
994
|
const sentAt = this.sentAt.get(request);
|
|
718
|
-
if (
|
|
995
|
+
if (
|
|
996
|
+
!late &&
|
|
997
|
+
sentAt !== undefined &&
|
|
998
|
+
savesBody(new URL(request.url()).pathname)
|
|
999
|
+
)
|
|
719
1000
|
record.saveDurationsMs.push(Date.now() - sentAt);
|
|
1001
|
+
if (new URL(request.url()).pathname !== SAVE_PATH) {
|
|
1002
|
+
this.pending.push(
|
|
1003
|
+
classifyCollabUpdate(answer).then(({ outcome, code }) =>
|
|
1004
|
+
tallySave(record, outcome, code, late),
|
|
1005
|
+
),
|
|
1006
|
+
);
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
720
1009
|
const lineage = this.lineageByRequest.get(request);
|
|
721
1010
|
const lineageResponse = lineage
|
|
722
1011
|
? this.saveLineage.beginResponse(lineage.entry, answer.status())
|
|
@@ -731,31 +1020,36 @@ export class TabSet {
|
|
|
731
1020
|
bodyState,
|
|
732
1021
|
bodyState === "valid" ? body : undefined,
|
|
733
1022
|
);
|
|
734
|
-
|
|
735
|
-
outcomes[outcome] = (outcomes[outcome] ?? 0) + 1;
|
|
736
|
-
if (code) record.saveCodes[code] = (record.saveCodes[code] ?? 0) + 1;
|
|
1023
|
+
tallySave(record, outcome, code, late);
|
|
737
1024
|
}),
|
|
738
1025
|
);
|
|
739
1026
|
}
|
|
740
1027
|
|
|
741
1028
|
private onRequestFailed(request: Request) {
|
|
742
|
-
if (
|
|
743
|
-
new URL(request.url()).pathname !== SAVE_PATH ||
|
|
744
|
-
request.method() !== "POST"
|
|
745
|
-
)
|
|
746
|
-
return;
|
|
1029
|
+
if (!isSave(request)) return;
|
|
747
1030
|
this.settleAborted(request);
|
|
748
1031
|
}
|
|
749
1032
|
}
|
|
750
1033
|
|
|
1034
|
+
function tallySave(
|
|
1035
|
+
record: TabRecord,
|
|
1036
|
+
outcome: SaveOutcome,
|
|
1037
|
+
code?: string,
|
|
1038
|
+
late = false,
|
|
1039
|
+
) {
|
|
1040
|
+
const outcomes = late ? record.lateSaveOutcomes : record.saveOutcomes;
|
|
1041
|
+
outcomes[outcome] = (outcomes[outcome] ?? 0) + 1;
|
|
1042
|
+
if (code) record.saveCodes[code] = (record.saveCodes[code] ?? 0) + 1;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
751
1045
|
type Held = { release: () => Promise<void> };
|
|
752
1046
|
type HeldSave = Held & { request: Request; cutOff: () => Promise<void> };
|
|
753
1047
|
|
|
754
1048
|
/**
|
|
755
|
-
* Controls when one tab's saves reach the server and
|
|
756
|
-
* reach the tab. Holding at arrival keeps a save unsent;
|
|
757
|
-
* lets the server apply it while the tab still thinks it is
|
|
758
|
-
* make a race happen in the same order on every run.
|
|
1049
|
+
* Controls when one tab's body saves (see `BODY_SAVES`) reach the server and
|
|
1050
|
+
* when their answers reach the tab. Holding at arrival keeps a save unsent;
|
|
1051
|
+
* holding the answer lets the server apply it while the tab still thinks it is
|
|
1052
|
+
* in flight. Both make a race happen in the same order on every run.
|
|
759
1053
|
*/
|
|
760
1054
|
export class SaveGate {
|
|
761
1055
|
private mode: "pass" | "arrival" | "answer" = "pass";
|
|
@@ -773,7 +1067,7 @@ export class SaveGate {
|
|
|
773
1067
|
if (!tabs) throw new Error("a SaveGate's page must belong to a TabSet");
|
|
774
1068
|
const gate = new SaveGate(page, tabs);
|
|
775
1069
|
await page.route(
|
|
776
|
-
(url) => url.pathname
|
|
1070
|
+
(url) => savesBody(url.pathname),
|
|
777
1071
|
(route) => gate.handle(route),
|
|
778
1072
|
);
|
|
779
1073
|
return gate;
|
|
@@ -932,6 +1226,34 @@ async function forward(send: () => Promise<void>): Promise<void> {
|
|
|
932
1226
|
}
|
|
933
1227
|
}
|
|
934
1228
|
|
|
1229
|
+
/**
|
|
1230
|
+
* The outbox keys a switched page holds in this browser: collab updates the
|
|
1231
|
+
* server has not acknowledged, one entry per connection. Tabs of one browser
|
|
1232
|
+
* share it, and an entry leaves once its updates are acknowledged.
|
|
1233
|
+
*/
|
|
1234
|
+
export async function outboxEntries(
|
|
1235
|
+
page: Page,
|
|
1236
|
+
documentId: string,
|
|
1237
|
+
): Promise<string[]> {
|
|
1238
|
+
return page.evaluate(
|
|
1239
|
+
({ prefix, doc }) => {
|
|
1240
|
+
const keys: string[] = [];
|
|
1241
|
+
for (let index = 0; index < localStorage.length; index++) {
|
|
1242
|
+
const key = localStorage.key(index);
|
|
1243
|
+
if (
|
|
1244
|
+
key?.startsWith(prefix) &&
|
|
1245
|
+
key.includes(doc) &&
|
|
1246
|
+
localStorage.getItem(key)
|
|
1247
|
+
)
|
|
1248
|
+
keys.push(key);
|
|
1249
|
+
}
|
|
1250
|
+
return keys;
|
|
1251
|
+
},
|
|
1252
|
+
// A key names the doc as encodeURIComponent(`${baseUrl}\0${docId}`).
|
|
1253
|
+
{ prefix: OUTBOX_PREFIX, doc: `%00${encodeURIComponent(documentId)}:` },
|
|
1254
|
+
);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
935
1257
|
export function delay(ms: number): Promise<void> {
|
|
936
1258
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
937
1259
|
}
|
|
@@ -946,7 +1268,7 @@ export async function typeAtParagraphEnd(
|
|
|
946
1268
|
const snapshot = await page.evaluate(captureFixtureInput, {
|
|
947
1269
|
phase,
|
|
948
1270
|
text,
|
|
949
|
-
editor:
|
|
1271
|
+
editor: ACTIVE_EDITOR,
|
|
950
1272
|
});
|
|
951
1273
|
if (!snapshot) return;
|
|
952
1274
|
await page.evaluate((detail) => {
|
|
@@ -959,39 +1281,93 @@ export async function typeAtParagraphEnd(
|
|
|
959
1281
|
}, JSON.stringify(snapshot));
|
|
960
1282
|
};
|
|
961
1283
|
await capture("before-caret");
|
|
962
|
-
await page
|
|
963
|
-
|
|
1284
|
+
await page
|
|
1285
|
+
.locator(`${ACTIVE_EDITOR} > p`, { hasText: anchor })
|
|
1286
|
+
.first()
|
|
1287
|
+
.click();
|
|
1288
|
+
// "End" stops at a wrapped visual line, and a caret set only in the DOM is
|
|
1289
|
+
// lost when a remote update re-renders before ProseMirror reads it: the
|
|
1290
|
+
// keys then land where the click put them. Set it in the editor's state.
|
|
964
1291
|
await page.evaluate(
|
|
965
1292
|
({ needle, editor }) => {
|
|
966
|
-
const
|
|
967
|
-
(
|
|
968
|
-
);
|
|
969
|
-
if (!
|
|
970
|
-
const
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
}
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
if (!last) throw new Error(`No text in ${needle}`);
|
|
985
|
-
const range = document.createRange();
|
|
986
|
-
range.setStart(last, last.length);
|
|
987
|
-
const selection = window.getSelection()!;
|
|
988
|
-
selection.removeAllRanges();
|
|
989
|
-
selection.addRange(range);
|
|
1293
|
+
const tiptap = (
|
|
1294
|
+
document.querySelector(editor) as (Element & { editor?: Editor }) | null
|
|
1295
|
+
)?.editor;
|
|
1296
|
+
if (!tiptap) throw new Error(`No TipTap editor on ${editor}`);
|
|
1297
|
+
const { doc } = tiptap.state;
|
|
1298
|
+
for (let index = 0, offset = 0; index < doc.childCount; index++) {
|
|
1299
|
+
const node = doc.child(index);
|
|
1300
|
+
if (
|
|
1301
|
+
node.type.name === "paragraph" &&
|
|
1302
|
+
node.textContent.includes(needle)
|
|
1303
|
+
) {
|
|
1304
|
+
tiptap.commands.setTextSelection(offset + node.nodeSize - 1);
|
|
1305
|
+
tiptap.view.focus();
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
offset += node.nodeSize;
|
|
1309
|
+
}
|
|
1310
|
+
throw new Error(`No paragraph contains ${needle}`);
|
|
990
1311
|
},
|
|
991
|
-
{ needle: anchor, editor:
|
|
1312
|
+
{ needle: anchor, editor: ACTIVE_EDITOR },
|
|
992
1313
|
);
|
|
993
1314
|
await page.keyboard.type(text, { delay: delayMs });
|
|
994
1315
|
await capture("after-input");
|
|
1316
|
+
await expectTypedAtEnd(page, anchor, text);
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
/**
|
|
1320
|
+
* Stop when the keys typed into a paragraph do not end it: a marker typed
|
|
1321
|
+
* into another breaks both, and the counts after would report a loss. The
|
|
1322
|
+
* text alone cannot say whether the caret moved before the keys landed or
|
|
1323
|
+
* the editor moved them after, so the error names neither as the cause.
|
|
1324
|
+
*/
|
|
1325
|
+
async function expectTypedAtEnd(
|
|
1326
|
+
page: Page,
|
|
1327
|
+
anchor: string,
|
|
1328
|
+
text: string,
|
|
1329
|
+
): Promise<void> {
|
|
1330
|
+
// A space typed at a paragraph's end can arrive as a no-break space.
|
|
1331
|
+
const spaced = (value: string) => value.replace(/\s/g, " ");
|
|
1332
|
+
const typed = spaced(text);
|
|
1333
|
+
const deadline = Date.now() + 2_000;
|
|
1334
|
+
for (;;) {
|
|
1335
|
+
const read = await page.evaluate(
|
|
1336
|
+
({ needle, editor }) => {
|
|
1337
|
+
const tiptap = (
|
|
1338
|
+
document.querySelector(editor) as
|
|
1339
|
+
| (Element & { editor?: Editor })
|
|
1340
|
+
| null
|
|
1341
|
+
)?.editor;
|
|
1342
|
+
if (!tiptap) throw new Error(`No TipTap editor on ${editor}`);
|
|
1343
|
+
const { doc } = tiptap.state;
|
|
1344
|
+
let paragraph: string | null = null;
|
|
1345
|
+
for (
|
|
1346
|
+
let index = 0;
|
|
1347
|
+
index < doc.childCount && paragraph === null;
|
|
1348
|
+
index++
|
|
1349
|
+
) {
|
|
1350
|
+
const node = doc.child(index);
|
|
1351
|
+
if (
|
|
1352
|
+
node.type.name === "paragraph" &&
|
|
1353
|
+
node.textContent.includes(needle)
|
|
1354
|
+
)
|
|
1355
|
+
paragraph = node.textContent;
|
|
1356
|
+
}
|
|
1357
|
+
return { paragraph, body: doc.textContent };
|
|
1358
|
+
},
|
|
1359
|
+
{ needle: anchor, editor: ACTIVE_EDITOR },
|
|
1360
|
+
);
|
|
1361
|
+
if (read.paragraph !== null && spaced(read.paragraph).endsWith(typed))
|
|
1362
|
+
return;
|
|
1363
|
+
if (Date.now() > deadline)
|
|
1364
|
+
throw new Error(
|
|
1365
|
+
spaced(read.body).includes(typed.trim())
|
|
1366
|
+
? `The keys typed for ${JSON.stringify(typed)} are in the editor, but the paragraph containing ${JSON.stringify(anchor)} does not end with them: it reads ${JSON.stringify(read.paragraph)}. Either the caret moved before they landed or the editor moved them after.`
|
|
1367
|
+
: `The editor does not hold the keys typed for ${JSON.stringify(typed)} at all; the paragraph containing ${JSON.stringify(anchor)} reads ${JSON.stringify(read.paragraph)}.`,
|
|
1368
|
+
);
|
|
1369
|
+
await delay(50);
|
|
1370
|
+
}
|
|
995
1371
|
}
|
|
996
1372
|
|
|
997
1373
|
/** Select `text` in the editor and delete it with the keyboard, as a person would. */
|
|
@@ -1018,10 +1394,10 @@ export async function deleteEditorText(
|
|
|
1018
1394
|
}
|
|
1019
1395
|
throw new Error(`The editor has no text node containing ${needle}`);
|
|
1020
1396
|
},
|
|
1021
|
-
{ needle: text, editor:
|
|
1397
|
+
{ needle: text, editor: ACTIVE_EDITOR },
|
|
1022
1398
|
);
|
|
1023
1399
|
await page.keyboard.press("Backspace");
|
|
1024
|
-
await expect(page.locator(
|
|
1400
|
+
await expect(page.locator(ACTIVE_EDITOR)).not.toContainText(text);
|
|
1025
1401
|
}
|
|
1026
1402
|
|
|
1027
1403
|
export function countMarkers(
|
|
@@ -1035,6 +1411,27 @@ export function countMarkers(
|
|
|
1035
1411
|
|
|
1036
1412
|
const MCP_TOKENS_PATH = "/_agent-native/mcp/connect/tokens";
|
|
1037
1413
|
|
|
1414
|
+
// The run's one shared connector, written by global setup and revoked by
|
|
1415
|
+
// global teardown. The device flow allows 20 starts a minute per server, and
|
|
1416
|
+
// the token list cannot tell apart tokens two workers mint at once, so specs
|
|
1417
|
+
// that call many tools share this connection instead of each making one.
|
|
1418
|
+
const SHARED_CONNECTOR_FILE = AUTH_FILES.connector;
|
|
1419
|
+
|
|
1420
|
+
interface SharedConnector {
|
|
1421
|
+
headers: Record<string, string>;
|
|
1422
|
+
tokenId: string | null;
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
function readSharedConnector(): SharedConnector | null {
|
|
1426
|
+
if (!existsSync(SHARED_CONNECTOR_FILE)) return null;
|
|
1427
|
+
const saved = JSON.parse(
|
|
1428
|
+
readFileSync(SHARED_CONNECTOR_FILE, "utf8"),
|
|
1429
|
+
) as Partial<SharedConnector>;
|
|
1430
|
+
if (!saved.headers || !Object.keys(saved.headers).length)
|
|
1431
|
+
throw new Error(`${SHARED_CONNECTOR_FILE} names no connector headers`);
|
|
1432
|
+
return { headers: saved.headers, tokenId: saved.tokenId ?? null };
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1038
1435
|
async function activeMcpTokenIds(page: Page): Promise<Set<string>> {
|
|
1039
1436
|
const response = await page.request.get(MCP_TOKENS_PATH);
|
|
1040
1437
|
const text = await response.text();
|
|
@@ -1117,6 +1514,35 @@ export class AgentClient {
|
|
|
1117
1514
|
return new AgentClient(page, headers, minted[0]);
|
|
1118
1515
|
}
|
|
1119
1516
|
|
|
1517
|
+
/** Connect the run's shared connector; only global setup calls this. */
|
|
1518
|
+
static async connectShared(page: Page): Promise<void> {
|
|
1519
|
+
const agent = await AgentClient.connect(page);
|
|
1520
|
+
const saved: SharedConnector = {
|
|
1521
|
+
headers: agent.connectorHeaders,
|
|
1522
|
+
tokenId: agent.tokenId,
|
|
1523
|
+
};
|
|
1524
|
+
writeFileSync(SHARED_CONNECTOR_FILE, JSON.stringify(saved));
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
/** The connector global setup made, acting through this test's page. */
|
|
1528
|
+
static shared(page: Page): AgentClient {
|
|
1529
|
+
const saved = readSharedConnector();
|
|
1530
|
+
if (!saved)
|
|
1531
|
+
throw new Error(
|
|
1532
|
+
`No shared MCP connector: global setup writes ${SHARED_CONNECTOR_FILE}.`,
|
|
1533
|
+
);
|
|
1534
|
+
// No token id: a test's disconnect() leaves the shared token alone.
|
|
1535
|
+
return new AgentClient(page, saved.headers, null);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
/** Revoke the shared connector; only global teardown calls this. */
|
|
1539
|
+
static async revokeShared(page: Page): Promise<void> {
|
|
1540
|
+
const saved = readSharedConnector();
|
|
1541
|
+
if (!saved) return;
|
|
1542
|
+
await new AgentClient(page, saved.headers, saved.tokenId).disconnect();
|
|
1543
|
+
rmSync(SHARED_CONNECTOR_FILE);
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1120
1546
|
/** Connect, apply one edit, and revoke the connection even if the edit fails. */
|
|
1121
1547
|
static async editOnce(
|
|
1122
1548
|
page: Page,
|
|
@@ -1147,29 +1573,30 @@ export class AgentClient {
|
|
|
1147
1573
|
).toBe(false);
|
|
1148
1574
|
}
|
|
1149
1575
|
|
|
1150
|
-
/**
|
|
1151
|
-
|
|
1152
|
-
|
|
1576
|
+
/**
|
|
1577
|
+
* Call one tool over the MCP transport, exactly as a connector does, and
|
|
1578
|
+
* return what the connector would see: the tool's text and whether the
|
|
1579
|
+
* server marked it an error. Transport failures fail the test.
|
|
1580
|
+
*/
|
|
1581
|
+
async call(
|
|
1582
|
+
name: string,
|
|
1583
|
+
args: Record<string, unknown>,
|
|
1584
|
+
): Promise<McpToolResult> {
|
|
1153
1585
|
const response = await this.page.request.post("/_agent-native/mcp", {
|
|
1154
1586
|
headers: {
|
|
1155
1587
|
...this.connectorHeaders,
|
|
1156
1588
|
Accept: "application/json, text/event-stream",
|
|
1157
1589
|
"mcp-protocol-version": "2026-07-28",
|
|
1158
1590
|
"mcp-method": "tools/call",
|
|
1159
|
-
"mcp-name":
|
|
1591
|
+
"mcp-name": name,
|
|
1160
1592
|
},
|
|
1161
1593
|
data: {
|
|
1162
1594
|
jsonrpc: "2.0",
|
|
1163
1595
|
id: 1,
|
|
1164
1596
|
method: "tools/call",
|
|
1165
1597
|
params: {
|
|
1166
|
-
name
|
|
1167
|
-
arguments:
|
|
1168
|
-
id,
|
|
1169
|
-
baseRevision: revision,
|
|
1170
|
-
idempotencyKey: `${id}-${find}-${Date.now()}`,
|
|
1171
|
-
edits: [{ find, replace }],
|
|
1172
|
-
},
|
|
1598
|
+
name,
|
|
1599
|
+
arguments: args,
|
|
1173
1600
|
_meta: {
|
|
1174
1601
|
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
|
|
1175
1602
|
"io.modelcontextprotocol/clientInfo": {
|
|
@@ -1182,7 +1609,7 @@ export class AgentClient {
|
|
|
1182
1609
|
},
|
|
1183
1610
|
});
|
|
1184
1611
|
const raw = await response.text();
|
|
1185
|
-
expect(response.ok(),
|
|
1612
|
+
expect(response.ok(), `${name} over MCP: ${raw}`).toBe(true);
|
|
1186
1613
|
const payload = raw.trimStart().startsWith("{")
|
|
1187
1614
|
? JSON.parse(raw)
|
|
1188
1615
|
: JSON.parse(
|
|
@@ -1192,21 +1619,93 @@ export class AgentClient {
|
|
|
1192
1619
|
.map((line) => line.slice("data:".length))
|
|
1193
1620
|
.join(""),
|
|
1194
1621
|
);
|
|
1195
|
-
expect(payload.
|
|
1196
|
-
true,
|
|
1197
|
-
);
|
|
1622
|
+
expect(payload.error, `${name} over MCP: ${raw}`).toBeUndefined();
|
|
1198
1623
|
const text = payload.result?.content?.[0]?.text;
|
|
1199
|
-
expect(typeof text,
|
|
1624
|
+
expect(typeof text, `${name} over MCP returned no text: ${raw}`).toBe(
|
|
1200
1625
|
"string",
|
|
1201
1626
|
);
|
|
1202
|
-
const
|
|
1627
|
+
const structured = payload.result?.structuredContent;
|
|
1628
|
+
return {
|
|
1629
|
+
isError: payload.result?.isError === true,
|
|
1630
|
+
text,
|
|
1631
|
+
structured:
|
|
1632
|
+
structured && typeof structured === "object" ? structured : null,
|
|
1633
|
+
raw,
|
|
1634
|
+
};
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
/**
|
|
1638
|
+
* Call a tool that must succeed and return the object a connector can read
|
|
1639
|
+
* from it: its structured content, or its text when that is JSON. A tool
|
|
1640
|
+
* that answers with prose alone fails here, naming the prose.
|
|
1641
|
+
*/
|
|
1642
|
+
async callJson<T = Record<string, any>>(
|
|
1643
|
+
name: string,
|
|
1644
|
+
args: Record<string, unknown>,
|
|
1645
|
+
): Promise<T> {
|
|
1646
|
+
const result = await this.call(name, args);
|
|
1647
|
+
expect(result.isError, `${name} over MCP: ${result.raw}`).toBe(false);
|
|
1648
|
+
if (result.structured) return result.structured as T;
|
|
1649
|
+
try {
|
|
1650
|
+
return JSON.parse(result.text) as T;
|
|
1651
|
+
} catch {
|
|
1652
|
+
throw new Error(
|
|
1653
|
+
`${name} over MCP returned prose, not a result object: ${result.text}`,
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
|
|
1658
|
+
/**
|
|
1659
|
+
* Create a page as a connector does. create-document may answer with a
|
|
1660
|
+
* one-line summary rather than a result object; a connector then finds the
|
|
1661
|
+
* new page's id in the summary's link, and so does this.
|
|
1662
|
+
*/
|
|
1663
|
+
async createPage(
|
|
1664
|
+
title: string,
|
|
1665
|
+
content: string,
|
|
1666
|
+
): Promise<{ id: string; result: McpToolResult }> {
|
|
1667
|
+
const result = await this.call("create-document", { title, content });
|
|
1668
|
+
expect(result.isError, result.raw).toBe(false);
|
|
1669
|
+
return { id: createdPageId(result), result };
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
/** Apply one find/replace and fail unless the server reports it applied. */
|
|
1673
|
+
async edit(id: string, find: string, replace: string): Promise<void> {
|
|
1674
|
+
const { revision } = await getDocument(this.page, id);
|
|
1675
|
+
const receipt = await this.callJson<{ applied?: number; total?: number }>(
|
|
1676
|
+
"edit-document",
|
|
1677
|
+
{
|
|
1678
|
+
id,
|
|
1679
|
+
baseRevision: revision,
|
|
1680
|
+
idempotencyKey: `${id}-${find}-${Date.now()}`,
|
|
1681
|
+
edits: [{ find, replace }],
|
|
1682
|
+
},
|
|
1683
|
+
);
|
|
1203
1684
|
expect(
|
|
1204
|
-
receipt.applied,
|
|
1205
|
-
`edit-document
|
|
1206
|
-
).
|
|
1685
|
+
{ applied: receipt.applied, total: receipt.total },
|
|
1686
|
+
`edit-document receipt: ${JSON.stringify(receipt)}`,
|
|
1687
|
+
).toEqual({ applied: 1, total: 1 });
|
|
1207
1688
|
}
|
|
1208
1689
|
}
|
|
1209
1690
|
|
|
1691
|
+
export interface McpToolResult {
|
|
1692
|
+
isError: boolean;
|
|
1693
|
+
text: string;
|
|
1694
|
+
/** The tool's `structuredContent`, when it sent one. */
|
|
1695
|
+
structured: Record<string, unknown> | null;
|
|
1696
|
+
raw: string;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
/** The id of the page a successful create-document over MCP made. */
|
|
1700
|
+
export function createdPageId(result: McpToolResult): string {
|
|
1701
|
+
const id =
|
|
1702
|
+
(typeof result.structured?.id === "string" && result.structured.id) ||
|
|
1703
|
+
result.text.match(/"id":\s*"([\w-]+)"/)?.[1] ||
|
|
1704
|
+
result.text.match(/\/page\/([\w-]+)/)?.[1];
|
|
1705
|
+
if (!id) throw new Error(`create-document named no page: ${result.raw}`);
|
|
1706
|
+
return id;
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1210
1709
|
export interface IntegrityObservation {
|
|
1211
1710
|
at: "deadline" | "refresh" | "reopened-alone";
|
|
1212
1711
|
surface: string;
|
|
@@ -1237,7 +1736,7 @@ function judge(
|
|
|
1237
1736
|
}
|
|
1238
1737
|
|
|
1239
1738
|
async function editorText(page: Page): Promise<string> {
|
|
1240
|
-
return page.locator(
|
|
1739
|
+
return page.locator(ACTIVE_EDITOR).innerText();
|
|
1241
1740
|
}
|
|
1242
1741
|
|
|
1243
1742
|
const CONVERGENCE_DEADLINE_MS = 45_000;
|
|
@@ -1329,10 +1828,15 @@ export interface ScenarioRecord {
|
|
|
1329
1828
|
tags: string[];
|
|
1330
1829
|
notes: Record<string, unknown>;
|
|
1331
1830
|
build: string;
|
|
1831
|
+
/** The side of the D2 live-body gate the scenario ran on. */
|
|
1832
|
+
gate: "off" | "on";
|
|
1332
1833
|
authoredEdits: number;
|
|
1333
1834
|
markers: number;
|
|
1334
1835
|
durationMs: number;
|
|
1335
|
-
|
|
1836
|
+
/** Null when the scenario stopped early, before the page was observed. */
|
|
1837
|
+
integrity: IntegrityObservation[] | null;
|
|
1838
|
+
/** Why the scenario stopped before its last step, if it did. */
|
|
1839
|
+
stoppedEarly?: string;
|
|
1336
1840
|
tabs: TabRecord[];
|
|
1337
1841
|
}
|
|
1338
1842
|
|
|
@@ -1355,6 +1859,8 @@ export function integrityProblem(entry: IntegrityObservation): boolean {
|
|
|
1355
1859
|
}
|
|
1356
1860
|
|
|
1357
1861
|
export function integrityFailures(record: ScenarioRecord): string[] {
|
|
1862
|
+
if (record.integrity === null)
|
|
1863
|
+
return [`${record.scenario} stopped before its page was observed`];
|
|
1358
1864
|
return record.integrity
|
|
1359
1865
|
.filter(integrityProblem)
|
|
1360
1866
|
.map(
|