@agent-native/core 0.127.3 → 0.128.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +2 -2
- package/corpus/core/CHANGELOG.md +101 -0
- package/corpus/core/README.md +5 -26
- package/corpus/core/docs/content/actions.mdx +47 -4
- package/corpus/core/docs/content/native-chat-ui.mdx +7 -0
- package/corpus/core/docs/content/organizations-teams-permissions.mdx +109 -3
- package/corpus/core/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
- package/corpus/core/docs/content/toolkit-org-team.mdx +72 -12
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/a2a/artifact-response.ts +36 -29
- package/corpus/core/src/action.ts +83 -2
- package/corpus/core/src/chat-threads/store.ts +48 -43
- package/corpus/core/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
- package/corpus/core/src/client/AgentPanel.tsx +26 -6
- package/corpus/core/src/client/AssistantChat.tsx +63 -7
- package/corpus/core/src/client/DefaultSpinner.tsx +29 -0
- package/corpus/core/src/client/org/TeamPage.tsx +161 -6
- package/corpus/core/src/client/org/hooks.ts +67 -0
- package/corpus/core/src/client/org/index.ts +9 -0
- package/corpus/core/src/client/transcription/use-live-transcription.ts +62 -10
- package/corpus/core/src/db/client.ts +42 -3
- package/corpus/core/src/db/ensure-additive-columns.ts +60 -33
- package/corpus/core/src/deploy/build.ts +31 -2
- package/corpus/core/src/mcp-client/routes.ts +10 -1
- package/corpus/core/src/org/app-roles-handlers.ts +152 -0
- package/corpus/core/src/org/app-roles.ts +355 -0
- package/corpus/core/src/org/index.ts +27 -1
- package/corpus/core/src/org/migrations.ts +22 -0
- package/corpus/core/src/org/plugin.ts +27 -0
- package/corpus/core/src/org/schema.ts +15 -0
- package/corpus/core/src/scripts/docs/search.ts +17 -0
- package/corpus/core/src/scripts/docs/source-search.ts +10 -0
- package/corpus/core/src/server/agent-chat/script-entries.ts +3 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +53 -52
- package/corpus/core/src/server/builder-design-systems.ts +299 -82
- package/corpus/core/src/server/core-routes-plugin.ts +6 -1
- package/corpus/core/src/server/framework-request-handler.ts +44 -6
- package/corpus/core/src/server/index.ts +8 -0
- package/corpus/core/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/core/src/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/corpus/core/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/corpus/core/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/analytics/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/analytics/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/analytics/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/analytics/_gitignore +2 -0
- package/corpus/templates/analytics/actions/data-source-status.ts +21 -12
- package/corpus/templates/analytics/app/global.css +7 -7
- package/corpus/templates/analytics/app/i18n-data.ts +30 -0
- package/corpus/templates/analytics/app/lib/data-source-status.ts +2 -1
- package/corpus/templates/analytics/app/pages/DataSources.tsx +54 -10
- package/corpus/templates/analytics/changelog/2026-07-28-analytics-pages-load-reliably-with-large-dashboard-workspaces.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-28-dashboard-loading-shimmer-now-flows-smoothly-in-one-directi.md +6 -0
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +5 -4
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +54 -42
- package/corpus/templates/analytics/server/plugins/db.ts +1 -18
- package/corpus/templates/assets/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/assets/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/assets/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/assets/_gitignore +2 -0
- package/corpus/templates/brain/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/brain/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/brain/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/calendar/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/calendar/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/calendar/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/calendar/_gitignore +2 -0
- package/corpus/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/clips/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/clips/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/clips/_gitignore +2 -0
- package/corpus/templates/clips/actions/request-transcript.ts +77 -11
- package/corpus/templates/clips/actions/save-browser-transcript.ts +28 -7
- package/corpus/templates/clips/app/routes/record.tsx +11 -3
- package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-save-a-truncated-transcript-as-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-browser-recordings-no-longer-stop-transcribing-partway-throu.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-desktop-full-screen-clips-now-get-an-instant-local-transcrip.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-long-transcriptions-no-longer-show-a-false-transcription-sto.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-restarting-for-an-update-now-installs-the-newest-release-ins.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-28-the-meeting-recording-pill-now-anchors-to-the-right-edge-of-.md +6 -0
- package/corpus/templates/clips/desktop/src/lib/audio-meter.ts +31 -2
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +114 -13
- package/corpus/templates/clips/desktop/src/lib/updater.ts +12 -4
- package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +40 -15
- package/corpus/templates/clips/desktop/src/styles.css +10 -7
- package/corpus/templates/clips/desktop/src-tauri/src/recording_indicator.rs +21 -14
- package/corpus/templates/clips/shared/transcript-status.ts +10 -0
- package/corpus/templates/content/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/content/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/content/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/content/_gitignore +2 -0
- package/corpus/templates/crm/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/design/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/design/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/design/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +46 -3
- package/corpus/templates/design/.generated/bridge/editor-chrome.generated.ts +7 -5
- package/corpus/templates/design/_gitignore +2 -0
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +2 -2
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +7 -4
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +1 -1
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +10 -4
- package/corpus/templates/design/app/i18n-data.ts +10 -0
- package/corpus/templates/design/app/lib/builder-design-system-upload.ts +280 -0
- package/corpus/templates/design/app/lib/design-ui-events.ts +5 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +90 -54
- package/corpus/templates/design/app/root.tsx +18 -1
- package/corpus/templates/design/changelog/2026-07-28-figma-fig-uploads-now-show-indexing-progress-and-an-open-in-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-28-show-or-hide-design-editing-chrome-with-cmd-on-apple-devices.md +6 -0
- package/corpus/templates/design/server/handlers/design-system-decode-job-status.ts +49 -0
- package/corpus/templates/design/server/handlers/design-system-upload-start.ts +87 -0
- package/corpus/templates/design/server/handlers/index-design-system-sources.ts +82 -0
- package/corpus/templates/design/server/routes/api/design-system-decode-job-status.get.ts +1 -0
- package/corpus/templates/design/server/routes/api/design-system-upload-start.post.ts +1 -0
- package/corpus/templates/design/server/routes/api/index-design-system-sources.post.ts +1 -0
- package/corpus/templates/dispatch/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/dispatch/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/dispatch/_gitignore +2 -0
- package/corpus/templates/forms/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/forms/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/forms/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/forms/_gitignore +2 -0
- package/corpus/templates/macros/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/macros/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/macros/_gitignore +2 -0
- package/corpus/templates/mail/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/mail/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/mail/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/mail/_gitignore +2 -0
- package/corpus/templates/plan/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/plan/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/plan/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/plan/_gitignore +2 -0
- package/corpus/templates/slides/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/slides/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/slides/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/slides/_gitignore +2 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +126 -53
- package/corpus/templates/slides/app/components/design-system/builder-design-system-upload.ts +271 -0
- package/corpus/templates/slides/app/components/design-system/builder-index-response.ts +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/server/handlers/design-system-decode-job-status.ts +49 -0
- package/corpus/templates/slides/server/handlers/design-system-upload-start.ts +87 -0
- package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +79 -0
- package/corpus/templates/slides/server/routes/api/design-system-decode-job-status.get.ts +1 -0
- package/corpus/templates/slides/server/routes/api/design-system-upload-start.post.ts +1 -0
- package/corpus/templates/slides/server/routes/api/index-design-system-sources.post.ts +1 -0
- package/corpus/templates/tasks/.agents/skills/actions/SKILL.md +32 -0
- package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/corpus/templates/tasks/.agents/skills/security/SKILL.md +31 -0
- package/corpus/templates/tasks/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/templates/tasks/_gitignore +2 -0
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +30 -29
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/action.d.ts +36 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +37 -2
- package/dist/action.js.map +1 -1
- package/dist/chat-threads/store.d.ts +12 -0
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +48 -42
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.d.ts.map +1 -1
- package/dist/cli/skills-content/design-visual-edit-skill.js +46 -3
- package/dist/cli/skills-content/design-visual-edit-skill.js.map +1 -1
- package/dist/client/AgentPanel.d.ts +3 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +11 -9
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +57 -6
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/DefaultSpinner.d.ts +7 -0
- package/dist/client/DefaultSpinner.d.ts.map +1 -1
- package/dist/client/DefaultSpinner.js +25 -1
- package/dist/client/DefaultSpinner.js.map +1 -1
- package/dist/client/org/TeamPage.d.ts +13 -1
- package/dist/client/org/TeamPage.d.ts.map +1 -1
- package/dist/client/org/TeamPage.js +41 -11
- package/dist/client/org/TeamPage.js.map +1 -1
- package/dist/client/org/hooks.d.ts +37 -0
- package/dist/client/org/hooks.d.ts.map +1 -1
- package/dist/client/org/hooks.js +37 -0
- package/dist/client/org/hooks.js.map +1 -1
- package/dist/client/org/index.d.ts +3 -2
- package/dist/client/org/index.d.ts.map +1 -1
- package/dist/client/org/index.js +1 -1
- package/dist/client/org/index.js.map +1 -1
- package/dist/client/transcription/use-live-transcription.d.ts +8 -0
- package/dist/client/transcription/use-live-transcription.d.ts.map +1 -1
- package/dist/client/transcription/use-live-transcription.js +38 -11
- package/dist/client/transcription/use-live-transcription.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts +12 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +40 -3
- package/dist/db/client.js.map +1 -1
- package/dist/db/ensure-additive-columns.d.ts.map +1 -1
- package/dist/db/ensure-additive-columns.js +54 -32
- package/dist/db/ensure-additive-columns.js.map +1 -1
- package/dist/deploy/build.d.ts +1 -0
- package/dist/deploy/build.d.ts.map +1 -1
- package/dist/deploy/build.js +23 -2
- package/dist/deploy/build.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp-client/routes.d.ts +3 -1
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +8 -2
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/org/app-roles-handlers.d.ts +27 -0
- package/dist/org/app-roles-handlers.d.ts.map +1 -0
- package/dist/org/app-roles-handlers.js +125 -0
- package/dist/org/app-roles-handlers.js.map +1 -0
- package/dist/org/app-roles.d.ts +136 -0
- package/dist/org/app-roles.d.ts.map +1 -0
- package/dist/org/app-roles.js +216 -0
- package/dist/org/app-roles.js.map +1 -0
- package/dist/org/index.d.ts +4 -1
- package/dist/org/index.d.ts.map +1 -1
- package/dist/org/index.js +3 -1
- package/dist/org/index.js.map +1 -1
- package/dist/org/migrations.d.ts.map +1 -1
- package/dist/org/migrations.js +22 -0
- package/dist/org/migrations.js.map +1 -1
- package/dist/org/plugin.d.ts +2 -0
- package/dist/org/plugin.d.ts.map +1 -1
- package/dist/org/plugin.js +20 -0
- package/dist/org/plugin.js.map +1 -1
- package/dist/org/schema.d.ts +143 -0
- package/dist/org/schema.d.ts.map +1 -1
- package/dist/org/schema.js +14 -0
- package/dist/org/schema.js.map +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +8 -8
- package/dist/provider-api/actions/provider-api.d.ts +4 -4
- package/dist/scripts/docs/search.d.ts.map +1 -1
- package/dist/scripts/docs/search.js +15 -0
- package/dist/scripts/docs/search.js.map +1 -1
- package/dist/scripts/docs/source-search.d.ts +7 -0
- package/dist/scripts/docs/source-search.d.ts.map +1 -1
- package/dist/scripts/docs/source-search.js +9 -0
- package/dist/scripts/docs/source-search.js.map +1 -1
- package/dist/secrets/routes.d.ts +9 -9
- package/dist/server/agent-chat/script-entries.d.ts.map +1 -1
- package/dist/server/agent-chat/script-entries.js +3 -0
- package/dist/server/agent-chat/script-entries.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +46 -48
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts +49 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +221 -69
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +6 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/framework-request-handler.d.ts.map +1 -1
- package/dist/server/framework-request-handler.js +42 -6
- package/dist/server/framework-request-handler.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/dist/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/docs/content/actions.mdx +47 -4
- package/docs/content/native-chat-ui.mdx +7 -0
- package/docs/content/organizations-teams-permissions.mdx +109 -3
- package/docs/content/template-design-collaboration-and-full-apps.mdx +15 -0
- package/docs/content/toolkit-org-team.mdx +72 -12
- package/package.json +2 -1
- package/src/a2a/artifact-response.ts +36 -29
- package/src/action.ts +83 -2
- package/src/chat-threads/store.ts +48 -43
- package/src/cli/skills-content/design-visual-edit-skill.ts +46 -3
- package/src/client/AgentPanel.tsx +26 -6
- package/src/client/AssistantChat.tsx +63 -7
- package/src/client/DefaultSpinner.tsx +29 -0
- package/src/client/org/TeamPage.tsx +161 -6
- package/src/client/org/hooks.ts +67 -0
- package/src/client/org/index.ts +9 -0
- package/src/client/transcription/use-live-transcription.ts +62 -10
- package/src/db/client.ts +42 -3
- package/src/db/ensure-additive-columns.ts +60 -33
- package/src/deploy/build.ts +31 -2
- package/src/mcp-client/routes.ts +10 -1
- package/src/org/app-roles-handlers.ts +152 -0
- package/src/org/app-roles.ts +355 -0
- package/src/org/index.ts +27 -1
- package/src/org/migrations.ts +22 -0
- package/src/org/plugin.ts +27 -0
- package/src/org/schema.ts +15 -0
- package/src/scripts/docs/search.ts +17 -0
- package/src/scripts/docs/source-search.ts +10 -0
- package/src/server/agent-chat/script-entries.ts +3 -0
- package/src/server/agent-chat-plugin.ts +53 -52
- package/src/server/builder-design-systems.ts +299 -82
- package/src/server/core-routes-plugin.ts +6 -1
- package/src/server/framework-request-handler.ts +44 -6
- package/src/server/index.ts +8 -0
- package/src/templates/chat/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/chat/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/chat/.agents/skills/sharing/SKILL.md +4 -0
- package/src/templates/default/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/default/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/headless/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +32 -0
- package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +7 -0
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +40 -0
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +31 -0
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +4 -0
- package/corpus/core/src/templates/chat/.agents/skills/actions/SKILL.md +0 -530
- package/corpus/core/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +0 -191
- package/corpus/core/src/templates/chat/.agents/skills/agent-native-docs/SKILL.md +0 -115
- package/corpus/core/src/templates/chat/.agents/skills/agent-native-toolkit/SKILL.md +0 -177
- package/corpus/core/src/templates/chat/.agents/skills/capture-learnings/SKILL.md +0 -89
- package/corpus/core/src/templates/chat/.agents/skills/create-skill/SKILL.md +0 -221
- package/corpus/core/src/templates/chat/.agents/skills/customizing-agent-native/SKILL.md +0 -220
- package/corpus/core/src/templates/chat/.agents/skills/delegate-to-agent/SKILL.md +0 -263
- package/corpus/core/src/templates/chat/.agents/skills/feature-flags/SKILL.md +0 -169
- package/corpus/core/src/templates/chat/.agents/skills/frontend-design/SKILL.md +0 -174
- package/corpus/core/src/templates/chat/.agents/skills/real-time-sync/SKILL.md +0 -232
- package/corpus/core/src/templates/chat/.agents/skills/security/SKILL.md +0 -282
- package/corpus/core/src/templates/chat/.agents/skills/self-modifying-code/SKILL.md +0 -119
- package/corpus/core/src/templates/chat/.agents/skills/shadcn-ui/SKILL.md +0 -123
- package/corpus/core/src/templates/chat/.agents/skills/upgrade-agent-native/SKILL.md +0 -122
- package/corpus/core/src/templates/chat/.env.example +0 -5
- package/corpus/core/src/templates/chat/.ignore +0 -0
- package/corpus/core/src/templates/chat/.oxfmtrc.json +0 -8
- package/corpus/core/src/templates/chat/AGENTS.md +0 -77
- package/corpus/core/src/templates/chat/CHANGELOG.md +0 -10
- package/corpus/core/src/templates/chat/DEVELOPING.md +0 -185
- package/corpus/core/src/templates/chat/README.md +0 -32
- package/corpus/core/src/templates/chat/_gitignore +0 -46
- package/corpus/core/src/templates/chat/actions/hello.ts +0 -13
- package/corpus/core/src/templates/chat/actions/navigate.ts +0 -41
- package/corpus/core/src/templates/chat/actions/run.ts +0 -2
- package/corpus/core/src/templates/chat/actions/view-screen.ts +0 -31
- package/corpus/core/src/templates/chat/app/components/layout/Header.tsx +0 -60
- package/corpus/core/src/templates/chat/app/components/layout/Layout.tsx +0 -188
- package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +0 -505
- package/corpus/core/src/templates/chat/app/components/ui/button.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/card.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/dropdown-menu.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/input.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/label.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/sheet.tsx +0 -1
- package/corpus/core/src/templates/chat/app/components/ui/toolkit-provider.tsx +0 -17
- package/corpus/core/src/templates/chat/app/components/ui/tooltip.tsx +0 -1
- package/corpus/core/src/templates/chat/app/design-system.ts +0 -3
- package/corpus/core/src/templates/chat/app/entry.client.tsx +0 -22
- package/corpus/core/src/templates/chat/app/entry.server.tsx +0 -10
- package/corpus/core/src/templates/chat/app/global.css +0 -93
- package/corpus/core/src/templates/chat/app/hooks/use-navigation-state.ts +0 -93
- package/corpus/core/src/templates/chat/app/i18n/ar-SA.ts +0 -68
- package/corpus/core/src/templates/chat/app/i18n/de-DE.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/en-US.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/es-ES.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/fr-FR.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/hi-IN.ts +0 -69
- package/corpus/core/src/templates/chat/app/i18n/index.ts +0 -34
- package/corpus/core/src/templates/chat/app/i18n/ja-JP.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/ko-KR.ts +0 -70
- package/corpus/core/src/templates/chat/app/i18n/pt-BR.ts +0 -71
- package/corpus/core/src/templates/chat/app/i18n/zh-CN.ts +0 -66
- package/corpus/core/src/templates/chat/app/i18n/zh-TW.ts +0 -66
- package/corpus/core/src/templates/chat/app/i18n-data.ts +0 -556
- package/corpus/core/src/templates/chat/app/lib/agent-page.tsx +0 -49
- package/corpus/core/src/templates/chat/app/lib/app-config.ts +0 -11
- package/corpus/core/src/templates/chat/app/lib/tab-id.ts +0 -1
- package/corpus/core/src/templates/chat/app/lib/utils.ts +0 -1
- package/corpus/core/src/templates/chat/app/root.tsx +0 -173
- package/corpus/core/src/templates/chat/app/routes/_index.tsx +0 -94
- package/corpus/core/src/templates/chat/app/routes/agent.tsx +0 -24
- package/corpus/core/src/templates/chat/app/routes/chat.$threadId.tsx +0 -1
- package/corpus/core/src/templates/chat/app/routes/database.tsx +0 -17
- package/corpus/core/src/templates/chat/app/routes/extensions.$id.$slug.tsx +0 -2
- package/corpus/core/src/templates/chat/app/routes/extensions.$id.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes/extensions.tsx +0 -5
- package/corpus/core/src/templates/chat/app/routes/observability.tsx +0 -19
- package/corpus/core/src/templates/chat/app/routes/settings.tsx +0 -89
- package/corpus/core/src/templates/chat/app/routes/team.tsx +0 -11
- package/corpus/core/src/templates/chat/app/routes.ts +0 -4
- package/corpus/core/src/templates/chat/app/vite-env.d.ts +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-24-a-new-settings-page-gives-quick-access-to-language-workspace.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-24-added-a-language-picker-and-localized-app-chrome-for-support.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-27-traditional-chinese-copy-uses-taiwan-terminology.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-28-left-sidebar-collapse-motion-and-footer-chrome-are-quieter.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-06-29-chat-layouts-adapt-when-the-agent-sidebar-is-open.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-08-settings-are-cleaner-and-searchable.md +0 -5
- package/corpus/core/src/templates/chat/changelog/2026-07-10-chat-now-makes-ai-connection-setup-clear-without-shifting-th.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-13-a-full-agent-page-now-brings-context-files-connections-jobs-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-14-chat-opens-reliably-on-hosted-deployments-instead-of-failing.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-14-fixed-chat-template-startup-with-older-core-versions.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-15-chat-navigation-focuses-on-chat-and-agent.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-17-the-agent-chat-sidebar-stays-closed-until-you-open-it-or-sta.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-compact-sidebar-footer.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-full-page-chat-keeps-the-active-conversation-when-moving-to-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-manage-agent-navigation-now-uses-the-connected-nodes-icon.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-22-recent-chats-are-easier-to-scan-and-expand.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-23-full-page-chat-is-better-centered-with-quieter-chat-history-.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-24-borderless-secondary-surfaces.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-24-sidebar-footer-controls-follow-a-consistent-order.md +0 -6
- package/corpus/core/src/templates/chat/changelog/2026-07-25-settings-navigation-now-keeps-manage-agent-as-a-dedicated-li.md +0 -6
- package/corpus/core/src/templates/chat/components.json +0 -20
- package/corpus/core/src/templates/chat/learnings.defaults.md +0 -5
- package/corpus/core/src/templates/chat/netlify.toml +0 -11
- package/corpus/core/src/templates/chat/package.json +0 -92
- package/corpus/core/src/templates/chat/public/agent-native-icon-dark.svg +0 -10
- package/corpus/core/src/templates/chat/public/agent-native-icon-light.svg +0 -10
- package/corpus/core/src/templates/chat/public/agent-native-logo-dark.svg +0 -21
- package/corpus/core/src/templates/chat/public/agent-native-logo-light.svg +0 -21
- package/corpus/core/src/templates/chat/public/favicon.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-180.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-192.svg +0 -1
- package/corpus/core/src/templates/chat/public/icon-512.svg +0 -1
- package/corpus/core/src/templates/chat/public/manifest.json +0 -21
- package/corpus/core/src/templates/chat/react-router.config.ts +0 -7
- package/corpus/core/src/templates/chat/server/middleware/auth.ts +0 -15
- package/corpus/core/src/templates/chat/server/plugins/agent-chat.ts +0 -21
- package/corpus/core/src/templates/chat/server/plugins/auth.ts +0 -17
- package/corpus/core/src/templates/chat/server/routes/[...page].get.ts +0 -5
- package/corpus/core/src/templates/chat/ssr-entry.ts +0 -15
- package/corpus/core/src/templates/chat/tsconfig.json +0 -21
- package/corpus/core/src/templates/chat/vite.config.ts +0 -19
- package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +0 -151
- package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +0 -1
- package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +0 -119
- package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +0 -1
|
@@ -305,6 +305,38 @@ export default defineAction({
|
|
|
305
305
|
|
|
306
306
|
On success the validated value is returned, so coercion/defaults on `outputSchema` apply. Omit `outputSchema` and behavior is byte-for-byte unchanged (no wrapping).
|
|
307
307
|
|
|
308
|
+
### Authorization (`authorize`)
|
|
309
|
+
|
|
310
|
+
`authorize` decides whether the caller may run the action at all. It wraps
|
|
311
|
+
`run`, so it holds at **all six dispatch sites** — agent tool, HTTP, frontend
|
|
312
|
+
hook, MCP, A2A, CLI — unlike `needsApproval`, which is honoured only in the
|
|
313
|
+
agent loop. Use `authorize` for "not everyone may do this"; use `needsApproval`
|
|
314
|
+
to ask a human to bless one call a permitted caller is already allowed to make.
|
|
315
|
+
|
|
316
|
+
```ts
|
|
317
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
318
|
+
|
|
319
|
+
export default defineAction({
|
|
320
|
+
description: "Archive a client roster.",
|
|
321
|
+
schema: z.object({ id: z.string() }),
|
|
322
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
323
|
+
run: async (args) => {
|
|
324
|
+
/* ... */
|
|
325
|
+
},
|
|
326
|
+
});
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
The wrappers compose as `validate input -> authorize -> run -> validate output
|
|
330
|
+
-> audit`: the gate sits inside input validation, so a guard reading `args` gets
|
|
331
|
+
the parsed, coerced value, and auditing is outermost, so denials are recorded.
|
|
332
|
+
|
|
333
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
334
|
+
generically; anything else (including `undefined`) allows. A guarded action
|
|
335
|
+
needs a user identity, so an unattended CLI/cron caller with no user email is
|
|
336
|
+
denied. `authorize` gates the operation; `accessFilter` / `assertAccess` still
|
|
337
|
+
scope which rows a permitted caller may touch. See the `authentication` skill
|
|
338
|
+
for `defineAppRoles` and the `sharing` skill for row scoping.
|
|
339
|
+
|
|
308
340
|
### Human-in-the-Loop Approval (`needsApproval`)
|
|
309
341
|
|
|
310
342
|
For high-consequence, outward-facing, hard-to-undo actions (sending an email, charging a card, deleting an account), set `needsApproval` so the agent **cannot** run the action without a human approving the specific call:
|
|
@@ -159,6 +159,35 @@ whole site. Data scoping lives in actions and API routes; the client gates
|
|
|
159
159
|
private UI after the shell loads. See the `authentication` skill and
|
|
160
160
|
`guard:ssr-cache-shell` / `ssr-handler.spec.ts`.
|
|
161
161
|
|
|
162
|
+
**Authorization beyond "is there a session" — `authorize`.** The auth guard only
|
|
163
|
+
proves *someone* is signed in. To restrict an operation to some teammates, set
|
|
164
|
+
`authorize` on the `defineAction`. It wraps `run`, so it applies at every
|
|
165
|
+
dispatch site (agent tool, HTTP, frontend, MCP, A2A, CLI) — unlike
|
|
166
|
+
`needsApproval`, which is honoured only in the agent loop.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { coachAccess } from "../lib/access.js"; // defineAppRoles(...)
|
|
170
|
+
|
|
171
|
+
export default defineAction({
|
|
172
|
+
description: "Archive a client roster.",
|
|
173
|
+
schema: z.object({ id: z.string() }),
|
|
174
|
+
authorize: coachAccess.requireAny("coach-admin"),
|
|
175
|
+
run: async (args) => {
|
|
176
|
+
/* ... */
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
A guard that throws denies with its own message; returning `false` denies
|
|
182
|
+
generically; anything else (including `undefined`) allows. Guarded actions need
|
|
183
|
+
a user identity — an unattended CLI/cron caller with no user email is denied.
|
|
184
|
+
|
|
185
|
+
`authorize` is **not** a substitute for `accessFilter` / `assertAccess`. It
|
|
186
|
+
decides whether this caller may perform the operation at all; `accessFilter` /
|
|
187
|
+
`assertAccess` scope which rows a permitted caller may see or touch. A
|
|
188
|
+
restricted write action needs both. See the `authentication` skill for
|
|
189
|
+
`defineAppRoles` and the `actions` skill for the full surface.
|
|
190
|
+
|
|
162
191
|
## Human-in-the-Loop Approval for High-Consequence Actions
|
|
163
192
|
|
|
164
193
|
For a small set of outward-facing, hard-to-undo operations — sending an email, charging a card, deleting an account, posting publicly — auth and access control are necessary but not sufficient: you also do not want the **agent** to perform them autonomously. Set `needsApproval` on the `defineAction` so the agent cannot run the action without a human approving the specific call.
|
|
@@ -274,6 +303,8 @@ Run `pnpm action db-check-scoping` to verify. Use `--require-org` for multi-org
|
|
|
274
303
|
- [ ] New env vars in `.env` only, not committed
|
|
275
304
|
- [ ] New user-data tables have `owner_email` column
|
|
276
305
|
- [ ] Custom routes call `getSession` and reject unauthenticated requests
|
|
306
|
+
- [ ] Actions only some teammates may run set `authorize` (in addition to any
|
|
307
|
+
`accessFilter` / `assertAccess` row scoping)
|
|
277
308
|
|
|
278
309
|
## Related Skills
|
|
279
310
|
|
|
@@ -34,6 +34,8 @@ Visibility is coarse. Explicit share grants are fine-grained (per user or per or
|
|
|
34
34
|
- **`editor`** — read + write.
|
|
35
35
|
- **`admin`** — read + write + manage shares. Does NOT replace the single `owner_email` on the resource.
|
|
36
36
|
|
|
37
|
+
There are three role systems and they never imply one another. A share role answers "what may this person do to **one row**". An org role (`org_members.role`) answers "what may this person do to the **team**". An app role (`defineAppRoles`, see the `authentication` skill) answers "what may this person do inside **one app**". A share `admin` is not an app admin and neither is an org admin.
|
|
38
|
+
|
|
37
39
|
### Anonymous public URLs stay separate
|
|
38
40
|
|
|
39
41
|
Form "publish" slugs, booking-link slugs, any feature that exposes a URL to unauthenticated users — these are a different axis and are NOT controlled by the sharing system. Keep them alongside it.
|
|
@@ -137,6 +139,8 @@ export default defineAction({
|
|
|
137
139
|
|
|
138
140
|
For delete actions use `"admin"` (or fold in `"owner"` to require the real owner).
|
|
139
141
|
|
|
142
|
+
`authorize` is a different axis, not an alternative: it gates whether the caller may run the operation at all, while `assertAccess` scopes which row they may touch. A write action restricted to some teammates needs both — `authorize: appAccess.requireAny(...)` on the action, `assertAccess` inside `run`.
|
|
143
|
+
|
|
140
144
|
## Create actions must set owner
|
|
141
145
|
|
|
142
146
|
When inserting a new row, fill `ownerEmail` and `orgId` from the request context:
|
|
@@ -25,6 +25,32 @@ hosted Design MCP connector together. The open Skills CLI path
|
|
|
25
25
|
(`npx skills@latest add BuilderIO/agent-native --skill visual-edit`) installs
|
|
26
26
|
exported instructions only, with no MCP connector registration.
|
|
27
27
|
|
|
28
|
+
## Put Design Beside The Chat
|
|
29
|
+
|
|
30
|
+
After `open-visual-edit` returns `openUrl`, open that URL in the coding host's
|
|
31
|
+
inline browser when one is available. This is the preferred working surface:
|
|
32
|
+
the user can keep Design's canvas beside the conversation, inspect the same
|
|
33
|
+
screens as the agent, and iterate without switching apps.
|
|
34
|
+
|
|
35
|
+
- In Codex Desktop, use the in-app Browser tool to open `openUrl`. The built-in
|
|
36
|
+
browser is the right surface for localhost and public pages that should stay
|
|
37
|
+
inside the app.
|
|
38
|
+
- In Claude Code Desktop's Code tab, open or preview `openUrl` in the Browser
|
|
39
|
+
pane. Ask Claude to preview it rather than opening the system browser.
|
|
40
|
+
- In VS Code, use the Agent Native Design webview/deep link described below.
|
|
41
|
+
- Inline browser availability is host-dependent. CLI, remote, or restricted
|
|
42
|
+
sessions may not expose one. If the inline surface is unavailable or disabled,
|
|
43
|
+
return the normal **Open design** link instead of claiming it opened.
|
|
44
|
+
|
|
45
|
+
Prefer the host's browser/preview tool over telling the user to press a keyboard
|
|
46
|
+
shortcut. Keep the canvas pane beside chat when the host supports rearrangeable
|
|
47
|
+
panes.
|
|
48
|
+
|
|
49
|
+
Inside Design, use **Show/Hide UI** from the `Cmd+K` menu or press
|
|
50
|
+
`Cmd+Shift+\` on Apple platforms / `Ctrl+Shift+\` elsewhere to toggle all
|
|
51
|
+
editing chrome so only the canvas remains. The same action is available from
|
|
52
|
+
Design's empty-canvas context menu.
|
|
53
|
+
|
|
28
54
|
## Core Model
|
|
29
55
|
|
|
30
56
|
- Each screen is a URL-backed iframe, not copied HTML.
|
|
@@ -54,6 +80,23 @@ exported instructions only, with no MCP connector registration.
|
|
|
54
80
|
`localhost:1234/onboarding/1` means
|
|
55
81
|
`http://localhost:1234/onboarding/1`.
|
|
56
82
|
|
|
83
|
+
## Useful Canvas Sets
|
|
84
|
+
|
|
85
|
+
Translate the user's requested review into the smallest useful set of frames:
|
|
86
|
+
|
|
87
|
+
- **Multi-step flow:** one ordered frame per route or query state, such as cart,
|
|
88
|
+
shipping, payment, and confirmation.
|
|
89
|
+
- **Multiple pages:** one frame per meaningful route, such as home, pricing,
|
|
90
|
+
docs, and account settings.
|
|
91
|
+
- **Responsive comparison:** repeat the same route at the requested desktop,
|
|
92
|
+
tablet, and mobile viewports so they align in one row.
|
|
93
|
+
- **State review:** repeat a route for meaningful URL-addressable states such as
|
|
94
|
+
empty, loading, error, modal-open, or selected-item views.
|
|
95
|
+
|
|
96
|
+
Do not expand every discovered route or every viewport unless the user asks for
|
|
97
|
+
an exhaustive audit. Preserve the user's labels and sequence so the canvas reads
|
|
98
|
+
like the workflow they described.
|
|
99
|
+
|
|
57
100
|
## Select And Reprompt
|
|
58
101
|
|
|
59
102
|
When a chat message begins with `[Reprompt selection]`, the selected subtree is
|
|
@@ -275,9 +318,9 @@ Fallback, only when `open-visual-edit` is unavailable:
|
|
|
275
318
|
## Open The Design Surface
|
|
276
319
|
|
|
277
320
|
- Use the `link`, `deepLink`, or MCP App embed returned by Design actions so
|
|
278
|
-
the user sees the canvas.
|
|
279
|
-
|
|
280
|
-
|
|
321
|
+
the user sees the canvas. Follow **Put Design Beside The Chat**: prefer the
|
|
322
|
+
host's inline Browser, preview, or webview panel; otherwise surface the
|
|
323
|
+
**Open design** link.
|
|
281
324
|
- Return or open the `openUrl` / action link, not a hand-built
|
|
282
325
|
`/design/:id?_session=...` URL.
|
|
283
326
|
- If the user is working in VS Code, the Agent Native extension can open the
|
|
@@ -3177,17 +3177,19 @@ export const editorChromeBridgeScript: string = `"use strict";
|
|
|
3177
3177
|
// Cmd/Ctrl+R rename / Cmd/Ctrl+Shift+R paste-to-replace (onRename /
|
|
3178
3178
|
// onPasteToReplace) — both live under bare primary+r.
|
|
3179
3179
|
"r",
|
|
3180
|
-
// Cmd/Ctrl
|
|
3181
|
-
|
|
3180
|
+
// Cmd/Ctrl+K — open the host command menu even while the iframe has
|
|
3181
|
+
// focus. DesignEditor routes this chord to openCommandMenu().
|
|
3182
|
+
"k"
|
|
3182
3183
|
].indexOf(normalized) !== -1 || e.code === "Digit1" || e.code === "Digit2" || key === "1" || key === "2" || // Cmd/Ctrl+Shift+H / +L — toggle hidden / toggle locked
|
|
3183
3184
|
// (onToggleHidden / onToggleLocked). Gated on shiftKey so bare
|
|
3184
3185
|
// Cmd+H / Cmd+L — common OS "Hide app" / browser "focus address bar"
|
|
3185
3186
|
// shortcuts the host has no bare-primary binding for — are left
|
|
3186
3187
|
// alone (see useDesignHotkeys.ts: both require event.shiftKey).
|
|
3187
|
-
e.shiftKey && (normalized === "h" || normalized === "l") || // Cmd/Ctrl+
|
|
3188
|
+
e.shiftKey && (normalized === "h" || normalized === "l") || // Cmd/Ctrl+Shift+\\ — minimize UI (onToggleUi). Keep the Shift gate
|
|
3189
|
+
// here so the iframe never intercepts a desktop host's bare Cmd/Ctrl+\\.
|
|
3190
|
+
e.shiftKey && normalized === "\\\\" || // Cmd/Ctrl+Alt+B detach instance / Cmd/Ctrl+Alt+K create component
|
|
3188
3191
|
// (onDetachInstance / onCreateComponent). Gated on altKey so bare
|
|
3189
|
-
// Cmd+B
|
|
3190
|
-
// binding for either.
|
|
3192
|
+
// Cmd+B is left alone — the host has no bare-primary binding for it.
|
|
3191
3193
|
e.altKey && (normalized === "b" || normalized === "k") || // Ctrl+Alt+H / Ctrl+Alt+T — distribute horizontal / tidy up
|
|
3192
3194
|
// (onDistributeSelection / onTidyUp). useDesignHotkeys.ts keeps these
|
|
3193
3195
|
// on LITERAL Control on every platform (never remapped to Cmd), so
|
|
@@ -52,7 +52,7 @@ import type { CanvasLayerHitCandidate } from "./types";
|
|
|
52
52
|
// EMPTY canvas (no selection):
|
|
53
53
|
// Paste here
|
|
54
54
|
// [sep]
|
|
55
|
-
// Show/Hide UI
|
|
55
|
+
// Show/Hide UI ⇧⌘\ · Show/Hide comments ⇧C
|
|
56
56
|
//
|
|
57
57
|
// Real Figma has no Duplicate/Delete/Select-all/Zoom items on either canvas
|
|
58
58
|
// menu (all keyboard-only there) — those are intentionally NOT rendered here
|
|
@@ -461,7 +461,7 @@ const DEFAULT_SHORTCUTS: CanvasContextMenuShortcuts = {
|
|
|
461
461
|
rotateClockwise: "",
|
|
462
462
|
flipHorizontal: "⇧H",
|
|
463
463
|
flipVertical: "⇧V",
|
|
464
|
-
toggleUi: "
|
|
464
|
+
toggleUi: "⇧⌘\\",
|
|
465
465
|
toggleComments: "⇧C",
|
|
466
466
|
};
|
|
467
467
|
|
|
@@ -4672,8 +4672,9 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
4672
4672
|
// Cmd/Ctrl+R rename / Cmd/Ctrl+Shift+R paste-to-replace (onRename /
|
|
4673
4673
|
// onPasteToReplace) — both live under bare primary+r.
|
|
4674
4674
|
"r",
|
|
4675
|
-
// Cmd/Ctrl
|
|
4676
|
-
|
|
4675
|
+
// Cmd/Ctrl+K — open the host command menu even while the iframe has
|
|
4676
|
+
// focus. DesignEditor routes this chord to openCommandMenu().
|
|
4677
|
+
"k",
|
|
4677
4678
|
].indexOf(normalized) !== -1 ||
|
|
4678
4679
|
e.code === "Digit1" ||
|
|
4679
4680
|
e.code === "Digit2" ||
|
|
@@ -4685,10 +4686,12 @@ declare var __SELECTED_LAYER_DRAG_PRIORITY__: boolean;
|
|
|
4685
4686
|
// shortcuts the host has no bare-primary binding for — are left
|
|
4686
4687
|
// alone (see useDesignHotkeys.ts: both require event.shiftKey).
|
|
4687
4688
|
(e.shiftKey && (normalized === "h" || normalized === "l")) ||
|
|
4689
|
+
// Cmd/Ctrl+Shift+\ — minimize UI (onToggleUi). Keep the Shift gate
|
|
4690
|
+
// here so the iframe never intercepts a desktop host's bare Cmd/Ctrl+\.
|
|
4691
|
+
(e.shiftKey && normalized === "\\") ||
|
|
4688
4692
|
// Cmd/Ctrl+Alt+B detach instance / Cmd/Ctrl+Alt+K create component
|
|
4689
4693
|
// (onDetachInstance / onCreateComponent). Gated on altKey so bare
|
|
4690
|
-
// Cmd+B
|
|
4691
|
-
// binding for either.
|
|
4694
|
+
// Cmd+B is left alone — the host has no bare-primary binding for it.
|
|
4692
4695
|
(e.altKey && (normalized === "b" || normalized === "k")) ||
|
|
4693
4696
|
// Ctrl+Alt+H / Ctrl+Alt+T — distribute horizontal / tidy up
|
|
4694
4697
|
// (onDistributeSelection / onTidyUp). useDesignHotkeys.ts keeps these
|
|
@@ -142,7 +142,7 @@ export const DESIGN_SHORTCUTS: readonly DesignShortcutDefinition[] = [
|
|
|
142
142
|
shortcut({
|
|
143
143
|
id: "toggle-ui",
|
|
144
144
|
category: "view",
|
|
145
|
-
bindings: ["$mod+\\"],
|
|
145
|
+
bindings: ["$mod+shift+\\"],
|
|
146
146
|
labelKey: "designEditor.keyboardShortcuts.commands.toggleUi",
|
|
147
147
|
handler: "onToggleUi",
|
|
148
148
|
}),
|
|
@@ -203,8 +203,8 @@ export interface UseDesignHotkeysProps {
|
|
|
203
203
|
* modifiers held) or SHIFT_TOOL_SHORTCUTS (which has no "a" entry).
|
|
204
204
|
*/
|
|
205
205
|
onAddAutoLayout?: DesignHotkeyHandler;
|
|
206
|
-
/** Figma's Cmd+\
|
|
207
|
-
*
|
|
206
|
+
/** Figma's Cmd/Ctrl+Shift+\ "Minimize UI" shortcut, applied here to the
|
|
207
|
+
* full Design chrome (left rail, right panel, and bottom toolbar). */
|
|
208
208
|
onToggleUi?: DesignHotkeyHandler;
|
|
209
209
|
/** Figma's Shift+C — toggle Show/Hide comments (comment pins). */
|
|
210
210
|
onToggleComments?: DesignHotkeyHandler;
|
|
@@ -725,8 +725,14 @@ export function handleDesignHotkey(
|
|
|
725
725
|
return run(props.onAddAutoLayout);
|
|
726
726
|
}
|
|
727
727
|
|
|
728
|
-
// Figma
|
|
729
|
-
|
|
728
|
+
// Figma's "Minimize UI" chord avoids the bare Cmd+\ shortcut that desktop
|
|
729
|
+
// coding hosts can reserve for closing their focused pane.
|
|
730
|
+
if (
|
|
731
|
+
isPlatformPrimaryModifier(event) &&
|
|
732
|
+
!event.altKey &&
|
|
733
|
+
event.shiftKey &&
|
|
734
|
+
key === "\\"
|
|
735
|
+
) {
|
|
730
736
|
return run(props.onToggleUi);
|
|
731
737
|
}
|
|
732
738
|
|
|
@@ -1422,6 +1422,7 @@ const enUS = {
|
|
|
1422
1422
|
figmaParsingTitle: "Starting Builder DSI indexing...",
|
|
1423
1423
|
figmaParsingDescription:
|
|
1424
1424
|
"Builder will extract tokens, components, assets, and usage guidance",
|
|
1425
|
+
figmaDecodeFailed: "Decoding failed: {{error}}",
|
|
1425
1426
|
uploadFig: "Connect Figma with a .fig file",
|
|
1426
1427
|
figmaSaveLocalCopy:
|
|
1427
1428
|
"Upload a local copy from Figma: File -> Save local copy",
|
|
@@ -1891,6 +1892,7 @@ const designLocaleOverrides = {
|
|
|
1891
1892
|
"通过 Builder DSI 连接 Figma、代码和可选的 design.md 指引。上下文越多,代理得到的系统越准确。",
|
|
1892
1893
|
figmaParsingTitle: "正在启动 Builder DSI 索引...",
|
|
1893
1894
|
figmaParsingDescription: "Builder 会提取令牌、组件、资产和使用指引",
|
|
1895
|
+
figmaDecodeFailed: "解码失败:{{error}}",
|
|
1894
1896
|
uploadFig: "连接 Figma .fig 文件",
|
|
1895
1897
|
figmaSaveLocalCopy: "上传 Figma 本地副本:File -> Save local copy",
|
|
1896
1898
|
websiteUrl: "网站URL",
|
|
@@ -2295,6 +2297,7 @@ const designLocaleOverrides = {
|
|
|
2295
2297
|
figmaParsingTitle: "Iniciando indexación de Builder DSI...",
|
|
2296
2298
|
figmaParsingDescription:
|
|
2297
2299
|
"Builder extraerá tokens, componentes, recursos y guía de uso.",
|
|
2300
|
+
figmaDecodeFailed: "Error al decodificar: {{error}}",
|
|
2298
2301
|
uploadFig: "Conectar Figma con un archivo .fig",
|
|
2299
2302
|
figmaSaveLocalCopy:
|
|
2300
2303
|
"Sube una copia local de Figma: File -> Save local copy",
|
|
@@ -2720,6 +2723,7 @@ const designLocaleOverrides = {
|
|
|
2720
2723
|
figmaParsingTitle: "Démarrage de l’indexation Builder DSI...",
|
|
2721
2724
|
figmaParsingDescription:
|
|
2722
2725
|
"Builder extraira les jetons, composants, ressources et consignes d’utilisation",
|
|
2726
|
+
figmaDecodeFailed: "Échec du décodage : {{error}}",
|
|
2723
2727
|
uploadFig: "Connecter Figma avec un fichier .fig",
|
|
2724
2728
|
figmaSaveLocalCopy:
|
|
2725
2729
|
"Importez une copie locale Figma : File -> Save local copy",
|
|
@@ -3145,6 +3149,7 @@ const designLocaleOverrides = {
|
|
|
3145
3149
|
figmaParsingTitle: "Builder-DSI-Indizierung wird gestartet...",
|
|
3146
3150
|
figmaParsingDescription:
|
|
3147
3151
|
"Builder extrahiert Tokens, Komponenten, Assets und Nutzungsanweisungen",
|
|
3152
|
+
figmaDecodeFailed: "Dekodierung fehlgeschlagen: {{error}}",
|
|
3148
3153
|
uploadFig: "Figma mit einer .fig-Datei verbinden",
|
|
3149
3154
|
figmaSaveLocalCopy:
|
|
3150
3155
|
"Lade eine lokale Figma-Kopie hoch: File -> Save local copy",
|
|
@@ -3570,6 +3575,7 @@ const designLocaleOverrides = {
|
|
|
3570
3575
|
figmaParsingTitle: "Builder DSI のインデックス作成を開始しています...",
|
|
3571
3576
|
figmaParsingDescription:
|
|
3572
3577
|
"Builder がトークン、コンポーネント、アセット、利用ガイドを抽出します",
|
|
3578
|
+
figmaDecodeFailed: "デコードに失敗しました: {{error}}",
|
|
3573
3579
|
uploadFig: "Figma .fig ファイルを接続",
|
|
3574
3580
|
figmaSaveLocalCopy:
|
|
3575
3581
|
"Figma のローカルコピーをアップロード: File -> Save local copy",
|
|
@@ -3990,6 +3996,7 @@ const designLocaleOverrides = {
|
|
|
3990
3996
|
figmaParsingTitle: "Builder DSI 색인 생성을 시작하는 중...",
|
|
3991
3997
|
figmaParsingDescription:
|
|
3992
3998
|
"Builder가 토큰, 컴포넌트, 자산, 사용 지침을 추출합니다",
|
|
3999
|
+
figmaDecodeFailed: "디코딩에 실패했습니다: {{error}}",
|
|
3993
4000
|
uploadFig: "Figma .fig 파일 연결",
|
|
3994
4001
|
figmaSaveLocalCopy: "Figma 로컬 사본 업로드: File -> Save local copy",
|
|
3995
4002
|
websiteUrl: "웹사이트 URL",
|
|
@@ -4404,6 +4411,7 @@ const designLocaleOverrides = {
|
|
|
4404
4411
|
figmaParsingTitle: "Iniciando indexação do Builder DSI...",
|
|
4405
4412
|
figmaParsingDescription:
|
|
4406
4413
|
"Builder extrairá tokens, componentes, recursos e orientações de uso",
|
|
4414
|
+
figmaDecodeFailed: "Falha na decodificação: {{error}}",
|
|
4407
4415
|
uploadFig: "Conectar Figma com um arquivo .fig",
|
|
4408
4416
|
figmaSaveLocalCopy:
|
|
4409
4417
|
"Envie uma cópia local do Figma: File -> Save local copy",
|
|
@@ -4824,6 +4832,7 @@ const designLocaleOverrides = {
|
|
|
4824
4832
|
figmaParsingTitle: "Builder DSI indexing शुरू की जा रही है...",
|
|
4825
4833
|
figmaParsingDescription:
|
|
4826
4834
|
"Builder टोकन, कंपोनेंट, एसेट और उपयोग मार्गदर्शन निकालेगा",
|
|
4835
|
+
figmaDecodeFailed: "डिकोडिंग विफल: {{error}}",
|
|
4827
4836
|
uploadFig: "Figma .fig फ़ाइल कनेक्ट करें",
|
|
4828
4837
|
figmaSaveLocalCopy: "Figma स्थानीय कॉपी अपलोड करें: File -> Save local copy",
|
|
4829
4838
|
websiteUrl: "वेबसाइट URL",
|
|
@@ -5234,6 +5243,7 @@ const designLocaleOverrides = {
|
|
|
5234
5243
|
figmaParsingTitle: "جارٍ بدء فهرسة Builder DSI...",
|
|
5235
5244
|
figmaParsingDescription:
|
|
5236
5245
|
"سيستخرج Builder الرموز والمكونات والأصول وإرشادات الاستخدام",
|
|
5246
|
+
figmaDecodeFailed: "فشل فك الترميز: {{error}}",
|
|
5237
5247
|
uploadFig: "ربط Figma بملف .fig",
|
|
5238
5248
|
figmaSaveLocalCopy: "حمّل نسخة Figma محلية: File -> Save local copy",
|
|
5239
5249
|
websiteUrl: "موقع URL",
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
import { appApiPath } from "@agent-native/core/client/api-path";
|
|
2
|
+
|
|
3
|
+
// GCS resumable uploads require every chunk except the last to be a multiple
|
|
4
|
+
// of 256 KiB. 16 MiB is the recommended default and keeps very large `.fig`
|
|
5
|
+
// files off a single request body (the serverless host caps bodies well below
|
|
6
|
+
// Figma export sizes).
|
|
7
|
+
const GCS_CHUNK_SIZE = 16 * 1024 * 1024;
|
|
8
|
+
const MAX_CHUNK_RETRIES = 5;
|
|
9
|
+
|
|
10
|
+
interface UploadSlot {
|
|
11
|
+
idx: number;
|
|
12
|
+
uploadUrl: string;
|
|
13
|
+
uploadToken: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface BuilderIndexResult {
|
|
17
|
+
designSystemId: string;
|
|
18
|
+
localDesignSystemId?: string;
|
|
19
|
+
builderUrl?: string;
|
|
20
|
+
suggestedTitle?: string | null;
|
|
21
|
+
status?: string;
|
|
22
|
+
uploadedFileCount?: number;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function readJson(res: Response): Promise<any> {
|
|
27
|
+
try {
|
|
28
|
+
return await res.json();
|
|
29
|
+
} catch {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function requestUploadSlots(files: File[]): Promise<UploadSlot[]> {
|
|
35
|
+
const res = await fetch(appApiPath("/api/design-system-upload-start"), {
|
|
36
|
+
method: "POST",
|
|
37
|
+
headers: { "Content-Type": "application/json" },
|
|
38
|
+
body: JSON.stringify({
|
|
39
|
+
attachments: files.map((file) => ({
|
|
40
|
+
name: file.name,
|
|
41
|
+
mimetype: file.type || "application/octet-stream",
|
|
42
|
+
declaredSize: file.size,
|
|
43
|
+
})),
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
const json = await readJson(res);
|
|
47
|
+
if (!res.ok || json?.error) {
|
|
48
|
+
throw new Error(json?.error || `Failed to start upload (${res.status})`);
|
|
49
|
+
}
|
|
50
|
+
const slots = Array.isArray(json?.uploads)
|
|
51
|
+
? ([...json.uploads] as UploadSlot[]).sort((a, b) => a.idx - b.idx)
|
|
52
|
+
: [];
|
|
53
|
+
if (slots.length !== files.length) {
|
|
54
|
+
throw new Error("Upload could not be started for all files.");
|
|
55
|
+
}
|
|
56
|
+
return slots;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function initiateResumableSession(
|
|
60
|
+
uploadUrl: string,
|
|
61
|
+
mimetype: string,
|
|
62
|
+
fileSize: number,
|
|
63
|
+
): Promise<string> {
|
|
64
|
+
const response = await fetch(uploadUrl, {
|
|
65
|
+
method: "POST",
|
|
66
|
+
headers: {
|
|
67
|
+
"x-goog-resumable": "start",
|
|
68
|
+
// The signed URL commits to the exact declared size; echo it back
|
|
69
|
+
// byte-for-byte or GCS rejects the session.
|
|
70
|
+
"x-goog-content-length-range": `0,${fileSize}`,
|
|
71
|
+
"Content-Type": mimetype,
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
if (!response.ok) {
|
|
75
|
+
throw new Error(`Failed to initiate upload session (${response.status})`);
|
|
76
|
+
}
|
|
77
|
+
const sessionUri = response.headers.get("Location");
|
|
78
|
+
if (!sessionUri) {
|
|
79
|
+
throw new Error("Upload session URI missing from storage response");
|
|
80
|
+
}
|
|
81
|
+
return sessionUri;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// GCS reports the highest committed byte in a `Range: bytes=0-<end>` header.
|
|
85
|
+
function committedOffsetFromRange(response: Response): number | null {
|
|
86
|
+
const match = response.headers.get("Range")?.match(/bytes=0-(\d+)/);
|
|
87
|
+
return match ? parseInt(match[1], 10) + 1 : null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function queryCommittedOffset(
|
|
91
|
+
sessionUri: string,
|
|
92
|
+
total: number,
|
|
93
|
+
): Promise<number> {
|
|
94
|
+
const response = await fetch(sessionUri, {
|
|
95
|
+
method: "PUT",
|
|
96
|
+
headers: { "Content-Range": `bytes */${total}` },
|
|
97
|
+
});
|
|
98
|
+
if (response.status === 200 || response.status === 201) return total;
|
|
99
|
+
if (response.status === 308) return committedOffsetFromRange(response) ?? 0;
|
|
100
|
+
throw new Error(`Failed to query upload status (${response.status})`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function delay(ms: number, signal?: AbortSignal): Promise<void> {
|
|
104
|
+
return new Promise((resolve, reject) => {
|
|
105
|
+
if (signal?.aborted) {
|
|
106
|
+
return reject(new DOMException("Aborted", "AbortError"));
|
|
107
|
+
}
|
|
108
|
+
const timer = setTimeout(resolve, ms);
|
|
109
|
+
signal?.addEventListener(
|
|
110
|
+
"abort",
|
|
111
|
+
() => {
|
|
112
|
+
clearTimeout(timer);
|
|
113
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
114
|
+
},
|
|
115
|
+
{ once: true },
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function streamFileToStorage(
|
|
121
|
+
slot: UploadSlot,
|
|
122
|
+
file: File,
|
|
123
|
+
onProgress: (uploadedBytes: number) => void,
|
|
124
|
+
): Promise<void> {
|
|
125
|
+
const mimetype = file.type || "application/octet-stream";
|
|
126
|
+
const sessionUri = await initiateResumableSession(
|
|
127
|
+
slot.uploadUrl,
|
|
128
|
+
mimetype,
|
|
129
|
+
file.size,
|
|
130
|
+
);
|
|
131
|
+
const total = file.size;
|
|
132
|
+
|
|
133
|
+
if (total === 0) {
|
|
134
|
+
const response = await fetch(sessionUri, {
|
|
135
|
+
method: "PUT",
|
|
136
|
+
headers: { "Content-Range": "bytes */0" },
|
|
137
|
+
body: new Uint8Array(0),
|
|
138
|
+
});
|
|
139
|
+
if (response.status !== 200 && response.status !== 201) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Failed to finalize zero-byte upload (${response.status})`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
onProgress(0);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
let offset = 0;
|
|
149
|
+
let retries = 0;
|
|
150
|
+
while (offset < total) {
|
|
151
|
+
const end = Math.min(offset + GCS_CHUNK_SIZE, total);
|
|
152
|
+
const isLast = end === total;
|
|
153
|
+
try {
|
|
154
|
+
const response = await fetch(sessionUri, {
|
|
155
|
+
method: "PUT",
|
|
156
|
+
headers: { "Content-Range": `bytes ${offset}-${end - 1}/${total}` },
|
|
157
|
+
body: file.slice(offset, end),
|
|
158
|
+
});
|
|
159
|
+
if (response.status === 200 || response.status === 201) {
|
|
160
|
+
offset = total;
|
|
161
|
+
} else if (!isLast && response.status === 308) {
|
|
162
|
+
const nextOffset = committedOffsetFromRange(response) ?? offset;
|
|
163
|
+
if (nextOffset <= offset) {
|
|
164
|
+
throw new Error(`Upload stalled at byte ${offset}`);
|
|
165
|
+
}
|
|
166
|
+
offset = nextOffset;
|
|
167
|
+
} else {
|
|
168
|
+
throw new Error(`Unexpected upload status ${response.status}`);
|
|
169
|
+
}
|
|
170
|
+
retries = 0;
|
|
171
|
+
onProgress(offset);
|
|
172
|
+
} catch (err) {
|
|
173
|
+
if (++retries > MAX_CHUNK_RETRIES) throw err;
|
|
174
|
+
await delay(500 * retries);
|
|
175
|
+
try {
|
|
176
|
+
offset = await queryCommittedOffset(sessionUri, total);
|
|
177
|
+
} catch {
|
|
178
|
+
// If the offset query also fails, retry from the last local offset —
|
|
179
|
+
// GCS's resumable PUT safely re-acknowledges bytes it already has.
|
|
180
|
+
}
|
|
181
|
+
onProgress(offset);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface UploadAndIndexOptions {
|
|
187
|
+
projectName?: string;
|
|
188
|
+
onProgress?: (fraction: number) => void;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Streams `.fig`/design files straight to storage in resumable chunks, then
|
|
193
|
+
* finalizes Builder DSI indexing with the resulting upload tokens. No file
|
|
194
|
+
* bytes pass through the app server, so arbitrarily large Figma files work.
|
|
195
|
+
*/
|
|
196
|
+
export async function uploadAndIndexFigmaFiles(
|
|
197
|
+
files: File[],
|
|
198
|
+
options: UploadAndIndexOptions = {},
|
|
199
|
+
): Promise<BuilderIndexResult> {
|
|
200
|
+
if (files.length === 0) throw new Error("No files to upload.");
|
|
201
|
+
|
|
202
|
+
const slots = await requestUploadSlots(files);
|
|
203
|
+
|
|
204
|
+
const totalBytes = files.reduce((sum, file) => sum + file.size, 0) || 1;
|
|
205
|
+
const uploadedPerFile = new Array<number>(files.length).fill(0);
|
|
206
|
+
for (let i = 0; i < files.length; i++) {
|
|
207
|
+
await streamFileToStorage(slots[i], files[i], (uploaded) => {
|
|
208
|
+
uploadedPerFile[i] = uploaded;
|
|
209
|
+
const done = uploadedPerFile.reduce((sum, n) => sum + n, 0);
|
|
210
|
+
options.onProgress?.(Math.min(done / totalBytes, 1));
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const res = await fetch(appApiPath("/api/index-design-system-sources"), {
|
|
215
|
+
method: "POST",
|
|
216
|
+
headers: { "Content-Type": "application/json" },
|
|
217
|
+
body: JSON.stringify({
|
|
218
|
+
projectName: options.projectName,
|
|
219
|
+
uploadTokens: slots.map((slot) => slot.uploadToken),
|
|
220
|
+
}),
|
|
221
|
+
});
|
|
222
|
+
const json = await readJson(res);
|
|
223
|
+
if (!res.ok || json?.error) {
|
|
224
|
+
throw new Error(json?.error || `Indexing failed (${res.status})`);
|
|
225
|
+
}
|
|
226
|
+
return json as BuilderIndexResult;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export interface DecodeJobStatus {
|
|
230
|
+
status: "pending" | "processing" | "complete" | "error";
|
|
231
|
+
branchUrl: string | null;
|
|
232
|
+
error: string | null;
|
|
233
|
+
framesProcessed: number;
|
|
234
|
+
totalFrames: number;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const DECODE_JOB_POLL_INTERVAL_MS = 5_000;
|
|
238
|
+
const DECODE_JOB_MAX_POLLS = 120; // ~10 min at 5s, so a stuck job can't loop forever
|
|
239
|
+
|
|
240
|
+
export interface PollDecodeJobOptions {
|
|
241
|
+
signal?: AbortSignal;
|
|
242
|
+
onUpdate?: (status: DecodeJobStatus) => void;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* After indexing returns a jobId, the `.fig` decode job is still `pending` with
|
|
247
|
+
* no branchUrl. Poll until the branch appears or the job reaches a terminal
|
|
248
|
+
* state. A job that reports `status: "error"` resolves so the caller can read
|
|
249
|
+
* `status.error`; network failures, timeouts, and aborts reject.
|
|
250
|
+
*/
|
|
251
|
+
export async function pollDecodeJobStatus(
|
|
252
|
+
jobId: string,
|
|
253
|
+
options: PollDecodeJobOptions = {},
|
|
254
|
+
): Promise<DecodeJobStatus> {
|
|
255
|
+
const { signal, onUpdate } = options;
|
|
256
|
+
const path = appApiPath(
|
|
257
|
+
`/api/design-system-decode-job-status?jobId=${encodeURIComponent(jobId)}`,
|
|
258
|
+
);
|
|
259
|
+
for (let i = 0; i < DECODE_JOB_MAX_POLLS; i++) {
|
|
260
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
261
|
+
const res = await fetch(path, { signal });
|
|
262
|
+
const json = await readJson(res);
|
|
263
|
+
if (!res.ok || json?.error) {
|
|
264
|
+
throw new Error(json?.error || `Status check failed (${res.status})`);
|
|
265
|
+
}
|
|
266
|
+
const status = json as DecodeJobStatus;
|
|
267
|
+
onUpdate?.(status);
|
|
268
|
+
if (
|
|
269
|
+
status.branchUrl ||
|
|
270
|
+
status.status === "complete" ||
|
|
271
|
+
status.status === "error"
|
|
272
|
+
) {
|
|
273
|
+
return status;
|
|
274
|
+
}
|
|
275
|
+
await delay(DECODE_JOB_POLL_INTERVAL_MS, signal);
|
|
276
|
+
}
|
|
277
|
+
throw new Error(
|
|
278
|
+
"Timed out waiting for the design system to finish decoding.",
|
|
279
|
+
);
|
|
280
|
+
}
|