@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
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
|
|
2
|
-
import { appApiPath } from "@agent-native/core/client/api-path";
|
|
3
2
|
import {
|
|
4
3
|
useActionQuery,
|
|
5
4
|
useActionMutation,
|
|
@@ -36,9 +35,13 @@ import { Label } from "@/components/ui/label";
|
|
|
36
35
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
37
36
|
import { Textarea } from "@/components/ui/textarea";
|
|
38
37
|
|
|
38
|
+
import {
|
|
39
|
+
uploadAndIndexFigmaFiles,
|
|
40
|
+
pollDecodeJobStatus,
|
|
41
|
+
type DecodeJobStatus,
|
|
42
|
+
} from "./builder-design-system-upload";
|
|
39
43
|
import {
|
|
40
44
|
MAX_BUILDER_INDEX_UPLOAD_BYTES,
|
|
41
|
-
readBuilderIndexResponse,
|
|
42
45
|
formatFileSize,
|
|
43
46
|
type BuilderIndexResult,
|
|
44
47
|
} from "./builder-index-response";
|
|
@@ -117,6 +120,62 @@ export function DesignSystemSetup({
|
|
|
117
120
|
const [builderIndexError, setBuilderIndexError] = useState<string | null>(
|
|
118
121
|
null,
|
|
119
122
|
);
|
|
123
|
+
const [decodeStatus, setDecodeStatus] = useState<DecodeJobStatus | null>(
|
|
124
|
+
null,
|
|
125
|
+
);
|
|
126
|
+
const decodePollRef = useRef<AbortController | null>(null);
|
|
127
|
+
|
|
128
|
+
const stopDecodePolling = useCallback(() => {
|
|
129
|
+
decodePollRef.current?.abort();
|
|
130
|
+
decodePollRef.current = null;
|
|
131
|
+
}, []);
|
|
132
|
+
|
|
133
|
+
const startDecodePolling = useCallback(
|
|
134
|
+
(jobId: string, indexResult: BuilderIndexResult) => {
|
|
135
|
+
decodePollRef.current?.abort();
|
|
136
|
+
const controller = new AbortController();
|
|
137
|
+
decodePollRef.current = controller;
|
|
138
|
+
setDecodeStatus({
|
|
139
|
+
status: "pending",
|
|
140
|
+
branchUrl: null,
|
|
141
|
+
error: null,
|
|
142
|
+
framesProcessed: 0,
|
|
143
|
+
totalFrames: 0,
|
|
144
|
+
});
|
|
145
|
+
pollDecodeJobStatus(jobId, {
|
|
146
|
+
signal: controller.signal,
|
|
147
|
+
onUpdate: (status) => {
|
|
148
|
+
if (!controller.signal.aborted) setDecodeStatus(status);
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
.then((status) => {
|
|
152
|
+
if (controller.signal.aborted) return;
|
|
153
|
+
setDecodeStatus(status);
|
|
154
|
+
setBuilderIndexResult(
|
|
155
|
+
status.branchUrl
|
|
156
|
+
? { ...indexResult, builderUrl: status.branchUrl }
|
|
157
|
+
: indexResult,
|
|
158
|
+
);
|
|
159
|
+
setBuilderIndexing(false);
|
|
160
|
+
})
|
|
161
|
+
.catch((err: unknown) => {
|
|
162
|
+
if (controller.signal.aborted) return;
|
|
163
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
164
|
+
setDecodeStatus((prev) => ({
|
|
165
|
+
status: "error",
|
|
166
|
+
branchUrl: prev?.branchUrl ?? null,
|
|
167
|
+
error: err instanceof Error ? err.message : String(err),
|
|
168
|
+
framesProcessed: prev?.framesProcessed ?? 0,
|
|
169
|
+
totalFrames: prev?.totalFrames ?? 0,
|
|
170
|
+
}));
|
|
171
|
+
setBuilderIndexResult(indexResult);
|
|
172
|
+
setBuilderIndexing(false);
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
[],
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
useEffect(() => stopDecodePolling, [stopDecodePolling]);
|
|
120
179
|
|
|
121
180
|
const codeInputRef = useRef<HTMLInputElement>(null);
|
|
122
181
|
const docInputRef = useRef<HTMLInputElement>(null);
|
|
@@ -170,8 +229,10 @@ export function DesignSystemSetup({
|
|
|
170
229
|
setBuilderIndexing(false);
|
|
171
230
|
setBuilderIndexResult(null);
|
|
172
231
|
setBuilderIndexError(null);
|
|
232
|
+
stopDecodePolling();
|
|
233
|
+
setDecodeStatus(null);
|
|
173
234
|
}
|
|
174
|
-
}, [open]);
|
|
235
|
+
}, [open, stopDecodePolling]);
|
|
175
236
|
|
|
176
237
|
const hasAnySources = useMemo(() => {
|
|
177
238
|
return (
|
|
@@ -269,30 +330,34 @@ export function DesignSystemSetup({
|
|
|
269
330
|
|
|
270
331
|
setBuilderIndexError(null);
|
|
271
332
|
setBuilderIndexResult(null);
|
|
333
|
+
stopDecodePolling();
|
|
334
|
+
setDecodeStatus(null);
|
|
272
335
|
setBuilderIndexing(true);
|
|
273
336
|
try {
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
|
|
337
|
+
const suggestedTitle =
|
|
338
|
+
file.name
|
|
339
|
+
.replace(/\.fig$/i, "")
|
|
340
|
+
.replace(/[-_]+/g, " ")
|
|
341
|
+
.trim() || "Imported brand";
|
|
342
|
+
const parsed = await uploadAndIndexFigmaFiles([file], {
|
|
343
|
+
projectName: suggestedTitle,
|
|
344
|
+
});
|
|
345
|
+
if (parsed.jobId) {
|
|
346
|
+
startDecodePolling(parsed.jobId, parsed);
|
|
347
|
+
} else {
|
|
348
|
+
setBuilderIndexResult(parsed);
|
|
349
|
+
setBuilderIndexing(false);
|
|
350
|
+
}
|
|
285
351
|
} catch (err) {
|
|
286
352
|
setBuilderIndexError(
|
|
287
353
|
err instanceof Error
|
|
288
354
|
? err.message
|
|
289
355
|
: t("designSystemSetup.figParseFailed"),
|
|
290
356
|
);
|
|
291
|
-
} finally {
|
|
292
357
|
setBuilderIndexing(false);
|
|
293
358
|
}
|
|
294
359
|
},
|
|
295
|
-
[t],
|
|
360
|
+
[t, startDecodePolling, stopDecodePolling],
|
|
296
361
|
);
|
|
297
362
|
|
|
298
363
|
const handleEditSave = async () => {
|
|
@@ -543,7 +608,10 @@ export function DesignSystemSetup({
|
|
|
543
608
|
) : (
|
|
544
609
|
<BuilderIndexPreview
|
|
545
610
|
result={builderIndexResult}
|
|
611
|
+
decodeStatus={decodeStatus}
|
|
546
612
|
onReset={() => {
|
|
613
|
+
stopDecodePolling();
|
|
614
|
+
setDecodeStatus(null);
|
|
547
615
|
setBuilderIndexResult(null);
|
|
548
616
|
setBuilderIndexError(null);
|
|
549
617
|
}}
|
|
@@ -880,12 +948,22 @@ function TagList({
|
|
|
880
948
|
|
|
881
949
|
function BuilderIndexPreview({
|
|
882
950
|
result,
|
|
951
|
+
decodeStatus,
|
|
883
952
|
onReset,
|
|
884
953
|
}: {
|
|
885
954
|
result: BuilderIndexResult;
|
|
955
|
+
decodeStatus: DecodeJobStatus | null;
|
|
886
956
|
onReset: () => void;
|
|
887
957
|
}) {
|
|
888
958
|
const t = useT();
|
|
959
|
+
const decodeDone =
|
|
960
|
+
decodeStatus == null ||
|
|
961
|
+
Boolean(decodeStatus.branchUrl) ||
|
|
962
|
+
decodeStatus.status === "complete";
|
|
963
|
+
const decodeFailed = decodeStatus?.status === "error";
|
|
964
|
+
const decodeText = decodeFailed
|
|
965
|
+
? t("designSystemSetup.decodeFailed", { error: decodeStatus?.error ?? "" })
|
|
966
|
+
: null;
|
|
889
967
|
return (
|
|
890
968
|
<div className="space-y-4 rounded-lg border border-border bg-accent/40 p-4">
|
|
891
969
|
<div className="flex items-start gap-3">
|
|
@@ -905,44 +983,39 @@ function BuilderIndexPreview({
|
|
|
905
983
|
</div>
|
|
906
984
|
</div>
|
|
907
985
|
|
|
908
|
-
|
|
909
|
-
<
|
|
910
|
-
{
|
|
911
|
-
</
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
<
|
|
916
|
-
{
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
986
|
+
{decodeText && (
|
|
987
|
+
<div className="border-t border-border pt-3 text-xs text-destructive">
|
|
988
|
+
{decodeText}
|
|
989
|
+
</div>
|
|
990
|
+
)}
|
|
991
|
+
|
|
992
|
+
{(decodeDone || decodeFailed) && (
|
|
993
|
+
<div className="flex flex-wrap items-center gap-2 border-t border-border pt-3">
|
|
994
|
+
{decodeDone && !decodeFailed && (
|
|
995
|
+
<Button size="sm" asChild className="cursor-pointer">
|
|
996
|
+
<a
|
|
997
|
+
href={withBuilderUtmTrackingParams(result.builderUrl, {
|
|
998
|
+
campaign: "product",
|
|
999
|
+
content: "design_system_intelligence",
|
|
1000
|
+
})}
|
|
1001
|
+
target="_blank"
|
|
1002
|
+
rel="noreferrer"
|
|
1003
|
+
>
|
|
1004
|
+
<IconExternalLink className="w-3.5 h-3.5" />
|
|
1005
|
+
{t("designSystemSetup.openInBuilder")}
|
|
1006
|
+
</a>
|
|
1007
|
+
</Button>
|
|
1008
|
+
)}
|
|
1009
|
+
<Button
|
|
1010
|
+
size="sm"
|
|
1011
|
+
variant="ghost"
|
|
1012
|
+
onClick={onReset}
|
|
1013
|
+
className="cursor-pointer"
|
|
932
1014
|
>
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
<Button
|
|
938
|
-
size="sm"
|
|
939
|
-
variant="ghost"
|
|
940
|
-
onClick={onReset}
|
|
941
|
-
className="cursor-pointer"
|
|
942
|
-
>
|
|
943
|
-
{t("designSystemSetup.chooseAnotherFile")}
|
|
944
|
-
</Button>
|
|
945
|
-
</div>
|
|
1015
|
+
{t("designSystemSetup.chooseAnotherFile")}
|
|
1016
|
+
</Button>
|
|
1017
|
+
</div>
|
|
1018
|
+
)}
|
|
946
1019
|
</div>
|
|
947
1020
|
);
|
|
948
1021
|
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { appApiPath } from "@agent-native/core/client/api-path";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type BuilderIndexResult,
|
|
5
|
+
readBuilderIndexResponse,
|
|
6
|
+
} from "./builder-index-response";
|
|
7
|
+
|
|
8
|
+
// GCS resumable uploads require every chunk except the last to be a multiple
|
|
9
|
+
// of 256 KiB. 16 MiB is the recommended default and keeps very large `.fig`
|
|
10
|
+
// files off a single request body (the serverless host caps bodies well below
|
|
11
|
+
// Figma export sizes).
|
|
12
|
+
const GCS_CHUNK_SIZE = 16 * 1024 * 1024;
|
|
13
|
+
const MAX_CHUNK_RETRIES = 5;
|
|
14
|
+
|
|
15
|
+
interface UploadSlot {
|
|
16
|
+
idx: number;
|
|
17
|
+
uploadUrl: string;
|
|
18
|
+
uploadToken: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function readJson(res: Response): Promise<any> {
|
|
22
|
+
try {
|
|
23
|
+
return await res.json();
|
|
24
|
+
} catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async function requestUploadSlots(files: File[]): Promise<UploadSlot[]> {
|
|
30
|
+
const res = await fetch(appApiPath("/api/design-system-upload-start"), {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: { "Content-Type": "application/json" },
|
|
33
|
+
body: JSON.stringify({
|
|
34
|
+
attachments: files.map((file) => ({
|
|
35
|
+
name: file.name,
|
|
36
|
+
mimetype: file.type || "application/octet-stream",
|
|
37
|
+
declaredSize: file.size,
|
|
38
|
+
})),
|
|
39
|
+
}),
|
|
40
|
+
});
|
|
41
|
+
const json = await readJson(res);
|
|
42
|
+
if (!res.ok || json?.error) {
|
|
43
|
+
throw new Error(json?.error || `Failed to start upload (${res.status})`);
|
|
44
|
+
}
|
|
45
|
+
const slots = Array.isArray(json?.uploads)
|
|
46
|
+
? ([...json.uploads] as UploadSlot[]).sort((a, b) => a.idx - b.idx)
|
|
47
|
+
: [];
|
|
48
|
+
if (slots.length !== files.length) {
|
|
49
|
+
throw new Error("Upload could not be started for all files.");
|
|
50
|
+
}
|
|
51
|
+
return slots;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function initiateResumableSession(
|
|
55
|
+
uploadUrl: string,
|
|
56
|
+
mimetype: string,
|
|
57
|
+
fileSize: number,
|
|
58
|
+
): Promise<string> {
|
|
59
|
+
const response = await fetch(uploadUrl, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: {
|
|
62
|
+
"x-goog-resumable": "start",
|
|
63
|
+
// The signed URL commits to the exact declared size; echo it back
|
|
64
|
+
// byte-for-byte or GCS rejects the session.
|
|
65
|
+
"x-goog-content-length-range": `0,${fileSize}`,
|
|
66
|
+
"Content-Type": mimetype,
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
if (!response.ok) {
|
|
70
|
+
throw new Error(`Failed to initiate upload session (${response.status})`);
|
|
71
|
+
}
|
|
72
|
+
const sessionUri = response.headers.get("Location");
|
|
73
|
+
if (!sessionUri) {
|
|
74
|
+
throw new Error("Upload session URI missing from storage response");
|
|
75
|
+
}
|
|
76
|
+
return sessionUri;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// GCS reports the highest committed byte in a `Range: bytes=0-<end>` header.
|
|
80
|
+
function committedOffsetFromRange(response: Response): number | null {
|
|
81
|
+
const match = response.headers.get("Range")?.match(/bytes=0-(\d+)/);
|
|
82
|
+
return match ? parseInt(match[1], 10) + 1 : null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function queryCommittedOffset(
|
|
86
|
+
sessionUri: string,
|
|
87
|
+
total: number,
|
|
88
|
+
): Promise<number> {
|
|
89
|
+
const response = await fetch(sessionUri, {
|
|
90
|
+
method: "PUT",
|
|
91
|
+
headers: { "Content-Range": `bytes */${total}` },
|
|
92
|
+
});
|
|
93
|
+
if (response.status === 200 || response.status === 201) return total;
|
|
94
|
+
if (response.status === 308) return committedOffsetFromRange(response) ?? 0;
|
|
95
|
+
throw new Error(`Failed to query upload status (${response.status})`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function delay(ms: number, signal?: AbortSignal): Promise<void> {
|
|
99
|
+
return new Promise((resolve, reject) => {
|
|
100
|
+
if (signal?.aborted) {
|
|
101
|
+
return reject(new DOMException("Aborted", "AbortError"));
|
|
102
|
+
}
|
|
103
|
+
const timer = setTimeout(resolve, ms);
|
|
104
|
+
signal?.addEventListener(
|
|
105
|
+
"abort",
|
|
106
|
+
() => {
|
|
107
|
+
clearTimeout(timer);
|
|
108
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
109
|
+
},
|
|
110
|
+
{ once: true },
|
|
111
|
+
);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function streamFileToStorage(
|
|
116
|
+
slot: UploadSlot,
|
|
117
|
+
file: File,
|
|
118
|
+
onProgress: (uploadedBytes: number) => void,
|
|
119
|
+
): Promise<void> {
|
|
120
|
+
const mimetype = file.type || "application/octet-stream";
|
|
121
|
+
const sessionUri = await initiateResumableSession(
|
|
122
|
+
slot.uploadUrl,
|
|
123
|
+
mimetype,
|
|
124
|
+
file.size,
|
|
125
|
+
);
|
|
126
|
+
const total = file.size;
|
|
127
|
+
|
|
128
|
+
if (total === 0) {
|
|
129
|
+
const response = await fetch(sessionUri, {
|
|
130
|
+
method: "PUT",
|
|
131
|
+
headers: { "Content-Range": "bytes */0" },
|
|
132
|
+
body: new Uint8Array(0),
|
|
133
|
+
});
|
|
134
|
+
if (response.status !== 200 && response.status !== 201) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Failed to finalize zero-byte upload (${response.status})`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
onProgress(0);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let offset = 0;
|
|
144
|
+
let retries = 0;
|
|
145
|
+
while (offset < total) {
|
|
146
|
+
const end = Math.min(offset + GCS_CHUNK_SIZE, total);
|
|
147
|
+
const isLast = end === total;
|
|
148
|
+
try {
|
|
149
|
+
const response = await fetch(sessionUri, {
|
|
150
|
+
method: "PUT",
|
|
151
|
+
headers: { "Content-Range": `bytes ${offset}-${end - 1}/${total}` },
|
|
152
|
+
body: file.slice(offset, end),
|
|
153
|
+
});
|
|
154
|
+
if (response.status === 200 || response.status === 201) {
|
|
155
|
+
offset = total;
|
|
156
|
+
} else if (!isLast && response.status === 308) {
|
|
157
|
+
const nextOffset = committedOffsetFromRange(response) ?? offset;
|
|
158
|
+
if (nextOffset <= offset) {
|
|
159
|
+
throw new Error(`Upload stalled at byte ${offset}`);
|
|
160
|
+
}
|
|
161
|
+
offset = nextOffset;
|
|
162
|
+
} else {
|
|
163
|
+
throw new Error(`Unexpected upload status ${response.status}`);
|
|
164
|
+
}
|
|
165
|
+
retries = 0;
|
|
166
|
+
onProgress(offset);
|
|
167
|
+
} catch (err) {
|
|
168
|
+
if (++retries > MAX_CHUNK_RETRIES) throw err;
|
|
169
|
+
await delay(500 * retries);
|
|
170
|
+
try {
|
|
171
|
+
offset = await queryCommittedOffset(sessionUri, total);
|
|
172
|
+
} catch {
|
|
173
|
+
// If the offset query also fails, retry from the last local offset —
|
|
174
|
+
// GCS's resumable PUT safely re-acknowledges bytes it already has.
|
|
175
|
+
}
|
|
176
|
+
onProgress(offset);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export interface UploadAndIndexOptions {
|
|
182
|
+
projectName?: string;
|
|
183
|
+
onProgress?: (fraction: number) => void;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Streams `.fig`/design files straight to storage in resumable chunks, then
|
|
188
|
+
* finalizes Builder DSI indexing with the resulting upload tokens. No file
|
|
189
|
+
* bytes pass through the app server, so arbitrarily large Figma files work.
|
|
190
|
+
*/
|
|
191
|
+
export async function uploadAndIndexFigmaFiles(
|
|
192
|
+
files: File[],
|
|
193
|
+
options: UploadAndIndexOptions = {},
|
|
194
|
+
): Promise<BuilderIndexResult> {
|
|
195
|
+
if (files.length === 0) throw new Error("No files to upload.");
|
|
196
|
+
|
|
197
|
+
const slots = await requestUploadSlots(files);
|
|
198
|
+
|
|
199
|
+
const totalBytes = files.reduce((sum, file) => sum + file.size, 0) || 1;
|
|
200
|
+
const uploadedPerFile = new Array<number>(files.length).fill(0);
|
|
201
|
+
for (let i = 0; i < files.length; i++) {
|
|
202
|
+
await streamFileToStorage(slots[i], files[i], (uploaded) => {
|
|
203
|
+
uploadedPerFile[i] = uploaded;
|
|
204
|
+
const done = uploadedPerFile.reduce((sum, n) => sum + n, 0);
|
|
205
|
+
options.onProgress?.(Math.min(done / totalBytes, 1));
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const res = await fetch(appApiPath("/api/index-design-system-sources"), {
|
|
210
|
+
method: "POST",
|
|
211
|
+
headers: { "Content-Type": "application/json" },
|
|
212
|
+
body: JSON.stringify({
|
|
213
|
+
projectName: options.projectName,
|
|
214
|
+
uploadTokens: slots.map((slot) => slot.uploadToken),
|
|
215
|
+
}),
|
|
216
|
+
});
|
|
217
|
+
return readBuilderIndexResponse(res);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
export interface DecodeJobStatus {
|
|
221
|
+
status: "pending" | "processing" | "complete" | "error";
|
|
222
|
+
branchUrl: string | null;
|
|
223
|
+
error: string | null;
|
|
224
|
+
framesProcessed: number;
|
|
225
|
+
totalFrames: number;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const DECODE_JOB_POLL_INTERVAL_MS = 5_000;
|
|
229
|
+
const DECODE_JOB_MAX_POLLS = 120; // ~10 min at 5s, so a stuck job can't loop forever
|
|
230
|
+
|
|
231
|
+
export interface PollDecodeJobOptions {
|
|
232
|
+
signal?: AbortSignal;
|
|
233
|
+
onUpdate?: (status: DecodeJobStatus) => void;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* After indexing returns a jobId, the `.fig` decode job is still `pending` with
|
|
238
|
+
* no branchUrl. Poll until the branch appears or the job reaches a terminal
|
|
239
|
+
* state. A job that reports `status: "error"` resolves so the caller can read
|
|
240
|
+
* `status.error`; network failures, timeouts, and aborts reject.
|
|
241
|
+
*/
|
|
242
|
+
export async function pollDecodeJobStatus(
|
|
243
|
+
jobId: string,
|
|
244
|
+
options: PollDecodeJobOptions = {},
|
|
245
|
+
): Promise<DecodeJobStatus> {
|
|
246
|
+
const { signal, onUpdate } = options;
|
|
247
|
+
const path = appApiPath(
|
|
248
|
+
`/api/design-system-decode-job-status?jobId=${encodeURIComponent(jobId)}`,
|
|
249
|
+
);
|
|
250
|
+
for (let i = 0; i < DECODE_JOB_MAX_POLLS; i++) {
|
|
251
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
252
|
+
const res = await fetch(path, { signal });
|
|
253
|
+
const json = await readJson(res);
|
|
254
|
+
if (!res.ok || json?.error) {
|
|
255
|
+
throw new Error(json?.error || `Status check failed (${res.status})`);
|
|
256
|
+
}
|
|
257
|
+
const status = json as DecodeJobStatus;
|
|
258
|
+
onUpdate?.(status);
|
|
259
|
+
if (
|
|
260
|
+
status.branchUrl ||
|
|
261
|
+
status.status === "complete" ||
|
|
262
|
+
status.status === "error"
|
|
263
|
+
) {
|
|
264
|
+
return status;
|
|
265
|
+
}
|
|
266
|
+
await delay(DECODE_JOB_POLL_INTERVAL_MS, signal);
|
|
267
|
+
}
|
|
268
|
+
throw new Error(
|
|
269
|
+
"Timed out waiting for the design system to finish decoding.",
|
|
270
|
+
);
|
|
271
|
+
}
|
|
@@ -13,7 +13,7 @@ export interface BuilderIndexResult {
|
|
|
13
13
|
builderConnectUrl?: string;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
export const MAX_BUILDER_INDEX_UPLOAD_BYTES =
|
|
16
|
+
export const MAX_BUILDER_INDEX_UPLOAD_BYTES = 512 * 1024 * 1024;
|
|
17
17
|
|
|
18
18
|
export function formatFileSize(bytes: number): string {
|
|
19
19
|
return `${Math.round(bytes / 1024 / 1024)} MB`;
|
|
@@ -537,6 +537,7 @@ const messages = {
|
|
|
537
537
|
builderDesignSystemId: "Design system",
|
|
538
538
|
builderJobId: "Job",
|
|
539
539
|
openInBuilder: "Open in Builder",
|
|
540
|
+
decodeFailed: "Decoding failed: {{error}}",
|
|
540
541
|
websiteUrl: "Website URL",
|
|
541
542
|
websitePlaceholder: "example.com or Nike",
|
|
542
543
|
add: "Add",
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FeatureNotConfiguredError,
|
|
3
|
+
fetchBuilderDesignSystemDecodeJobStatus,
|
|
4
|
+
getSession,
|
|
5
|
+
} from "@agent-native/core/server";
|
|
6
|
+
import { defineEventHandler, getQuery, setResponseStatus } from "h3";
|
|
7
|
+
|
|
8
|
+
import { withSlidesRequestContext } from "./request-auth-context.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reads a Builder design-system decode job's status. The UI polls this after
|
|
12
|
+
* `/api/index-design-system-sources` returns a jobId, until the `.fig` decode
|
|
13
|
+
* job leaves `pending` and exposes a `branchUrl` (or reports an `error`).
|
|
14
|
+
*/
|
|
15
|
+
export const designSystemDecodeJobStatus = defineEventHandler(async (event) => {
|
|
16
|
+
const session = await getSession(event).catch(() => null);
|
|
17
|
+
if (!session?.email) {
|
|
18
|
+
setResponseStatus(event, 401);
|
|
19
|
+
return { error: "Unauthorized" };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const jobId = getQuery(event).jobId;
|
|
23
|
+
if (typeof jobId !== "string" || !jobId.trim()) {
|
|
24
|
+
setResponseStatus(event, 400);
|
|
25
|
+
return { error: "jobId is required." };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
try {
|
|
29
|
+
return await withSlidesRequestContext(event, () =>
|
|
30
|
+
fetchBuilderDesignSystemDecodeJobStatus(jobId.trim()),
|
|
31
|
+
);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
if (err instanceof FeatureNotConfiguredError) {
|
|
34
|
+
setResponseStatus(event, 412);
|
|
35
|
+
return {
|
|
36
|
+
error: err.message,
|
|
37
|
+
builderConnectUrl:
|
|
38
|
+
err.builderConnectUrl ?? "/_agent-native/builder/connect",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
setResponseStatus(event, 502);
|
|
42
|
+
return {
|
|
43
|
+
error:
|
|
44
|
+
err instanceof Error
|
|
45
|
+
? err.message
|
|
46
|
+
: "Failed to read decode job status.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FeatureNotConfiguredError,
|
|
3
|
+
getSession,
|
|
4
|
+
startBuilderDesignSystemUpload,
|
|
5
|
+
} from "@agent-native/core/server";
|
|
6
|
+
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
|
7
|
+
|
|
8
|
+
import { withSlidesRequestContext } from "./request-auth-context.js";
|
|
9
|
+
|
|
10
|
+
const MAX_FIG_BYTES = 512 * 1024 * 1024;
|
|
11
|
+
|
|
12
|
+
interface AttachmentInput {
|
|
13
|
+
name?: unknown;
|
|
14
|
+
mimetype?: unknown;
|
|
15
|
+
declaredSize?: unknown;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Opens signed resumable-upload slots so the browser can stream large `.fig`
|
|
20
|
+
* bytes straight to storage. Only small JSON metadata rides through the app
|
|
21
|
+
* server; the file bytes never do.
|
|
22
|
+
*/
|
|
23
|
+
export const designSystemUploadStart = defineEventHandler(async (event) => {
|
|
24
|
+
const session = await getSession(event).catch(() => null);
|
|
25
|
+
if (!session?.email) {
|
|
26
|
+
setResponseStatus(event, 401);
|
|
27
|
+
return { error: "Unauthorized" };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const body = (await readBody(event).catch(() => null)) as {
|
|
31
|
+
attachments?: AttachmentInput[];
|
|
32
|
+
} | null;
|
|
33
|
+
const rawList = Array.isArray(body?.attachments) ? body.attachments : [];
|
|
34
|
+
if (rawList.length === 0) {
|
|
35
|
+
setResponseStatus(event, 400);
|
|
36
|
+
return { error: "No attachments provided." };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const attachments: {
|
|
40
|
+
name: string;
|
|
41
|
+
mimetype: string;
|
|
42
|
+
declaredSize: number;
|
|
43
|
+
}[] = [];
|
|
44
|
+
for (const raw of rawList) {
|
|
45
|
+
const name = typeof raw?.name === "string" ? raw.name.trim() : "";
|
|
46
|
+
const mimetype =
|
|
47
|
+
typeof raw?.mimetype === "string" && raw.mimetype.trim()
|
|
48
|
+
? raw.mimetype.trim()
|
|
49
|
+
: "application/octet-stream";
|
|
50
|
+
const declaredSize = Number(raw?.declaredSize);
|
|
51
|
+
if (!name) {
|
|
52
|
+
setResponseStatus(event, 400);
|
|
53
|
+
return { error: "Attachment name is required." };
|
|
54
|
+
}
|
|
55
|
+
if (!Number.isSafeInteger(declaredSize) || declaredSize <= 0) {
|
|
56
|
+
setResponseStatus(event, 400);
|
|
57
|
+
return { error: "Attachment declaredSize must be a positive integer." };
|
|
58
|
+
}
|
|
59
|
+
if (declaredSize > MAX_FIG_BYTES) {
|
|
60
|
+
setResponseStatus(event, 413);
|
|
61
|
+
return {
|
|
62
|
+
error: `File too large (max ${Math.round(MAX_FIG_BYTES / 1024 / 1024)} MB).`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
attachments.push({ name, mimetype, declaredSize });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
const uploads = await withSlidesRequestContext(event, () =>
|
|
70
|
+
startBuilderDesignSystemUpload(attachments),
|
|
71
|
+
);
|
|
72
|
+
return { uploads };
|
|
73
|
+
} catch (err) {
|
|
74
|
+
if (err instanceof FeatureNotConfiguredError) {
|
|
75
|
+
setResponseStatus(event, 412);
|
|
76
|
+
return {
|
|
77
|
+
error: err.message,
|
|
78
|
+
builderConnectUrl:
|
|
79
|
+
err.builderConnectUrl ?? "/_agent-native/builder/connect",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
setResponseStatus(event, 502);
|
|
83
|
+
return {
|
|
84
|
+
error: err instanceof Error ? err.message : "Failed to start upload.",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
});
|