@agent-native/core-corpus 0.219.0 → 0.220.0-nightly-20261023212848
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/SKILL.md +1 -0
- package/corpus/templates/analytics/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/analytics/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/assets/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/assets/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/brain/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/brain/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/calendar/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/calendar/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/chat/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/clips/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/clips/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/clips/app/components/recorder/storage-setup-card.tsx +146 -14
- package/corpus/templates/clips/app/routes/record.tsx +11 -0
- package/corpus/templates/clips/desktop/src/app.tsx +74 -16
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +12 -4
- package/corpus/templates/clips/desktop/src/lib/recording-request.ts +54 -0
- package/corpus/templates/clips/desktop/src/lib/url.ts +7 -1
- package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +54 -2
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +1 -0
- package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +95 -0
- package/corpus/templates/community/qr/package.json +1 -1
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +12 -0
- package/corpus/templates/content/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/content/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/content/actions/_builder-docs-client.ts +75 -28
- package/corpus/templates/content/actions/_content-database-row-migration.ts +10 -2
- package/corpus/templates/content/actions/_content-save-outcomes.ts +1 -0
- package/corpus/templates/content/actions/_database-block-actions.ts +6 -2
- package/corpus/templates/content/actions/_database-source-utils.ts +36 -3
- package/corpus/templates/content/actions/_database-utils.ts +49 -1
- package/corpus/templates/content/actions/_document-edit-mutation.ts +280 -0
- package/corpus/templates/content/actions/_document-flush.ts +13 -0
- package/corpus/templates/content/actions/_github-source-freshness.ts +2 -0
- package/corpus/templates/content/actions/_github-source-metadata.ts +15 -1
- package/corpus/templates/content/actions/_github-source.ts +1031 -345
- package/corpus/templates/content/actions/_move-page-to-space.ts +5 -0
- package/corpus/templates/content/actions/_property-utils.ts +18 -11
- package/corpus/templates/content/actions/add-comment.ts +56 -29
- package/corpus/templates/content/actions/attach-content-database-source.ts +29 -14
- package/corpus/templates/content/actions/bind-content-database-source-field.ts +18 -5
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +12 -5
- package/corpus/templates/content/actions/change-content-database-source-role.ts +13 -7
- package/corpus/templates/content/actions/create-content-database.ts +11 -4
- package/corpus/templates/content/actions/delete-document-property.ts +7 -2
- package/corpus/templates/content/actions/delete-document.ts +8 -0
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +18 -5
- package/corpus/templates/content/actions/duplicate-database-item.ts +13 -7
- package/corpus/templates/content/actions/duplicate-database-items.ts +28 -22
- package/corpus/templates/content/actions/edit-document.ts +119 -4
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +13 -5
- package/corpus/templates/content/actions/get-content-database.ts +30 -13
- package/corpus/templates/content/actions/import-content-source.ts +41 -18
- package/corpus/templates/content/actions/materialize-builder-required-fields.ts +9 -3
- package/corpus/templates/content/actions/migrate-content-database-rows.ts +29 -3
- package/corpus/templates/content/actions/move-database-item.ts +12 -6
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +8 -4
- package/corpus/templates/content/actions/preview-content-database-source-attach.ts +6 -3
- package/corpus/templates/content/actions/query-content-database-items.ts +24 -5
- package/corpus/templates/content/actions/remove-database-items.ts +19 -10
- package/corpus/templates/content/actions/resolve-local-folder-conflict.ts +6 -2
- package/corpus/templates/content/actions/restore-document-version.ts +305 -65
- package/corpus/templates/content/actions/review-content-database-source-change-set.ts +11 -4
- package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +11 -4
- package/corpus/templates/content/actions/set-document-property.ts +6 -2
- package/corpus/templates/content/actions/set-image-alt-text.ts +10 -2
- package/corpus/templates/content/actions/set-live-body-switch.ts +4 -1
- package/corpus/templates/content/actions/share-local-file-document.ts +6 -2
- package/corpus/templates/content/actions/stage-builder-revision.ts +10 -4
- package/corpus/templates/content/actions/suggest-document-edit.ts +256 -15
- package/corpus/templates/content/actions/sync-local-folder-source.ts +28 -4
- package/corpus/templates/content/actions/transcribe-media.ts +16 -2
- package/corpus/templates/content/actions/update-content-database-view.ts +8 -2
- package/corpus/templates/content/actions/update-document.ts +11 -2
- package/corpus/templates/content/actions/validate-builder-source-execution.ts +11 -4
- package/corpus/templates/content/app/components/editor/CommentComposer.tsx +142 -2
- package/corpus/templates/content/app/components/editor/CommentEntry.tsx +30 -5
- package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +707 -283
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +38 -40
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +2 -2
- package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +27 -4
- package/corpus/templates/content/app/components/editor/SuggestionReviewCard.tsx +264 -0
- package/corpus/templates/content/app/components/editor/SuggestionReviewCardSkeleton.tsx +13 -0
- package/corpus/templates/content/app/components/editor/ThreadSuggestion.tsx +3 -2
- package/corpus/templates/content/app/components/editor/block-field-comment-threads.ts +3 -2
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +16 -18
- package/corpus/templates/content/app/components/editor/database/GitHubSourceStatusLine.tsx +149 -3
- package/corpus/templates/content/app/components/editor/database/github-source-text.ts +1 -0
- package/corpus/templates/content/app/components/editor/database/navigation-state.ts +10 -3
- package/corpus/templates/content/app/components/editor/database/settings.tsx +8 -8
- package/corpus/templates/content/app/components/editor/discussion-panel.tsx +504 -0
- package/corpus/templates/content/app/components/layout/ContentStartupShell.tsx +12 -0
- package/corpus/templates/content/app/discussion-messages.ts +270 -0
- package/corpus/templates/content/app/hooks/use-comments.ts +6 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +114 -110
- package/corpus/templates/content/app/hooks/use-github-folder.ts +15 -5
- package/corpus/templates/content/app/i18n-data.ts +19 -0
- package/corpus/templates/content/app/lib/content-database-query-cache.ts +60 -0
- package/corpus/templates/content/app/root.tsx +23 -8
- package/corpus/templates/content/app/routes/suggestions.$documentId.tsx +79 -0
- package/corpus/templates/content/changelog/2026-10-21-agents-suggested-edits-show-inline-in-mcp-apps-hosts-like-cl.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-comments-panel-is-now-discussion.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-a-big-github-folder-fills-its-collection-much-faster-and-kee.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-a-github-folder-sync-keeps-going-when-file-storage-fails-fil.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-collections-with-large-select-properties-open-faster-and-use.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-pressing-escape-while-writing-a-comment-reply-or-edit-cancel.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.comment.page-owned.md +7 -7
- package/corpus/templates/content/docs/product/capabilities/content.discussion.page.md +43 -28
- package/corpus/templates/content/docs/product/encyclopedia.md +7 -7
- package/corpus/templates/content/e2e/helpers.ts +1 -1
- package/corpus/templates/content/scripts/historical-icon-apply.ts +6 -2
- package/corpus/templates/content/scripts/migrate-historical-icon-urls.ts +10 -0
- package/corpus/templates/content/server/db/schema.ts +25 -0
- package/corpus/templates/content/server/lib/comment-ai.ts +13 -17
- package/corpus/templates/content/server/lib/comment-anchor-follow.ts +107 -0
- package/corpus/templates/content/server/lib/comment-notifications.ts +3 -3
- package/corpus/templates/content/server/lib/document-body-revision.ts +159 -2
- package/corpus/templates/content/server/lib/document-body-steps.ts +182 -0
- package/corpus/templates/content/server/lib/document-history.ts +44 -0
- package/corpus/templates/content/server/lib/document-title-propagation.ts +16 -3
- package/corpus/templates/content/server/lib/github-source-client.ts +100 -12
- package/corpus/templates/content/server/lib/live-body-writer.ts +96 -15
- package/corpus/templates/content/server/lib/notion-sync.ts +109 -11
- package/corpus/templates/content/server/lib/private-icon-references.ts +4 -2
- package/corpus/templates/content/server/lib/suggested-edits.ts +395 -353
- package/corpus/templates/content/server/lib/suggestion-live-accept.ts +284 -0
- package/corpus/templates/content/server/lib/suggestion-rebaseline.ts +237 -0
- package/corpus/templates/content/server/live-copy/anchor-text.ts +48 -0
- package/corpus/templates/content/server/live-copy/apply-suggestion-edit.ts +528 -0
- package/corpus/templates/content/server/live-copy/binding.ts +3 -0
- package/corpus/templates/content/server/live-copy/persist.ts +94 -30
- package/corpus/templates/content/server/live-copy/rebase.ts +330 -0
- package/corpus/templates/content/server/live-copy/switch.ts +5 -1
- package/corpus/templates/content/server/live-copy/task-names.ts +1 -0
- package/corpus/templates/content/server/live-copy/tasks.ts +160 -6
- package/corpus/templates/content/server/live-copy/write-cause.ts +9 -0
- package/corpus/templates/content/server/live-copy/write.ts +146 -3
- package/corpus/templates/content/server/plugins/db.ts +16 -0
- package/corpus/templates/content/server/test-support/live-copy-page.ts +76 -0
- package/corpus/templates/content/shared/api.ts +64 -5
- package/corpus/templates/content/shared/comment-ai.ts +9 -0
- package/corpus/templates/content/shared/comment-reanchor.ts +148 -2
- package/corpus/templates/content/shared/database-row-properties.ts +172 -0
- package/corpus/templates/content/shared/github-source.ts +5 -2
- package/corpus/templates/content/shared/suggestion-apply.ts +314 -0
- package/corpus/templates/content/shared/suggestion-link.ts +11 -0
- package/corpus/templates/content/shared/suggestion-rebase.ts +1 -1
- package/corpus/templates/content/shared/suggestion-rebaseline.ts +256 -0
- package/corpus/templates/content/vite.config.ts +1 -1
- package/corpus/templates/crm/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/crm/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/crm/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +46 -8
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +12 -1
- package/corpus/templates/design/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/design/.agents/skills/hubspot-email/SKILL.md +146 -0
- package/corpus/templates/design/.agents/skills/hubspot-email-review/SKILL.md +84 -0
- package/corpus/templates/design/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/design/.generated/bridge/native-builtin-metadata.generated.ts +326 -0
- package/corpus/templates/design/.generated/bridge/native-worker-source.generated.ts +6 -0
- package/corpus/templates/design/AGENTS.md +22 -23
- package/corpus/templates/design/actions/create-file.ts +40 -4
- package/corpus/templates/design/actions/edit-design.ts +1 -1
- package/corpus/templates/design/actions/export-hubspot-html.ts +110 -0
- package/corpus/templates/design/actions/export-png.ts +42 -3
- package/corpus/templates/design/actions/generate-design.ts +84 -28
- package/corpus/templates/design/actions/get-design-snapshot.ts +5 -1
- package/corpus/templates/design/actions/get-design-surface-index.ts +1 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +217 -116
- package/corpus/templates/design/actions/update-file.ts +9 -0
- package/corpus/templates/design/actions/view-screen.ts +16 -1
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +8 -1
- package/corpus/templates/design/app/components/design/EditPanel.tsx +1 -5
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +3 -3
- package/corpus/templates/design/app/components/design/design-canvas/content-size-report.ts +13 -3
- package/corpus/templates/design/app/components/design/design-canvas/interact-document.ts +10 -3
- package/corpus/templates/design/app/i18n/en-US.ts +13 -0
- package/corpus/templates/design/app/pages/design-editor/commands/download-hubspot-html.ts +86 -0
- package/corpus/templates/design/app/pages/design-editor/design-editor-view.tsx +1 -0
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-canvas-and-screens.ts +2 -1
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-export-and-handoff.ts +18 -0
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-screen-rendering.tsx +1 -0
- package/corpus/templates/design/app/pages/design-editor/domains/use-hubspot-html-export.ts +124 -0
- package/corpus/templates/design/app/pages/design-editor/effects/publish-agent-selection-context.ts +15 -0
- package/corpus/templates/design/app/pages/design-editor/png-export-render.ts +12 -1
- package/corpus/templates/design/app/pages/design-editor/view/editor-dialogs.tsx +10 -0
- package/corpus/templates/design/app/pages/design-editor/view/export-submenu-content.tsx +11 -0
- package/corpus/templates/design/app/pages/design-editor/view/hubspot-email-conversion-dialog.tsx +54 -0
- package/corpus/templates/design/changelog/2026-10-22-create-hubspot-email-frames-rebuild-existing-frames-for-emai.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-hubspot-conversion-exports-can-verify-that-original-link-des.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-hubspot-emails-receive-an-independent-content-and-mobile-lay.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-hug-frames-expand-to-show-their-full-content-in-the-canvas-a.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-preview-hubspot-emails-with-sample-recipient-names-and-butto.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-screenshot-previews-use-local-chromium-when-available-for-fa.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-verification-and-export-requests-finish-without-requiring-un.md +6 -0
- package/corpus/templates/design/changelog/2026-10-23-external-stylesheet-image-export.md +6 -0
- package/corpus/templates/design/changelog/2026-10-23-html-motion-edits-preserve-interactive-alpine-visibility-sta.md +6 -0
- package/corpus/templates/design/changelog/2026-10-23-motion-editing-works-again-on-designs-that-load-tailwind-and.md +6 -0
- package/corpus/templates/design/changelog/2026-10-23-promo-artwork-uses-delivery-size-typography.md +6 -0
- package/corpus/templates/design/server/lib/design-response-guard.ts +29 -1
- package/corpus/templates/design/server/lib/email-css-properties.ts +128 -0
- package/corpus/templates/design/server/lib/email-css-values.ts +36 -0
- package/corpus/templates/design/server/lib/email-css-visibility.ts +72 -0
- package/corpus/templates/design/server/lib/email-image-bytes.ts +87 -0
- package/corpus/templates/design/server/lib/email-text-color.ts +85 -0
- package/corpus/templates/design/server/lib/hubl-interpolation.ts +63 -0
- package/corpus/templates/design/server/lib/hubspot-email-export.ts +1005 -0
- package/corpus/templates/design/server/lib/hubspot-email-preview.ts +153 -0
- package/corpus/templates/design/server/lib/playwright-runtime.ts +6 -6
- package/corpus/templates/design/server/lib/protect-hubl-tokens.ts +31 -0
- package/corpus/templates/design/server/lib/screenshot-readiness.ts +176 -0
- package/corpus/templates/design/server/plugins/agent-chat.ts +2 -0
- package/corpus/templates/design/server/source-workspace.ts +22 -0
- package/corpus/templates/design/shared/hubl-tokens.ts +55 -0
- package/corpus/templates/design/shared/hubspot-email-authoring.ts +35 -0
- package/corpus/templates/design/shared/hubspot-email.ts +100 -0
- package/corpus/templates/design/shared/motion-html-source.ts +547 -16
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/dispatch/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/dispatch/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/factory/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/factory/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/factory/.agents/skills/review-prs/SKILL.md +27 -3
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/forms/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/forms/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/mail/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/mail/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/plan/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/plan/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/slides/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/slides/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/slides/actions/patch-deck.ts +17 -7
- package/corpus/templates/slides/changelog/2026-10-23-the-agent-retries-a-slide-edit-whose-text-it-could-not-find-.md +6 -0
- package/corpus/templates/slides/scripts/edit-fidelity/run-options.ts +26 -0
- package/corpus/templates/slides/scripts/edit-fidelity/run.ts +25 -4
- package/corpus/templates/slides-2/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/slides-2/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/corpus/templates/slides-2/.deploy-tmp/agent-native-provided-plugins.mjs +10 -0
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +1 -0
- package/corpus/templates/tasks/.agents/skills/external-agents/references/mcp-apps-embedding.md +12 -5
- package/package.json +1 -1
package/corpus/README.md
CHANGED
|
@@ -172,6 +172,7 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
|
|
|
172
172
|
- **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
|
|
173
173
|
- **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
|
|
174
174
|
- **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
|
|
175
|
+
- **Do** throw `NoWriteError(message, { errorCode, statusCode })` instead of `fail()` for a rejection raised before the action's first write, such as an edit that matches nothing or a missing target. The agent then retries with corrected arguments instead of stopping on a write whose outcome is unknown. Throw it only before the first write: the framework rejects the claim when a nested write action ran, but it cannot see the handler's own writes.
|
|
175
176
|
- **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
|
|
176
177
|
- **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
|
|
177
178
|
- **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
|
package/corpus/templates/analytics/.agents/skills/external-agents/references/mcp-apps-embedding.md
CHANGED
|
@@ -162,8 +162,15 @@ actions for Forms, Content, Clips, Slides, and Design. The action should return
|
|
|
162
162
|
concise structured content plus the link; it should not dump large catalogs or
|
|
163
163
|
HTML.
|
|
164
164
|
|
|
165
|
-
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
-
Apps
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
+
Hosts that render MCP Apps inline today include Claude chat on web, desktop, and
|
|
167
|
+
mobile, plus the Claude Desktop Code tab; ChatGPT; VS Code GitHub Copilot (1.109+);
|
|
168
|
+
Microsoft 365 Copilot; Cursor (2.6+); Goose; Postman; MCPJam; Codex Desktop (26.616+);
|
|
169
|
+
and T3 Code (in Codex threads). Desktop Code rendering is observed in
|
|
170
|
+
[widget bug reports](https://github.com/anthropics/claude-code/issues/103809).
|
|
171
|
+
Treat the Claude Code terminal, Cowork, and Code on claude.ai web as link-out hosts.
|
|
172
|
+
[Cowork doesn't declare MCP Apps yet](https://github.com/anthropics/claude-code/issues/103924),
|
|
173
|
+
and using it on the same connector can make inline apps disappear in Chat until
|
|
174
|
+
you reconnect the connector. Host support varies by plan, release channel, and client version,
|
|
175
|
+
so keep the deep link fallback. See the community-maintained
|
|
176
|
+
[MCP client matrix](https://modelcontextprotocol.io/extensions/client-matrix).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","analytics-alert-jobs","analytics-rollup-backfill-jobs","auth","collab","config","content-metrics-collection-jobs","core-routes","creative-context","dashboard-report-jobs","db","feature-flags","labs","onboarding","otel","session-replay-retention-jobs","transactional-emails","uptime-monitor-jobs"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -172,6 +172,7 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
|
|
|
172
172
|
- **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
|
|
173
173
|
- **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
|
|
174
174
|
- **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
|
|
175
|
+
- **Do** throw `NoWriteError(message, { errorCode, statusCode })` instead of `fail()` for a rejection raised before the action's first write, such as an edit that matches nothing or a missing target. The agent then retries with corrected arguments instead of stopping on a write whose outcome is unknown. Throw it only before the first write: the framework rejects the claim when a nested write action ran, but it cannot see the handler's own writes.
|
|
175
176
|
- **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
|
|
176
177
|
- **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
|
|
177
178
|
- **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
|
package/corpus/templates/assets/.agents/skills/external-agents/references/mcp-apps-embedding.md
CHANGED
|
@@ -162,8 +162,15 @@ actions for Forms, Content, Clips, Slides, and Design. The action should return
|
|
|
162
162
|
concise structured content plus the link; it should not dump large catalogs or
|
|
163
163
|
HTML.
|
|
164
164
|
|
|
165
|
-
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
-
Apps
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
+
Hosts that render MCP Apps inline today include Claude chat on web, desktop, and
|
|
167
|
+
mobile, plus the Claude Desktop Code tab; ChatGPT; VS Code GitHub Copilot (1.109+);
|
|
168
|
+
Microsoft 365 Copilot; Cursor (2.6+); Goose; Postman; MCPJam; Codex Desktop (26.616+);
|
|
169
|
+
and T3 Code (in Codex threads). Desktop Code rendering is observed in
|
|
170
|
+
[widget bug reports](https://github.com/anthropics/claude-code/issues/103809).
|
|
171
|
+
Treat the Claude Code terminal, Cowork, and Code on claude.ai web as link-out hosts.
|
|
172
|
+
[Cowork doesn't declare MCP Apps yet](https://github.com/anthropics/claude-code/issues/103924),
|
|
173
|
+
and using it on the same connector can make inline apps disappear in Chat until
|
|
174
|
+
you reconnect the connector. Host support varies by plan, release channel, and client version,
|
|
175
|
+
so keep the deep link fallback. See the community-maintained
|
|
176
|
+
[MCP client matrix](https://modelcontextprotocol.io/extensions/client-matrix).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","creative-context","db","labs","onboarding","otel"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -172,6 +172,7 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
|
|
|
172
172
|
- **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
|
|
173
173
|
- **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
|
|
174
174
|
- **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
|
|
175
|
+
- **Do** throw `NoWriteError(message, { errorCode, statusCode })` instead of `fail()` for a rejection raised before the action's first write, such as an edit that matches nothing or a missing target. The agent then retries with corrected arguments instead of stopping on a write whose outcome is unknown. Throw it only before the first write: the framework rejects the claim when a nested write action ran, but it cannot see the handler's own writes.
|
|
175
176
|
- **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
|
|
176
177
|
- **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
|
|
177
178
|
- **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
|
package/corpus/templates/brain/.agents/skills/external-agents/references/mcp-apps-embedding.md
CHANGED
|
@@ -162,8 +162,15 @@ actions for Forms, Content, Clips, Slides, and Design. The action should return
|
|
|
162
162
|
concise structured content plus the link; it should not dump large catalogs or
|
|
163
163
|
HTML.
|
|
164
164
|
|
|
165
|
-
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
-
Apps
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
+
Hosts that render MCP Apps inline today include Claude chat on web, desktop, and
|
|
167
|
+
mobile, plus the Claude Desktop Code tab; ChatGPT; VS Code GitHub Copilot (1.109+);
|
|
168
|
+
Microsoft 365 Copilot; Cursor (2.6+); Goose; Postman; MCPJam; Codex Desktop (26.616+);
|
|
169
|
+
and T3 Code (in Codex threads). Desktop Code rendering is observed in
|
|
170
|
+
[widget bug reports](https://github.com/anthropics/claude-code/issues/103809).
|
|
171
|
+
Treat the Claude Code terminal, Cowork, and Code on claude.ai web as link-out hosts.
|
|
172
|
+
[Cowork doesn't declare MCP Apps yet](https://github.com/anthropics/claude-code/issues/103924),
|
|
173
|
+
and using it on the same connector can make inline apps disappear in Chat until
|
|
174
|
+
you reconnect the connector. Host support varies by plan, release channel, and client version,
|
|
175
|
+
so keep the deep link fallback. See the community-maintained
|
|
176
|
+
[MCP client matrix](https://modelcontextprotocol.io/extensions/client-matrix).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","brain-jobs","core-routes","db","otel"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -172,6 +172,7 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
|
|
|
172
172
|
- **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
|
|
173
173
|
- **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
|
|
174
174
|
- **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
|
|
175
|
+
- **Do** throw `NoWriteError(message, { errorCode, statusCode })` instead of `fail()` for a rejection raised before the action's first write, such as an edit that matches nothing or a missing target. The agent then retries with corrected arguments instead of stopping on a write whose outcome is unknown. Throw it only before the first write: the framework rejects the claim when a nested write action ran, but it cannot see the handler's own writes.
|
|
175
176
|
- **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
|
|
176
177
|
- **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
|
|
177
178
|
- **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
|
package/corpus/templates/calendar/.agents/skills/external-agents/references/mcp-apps-embedding.md
CHANGED
|
@@ -162,8 +162,15 @@ actions for Forms, Content, Clips, Slides, and Design. The action should return
|
|
|
162
162
|
concise structured content plus the link; it should not dump large catalogs or
|
|
163
163
|
HTML.
|
|
164
164
|
|
|
165
|
-
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
-
Apps
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
+
Hosts that render MCP Apps inline today include Claude chat on web, desktop, and
|
|
167
|
+
mobile, plus the Claude Desktop Code tab; ChatGPT; VS Code GitHub Copilot (1.109+);
|
|
168
|
+
Microsoft 365 Copilot; Cursor (2.6+); Goose; Postman; MCPJam; Codex Desktop (26.616+);
|
|
169
|
+
and T3 Code (in Codex threads). Desktop Code rendering is observed in
|
|
170
|
+
[widget bug reports](https://github.com/anthropics/claude-code/issues/103809).
|
|
171
|
+
Treat the Claude Code terminal, Cowork, and Code on claude.ai web as link-out hosts.
|
|
172
|
+
[Cowork doesn't declare MCP Apps yet](https://github.com/anthropics/claude-code/issues/103924),
|
|
173
|
+
and using it on the same connector can make inline apps disappear in Chat until
|
|
174
|
+
you reconnect the connector. Host support varies by plan, release channel, and client version,
|
|
175
|
+
so keep the deep link fallback. See the community-maintained
|
|
176
|
+
[MCP client matrix](https://modelcontextprotocol.io/extensions/client-matrix).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","core-routes","db","event-rules","oauth-refresh","otel","transactional-emails"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -172,6 +172,7 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
|
|
|
172
172
|
- **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
|
|
173
173
|
- **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
|
|
174
174
|
- **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
|
|
175
|
+
- **Do** throw `NoWriteError(message, { errorCode, statusCode })` instead of `fail()` for a rejection raised before the action's first write, such as an edit that matches nothing or a missing target. The agent then retries with corrected arguments instead of stopping on a write whose outcome is unknown. Throw it only before the first write: the framework rejects the claim when a nested write action ran, but it cannot see the handler's own writes.
|
|
175
176
|
- **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
|
|
176
177
|
- **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
|
|
177
178
|
- **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","otel"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -172,6 +172,7 @@ Everything else — CRUD, settings, search, list/detail reads, auth state, anyth
|
|
|
172
172
|
- **Do** signal failure by throwing, using `fail()` for expected caller-readable failures. Never return `{ error: ... }` as a failure result: a normal return is treated as a successful action. Reserve bare errors for unexpected internal faults.
|
|
173
173
|
- **Do** use `fail()` rather than a bare `Error` for caller-readable failures. It carries the action's message, `errorCode`, and `details` to the browser and to agents; unexpected errors become a generic 500. Reserve bare throws for internal faults.
|
|
174
174
|
- **Do** give `fail()` the status that matches the cause: it defaults to `400`, and `useActionQuery` retries only `429`, `502`, `503`, and `504`. Mutations do not retry; use transient statuses only for retryable failures.
|
|
175
|
+
- **Do** throw `NoWriteError(message, { errorCode, statusCode })` instead of `fail()` for a rejection raised before the action's first write, such as an edit that matches nothing or a missing target. The agent then retries with corrected arguments instead of stopping on a write whose outcome is unknown. Throw it only before the first write: the framework rejects the claim when a nested write action ran, but it cannot see the handler's own writes.
|
|
175
176
|
- **Do** render `actionErrorMessage(error) ?? yourCopy` in UI, never bare `error.message`. The message keeps an `Action <name> failed:` prefix that belongs in a console, so a toast built from it reads "Action update-brand-kit failed: That name is taken." The helper returns only what the action wrote, and `undefined` when nothing did (network drop, proxy HTML page), which is why the fallback is not optional.
|
|
176
177
|
- **Do** pass a real `errorCode` when the agent should branch on the failure rather than re-read it. Codes other than the default `action_failed` are appended to the tool result as `(errorCode: not_found)`, on both the in-app agent and MCP. `details` follow as an `Error details: {...}` JSON line, and as `structuredContent.error` over MCP, capped at 2,000 characters, so keep them to what the agent acts on next: ids, limits, field names. The status never reaches either.
|
|
177
178
|
- **Don't** re-export actions as REST — `/_agent-native/actions/:name` is already the REST surface; duplicating it under `/api/*` hides the operation from agents.
|
package/corpus/templates/clips/.agents/skills/external-agents/references/mcp-apps-embedding.md
CHANGED
|
@@ -162,8 +162,15 @@ actions for Forms, Content, Clips, Slides, and Design. The action should return
|
|
|
162
162
|
concise structured content plus the link; it should not dump large catalogs or
|
|
163
163
|
HTML.
|
|
164
164
|
|
|
165
|
-
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
-
Apps
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
165
|
+
Compatibility target: build to the standard once, not per-client shims.
|
|
166
|
+
Hosts that render MCP Apps inline today include Claude chat on web, desktop, and
|
|
167
|
+
mobile, plus the Claude Desktop Code tab; ChatGPT; VS Code GitHub Copilot (1.109+);
|
|
168
|
+
Microsoft 365 Copilot; Cursor (2.6+); Goose; Postman; MCPJam; Codex Desktop (26.616+);
|
|
169
|
+
and T3 Code (in Codex threads). Desktop Code rendering is observed in
|
|
170
|
+
[widget bug reports](https://github.com/anthropics/claude-code/issues/103809).
|
|
171
|
+
Treat the Claude Code terminal, Cowork, and Code on claude.ai web as link-out hosts.
|
|
172
|
+
[Cowork doesn't declare MCP Apps yet](https://github.com/anthropics/claude-code/issues/103924),
|
|
173
|
+
and using it on the same connector can make inline apps disappear in Chat until
|
|
174
|
+
you reconnect the connector. Host support varies by plan, release channel, and client version,
|
|
175
|
+
so keep the deep link fallback. See the community-maintained
|
|
176
|
+
[MCP client matrix](https://modelcontextprotocol.io/extensions/client-matrix).
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// AUTO-GENERATED by @agent-native/core deploy build
|
|
2
|
+
import { markDefaultPluginProvided } from "@agent-native/core/server/edge";
|
|
3
|
+
|
|
4
|
+
const pluginStems = ["agent-chat","auth","calendar-jobs","config","core-routes","db","feature-flags","labs","onboarding","onboarding-calendar","otel","transactional-email-catalog"];
|
|
5
|
+
|
|
6
|
+
export default function markBuildDiscoveredPlugins(nitroApp) {
|
|
7
|
+
for (const stem of pluginStems) {
|
|
8
|
+
markDefaultPluginProvided(nitroApp, stem);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -31,10 +31,11 @@ import {
|
|
|
31
31
|
// success should finish this card's setup; a connection made long after the
|
|
32
32
|
// cancel belongs to something else.
|
|
33
33
|
const CANCELLED_SETUP_RECOVERY_MS = 60_000;
|
|
34
|
+
// The custom-keys form finishes in another tab with no signal back, so a
|
|
35
|
+
// status read on leaving or returning credits it only this long after it was
|
|
36
|
+
// opened; storage set up later belongs to something else.
|
|
37
|
+
const CUSTOM_KEYS_CREDIT_WINDOW_MS = 15 * 60_000;
|
|
34
38
|
|
|
35
|
-
// The S3 path finishes in settings, outside this card, so only the choice is
|
|
36
|
-
// recorded here; a later `recording_started.storage_connected` shows whether
|
|
37
|
-
// it landed.
|
|
38
39
|
function trackStorageStep(
|
|
39
40
|
name:
|
|
40
41
|
| "onboarding_step_viewed"
|
|
@@ -66,6 +67,8 @@ export interface StorageSetupCardProps {
|
|
|
66
67
|
*/
|
|
67
68
|
recordingAttemptId?: string;
|
|
68
69
|
outputId?: string;
|
|
70
|
+
/** Why the host is showing the card, recorded on every step event. */
|
|
71
|
+
setupReason?: string;
|
|
69
72
|
}
|
|
70
73
|
|
|
71
74
|
export function StorageSetupCard({
|
|
@@ -79,6 +82,7 @@ export function StorageSetupCard({
|
|
|
79
82
|
connectFlow = "file_upload",
|
|
80
83
|
recordingAttemptId,
|
|
81
84
|
outputId,
|
|
85
|
+
setupReason,
|
|
82
86
|
}: StorageSetupCardProps) {
|
|
83
87
|
const t = useT();
|
|
84
88
|
const storageSetupHref = useStorageSetupHref();
|
|
@@ -100,6 +104,9 @@ export function StorageSetupCard({
|
|
|
100
104
|
const connectRequestedRef = useRef(false);
|
|
101
105
|
const connectIntentExpiresAtRef = useRef<number | null>(null);
|
|
102
106
|
const [stepViewId] = useState(createOnboardingCorrelationId);
|
|
107
|
+
// Fixed for the showing: the host's status can change while the card is up,
|
|
108
|
+
// and every event under one step_view_id must agree on why it showed.
|
|
109
|
+
const [viewSetupReason] = useState(setupReason);
|
|
103
110
|
const stepProperties = useMemo(
|
|
104
111
|
() => ({
|
|
105
112
|
flow: connectSource,
|
|
@@ -108,8 +115,69 @@ export function StorageSetupCard({
|
|
|
108
115
|
? { recording_attempt_id: recordingAttemptId }
|
|
109
116
|
: {}),
|
|
110
117
|
...(outputId ? { output_id: outputId } : {}),
|
|
118
|
+
...(viewSetupReason ? { setup_reason: viewSetupReason } : {}),
|
|
111
119
|
}),
|
|
112
|
-
[connectSource, stepViewId, recordingAttemptId, outputId],
|
|
120
|
+
[connectSource, stepViewId, recordingAttemptId, outputId, viewSetupReason],
|
|
121
|
+
);
|
|
122
|
+
const stepPropertiesRef = useRef(stepProperties);
|
|
123
|
+
stepPropertiesRef.current = stepProperties;
|
|
124
|
+
const builderHandedOffRef = useRef(false);
|
|
125
|
+
const skippedRef = useRef(false);
|
|
126
|
+
const customKeysOpenedAtRef = useRef<number | null>(null);
|
|
127
|
+
const customKeysOpenedRecently = useCallback(() => {
|
|
128
|
+
const openedAt = customKeysOpenedAtRef.current;
|
|
129
|
+
return (
|
|
130
|
+
openedAt !== null && Date.now() - openedAt <= CUSTOM_KEYS_CREDIT_WINDOW_MS
|
|
131
|
+
);
|
|
132
|
+
}, []);
|
|
133
|
+
const completionTrackedRef = useRef(false);
|
|
134
|
+
const returnReadInFlightRef = useRef(false);
|
|
135
|
+
const storageBeforeSetupRef = useRef<Promise<
|
|
136
|
+
{ status: VideoStorageStatus } | { error: unknown }
|
|
137
|
+
> | null>(null);
|
|
138
|
+
const readStorageBeforeSetup = useCallback(() => {
|
|
139
|
+
storageBeforeSetupRef.current ??= fetchVideoStorageStatus({
|
|
140
|
+
timeoutMs: 10_000,
|
|
141
|
+
}).then(
|
|
142
|
+
(status) => ({ status }),
|
|
143
|
+
(error: unknown) => ({ error }),
|
|
144
|
+
);
|
|
145
|
+
}, []);
|
|
146
|
+
|
|
147
|
+
// The route hosting this card can unmount it the moment the shared storage
|
|
148
|
+
// status reads configured, before this card's poll sees it, so the unmount
|
|
149
|
+
// path below reads the status once more and records through this too.
|
|
150
|
+
// Only a change to the workspace's own storage completes this step: free
|
|
151
|
+
// hosted clips also read as configured, and own storage that was already
|
|
152
|
+
// there at the showing's first setup click was not set up by this card.
|
|
153
|
+
// The read of storage before setup must start before any setup request
|
|
154
|
+
// can, since one-request account activation can finish before a read sent
|
|
155
|
+
// with it.
|
|
156
|
+
const trackCompletedIfConfigured = useCallback(
|
|
157
|
+
(status: VideoStorageStatus) => {
|
|
158
|
+
const before = storageBeforeSetupRef.current;
|
|
159
|
+
if (status.mode !== "own" || !before || completionTrackedRef.current) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
// Claimed before the wait, so reads landing together record once.
|
|
163
|
+
completionTrackedRef.current = true;
|
|
164
|
+
void before.then((read) => {
|
|
165
|
+
if ("error" in read) {
|
|
166
|
+
console.warn(
|
|
167
|
+
"[storage-setup] storage before setup could not be read:",
|
|
168
|
+
read.error,
|
|
169
|
+
);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (read.status.mode === "own" || skippedRef.current) return;
|
|
173
|
+
const methodId = status.activeProvider?.id;
|
|
174
|
+
trackStorageStep("onboarding_step_completed", {
|
|
175
|
+
...stepPropertiesRef.current,
|
|
176
|
+
...(methodId ? { method_id: methodId } : {}),
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
},
|
|
180
|
+
[],
|
|
113
181
|
);
|
|
114
182
|
|
|
115
183
|
const clearConfiguredTimeout = useCallback(() => {
|
|
@@ -177,10 +245,7 @@ export function StorageSetupCard({
|
|
|
177
245
|
stop();
|
|
178
246
|
setConnecting(false);
|
|
179
247
|
setConnected(true);
|
|
180
|
-
|
|
181
|
-
...stepProperties,
|
|
182
|
-
method_id: "builder",
|
|
183
|
-
});
|
|
248
|
+
trackCompletedIfConfigured(status);
|
|
184
249
|
clearConfiguredTimeout();
|
|
185
250
|
configuredTimeoutRef.current = setTimeout(() => {
|
|
186
251
|
configuredTimeoutRef.current = null;
|
|
@@ -211,9 +276,9 @@ export function StorageSetupCard({
|
|
|
211
276
|
}, [
|
|
212
277
|
clearConfiguredTimeout,
|
|
213
278
|
onConfigured,
|
|
214
|
-
stepProperties,
|
|
215
279
|
stopVisibilityHandler,
|
|
216
280
|
t,
|
|
281
|
+
trackCompletedIfConfigured,
|
|
217
282
|
]);
|
|
218
283
|
|
|
219
284
|
const handleBuilderConnected = useCallback(() => {
|
|
@@ -222,6 +287,7 @@ export function StorageSetupCard({
|
|
|
222
287
|
connectRequestedRef.current = false;
|
|
223
288
|
connectIntentExpiresAtRef.current = null;
|
|
224
289
|
if (expiresAt !== null && Date.now() > expiresAt) return;
|
|
290
|
+
builderHandedOffRef.current = true;
|
|
225
291
|
startFileUploadPoll();
|
|
226
292
|
}, [startFileUploadPoll]);
|
|
227
293
|
|
|
@@ -269,6 +335,7 @@ export function StorageSetupCard({
|
|
|
269
335
|
setStatusIssue("connect-not-allowed");
|
|
270
336
|
return;
|
|
271
337
|
}
|
|
338
|
+
readStorageBeforeSetup();
|
|
272
339
|
connectRequestedRef.current = true;
|
|
273
340
|
connectIntentExpiresAtRef.current = null;
|
|
274
341
|
setStatusIssue(null);
|
|
@@ -281,7 +348,12 @@ export function StorageSetupCard({
|
|
|
281
348
|
scope: builderConnectionScope,
|
|
282
349
|
});
|
|
283
350
|
},
|
|
284
|
-
[
|
|
351
|
+
[
|
|
352
|
+
builderConnectionScope,
|
|
353
|
+
builderConnect.start,
|
|
354
|
+
readStorageBeforeSetup,
|
|
355
|
+
stepProperties,
|
|
356
|
+
],
|
|
285
357
|
);
|
|
286
358
|
const handleBuilderCancel = useCallback(() => {
|
|
287
359
|
connectIntentExpiresAtRef.current =
|
|
@@ -290,6 +362,7 @@ export function StorageSetupCard({
|
|
|
290
362
|
}, [builderConnect.cancel]);
|
|
291
363
|
const handleSkip = useCallback(() => {
|
|
292
364
|
clearConfiguredTimeout();
|
|
365
|
+
skippedRef.current = true;
|
|
293
366
|
trackStorageStep("onboarding_step_skipped", {
|
|
294
367
|
...stepProperties,
|
|
295
368
|
});
|
|
@@ -307,8 +380,41 @@ export function StorageSetupCard({
|
|
|
307
380
|
)
|
|
308
381
|
: null;
|
|
309
382
|
const builderConnecting = builderConnect.connecting;
|
|
383
|
+
const builderConnectingRef = useRef(builderConnecting);
|
|
384
|
+
builderConnectingRef.current = builderConnecting;
|
|
310
385
|
const actionConnecting = connecting || builderConnecting;
|
|
311
386
|
|
|
387
|
+
// The custom-keys form opens in another tab, and some routes keep this card
|
|
388
|
+
// mounted after it saves, so a return to this tab reads the status too.
|
|
389
|
+
useEffect(() => {
|
|
390
|
+
const readOnReturn = () => {
|
|
391
|
+
if (
|
|
392
|
+
document.hidden ||
|
|
393
|
+
!customKeysOpenedRecently() ||
|
|
394
|
+
completionTrackedRef.current ||
|
|
395
|
+
skippedRef.current ||
|
|
396
|
+
returnReadInFlightRef.current
|
|
397
|
+
) {
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
returnReadInFlightRef.current = true;
|
|
401
|
+
void fetchVideoStorageStatus({ timeoutMs: 10_000 })
|
|
402
|
+
.then(trackCompletedIfConfigured)
|
|
403
|
+
.catch((err) => {
|
|
404
|
+
console.warn("[storage-setup] completion check failed:", err);
|
|
405
|
+
})
|
|
406
|
+
.finally(() => {
|
|
407
|
+
returnReadInFlightRef.current = false;
|
|
408
|
+
});
|
|
409
|
+
};
|
|
410
|
+
window.addEventListener("focus", readOnReturn);
|
|
411
|
+
document.addEventListener("visibilitychange", readOnReturn);
|
|
412
|
+
return () => {
|
|
413
|
+
window.removeEventListener("focus", readOnReturn);
|
|
414
|
+
document.removeEventListener("visibilitychange", readOnReturn);
|
|
415
|
+
};
|
|
416
|
+
}, [customKeysOpenedRecently, trackCompletedIfConfigured]);
|
|
417
|
+
|
|
312
418
|
useEffect(() => {
|
|
313
419
|
trackStorageStep("onboarding_step_viewed", {
|
|
314
420
|
...stepProperties,
|
|
@@ -319,6 +425,24 @@ export function StorageSetupCard({
|
|
|
319
425
|
mountedRef.current = true;
|
|
320
426
|
return () => {
|
|
321
427
|
mountedRef.current = false;
|
|
428
|
+
// The route can unmount this card mid-setup: while the connect flow is
|
|
429
|
+
// still connecting, or after this card accepted the connect but before
|
|
430
|
+
// its storage poll saw it. After a cancel the flow keeps connecting
|
|
431
|
+
// through its popup-closed grace, so crediting then relies on that grace
|
|
432
|
+
// staying shorter than CANCELLED_SETUP_RECOVERY_MS.
|
|
433
|
+
const setupPending =
|
|
434
|
+
!completionTrackedRef.current &&
|
|
435
|
+
!skippedRef.current &&
|
|
436
|
+
(builderHandedOffRef.current ||
|
|
437
|
+
builderConnectingRef.current ||
|
|
438
|
+
customKeysOpenedRecently());
|
|
439
|
+
if (setupPending) {
|
|
440
|
+
void fetchVideoStorageStatus({ timeoutMs: 10_000 })
|
|
441
|
+
.then(trackCompletedIfConfigured)
|
|
442
|
+
.catch((err) => {
|
|
443
|
+
console.warn("[storage-setup] completion check failed:", err);
|
|
444
|
+
});
|
|
445
|
+
}
|
|
322
446
|
clearConfiguredTimeout();
|
|
323
447
|
if (pollRef.current) {
|
|
324
448
|
clearInterval(pollRef.current);
|
|
@@ -326,7 +450,12 @@ export function StorageSetupCard({
|
|
|
326
450
|
}
|
|
327
451
|
stopVisibilityHandler();
|
|
328
452
|
};
|
|
329
|
-
}, [
|
|
453
|
+
}, [
|
|
454
|
+
clearConfiguredTimeout,
|
|
455
|
+
customKeysOpenedRecently,
|
|
456
|
+
stopVisibilityHandler,
|
|
457
|
+
trackCompletedIfConfigured,
|
|
458
|
+
]);
|
|
330
459
|
|
|
331
460
|
return (
|
|
332
461
|
<div className="mx-auto flex w-full max-w-md flex-col gap-5 rounded-2xl border border-border bg-card p-6 shadow-lg">
|
|
@@ -357,6 +486,7 @@ export function StorageSetupCard({
|
|
|
357
486
|
cancel: undefined,
|
|
358
487
|
}}
|
|
359
488
|
onConnect={handleBuilderConnect}
|
|
489
|
+
onTriggerClick={readStorageBeforeSetup}
|
|
360
490
|
>
|
|
361
491
|
<Button
|
|
362
492
|
type="button"
|
|
@@ -379,12 +509,14 @@ export function StorageSetupCard({
|
|
|
379
509
|
href={storageSetupHref}
|
|
380
510
|
target="_blank"
|
|
381
511
|
rel="noopener noreferrer"
|
|
382
|
-
onClick={() =>
|
|
512
|
+
onClick={() => {
|
|
513
|
+
readStorageBeforeSetup();
|
|
514
|
+
customKeysOpenedAtRef.current = Date.now();
|
|
383
515
|
trackStorageStep("onboarding_method_clicked", {
|
|
384
516
|
...stepProperties,
|
|
385
517
|
method_id: "s3",
|
|
386
|
-
})
|
|
387
|
-
}
|
|
518
|
+
});
|
|
519
|
+
}}
|
|
388
520
|
>
|
|
389
521
|
{t("storageSetup.customKeys")}
|
|
390
522
|
</a>
|
|
@@ -1279,6 +1279,16 @@ export function shouldRedirectToStorageSetupHome({
|
|
|
1279
1279
|
);
|
|
1280
1280
|
}
|
|
1281
1281
|
|
|
1282
|
+
export function storageSetupReason(
|
|
1283
|
+
status: Pick<VideoStorageStatus, "denyReason"> | undefined,
|
|
1284
|
+
): string {
|
|
1285
|
+
if (!status) return "status_unavailable";
|
|
1286
|
+
// "disabled" means free hosted clips are off, not that a hosted clip was denied.
|
|
1287
|
+
return status.denyReason && status.denyReason !== "disabled"
|
|
1288
|
+
? `hosted_${status.denyReason}`
|
|
1289
|
+
: "storage_required";
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1282
1292
|
export function shouldShowFirstRunStorageSetup({
|
|
1283
1293
|
storageConfigured,
|
|
1284
1294
|
storageStatusUnavailable,
|
|
@@ -4187,6 +4197,7 @@ export default function RecordRoute() {
|
|
|
4187
4197
|
showBuilderStorageOffer={!hostedAllowanceExhausted}
|
|
4188
4198
|
connectSource="clips_record_storage_setup_card"
|
|
4189
4199
|
connectFlow="record"
|
|
4200
|
+
setupReason={storageSetupReason(storageQuery.data)}
|
|
4190
4201
|
/>
|
|
4191
4202
|
</div>
|
|
4192
4203
|
) : showStorageStatusUnavailable ? (
|